diff options
author | mjacob <mjacob@cvs.openbsd.org> | 2001-02-12 23:45:00 +0000 |
---|---|---|
committer | mjacob <mjacob@cvs.openbsd.org> | 2001-02-12 23:45:00 +0000 |
commit | 06820e490f119d5888ba6860c535fb98be037e68 (patch) | |
tree | 26ebbdd099f434478599512dd0e84c4857087920 /sys/dev | |
parent | 2a4b2e1930d941ef16e9ef9596e4ae1a1b6b9b57 (diff) |
Remove ISP2100_FABRIC defines- we always handle fabric now. Insert
isp_getmap helper function (for getting Loop Position map). Make
sure we (for our own benefit) mark req_state_flags with RQSF_GOT_SENSE
for Fibre Channel if we got sense data- the !*$)!*$)~*$)*$ Qlogic
f/w doesn't do so. Add ISPCTL_SCAN_FABRIC, ISPCTL_SCAN_LOOP, ISPCTL_SEND_LIP,
and ISPCTL_GET_POSMAP isp_control functions. Correctly send async notifications
upstream for changes in the name server, changes in the port database, and
f/w crashes. Correctly set topology when we get a ASYNC_PTPMODE event.
Quite massively redo how we handle Loop events- we've now added several
intermediate states between LOOP_PDB_RCVD and LOOP_READY. This allows us
a lot finer control about how we scan fabric, whether we go further
than scanning fabric, how we look at the local loop, and whether we
merge entries at the level or not. This is the next to last step for
moving managing loop state out of the core module entirely (whereupon
loop && fabric events will simply freeze the command queue and a thread
will run to figure out what's changed and *it* will re-enable the queu).
This fine amount of control also gets us closer to having an external
policy engine decide which fabric devices we really want to log into.
When resetting the Qlogic 2X00 units, reset the FPM (Fibre Protocol
Module) and FBM (Fibre Buffer Modules). Also remember to clear the
semaphore registers. Tell the RISC processor to not halt on FPM
parity errors.
Throw out the ISP_CFG_NOINIT silliness and instead go to the use of
adapter 'roles' to see whether one completes initialization or not
(mostly for Fibre Channel). The ultimate intent, btw, of all of this
is to have a warm standby adapter for failover reasons. Because
we do roles now, setting of Target Capable Class 3 service parameters
in the ICB for the 2x00 cards reflects from role. Also, in isp_start,
if we're not supporting an initiator role, we bounce outgoing commands
with a Selection Timeout error. Also clean out the TOGGLE_TMODE
goop for FC- there is no toggling of target mode like there is
for parallel SCSI cards.
Do more cleanup with respect to using target ids 0..125 in F-port
topologies. Also keep track of things which *were* fabric devices
so that when you rescan the fabric you can notify the outer layers
when fabric devices go away.
Only force a LOGOUT for fabric devices if they're still logged in
(i.e., you cat their Port Database entry. Clean up the Get All Next
scanning.
Finally, use a new tag in the softc to store the opcode for the
last mailbox command used so we can report which opcode timed
out.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/ic/isp.c | 1127 |
1 files changed, 705 insertions, 422 deletions
diff --git a/sys/dev/ic/isp.c b/sys/dev/ic/isp.c index 727e1d6e654..09f16c08c01 100644 --- a/sys/dev/ic/isp.c +++ b/sys/dev/ic/isp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: isp.c,v 1.19 2001/01/09 03:26:18 mjacob Exp $ */ +/* $OpenBSD: isp.c,v 1.20 2001/02/12 23:44:59 mjacob Exp $ */ /* * Machine and OS Independent (well, as best as possible) * code for the Qlogic ISP SCSI adapters. @@ -72,7 +72,6 @@ static const char portdup[] = "Target %d duplicates Target %d- killing off both"; static const char retained[] = "Retaining Loop ID 0x%x for Target %d (Port 0x%x)"; -#ifdef ISP2100_FABRIC static const char lretained[] = "Retained login of Target %d (Loop ID 0x%x) Port 0x%x"; static const char plogout[] = @@ -87,7 +86,6 @@ static const char pdbmfail2[] = "PDB Port info for Device @ Port 0x%x does not match up (0x%x)"; static const char ldumped[] = "Target %d (Loop ID 0x%x) Port 0x%x dumped after login info mismatch"; -#endif static const char notresp[] = "Not RESPONSE in RESPONSE Queue (type 0x%x) @ idx %d (next %d) nlooked %d"; static const char xact1[] = @@ -101,7 +99,7 @@ static const char pskip[] = static const char topology[] = "Loop ID %d, AL_PA 0x%x, Port ID 0x%x, Loop State 0x%x, Topology '%s'"; static const char finmsg[] = - "(%d.%d.%d): FIN dl%d resid%d STS 0x%x SKEY %c XS_ERR=0x%x"; + "(%d.%d.%d): FIN dl%d resid %d STS 0x%x SKEY %c XS_ERR=0x%x"; /* * Local function prototypes. */ @@ -115,16 +113,15 @@ static void isp_scsi_init __P((struct ispsoftc *)); static void isp_scsi_channel_init __P((struct ispsoftc *, int)); static void isp_fibre_init __P((struct ispsoftc *)); static void isp_mark_getpdb_all __P((struct ispsoftc *)); +static int isp_getmap __P((struct ispsoftc *, fcpos_map_t *)); static int isp_getpdb __P((struct ispsoftc *, int, isp_pdb_t *)); static u_int64_t isp_get_portname __P((struct ispsoftc *, int, int)); static int isp_fclink_test __P((struct ispsoftc *, int)); static char *isp2100_fw_statename __P((int)); -static int isp_same_lportdb __P((struct lportdb *, struct lportdb *)); -static int isp_pdb_sync __P((struct ispsoftc *, int)); -#ifdef ISP2100_FABRIC +static int isp_pdb_sync __P((struct ispsoftc *)); +static int isp_scan_loop __P((struct ispsoftc *)); static int isp_scan_fabric __P((struct ispsoftc *)); static void isp_register_fc4_type __P((struct ispsoftc *)); -#endif static void isp_fw_state __P((struct ispsoftc *)); static void isp_mboxcmd __P((struct ispsoftc *, mbreg_t *, int)); @@ -203,7 +200,8 @@ isp_reset(isp) DISABLE_INTS(isp); /* - * Put the board into PAUSE mode (so we can read the SXP registers). + * Put the board into PAUSE mode (so we can read the SXP registers + * or write FPM/FBM registers). */ ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); @@ -218,6 +216,14 @@ isp_reset(isp) default: break; } + /* + * While we're paused, reset the FPM module and FBM fifos. + */ + ISP_WRITE(isp, BIU2100_CSR, BIU2100_FPM0_REGS); + ISP_WRITE(isp, FPM_DIAG_CONFIG, FPM_SOFT_RESET); + ISP_WRITE(isp, BIU2100_CSR, BIU2100_FB_REGS); + ISP_WRITE(isp, FBM_CMD, FBMCMD_FIFO_RESET_ALL); + ISP_WRITE(isp, BIU2100_CSR, BIU2100_RISC_REGS); } else if (IS_1240(isp)) { sdparam *sdp = isp->isp_param; revname = "1240"; @@ -461,6 +467,8 @@ again: */ ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); USEC_DELAY(100); + /* Clear semaphore register (just to be sure) */ + ISP_WRITE(isp, BIU_SEMA, 0); /* * Establish some initial burst rate stuff. @@ -498,6 +506,9 @@ again: #endif } else { ISP_WRITE(isp, RISC_MTR2100, 0x1212); + if (IS_2200(isp)) { + ISP_WRITE(isp, HCCR, HCCR_2X00_DISABLE_PARITY_PAUSE); + } } ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); /* release paused processor */ @@ -729,12 +740,10 @@ isp_init(isp) if (IS_DUALBUS(isp)) { isp_setdfltparm(isp, 1); } - if ((isp->isp_confopts & ISP_CFG_NOINIT) == 0) { - if (IS_FC(isp)) { - isp_fibre_init(isp); - } else { - isp_scsi_init(isp); - } + if (IS_FC(isp)) { + isp_fibre_init(isp); + } else { + isp_scsi_init(isp); } } @@ -751,6 +760,13 @@ isp_scsi_init(isp) sdp_chan1++; } + /* + * If we have no role (neither target nor initiator), return. + */ + if (isp->isp_role == ISP_ROLE_NONE) { + return; + } + /* First do overall per-card settings. */ /* @@ -1012,6 +1028,20 @@ isp_fibre_init(isp) fcp = isp->isp_param; + /* + * Do this *before* initializing the firmware. + */ + isp_mark_getpdb_all(isp); + fcp->isp_fwstate = FW_CONFIG_WAIT; + fcp->isp_loopstate = LOOP_NIL; + + /* + * If we have no role (neither target nor initiator), return. + */ + if (isp->isp_role == ISP_ROLE_NONE) { + return; + } + loopid = DEFAULT_LOOPID(isp); icbp = (isp_icb_t *) fcp->isp_scratch; MEMZERO(icbp, sizeof (*icbp)); @@ -1051,6 +1081,19 @@ isp_fibre_init(isp) * Node Name && Port Names to be distinct. */ + + /* + * Make sure that target role reflects into fwoptions. + */ + if (isp->isp_role & ISP_ROLE_TARGET) { + fcp->isp_fwoptions |= ICBOPT_TGT_ENABLE; + } else { + fcp->isp_fwoptions &= ~ICBOPT_TGT_ENABLE; + } + + /* + * Propagate all of this into the ICB structure. + */ icbp->icb_fwoptions = fcp->isp_fwoptions; icbp->icb_maxfrmlen = fcp->isp_maxfrmlen; if (icbp->icb_maxfrmlen < ICB_MIN_FRMLEN || @@ -1127,13 +1170,10 @@ isp_fibre_init(isp) "isp_fibre_init: fwoptions 0x%x", fcp->isp_fwoptions); ISP_SWIZZLE_ICB(isp, icbp); + /* - * Do this *before* initializing the firmware. + * Init the firmware */ - isp_mark_getpdb_all(isp); - fcp->isp_fwstate = FW_CONFIG_WAIT; - fcp->isp_loopstate = LOOP_NIL; - mbs.param[0] = MBOX_INIT_FIRMWARE; mbs.param[1] = 0; mbs.param[2] = DMA_MSW(fcp->isp_scdma); @@ -1163,6 +1203,36 @@ isp_fibre_init(isp) * else failure. */ +static int +isp_getmap(isp, map) + struct ispsoftc *isp; + fcpos_map_t *map; +{ + fcparam *fcp = (fcparam *) isp->isp_param; + mbreg_t mbs; + + mbs.param[0] = MBOX_GET_FC_AL_POSITION_MAP; + mbs.param[1] = 0; + mbs.param[2] = DMA_MSW(fcp->isp_scdma); + mbs.param[3] = DMA_LSW(fcp->isp_scdma); + /* + * Unneeded. For the 2100, except for initializing f/w, registers + * 4/5 have to not be written to. + * mbs.param[4] = 0; + * mbs.param[5] = 0; + * + */ + mbs.param[6] = 0; + mbs.param[7] = 0; + isp_mboxcmd(isp, &mbs, MBLOGALL & ~MBOX_COMMAND_PARAM_ERROR); + if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { + MEMCPY(map, fcp->isp_scratch, sizeof (fcpos_map_t)); + map->fwmap = mbs.param[1] != 0; + return (0); + } + return (-1); +} + static void isp_mark_getpdb_all(isp) struct ispsoftc *isp; @@ -1170,7 +1240,7 @@ isp_mark_getpdb_all(isp) fcparam *fcp = (fcparam *) isp->isp_param; int i; for (i = 0; i < MAX_FC_TARG; i++) { - fcp->portdb[i].valid = 0; + fcp->portdb[i].valid = fcp->portdb[i].fabric_dev = 0; } } @@ -1249,12 +1319,12 @@ isp_fclink_test(isp, usdelay) "F Port (no FLOGI_ACC response)" }; mbreg_t mbs; - int count; + int count, check_for_fabric; u_int8_t lwfs; fcparam *fcp; -#if defined(ISP2100_FABRIC) + struct lportdb *lp; isp_pdb_t pdb; -#endif + fcp = isp->isp_param; /* @@ -1347,23 +1417,42 @@ isp_fclink_test(isp, usdelay) } else { fcp->isp_topo = TOPO_NL_PORT; } - fcp->isp_alpa = mbs.param[2]; + fcp->isp_portid = fcp->isp_alpa = mbs.param[2] & 0xff; -#if defined(ISP2100_FABRIC) + /* + * Check to see if we're on a fabric by trying to see if we + * can talk to the fabric name server. This can be a bit + * tricky because if we're a 2100, we should check always + * (in case we're connected to an server doing aliasing). + */ fcp->isp_onfabric = 0; - if (fcp->isp_topo != TOPO_N_PORT && - isp_getpdb(isp, FL_PORT_ID, &pdb) == 0) { - struct lportdb *lp; + + if (IS_2100(isp)) + check_for_fabric = 1; + else if (fcp->isp_topo == TOPO_FL_PORT || fcp->isp_topo == TOPO_F_PORT) + check_for_fabric = 1; + else + check_for_fabric = 0; + + if (check_for_fabric && isp_getpdb(isp, FL_PORT_ID, &pdb) == 0) { + int loopid = FL_PORT_ID; if (IS_2100(isp)) { fcp->isp_topo = TOPO_FL_PORT; } - fcp->isp_portid = mbs.param[2] | (((int)mbs.param[3]) << 16); - fcp->isp_onfabric = 1; + + if (BITS2WORD(pdb.pdb_portid_bits) == 0) { + /* + * Crock. + */ + fcp->isp_topo = TOPO_NL_PORT; + goto not_on_fabric; + } + fcp->isp_portid = mbs.param[2] | ((int) mbs.param[3] << 16); /* * Save the Fabric controller's port database entry. */ - lp = &fcp->portdb[FL_PORT_ID]; + lp = &fcp->portdb[loopid]; lp->node_wwn = (((u_int64_t)pdb.pdb_nodename[0]) << 56) | (((u_int64_t)pdb.pdb_nodename[1]) << 48) | @@ -1387,11 +1476,11 @@ isp_fclink_test(isp, usdelay) lp->portid = BITS2WORD(pdb.pdb_portid_bits); lp->loopid = pdb.pdb_loopid; lp->loggedin = lp->valid = 1; + fcp->isp_onfabric = 1; + (void) isp_async(isp, ISPASYNC_PROMENADE, &loopid); isp_register_fc4_type(isp); - } else -#endif - { - fcp->isp_portid = mbs.param[2]; + } else { +not_on_fabric: fcp->isp_onfabric = 0; fcp->portdb[FL_PORT_ID].valid = 0; } @@ -1399,6 +1488,45 @@ isp_fclink_test(isp, usdelay) isp_prt(isp, ISP_LOGINFO, topology, fcp->isp_loopid, fcp->isp_alpa, fcp->isp_portid, fcp->isp_loopstate, toponames[fcp->isp_topo]); + /* + * Announce ourselves, too. This involves synthesizing an entry. + */ + if (fcp->isp_iid_set == 0) { + fcp->isp_iid_set = 1; + fcp->isp_iid = fcp->isp_loopid; + lp = &fcp->portdb[fcp->isp_iid]; + } else { + lp = &fcp->portdb[fcp->isp_iid]; + if (fcp->isp_portid != lp->portid || + fcp->isp_loopid != lp->loopid || + fcp->isp_nodewwn != ISP_NODEWWN(isp) || + fcp->isp_portwwn != ISP_PORTWWN(isp)) { + lp->valid = 0; + count = fcp->isp_iid; + (void) isp_async(isp, ISPASYNC_PROMENADE, &count); + } + } + lp->loopid = fcp->isp_loopid; + lp->portid = fcp->isp_portid; + lp->node_wwn = ISP_NODEWWN(isp); + lp->port_wwn = ISP_PORTWWN(isp); + switch (isp->isp_role) { + case ISP_ROLE_NONE: + lp->roles = 0; + break; + case ISP_ROLE_TARGET: + lp->roles = SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT; + break; + case ISP_ROLE_INITIATOR: + lp->roles = SVC3_INI_ROLE >> SVC3_ROLE_SHIFT; + break; + case ISP_ROLE_BOTH: + lp->roles = (SVC3_INI_ROLE|SVC3_TGT_ROLE) >> SVC3_ROLE_SHIFT; + break; + } + lp->loggedin = lp->valid = 1; + count = fcp->isp_iid; + (void) isp_async(isp, ISPASYNC_PROMENADE, &count); return (0); } @@ -1419,320 +1547,81 @@ isp2100_fw_statename(state) } } -static int -isp_same_lportdb(a, b) - struct lportdb *a, *b; -{ - /* - * We decide two lports are the same if they have non-zero and - * identical port WWNs and identical loop IDs. - */ - - if (a->port_wwn == 0 || a->port_wwn != b->port_wwn || - a->loopid != b->loopid || a->roles != b->roles) { - return (0); - } else { - return (1); - } -} - /* * Synchronize our soft copy of the port database with what the f/w thinks * (with a view toward possibly for a specific target....) */ static int -isp_pdb_sync(isp, target) +isp_pdb_sync(isp) struct ispsoftc *isp; - int target; { - struct lportdb *lp, *tport; + struct lportdb *lp; fcparam *fcp = isp->isp_param; isp_pdb_t pdb; - int loopid, frange, prange, lim; + int loopid, base, lim; -#ifdef ISP2100_FABRIC - /* - * XXX: If we do this *after* building up our local port database, - * XXX: the commands simply don't work. - */ /* - * (Re)discover all fabric devices + * Make sure we're okay for doing this right now. */ - if (fcp->isp_onfabric) - (void) isp_scan_fabric(isp); -#endif - - - switch (fcp->isp_topo) { - case TOPO_F_PORT: - case TOPO_PTP_STUB: - frange = prange = 0; - break; - case TOPO_N_PORT: - prange = 2; - break; - default: - frange = FC_SNS_ID+1; - prange = FL_PORT_ID; - break; + if (fcp->isp_loopstate != LOOP_PDB_RCVD && + fcp->isp_loopstate != LOOP_FSCAN_DONE && + fcp->isp_loopstate != LOOP_LSCAN_DONE) { + return (-1); } - /* - * Run through the local loop ports and get port database info - * for each loop ID. - * - * There's a somewhat unexplained situation where the f/w passes back - * the wrong database entity- if that happens, just restart (up to - * FL_PORT_ID times). - */ - tport = fcp->tport; - - /* - * make sure the temp port database is clean... - */ - MEMZERO((void *) tport, sizeof (tport)); - - for (lim = loopid = 0; loopid < prange; loopid++) { - lp = &tport[loopid]; - lp->node_wwn = isp_get_portname(isp, loopid, 1); - if (fcp->isp_loopstate < LOOP_PDB_RCVD) - return (-1); - if (lp->node_wwn == 0) - continue; - lp->port_wwn = isp_get_portname(isp, loopid, 0); - if (fcp->isp_loopstate < LOOP_PDB_RCVD) - return (-1); - if (lp->port_wwn == 0) { - lp->node_wwn = 0; - continue; - } - - /* - * Get an entry.... - */ - if (isp_getpdb(isp, loopid, &pdb) != 0) { - if (fcp->isp_loopstate < LOOP_PDB_RCVD) + if (fcp->isp_topo == TOPO_FL_PORT || fcp->isp_topo == TOPO_NL_PORT || + fcp->isp_topo == TOPO_N_PORT) { + if (fcp->isp_loopstate < LOOP_LSCAN_DONE) { + if (isp_scan_loop(isp) != 0) { return (-1); - continue; - } - - if (fcp->isp_loopstate < LOOP_PDB_RCVD) - return (-1); - - /* - * If the returned database element doesn't match what we - * asked for, restart the process entirely (up to a point...). - */ - if (pdb.pdb_loopid != loopid) { - loopid = 0; - if (lim++ < FL_PORT_ID) { - continue; } - isp_prt(isp, ISP_LOGWARN, - "giving up on synchronizing the port database"); - return (-1); - } - - /* - * Save the pertinent info locally. - */ - lp->node_wwn = - (((u_int64_t)pdb.pdb_nodename[0]) << 56) | - (((u_int64_t)pdb.pdb_nodename[1]) << 48) | - (((u_int64_t)pdb.pdb_nodename[2]) << 40) | - (((u_int64_t)pdb.pdb_nodename[3]) << 32) | - (((u_int64_t)pdb.pdb_nodename[4]) << 24) | - (((u_int64_t)pdb.pdb_nodename[5]) << 16) | - (((u_int64_t)pdb.pdb_nodename[6]) << 8) | - (((u_int64_t)pdb.pdb_nodename[7])); - lp->port_wwn = - (((u_int64_t)pdb.pdb_portname[0]) << 56) | - (((u_int64_t)pdb.pdb_portname[1]) << 48) | - (((u_int64_t)pdb.pdb_portname[2]) << 40) | - (((u_int64_t)pdb.pdb_portname[3]) << 32) | - (((u_int64_t)pdb.pdb_portname[4]) << 24) | - (((u_int64_t)pdb.pdb_portname[5]) << 16) | - (((u_int64_t)pdb.pdb_portname[6]) << 8) | - (((u_int64_t)pdb.pdb_portname[7])); - lp->roles = - (pdb.pdb_prli_svc3 & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT; - lp->portid = BITS2WORD(pdb.pdb_portid_bits); - lp->loopid = pdb.pdb_loopid; - /* - * Do a quick check to see whether this matches the saved port - * database for the same loopid. We do this here to save - * searching later (if possible). Note that this fails over - * time as things shuffle on the loop- we get the current - * loop state (where loop id as an index matches loop id in - * use) and then compare it to our saved database which - * never shifts. - */ - if (target >= 0 && isp_same_lportdb(lp, &fcp->portdb[target])) { - lp->valid = 1; } } + fcp->isp_loopstate = LOOP_SYNCING_PDB; /* * If we get this far, we've settled our differences with the f/w - * and we can say that the loop state is ready. + * (for local loop device) and we can say that the loop state is ready. */ - fcp->isp_loopstate = LOOP_READY; - /* - * Mark all of the permanent local loop database entries as invalid. - */ - for (loopid = 0; loopid < FL_PORT_ID; loopid++) { - fcp->portdb[loopid].valid = 0; + if (fcp->isp_topo == TOPO_NL_PORT) { + fcp->loop_seen_once = 1; + fcp->isp_loopstate = LOOP_READY; + return (0); } /* - * Now merge our local copy of the port database into our saved copy. - * Notify the outer layers of new devices arriving. + * Find all Fabric Entities that didn't make it from one scan to the + * next and let the world know they went away. Scan the whole database. */ - for (loopid = 0; loopid < prange; loopid++) { - int i; - - /* - * If we don't have a non-zero Port WWN, we're not here. - */ - if (tport[loopid].port_wwn == 0) { - continue; - } - - /* - * If we've already marked our tmp copy as valid, - * this means that we've decided that it's the - * same as our saved data base. This didn't include - * the 'valid' marking so we have set that here. - */ - if (tport[loopid].valid) { - fcp->portdb[loopid].valid = 1; - continue; - } - - /* - * For the purposes of deciding whether this is the - * 'same' device or not, we only search for an identical - * Port WWN. Node WWNs may or may not be the same as - * the Port WWN, and there may be multiple different - * Port WWNs with the same Node WWN. It would be chaos - * to have multiple identical Port WWNs, so we don't - * allow that. - */ - - for (i = 0; i < FL_PORT_ID; i++) { - int j; - if (fcp->portdb[i].port_wwn == 0) - continue; - if (fcp->portdb[i].port_wwn != tport[loopid].port_wwn) - continue; - /* - * We found this WWN elsewhere- it's changed - * loopids then. We don't change it's actual - * position in our cached port database- we - * just change the actual loop ID we'd use. - */ - if (fcp->portdb[i].loopid != loopid) { - isp_prt(isp, ISP_LOGINFO, portshift, i, - fcp->portdb[i].loopid, - fcp->portdb[i].portid, loopid, - tport[loopid].portid); - } - fcp->portdb[i].portid = tport[loopid].portid; - fcp->portdb[i].loopid = loopid; - fcp->portdb[i].valid = 1; - fcp->portdb[i].roles = tport[loopid].roles; - - /* - * Now make sure this Port WWN doesn't exist elsewhere - * in the port database. - */ - for (j = i+1; j < FL_PORT_ID; j++) { - if (fcp->portdb[i].port_wwn != - fcp->portdb[j].port_wwn) { - continue; - } - isp_prt(isp, ISP_LOGWARN, portdup, j, i); - /* - * Invalidate the 'old' *and* 'new' ones. - * This is really harsh and not quite right, - * but if this happens, we really don't know - * who is what at this point. - */ - fcp->portdb[i].valid = 0; - fcp->portdb[j].valid = 0; - } - break; - } - - /* - * If we didn't traverse the entire port database, - * then we found (and remapped) an existing entry. - * No need to notify anyone- go for the next one. - */ - if (i < FL_PORT_ID) { + for (lp = &fcp->portdb[0]; lp < &fcp->portdb[MAX_FC_TARG]; lp++) { + if (lp->was_fabric_dev && lp->fabric_dev == 0) { + loopid = lp - fcp->portdb; + lp->valid = 0; /* should already be set */ + (void) isp_async(isp, ISPASYNC_PROMENADE, &loopid); + MEMZERO((void *) lp, sizeof (*lp)); continue; } - - /* - * We've not found this Port WWN anywhere. It's a new entry. - * See if we can leave it where it is (with target == loopid). - */ - if (fcp->portdb[loopid].port_wwn != 0) { - for (lim = 0; lim < FL_PORT_ID; lim++) { - if (fcp->portdb[lim].port_wwn == 0) - break; - } - /* "Cannot Happen" */ - if (lim == FL_PORT_ID) { - isp_prt(isp, ISP_LOGWARN, "Remap Overflow"); - continue; - } - i = lim; - } else { - i = loopid; - } - - /* - * NB: The actual loopid we use here is loopid- we may - * in fact be at a completely different index (target). - */ - fcp->portdb[i].loopid = loopid; - fcp->portdb[i].port_wwn = tport[loopid].port_wwn; - fcp->portdb[i].node_wwn = tport[loopid].node_wwn; - fcp->portdb[i].roles = tport[loopid].roles; - fcp->portdb[i].portid = tport[loopid].portid; - fcp->portdb[i].valid = 1; - - /* - * Tell the outside world we've arrived. - */ - (void) isp_async(isp, ISPASYNC_LOGGED_INOUT, &i); + lp->was_fabric_dev = lp->fabric_dev; } - /* - * Now find all previously used targets that are now invalid and - * notify the outer layers that they're gone. - */ - for (lp = fcp->portdb; lp < &fcp->portdb[prange]; lp++) { - if (lp->valid || lp->port_wwn == 0) - continue; + if (fcp->isp_topo == TOPO_FL_PORT) + base = FC_SNS_ID+1; + else + base = 0; - /* - * Tell the outside world we've gone away. - */ - loopid = lp - fcp->portdb; - (void) isp_async(isp, ISPASYNC_LOGGED_INOUT, &loopid); - MEMZERO((void *) lp, sizeof (*lp)); - } + if (fcp->isp_topo == TOPO_N_PORT) + lim = 1; + else + lim = MAX_FC_TARG; -#ifdef ISP2100_FABRIC /* - * Now log in any fabric devices + * Now log in any fabric devices that the outer layer has + * left for us to see. This seems the most sane policy + * for the moment. */ - for (lp = &fcp->portdb[frange]; - lp < &fcp->portdb[MAX_FC_TARG]; lp++) { + for (lp = &fcp->portdb[base]; lp < &fcp->portdb[lim]; lp++) { u_int32_t portid; mbreg_t mbs; @@ -1801,25 +1690,38 @@ isp_pdb_sync(isp, target) } } + if (fcp->isp_fwstate != FW_READY || + fcp->isp_loopstate != LOOP_SYNCING_PDB) { + return (-1); + } + /* * Force a logout if we were logged in. */ if (lp->loggedin) { - mbs.param[0] = MBOX_FABRIC_LOGOUT; - mbs.param[1] = lp->loopid << 8; - mbs.param[2] = 0; - mbs.param[3] = 0; - isp_mboxcmd(isp, &mbs, MBLOGNONE); + if (isp_getpdb(isp, lp->loopid, &pdb) == 0) { + mbs.param[0] = MBOX_FABRIC_LOGOUT; + mbs.param[1] = lp->loopid << 8; + mbs.param[2] = 0; + mbs.param[3] = 0; + isp_mboxcmd(isp, &mbs, MBLOGNONE); + lp->loggedin = 0; + isp_prt(isp, ISP_LOGINFO, plogout, + (int) (lp - fcp->portdb), lp->loopid, + lp->portid); + } lp->loggedin = 0; - isp_prt(isp, ISP_LOGINFO, plogout, - (int) (lp - fcp->portdb), lp->loopid, lp->portid); + if (fcp->isp_fwstate != FW_READY || + fcp->isp_loopstate != LOOP_SYNCING_PDB) { + return (-1); + } } /* * And log in.... */ loopid = lp - fcp->portdb; - lp->loopid = 0; + lp->loopid = FL_PORT_ID; do { mbs.param[0] = MBOX_FABRIC_LOGIN; mbs.param[1] = loopid << 8; @@ -1831,6 +1733,10 @@ isp_pdb_sync(isp, target) } isp_mboxcmd(isp, &mbs, MBLOGALL & ~(MBOX_LOOP_ID_USED | MBOX_PORT_ID_USED | MBOX_COMMAND_ERROR)); + if (fcp->isp_fwstate != FW_READY || + fcp->isp_loopstate != LOOP_SYNCING_PDB) { + return (-1); + } switch (mbs.param[0]) { case MBOX_LOOP_ID_USED: /* @@ -1867,14 +1773,15 @@ isp_pdb_sync(isp, target) loopid = MAX_FC_TARG; break; } - } while (lp->loopid == 0 && loopid < MAX_FC_TARG); + } while (lp->loopid == FL_PORT_ID && loopid < MAX_FC_TARG); /* * If we get here and we haven't set a Loop ID, * we failed to log into this device. */ - if (lp->loopid == 0) { + if (lp->loopid == FL_PORT_ID) { + lp->loopid = 0; continue; } @@ -1886,6 +1793,11 @@ isp_pdb_sync(isp, target) goto dump_em; } + if (fcp->isp_fwstate != FW_READY || + fcp->isp_loopstate != LOOP_SYNCING_PDB) { + return (-1); + } + if (pdb.pdb_loopid != lp->loopid) { isp_prt(isp, ISP_LOGWARN, pdbmfail1, lp->portid, pdb.pdb_loopid); @@ -1924,7 +1836,7 @@ isp_pdb_sync(isp, target) if (lp->node_wwn && lp->port_wwn) { lp->valid = 1; loopid = lp - fcp->portdb; - (void) isp_async(isp, ISPASYNC_LOGGED_INOUT, &loopid); + (void) isp_async(isp, ISPASYNC_PROMENADE, &loopid); continue; } dump_em: @@ -1936,34 +1848,317 @@ dump_em: mbs.param[2] = 0; mbs.param[3] = 0; isp_mboxcmd(isp, &mbs, MBLOGNONE); + if (fcp->isp_fwstate != FW_READY || + fcp->isp_loopstate != LOOP_SYNCING_PDB) { + return (-1); + } } -#endif /* * If we get here, we've for sure seen not only a valid loop * but know what is or isn't on it, so mark this for usage * in isp_start. */ fcp->loop_seen_once = 1; + fcp->isp_loopstate = LOOP_READY; + return (0); +} + +static int +isp_scan_loop(isp) + struct ispsoftc *isp; +{ + struct lportdb *lp; + fcparam *fcp = isp->isp_param; + isp_pdb_t pdb; + int loopid, lim, hival; + + switch (fcp->isp_topo) { + case TOPO_NL_PORT: + hival = FL_PORT_ID; + break; + case TOPO_N_PORT: + hival = 2; + break; + case TOPO_FL_PORT: + hival = FC_PORT_ID; + break; + default: + fcp->isp_loopstate = LOOP_LSCAN_DONE; + return (0); + } + fcp->isp_loopstate = LOOP_SCANNING_LOOP; + + /* + * make sure the temp port database is clean... + */ + MEMZERO((void *)fcp->tport, sizeof (fcp->tport)); + + /* + * Run through the local loop ports and get port database info + * for each loop ID. + * + * There's a somewhat unexplained situation where the f/w passes back + * the wrong database entity- if that happens, just restart (up to + * FL_PORT_ID times). + */ + for (lim = loopid = 0; loopid < hival; loopid++) { + lp = &fcp->tport[loopid]; + + /* + * Don't even try for ourselves... + */ + if (loopid == fcp->isp_loopid) + continue; + + lp->node_wwn = isp_get_portname(isp, loopid, 1); + if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) + return (-1); + if (lp->node_wwn == 0) + continue; + lp->port_wwn = isp_get_portname(isp, loopid, 0); + if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) + return (-1); + if (lp->port_wwn == 0) { + lp->node_wwn = 0; + continue; + } + + /* + * Get an entry.... + */ + if (isp_getpdb(isp, loopid, &pdb) != 0) { + if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) + return (-1); + continue; + } + if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) { + return (-1); + } + + /* + * If the returned database element doesn't match what we + * asked for, restart the process entirely (up to a point...). + */ + if (pdb.pdb_loopid != loopid) { + loopid = 0; + if (lim++ < hival) { + continue; + } + isp_prt(isp, ISP_LOGWARN, + "giving up on synchronizing the port database"); + return (-1); + } + + /* + * Save the pertinent info locally. + */ + lp->node_wwn = + (((u_int64_t)pdb.pdb_nodename[0]) << 56) | + (((u_int64_t)pdb.pdb_nodename[1]) << 48) | + (((u_int64_t)pdb.pdb_nodename[2]) << 40) | + (((u_int64_t)pdb.pdb_nodename[3]) << 32) | + (((u_int64_t)pdb.pdb_nodename[4]) << 24) | + (((u_int64_t)pdb.pdb_nodename[5]) << 16) | + (((u_int64_t)pdb.pdb_nodename[6]) << 8) | + (((u_int64_t)pdb.pdb_nodename[7])); + lp->port_wwn = + (((u_int64_t)pdb.pdb_portname[0]) << 56) | + (((u_int64_t)pdb.pdb_portname[1]) << 48) | + (((u_int64_t)pdb.pdb_portname[2]) << 40) | + (((u_int64_t)pdb.pdb_portname[3]) << 32) | + (((u_int64_t)pdb.pdb_portname[4]) << 24) | + (((u_int64_t)pdb.pdb_portname[5]) << 16) | + (((u_int64_t)pdb.pdb_portname[6]) << 8) | + (((u_int64_t)pdb.pdb_portname[7])); + lp->roles = + (pdb.pdb_prli_svc3 & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT; + lp->portid = BITS2WORD(pdb.pdb_portid_bits); + lp->loopid = pdb.pdb_loopid; + } + + /* + * Mark all of the permanent local loop database entries as invalid + * (except our own entry). + */ + for (loopid = 0; loopid < hival; loopid++) { + if (loopid == fcp->isp_iid) { + fcp->portdb[loopid].valid = 1; + fcp->portdb[loopid].loopid = fcp->isp_loopid; + continue; + } + fcp->portdb[loopid].valid = 0; + } + + /* + * Now merge our local copy of the port database into our saved copy. + * Notify the outer layers of new devices arriving. + */ + for (loopid = 0; loopid < hival; loopid++) { + int i; + + /* + * If we don't have a non-zero Port WWN, we're not here. + */ + if (fcp->tport[loopid].port_wwn == 0) { + continue; + } + + /* + * Skip ourselves. + */ + if (loopid == fcp->isp_iid) { + continue; + } + + /* + * For the purposes of deciding whether this is the + * 'same' device or not, we only search for an identical + * Port WWN. Node WWNs may or may not be the same as + * the Port WWN, and there may be multiple different + * Port WWNs with the same Node WWN. It would be chaos + * to have multiple identical Port WWNs, so we don't + * allow that. + */ + + for (i = 0; i < hival; i++) { + int j; + if (fcp->portdb[i].port_wwn == 0) + continue; + if (fcp->portdb[i].port_wwn != + fcp->tport[loopid].port_wwn) + continue; + /* + * We found this WWN elsewhere- it's changed + * loopids then. We don't change it's actual + * position in our cached port database- we + * just change the actual loop ID we'd use. + */ + if (fcp->portdb[i].loopid != loopid) { + isp_prt(isp, ISP_LOGINFO, portshift, i, + fcp->portdb[i].loopid, + fcp->portdb[i].portid, loopid, + fcp->tport[loopid].portid); + } + fcp->portdb[i].portid = fcp->tport[loopid].portid; + fcp->portdb[i].loopid = loopid; + fcp->portdb[i].valid = 1; + fcp->portdb[i].roles = fcp->tport[loopid].roles; + + /* + * Now make sure this Port WWN doesn't exist elsewhere + * in the port database. + */ + for (j = i+1; j < hival; j++) { + if (fcp->portdb[i].port_wwn != + fcp->portdb[j].port_wwn) { + continue; + } + isp_prt(isp, ISP_LOGWARN, portdup, j, i); + /* + * Invalidate the 'old' *and* 'new' ones. + * This is really harsh and not quite right, + * but if this happens, we really don't know + * who is what at this point. + */ + fcp->portdb[i].valid = 0; + fcp->portdb[j].valid = 0; + } + break; + } + + /* + * If we didn't traverse the entire port database, + * then we found (and remapped) an existing entry. + * No need to notify anyone- go for the next one. + */ + if (i < hival) { + continue; + } + + /* + * We've not found this Port WWN anywhere. It's a new entry. + * See if we can leave it where it is (with target == loopid). + */ + if (fcp->portdb[loopid].port_wwn != 0) { + for (lim = 0; lim < hival; lim++) { + if (fcp->portdb[lim].port_wwn == 0) + break; + } + /* "Cannot Happen" */ + if (lim == hival) { + isp_prt(isp, ISP_LOGWARN, "Remap Overflow"); + continue; + } + i = lim; + } else { + i = loopid; + } + + /* + * NB: The actual loopid we use here is loopid- we may + * in fact be at a completely different index (target). + */ + fcp->portdb[i].loopid = loopid; + fcp->portdb[i].port_wwn = fcp->tport[loopid].port_wwn; + fcp->portdb[i].node_wwn = fcp->tport[loopid].node_wwn; + fcp->portdb[i].roles = fcp->tport[loopid].roles; + fcp->portdb[i].portid = fcp->tport[loopid].portid; + fcp->portdb[i].valid = 1; + + /* + * Tell the outside world we've arrived. + */ + (void) isp_async(isp, ISPASYNC_PROMENADE, &i); + } + + /* + * Now find all previously used targets that are now invalid and + * notify the outer layers that they're gone. + */ + for (lp = &fcp->portdb[0]; lp < &fcp->portdb[hival]; lp++) { + if (lp->valid || lp->port_wwn == 0) { + continue; + } + + /* + * Tell the outside world we've gone + * away and erase our pdb entry. + * + */ + loopid = lp - fcp->portdb; + (void) isp_async(isp, ISPASYNC_PROMENADE, &loopid); + MEMZERO((void *) lp, sizeof (*lp)); + } + fcp->isp_loopstate = LOOP_LSCAN_DONE; return (0); } -#ifdef ISP2100_FABRIC static int isp_scan_fabric(isp) struct ispsoftc *isp; { fcparam *fcp = isp->isp_param; - u_int32_t portid, first_nz_portid; + u_int32_t portid, first_portid; sns_screq_t *reqp; sns_scrsp_t *resp; mbreg_t mbs; - int hicap; + int hicap, first_portid_seen; + + if (fcp->isp_onfabric == 0) { + fcp->isp_loopstate = LOOP_FSCAN_DONE; + return (0); + } reqp = (sns_screq_t *) fcp->isp_scratch; resp = (sns_scrsp_t *) (&((char *)fcp->isp_scratch)[0x100]); - first_nz_portid = portid = fcp->isp_portid; + /* + * Since Port IDs are 24 bits, we can check against having seen + * anything yet with this value. + */ + first_portid = portid = fcp->isp_portid; + fcp->isp_loopstate = LOOP_SCANNING_FABRIC; - for (hicap = 0; hicap < 1024; hicap++) { + for (first_portid_seen = hicap = 0; hicap < 65535; hicap++) { MEMZERO((void *) reqp, SNS_GAN_REQ_SIZE); reqp->snscb_rblen = SNS_GAN_RESP_SIZE >> 1; reqp->snscb_addr[RQRSP_ADDR0015] = @@ -1983,25 +2178,32 @@ isp_scan_fabric(isp) mbs.param[7] = 0; isp_mboxcmd(isp, &mbs, MBLOGALL); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + if (fcp->isp_loopstate == LOOP_SCANNING_FABRIC) { + fcp->isp_loopstate = LOOP_PDB_RCVD; + } + return (-1); + } + if (fcp->isp_fwstate != FW_READY || + fcp->isp_loopstate < LOOP_SCANNING_FABRIC) { return (-1); } ISP_UNSWIZZLE_SNS_RSP(isp, resp, SNS_GAN_RESP_SIZE >> 1); portid = (((u_int32_t) resp->snscb_port_id[0]) << 16) | (((u_int32_t) resp->snscb_port_id[1]) << 8) | (((u_int32_t) resp->snscb_port_id[2])); - if (isp_async(isp, ISPASYNC_FABRIC_DEV, resp)) { - return (-1); - } - if (first_nz_portid == 0 && portid) { - first_nz_portid = portid; - } - if (first_nz_portid == portid) { + (void) isp_async(isp, ISPASYNC_FABRIC_DEV, resp); + if (first_portid == portid) { + fcp->isp_loopstate = LOOP_FSCAN_DONE; return (0); } } + + isp_prt(isp, ISP_LOGWARN, "broken fabric nameserver...*wheeze*..."); + /* * We either have a broken name server or a huge fabric if we get here. */ + fcp->isp_loopstate = LOOP_FSCAN_DONE; return (0); } @@ -2034,10 +2236,10 @@ isp_register_fc4_type(struct ispsoftc *isp) mbs.param[7] = 0; isp_mboxcmd(isp, &mbs, MBLOGALL); if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGINFO, "Register FC4 types succeeded"); + isp_prt(isp, ISP_LOGDEBUG0, "Register FC4 types succeeded"); } } -#endif + /* * Start a command. Locking is assumed done in the caller. */ @@ -2060,6 +2262,19 @@ isp_start(xs) XS_INITERR(xs); isp = XS_ISP(xs); + + /* + * Check to make sure we're supporting initiator role. + */ + if ((isp->isp_role & ISP_ROLE_INITIATOR) == 0) { + XS_SETERR(xs, HBA_SELTIMEOUT); + return (CMD_COMPLETE); + } + + /* + * Now make sure we're running. + */ + if (isp->isp_state != ISP_RUNSTATE) { isp_prt(isp, ISP_LOGERR, "Adapter not at RUNSTATE"); XS_SETERR(xs, HBA_BOTCH); @@ -2089,7 +2304,32 @@ isp_start(xs) if (IS_FC(isp)) { fcparam *fcp = isp->isp_param; struct lportdb *lp; -#if defined(ISP2100_FABRIC) + /* + * Check for f/w being in ready state. If the f/w + * isn't in ready state, then we don't know our + * loop ID and the f/w hasn't completed logging + * into all targets on the loop. If this is the + * case, then bounce the command. We pretend this is + * a SELECTION TIMEOUT error if we've never gone to + * FW_READY state at all- in this case we may not + * be hooked to a loop at all and we shouldn't hang + * the machine for this. Otherwise, defer this command + * until later. + */ + if (fcp->isp_fwstate != FW_READY) { + /* + * Give ourselves at most a 250ms delay. + */ + if (isp_fclink_test(isp, 250000)) { + XS_SETERR(xs, HBA_SELTIMEOUT); + if (fcp->loop_seen_once) { + return (CMD_RQLATER); + } else { + return (CMD_COMPLETE); + } + } + } + /* * If we're not on a Fabric, we can't have a target * above FL_PORT_ID-1. @@ -2116,32 +2356,6 @@ isp_start(xs) return (CMD_COMPLETE); } } -#endif - /* - * Check for f/w being in ready state. If the f/w - * isn't in ready state, then we don't know our - * loop ID and the f/w hasn't completed logging - * into all targets on the loop. If this is the - * case, then bounce the command. We pretend this is - * a SELECTION TIMEOUT error if we've never gone to - * FW_READY state at all- in this case we may not - * be hooked to a loop at all and we shouldn't hang - * the machine for this. Otherwise, defer this command - * until later. - */ - if (fcp->isp_fwstate != FW_READY) { - /* - * Give ourselves at most a 250ms delay. - */ - if (isp_fclink_test(isp, 250000)) { - XS_SETERR(xs, HBA_SELTIMEOUT); - if (fcp->loop_seen_once) { - return (CMD_RQLATER); - } else { - return (CMD_COMPLETE); - } - } - } /* * If our loop state is such that we haven't yet received @@ -2161,15 +2375,44 @@ isp_start(xs) } /* + * If we're in the middle of loop or fabric scanning + * or merging the port databases, retry this command later. + */ + if (fcp->isp_loopstate == LOOP_SCANNING_FABRIC || + fcp->isp_loopstate == LOOP_SCANNING_LOOP || + fcp->isp_loopstate == LOOP_SYNCING_PDB) { + return (CMD_RQLATER); + } + + /* + * If our loop state is now such that we've just now + * received a Port Database Change notification, then + * we have to go off and (re)scan the fabric. We back + * out and try again later if this doesn't work. + */ + if (fcp->isp_loopstate == LOOP_PDB_RCVD && fcp->isp_onfabric) { + if (isp_scan_fabric(isp)) { + return (CMD_RQLATER); + } + if (fcp->isp_fwstate != FW_READY || + fcp->isp_loopstate < LOOP_PDB_RCVD) { + return (CMD_RQLATER); + } + } + + /* * If our loop state is now such that we've just now * received a Port Database Change notification, then * we have to go off and (re)synchronize our port * database. */ - if (fcp->isp_loopstate == LOOP_PDB_RCVD) { - if (isp_pdb_sync(isp, target)) { - XS_SETERR(xs, HBA_SELTIMEOUT); - return (CMD_COMPLETE); + if (fcp->isp_loopstate < LOOP_READY) { + if (isp_pdb_sync(isp)) { + return (CMD_RQLATER); + } + if (fcp->isp_fwstate != FW_READY || + fcp->isp_loopstate != LOOP_READY) { + return (CMD_RQLATER); } } @@ -2193,7 +2436,7 @@ isp_start(xs) return (CMD_COMPLETE); } /* - * Now turn target into what the actual loop ID is. + * Now turn target into what the actual Loop ID is. */ target = lp->loopid; } @@ -2328,8 +2571,9 @@ isp_start(xs) } XS_SETERR(xs, HBA_NOERROR); isp_prt(isp, ISP_LOGDEBUG2, - "START cmd for %d.%d.%d cmd 0x%x datalen %d", - XS_CHANNEL(xs), target, XS_LUN(xs), XS_CDBP(xs)[0], XS_XFRLEN(xs)); + "START cmd for %d.%d.%d cmd 0x%x datalen %ld", + XS_CHANNEL(xs), target, XS_LUN(xs), XS_CDBP(xs)[0], + (long) XS_XFRLEN(xs)); ISP_ADD_REQUEST(isp, iptr); isp->isp_nactive++; if (isp->isp_sendmarker) @@ -2439,25 +2683,66 @@ isp_control(isp, ctl, arg) break; case ISPCTL_UPDATE_PARAMS: + isp_update(isp); return (0); case ISPCTL_FCLINK_TEST: + if (IS_FC(isp)) { int usdelay = (arg)? *((int *) arg) : 250000; return (isp_fclink_test(isp, usdelay)); } break; + case ISPCTL_SCAN_FABRIC: + + if (IS_FC(isp)) { + return (isp_scan_fabric(isp)); + } + break; + + case ISPCTL_SCAN_LOOP: + + if (IS_FC(isp)) { + return (isp_scan_loop(isp)); + } + break; + case ISPCTL_PDB_SYNC: + + if (IS_FC(isp)) { + return (isp_pdb_sync(isp)); + } + break; + + case ISPCTL_SEND_LIP: + if (IS_FC(isp)) { - return (isp_pdb_sync(isp, -1)); + mbs.param[0] = MBOX_INIT_LIP; + isp_mboxcmd(isp, &mbs, MBLOGALL); + if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { + return (0); + } + } + break; + + case ISPCTL_GET_POSMAP: + + if (IS_FC(isp) && arg) { + return (isp_getmap(isp, arg)); } break; + #ifdef ISP_TARGET_MODE case ISPCTL_TOGGLE_TMODE: { int ena = *(int *)arg; + + /* + * We don't check/set against role here- that's the + * responsibility for the outer layer to coordinate. + */ if (IS_SCSI(isp)) { mbs.param[0] = MBOX_ENABLE_TARGET_MODE; mbs.param[1] = (ena)? ENABLE_TARGET_FLAG : 0; @@ -2465,33 +2750,6 @@ isp_control(isp, ctl, arg) if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { break; } - } else { - fcparam *fcp = isp->isp_param; - /* - * We assume somebody has quiesced this bus. - */ - if (ena) { - if (fcp->isp_fwoptions & ICBOPT_TGT_ENABLE) { - return (0); - } - fcp->isp_fwoptions |= ICBOPT_TGT_ENABLE; - } else { - if (!(fcp->isp_fwoptions & ICBOPT_TGT_ENABLE)) { - return (0); - } - fcp->isp_fwoptions &= ~ICBOPT_TGT_ENABLE; - } - isp->isp_state = ISP_NILSTATE; - isp_reset(isp); - if (isp->isp_state != ISP_RESETSTATE) { - break; - } - isp_init(isp); - if ((isp->isp_confopts & ISP_CFG_NOINIT) == 0) { - if (isp->isp_state == ISP_INITSTATE) { - isp->isp_state = ISP_RUNSTATE; - } - } } return (0); } @@ -2805,10 +3063,13 @@ isp_intr(arg) (*XS_STSP(xs) == SCSI_CHECK) && (sp->req_scsi_status & RQCS_SV)) { XS_SAVE_SENSE(xs, sp); + /* solely for the benefit of debug */ + sp->req_state_flags |= RQSF_GOT_SENSE; } } - isp_prt(isp, ISP_LOGDEBUG2, "asked for %d got resid %d", - XS_XFRLEN(xs), sp->req_resid); + isp_prt(isp, ISP_LOGDEBUG2, + "asked for %ld got resid %ld", (long) XS_XFRLEN(xs), + (long) sp->req_resid); break; case RQSTYPE_REQUEST: if (sp->req_header.rqs_flags & RQSFLAG_FULL) { @@ -2840,14 +3101,15 @@ isp_intr(arg) } if (((isp->isp_dblev & (ISP_LOGDEBUG2|ISP_LOGDEBUG3))) || - ((isp->isp_dblev & ISP_LOGDEBUG1) && !XS_NOERR(xs))) { + ((isp->isp_dblev & ISP_LOGDEBUG1) && ((!XS_NOERR(xs)) || + (*XS_STSP(xs) != SCSI_GOOD)))) { char skey; if (sp->req_state_flags & RQSF_GOT_SENSE) { skey = XS_SNSKEY(xs) & 0xf; if (skey < 10) skey += '0'; else - skey += 'a'; + skey += 'a' - 10; } else if (*XS_STSP(xs) == SCSI_CHECK) { skey = '?'; } else { @@ -2919,7 +3181,7 @@ isp_parse_async(isp, mbox) "Internal FW Error @ RISC Addr 0x%x", mbox); isp_reinit(isp); #ifdef ISP_TARGET_MODE - isp_target_async(isp, bus, mbox); + isp_target_async(isp, bus, ASYNC_SYSTEM_ERROR); #endif /* no point continuing after this */ return (-1); @@ -3082,7 +3344,7 @@ isp_parse_async(isp, mbox) isp->isp_sendmarker = 1; FCPARAM(isp)->isp_loopstate = LOOP_PDB_RCVD; isp_mark_getpdb_all(isp); - isp_async(isp, ISPASYNC_CHANGE_NOTIFY, (void *) 0); + isp_async(isp, ISPASYNC_CHANGE_NOTIFY, ISPASYNC_CHANGE_PDB); break; case ASYNC_CHANGE_NOTIFY: @@ -3091,18 +3353,19 @@ isp_parse_async(isp, mbox) */ FCPARAM(isp)->isp_loopstate = LOOP_PDB_RCVD; isp_mark_getpdb_all(isp); - isp_async(isp, ISPASYNC_CHANGE_NOTIFY, (void *) 1); + isp_async(isp, ISPASYNC_CHANGE_NOTIFY, ISPASYNC_CHANGE_SNS); break; case ASYNC_PTPMODE: if (FCPARAM(isp)->isp_onfabric) - FCPARAM(isp)->isp_topo = TOPO_N_PORT; - else FCPARAM(isp)->isp_topo = TOPO_F_PORT; + else + FCPARAM(isp)->isp_topo = TOPO_N_PORT; isp_mark_getpdb_all(isp); isp->isp_sendmarker = 1; FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; FCPARAM(isp)->isp_loopstate = LOOP_LIP_RCVD; + isp_async(isp, ISPASYNC_CHANGE_NOTIFY, ISPASYNC_CHANGE_OTHER); #ifdef ISP_TARGET_MODE isp_target_async(isp, bus, mbox); #endif @@ -3111,16 +3374,19 @@ isp_parse_async(isp, mbox) case ASYNC_CONNMODE: mbox = ISP_READ(isp, OUTMAILBOX1); + isp_mark_getpdb_all(isp); switch (mbox) { case ISP_CONN_LOOP: - isp_prt(isp, ISP_LOGINFO, "Point-to-Point->Loop mode"); + isp_prt(isp, ISP_LOGINFO, + "Point-to-Point -> Loop mode"); break; case ISP_CONN_PTP: - isp_prt(isp, ISP_LOGINFO, "Loop->Point-to-Point mode"); + isp_prt(isp, ISP_LOGINFO, + "Loop -> Point-to-Point mode"); break; case ISP_CONN_BADLIP: isp_prt(isp, ISP_LOGWARN, - "Point-to-Point->Loop mode (1)"); + "Point-to-Point -> Loop mode (BAD LIP)"); break; case ISP_CONN_FATAL: isp_prt(isp, ISP_LOGERR, "FATAL CONNECTION ERROR"); @@ -3130,11 +3396,19 @@ isp_parse_async(isp, mbox) #endif /* no point continuing after this */ return (-1); - case ISP_CONN_LOOPBACK: isp_prt(isp, ISP_LOGWARN, "Looped Back in Point-to-Point mode"); + break; + default: + isp_prt(isp, ISP_LOGWARN, + "Unknown connection mode (0x%x)", mbox); + break; } + isp_async(isp, ISPASYNC_CHANGE_NOTIFY, ISPASYNC_CHANGE_OTHER); + isp->isp_sendmarker = 1; + FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; + FCPARAM(isp)->isp_loopstate = LOOP_LIP_RCVD; break; default: @@ -4059,6 +4333,8 @@ isp_mboxcmd(isp, mbp, logmask) isp->isp_mboxtmp[box] = mbp->param[box] = 0; } + isp->isp_lastmbxcmd = opcode; + /* * We assume that we can't overwrite a previous command. */ @@ -4159,8 +4435,9 @@ isp_fw_state(isp) mbs.param[0] = MBOX_GET_FW_STATE; isp_mboxcmd(isp, &mbs, MBLOGALL); - if (mbs.param[0] == MBOX_COMMAND_COMPLETE) + if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { fcp->isp_fwstate = mbs.param[1]; + } } } @@ -4568,15 +4845,21 @@ isp_reinit(isp) u_int32_t handle; isp_reset(isp); - if (isp->isp_state == ISP_RESETSTATE) { - isp_init(isp); - if (isp->isp_state == ISP_INITSTATE) { - isp->isp_state = ISP_RUNSTATE; - } + if (isp->isp_state != ISP_RESETSTATE) { + isp_prt(isp, ISP_LOGERR, "isp_reinit cannot reset card"); + goto skip; + } + isp_init(isp); + if (isp->isp_role == ISP_ROLE_NONE) { + goto skip; + } + if (isp->isp_state == ISP_INITSTATE) { + isp->isp_state = ISP_RUNSTATE; } if (isp->isp_state != ISP_RUNSTATE) { - isp_prt(isp, ISP_LOGERR, "isp_reinit cannot restart ISP"); + isp_prt(isp, ISP_LOGERR, "isp_reinit cannot restart card"); } +skip: isp->isp_nactive = 0; for (handle = 1; (int) handle <= isp->isp_maxcmds; handle++) { |