From 06820e490f119d5888ba6860c535fb98be037e68 Mon Sep 17 00:00:00 2001 From: mjacob Date: Mon, 12 Feb 2001 23:45:00 +0000 Subject: 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. --- sys/dev/ic/isp.c | 1361 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 822 insertions(+), 539 deletions(-) (limited to 'sys/dev') 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,551 +1547,618 @@ 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. + * Make sure we're okay for doing this right now. */ + if (fcp->isp_loopstate != LOOP_PDB_RCVD && + fcp->isp_loopstate != LOOP_FSCAN_DONE && + fcp->isp_loopstate != LOOP_LSCAN_DONE) { + return (-1); + } + + 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); + } + } + } + fcp->isp_loopstate = LOOP_SYNCING_PDB; + /* - * (Re)discover all fabric devices + * If we get this far, we've settled our differences with the f/w + * (for local loop device) and we can say that the loop state is ready. */ - 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_topo == TOPO_NL_PORT) { + fcp->loop_seen_once = 1; + fcp->isp_loopstate = LOOP_READY; + return (0); } /* - * 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). + * 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. */ - tport = fcp->tport; + 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; + } + lp->was_fabric_dev = lp->fabric_dev; + } + + if (fcp->isp_topo == TOPO_FL_PORT) + base = FC_SNS_ID+1; + else + base = 0; + + if (fcp->isp_topo == TOPO_N_PORT) + lim = 1; + else + lim = MAX_FC_TARG; /* - * make sure the temp port database is clean... + * 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. */ - MEMZERO((void *) tport, sizeof (tport)); + for (lp = &fcp->portdb[base]; lp < &fcp->portdb[lim]; lp++) { + u_int32_t portid; + mbreg_t mbs; - 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) + loopid = lp - fcp->portdb; + if (loopid >= FL_PORT_ID && loopid <= FC_SNS_ID) { continue; - lp->port_wwn = isp_get_portname(isp, loopid, 0); - if (fcp->isp_loopstate < LOOP_PDB_RCVD) - return (-1); + } + + /* + * Anything here? + */ if (lp->port_wwn == 0) { - lp->node_wwn = 0; continue; } /* - * Get an entry.... + * Don't try to log into yourself. */ - if (isp_getpdb(isp, loopid, &pdb) != 0) { - if (fcp->isp_loopstate < LOOP_PDB_RCVD) - return (-1); + if ((portid = lp->portid) == fcp->isp_portid) { 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 we'd been logged in- see if we still are and we haven't + * changed. If so, no need to log ourselves out, etc.. + * + * Unfortunately, our charming Qlogic f/w has decided to + * return a valid port database entry for a fabric device + * that has, in fact, gone away. And it hangs trying to + * log it out. */ - if (pdb.pdb_loopid != loopid) { - loopid = 0; - if (lim++ < FL_PORT_ID) { + if (lp->loggedin && + isp_getpdb(isp, lp->loopid, &pdb) == 0) { + int nrole; + u_int64_t nwwnn, nwwpn; + nwwnn = + (((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])); + nwwpn = + (((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])); + nrole = (pdb.pdb_prli_svc3 & SVC3_ROLE_MASK) >> + SVC3_ROLE_SHIFT; + if (pdb.pdb_loopid == lp->loopid && lp->portid == + (u_int32_t) BITS2WORD(pdb.pdb_portid_bits) && + nwwnn == lp->node_wwn && nwwpn == lp->port_wwn && + lp->roles == nrole) { + lp->loggedin = lp->valid = 1; + isp_prt(isp, ISP_LOGINFO, lretained, + (int) (lp - fcp->portdb), + (int) lp->loopid, lp->portid); 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; + if (fcp->isp_fwstate != FW_READY || + fcp->isp_loopstate != LOOP_SYNCING_PDB) { + return (-1); } - } - - /* - * If we get this far, we've settled our differences with the f/w - * 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; - } - - /* - * 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 < prange; loopid++) { - int i; /* - * If we don't have a non-zero Port WWN, we're not here. + * Force a logout if we were logged in. */ - if (tport[loopid].port_wwn == 0) { - continue; + if (lp->loggedin) { + 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; + if (fcp->isp_fwstate != FW_READY || + fcp->isp_loopstate != LOOP_SYNCING_PDB) { + return (-1); + } } /* - * 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. + * And log in.... */ - 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); + loopid = lp - fcp->portdb; + lp->loopid = FL_PORT_ID; + do { + mbs.param[0] = MBOX_FABRIC_LOGIN; + mbs.param[1] = loopid << 8; + mbs.param[2] = portid >> 16; + mbs.param[3] = portid & 0xffff; + if (IS_2200(isp)) { + /* only issue a PLOGI if not logged in */ + mbs.param[1] |= 0x1; } - 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); + 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: /* - * 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. + * Try the next available loop id. */ - fcp->portdb[i].valid = 0; - fcp->portdb[j].valid = 0; + loopid++; + break; + case MBOX_PORT_ID_USED: + /* + * This port is already logged in. + * Snaffle the loop id it's using if it's + * nonzero, otherwise we're hosed. + */ + if (mbs.param[1] != 0) { + loopid = mbs.param[1]; + isp_prt(isp, ISP_LOGINFO, retained, + loopid, (int) (lp - fcp->portdb), + lp->portid); + } else { + loopid = MAX_FC_TARG; + break; + } + /* FALLTHROUGH */ + case MBOX_COMMAND_COMPLETE: + lp->loggedin = 1; + lp->loopid = loopid; + break; + case MBOX_COMMAND_ERROR: + isp_prt(isp, ISP_LOGINFO, plogierr, + portid, mbs.param[1]); + /* FALLTHROUGH */ + case MBOX_ALL_IDS_USED: /* We're outta IDs */ + default: + loopid = MAX_FC_TARG; + break; } - break; - } + } while (lp->loopid == FL_PORT_ID && loopid < MAX_FC_TARG); /* - * 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 we get here and we haven't set a Loop ID, + * we failed to log into this device. */ - if (i < FL_PORT_ID) { + + if (lp->loopid == FL_PORT_ID) { + lp->loopid = 0; 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). + * Make sure we can get the approriate port information. */ - 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; + if (isp_getpdb(isp, lp->loopid, &pdb) != 0) { + isp_prt(isp, ISP_LOGWARN, nopdb, lp->portid); + goto dump_em; } - /* - * 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; + 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); + goto dump_em; + } + + if (lp->portid != (u_int32_t) BITS2WORD(pdb.pdb_portid_bits)) { + isp_prt(isp, ISP_LOGWARN, pdbmfail2, + lp->portid, BITS2WORD(pdb.pdb_portid_bits)); + goto dump_em; + } + lp->roles = + (pdb.pdb_prli_svc3 & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT; + 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])); /* - * Tell the outside world we've arrived. + * Check to make sure this all makes sense. */ - (void) isp_async(isp, ISPASYNC_LOGGED_INOUT, &i); + if (lp->node_wwn && lp->port_wwn) { + lp->valid = 1; + loopid = lp - fcp->portdb; + (void) isp_async(isp, ISPASYNC_PROMENADE, &loopid); + continue; + } +dump_em: + lp->valid = 0; + isp_prt(isp, ISP_LOGINFO, + ldumped, loopid, lp->loopid, lp->portid); + 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 (fcp->isp_fwstate != FW_READY || + fcp->isp_loopstate != LOOP_SYNCING_PDB) { + return (-1); + } } - /* - * Now find all previously used targets that are now invalid and - * notify the outer layers that they're gone. + * 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. */ - for (lp = fcp->portdb; lp < &fcp->portdb[prange]; lp++) { - if (lp->valid || lp->port_wwn == 0) - continue; + fcp->loop_seen_once = 1; + fcp->isp_loopstate = LOOP_READY; + return (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)); +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; -#ifdef ISP2100_FABRIC /* - * Now log in any fabric devices + * make sure the temp port database is clean... */ - for (lp = &fcp->portdb[frange]; - lp < &fcp->portdb[MAX_FC_TARG]; lp++) { - u_int32_t portid; - mbreg_t mbs; + MEMZERO((void *)fcp->tport, sizeof (fcp->tport)); - loopid = lp - fcp->portdb; - if (loopid >= FL_PORT_ID && loopid <= FC_SNS_ID) { + /* + * 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; } /* - * Anything here? + * Get an entry.... */ - if (lp->port_wwn == 0) { + 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); + } /* - * Don't try to log into yourself. + * If the returned database element doesn't match what we + * asked for, restart the process entirely (up to a point...). */ - if ((portid = lp->portid) == fcp->isp_portid) { + 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'd been logged in- see if we still are and we haven't - * changed. If so, no need to log ourselves out, etc.. - * - * Unfortunately, our charming Qlogic f/w has decided to - * return a valid port database entry for a fabric device - * that has, in fact, gone away. And it hangs trying to - * log it out. + * If we don't have a non-zero Port WWN, we're not here. */ - if (lp->loggedin && - isp_getpdb(isp, lp->loopid, &pdb) == 0) { - int nrole; - u_int64_t nwwnn, nwwpn; - nwwnn = - (((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])); - nwwpn = - (((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])); - nrole = (pdb.pdb_prli_svc3 & SVC3_ROLE_MASK) >> - SVC3_ROLE_SHIFT; - if (pdb.pdb_loopid == lp->loopid && lp->portid == - (u_int32_t) BITS2WORD(pdb.pdb_portid_bits) && - nwwnn == lp->node_wwn && nwwpn == lp->port_wwn && - lp->roles == nrole) { - lp->loggedin = lp->valid = 1; - isp_prt(isp, ISP_LOGINFO, lretained, - (int) (lp - fcp->portdb), - (int) lp->loopid, lp->portid); - continue; - } + if (fcp->tport[loopid].port_wwn == 0) { + continue; } /* - * Force a logout if we were logged in. + * Skip ourselves. */ - 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); - lp->loggedin = 0; - isp_prt(isp, ISP_LOGINFO, plogout, - (int) (lp - fcp->portdb), lp->loopid, lp->portid); + if (loopid == fcp->isp_iid) { + continue; } /* - * And log in.... + * 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. */ - loopid = lp - fcp->portdb; - lp->loopid = 0; - do { - mbs.param[0] = MBOX_FABRIC_LOGIN; - mbs.param[1] = loopid << 8; - mbs.param[2] = portid >> 16; - mbs.param[3] = portid & 0xffff; - if (IS_2200(isp)) { - /* only issue a PLOGI if not logged in */ - mbs.param[1] |= 0x1; + + 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); } - isp_mboxcmd(isp, &mbs, MBLOGALL & ~(MBOX_LOOP_ID_USED | - MBOX_PORT_ID_USED | MBOX_COMMAND_ERROR)); - switch (mbs.param[0]) { - case MBOX_LOOP_ID_USED: - /* - * Try the next available loop id. - */ - loopid++; - break; - case MBOX_PORT_ID_USED: - /* - * This port is already logged in. - * Snaffle the loop id it's using if it's - * nonzero, otherwise we're hosed. - */ - if (mbs.param[1] != 0) { - loopid = mbs.param[1]; - isp_prt(isp, ISP_LOGINFO, retained, - loopid, (int) (lp - fcp->portdb), - lp->portid); - } else { - loopid = MAX_FC_TARG; - break; + 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; } - /* FALLTHROUGH */ - case MBOX_COMMAND_COMPLETE: - lp->loggedin = 1; - lp->loopid = loopid; - break; - case MBOX_COMMAND_ERROR: - isp_prt(isp, ISP_LOGINFO, plogierr, - portid, mbs.param[1]); - /* FALLTHROUGH */ - case MBOX_ALL_IDS_USED: /* We're outta IDs */ - default: - loopid = MAX_FC_TARG; - break; + 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; } - } while (lp->loopid == 0 && loopid < MAX_FC_TARG); + break; + } /* - * If we get here and we haven't set a Loop ID, - * we failed to log into this device. + * 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 (lp->loopid == 0) { + if (i < hival) { continue; } /* - * Make sure we can get the approriate port information. + * 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 (isp_getpdb(isp, lp->loopid, &pdb) != 0) { - isp_prt(isp, ISP_LOGWARN, nopdb, lp->portid); - goto dump_em; - } - - if (pdb.pdb_loopid != lp->loopid) { - isp_prt(isp, ISP_LOGWARN, pdbmfail1, - lp->portid, pdb.pdb_loopid); - goto dump_em; + 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; } - if (lp->portid != (u_int32_t) BITS2WORD(pdb.pdb_portid_bits)) { - isp_prt(isp, ISP_LOGWARN, pdbmfail2, - lp->portid, BITS2WORD(pdb.pdb_portid_bits)); - goto dump_em; - } + /* + * 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; - lp->roles = - (pdb.pdb_prli_svc3 & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT; - 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])); /* - * Check to make sure this all makes sense. + * Tell the outside world we've arrived. */ - if (lp->node_wwn && lp->port_wwn) { - lp->valid = 1; - loopid = lp - fcp->portdb; - (void) isp_async(isp, ISPASYNC_LOGGED_INOUT, &loopid); - continue; - } -dump_em: - lp->valid = 0; - isp_prt(isp, ISP_LOGINFO, - ldumped, loopid, lp->loopid, lp->portid); - 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); + (void) isp_async(isp, ISPASYNC_PROMENADE, &i); } -#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. + * Now find all previously used targets that are now invalid and + * notify the outer layers that they're gone. */ - fcp->loop_seen_once = 1; + 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 @@ -2160,16 +2374,45 @@ 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++) { -- cgit v1.2.3