diff options
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/ic/isp.c | 1361 |
1 files changed, 1177 insertions, 184 deletions
diff --git a/sys/dev/ic/isp.c b/sys/dev/ic/isp.c index 44a41ff45dd..2c7ccd1d4fc 100644 --- a/sys/dev/ic/isp.c +++ b/sys/dev/ic/isp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: isp.c,v 1.25 2001/12/14 00:20:54 mjacob Exp $ */ +/* $OpenBSD: isp.c,v 1.26 2002/05/17 01:31:13 mjacob Exp $ */ /* * Machine and OS Independent (well, as best as possible) * code for the Qlogic ISP SCSI adapters. @@ -96,6 +96,8 @@ static const char pskip[] = "SCSI phase skipped for target %d.%d.%d"; static const char topology[] = "Loop ID %d, AL_PA 0x%x, Port ID 0x%x, Loop State 0x%x, Topology '%s'"; +static const char swrej[] = + "Fabric Nameserver rejected %s (Reason=0x%x Expl=0x%x) for Port ID 0x%x"; static const char finmsg[] = "(%d.%d.%d): FIN dl%d resid %d STS 0x%x SKEY %c XS_ERR=0x%x"; static const char sc0[] = @@ -105,16 +107,19 @@ static const char sc1[] = static const char sc2[] = "%s CHAN %d TGT %d FLAGS 0x%x 0x%x/0x%x"; static const char sc3[] = "Generated"; static const char sc4[] = "NVRAM"; +static const char bun[] = + "bad underrun for %d.%d (count %d, resid %d, status %s)"; /* * Local function prototypes. */ -static int isp_parse_async(struct ispsoftc *, int); +static int isp_parse_async(struct ispsoftc *, u_int16_t); static int isp_handle_other_response(struct ispsoftc *, int, isphdr_t *, u_int16_t *); static void isp_parse_status(struct ispsoftc *, ispstatusreq_t *, XS_T *); static void isp_fastpost_complete(struct ispsoftc *, u_int16_t); +static int isp_mbox_continue(struct ispsoftc *); static void isp_scsi_init(struct ispsoftc *); static void isp_scsi_channel_init(struct ispsoftc *, int); static void isp_fibre_init(struct ispsoftc *); @@ -126,9 +131,11 @@ static int isp_fclink_test(struct ispsoftc *, int); static char *isp2100_fw_statename(int); static int isp_pdb_sync(struct ispsoftc *); static int isp_scan_loop(struct ispsoftc *); -static int isp_scan_fabric(struct ispsoftc *); +static int isp_fabric_mbox_cmd(struct ispsoftc *, mbreg_t *); +static int isp_scan_fabric(struct ispsoftc *, int); static void isp_register_fc4_type(struct ispsoftc *); static void isp_fw_state(struct ispsoftc *); +static void isp_mboxcmd_qnw(struct ispsoftc *, mbreg_t *, int); static void isp_mboxcmd(struct ispsoftc *, mbreg_t *, int); static void isp_update(struct ispsoftc *); @@ -213,7 +220,7 @@ isp_reset(struct ispsoftc *isp) * Set up default request/response queue in-pointer/out-pointer * register indices. */ - if (IS_2300(isp)) { + if (IS_23XX(isp)) { isp->isp_rqstinrp = BIU_REQINP; isp->isp_rqstoutrp = BIU_REQOUTP; isp->isp_respinrp = BIU_RSPINP; @@ -242,6 +249,9 @@ isp_reset(struct ispsoftc *isp) case ISP_HA_FC_2300: btype = "2300"; break; + case ISP_HA_FC_2312: + btype = "2312"; + break; default: break; } @@ -535,7 +545,7 @@ again: #endif } else { ISP_WRITE(isp, RISC_MTR2100, 0x1212); - if (IS_2200(isp) || IS_2300(isp)) { + if (IS_2200(isp) || IS_23XX(isp)) { ISP_WRITE(isp, HCCR, HCCR_2X00_DISABLE_PARITY_PAUSE); } } @@ -553,7 +563,7 @@ again: * Avoid doing this on the 2312 because you can generate a PCI * parity error (chip breakage). */ - if (IS_2300(isp)) { + if (IS_23XX(isp)) { USEC_DELAY(5); } else { loops = MBOX_DELAY_COUNT; @@ -619,26 +629,26 @@ again: dodnld = 0; } - if (IS_2300(isp)) + if (IS_23XX(isp)) code_org = ISP_CODE_ORG_2300; else code_org = ISP_CODE_ORG; if (dodnld) { - u_int16_t fwlen = isp->isp_mdvec->dv_ispfw[3]; - for (i = 0; i < fwlen; i++) { - mbs.param[0] = MBOX_WRITE_RAM_WORD; - mbs.param[1] = code_org + i; - mbs.param[2] = isp->isp_mdvec->dv_ispfw[i]; - isp_mboxcmd(isp, &mbs, MBLOGNONE); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGERR, - "F/W download failed at word %d", i); - dodnld = 0; - goto again; - } + isp->isp_mbxworkp = (void *) &isp->isp_mdvec->dv_ispfw[1]; + isp->isp_mbxwrk0 = isp->isp_mdvec->dv_ispfw[3] - 1; + isp->isp_mbxwrk1 = code_org + 1; + mbs.param[0] = MBOX_WRITE_RAM_WORD; + mbs.param[1] = code_org; + mbs.param[2] = isp->isp_mdvec->dv_ispfw[0]; + isp_mboxcmd(isp, &mbs, MBLOGNONE); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, + "F/W download failed at word %d", + isp->isp_mbxwrk1 - code_org); + dodnld = 0; + goto again; } - /* * Verify that it downloaded correctly. */ @@ -666,8 +676,10 @@ again: mbs.param[0] = MBOX_EXEC_FIRMWARE; mbs.param[1] = code_org; isp_mboxcmd(isp, &mbs, MBLOGNONE); - /* give it a chance to start */ - USEC_SLEEP(isp, 500); + /* + * Give it a chance to start. + */ + USEC_DELAY(500); if (IS_SCSI(isp)) { /* @@ -765,7 +777,7 @@ again: * of knowing how many luns we support. * * Expanded lun firmware gives you 32 luns for SCSI cards and - * 65536 luns for Fibre Channel cards. + * 16384 luns for Fibre Channel cards. * * It turns out that even for QLogic 2100s with ROM 1.10 and above * we do get a firmware attributes word returned in mailbox register 6. @@ -788,7 +800,7 @@ again: } } else { if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) { - isp->isp_maxluns = 65536; + isp->isp_maxluns = 16384; } else { isp->isp_maxluns = 16; } @@ -966,8 +978,15 @@ isp_scsi_init(struct ispsoftc *isp) mbs.param[1] = 0; if (IS_ULTRA2(isp)) mbs.param[1] |= FW_FEATURE_LVD_NOTIFY; +#ifndef ISP_NO_RIO + if (IS_ULTRA2(isp) || IS_1240(isp)) + mbs.param[1] |= FW_FEATURE_RIO_16BIT; +#else +#ifndef ISP_NO_FASTPOST if (IS_ULTRA2(isp) || IS_1240(isp)) mbs.param[1] |= FW_FEATURE_FAST_POST; +#endif +#endif if (mbs.param[1] != 0) { u_int16_t sfeat = mbs.param[1]; isp_mboxcmd(isp, &mbs, MBLOGALL); @@ -1128,7 +1147,7 @@ isp_fibre_init(struct ispsoftc *isp) return; } - loopid = DEFAULT_LOOPID(isp); + loopid = fcp->isp_loopid; MEMZERO(icbp, sizeof (*icbp)); icbp->icb_version = ICB_VERSION1; @@ -1160,7 +1179,6 @@ isp_fibre_init(struct ispsoftc *isp) */ fcp->isp_fwoptions |= ICBOPT_PDBCHANGE_AE; - /* * Make sure that target role reflects into fwoptions. */ @@ -1204,7 +1222,7 @@ isp_fibre_init(struct ispsoftc *isp) * * NB: for the 2300, ICBOPT_EXTENDED is required. */ - if (IS_2200(isp) || IS_2300(isp)) { + if (IS_2200(isp) || IS_23XX(isp)) { icbp->icb_fwoptions |= ICBOPT_EXTENDED; /* * Prefer or force Point-To-Point instead Loop? @@ -1223,8 +1241,8 @@ isp_fibre_init(struct ispsoftc *isp) icbp->icb_xfwoptions |= ICBXOPT_LOOP_2_PTP; break; } - if (IS_2300(isp)) { - if (isp->isp_revision < 2) { + if (IS_23XX(isp)) { + if (IS_2300(isp) && isp->isp_revision < 2) { icbp->icb_fwoptions &= ~ICBOPT_FAST_POST; } if (isp->isp_confopts & ISP_CFG_ONEGB) { @@ -1237,8 +1255,29 @@ isp_fibre_init(struct ispsoftc *isp) } } +#ifndef ISP_NO_RIO_FC + /* + * RIO seems to be enabled in 2100s for fw >= 1.17.0. + * + * I've had some questionable problems with RIO on 2200. + * More specifically, on a 2204 I had problems with RIO + * on a Linux system where I was dropping commands right + * and left. It's not clear to me what the actual problem + * was, but it seems safer to only support this on the + * 23XX cards. + * + * I have it disabled if we support a target mode role for + * reasons I can't now remember. + */ + if ((isp->isp_role & ISP_ROLE_TARGET) == 0 && IS_23XX(isp)) { + icbp->icb_xfwoptions |= ICBXOPT_RIO_16BIT; + icbp->icb_racctimer = 4; + icbp->icb_idelaytimer = 8; + } +#endif + if ((IS_2200(isp) && ISP_FW_REVX(isp->isp_fwrev) >= - ISP_FW_REV(2, 1, 26)) || IS_2300(isp)) { + ISP_FW_REV(2, 1, 26)) || IS_23XX(isp)) { /* * Turn on LIP F8 async event (1) * Turn on generate AE 8013 on all LIP Resets (2) @@ -1252,7 +1291,7 @@ isp_fibre_init(struct ispsoftc *isp) } icbp->icb_logintime = 30; /* 30 second login timeout */ - if (IS_2300(isp)) { + if (IS_23XX(isp)) { ISP_WRITE(isp, isp->isp_rqstinrp, 0); ISP_WRITE(isp, isp->isp_rqstoutrp, 0); ISP_WRITE(isp, isp->isp_respinrp, 0); @@ -1287,6 +1326,8 @@ isp_fibre_init(struct ispsoftc *isp) icbp->icb_respaddr[RQRSP_ADDR4863] = DMA_WD3(isp->isp_result_dma); isp_prt(isp, ISP_LOGDEBUG1, "isp_fibre_init: fwoptions 0x%x", fcp->isp_fwoptions); + + FC_SCRATCH_ACQUIRE(isp); isp_put_icb(isp, icbp, (isp_icb_t *)fcp->isp_scratch); /* @@ -1301,6 +1342,7 @@ isp_fibre_init(struct ispsoftc *isp) mbs.param[6] = DMA_WD3(fcp->isp_scdma); mbs.param[7] = DMA_WD2(fcp->isp_scdma); isp_mboxcmd(isp, &mbs, MBLOGALL); + FC_SCRATCH_RELEASE(isp); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; } @@ -1340,12 +1382,15 @@ isp_getmap(struct ispsoftc *isp, fcpos_map_t *map) */ mbs.param[6] = 0; mbs.param[7] = 0; + FC_SCRATCH_ACQUIRE(isp); 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; + FC_SCRATCH_RELEASE(isp); return (0); } + FC_SCRATCH_RELEASE(isp); return (-1); } @@ -1378,11 +1423,14 @@ isp_getpdb(struct ispsoftc *isp, int id, isp_pdb_t *pdbp) */ mbs.param[6] = DMA_WD3(fcp->isp_scdma); mbs.param[7] = DMA_WD2(fcp->isp_scdma); + FC_SCRATCH_ACQUIRE(isp); isp_mboxcmd(isp, &mbs, MBLOGALL & ~MBOX_COMMAND_PARAM_ERROR); if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { isp_get_pdb(isp, (isp_pdb_t *)fcp->isp_scratch, pdbp); + FC_SCRATCH_RELEASE(isp); return (0); } + FC_SCRATCH_RELEASE(isp); return (-1); } @@ -1517,7 +1565,7 @@ isp_fclink_test(struct ispsoftc *isp, int usdelay) return (-1); } fcp->isp_loopid = mbs.param[1]; - if (IS_2200(isp) || IS_2300(isp)) { + if (IS_2200(isp) || IS_23XX(isp)) { int topo = (int) mbs.param[6]; if (topo < TOPO_NL_PORT || topo > TOPO_PTP_STUB) topo = TOPO_PTP_STUB; @@ -1594,7 +1642,7 @@ not_on_fabric: } fcp->isp_gbspeed = 1; - if (IS_2300(isp)) { + if (IS_23XX(isp)) { mbs.param[0] = MBOX_GET_SET_DATA_RATE; mbs.param[1] = MBGSD_GET_RATE; /* mbs.param[2] undefined if we're just getting rate */ @@ -1607,7 +1655,7 @@ not_on_fabric: } } - isp_prt(isp, ISP_LOGINFO, topology, fcp->isp_loopid, fcp->isp_alpa, + isp_prt(isp, ISP_LOGCONFIG, topology, fcp->isp_loopid, fcp->isp_alpa, fcp->isp_portid, fcp->isp_loopstate, toponames[fcp->isp_topo]); /* @@ -1774,7 +1822,7 @@ isp_pdb_sync(struct ispsoftc *isp) * that has, in fact, gone away. And it hangs trying to * log it out. */ - if (lp->loggedin && + if (lp->loggedin && lp->force_logout == 0 && isp_getpdb(isp, lp->loopid, &pdb) == 0) { int nrole; u_int64_t nwwnn, nwwpn; @@ -1803,15 +1851,13 @@ isp_pdb_sync(struct ispsoftc *isp) nwwnn == lp->node_wwn && nwwpn == lp->port_wwn && lp->roles == nrole && lp->force_logout == 0) { lp->loggedin = lp->valid = 1; - isp_prt(isp, ISP_LOGINFO, lretained, + isp_prt(isp, ISP_LOGCONFIG, lretained, (int) (lp - fcp->portdb), (int) lp->loopid, lp->portid); continue; } } - lp->force_logout = 0; - if (fcp->isp_fwstate != FW_READY || fcp->isp_loopstate != LOOP_SYNCING_PDB) { return (-1); @@ -1821,18 +1867,18 @@ isp_pdb_sync(struct ispsoftc *isp) * Force a logout if we were logged in. */ if (lp->loggedin) { - if (isp_getpdb(isp, lp->loopid, &pdb) == 0) { + if (lp->force_logout || + 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; + lp->force_logout = lp->loggedin = 0; if (fcp->isp_fwstate != FW_READY || fcp->isp_loopstate != LOOP_SYNCING_PDB) { return (-1); @@ -1849,10 +1895,6 @@ isp_pdb_sync(struct ispsoftc *isp) mbs.param[1] = loopid << 8; mbs.param[2] = portid >> 16; mbs.param[3] = portid & 0xffff; - if (IS_2200(isp) || IS_2300(isp)) { - /* only issue a PLOGI if not logged in */ - mbs.param[1] |= 0x1; - } isp_mboxcmd(isp, &mbs, MBLOGALL & ~(MBOX_LOOP_ID_USED | MBOX_PORT_ID_USED | MBOX_COMMAND_ERROR)); if (fcp->isp_fwstate != FW_READY || @@ -2256,18 +2298,69 @@ isp_scan_loop(struct ispsoftc *isp) return (0); } + static int -isp_scan_fabric(struct ispsoftc *isp) +isp_fabric_mbox_cmd(struct ispsoftc *isp, mbreg_t *mbp) +{ + isp_mboxcmd(isp, mbp, MBLOGNONE); + if (mbp->param[0] != MBOX_COMMAND_COMPLETE) { + if (FCPARAM(isp)->isp_loopstate == LOOP_SCANNING_FABRIC) { + FCPARAM(isp)->isp_loopstate = LOOP_PDB_RCVD; + } + if (mbp->param[0] == MBOX_COMMAND_ERROR) { + char tbuf[16]; + char *m; + switch (mbp->param[1]) { + case 1: + m = "No Loop"; + break; + case 2: + m = "Failed to allocate IOCB buffer"; + break; + case 3: + m = "Failed to allocate XCB buffer"; + break; + case 4: + m = "timeout or transmit failed"; + break; + case 5: + m = "no fabric loop"; + break; + case 6: + m = "remote device not a target"; + break; + default: + SNPRINTF(tbuf, sizeof tbuf, "%x", + mbp->param[1]); + m = tbuf; + break; + } + isp_prt(isp, ISP_LOGERR, "SNS Failed- %s", m); + } + return (-1); + } + + if (FCPARAM(isp)->isp_fwstate != FW_READY || + FCPARAM(isp)->isp_loopstate < LOOP_SCANNING_FABRIC) { + return (-1); + } + return(0); +} + +#ifdef ISP_USE_GA_NXT +static int +isp_scan_fabric(struct ispsoftc *isp, int ftype) { fcparam *fcp = isp->isp_param; u_int32_t portid, first_portid, last_portid; - int hicap, first_portid_seen, last_port_same; + int hicap, last_port_same; if (fcp->isp_onfabric == 0) { fcp->isp_loopstate = LOOP_FSCAN_DONE; return (0); } + FC_SCRATCH_ACQUIRE(isp); /* * Since Port IDs are 24 bits, we can check against having seen @@ -2278,28 +2371,28 @@ isp_scan_fabric(struct ispsoftc *isp) first_portid = portid = fcp->isp_portid; fcp->isp_loopstate = LOOP_SCANNING_FABRIC; - - for (first_portid_seen = hicap = 0; hicap < 65535; hicap++) { + for (hicap = 0; hicap < GA_NXT_MAX; hicap++) { mbreg_t mbs; sns_screq_t *rq; - sns_ganrsp_t *rs0, *rs1; - u_int8_t sc[SNS_GAN_REQ_SIZE]; + sns_ga_nxt_rsp_t *rs0, *rs1; + struct lportdb lcl; + u_int8_t sc[SNS_GA_NXT_RESP_SIZE]; rq = (sns_screq_t *)sc; - MEMZERO((void *) rq, SNS_GAN_REQ_SIZE); - rq->snscb_rblen = SNS_GAN_RESP_SIZE >> 1; + MEMZERO((void *) rq, SNS_GA_NXT_REQ_SIZE); + rq->snscb_rblen = SNS_GA_NXT_RESP_SIZE >> 1; rq->snscb_addr[RQRSP_ADDR0015] = DMA_WD0(fcp->isp_scdma+0x100); rq->snscb_addr[RQRSP_ADDR1631] = DMA_WD1(fcp->isp_scdma+0x100); rq->snscb_addr[RQRSP_ADDR3247] = DMA_WD2(fcp->isp_scdma+0x100); rq->snscb_addr[RQRSP_ADDR4863] = DMA_WD3(fcp->isp_scdma+0x100); rq->snscb_sblen = 6; - rq->snscb_data[0] = SNS_GAN; + rq->snscb_data[0] = SNS_GA_NXT; rq->snscb_data[4] = portid & 0xffff; rq->snscb_data[5] = (portid >> 16) & 0xff; isp_put_sns_request(isp, rq, (sns_screq_t *) fcp->isp_scratch); - MEMORYBARRIER(isp, SYNC_SFORDEV, 0, SNS_GAN_REQ_SIZE); + MEMORYBARRIER(isp, SYNC_SFORDEV, 0, SNS_GA_NXT_REQ_SIZE); mbs.param[0] = MBOX_SEND_SNS; - mbs.param[1] = SNS_GAN_REQ_SIZE >> 1; + mbs.param[1] = SNS_GA_NXT_REQ_SIZE >> 1; mbs.param[2] = DMA_WD1(fcp->isp_scdma); mbs.param[3] = DMA_WD0(fcp->isp_scdma); /* @@ -2307,57 +2400,80 @@ isp_scan_fabric(struct ispsoftc *isp) */ mbs.param[6] = DMA_WD3(fcp->isp_scdma); mbs.param[7] = DMA_WD2(fcp->isp_scdma); - isp_mboxcmd(isp, &mbs, MBLOGNONE); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - if (fcp->isp_loopstate == LOOP_SCANNING_FABRIC) { + if (isp_fabric_mbox_cmd(isp, &mbs)) { + if (fcp->isp_loopstate >= LOOP_SCANNING_FABRIC) { fcp->isp_loopstate = LOOP_PDB_RCVD; } - if (mbs.param[0] == MBOX_COMMAND_ERROR) { - char tbuf[16]; - char *m; - switch (mbs.param[1]) { - case 1: - m = "No Loop"; - break; - case 2: - m = "Failed to allocate IOCB buffer"; - break; - case 3: - m = "Failed to allocate XCB buffer"; - break; - case 4: - m = "timeout or transmit failed"; - break; - case 5: - m = "no fabric loop"; - break; - case 6: - m = "remote device not a target"; - break; - default: - SNPRINTF(tbuf, sizeof tbuf, "%x", - mbs.param[1]); - m = tbuf; - break; - } - isp_prt(isp, ISP_LOGERR, "SNS Failed- %s", m); - } + FC_SCRATCH_RELEASE(isp); return (-1); } - if (fcp->isp_fwstate != FW_READY || - fcp->isp_loopstate < LOOP_SCANNING_FABRIC) { - return (-1); + MEMORYBARRIER(isp, SYNC_SFORCPU, 0x100, SNS_GA_NXT_RESP_SIZE); + rs1 = (sns_ga_nxt_rsp_t *) sc; + rs0 = (sns_ga_nxt_rsp_t *) ((u_int8_t *)fcp->isp_scratch+0x100); + isp_get_ga_nxt_response(isp, rs0, rs1); + if (rs1->snscb_cthdr.ct_response != FS_ACC) { + isp_prt(isp, ISP_LOGWARN, swrej, "GA_NXT", + rs1->snscb_cthdr.ct_reason, + rs1->snscb_cthdr.ct_explanation, portid); + FC_SCRATCH_RELEASE(isp); + fcp->isp_loopstate = LOOP_FSCAN_DONE; + return (0); } - MEMORYBARRIER(isp, SYNC_SFORCPU, 0x100, SNS_GAN_RESP_SIZE); - rs1 = (sns_ganrsp_t *) fcp->isp_scratch; - rs0 = (sns_ganrsp_t *) ((u_int8_t *)fcp->isp_scratch + 0x100); - isp_get_gan_response(isp, rs0, rs1); - portid = (((u_int32_t) rs1->snscb_port_id[0]) << 16) | + portid = + (((u_int32_t) rs1->snscb_port_id[0]) << 16) | (((u_int32_t) rs1->snscb_port_id[1]) << 8) | (((u_int32_t) rs1->snscb_port_id[2])); - (void) isp_async(isp, ISPASYNC_FABRIC_DEV, rs1); + + /* + * Okay, we now have information about a fabric object. + * If it is the type we're interested in, tell the outer layers + * about it. The outer layer needs to know: Port ID, WWNN, + * WWPN, FC4 type, and port type. + * + * The lportdb structure is adequate for this. + */ + MEMZERO(&lcl, sizeof (lcl)); + lcl.port_type = rs1->snscb_port_type; + lcl.fc4_type = ftype; + lcl.portid = portid; + lcl.node_wwn = + (((u_int64_t)rs1->snscb_nodename[0]) << 56) | + (((u_int64_t)rs1->snscb_nodename[1]) << 48) | + (((u_int64_t)rs1->snscb_nodename[2]) << 40) | + (((u_int64_t)rs1->snscb_nodename[3]) << 32) | + (((u_int64_t)rs1->snscb_nodename[4]) << 24) | + (((u_int64_t)rs1->snscb_nodename[5]) << 16) | + (((u_int64_t)rs1->snscb_nodename[6]) << 8) | + (((u_int64_t)rs1->snscb_nodename[7])); + lcl.port_wwn = + (((u_int64_t)rs1->snscb_portname[0]) << 56) | + (((u_int64_t)rs1->snscb_portname[1]) << 48) | + (((u_int64_t)rs1->snscb_portname[2]) << 40) | + (((u_int64_t)rs1->snscb_portname[3]) << 32) | + (((u_int64_t)rs1->snscb_portname[4]) << 24) | + (((u_int64_t)rs1->snscb_portname[5]) << 16) | + (((u_int64_t)rs1->snscb_portname[6]) << 8) | + (((u_int64_t)rs1->snscb_portname[7])); + + /* + * Does this fabric object support the type we want? + * If not, skip it. + */ + if (rs1->snscb_fc4_types[ftype >> 5] & (1 << (ftype & 0x1f))) { + if (first_portid == portid) { + lcl.last_fabric_dev = 1; + } else { + lcl.last_fabric_dev = 0; + } + (void) isp_async(isp, ISPASYNC_FABRIC_DEV, &lcl); + } else { + isp_prt(isp, ISP_LOGDEBUG0, + "PortID 0x%x doesn't support FC4 type 0x%x", + portid, ftype); + } if (first_portid == portid) { fcp->isp_loopstate = LOOP_FSCAN_DONE; + FC_SCRATCH_RELEASE(isp); return (0); } if (portid == last_portid) { @@ -2367,46 +2483,346 @@ isp_scan_fabric(struct ispsoftc *isp) break; } } else { + last_port_same = 0 ; last_portid = portid; } } + FC_SCRATCH_RELEASE(isp); + if (hicap >= GA_NXT_MAX) { + isp_prt(isp, ISP_LOGWARN, "fabric too big (> %d)", GA_NXT_MAX); + } + fcp->isp_loopstate = LOOP_FSCAN_DONE; + return (0); +} +#else +#define GIDLEN ((ISP2100_SCRLEN >> 1) + 16) +#define NGENT ((GIDLEN - 16) >> 2) - if (hicap >= 65535) { - isp_prt(isp, ISP_LOGWARN, "fabric too big (> 65535)"); +#define IGPOFF (ISP2100_SCRLEN - GIDLEN) +#define GXOFF (256) + +static int +isp_scan_fabric(struct ispsoftc *isp, int ftype) +{ + fcparam *fcp = FCPARAM(isp); + mbreg_t mbs; + int i; + sns_gid_ft_req_t *rq; + sns_gid_ft_rsp_t *rs0, *rs1; + + if (fcp->isp_onfabric == 0) { + fcp->isp_loopstate = LOOP_FSCAN_DONE; + return (0); } + FC_SCRATCH_ACQUIRE(isp); + fcp->isp_loopstate = LOOP_SCANNING_FABRIC; + + rq = (sns_gid_ft_req_t *)fcp->tport; + MEMZERO((void *) rq, SNS_GID_FT_REQ_SIZE); + rq->snscb_rblen = GIDLEN >> 1; + rq->snscb_addr[RQRSP_ADDR0015] = DMA_WD0(fcp->isp_scdma+IGPOFF); + rq->snscb_addr[RQRSP_ADDR1631] = DMA_WD1(fcp->isp_scdma+IGPOFF); + rq->snscb_addr[RQRSP_ADDR3247] = DMA_WD2(fcp->isp_scdma+IGPOFF); + rq->snscb_addr[RQRSP_ADDR4863] = DMA_WD3(fcp->isp_scdma+IGPOFF); + rq->snscb_sblen = 6; + rq->snscb_cmd = SNS_GID_FT; + rq->snscb_mword_div_2 = NGENT; + rq->snscb_fc4_type = ftype; + isp_put_gid_ft_request(isp, rq, (sns_gid_ft_req_t *) fcp->isp_scratch); + MEMORYBARRIER(isp, SYNC_SFORDEV, 0, SNS_GID_FT_REQ_SIZE); + mbs.param[0] = MBOX_SEND_SNS; + mbs.param[1] = SNS_GID_FT_REQ_SIZE >> 1; + mbs.param[2] = DMA_WD1(fcp->isp_scdma); + mbs.param[3] = DMA_WD0(fcp->isp_scdma); + /* - * We either have a broken name server or a huge fabric if we get here. + * Leave 4 and 5 alone */ + mbs.param[6] = DMA_WD3(fcp->isp_scdma); + mbs.param[7] = DMA_WD2(fcp->isp_scdma); + if (isp_fabric_mbox_cmd(isp, &mbs)) { + if (fcp->isp_loopstate >= LOOP_SCANNING_FABRIC) { + fcp->isp_loopstate = LOOP_PDB_RCVD; + } + FC_SCRATCH_RELEASE(isp); + return (-1); + } + if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { + FC_SCRATCH_RELEASE(isp); + return (-1); + } + MEMORYBARRIER(isp, SYNC_SFORCPU, IGPOFF, GIDLEN); + rs1 = (sns_gid_ft_rsp_t *) fcp->tport; + rs0 = (sns_gid_ft_rsp_t *) ((u_int8_t *)fcp->isp_scratch+IGPOFF); + isp_get_gid_ft_response(isp, rs0, rs1, NGENT); + if (rs1->snscb_cthdr.ct_response != FS_ACC) { + isp_prt(isp, ISP_LOGWARN, swrej, "GID_FT", + rs1->snscb_cthdr.ct_reason, + rs1->snscb_cthdr.ct_explanation, 0); + FC_SCRATCH_RELEASE(isp); + fcp->isp_loopstate = LOOP_FSCAN_DONE; + return (0); + } + + /* + * Okay, we now have a list of Port IDs for this class of device. + * Go through the list and for each one get the WWPN/WWNN for it + * and tell the outer layers about it. The outer layer needs to + * know: Port ID, WWNN, WWPN, FC4 type, and (possibly) port type. + * + * The lportdb structure is adequate for this. + */ + i = -1; + do { + sns_gxn_id_req_t grqbuf, *gq = &grqbuf; + sns_gxn_id_rsp_t *gs0, grsbuf, *gs1 = &grsbuf; + struct lportdb lcl; +#if 0 + sns_gff_id_rsp_t *fs0, ffsbuf, *fs1 = &ffsbuf; +#endif + + i++; + MEMZERO(&lcl, sizeof (lcl)); + lcl.fc4_type = ftype; + lcl.portid = + (((u_int32_t) rs1->snscb_ports[i].portid[0]) << 16) | + (((u_int32_t) rs1->snscb_ports[i].portid[1]) << 8) | + (((u_int32_t) rs1->snscb_ports[i].portid[2])); + + MEMZERO((void *) gq, sizeof (sns_gxn_id_req_t)); + gq->snscb_rblen = SNS_GXN_ID_RESP_SIZE >> 1; + gq->snscb_addr[RQRSP_ADDR0015] = DMA_WD0(fcp->isp_scdma+GXOFF); + gq->snscb_addr[RQRSP_ADDR1631] = DMA_WD1(fcp->isp_scdma+GXOFF); + gq->snscb_addr[RQRSP_ADDR3247] = DMA_WD2(fcp->isp_scdma+GXOFF); + gq->snscb_addr[RQRSP_ADDR4863] = DMA_WD3(fcp->isp_scdma+GXOFF); + gq->snscb_sblen = 6; + gq->snscb_cmd = SNS_GPN_ID; + gq->snscb_portid = lcl.portid; + isp_put_gxn_id_request(isp, gq, + (sns_gxn_id_req_t *) fcp->isp_scratch); + MEMORYBARRIER(isp, SYNC_SFORDEV, 0, SNS_GXN_ID_REQ_SIZE); + mbs.param[0] = MBOX_SEND_SNS; + mbs.param[1] = SNS_GXN_ID_REQ_SIZE >> 1; + mbs.param[2] = DMA_WD1(fcp->isp_scdma); + mbs.param[3] = DMA_WD0(fcp->isp_scdma); + /* + * Leave 4 and 5 alone + */ + mbs.param[6] = DMA_WD3(fcp->isp_scdma); + mbs.param[7] = DMA_WD2(fcp->isp_scdma); + if (isp_fabric_mbox_cmd(isp, &mbs)) { + if (fcp->isp_loopstate >= LOOP_SCANNING_FABRIC) { + fcp->isp_loopstate = LOOP_PDB_RCVD; + } + FC_SCRATCH_RELEASE(isp); + return (-1); + } + if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { + FC_SCRATCH_RELEASE(isp); + return (-1); + } + MEMORYBARRIER(isp, SYNC_SFORCPU, GXOFF, SNS_GXN_ID_RESP_SIZE); + gs0 = (sns_gxn_id_rsp_t *) ((u_int8_t *)fcp->isp_scratch+GXOFF); + isp_get_gxn_id_response(isp, gs0, gs1); + if (gs1->snscb_cthdr.ct_response != FS_ACC) { + isp_prt(isp, ISP_LOGWARN, swrej, "GPN_ID", + gs1->snscb_cthdr.ct_reason, + gs1->snscb_cthdr.ct_explanation, lcl.portid); + if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { + FC_SCRATCH_RELEASE(isp); + return (-1); + } + continue; + } + lcl.port_wwn = + (((u_int64_t)gs1->snscb_wwn[0]) << 56) | + (((u_int64_t)gs1->snscb_wwn[1]) << 48) | + (((u_int64_t)gs1->snscb_wwn[2]) << 40) | + (((u_int64_t)gs1->snscb_wwn[3]) << 32) | + (((u_int64_t)gs1->snscb_wwn[4]) << 24) | + (((u_int64_t)gs1->snscb_wwn[5]) << 16) | + (((u_int64_t)gs1->snscb_wwn[6]) << 8) | + (((u_int64_t)gs1->snscb_wwn[7])); + + MEMZERO((void *) gq, sizeof (sns_gxn_id_req_t)); + gq->snscb_rblen = SNS_GXN_ID_RESP_SIZE >> 1; + gq->snscb_addr[RQRSP_ADDR0015] = DMA_WD0(fcp->isp_scdma+GXOFF); + gq->snscb_addr[RQRSP_ADDR1631] = DMA_WD1(fcp->isp_scdma+GXOFF); + gq->snscb_addr[RQRSP_ADDR3247] = DMA_WD2(fcp->isp_scdma+GXOFF); + gq->snscb_addr[RQRSP_ADDR4863] = DMA_WD3(fcp->isp_scdma+GXOFF); + gq->snscb_sblen = 6; + gq->snscb_cmd = SNS_GNN_ID; + gq->snscb_portid = lcl.portid; + isp_put_gxn_id_request(isp, gq, + (sns_gxn_id_req_t *) fcp->isp_scratch); + MEMORYBARRIER(isp, SYNC_SFORDEV, 0, SNS_GXN_ID_REQ_SIZE); + mbs.param[0] = MBOX_SEND_SNS; + mbs.param[1] = SNS_GXN_ID_REQ_SIZE >> 1; + mbs.param[2] = DMA_WD1(fcp->isp_scdma); + mbs.param[3] = DMA_WD0(fcp->isp_scdma); + /* + * Leave 4 and 5 alone + */ + mbs.param[6] = DMA_WD3(fcp->isp_scdma); + mbs.param[7] = DMA_WD2(fcp->isp_scdma); + if (isp_fabric_mbox_cmd(isp, &mbs)) { + if (fcp->isp_loopstate >= LOOP_SCANNING_FABRIC) { + fcp->isp_loopstate = LOOP_PDB_RCVD; + } + FC_SCRATCH_RELEASE(isp); + return (-1); + } + if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { + FC_SCRATCH_RELEASE(isp); + return (-1); + } + MEMORYBARRIER(isp, SYNC_SFORCPU, GXOFF, SNS_GXN_ID_RESP_SIZE); + gs0 = (sns_gxn_id_rsp_t *) ((u_int8_t *)fcp->isp_scratch+GXOFF); + isp_get_gxn_id_response(isp, gs0, gs1); + if (gs1->snscb_cthdr.ct_response != FS_ACC) { + isp_prt(isp, ISP_LOGWARN, swrej, "GNN_ID", + gs1->snscb_cthdr.ct_reason, + gs1->snscb_cthdr.ct_explanation, lcl.portid); + if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { + FC_SCRATCH_RELEASE(isp); + return (-1); + } + continue; + } + lcl.node_wwn = + (((u_int64_t)gs1->snscb_wwn[0]) << 56) | + (((u_int64_t)gs1->snscb_wwn[1]) << 48) | + (((u_int64_t)gs1->snscb_wwn[2]) << 40) | + (((u_int64_t)gs1->snscb_wwn[3]) << 32) | + (((u_int64_t)gs1->snscb_wwn[4]) << 24) | + (((u_int64_t)gs1->snscb_wwn[5]) << 16) | + (((u_int64_t)gs1->snscb_wwn[6]) << 8) | + (((u_int64_t)gs1->snscb_wwn[7])); + + /* + * The QLogic f/w is bouncing this with a parameter error. + */ +#if 0 + /* + * Try and get FC4 Features (FC-GS-3 only). + * We can use the sns_gxn_id_req_t for this request. + */ + MEMZERO((void *) gq, sizeof (sns_gxn_id_req_t)); + gq->snscb_rblen = SNS_GFF_ID_RESP_SIZE >> 1; + gq->snscb_addr[RQRSP_ADDR0015] = DMA_WD0(fcp->isp_scdma+GXOFF); + gq->snscb_addr[RQRSP_ADDR1631] = DMA_WD1(fcp->isp_scdma+GXOFF); + gq->snscb_addr[RQRSP_ADDR3247] = DMA_WD2(fcp->isp_scdma+GXOFF); + gq->snscb_addr[RQRSP_ADDR4863] = DMA_WD3(fcp->isp_scdma+GXOFF); + gq->snscb_sblen = 6; + gq->snscb_cmd = SNS_GFF_ID; + gq->snscb_portid = lcl.portid; + isp_put_gxn_id_request(isp, gq, + (sns_gxn_id_req_t *) fcp->isp_scratch); + MEMORYBARRIER(isp, SYNC_SFORDEV, 0, SNS_GXN_ID_REQ_SIZE); + mbs.param[0] = MBOX_SEND_SNS; + mbs.param[1] = SNS_GXN_ID_REQ_SIZE >> 1; + mbs.param[2] = DMA_WD1(fcp->isp_scdma); + mbs.param[3] = DMA_WD0(fcp->isp_scdma); + /* + * Leave 4 and 5 alone + */ + mbs.param[6] = DMA_WD3(fcp->isp_scdma); + mbs.param[7] = DMA_WD2(fcp->isp_scdma); + if (isp_fabric_mbox_cmd(isp, &mbs)) { + if (fcp->isp_loopstate >= LOOP_SCANNING_FABRIC) { + fcp->isp_loopstate = LOOP_PDB_RCVD; + } + FC_SCRATCH_RELEASE(isp); + return (-1); + } + if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { + FC_SCRATCH_RELEASE(isp); + return (-1); + } + MEMORYBARRIER(isp, SYNC_SFORCPU, GXOFF, SNS_GFF_ID_RESP_SIZE); + fs0 = (sns_gff_id_rsp_t *) ((u_int8_t *)fcp->isp_scratch+GXOFF); + isp_get_gff_id_response(isp, fs0, fs1); + if (fs1->snscb_cthdr.ct_response != FS_ACC) { + isp_prt(isp, /* ISP_LOGDEBUG0 */ ISP_LOGWARN, + swrej, "GFF_ID", + fs1->snscb_cthdr.ct_reason, + fs1->snscb_cthdr.ct_explanation, lcl.portid); + if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { + FC_SCRATCH_RELEASE(isp); + return (-1); + } + } else { + int index = (ftype >> 3); + int bshft = (ftype & 0x7) * 4; + int fc4_fval = + (fs1->snscb_fc4_features[index] >> bshft) & 0xf; + if (fc4_fval & 0x1) { + lcl.roles |= + (SVC3_INI_ROLE >> SVC3_ROLE_SHIFT); + } + if (fc4_fval & 0x2) { + lcl.roles |= + (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT); + } + } +#endif + + /* + * If we really want to know what kind of port type this is, + * we have to run another CT command. Otherwise, we'll leave + * it as undefined. + * + lcl.port_type = 0; + */ + if (rs1->snscb_ports[i].control & 0x80) { + lcl.last_fabric_dev = 1; + } else { + lcl.last_fabric_dev = 0; + } + (void) isp_async(isp, ISPASYNC_FABRIC_DEV, &lcl); + + } while ((rs1->snscb_ports[i].control & 0x80) == 0 && i < NGENT-1); + + /* + * If we're not at the last entry, our list isn't big enough. + */ + if ((rs1->snscb_ports[i].control & 0x80) == 0) { + isp_prt(isp, ISP_LOGWARN, "fabric too big for scratch area"); + } + + FC_SCRATCH_RELEASE(isp); fcp->isp_loopstate = LOOP_FSCAN_DONE; return (0); } +#endif static void isp_register_fc4_type(struct ispsoftc *isp) { fcparam *fcp = isp->isp_param; - u_int8_t local[SNS_RFT_REQ_SIZE]; + u_int8_t local[SNS_RFT_ID_REQ_SIZE]; sns_screq_t *reqp = (sns_screq_t *) local; mbreg_t mbs; - MEMZERO((void *) reqp, SNS_RFT_REQ_SIZE); - reqp->snscb_rblen = SNS_RFT_RESP_SIZE >> 1; + MEMZERO((void *) reqp, SNS_RFT_ID_REQ_SIZE); + reqp->snscb_rblen = SNS_RFT_ID_RESP_SIZE >> 1; reqp->snscb_addr[RQRSP_ADDR0015] = DMA_WD0(fcp->isp_scdma + 0x100); reqp->snscb_addr[RQRSP_ADDR1631] = DMA_WD1(fcp->isp_scdma + 0x100); reqp->snscb_addr[RQRSP_ADDR3247] = DMA_WD2(fcp->isp_scdma + 0x100); reqp->snscb_addr[RQRSP_ADDR4863] = DMA_WD3(fcp->isp_scdma + 0x100); reqp->snscb_sblen = 22; - reqp->snscb_data[0] = SNS_RFT; + reqp->snscb_data[0] = SNS_RFT_ID; reqp->snscb_data[4] = fcp->isp_portid & 0xffff; reqp->snscb_data[5] = (fcp->isp_portid >> 16) & 0xff; - reqp->snscb_data[6] = 0x100; /* SCS - FCP */ + reqp->snscb_data[6] = (1 << FC4_SCSI); #if 0 - reqp->snscb_data[6] |= 20; /* ISO/IEC 8802-2 LLC/SNAP */ + reqp->snscb_data[6] |= (1 << FC4_IP); /* ISO/IEC 8802-2 LLC/SNAP */ #endif + FC_SCRATCH_ACQUIRE(isp); isp_put_sns_request(isp, reqp, (sns_screq_t *) fcp->isp_scratch); mbs.param[0] = MBOX_SEND_SNS; - mbs.param[1] = SNS_RFT_REQ_SIZE >> 1; + mbs.param[1] = SNS_RFT_ID_REQ_SIZE >> 1; mbs.param[2] = DMA_WD1(fcp->isp_scdma); mbs.param[3] = DMA_WD0(fcp->isp_scdma); /* @@ -2415,6 +2831,7 @@ isp_register_fc4_type(struct ispsoftc *isp) mbs.param[6] = DMA_WD3(fcp->isp_scdma); mbs.param[7] = DMA_WD2(fcp->isp_scdma); isp_mboxcmd(isp, &mbs, MBLOGALL); + FC_SCRATCH_RELEASE(isp); if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { isp_prt(isp, ISP_LOGDEBUG0, "Register FC4 types succeeded"); } @@ -2603,7 +3020,7 @@ isp_start(XS_T *xs) * 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)) { + if (isp_scan_fabric(isp, FC4_SCSI)) { return (CMD_RQLATER); } if (fcp->isp_fwstate != FW_READY || @@ -2902,7 +3319,8 @@ isp_control(struct ispsoftc *isp, ispctl_t ctl, void *arg) case ISPCTL_SCAN_FABRIC: if (IS_FC(isp)) { - return (isp_scan_fabric(isp)); + int ftype = (arg)? *((int *) arg) : FC4_SCSI; + return (isp_scan_fabric(isp, ftype)); } break; @@ -2979,7 +3397,9 @@ isp_control(struct ispsoftc *isp, ispctl_t ctl, void *arg) * Limit our stack depth by sticking with the max likely number * of completions on a request queue at any one time. */ -#define MAX_REQUESTQ_COMPLETIONS 32 +#ifndef MAX_REQUESTQ_COMPLETIONS +#define MAX_REQUESTQ_COMPLETIONS 64 +#endif void isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) @@ -2988,12 +3408,14 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) u_int16_t iptr, optr, junk; int i, nlooked = 0, ndone = 0; +again: /* * Is this a mailbox related interrupt? * The mailbox semaphore will be nonzero if so. */ if (sema) { if (mbox & 0x4000) { + isp->isp_intmboxc++; if (isp->isp_mboxbsy) { int i = 0, obits = isp->isp_obits; isp->isp_mboxtmp[i++] = mbox; @@ -3004,18 +3426,19 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) isp->isp_mboxtmp[i] = ISP_READ(isp, MBOX_OFF(i)); } + if (isp->isp_mbxwrk0) { + if (isp_mbox_continue(isp) == 0) { + return; + } + } MBOX_NOTIFY_COMPLETE(isp); } else { isp_prt(isp, ISP_LOGWARN, "Mbox Command Async (0x%x) with no waiters", mbox); } - } else { - int fhandle = isp_parse_async(isp, (int) mbox); - isp_prt(isp, ISP_LOGDEBUG2, "Async Mbox 0x%x", mbox); - if (fhandle > 0) { - isp_fastpost_complete(isp, (u_int16_t) fhandle); - } + } else if (isp_parse_async(isp, mbox) < 0) { + return; } if (IS_FC(isp) || isp->isp_state != ISP_RUNSTATE) { ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT); @@ -3046,8 +3469,11 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) * * If we're a 2300, we can ask what hardware what it thinks. */ - if (IS_2300(isp)) { + if (IS_23XX(isp)) { optr = ISP_READ(isp, isp->isp_respoutrp); + /* + * Debug: to be taken out eventually + */ if (isp->isp_residx != optr) { isp_prt(isp, ISP_LOGWARN, "optr %x soft optr %x", optr, isp->isp_residx); @@ -3059,8 +3485,10 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) /* * You *must* read the Response Queue In Pointer * prior to clearing the RISC interrupt. + * + * Debounce the 2300 if revision less than 2. */ - if (IS_2100(isp) || IS_2300(isp)) { + if (IS_2100(isp) || (IS_2300(isp) && isp->isp_revision < 2)) { i = 0; do { iptr = READ_RESPONSE_QUEUE_IN_POINTER(isp); @@ -3077,6 +3505,7 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) } else { iptr = READ_RESPONSE_QUEUE_IN_POINTER(isp); } + isp->isp_resodx = iptr; if (optr == iptr && sema == 0) { @@ -3088,7 +3517,7 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) * make sure the old interrupt went away (to avoid 'ringing' * effects), but that didn't stop this from occurring. */ - if (IS_2300(isp)) { + if (IS_23XX(isp)) { USEC_DELAY(100); iptr = READ_RESPONSE_QUEUE_IN_POINTER(isp); junk = ISP_READ(isp, BIU_R2HSTSLO); @@ -3096,15 +3525,30 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) junk = ISP_READ(isp, BIU_ISR); } if (optr == iptr) { - isp_prt(isp, ISP_LOGDEBUG0, + if (IS_23XX(isp)) { + ; + } else { + sema = ISP_READ(isp, BIU_SEMA); + mbox = ISP_READ(isp, OUTMAILBOX0); + if ((sema & 0x3) && (mbox & 0x8000)) { + goto again; + } + } + isp->isp_intbogus++; + isp_prt(isp, ISP_LOGDEBUG1, "bogus intr- isr %x (%x) iptr %x optr %x", isr, junk, iptr, optr); - isp->isp_intbogus++; } } + isp->isp_resodx = iptr; ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT); ISP_WRITE(isp, BIU_SEMA, 0); + if (isp->isp_rspbsy) { + return; + } + isp->isp_rspbsy = 1; + while (optr != iptr) { ispstatusreq_t local, *sp = &local; isphdr_t *hp; @@ -3125,8 +3569,24 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) if (type == RQSTYPE_RESPONSE) { isp_get_response(isp, (ispstatusreq_t *) hp, sp); + } else if (type == RQSTYPE_RIO2) { + isp_rio2_t rio; + isp_get_rio2(isp, (isp_rio2_t *) hp, &rio); + for (i = 0; i < rio.req_header.rqs_seqno; i++) { + isp_fastpost_complete(isp, rio.req_handles[i]); + } + if (isp->isp_fpcchiwater < rio.req_header.rqs_seqno) + isp->isp_fpcchiwater = rio.req_header.rqs_seqno; + MEMZERO(hp, QENTRY_LEN); /* PERF */ + continue; } else { - if (!isp_handle_other_response(isp, type, hp, &optr)) { + /* + * Somebody reachable via isp_handle_other_response + * may have updated the response queue pointers for + * us, so we reload our goal index. + */ + if (isp_handle_other_response(isp, type, hp, &optr)) { + iptr = isp->isp_resodx; MEMZERO(hp, QENTRY_LEN); /* PERF */ continue; } @@ -3200,10 +3660,18 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) } xs = isp_find_xs(isp, sp->req_handle); if (xs == NULL) { + u_int8_t ts = sp->req_completion_status & 0xff; MEMZERO(hp, QENTRY_LEN); /* PERF */ - isp_prt(isp, ISP_LOGERR, - "cannot find handle 0x%x in xflist", - sp->req_handle); + /* + * Only whine if this isn't the expected fallout of + * aborting the command. + */ + if (sp->req_header.rqs_entry_type != RQSTYPE_RESPONSE || + ts != RQCS_ABORTED) { + isp_prt(isp, ISP_LOGERR, + "cannot find handle 0x%x in xflist", + sp->req_handle); + } WRITE_RESPONSE_QUEUE_OUT_POINTER(isp, optr); continue; } @@ -3347,15 +3815,19 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) if (nlooked) { WRITE_RESPONSE_QUEUE_OUT_POINTER(isp, optr); /* - * While we're at it, reqad the requst queue out pointer. + * While we're at it, read the requst queue out pointer. */ isp->isp_reqodx = READ_REQUEST_QUEUE_OUT_POINTER(isp); + if (isp->isp_rscchiwater < ndone) + isp->isp_rscchiwater = ndone; } isp->isp_residx = optr; + isp->isp_rspbsy = 0; for (i = 0; i < ndone; i++) { xs = complist[i]; if (xs) { + isp->isp_rsltccmplt++; isp_done(xs); } } @@ -3366,29 +3838,32 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) */ static int -isp_parse_async(struct ispsoftc *isp, int mbox) +isp_parse_async(struct ispsoftc *isp, u_int16_t mbox) { + int rval = 0; int bus; - u_int16_t fast_post_handle = 0; if (IS_DUALBUS(isp)) { bus = ISP_READ(isp, OUTMAILBOX6); } else { bus = 0; } + isp_prt(isp, ISP_LOGDEBUG2, "Async Mbox 0x%x", mbox); switch (mbox) { case ASYNC_BUS_RESET: isp->isp_sendmarker |= (1 << bus); #ifdef ISP_TARGET_MODE - isp_target_async(isp, bus, mbox); + if (isp_target_async(isp, bus, mbox)) + rval = -1; #endif isp_async(isp, ISPASYNC_BUS_RESET, &bus); break; case ASYNC_SYSTEM_ERROR: isp_async(isp, ISPASYNC_FW_CRASH, NULL); /* no point continuing after this */ - return (-1); + rval = -1; + break; case ASYNC_RQS_XFER_ERR: isp_prt(isp, ISP_LOGERR, "Request Queue Transfer Error"); @@ -3412,7 +3887,8 @@ isp_parse_async(struct ispsoftc *isp, int mbox) "timeout initiated SCSI bus reset of bus %d", bus); isp->isp_sendmarker |= (1 << bus); #ifdef ISP_TARGET_MODE - isp_target_async(isp, bus, mbox); + if (isp_target_async(isp, bus, mbox)) + rval = -1; #endif break; @@ -3420,7 +3896,8 @@ isp_parse_async(struct ispsoftc *isp, int mbox) isp_prt(isp, ISP_LOGINFO, "device reset on bus %d", bus); isp->isp_sendmarker |= (1 << bus); #ifdef ISP_TARGET_MODE - isp_target_async(isp, bus, mbox); + if (isp_target_async(isp, bus, mbox)) + rval = -1; #endif break; @@ -3477,26 +3954,48 @@ isp_parse_async(struct ispsoftc *isp, int mbox) isp->isp_sendmarker |= (1 << bus); break; + /* + * We can use bus, which will always be zero for FC cards, + * as a mailbox pattern accumulator to be checked below. + */ + case ASYNC_RIO5: + bus = 0x1ce; /* outgoing mailbox regs 1-3, 6-7 */ + break; + + case ASYNC_RIO4: + bus = 0x14e; /* outgoing mailbox regs 1-3, 6 */ + break; + + case ASYNC_RIO3: + bus = 0x10e; /* outgoing mailbox regs 1-3 */ + break; + + case ASYNC_RIO2: + bus = 0x106; /* outgoing mailbox regs 1-2 */ + break; + + case ASYNC_RIO1: case ASYNC_CMD_CMPLT: - fast_post_handle = ISP_READ(isp, OUTMAILBOX1); - isp_prt(isp, ISP_LOGDEBUG3, "fast post completion of %u", - fast_post_handle); + bus = 0x102; /* outgoing mailbox regs 1 */ + break; + + case ASYNC_RIO_RESP: break; case ASYNC_CTIO_DONE: + { #ifdef ISP_TARGET_MODE - /* - * Bus gets overloaded with the handle. Dual bus - * cards don't put bus# into the handle. - */ - bus = (ISP_READ(isp, OUTMAILBOX2) << 16) | - ISP_READ(isp, OUTMAILBOX1); - isp_target_async(isp, bus, mbox); + int handle = + (ISP_READ(isp, OUTMAILBOX2) << 16) | + (ISP_READ(isp, OUTMAILBOX1)); + if (isp_target_async(isp, handle, mbox)) + rval = -1; #else isp_prt(isp, ISP_LOGINFO, "Fast Posting CTIO done"); #endif + isp->isp_fphccmplt++; /* count it as a fast posting intr */ break; - + } case ASYNC_LIP_F8: case ASYNC_LIP_OCCURRED: FCPARAM(isp)->isp_lipseq = @@ -3507,7 +4006,8 @@ isp_parse_async(struct ispsoftc *isp, int mbox) isp_mark_getpdb_all(isp); isp_async(isp, ISPASYNC_LIP, NULL); #ifdef ISP_TARGET_MODE - isp_target_async(isp, bus, mbox); + if (isp_target_async(isp, bus, mbox)) + rval = -1; #endif /* * We've had problems with data corruption occuring on @@ -3541,7 +4041,8 @@ isp_parse_async(struct ispsoftc *isp, int mbox) isp_mark_getpdb_all(isp); isp_async(isp, ISPASYNC_LOOP_UP, NULL); #ifdef ISP_TARGET_MODE - isp_target_async(isp, bus, mbox); + if (isp_target_async(isp, bus, mbox)) + rval = -1; #endif break; @@ -3552,7 +4053,8 @@ isp_parse_async(struct ispsoftc *isp, int mbox) isp_mark_getpdb_all(isp); isp_async(isp, ISPASYNC_LOOP_DOWN, NULL); #ifdef ISP_TARGET_MODE - isp_target_async(isp, bus, mbox); + if (isp_target_async(isp, bus, mbox)) + rval = -1; #endif break; @@ -3563,7 +4065,8 @@ isp_parse_async(struct ispsoftc *isp, int mbox) isp_mark_getpdb_all(isp); isp_async(isp, ISPASYNC_LOOP_RESET, NULL); #ifdef ISP_TARGET_MODE - isp_target_async(isp, bus, mbox); + if (isp_target_async(isp, bus, mbox)) + rval = -1; #endif break; @@ -3594,7 +4097,8 @@ isp_parse_async(struct ispsoftc *isp, int mbox) 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); + if (isp_target_async(isp, bus, mbox)) + rval = -1; #endif isp_prt(isp, ISP_LOGINFO, "Point-to-Point mode"); break; @@ -3619,7 +4123,7 @@ isp_parse_async(struct ispsoftc *isp, int mbox) isp_prt(isp, ISP_LOGERR, "FATAL CONNECTION ERROR"); isp_reinit(isp); #ifdef ISP_TARGET_MODE - isp_target_async(isp, bus, ASYNC_SYSTEM_ERROR); + (void) isp_target_async(isp, bus, ASYNC_SYSTEM_ERROR); #endif /* no point continuing after this */ return (-1); @@ -3642,7 +4146,28 @@ isp_parse_async(struct ispsoftc *isp, int mbox) isp_prt(isp, ISP_LOGWARN, "Unknown Async Code 0x%x", mbox); break; } - return (fast_post_handle); + + if (bus & 0x100) { + int i, nh; + u_int16_t handles[5]; + + for (nh = 0, i = 1; i < MAX_MAILBOX; i++) { + if ((bus & (1 << i)) == 0) { + continue; + } + handles[nh++] = ISP_READ(isp, MBOX_OFF(i)); + } + for (i = 0; i < nh; i++) { + isp_fastpost_complete(isp, handles[i]); + isp_prt(isp, ISP_LOGDEBUG3, + "fast post completion of %u", handles[i]); + } + if (isp->isp_fpcchiwater < nh) + isp->isp_fpcchiwater = nh; + } else { + isp->isp_intoasync++; + } + return (rval); } /* @@ -3658,7 +4183,7 @@ isp_handle_other_response(struct ispsoftc *isp, int type, switch (type) { case RQSTYPE_STATUS_CONT: isp_prt(isp, ISP_LOGINFO, "Ignored Continuation Response"); - return (0); + return (1); case RQSTYPE_ATIO: case RQSTYPE_CTIO: case RQSTYPE_ENABLE_LUN: @@ -3669,8 +4194,11 @@ isp_handle_other_response(struct ispsoftc *isp, int type, case RQSTYPE_ATIO2: case RQSTYPE_CTIO2: case RQSTYPE_CTIO3: + isp->isp_rsltccmplt++; /* count as a response completion */ #ifdef ISP_TARGET_MODE - return (isp_target_notify(isp, (ispstatusreq_t *) hp, optrp)); + if (isp_target_notify(isp, (ispstatusreq_t *) hp, optrp)) { + return (1); + } #else optrp = optrp; /* FALLTHROUGH */ @@ -3678,11 +4206,11 @@ isp_handle_other_response(struct ispsoftc *isp, int type, case RQSTYPE_REQUEST: default: if (isp_async(isp, ISPASYNC_UNHANDLED_RESPONSE, hp)) { - return (0); + return (1); } isp_prt(isp, ISP_LOGWARN, "Unhandled Response Type 0x%x", isp_get_response_type(isp, hp)); - return (-1); + return (0); } } @@ -3882,11 +4410,25 @@ isp_parse_status(struct ispsoftc *isp, ispstatusreq_t *sp, XS_T *xs) break; case RQCS_DATA_UNDERRUN: + { + if (IS_FC(isp)) { + int ru_marked = (sp->req_scsi_status & RQCS_RU) != 0; + if (!ru_marked || sp->req_resid > XS_XFRLEN(xs)) { + isp_prt(isp, ISP_LOGWARN, bun, XS_TGT(xs), + XS_LUN(xs), XS_XFRLEN(xs), sp->req_resid, + (ru_marked)? "marked" : "not marked"); + if (XS_NOERR(xs)) { + XS_SETERR(xs, HBA_BOTCH); + } + return; + } + } XS_RESID(xs) = sp->req_resid; if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_NOERROR); } return; + } case RQCS_XACT_ERR1: isp_prt(isp, ISP_LOGERR, xact1, XS_CHANNEL(xs), @@ -3909,8 +4451,8 @@ isp_parse_status(struct ispsoftc *isp, ispstatusreq_t *sp, XS_T *xs) case RQCS_QUEUE_FULL: isp_prt(isp, ISP_LOGDEBUG0, - "internal queues full for %d.%d.%d status 0x%x", XS_TGT(xs), - XS_LUN(xs), XS_CHANNEL(xs), *XS_STSP(xs)); + "internal queues full for %d.%d.%d status 0x%x", + XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs), *XS_STSP(xs)); /* * If QFULL or some other status byte is set, then this @@ -3986,18 +4528,35 @@ isp_parse_status(struct ispsoftc *isp, ispstatusreq_t *sp, XS_T *xs) /* * No such port on the loop. Moral equivalent of SELTIMEO */ - isp_prt(isp, ISP_LOGINFO, - "Port Unavailable for target %d", XS_TGT(xs)); - if (XS_NOERR(xs)) { - XS_SETERR(xs, HBA_SELTIMEOUT); - } - return; case RQCS_PORT_LOGGED_OUT: /* * It was there (maybe)- treat as a selection timeout. */ - isp_prt(isp, ISP_LOGINFO, - "port logout for target %d", XS_TGT(xs)); + if ((sp->req_completion_status & 0xff) == RQCS_PORT_UNAVAILABLE) + isp_prt(isp, ISP_LOGINFO, + "port unavailable for target %d", XS_TGT(xs)); + else + isp_prt(isp, ISP_LOGINFO, + "port logout for target %d", XS_TGT(xs)); + /* + * If we're on a local loop, force a LIP (which is overkill) + * to force a re-login of this unit. If we're on fabric, + * then we'll have to relogin as a matter of course. + */ + if (FCPARAM(isp)->isp_topo == TOPO_NL_PORT || + FCPARAM(isp)->isp_topo == TOPO_FL_PORT) { + mbreg_t mbs; + mbs.param[0] = MBOX_INIT_LIP; + isp_mboxcmd_qnw(isp, &mbs, 1); + } + + /* + * Probably overkill. + */ + isp->isp_sendmarker = 1; + FCPARAM(isp)->isp_loopstate = LOOP_PDB_RCVD; + isp_mark_getpdb_all(isp); + isp_async(isp, ISPASYNC_CHANGE_NOTIFY, ISPASYNC_CHANGE_OTHER); if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_SELTIMEOUT); } @@ -4058,9 +4617,59 @@ isp_fastpost_complete(struct ispsoftc *isp, u_int16_t fph) } if (isp->isp_nactive) isp->isp_nactive--; + isp->isp_fphccmplt++; isp_done(xs); } +static int +isp_mbox_continue(struct ispsoftc *isp) +{ + mbreg_t mbs; + u_int16_t *ptr; + + switch (isp->isp_lastmbxcmd) { + case MBOX_WRITE_RAM_WORD: + case MBOX_READ_RAM_WORD: + case MBOX_READ_RAM_WORD_EXTENDED: + break; + default: + return (1); + } + if (isp->isp_mboxtmp[0] != MBOX_COMMAND_COMPLETE) { + isp->isp_mbxwrk0 = 0; + return (-1); + } + + + /* + * Clear the previous interrupt. + */ + ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT); + ISP_WRITE(isp, BIU_SEMA, 0); + + /* + * Continue with next word. + */ + ptr = isp->isp_mbxworkp; + switch (isp->isp_lastmbxcmd) { + case MBOX_WRITE_RAM_WORD: + mbs.param[2] = *ptr++; + mbs.param[1] = isp->isp_mbxwrk1++; + break; + case MBOX_READ_RAM_WORD: + case MBOX_READ_RAM_WORD_EXTENDED: + *ptr++ = isp->isp_mboxtmp[2]; + mbs.param[1] = isp->isp_mbxwrk1++; + break; + } + isp->isp_mbxworkp = ptr; + mbs.param[0] = isp->isp_lastmbxcmd; + isp->isp_mbxwrk0 -= 1; + isp_mboxcmd_qnw(isp, &mbs, 0); + return (0); +} + + #define HIBYT(x) ((x) >> 0x8) #define LOBYT(x) ((x) & 0xff) #define ISPOPMAP(a, b) (((a) << 8) | (b)) @@ -4276,7 +4885,7 @@ static u_int16_t mbpfc[] = { ISPOPMAP(0x00, 0x00), /* 0x0c: */ ISPOPMAP(0x00, 0x00), /* 0x0d: */ ISPOPMAP(0x01, 0x05), /* 0x0e: MBOX_CHECK_FIRMWARE */ - ISPOPMAP(0x00, 0x00), /* 0x0f: */ + ISPOPMAP(0x03, 0x07), /* 0x0f: MBOX_READ_RAM_WORD_EXTENDED(1) */ ISPOPMAP(0x1f, 0x11), /* 0x10: MBOX_INIT_REQ_QUEUE */ ISPOPMAP(0x2f, 0x21), /* 0x11: MBOX_INIT_RES_QUEUE */ ISPOPMAP(0x0f, 0x01), /* 0x12: MBOX_EXECUTE_IOCB */ @@ -4352,8 +4961,8 @@ static u_int16_t mbpfc[] = { ISPOPMAP(0x00, 0x00), /* 0x58: */ ISPOPMAP(0x00, 0x00), /* 0x59: */ ISPOPMAP(0x00, 0x00), /* 0x5a: */ - ISPOPMAP(0x00, 0x00), /* 0x5b: */ - ISPOPMAP(0x00, 0x00), /* 0x5c: */ + ISPOPMAP(0x03, 0x01), /* 0x5b: MBOX_DRIVER_HEARTBEAT */ + ISPOPMAP(0xcf, 0x01), /* 0x5c: MBOX_FW_HEARTBEAT */ ISPOPMAP(0x07, 0x03), /* 0x5d: MBOX_GET_SET_DATA_RATE */ ISPOPMAP(0x00, 0x00), /* 0x5e: */ ISPOPMAP(0x00, 0x00), /* 0x5f: */ @@ -4389,6 +4998,13 @@ static u_int16_t mbpfc[] = { ISPOPMAP(0xcf, 0x01), /* 0x7d: SEND LFA */ ISPOPMAP(0x07, 0x01) /* 0x7e: Lun RESET */ }; +/* + * Footnotes + * + * (1): this sets bits 21..16 in mailbox register #8, which we nominally + * do not access at this time in the core driver. The caller is + * responsible for setting this register first (Gross!). + */ #ifndef ISP_STRIPPED static char *fc_mbcmd_names[] = { @@ -4405,7 +5021,7 @@ static char *fc_mbcmd_names[] = { "DUMP RAM", NULL, NULL, - NULL, + "READ RAM WORD EXTENDED", "CHECK FIRMWARE", NULL, "INIT REQUEST QUEUE", @@ -4523,6 +5139,46 @@ static char *fc_mbcmd_names[] = { #endif static void +isp_mboxcmd_qnw(struct ispsoftc *isp, mbreg_t *mbp, int nodelay) +{ + unsigned int lim, ibits, obits, box, opcode; + u_int16_t *mcp; + + if (IS_FC(isp)) { + mcp = mbpfc; + lim = (sizeof (mbpfc) / sizeof (mbpfc[0])); + } else { + mcp = mbpscsi; + lim = (sizeof (mbpscsi) / sizeof (mbpscsi[0])); + } + opcode = mbp->param[0]; + ibits = HIBYT(mcp[opcode]) & NMBOX_BMASK(isp); + obits = LOBYT(mcp[opcode]) & NMBOX_BMASK(isp); + for (box = 0; box < MAX_MAILBOX; box++) { + if (ibits & (1 << box)) { + ISP_WRITE(isp, MBOX_OFF(box), mbp->param[box]); + } + if (nodelay == 0) { + isp->isp_mboxtmp[box] = mbp->param[box] = 0; + } + } + if (nodelay == 0) { + isp->isp_lastmbxcmd = opcode; + isp->isp_obits = obits; + isp->isp_mboxbsy = 1; + } + ISP_WRITE(isp, HCCR, HCCR_CMD_SET_HOST_INT); + /* + * Oddly enough, if we're not delaying for an answer, + * delay a bit to give the f/w a chance to pick up the + * command. + */ + if (nodelay) { + USEC_DELAY(1000); + } +} + +static void isp_mboxcmd(struct ispsoftc *isp, mbreg_t *mbp, int logmask) { char *cname, *xname, tname[16], mname[16]; @@ -4870,22 +5526,31 @@ isp_setdfltparm(struct ispsoftc *isp, int channel) * or the platform code wants to use what had been * set in the defaults. */ - if (nvfail || (isp->isp_confopts & ISP_CFG_OWNWWN)) { - isp_prt(isp, ISP_LOGCONFIG, - "Using Node WWN 0x%08x%08x, Port WWN 0x%08x%08x", + if (nvfail) { + isp->isp_confopts |= ISP_CFG_OWNWWPN|ISP_CFG_OWNWWNN; + } + if (isp->isp_confopts & ISP_CFG_OWNWWNN) { + isp_prt(isp, ISP_LOGCONFIG, "Using Node WWN 0x%08x%08x", (u_int32_t) (DEFAULT_NODEWWN(isp) >> 32), - (u_int32_t) (DEFAULT_NODEWWN(isp) & 0xffffffff), + (u_int32_t) (DEFAULT_NODEWWN(isp) & 0xffffffff)); + ISP_NODEWWN(isp) = DEFAULT_NODEWWN(isp); + } else { + /* + * We always start out with values derived + * from NVRAM or our platform default. + */ + ISP_NODEWWN(isp) = fcp->isp_nodewwn; + } + if (isp->isp_confopts & ISP_CFG_OWNWWPN) { + isp_prt(isp, ISP_LOGCONFIG, "Using Port WWN 0x%08x%08x", (u_int32_t) (DEFAULT_PORTWWN(isp) >> 32), (u_int32_t) (DEFAULT_PORTWWN(isp) & 0xffffffff)); - isp->isp_confopts |= ISP_CFG_OWNWWN; - ISP_NODEWWN(isp) = DEFAULT_NODEWWN(isp); ISP_PORTWWN(isp) = DEFAULT_PORTWWN(isp); } else { /* * We always start out with values derived * from NVRAM or our platform default. */ - ISP_NODEWWN(isp) = fcp->isp_nodewwn; ISP_PORTWWN(isp) = fcp->isp_portwwn; } return; @@ -5159,6 +5824,9 @@ isp_rdnvram_word(struct ispsoftc *isp, int wo, u_int16_t *rp) if (IS_FC(isp)) { wo &= ((ISP2100_NVRAM_SIZE >> 1) - 1); + if (IS_2312(isp) && isp->isp_port) { + wo += 128; + } rqst = (ISP_NVRAM_READ << 8) | wo; cbits = 10; } else if (IS_ULTRA2(isp)) { @@ -5541,13 +6209,18 @@ isp_parse_nvram_2100(struct ispsoftc *isp, u_int8_t *nvram_data) } } fcp->isp_portwwn = wwn; - wwn = ISP2100_NVRAM_NODE_NAME(nvram_data); - if (wwn) { - isp_prt(isp, ISP_LOGCONFIG, "NVRAM Node WWN 0x%08x%08x", - (u_int32_t) (wwn >> 32), (u_int32_t) (wwn & 0xffffffff)); - if ((wwn >> 60) == 0) { - wwn |= (((u_int64_t) 2)<< 60); + if (IS_2200(isp) || IS_23XX(isp)) { + wwn = ISP2200_NVRAM_NODE_NAME(nvram_data); + if (wwn) { + isp_prt(isp, ISP_LOGCONFIG, "NVRAM Node WWN 0x%08x%08x", + (u_int32_t) (wwn >> 32), + (u_int32_t) (wwn & 0xffffffff)); + if ((wwn >> 60) == 0) { + wwn |= (((u_int64_t) 2)<< 60); + } } + } else { + wwn &= ~((u_int64_t) 0xfff << 48); } fcp->isp_nodewwn = wwn; @@ -5591,6 +6264,326 @@ isp_parse_nvram_2100(struct ispsoftc *isp, u_int8_t *nvram_data) ISP2100_NVRAM_EXECUTION_THROTTLE(nvram_data); fcp->isp_fwoptions = ISP2100_NVRAM_OPTIONS(nvram_data); isp_prt(isp, ISP_LOGDEBUG0, - "NVRAM: maxfrmlen %d execthrottle %d fwoptions 0x%x", - fcp->isp_maxfrmlen, fcp->isp_execthrottle, fcp->isp_fwoptions); + "NVRAM: maxfrmlen %d execthrottle %d fwoptions 0x%x loopid %x", + fcp->isp_maxfrmlen, fcp->isp_execthrottle, fcp->isp_fwoptions, + fcp->isp_loopid); +} + +#ifdef ISP_FW_CRASH_DUMP +static void isp2200_fw_dump(struct ispsoftc *); +static void isp2300_fw_dump(struct ispsoftc *); + +static void +isp2200_fw_dump(struct ispsoftc *isp) +{ + int i, j; + mbreg_t mbs; + u_int16_t *ptr; + + ptr = FCPARAM(isp)->isp_dump_data; + if (ptr == NULL) { + isp_prt(isp, ISP_LOGERR, + "No place to dump RISC registers and SRAM"); + return; + } + if (*ptr++) { + isp_prt(isp, ISP_LOGERR, + "dump area for RISC registers and SRAM already used"); + return; + } + ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); + for (i = 0; i < 100; i++) { + USEC_DELAY(100); + if (ISP_READ(isp, HCCR) & HCCR_PAUSE) { + break; + } + } + if (ISP_READ(isp, HCCR) & HCCR_PAUSE) { + /* + * PBIU Registers + */ + for (i = 0; i < 8; i++) { + *ptr++ = ISP_READ(isp, BIU_BLOCK + (i << 1)); + } + + /* + * Mailbox Registers + */ + for (i = 0; i < 8; i++) { + *ptr++ = ISP_READ(isp, MBOX_BLOCK + (i << 1)); + } + + /* + * DMA Registers + */ + for (i = 0; i < 48; i++) { + *ptr++ = ISP_READ(isp, DMA_BLOCK + 0x20 + (i << 1)); + } + + /* + * RISC H/W Registers + */ + ISP_WRITE(isp, BIU2100_CSR, 0); + for (i = 0; i < 16; i++) { + *ptr++ = ISP_READ(isp, BIU_BLOCK + 0xA0 + (i << 1)); + } + + /* + * RISC GP Registers + */ + for (j = 0; j < 8; j++) { + ISP_WRITE(isp, BIU_BLOCK + 0xA4, 0x2000 + (j << 8)); + for (i = 0; i < 16; i++) { + *ptr++ = + ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); + } + } + + /* + * Frame Buffer Hardware Registers + */ + ISP_WRITE(isp, BIU2100_CSR, 0x10); + for (i = 0; i < 16; i++) { + *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); + } + + /* + * Fibre Protocol Module 0 Hardware Registers + */ + ISP_WRITE(isp, BIU2100_CSR, 0x20); + for (i = 0; i < 64; i++) { + *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); + } + + /* + * Fibre Protocol Module 1 Hardware Registers + */ + ISP_WRITE(isp, BIU2100_CSR, 0x30); + for (i = 0; i < 64; i++) { + *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); + } + } else { + isp_prt(isp, ISP_LOGERR, "RISC Would Not Pause"); + return; + } + isp_prt(isp, ISP_LOGALL, + "isp_fw_dump: RISC registers dumped successfully"); + ISP_WRITE(isp, BIU2100_CSR, BIU2100_SOFT_RESET); + for (i = 0; i < 100; i++) { + USEC_DELAY(100); + if (ISP_READ(isp, OUTMAILBOX0) == 0) { + break; + } + } + if (ISP_READ(isp, OUTMAILBOX0) != 0) { + isp_prt(isp, ISP_LOGERR, "Board Would Not Reset"); + return; + } + ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); + for (i = 0; i < 100; i++) { + USEC_DELAY(100); + if (ISP_READ(isp, HCCR) & HCCR_PAUSE) { + break; + } + } + if ((ISP_READ(isp, HCCR) & HCCR_PAUSE) == 0) { + isp_prt(isp, ISP_LOGERR, "RISC Would Not Pause After Reset"); + return; + } + ISP_WRITE(isp, RISC_EMB, 0xf2); + ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); + for (i = 0; i < 100; i++) { + USEC_DELAY(100); + if ((ISP_READ(isp, HCCR) & HCCR_PAUSE) == 0) { + break; + } + } + ENABLE_INTS(isp); + mbs.param[0] = MBOX_READ_RAM_WORD; + mbs.param[1] = 0x1000; + isp->isp_mbxworkp = (void *) ptr; + isp->isp_mbxwrk0 = 0xefff; /* continuation count */ + isp->isp_mbxwrk1 = 0x1001; /* next SRAM address */ + isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGWARN, + "RAM DUMP FAILED @ WORD %x", isp->isp_mbxwrk1); + return; + } + ptr = isp->isp_mbxworkp; /* finish fetch of final word */ + *ptr++ = isp->isp_mboxtmp[2]; + isp_prt(isp, ISP_LOGALL, "isp_fw_dump: SRAM dumped succesfully"); + FCPARAM(isp)->isp_dump_data[0] = isp->isp_type; /* now used */ } + +static void +isp2300_fw_dump(struct ispsoftc *isp) +{ + int i, j; + mbreg_t mbs; + u_int16_t *ptr; + + ptr = FCPARAM(isp)->isp_dump_data; + if (ptr == NULL) { + isp_prt(isp, ISP_LOGERR, + "No place to dump RISC registers and SRAM"); + return; + } + if (*ptr++) { + isp_prt(isp, ISP_LOGERR, + "dump area for RISC registers and SRAM already used"); + return; + } + ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); + for (i = 0; i < 100; i++) { + USEC_DELAY(100); + if (ISP_READ(isp, HCCR) & HCCR_PAUSE) { + break; + } + } + if (ISP_READ(isp, HCCR) & HCCR_PAUSE) { + /* + * PBIU registers + */ + for (i = 0; i < 8; i++) { + *ptr++ = ISP_READ(isp, BIU_BLOCK + (i << 1)); + } + + /* + * ReqQ-RspQ-Risc2Host Status registers + */ + for (i = 0; i < 8; i++) { + *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x10 + (i << 1)); + } + + /* + * Mailbox Registers + */ + for (i = 0; i < 32; i++) { + *ptr++ = + ISP_READ(isp, PCI_MBOX_REGS2300_OFF + (i << 1)); + } + + /* + * Auto Request Response DMA registers + */ + ISP_WRITE(isp, BIU2100_CSR, 0x40); + for (i = 0; i < 32; i++) { + *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); + } + + /* + * DMA registers + */ + ISP_WRITE(isp, BIU2100_CSR, 0x50); + for (i = 0; i < 48; i++) { + *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); + } + + /* + * RISC hardware registers + */ + ISP_WRITE(isp, BIU2100_CSR, 0); + for (i = 0; i < 16; i++) { + *ptr++ = ISP_READ(isp, BIU_BLOCK + 0xA0 + (i << 1)); + } + + /* + * RISC GP? registers + */ + for (j = 0; j < 8; j++) { + ISP_WRITE(isp, BIU_BLOCK + 0xA4, 0x2000 + (j << 9)); + for (i = 0; i < 16; i++) { + *ptr++ = + ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); + } + } + + /* + * frame buffer hardware registers + */ + ISP_WRITE(isp, BIU2100_CSR, 0x10); + for (i = 0; i < 64; i++) { + *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); + } + + /* + * FPM B0 hardware registers + */ + ISP_WRITE(isp, BIU2100_CSR, 0x20); + for (i = 0; i < 64; i++) { + *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); + } + + /* + * FPM B1 hardware registers + */ + ISP_WRITE(isp, BIU2100_CSR, 0x30); + for (i = 0; i < 64; i++) { + *ptr++ = ISP_READ(isp, BIU_BLOCK + 0x80 + (i << 1)); + } + } else { + isp_prt(isp, ISP_LOGERR, "RISC Would Not Pause"); + return; + } + isp_prt(isp, ISP_LOGALL, + "isp_fw_dump: RISC registers dumped successfully"); + ISP_WRITE(isp, BIU2100_CSR, BIU2100_SOFT_RESET); + for (i = 0; i < 100; i++) { + USEC_DELAY(100); + if (ISP_READ(isp, OUTMAILBOX0) == 0) { + break; + } + } + if (ISP_READ(isp, OUTMAILBOX0) != 0) { + isp_prt(isp, ISP_LOGERR, "Board Would Not Reset"); + return; + } + ENABLE_INTS(isp); + mbs.param[0] = MBOX_READ_RAM_WORD; + mbs.param[1] = 0x800; + isp->isp_mbxworkp = (void *) ptr; + isp->isp_mbxwrk0 = 0xf7ff; /* continuation count */ + isp->isp_mbxwrk1 = 0x801; /* next SRAM address */ + isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGWARN, + "RAM DUMP FAILED @ WORD %x", isp->isp_mbxwrk1); + return; + } + ptr = isp->isp_mbxworkp; /* finish fetch of final word */ + *ptr++ = isp->isp_mboxtmp[2]; + + /* + * We don't have access to mailbox registers 8.. onward + * in our 'common' device model- so we have to set it + * here and hope it stays the same! + */ + ISP_WRITE(isp, PCI_MBOX_REGS2300_OFF + (8 << 1), 0x1); + + mbs.param[0] = MBOX_READ_RAM_WORD_EXTENDED; + mbs.param[1] = 0; + isp->isp_mbxworkp = (void *) ptr; + isp->isp_mbxwrk0 = 0xffff; /* continuation count */ + isp->isp_mbxwrk1 = 0x1; /* next SRAM address */ + isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGWARN, + "RAM DUMP FAILED @ WORD %x", 0x10000 + isp->isp_mbxwrk1); + return; + } + ptr = isp->isp_mbxworkp; /* finish final word */ + *ptr++ = mbs.param[2]; + isp_prt(isp, ISP_LOGALL, "isp_fw_dump: SRAM dumped succesfully"); + FCPARAM(isp)->isp_dump_data[0] = isp->isp_type; /* now used */ +} + +void +isp_fw_dump(struct ispsoftc *isp) +{ + if (IS_2200(isp)) + isp2200_fw_dump(isp); + else if (IS_23XX(isp)) + isp2300_fw_dump(isp); +} +#endif |