diff options
Diffstat (limited to 'sys/dev/ic/isp.c')
-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++) { |