diff options
| author | mjacob <mjacob@NetBSD.org> | 1999-10-14 02:27:12 +0000 |
|---|---|---|
| committer | mjacob <mjacob@NetBSD.org> | 1999-10-14 02:27:12 +0000 |
| commit | 2b760bfd7b8a7eac756c6744fd3c8e24ef1b1b70 (patch) | |
| tree | 7165dae162d40206025eee451b3894bd88d0806a /sys/dev/ic/isp.c | |
| parent | 74f3840c1baab976d7116124d4c17a6ee1ffc9bf (diff) | |
remove most target mode stuff. Change the arguments to the
isp_fastpost_complete function to include a handle. Do some
isr register debouncing. Use new inline functions for xflist
handle storage. Remove isp_dumpxflist function. Do some fixups
of NVRAM from some broken cards. Use Full Login after LIP option
for FC cards if f/w < 1.17 - there's a f/w bug that causes the
port database to not be actually refreshed for local loop devices!
Do the appropriate endian swizzling for the ICB. Ditto for SNS structures
(these are no-ops until UltraSparc PCI needs them).
Diffstat (limited to 'sys/dev/ic/isp.c')
| -rw-r--r-- | sys/dev/ic/isp.c | 1207 |
1 files changed, 311 insertions, 896 deletions
diff --git a/sys/dev/ic/isp.c b/sys/dev/ic/isp.c index 1bb34aaf414..1a3f2dc1784 100644 --- a/sys/dev/ic/isp.c +++ b/sys/dev/ic/isp.c @@ -1,5 +1,4 @@ -/* $NetBSD: isp.c,v 1.37 1999/07/05 20:31:35 mjacob Exp $ */ -/* release_6_5_99 */ +/* $NetBSD: isp.c,v 1.38 1999/10/14 02:27:12 mjacob Exp $ */ /* * Copyright (C) 1997, 1998, 1999 National Aeronautics & Space Administration * All rights reserved. @@ -26,6 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + /* * Machine and OS Independent (well, as best as possible) * code for the Qlogic ISP SCSI adapters. @@ -64,31 +64,6 @@ /* * Local static data */ -#ifdef ISP_TARGET_MODE -static const char tgtiqd[36] = { - 0x03, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x51, 0x4C, 0x4F, 0x47, 0x49, 0x43, 0x20, 0x20, -#ifdef __NetBSD__ - 0x4E, 0x45, 0x54, 0x42, 0x53, 0x44, 0x20, 0x20, -#else -# ifdef __FreeBSD__ - 0x46, 0x52, 0x45, 0x45, 0x42, 0x52, 0x44, 0x20, -# else -# ifdef __OpenBSD__ - 0x4F, 0x50, 0x45, 0x4E, 0x42, 0x52, 0x44, 0x20, -# else -# ifdef linux - 0x4C, 0x49, 0x4E, 0x55, 0x58, 0x20, 0x20, 0x20, -# else -# endif -# endif -# endif -#endif - 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x31 -}; -#endif - /* * Local function prototypes. @@ -96,17 +71,9 @@ static const char tgtiqd[36] = { static int isp_parse_async __P((struct ispsoftc *, int)); static int isp_handle_other_response __P((struct ispsoftc *, ispstatusreq_t *, u_int8_t *)); -#ifdef ISP_TARGET_MODE -static int isp_modify_lun __P((struct ispsoftc *, int, int, int)); -static void isp_notify_ack __P((struct ispsoftc *, void *)); -static void isp_handle_atio __P((struct ispsoftc *, void *)); -static void isp_handle_atio2 __P((struct ispsoftc *, void *)); -static void isp_handle_ctio __P((struct ispsoftc *, void *)); -static void isp_handle_ctio2 __P((struct ispsoftc *, void *)); -#endif static void isp_parse_status __P((struct ispsoftc *, ispstatusreq_t *, ISP_SCSI_XFER_T *)); -static void isp_fastpost_complete __P((struct ispsoftc *, int)); +static void isp_fastpost_complete __P((struct ispsoftc *, u_int32_t)); 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 *)); @@ -121,7 +88,6 @@ static int isp_scan_fabric __P((struct ispsoftc *)); #endif static void isp_fw_state __P((struct ispsoftc *)); static void isp_dumpregs __P((struct ispsoftc *, const char *)); -static void isp_dumpxflist __P((struct ispsoftc *)); static void isp_mboxcmd __P((struct ispsoftc *, mbreg_t *)); static void isp_update __P((struct ispsoftc *)); @@ -202,8 +168,8 @@ isp_reset(isp) case ISP_HA_FC_2200: revname[1] = '2'; /* - * Resident firmware for the 2200 appears to have - * SCCLUN enabled. + * Resident firmware for the 2200 appears + * to have SCCLUN enabled. */ #ifndef ISP2100_SCCLUN if (isp->isp_mdvec->dv_fwlen == 0) { @@ -392,7 +358,7 @@ again: */ loops = MBOX_DELAY_COUNT; for (;;) { - if (isp->isp_type & ISP_HA_SCSI) { + if (IS_SCSI(isp)) { if (!(ISP_READ(isp, BIU_ICR) & BIU_ICR_SOFT_RESET)) break; } else { @@ -468,13 +434,6 @@ again: */ ISP_RESET1(isp); -#if 0 - /* - * Enable interrupts - */ - ENABLE_INTS(isp); -#endif - /* * Wait for everything to finish firing up... */ @@ -582,7 +541,7 @@ again: mbs.param[1] = 0x1000; isp_mboxcmd(isp, &mbs); - if (isp->isp_type & ISP_HA_SCSI) { + if (IS_SCSI(isp)) { /* * Set CLOCK RATE, but only if asked to. */ @@ -591,38 +550,48 @@ again: mbs.param[1] = isp->isp_clock; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_dumpregs(isp, "failed to set CLOCKRATE"); + PRINTF("failed to set clockrate (0x%x)\n", + mbs.param[0]); /* but continue */ - } else { - IDPRINTF(3, ("%s: setting input clock to %d\n", - isp->isp_name, isp->isp_clock)); } } } mbs.param[0] = MBOX_ABOUT_FIRMWARE; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_dumpregs(isp, "ABOUT FIRMWARE command failed"); + PRINTF("could not get f/w started (0x%x)\n", mbs.param[0]); return; } - PRINTF("%s: Board Revision %s, %s F/W Revision %d.%d.%d\n", - isp->isp_name, revname, dodnld? "loaded" : "resident", - mbs.param[1], mbs.param[2], mbs.param[3]); + CFGPRINTF("%s: Board Revision %s, %s F/W Revision %d.%d.%d\n", + isp->isp_name, revname, dodnld? "loaded" : "resident", + mbs.param[1], mbs.param[2], mbs.param[3]); if (IS_FC(isp)) { if (ISP_READ(isp, BIU2100_CSR) & BIU2100_PCI64) { - PRINTF("%s: in 64-Bit PCI slot\n", isp->isp_name); + CFGPRINTF("%s: in 64-Bit PCI slot\n", isp->isp_name); } } + isp->isp_fwrev[0] = mbs.param[1]; isp->isp_fwrev[1] = mbs.param[2]; isp->isp_fwrev[2] = mbs.param[3]; if (isp->isp_romfw_rev[0] || isp->isp_romfw_rev[1] || isp->isp_romfw_rev[2]) { - PRINTF("%s: Last F/W revision was %d.%d.%d\n", isp->isp_name, + CFGPRINTF("%s: Last F/W revision was %d.%d.%d\n", isp->isp_name, isp->isp_romfw_rev[0], isp->isp_romfw_rev[1], isp->isp_romfw_rev[2]); } + + mbs.param[0] = MBOX_GET_FIRMWARE_STATUS; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + PRINTF("%s: could not GET FIRMWARE STATUS\n", isp->isp_name); + return; + } + isp->isp_maxcmds = mbs.param[2]; + CFGPRINTF("%s: %d max I/O commands supported\n", + isp->isp_name, mbs.param[2]); isp_fw_state(isp); + /* * Set up DMA for the request and result mailboxes. */ @@ -856,8 +825,8 @@ isp_scsi_channel_init(isp, channel) u_int16_t sdf; if (sdp->isp_devparam[tgt].dev_enable == 0) { - PRINTF("%s: skipping settings for target %d bus %d\n", - isp->isp_name, tgt, channel); + IDPRINTF(1, ("%s: skipping target %d bus %d settings\n", + isp->isp_name, tgt, channel)); continue; } @@ -993,31 +962,24 @@ isp_fibre_init(isp) icbp->icb_version = ICB_VERSION1; #ifdef ISP_TARGET_MODE - fcp->isp_fwoptions = ICBOPT_TGT_ENABLE|ICBOPT_INI_TGTTYPE; + fcp->isp_fwoptions = ICBOPT_TGT_ENABLE; #else fcp->isp_fwoptions = 0; #endif fcp->isp_fwoptions |= ICBOPT_FAIRNESS; fcp->isp_fwoptions |= ICBOPT_PDBCHANGE_AE; fcp->isp_fwoptions |= ICBOPT_HARD_ADDRESS; -#ifdef ISP2100_FABRIC -#if 0 - /* - * Do not use FULL LOGIN- it resets the loop too much. - */ - fcp->isp_fwoptions |= ICBOPT_FULL_LOGIN; -#endif -#endif -#if 0 /* - * Don't use this either + * We have to use FULL LOGIN even though it resets the loop too much + * because otherwise port database entries don't get updated after + * a LIP- this is a known f/w bug. */ - fcp->isp_fwoptions |= ICBOPT_INI_ADISC; -#endif + if (ISP_FW_REVX(isp->isp_fwrev) < ISP_FW_REV(1, 17, 0)) { + fcp->isp_fwoptions |= ICBOPT_FULL_LOGIN; + } #ifndef ISP_NO_FASTPOST_FC fcp->isp_fwoptions |= ICBOPT_FAST_POST; #endif - if (isp->isp_confopts & ISP_CFG_FULL_DUPLEX) fcp->isp_fwoptions |= ICBOPT_FULL_DUPLEX; @@ -1049,6 +1011,7 @@ isp_fibre_init(isp) icbp->icb_retry_delay = fcp->isp_retry_delay; icbp->icb_retry_count = fcp->isp_retry_count; icbp->icb_hardaddr = loopid; + icbp->icb_logintime = 30; /* 30 second login timeout */ if (fcp->isp_nodewwn) { u_int64_t pn; @@ -1074,15 +1037,22 @@ isp_fibre_init(isp) } else { fcp->isp_fwoptions &= ~(ICBOPT_USE_PORTNAME|ICBOPT_FULL_LOGIN); } - icbp->icb_rqstqlen = RQUEST_QUEUE_LEN; icbp->icb_rsltqlen = RESULT_QUEUE_LEN; icbp->icb_rqstaddr[RQRSP_ADDR0015] = DMA_LSW(isp->isp_rquest_dma); icbp->icb_rqstaddr[RQRSP_ADDR1631] = DMA_MSW(isp->isp_rquest_dma); icbp->icb_respaddr[RQRSP_ADDR0015] = DMA_LSW(isp->isp_result_dma); icbp->icb_respaddr[RQRSP_ADDR1631] = DMA_MSW(isp->isp_result_dma); - MemoryBarrier(); + ISP_SWIZZLE_ICB(isp, icbp); + + /* + * Do this *before* initializing the firmware. + */ + isp_mark_getpdb_all(isp); + fcp->isp_fwstate = FW_CONFIG_WAIT; + fcp->isp_loopstate = LOOP_NIL; + MemoryBarrier(); for (;;) { mbs.param[0] = MBOX_INIT_FIRMWARE; mbs.param[1] = 0; @@ -1096,7 +1066,7 @@ isp_fibre_init(isp) if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { PRINTF("%s: INIT FIRMWARE failed (code 0x%x)\n", isp->isp_name, mbs.param[0]); - if (mbs.param[0] & 0xc000) { + if (mbs.param[0] & 0x8000) { SYS_DELAY(1000); continue; } @@ -1113,9 +1083,6 @@ isp_fibre_init(isp) * Whatever happens, we're now committed to being here. */ isp->isp_state = ISP_INITSTATE; - fcp->isp_fwstate = FW_CONFIG_WAIT; - - isp_mark_getpdb_all(isp); #ifdef ISP_TARGET_MODE if (isp_modify_lun(isp, 0, 1, 1)) { @@ -1168,7 +1135,7 @@ isp_getpdb(isp, id, pdbp) switch (mbs.param[0]) { case MBOX_COMMAND_COMPLETE: MemoryBarrier(); - MEMCPY(pdbp, fcp->isp_scratch, sizeof (isp_pdb_t)); + ISP_UNSWIZZLE_AND_COPY_PDBP(isp, pdbp, fcp->isp_scratch); break; case MBOX_HOST_INTERFACE_ERROR: PRINTF("%s: DMA error getting port database\n", isp->isp_name); @@ -1223,8 +1190,15 @@ isp_fclink_test(isp, waitdelay) struct ispsoftc *isp; int waitdelay; { + static char *toponames[] = { + "Private Loop", + "FL Port", + "N-Port to N-Port", + "F Port" + }; + char *tname; mbreg_t mbs; - int count; + int count, topo = -1; u_int8_t lwfs; fcparam *fcp; #if defined(ISP2100_FABRIC) @@ -1267,6 +1241,19 @@ isp_fclink_test(isp, waitdelay) return (-1); } fcp->isp_loopid = mbs.param[1]; + if (isp->isp_type == ISP_HA_FC_2100) { + if (ISP_FW_REVX(isp->isp_fwrev) >= ISP_FW_REV(2, 0, 14)) { + topo = (int) mbs.param[6]; + } + } else if (isp->isp_type == ISP_HA_FC_2100) { + if (ISP_FW_REVX(isp->isp_fwrev) >= ISP_FW_REV(1, 17, 26)) { + topo = (int) mbs.param[6]; + } + } + if (topo < 0 || topo > 3) + tname = "unknown"; + else + tname = toponames[topo]; /* * If we're not on a fabric, the low 8 bits will be our AL_PA. @@ -1274,12 +1261,13 @@ isp_fclink_test(isp, waitdelay) */ fcp->isp_alpa = mbs.param[2]; #if defined(ISP2100_FABRIC) + fcp->isp_onfabric = 0; if (isp_getpdb(isp, FL_PORT_ID, &pdb) == 0) { fcp->isp_portid = mbs.param[2] | (((int)mbs.param[3]) << 16); fcp->isp_onfabric = 1; - PRINTF("%s: Loop ID %d, AL_PA 0x%x, Port ID 0x%x\n", - isp->isp_name, fcp->isp_loopid, fcp->isp_alpa, - fcp->isp_portid); + CFGPRINTF("%s: Loop ID %d, AL_PA 0x%x, Port ID 0x%x Loop State " + "0x%x topology %s\n", isp->isp_name, fcp->isp_loopid, + fcp->isp_alpa, fcp->isp_portid, fcp->isp_loopstate, tname); /* * Make sure we're logged out of all fabric devices. @@ -1299,8 +1287,9 @@ isp_fclink_test(isp, waitdelay) } } else #endif - PRINTF("%s: Loop ID %d, ALPA 0x%x\n", isp->isp_name, - fcp->isp_loopid, fcp->isp_alpa); + CFGPRINTF("%s: Loop ID %d, ALPA 0x%x Loop State 0x%x topology %s\n", + isp->isp_name, fcp->isp_loopid, fcp->isp_alpa, fcp->isp_loopstate, + tname); fcp->loop_seen_once = 1; return (0); } @@ -1336,13 +1325,11 @@ isp_pdb_sync(isp, target) struct ispsoftc *isp; int target; { - struct lportdb *lp, tport[FL_PORT_ID]; + struct lportdb *lp, *tport; fcparam *fcp = isp->isp_param; isp_pdb_t pdb; int loopid, lim; -target = target; - #ifdef ISP2100_FABRIC /* * XXX: If we do this *after* building up our local port database, @@ -1354,6 +1341,8 @@ target = target; if (fcp->isp_onfabric) (void) isp_scan_fabric(isp); #endif + + /* * Run through the local loop ports and get port database info * for each loop ID. @@ -1362,13 +1351,13 @@ target = target; * the wrong database entity- if that happens, just restart (up to * FL_PORT_ID times). */ + tport = fcp->tport; + MEMZERO((void *) tport, sizeof (tport)); for (lim = loopid = 0; loopid < FL_PORT_ID; loopid++) { /* * make sure the temp port database is clean... */ lp = &tport[loopid]; - MEMZERO((void *) lp, sizeof (*lp)); - lp->node_wwn = isp_get_portname(isp, loopid, 1); if (lp->node_wwn == 0) continue; @@ -1377,12 +1366,14 @@ target = target; lp->node_wwn = 0; continue; } + /* * Get an entry.... */ if (isp_getpdb(isp, loopid, &pdb) != 0) { continue; } + /* * If the returned database element doesn't match what we * asked for, restart the process entirely (up to a point...). @@ -1398,6 +1389,7 @@ target = target; "database\n", isp->isp_name); return (-1); } + /* * Save the pertinent info locally. */ @@ -1444,6 +1436,13 @@ target = target; 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. */ @@ -1451,12 +1450,6 @@ target = target; int i; /* - * While we're at it, clear the valid bit for the saved entry - * that coincidentally is at this same index. - */ - fcp->portdb[loopid].valid = 0; - - /* * If we don't have a non-zero Port WWN, we're not here. */ if (tport[loopid].port_wwn == 0) { @@ -1466,12 +1459,10 @@ target = target; /* * 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 does not include - * the 'valid' marking though so we have to turn it - * back on. + * same as our saved data base. This didn't include + * the 'valid' marking so we have set that here. */ if (tport[loopid].valid) { -IDPRINTF(0, ("%s: loopid %d already valid\n", isp->isp_name, loopid)); fcp->portdb[loopid].valid = 1; continue; } @@ -1499,12 +1490,19 @@ IDPRINTF(0, ("%s: loopid %d already valid\n", isp->isp_name, loopid)); * just change the actual loop ID we'd use. */ if (fcp->portdb[i].loopid != loopid) { - PRINTF("%s: Target ID %d (0x%x) was loopid 0x%x" - " and is now loopid 0x%x\n", isp->isp_name, - i, i, fcp->portdb[i].loopid, loopid); + PRINTF("%s: Target ID %d Loop 0x%x (Port 0x%x) " + "=> Loop 0x%x (Port 0x%x) \n", + isp->isp_name, 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; + /* + * XXX: Should we also propagate roles in case they + * XXX: changed? + */ /* * Now make sure this Port WWN doesn't exist elsewhere @@ -1613,7 +1611,7 @@ IDPRINTF(0, ("%s: loopid %d already valid\n", isp->isp_name, loopid)); /* * Force a logout. */ - lp->loopid = lp - fcp->portdb; + lp->loopid = loopid = lp - fcp->portdb; mbs.param[0] = MBOX_FABRIC_LOGOUT; mbs.param[1] = lp->loopid << 8; mbs.param[2] = 0; @@ -1629,10 +1627,46 @@ IDPRINTF(0, ("%s: loopid %d already valid\n", isp->isp_name, loopid)); mbs.param[3] = lp->portid & 0xffff; isp_mboxcmd(isp, &mbs); if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { - continue; lp->valid = 1; lp->fabdev = 1; - lp->roles = (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT); + if (isp_getpdb(isp, loopid, &pdb) != 0) { + /* + * Be kind... + */ + lp->roles = (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT); + PRINTF("%s: Faked PortID 0x%x into LoopID %d\n", + isp->isp_name, lp->portid, lp->loopid); + } else if (pdb.pdb_loopid != lp->loopid) { + lp->roles = (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT); + PRINTF("%s: Wanked PortID 0x%x to LoopID %d\n", + isp->isp_name, lp->portid, lp->loopid); + } else { + lp->roles = + (pdb.pdb_prli_svc3 & SVC3_ROLE_MASK) >> + SVC3_ROLE_SHIFT; + lp->portid = BITS2WORD(pdb.pdb_portid_bits); + lp->loopid = pdb.pdb_loopid; + 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])); + (void) isp_async(isp, ISPASYNC_PDB_CHANGED, + &loopid); + } } } #endif @@ -1666,6 +1700,7 @@ isp_scan_fabric(isp) reqp->snscb_data[0] = SNS_GAN; reqp->snscb_data[4] = portid & 0xffff; reqp->snscb_data[5] = (portid >> 16) & 0xff; + ISP_SWIZZLE_SNS_REQ(isp, reqp); mbs.param[0] = MBOX_SEND_SNS; mbs.param[1] = SNS_GAN_REQ_SIZE >> 1; mbs.param[2] = DMA_MSW(fcp->isp_scdma); @@ -1677,6 +1712,7 @@ isp_scan_fabric(isp) if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { 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])); @@ -1713,7 +1749,7 @@ ispscsicmd(xs) #define reqp _u._reqp #define t2reqp _u._t2reqp #define UZSIZE max(sizeof (ispreq_t), sizeof (ispreqt2_t)) - int target, i, rqidx; + int target, i; XS_INITERR(xs); isp = XS_ISP(xs); @@ -1744,7 +1780,6 @@ ispscsicmd(xs) if (IS_FC(isp)) { fcparam *fcp = isp->isp_param; struct lportdb *lp; - #if defined(ISP2100_FABRIC) if (target >= FL_PORT_ID) { /* @@ -1758,7 +1793,6 @@ ispscsicmd(xs) } } #endif - /* * Check for f/w being in ready state. If the f/w * isn't in ready state, then we don't know our @@ -1775,7 +1809,7 @@ ispscsicmd(xs) if (isp_fclink_test(isp, FC_FW_READY_DELAY)) { XS_SETERR(xs, HBA_SELTIMEOUT); if (fcp->loop_seen_once) { - return (CMD_EAGAIN); + return (CMD_RQLATER); } else { return (CMD_COMPLETE); } @@ -1790,7 +1824,7 @@ ispscsicmd(xs) */ if (fcp->isp_loopstate < LOOP_PDB_RCVD) { XS_SETERR(xs, HBA_SELTIMEOUT); - return (CMD_EAGAIN); + return (CMD_RQLATER); } /* @@ -1809,16 +1843,16 @@ ispscsicmd(xs) * Now check whether we should even think about pursuing this. */ lp = &fcp->portdb[target]; -if ( target < 0x80) { if (lp->valid == 0) { XS_SETERR(xs, HBA_SELTIMEOUT); return (CMD_COMPLETE); } if ((lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT)) == 0) { + IDPRINTF(3, ("%s: target %d is not a target\n", + isp->isp_name, target)); XS_SETERR(xs, HBA_SELTIMEOUT); return (CMD_COMPLETE); } -} /* * Now turn target into what the actual loop ID is. */ @@ -1839,7 +1873,7 @@ if ( target < 0x80) { reqp = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, iptr); iptr = ISP_NXT_QENTRY(iptr, RQUEST_QUEUE_LEN); if (iptr == optr) { - IDPRINTF(2, ("%s: Request Queue Overflow\n", isp->isp_name)); + IDPRINTF(0, ("%s: Request Queue Overflow\n", isp->isp_name)); XS_SETERR(xs, HBA_BOTCH); return (CMD_EAGAIN); } @@ -1862,9 +1896,8 @@ if ( target < 0x80) { reqp->req_header.rqs_entry_count = 1; reqp->req_header.rqs_entry_type = RQSTYPE_MARKER; reqp->req_modifier = SYNC_ALL; - ISP_SBUSIFY_ISPHDR(isp, &reqp->req_header); - reqp->req_target = i << 7; - ISP_SBUSIFY_ISPREQ(isp, reqp); + reqp->req_target = i << 7; /* insert bus number */ + ISP_SWIZZLE_REQUEST(isp, reqp); /* * Unconditionally update the input pointer anyway. @@ -1874,7 +1907,7 @@ if ( target < 0x80) { niptr = ISP_NXT_QENTRY(iptr, RQUEST_QUEUE_LEN); if (niptr == optr) { - IDPRINTF(2, ("%s: Request Queue Overflow+\n", + IDPRINTF(0, ("%s: Request Queue Overflow+\n", isp->isp_name)); XS_SETERR(xs, HBA_BOTCH); return (CMD_EAGAIN); @@ -1887,61 +1920,35 @@ if ( target < 0x80) { MEMZERO((void *) reqp, UZSIZE); reqp->req_header.rqs_entry_count = 1; - if (isp->isp_type & ISP_HA_FC) { + if (IS_FC(isp)) { reqp->req_header.rqs_entry_type = RQSTYPE_T2RQS; } else { reqp->req_header.rqs_entry_type = RQSTYPE_REQUEST; } reqp->req_header.rqs_flags = 0; - reqp->req_header.rqs_seqno = isp->isp_seqno++; - ISP_SBUSIFY_ISPHDR(isp, &reqp->req_header); - - for (rqidx = 0; rqidx < RQUEST_QUEUE_LEN; rqidx++) { - if (isp->isp_xflist[rqidx] == NULL) - break; - } - if (rqidx == RQUEST_QUEUE_LEN) { - IDPRINTF(2, ("%s: out of xflist pointers\n", isp->isp_name)); - XS_SETERR(xs, HBA_BOTCH); - return (CMD_EAGAIN); - } else { - /* - * Never have a handle that is zero, so - * set req_handle off by one. - */ - isp->isp_xflist[rqidx] = xs; - reqp->req_handle = rqidx+1; - } - - if (isp->isp_type & ISP_HA_FC) { + reqp->req_header.rqs_seqno = 0; + if (IS_FC(isp)) { /* * See comment in isp_intr */ XS_RESID(xs) = 0; /* - * Fibre Channel always requires some kind of tag. - * If we're marked as "Can't Tag", just do simple - * instead of ordered tags. It's pretty clear to me - * that we shouldn't do head of queue tagging in - * this case. + * Fibre Channel always requires some kind of tag, but + * the firmware seems to be happy if we don't use a tag. */ if (XS_CANTAG(xs)) { t2reqp->req_flags = XS_KINDOF_TAG(xs); - } else { - t2reqp->req_flags = REQFLAG_STAG; } } else { sdparam *sdp = (sdparam *)isp->isp_param; if ((sdp->isp_devparam[target].cur_dflags & DPARM_TQING) && XS_CANTAG(xs)) { reqp->req_flags = XS_KINDOF_TAG(xs); - } else { - reqp->req_flags = 0; } } reqp->req_target = target | (XS_CHANNEL(xs) << 7); - if (isp->isp_type & ISP_HA_SCSI) { + if (IS_SCSI(isp)) { reqp->req_lun_trn = XS_LUN(xs); reqp->req_cdblen = XS_CDBLEN(xs); } else { @@ -1953,10 +1960,6 @@ if ( target < 0x80) { } MEMCPY(reqp->req_cdb, XS_CDBP(xs), XS_CDBLEN(xs)); - IDPRINTF(5, ("%s(%d.%d.%d): START%d cmd 0x%x datalen %d\n", - isp->isp_name, XS_CHANNEL(xs), target, XS_LUN(xs), - reqp->req_header.rqs_seqno, reqp->req_cdb[0], XS_XFRLEN(xs))); - reqp->req_time = XS_TIME(xs) / 1000; if (reqp->req_time == 0 && XS_TIME(xs)) reqp->req_time = 1; @@ -1965,15 +1968,21 @@ if ( target < 0x80) { * Always give a bit more leeway to commands after a bus reset. * XXX: DOES NOT DISTINGUISH WHICH PORT MAY HAVE BEEN SYNCED */ - if (isp->isp_sendmarker && reqp->req_time < 5) + if (isp->isp_sendmarker && reqp->req_time < 5) { reqp->req_time = 5; - + } + if (isp_save_xs(isp, xs, &reqp->req_handle)) { + IDPRINTF(2, ("%s: out of xflist pointers\n", isp->isp_name)); + XS_SETERR(xs, HBA_BOTCH); + return (CMD_EAGAIN); + } + /* + * Set up DMA and/or do any bus swizzling of the request entry + * so that the Qlogic F/W understands what is being asked of it. + */ i = ISP_DMASETUP(isp, xs, reqp, &iptr, optr); if (i != CMD_QUEUED) { - /* - * Take memory of it away... - */ - isp->isp_xflist[rqidx] = NULL; + isp_destroy_handle(isp, reqp->req_handle); /* * dmasetup sets actual error in packet, and * return what we were given to return. @@ -1981,7 +1990,9 @@ if ( target < 0x80) { return (i); } XS_SETERR(xs, HBA_NOERROR); - ISP_SBUSIFY_ISPREQ(isp, reqp); + IDPRINTF(5, ("%s(%d.%d.%d): START cmd 0x%x datalen %d\n", + isp->isp_name, XS_CHANNEL(xs), target, XS_LUN(xs), + reqp->req_cdb[0], XS_XFRLEN(xs))); MemoryBarrier(); ISP_WRITE(isp, INMAILBOX4, iptr); isp->isp_reqidx = iptr; @@ -2006,7 +2017,8 @@ isp_control(isp, ctl, arg) { ISP_SCSI_XFER_T *xs; mbreg_t mbs; - int i, bus, tgt; + int bus, tgt; + u_int32_t handle; switch (ctl) { default: @@ -2019,19 +2031,18 @@ isp_control(isp, ctl, arg) * Issue a bus reset. */ mbs.param[0] = MBOX_BUS_RESET; - if (isp->isp_type & ISP_HA_SCSI) { + if (IS_SCSI(isp)) { mbs.param[1] = ((sdparam *) isp->isp_param)->isp_bus_reset_delay; if (mbs.param[1] < 2) mbs.param[1] = 2; + bus = *((int *) arg); + mbs.param[2] = bus; } else { - /* - * Unparameterized. - */ - mbs.param[1] = 5; + /* Unparameterized. */ + mbs.param[1] = 10; + bus = 0; } - bus = *((int *) arg); - mbs.param[2] = bus; isp->isp_sendmarker = 1 << bus; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { @@ -2050,7 +2061,8 @@ isp_control(isp, ctl, arg) mbs.param[2] = 3; /* 'delay', in seconds */ isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_dumpregs(isp, "Target Reset Failed"); + PRINTF("%s: isp_control MBOX_RESET_DEV failure (code " + "%x)\n", isp->isp_name, mbs.param[0]); break; } PRINTF("%s: Target %d on Bus %d Reset Succeeded\n", @@ -2060,34 +2072,29 @@ isp_control(isp, ctl, arg) case ISPCTL_ABORT_CMD: xs = (ISP_SCSI_XFER_T *) arg; - for (i = 0; i < RQUEST_QUEUE_LEN; i++) { - if (xs == isp->isp_xflist[i]) { - break; - } - } - if (i == RQUEST_QUEUE_LEN) { + handle = isp_find_handle(isp, xs); + if (handle == 0) { PRINTF("%s: isp_control- cannot find command to abort " "in active list\n", isp->isp_name); break; } + bus = XS_CHANNEL(xs); mbs.param[0] = MBOX_ABORT; + if (IS_FC(isp)) { #ifdef ISP2100_SCCLUN - if (isp->isp_type & ISP_HA_FC) { mbs.param[1] = XS_TGT(xs) << 8; mbs.param[4] = 0; mbs.param[5] = 0; mbs.param[6] = XS_LUN(xs); - } else { - mbs.param[1] = XS_TGT(xs) << 8 | XS_LUN(xs); - } #else - mbs.param[1] = XS_TGT(xs) << 8 | XS_LUN(xs); + mbs.param[1] = XS_TGT(xs) << 8 | XS_LUN(xs); #endif - /* - * XXX: WHICH BUS? - */ - mbs.param[2] = (i+1) >> 16; - mbs.param[3] = (i+1) & 0xffff; + } else { + mbs.param[1] = + (bus << 15) | (XS_TGT(xs) << 8) | XS_LUN(xs); + } + mbs.param[2] = handle >> 16; + mbs.param[3] = handle & 0xffff; isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { PRINTF("%s: isp_control MBOX_ABORT failure (code %x)\n", @@ -2122,14 +2129,17 @@ isp_intr(arg) ISP_SCSI_XFER_T *complist[RESULT_QUEUE_LEN], *xs; struct ispsoftc *isp = arg; u_int8_t iptr, optr; - u_int16_t isr, sema; + u_int16_t isr, isrb, sema; int i, nlooked = 0, ndone = 0; /* * Well, if we've disabled interrupts, we may get a case where - * isr isn't set, but sema is. + * isr isn't set, but sema is. In any case, debounce isr reads. */ - isr = ISP_READ(isp, BIU_ISR); + do { + isr = ISP_READ(isp, BIU_ISR); + isrb = ISP_READ(isp, BIU_ISR); + } while (isr != isrb); sema = ISP_READ(isp, BIU_SEMA) & 0x1; IDPRINTF(5, ("%s: isp_intr isr %x sem %x\n", isp->isp_name, isr, sema)); if (IS_FC(isp)) { @@ -2169,21 +2179,7 @@ isp_intr(arg) IDPRINTF(3, ("%s: Async Mbox 0x%x\n", isp->isp_name, mbox)); if (fhandle > 0) { - xs = (void *)isp->isp_xflist[fhandle - 1]; - isp->isp_xflist[fhandle - 1] = NULL; - /* - * Since we don't have a result queue entry - * item, we must believe that SCSI status is - * zero and that all data transferred. - */ - XS_RESID(xs) = 0; - XS_STS(xs) = 0; - if (XS_XFRLEN(xs)) { - ISP_DMAFREE(isp, xs, fhandle - 1); - } - if (isp->isp_nactive > 0) - isp->isp_nactive--; - XS_CMD_DONE(xs); + isp_fastpost_complete(isp, fhandle); } } ISP_WRITE(isp, BIU_SEMA, 0); @@ -2213,7 +2209,11 @@ isp_intr(arg) optr = ISP_NXT_QENTRY(optr, RESULT_QUEUE_LEN); nlooked++; MemoryBarrier(); - ISP_SBUSIFY_ISPHDR(isp, &sp->req_header); + /* + * Do any appropriate unswizzling of what the Qlogic f/w has + * written into memory so it makes sense to us. + */ + ISP_UNSWIZZLE_RESPONSE(isp, sp); if (sp->req_header.rqs_entry_type != RQSTYPE_RESPONSE) { if (isp_handle_other_response(isp, sp, &optr) == 0) { ISP_WRITE(isp, INMAILBOX5, optr); @@ -2267,22 +2267,20 @@ isp_intr(arg) } #undef _RQS_OFLAGS } - - if (sp->req_handle > RQUEST_QUEUE_LEN || sp->req_handle < 1) { + if (sp->req_handle > isp->isp_maxcmds || sp->req_handle < 1) { PRINTF("%s: bad request handle %d\n", isp->isp_name, - sp->req_handle); + sp->req_handle); ISP_WRITE(isp, INMAILBOX5, optr); continue; } - xs = (void *) isp->isp_xflist[sp->req_handle - 1]; + xs = isp_find_xs(isp, sp->req_handle); if (xs == NULL) { - PRINTF("%s: NULL xs in xflist (handle %x)\n", + PRINTF("%s: NULL xs in xflist (handle 0x%x)\n", isp->isp_name, sp->req_handle); - isp_dumpxflist(isp); ISP_WRITE(isp, INMAILBOX5, optr); continue; } - isp->isp_xflist[sp->req_handle - 1] = NULL; + isp_destroy_handle(isp, sp->req_handle); if (sp->req_status_flags & RQSTF_BUS_RESET) { isp->isp_sendmarker |= (1 << XS_CHANNEL(xs)); } @@ -2344,7 +2342,7 @@ isp_intr(arg) XS_SETERR(xs, HBA_BOTCH); } } - if (isp->isp_type & ISP_HA_SCSI) { + if (IS_SCSI(isp)) { XS_RESID(xs) = sp->req_resid; } else if (sp->req_scsi_status & RQCS_RU) { XS_RESID(xs) = sp->req_resid; @@ -2352,7 +2350,7 @@ isp_intr(arg) XS_XFRLEN(xs), sp->req_resid)); } if (XS_XFRLEN(xs)) { - ISP_DMAFREE(isp, xs, sp->req_handle - 1); + ISP_DMAFREE(isp, xs, sp->req_handle); } /* * XXX: If we have a check condition, but no Sense Data, @@ -2369,10 +2367,9 @@ isp_intr(arg) } if ((isp->isp_dblev >= 5) || (isp->isp_dblev > 2 && !XS_NOERR(xs))) { - PRINTF("%s(%d.%d): FIN%d dl%d resid%d STS %x", + PRINTF("%s(%d.%d): FIN dl%d resid%d STS %x", isp->isp_name, XS_TGT(xs), XS_LUN(xs), - sp->req_header.rqs_seqno, XS_XFRLEN(xs), - XS_RESID(xs), XS_STS(xs)); + XS_XFRLEN(xs), XS_RESID(xs), XS_STS(xs)); if (sp->req_state_flags & RQSF_GOT_SENSE) { PRINTF(" Skey: %x", XS_SNSKEY(xs)); if (!(XS_IS_SNS_VALID(xs))) { @@ -2550,7 +2547,7 @@ isp_parse_async(isp, mbox) ((fcparam *) isp->isp_param)->isp_loopstate = LOOP_LIP_RCVD; isp->isp_sendmarker = 1; isp_mark_getpdb_all(isp); - PRINTF("%s: LIP occurred\n", isp->isp_name); + IDPRINTF(1, ("%s: LIP occurred\n", isp->isp_name)); break; case ASYNC_LOOP_UP: @@ -2584,10 +2581,16 @@ isp_parse_async(isp, mbox) isp->isp_sendmarker = 1; ((fcparam *) isp->isp_param)->isp_loopstate = LOOP_PDB_RCVD; isp_mark_getpdb_all(isp); - IDPRINTF(3, ("%s: Port Database Changed\n", isp->isp_name)); + IDPRINTF(2, ("%s: Port Database Changed\n", isp->isp_name)); break; case ASYNC_CHANGE_NOTIFY: + isp_mark_getpdb_all(isp); + /* + * Not correct, but it will force us to rescan the loop. + */ + ((fcparam *) isp->isp_param)->isp_loopstate = LOOP_PDB_RCVD; + isp_async(isp, ISPASYNC_CHANGE_NOTIFY, NULL); break; default: @@ -2603,618 +2606,27 @@ isp_handle_other_response(isp, sp, optrp) ispstatusreq_t *sp; u_int8_t *optrp; { - u_int8_t iptr, optr; - int reqsize = 0; - void *ireqp = NULL; -#ifdef ISP_TARGET_MODE - union { - at_entry_t *atio; - at2_entry_t *at2io; - ct_entry_t *ctio; - ct2_entry_t *ct2io; - lun_entry_t *lunen; - in_entry_t *inot; - in_fcentry_t *inot_fc; - na_entry_t *nack; - na_fcentry_t *nack_fc; - void *voidp; -#define atio un.atio -#define at2io un.at2io -#define ctio un.ctio -#define ct2io un.ct2io -#define lunen un.lunen -#define inot un.inot -#define inot_fc un.inot_fc -#define nack un.nack -#define nack_fc un.nack_fc - } un; - - un.voidp = sp; -#endif - - switch (sp->req_header.rqs_entry_type) { - case RQSTYPE_REQUEST: - return (-1); -#ifdef ISP_TARGET_MODE - case RQSTYPE_NOTIFY_ACK: - { - static const char *f = - "%s: Notify Ack Status 0x%x Sequence Id 0x%x\n" - /* - * The ISP is acknowleding our ack of an Immediate Notify. - */ - if (isp->isp_type & ISP_HA_FC) { - PRINTF(f, isp->isp_name, - nack_fc->na-status, nack_fc->na_seqid); - } else { - PRINTF(f, isp->isp_name, - nack->na_status, nack->na_seqid); - } - break; - } - case RQSTYPE_NOTIFY: - { - u_int16_t seqid, status; - - /* - * Either the ISP received a SCSI message it cannot handle - * or some other out of band condition (e.g., Port Logout) - * or it is returning an Immediate Notify entry we sent. - */ - if (isp->isp_type & ISP_HA_FC) { - status = inot_fc->status; - seqid = inot_fc->in_seqid; - } else { - status = inot->status; - seqid = inot->seqid & 0xff; - } - PRINTF("%s: Immediate Notify Status 0x%x Sequence Id 0x%x\n", - isp->isp_name, status, seqid); - - switch (status) { - case IN_MSG_RECEIVED: - case IN_IDE_RECEIVED: - ptisp_got_msg(ptp, &inot); - break; - case IN_RSRC_UNAVAIL: - PRINTF("%s: Firmware out of ATIOs\n", isp->isp_name); - break; - case IN_ABORT_TASK: - PRINTF("%s: Abort Task iid %d rx_id 0x%x\n", - inot_fc->in_iid, seqid); - break; - case IN_PORT_LOGOUT: - PRINTF("%s: Port Logout for Initiator %d\n", - isp->isp_name, inot_fc->in_iid); - break; - default: - PRINTF("%s: bad status (0x%x) in Immediate Notify\n", - isp->isp_name, status); - break; - - } - isp_notify_ack(isp, un.voidp); - reqsize = 0; - break; - } + case RQSTYPE_ATIO: + case RQSTYPE_CTIO0: case RQSTYPE_ENABLE_LUN: case RQSTYPE_MODIFY_LUN: - if (lunen->req_status != 1) { - PRINTF("%s: ENABLE/MODIFY LUN returned status 0x%x\n", - isp->isp_name, lunen->req_status); - } - break; + case RQSTYPE_NOTIFY: + case RQSTYPE_NOTIFY_ACK: + case RQSTYPE_CTIO1: case RQSTYPE_ATIO2: - { - fcparam *fcp = isp->isp_param; - ispctiot2_t local, *ct2 = NULL; - ispatiot2_t *at2 = (ispatiot2_t *) sp; - int s, lun; - -#ifdef ISP2100_SCCLUN - lun = at2->req_scclun; -#else - lun = at2->req_lun; -#endif - PRINTF("%s: atio2 loopid %d for lun %d rxid 0x%x flags0x%x " - "tflags0x%x ecodes0x%x rqstatus0x%x\n", isp->isp_name, - at2->req_initiator, lun, at2->req_rxid, - at2->req_flags, at2->req_taskflags, at2->req_execodes, - at2->req_status); - - switch (at2->req_status & ~ATIO_SENSEVALID) { - case ATIO_PATH_INVALID: - PRINTF("%s: ATIO2 Path Invalid\n", isp->isp_name); - break; - case ATIO_NOCAP: - PRINTF("%s: ATIO2 No Cap\n", isp->isp_name); - break; - case ATIO_BDR_MSG: - PRINTF("%s: ATIO2 BDR Received\n", isp->isp_name); - break; - case ATIO_CDB_RECEIVED: - ct2 = &local; - break; - default: - PRINTF("%s: unknown req_status 0x%x\n", isp->isp_name, - at2->req_status); - break; - } - if (ct2 == NULL) { - /* - * Just do an ACCEPT on this fellow. - */ - at2->req_header.rqs_entry_type = RQSTYPE_ATIO2; - at2->req_header.rqs_flags = 0; - at2->req_flags = 1; - ireqp = at2; - reqsize = sizeof (*at2); - break; - } - PRINTF("%s: datalen %d cdb0=0x%x\n", isp->isp_name, - at2->req_datalen, at2->req_cdb[0]); - MEMZERO((void *) ct2, sizeof (*ct2)); - ct2->req_header.rqs_entry_type = RQSTYPE_CTIO2; - ct2->req_header.rqs_entry_count = 1; - ct2->req_header.rqs_flags = 0; - ct2->req_header.rqs_seqno = isp->isp_seqno++; - ct2->req_handle = (at2->req_initiator << 16) | lun; -#ifndef ISP2100_SCCLUN - ct2->req_lun = lun; -#endif - ct2->req_initiator = at2->req_initiator; - ct2->req_rxid = at2->req_rxid; - - ct2->req_flags = CTIO_SEND_STATUS; - switch (at2->req_cdb[0]) { - case 0x0: /* TUR */ - ct2->req_flags |= CTIO_NODATA | CTIO2_SMODE0; - ct2->req_m.mode0.req_scsi_status = CTIO2_STATUS_VALID; - break; - - case 0x3: /* REQUEST SENSE */ - case 0x12: /* INQUIRE */ - ct2->req_flags |= CTIO_SEND_DATA | CTIO2_SMODE0; - ct2->req_m.mode0.req_scsi_status = CTIO2_STATUS_VALID; - ct2->req_seg_count = 1; - if (at2->req_cdb[0] == 0x12) { - s = sizeof (tgtiqd); - MEMCPY(fcp->isp_scratch, tgtiqd, s); - } else { - s = at2->req_datalen; - MEMZERO(fcp->isp_scratch, s); - } - ct2->req_m.mode0.req_dataseg[0].ds_base = - fcp->isp_scdma; - ct2->req_m.mode0.req_dataseg[0].ds_count = s; - ct2->req_m.mode0.req_datalen = s; -#if 1 - if (at2->req_datalen < s) { - ct2->req_m.mode1.req_scsi_status |= - CTIO2_RESP_VALID|CTIO2_RSPOVERUN; - } else if (at2->req_datalen > s) { - ct2->req_m.mode1.req_scsi_status |= - CTIO2_RESP_VALID|CTIO2_RSPUNDERUN; - } -#endif - break; - - default: /* ALL OTHERS */ - ct2->req_flags |= CTIO_NODATA | CTIO2_SMODE1; - ct2->req_m.mode1.req_scsi_status = 0; -#if 1 - if (at2->req_datalen) { - ct2->req_m.mode1.req_scsi_status |= - CTIO2_RSPUNDERUN; - ct2->req_resid[0] = at2->req_datalen & 0xff; - ct2->req_resid[1] = - (at2->req_datalen >> 8) & 0xff; - ct2->req_resid[2] = - (at2->req_datalen >> 16) & 0xff; - ct2->req_resid[3] = - (at2->req_datalen >> 24) & 0xff; - } -#endif - if ((at2->req_status & ATIO_SENSEVALID) == 0) { - ct2->req_m.mode1.req_sense_len = 18; - ct2->req_m.mode1.req_scsi_status |= 2; - ct2->req_m.mode1.req_response[0] = 0x70; - ct2->req_m.mode1.req_response[2] = 0x2; - } else { - ct2->req_m.mode1.req_sense_len = 18; - ct2->req_m.mode1.req_scsi_status |= - at2->req_scsi_status; - MEMCPY(ct2->req_m.mode1.req_response, - at2->req_sense, sizeof (at2->req_sense)); - } - break; - } - reqsize = sizeof (*ct2); - ireqp = ct2; - break; - } case RQSTYPE_CTIO2: - { - ispatiot2_t *at2; - ispctiot2_t *ct2 = (ispctiot2_t *) sp; - PRINTF("%s: CTIO2 returned status 0x%x\n", isp->isp_name, - ct2->req_status); - /* - * Return the ATIO to the board. - */ - at2 = (ispatiot2_t *) sp; - at2->req_header.rqs_entry_type = RQSTYPE_ATIO2; - at2->req_header.rqs_entry_count = 1; - at2->req_header.rqs_flags = 0; - at2->req_header.rqs_seqno = isp->isp_seqno++; - at2->req_status = 1; - reqsize = sizeof (*at2); - ireqp = at2; - break; - } -#undef atio -#undef at2io -#undef ctio -#undef ct2io -#undef lunen -#undef inot -#undef inot_fc -#undef nack -#undef nack_fc + case RQSTYPE_CTIO3: +#ifdef ISP_TARGET_MODE + return(isp_target_notify(isp, sp, optrp)); +#else + /* FALLTHROUGH */ #endif + case RQSTYPE_REQUEST: default: - PRINTF("%s: other response type %x\n", isp->isp_name, - sp->req_header.rqs_entry_type); - break; - } - if (reqsize) { - void *reqp; - optr = isp->isp_reqodx = ISP_READ(isp, OUTMAILBOX4); - iptr = isp->isp_reqidx; - reqp = (void *) ISP_QUEUE_ENTRY(isp->isp_rquest, iptr); - iptr = ISP_NXT_QENTRY(iptr, RQUEST_QUEUE_LEN); - if (iptr == optr) { - PRINTF("%s: Request Queue Overflow other response\n", - isp->isp_name); - } else { - MEMCPY(reqp, ireqp, reqsize); - ISP_WRITE(isp, INMAILBOX4, iptr); - isp->isp_reqidx = iptr; - } - } - return (0); -} - -#ifdef ISP_TARGET_MODE - -static void isp_tmd_newcmd_dflt __P((void *, tmd_cmd_t *)); -static void isp_tmd_event_dflt __P((void *, int)); -static void isp_tmd_notify_dflt __P((void *, tmd_notify_t *)); - -static void isp_tgt_data_xfer __P ((tmd_cmd_t *)); -static void isp_tgt_endcmd __P ((tmd_cmd_t *, u_int8_t)); -static void isp_tgt_done __P ((tmd_cmd_t *)); - -static void -isp_tmd_newcmd_dflt(arg0, cmdp) - void *arg0; - tmd_cmd_t *cmdp; -{ -} - -static void -isp_tmd_event_dflt(arg0, event) - void *arg0; - int event; -{ -} - -static void -isp_tmd_notify_dflt(arg0, npt) - void *arg0; - tmd_notify_t *npt; -{ -} - -/* - * Locks held, and ints disabled (if FC). - * - * XXX: SETUP ONLY FOR INITIAL ENABLING RIGHT NOW - */ -static int -isp_modify_lun(isp, lun, icnt, ccnt) - struct ispsoftc *isp; - int lun; /* logical unit to enable, modify, or disable */ - int icnt; /* immediate notify count */ - int ccnt; /* command count */ -{ - isplun_t *ip = NULL; - u_int8_t iptr, optr; - - optr = isp->isp_reqodx = ISP_READ(isp, OUTMAILBOX4); - iptr = isp->isp_reqidx; - ip = (isplun_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, iptr); - iptr = ISP_NXT_QENTRY(iptr, RQUEST_QUEUE_LEN); - if (iptr == optr) { - PRINTF("%s: Request Queue Overflow in isp_modify_lun\n", - isp->isp_name); return (-1); } - - MEMZERO((void *) ip, sizeof (*ip)); - ip->req_header.rqs_entry_type = RQSTYPE_ENABLE_LUN; - ip->req_header.rqs_entry_count = 1; - ip->req_header.rqs_seqno = isp->isp_seqno++; - ip->req_handle = RQSTYPE_ENABLE_LUN; - if (isp->isp_type & ISP_HA_SCSI) { - ip->req_lun = lun; - } - ip->req_cmdcount = ccnt; - ip->req_imcount = icnt; - ip->req_timeout = 0; /* default 30 seconds */ - ISP_WRITE(isp, INMAILBOX4, iptr); - isp->isp_reqidx = iptr; - return (0); -} - -static void -isp_notify_ack(isp, ptrp) - struct ispsoftc *isp; - void *ptrp; -{ - void *reqp; - u_int8_t iptr, optr; - union { - na_fcentry_t _naf; - na_entry_t _nas; - } un; - - MEMZERO((caddr_t)&un, sizeof (un)); - un._nas.na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK; - un._nas.na_header.rqs_entry_count = 1; - - if (isp->isp_type & ISP_HA_FC) { - na_fcentry_t *na = &un._nas; - if (ptrp) { - in_fcentry_t *inp = ptrp; - na->na_iid = inp->in_iid; - na->na_lun = inp->in_lun; - na->na_task_flags = inp->in_task_flags; - na->na_seqid = inp->in_seqid; - na->na_status = inp->in_status; - } else { - na->na_flags = NAFC_RST_CLRD; - } - } else { - na_entry_t *na = &un._nas; - if (ptrp) { - in_entry_t *inp = ptrp; - na->na_iid = inp->in_iid; - na->na_lun = inp->in_lun; - na->na_tgt = inp->in_tgt; - na->na_seqid = inp->in_seqid; - } else { - na->na_flags = NA_RST_CLRD; - } - } - optr = isp->isp_reqodx = ISP_READ(isp, OUTMAILBOX4); - iptr = isp->isp_reqidx; - reqp = (void *) ISP_QUEUE_ENTRY(isp->isp_rquest, iptr); - iptr = ISP_NXT_QENTRY(iptr, RQUEST_QUEUE_LEN); - if (iptr == optr) { - PRINTF("%s: Request Queue Overflow For isp_notify_ack\n", - isp->isp_name); - } else { - MEMCPY(reqp, ireqp, sizeof (un)); - ISP_WRITE(isp, INMAILBOX4, iptr); - isp->isp_reqidx = iptr; - } -} - -/* - * These are dummy stubs for now until the outside framework is plugged in. - */ - -static void -isp_handle_atio (isp, aep) - struct ispsoftc *isp; - at_entry_t *aep; -{ - int status, connected; - tmd_cmd_t local, *cdp = &local; - - /* - * Get the ATIO status and see if we're still connected. - */ - status = aep->at_status; - connected = ((aep->at_flags & AT_NODISC) != 0); - - PRINTF("%s: ATIO status=0x%x, connected=%d\n", isp->isp_name, - status, connected); - - /* - * The firmware status (except for the SenseValid bit) indicates - * why this ATIO was sent to us. - * If SenseValid is set, the firware has recommended Sense Data. - * If the Disconnects Disabled bit is set in the flags field, - * we're still connected on the SCSI bus - i.e. the initiator - * did not set DiscPriv in the identify message. We don't care - * about this so it's ignored. - */ - switch (status & ~TGTSVALID) { - case AT_PATH_INVALID: - /* - * ATIO rejected by the firmware due to disabled lun. - */ - PRINTF("%s: Firmware rejected ATIO for disabled lun %d\n", - isp->isp_name, aep->at_lun); - break; - - case AT_PHASE_ERROR: - /* - * Bus Pase Sequence error. - * - * The firmware should have filled in the correct - * sense data. - */ - - - if (status & TGTSVALID) { - MEMCPY(&cdp->cd_sensedata, aep->at_sense, - sizeof (cdp->cd_sensedata)); - PRINTF("%s: Bus Phase Sequence error key 0x%x\n", - isp->isp_name, cdp->cd_sensedata[2] & 0xf); - } else { - PRINTF("%s: Bus Phase Sequence With No Sense\n", - isp->isp_name); - } - (*isp->isp_tmd_newcmd)(isp, cdp); - break; - - case AT_NOCAP: - /* - * Requested Capability not available - * We sent an ATIO that overflowed the firmware's - * command resource count. - */ - PRINTF("%s: Firmware rejected ATIO, command count overflow\n", - isp->isp_name); - break; - - case AT_BDR_MSG: - /* - * If we send an ATIO to the firmware to increment - * its command resource count, and the firmware is - * recovering from a Bus Device Reset, it returns - * the ATIO with this status. - */ - PRINTF("%s: ATIO returned with BDR received\n", isp->isp_name); - break; - - case AT_CDB: - /* - * New CDB - */ - cdp->cd_hba = isp; - cdp->cd_iid = aep->at_iid; - cdp->cd_tgt = aep->at_tgt; - cdp->cd_lun = aep->at_lun; - cdp->cd_tagtype = aep->at_tag_type; - cdp->cd_tagval = aep->at_tag_val; - MEMCPY(cdp->cd_cdb, aep->at_cdb, 16); - PRINTF("%s: CDB 0x%x itl %d/%d/%d\n", isp->isp_name, - cdp->cd_cdb[0], cdp->cd_iid, cdp->cd_tgt, cdp->cd_lun); - (*isp->isp_tmd_newcmd)(isp, cdp); - break; - - default: - PRINTF("%s: Unknown status (0x%x) in ATIO\n", - isp->isp_name, status); - cdp->cd_hba = isp; - cdp->cd_iid = aep->at_iid; - cdp->cd_tgt = aep->at_tgt; - cdp->cd_lun = aep->at_lun; - cdp->cd_tagtype = aep->at_tag_type; - cdp->cd_tagval = aep->at_tag_val; - isp_tgtcmd_done(cdp); - break; - } -} - -static void -isp_handle_atio2(isp, aep) - struct ispsoftc *isp; - at2_entry_t *aep; -{ - int status; - tmd_cmd_t local, *cdp = &local; - - /* - * Get the ATIO2 status. - */ - status = aep->at_status; - PRINTD("%s: ATIO2 status=0x%x\n", status); - - /* - * The firmware status (except for the SenseValid bit) indicates - * why this ATIO was sent to us. - * If SenseValid is set, the firware has recommended Sense Data. - */ - switch (status & ~TGTSVALID) { - case AT_PATH_INVALID: - /* - * ATIO rejected by the firmware due to disabled lun. - */ - PRINTF("%s: Firmware rejected ATIO2 for disabled lun %d\n", - isp->isp_name, aep->at_lun); - break; - - case AT_NOCAP: - /* - * Requested Capability not available - * We sent an ATIO that overflowed the firmware's - * command resource count. - */ - PRINTF("%s: Firmware rejected ATIO2, command count overflow\n", - isp->isp_name); - break; - - case AT_BDR_MSG: - /* - * If we send an ATIO to the firmware to increment - * its command resource count, and the firmware is - * recovering from a Bus Device Reset, it returns - * the ATIO with this status. - */ - PRINTF("%s: ATIO2 returned with BDR rcvd\n", isp->isp_name); - break; - - case AT_CDB: - /* - * New CDB - */ - cdp->cd_hba = isp; - cdp->cd_iid = aep->at_iid; - cdp->cd_tgt = 0; - cdp->cd_lun = aep->at_lun; - MEMCPY(cdp->cd_cdb, aep->at_cdb, 16); - cdp->cd_rxid = aep->at_rxid; - cdp->cp_origdlen = aep->at_datalen; - cdp->cp_totbytes = 0; - PRINTF("%s: CDB 0x%x rx_id 0x%x itl %d/%d/%d dlen %d\n", - isp->isp_name, cdp->cd_cdb[0], cdp->cd_tagval, cdp->cd_iid, - cdp->cd_tgt, cdp->cd_lun, aep->at_datalen); - (*isp->isp_tmd_newcmd)(isp, cdp); - break; - - default: - PRINTF("%s: Unknown status (0x%x) in ATIO2\n", - isp->isp_name, status); - cdp->cd_hba = isp; - cdp->cd_iid = aep->at_iid; - cdp->cd_tgt = aep->at_tgt; - cdp->cd_lun = aep->at_lun; - cdp->cp_rxid = aep->at_rxid; - isp_tgtcmd_done(cdp); - break; - } -} - -static void -isp_handle_ctio(isp, cep) - struct ispsoftc *isp; - ct_entry_t *aep; -{ -} - -static void -isp_handle_ctio2(isp, cep) - struct ispsoftc *isp; - at2_entry_t *aep; -{ } -#endif static void isp_parse_status(isp, sp, xs) @@ -3276,7 +2688,7 @@ isp_parse_status(isp, sp, xs) return; case RQCS_DATA_OVERRUN: - if (isp->isp_type & ISP_HA_FC) { + if (IS_FC(isp)) { XS_RESID(xs) = sp->req_resid; break; } @@ -3351,7 +2763,7 @@ isp_parse_status(isp, sp, xs) break; case RQCS_DATA_UNDERRUN: - if (isp->isp_type & ISP_HA_FC) { + if (IS_FC(isp)) { XS_RESID(xs) = sp->req_resid; /* an UNDERRUN is not a botch ??? */ } @@ -3476,19 +2888,21 @@ isp_parse_status(isp, sp, xs) static void isp_fastpost_complete(isp, fph) struct ispsoftc *isp; - int fph; + u_int32_t fph; { ISP_SCSI_XFER_T *xs; - if (fph < 1) + if (fph < 1) { return; - xs = (ISP_SCSI_XFER_T *) isp->isp_xflist[fph - 1]; - isp->isp_xflist[fph - 1] = NULL; + } + xs = isp_find_xs(isp, fph); if (xs == NULL) { - PRINTF("%s: fast posting handle 0x%x not found\n", - isp->isp_name, fph - 1); + PRINTF("%s: command for fast posting handle 0x%x not found\n", + isp->isp_name, fph); return; } + isp_destroy_handle(isp, fph); + /* * Since we don't have a result queue entry item, * we must believe that SCSI status is zero and @@ -3497,9 +2911,11 @@ isp_fastpost_complete(isp, fph) XS_RESID(xs) = 0; XS_STS(xs) = 0; if (XS_XFRLEN(xs)) { - ISP_DMAFREE(isp, xs, fph - 1); + ISP_DMAFREE(isp, xs, fph); } XS_CMD_DONE(xs); + if (isp->isp_nactive) + isp->isp_nactive--; } #define HINIB(x) ((x) >> 0x4) @@ -3658,7 +3074,7 @@ isp_mboxcmd(isp, mbp) * Check for variants */ #ifdef ISP2100_SCCLUN - if (isp->isp_type & ISP_HA_FC) { + if (IS_FC(isp)) { switch (mbp->param[0]) { case MBOX_ABORT: inparam = 7; @@ -3671,6 +3087,9 @@ isp_mboxcmd(isp, mbp) case MBOX_GET_DEV_QUEUE_STATUS: inparam = 3; break; + case MBOX_BUS_RESET: + inparam = 2; + break; default: break; } @@ -3685,6 +3104,12 @@ command_known: ISP_WRITE(isp, BIU_SEMA, 1); /* + * Qlogic Errata for the ISP2100 says that there is a necessary + * debounce between between writing the semaphore register + * and reading a mailbox register. I believe we're okay here. + */ + + /* * Make sure we can send some words. * Check to see if there's an async mbox event pending. */ @@ -3864,7 +3289,7 @@ command_known: /* * Pick up output parameters. Special case some of the readbacks - * for the dual port SCSI cards. + * for the dual port SCSI cards or FC Cards... */ if (IS_12X0(isp)) { switch (opcode) { @@ -3884,6 +3309,14 @@ command_known: mbp->param[2] = ISP_READ(isp, OUTMAILBOX2); break; } + } else if (IS_FC(isp)) { + switch (opcode) { + case MBOX_GET_LOOP_ID: + mbp->param[6] = ISP_READ(isp, OUTMAILBOX6); + break; + default: + break; + } } switch (outparam) { @@ -3914,32 +3347,24 @@ command_known: case MBOX_COMMAND_COMPLETE: break; case MBOX_INVALID_COMMAND: - IDPRINTF(2, ("%s: mbox cmd %x failed with INVALID_COMMAND\n", + IDPRINTF(2, ("%s: mbox cmd %x fails with INVALID_COMMAND\n", isp->isp_name, opcode)); break; case MBOX_HOST_INTERFACE_ERROR: - PRINTF("%s: mbox cmd %x failed with HOST_INTERFACE_ERROR\n", - isp->isp_name, opcode); + IDPRINTF(2, ("%s: mbox cmd %x fails with HOST_INTERFACE_ERR\n", + isp->isp_name, opcode)); break; case MBOX_TEST_FAILED: - PRINTF("%s: mbox cmd %x failed with TEST_FAILED\n", - isp->isp_name, opcode); + IDPRINTF(2, ("%s: mbox cmd %x fails with TEST_FAILED\n", + isp->isp_name, opcode)); break; case MBOX_COMMAND_ERROR: - if (opcode != MBOX_ABOUT_FIRMWARE) - PRINTF("%s: mbox cmd %x failed with COMMAND_ERROR\n", - isp->isp_name, opcode); + IDPRINTF(2, ("%s: mbox cmd %x fails with COMMAND_ERROR\n", + isp->isp_name, opcode)); break; case MBOX_COMMAND_PARAM_ERROR: - switch (opcode) { - case MBOX_GET_PORT_DB: - case MBOX_GET_PORT_NAME: - case MBOX_GET_DEV_QUEUE_PARAMS: - break; - default: - PRINTF("%s: mbox cmd %x failed with " - "COMMAND_PARAM_ERROR\n", isp->isp_name, opcode); - } + IDPRINTF(2, ("%s: mbox cmd %x fails with COMMAND_PARAM_ERROR\n", + isp->isp_name, opcode)); break; /* @@ -4019,7 +3444,7 @@ isp_dumpregs(isp, msg) const char *msg; { PRINTF("%s: %s\n", isp->isp_name, msg); - if (isp->isp_type & ISP_HA_SCSI) + if (IS_SCSI(isp)) PRINTF(" biu_conf1=%x", ISP_READ(isp, BIU_CONF1)); else PRINTF(" biu_csr=%x", ISP_READ(isp, BIU2100_CSR)); @@ -4028,7 +3453,7 @@ isp_dumpregs(isp, msg) PRINTF("risc_hccr=%x\n", ISP_READ(isp, HCCR)); - if (isp->isp_type & ISP_HA_SCSI) { + if (IS_SCSI(isp)) { ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); PRINTF(" cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n", ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS), @@ -4050,32 +3475,11 @@ isp_dumpregs(isp, msg) } static void -isp_dumpxflist(isp) - struct ispsoftc *isp; -{ - volatile ISP_SCSI_XFER_T *xs; - int i, hdp; - - for (hdp = i = 0; i < RQUEST_QUEUE_LEN; i++) { - xs = isp->isp_xflist[i]; - if (xs == NULL) { - continue; - } - if (hdp == 0) { - PRINTF("%s: active requests\n", isp->isp_name); - hdp++; - } - PRINTF(" Active Handle %d: tgt %d lun %d dlen %d\n", - i+1, XS_TGT(xs), XS_LUN(xs), XS_XFRLEN(xs)); - } -} - -static void isp_fw_state(isp) struct ispsoftc *isp; { mbreg_t mbs; - if (isp->isp_type & ISP_HA_FC) { + if (IS_FC(isp)) { int once = 0; fcparam *fcp = isp->isp_param; again: @@ -4142,7 +3546,7 @@ isp_update_bus(isp, bus) mbreg_t mbs; sdparam *sdp; - if (isp->isp_type & ISP_HA_FC) { + if (IS_FC(isp)) { return; } @@ -4154,8 +3558,8 @@ isp_update_bus(isp, bus) int get; if (sdp->isp_devparam[tgt].dev_enable == 0) { - PRINTF("%s: skipping update of target %d on bus %d\n", - isp->isp_name, tgt, bus); + IDPRINTF(1, ("%s: skipping target %d bus %d update\n", + isp->isp_name, tgt, bus)); continue; } @@ -4420,7 +3824,8 @@ isp_setdfltparm(isp, channel) /* * Re-initialize the ISP and complete all orphaned commands - * with a 'botched' notice. + * with a 'botched' notice. The reset/init routines should + * not disturb an already active list of commands. * * Locks held prior to coming here. */ @@ -4429,13 +3834,9 @@ void isp_restart(isp) struct ispsoftc *isp; { - ISP_SCSI_XFER_T *tlist[RQUEST_QUEUE_LEN], *xs; - int i; + ISP_SCSI_XFER_T *xs; + u_int32_t handle; - for (i = 0; i < RQUEST_QUEUE_LEN; i++) { - tlist[i] = (ISP_SCSI_XFER_T *) isp->isp_xflist[i]; - isp->isp_xflist[i] = NULL; - } #if 0 isp->isp_gotdparms = 0; #endif @@ -4449,15 +3850,20 @@ isp_restart(isp) if (isp->isp_state != ISP_RUNSTATE) { PRINTF("%s: isp_restart cannot restart ISP\n", isp->isp_name); } + isp->isp_nactive = 0; - for (i = 0; i < RQUEST_QUEUE_LEN; i++) { - xs = tlist[i]; - if (XS_NULL(xs)) { + for (handle = 1; handle <= (int) isp->isp_maxcmds; handle++) { + xs = isp_find_xs(isp, handle); + if (xs == NULL) { continue; } - if (isp->isp_nactive > 0) - isp->isp_nactive--; - XS_RESID(xs) = XS_XFRLEN(xs); + isp_destroy_handle(isp, handle); + if (XS_XFRLEN(xs)) { + ISP_DMAFREE(isp, xs, handle); + XS_RESID(xs) = XS_XFRLEN(xs); + } else { + XS_RESID(xs) = 0; + } XS_SETERR(xs, HBA_BUSRESET); XS_CMD_DONE(xs); } @@ -4797,14 +4203,24 @@ isp_read_nvram(isp) u_int32_t lo32; u_int32_t hi32; #endif - } wds; + } wd; u_int64_t full64; } wwnstore; wwnstore.full64 = ISP2100_NVRAM_NODE_NAME(nvram_data); - PRINTF("%s: Adapter WWN 0x%08x%08x\n", isp->isp_name, - wwnstore.wds.hi32, wwnstore.wds.lo32); + /* + * Broken PTI cards with nothing in the top nibble. Pah. + */ + if ((wwnstore.wd.hi32 >> 28) == 0) { + wwnstore.wd.hi32 |= (2 << 28); + CFGPRINTF("%s: (corrected) Adapter WWN 0x%08x%08x\n", + isp->isp_name, wwnstore.wd.hi32, wwnstore.wd.lo32); + } else { + CFGPRINTF("%s: Adapter WWN 0x%08x%08x\n", isp->isp_name, + wwnstore.wd.hi32, wwnstore.wd.lo32); + } fcp->isp_nodewwn = wwnstore.full64; + /* * If the Node WWN has 2 in the top nibble, we can * authoritatively construct a Port WWN by adding @@ -4821,8 +4237,7 @@ isp_read_nvram(isp) wwnstore.full64 = ISP2100_NVRAM_BOOT_NODE_NAME(nvram_data); if (wwnstore.full64 != 0) { PRINTF("%s: BOOT DEVICE WWN 0x%08x%08x\n", - isp->isp_name, wwnstore.wds.hi32, - wwnstore.wds.lo32); + isp->isp_name, wwnstore.wd.hi32, wwnstore.wd.lo32); } fcp->isp_maxalloc = ISP2100_NVRAM_MAXIOCBALLOCATION(nvram_data); |
