diff options
| author | Matt Jacob <mjacob@FreeBSD.org> | 2007-03-08 05:31:40 +0000 |
|---|---|---|
| committer | Matt Jacob <mjacob@FreeBSD.org> | 2007-03-08 05:31:40 +0000 |
| commit | ce15fc6671f96d50c7b31b8272310203ff487581 (patch) | |
| tree | 84f2429c6eb92dfc44fe35f02cf207b024ee6af5 /sys/dev/isp/isp.c | |
| parent | 0f4b76b11a40d929685894a1ff1ef2b5762ac660 (diff) | |
Notes
Diffstat (limited to 'sys/dev/isp/isp.c')
| -rw-r--r-- | sys/dev/isp/isp.c | 4946 |
1 files changed, 3124 insertions, 1822 deletions
diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index b880a45dec30..e504325cbfbc 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -26,8 +26,9 @@ /* * Machine and OS Independent (well, as best as possible) - * code for the Qlogic ISP SCSI adapters. + * code for the Qlogic ISP SCSI and FC-SCSI adapters. */ + /* * Inspiration and ideas about this driver are from Erik Moe's Linux driver * (qlogicisp.c) and Dave Miller's SBus version of same (qlogicisp.c). Some @@ -60,30 +61,16 @@ __FBSDID("$FreeBSD$"); */ #define MBOX_DELAY_COUNT 1000000 / 100 +#define ISP_MARK_PORTDB(a, b) \ + isp_prt(isp, ISP_LOGSANCFG, "line %d: markportdb", __LINE__); \ + isp_mark_portdb(a, b) /* * Local static data */ -static const char portshift[] = - "Target %d Loop ID 0x%x (Port 0x%x) => Loop 0x%x (Port 0x%x)"; -static const char portdup[] = - "Target %d duplicates Target %d- killing off both"; -static const char retained[] = - "Retaining Loop ID 0x%x for Target %d (Port 0x%x)"; -static const char lretained[] = - "Retained login of Target %d (Loop ID 0x%x) Port 0x%x"; -static const char plogout[] = - "Logging out Target %d at Loop ID 0x%x (Port 0x%x)"; -static const char plogierr[] = - "Command Error in PLOGI for Port 0x%x (0x%x)"; -static const char nopdb[] = - "Could not get PDB for Device @ Port 0x%x"; -static const char pdbmfail1[] = - "PDB Loop ID info for Device @ Port 0x%x does not match up (0x%x)"; -static const char pdbmfail2[] = - "PDB Port info for Device @ Port 0x%x does not match up (0x%x)"; -static const char ldumped[] = - "Target %d (Loop ID 0x%x) Port 0x%x dumped after login info mismatch"; +static const char fconf[] = + "PortDB[%d] changed:\n current =(0x%x@0x%06x 0x%08x%08x 0x%08x%08x)\n" + " database=(0x%x@0x%06x 0x%08x%08x 0x%08x%08x)"; static const char notresp[] = "Not RESPONSE in RESPONSE Queue (type 0x%x) @ idx %d (next %d) nlooked %d"; static const char xact1[] = @@ -95,9 +82,9 @@ static const char xact3[] = static const char pskip[] = "SCSI phase skipped for target %d.%d.%d"; static const char topology[] = - "Loop ID %d, 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"; + "HBA PortID 0x%06x N-Port Handle %d, Connection Topology '%s'"; +static const char ourwwn[] = + "HBA WWNN 0x%08x%08x HBA WWPN 0x%08x%08x"; 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[] = @@ -115,38 +102,51 @@ static const char bun[] = */ static int isp_parse_async(ispsoftc_t *, uint16_t); static int isp_handle_other_response(ispsoftc_t *, int, isphdr_t *, - uint16_t *); + uint32_t *); +static void +isp_parse_status(ispsoftc_t *, ispstatusreq_t *, XS_T *, long *); static void -isp_parse_status(ispsoftc_t *, ispstatusreq_t *, XS_T *); +isp_parse_status_24xx(ispsoftc_t *, isp24xx_statusreq_t *, XS_T *, long *); static void isp_fastpost_complete(ispsoftc_t *, uint16_t); static int isp_mbox_continue(ispsoftc_t *); static void isp_scsi_init(ispsoftc_t *); static void isp_scsi_channel_init(ispsoftc_t *, int); static void isp_fibre_init(ispsoftc_t *); -static void isp_mark_getpdb_all(ispsoftc_t *); -static int isp_getmap(ispsoftc_t *, fcpos_map_t *); -static int isp_getpdb(ispsoftc_t *, int, isp_pdb_t *); +static void isp_fibre_init_2400(ispsoftc_t *); +static void isp_mark_portdb(ispsoftc_t *, int); +static int isp_plogx(ispsoftc_t *, uint16_t, uint32_t, int, int); +static int isp_port_login(ispsoftc_t *, uint16_t, uint32_t); +static int isp_port_logout(ispsoftc_t *, uint16_t, uint32_t); +static int isp_getpdb(ispsoftc_t *, uint16_t, isp_pdb_t *, int); static uint64_t isp_get_portname(ispsoftc_t *, int, int); static int isp_fclink_test(ispsoftc_t *, int); -static const char *isp2100_fw_statename(int); +static const char *ispfc_fw_statename(int); static int isp_pdb_sync(ispsoftc_t *); static int isp_scan_loop(ispsoftc_t *); -static int isp_fabric_mbox_cmd(ispsoftc_t *, mbreg_t *); -static int isp_scan_fabric(ispsoftc_t *, int); -static void isp_register_fc4_type(ispsoftc_t *); +static int isp_gid_ft_sns(ispsoftc_t *); +static int isp_gid_ft_ct_passthru(ispsoftc_t *); +static int isp_scan_fabric(ispsoftc_t *); +static int isp_login_device(ispsoftc_t *, uint32_t, isp_pdb_t *, uint16_t *); +static int isp_register_fc4_type(ispsoftc_t *); +static int isp_register_fc4_type_24xx(ispsoftc_t *); +static uint16_t isp_nxt_handle(ispsoftc_t *, uint16_t); static void isp_fw_state(ispsoftc_t *); static void isp_mboxcmd_qnw(ispsoftc_t *, mbreg_t *, int); -static void isp_mboxcmd(ispsoftc_t *, mbreg_t *, int); +static void isp_mboxcmd(ispsoftc_t *, mbreg_t *); static void isp_update(ispsoftc_t *); static void isp_update_bus(ispsoftc_t *, int); static void isp_setdfltparm(ispsoftc_t *, int); static int isp_read_nvram(ispsoftc_t *); +static int isp_read_nvram_2400(ispsoftc_t *); static void isp_rdnvram_word(ispsoftc_t *, int, uint16_t *); +static void isp_rd_2400_nvram(ispsoftc_t *, uint32_t, uint32_t *); static void isp_parse_nvram_1020(ispsoftc_t *, uint8_t *); static void isp_parse_nvram_1080(ispsoftc_t *, int, uint8_t *); static void isp_parse_nvram_12160(ispsoftc_t *, int, uint8_t *); +static void isp_fix_nvram_wwns(ispsoftc_t *); static void isp_parse_nvram_2100(ispsoftc_t *, uint8_t *); +static void isp_parse_nvram_2400(ispsoftc_t *, uint8_t *); /* * Reset Hardware. @@ -160,9 +160,10 @@ void isp_reset(ispsoftc_t *isp) { mbreg_t mbs; - uint32_t code_org; + uint32_t code_org, val; int loops, i, dodnld = 1; - char *btype = "????"; + static const char *btype = "????"; + static const char dcrc[] = "Downloaded RISC Code Checksum Failure"; isp->isp_state = ISP_NILSTATE; @@ -202,10 +203,16 @@ isp_reset(ispsoftc_t *isp) /* * Just in case it was paused... */ - ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); + if (IS_24XX(isp)) { + ISP_WRITE(isp, BIU2400_HCCR, + HCCR_2400_CMD_RELEASE); + } else { + ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); + } MEMZERO(&mbs, sizeof (mbs)); mbs.param[0] = MBOX_ABOUT_FIRMWARE; - isp_mboxcmd(isp, &mbs, MBLOGNONE); + mbs.logval = MBLOGNONE; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { isp->isp_romfw_rev[0] = mbs.param[1]; isp->isp_romfw_rev[1] = mbs.param[2]; @@ -215,21 +222,51 @@ isp_reset(ispsoftc_t *isp) isp->isp_touched = 1; } - DISABLE_INTS(isp); + ISP_DISABLE_INTS(isp); + + /* + * Pick an initial maxcmds value which will be used + * to allocate xflist pointer space. It may be changed + * later by the firmware. + */ + if (IS_24XX(isp)) { + isp->isp_maxcmds = 4096; + } else if (IS_2322(isp)) { + isp->isp_maxcmds = 2048; + } else if (IS_23XX(isp) || IS_2200(isp)) { + isp->isp_maxcmds = 1024; + } else { + isp->isp_maxcmds = 512; + } + + /* + * Set up DMA for the request and result queues. + * + * We do this now so we can use the request queue + * for a dma + */ + if (ISP_MBOXDMASETUP(isp) != 0) { + isp_prt(isp, ISP_LOGERR, "Cannot setup DMA"); + return; + } + /* * Set up default request/response queue in-pointer/out-pointer * register indices. */ - if (IS_23XX(isp)) { + if (IS_24XX(isp)) { + isp->isp_rqstinrp = BIU2400_REQINP; + isp->isp_rqstoutrp = BIU2400_REQOUTP; + isp->isp_respinrp = BIU2400_RSPINP; + isp->isp_respoutrp = BIU2400_RSPOUTP; + isp->isp_atioinrp = BIU2400_ATIO_RSPINP; + isp->isp_atiooutrp = BIU2400_ATIO_REQINP; + } else if (IS_23XX(isp)) { isp->isp_rqstinrp = BIU_REQINP; isp->isp_rqstoutrp = BIU_REQOUTP; isp->isp_respinrp = BIU_RSPINP; isp->isp_respoutrp = BIU_RSPOUTP; - ISP_WRITE(isp, isp->isp_rqstinrp, 0); - ISP_WRITE(isp, isp->isp_rqstoutrp, 0); - ISP_WRITE(isp, isp->isp_respinrp, 0); - ISP_WRITE(isp, isp->isp_respoutrp, 0); } else { isp->isp_rqstinrp = INMAILBOX4; isp->isp_rqstoutrp = OUTMAILBOX4; @@ -241,7 +278,13 @@ isp_reset(ispsoftc_t *isp) * Put the board into PAUSE mode (so we can read the SXP registers * or write FPM/FBM registers). */ - ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); + if (IS_24XX(isp)) { + ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_HOST_INT); + ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_RISC_INT); + ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_PAUSE); + } else { + ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); + } if (IS_FC(isp)) { switch (isp->isp_type) { @@ -260,20 +303,24 @@ isp_reset(ispsoftc_t *isp) case ISP_HA_FC_2322: btype = "2322"; break; - case ISP_HA_FC_2422: + case ISP_HA_FC_2400: btype = "2422"; break; default: break; } - /* - * While we're paused, reset the FPM module and FBM fifos. - */ - ISP_WRITE(isp, BIU2100_CSR, BIU2100_FPM0_REGS); - ISP_WRITE(isp, FPM_DIAG_CONFIG, FPM_SOFT_RESET); - ISP_WRITE(isp, BIU2100_CSR, BIU2100_FB_REGS); - ISP_WRITE(isp, FBM_CMD, FBMCMD_FIFO_RESET_ALL); - ISP_WRITE(isp, BIU2100_CSR, BIU2100_RISC_REGS); + + if (!IS_24XX(isp)) { + /* + * While we're paused, reset the FPM module and FBM + * fifos. + */ + ISP_WRITE(isp, BIU2100_CSR, BIU2100_FPM0_REGS); + ISP_WRITE(isp, FPM_DIAG_CONFIG, FPM_SOFT_RESET); + ISP_WRITE(isp, BIU2100_CSR, BIU2100_FB_REGS); + ISP_WRITE(isp, FBM_CMD, FBMCMD_FIFO_RESET_ALL); + ISP_WRITE(isp, BIU2100_CSR, BIU2100_RISC_REGS); + } } else if (IS_1240(isp)) { sdparam *sdp = isp->isp_param; btype = "1240"; @@ -443,8 +490,6 @@ isp_reset(ispsoftc_t *isp) */ ISP_RESET0(isp); -again: - /* * Hit the chip over the head with hammer, * and give the ISP a chance to recover. @@ -466,6 +511,44 @@ again: DMA_CNTRL_CLEAR_CHAN | DMA_CNTRL_RESET_INT); + } else if (IS_24XX(isp)) { + /* + * Stop DMA and wait for it to stop. + */ + ISP_WRITE(isp, BIU2400_CSR, BIU2400_DMA_STOP|(3 << 4)); + for (val = loops = 0; loops < 30000; loops++) { + USEC_DELAY(10); + val = ISP_READ(isp, BIU2400_CSR); + if ((val & BIU2400_DMA_ACTIVE) == 0) { + break; + } + } + if (val & BIU2400_DMA_ACTIVE) { + ISP_RESET0(isp); + isp_prt(isp, ISP_LOGERR, "DMA Failed to Stop on Reset"); + return; + } + /* + * Hold it in SOFT_RESET and STOP state for 100us. + */ + ISP_WRITE(isp, BIU2400_CSR, + BIU2400_SOFT_RESET|BIU2400_DMA_STOP|(3 << 4)); + USEC_DELAY(100); + for (loops = 0; loops < 10000; loops++) { + USEC_DELAY(5); + val = ISP_READ(isp, OUTMAILBOX0); + } + for (val = loops = 0; loops < 500000; loops ++) { + val = ISP_READ(isp, BIU2400_CSR); + if ((val & BIU2400_SOFT_RESET) == 0) { + break; + } + } + if (val & BIU2400_SOFT_RESET) { + ISP_RESET0(isp); + isp_prt(isp, ISP_LOGERR, "Failed to come out of reset"); + return; + } } else { ISP_WRITE(isp, BIU2100_CSR, BIU2100_SOFT_RESET); /* @@ -490,8 +573,13 @@ again: loops = MBOX_DELAY_COUNT; for (;;) { if (IS_SCSI(isp)) { - if (!(ISP_READ(isp, BIU_ICR) & BIU_ICR_SOFT_RESET)) + if (!(ISP_READ(isp, BIU_ICR) & BIU_ICR_SOFT_RESET)) { break; + } + } else if (IS_24XX(isp)) { + if (ISP_READ(isp, OUTMAILBOX0) == 0) { + break; + } } else { if (!(ISP_READ(isp, BIU2100_CSR) & BIU2100_SOFT_RESET)) break; @@ -499,6 +587,7 @@ again: USEC_DELAY(100); if (--loops < 0) { ISP_DUMPREGS(isp, "chip reset timed out"); + ISP_RESET0(isp); return; } } @@ -510,24 +599,41 @@ again: if (IS_SCSI(isp)) { ISP_WRITE(isp, BIU_CONF1, 0); - } else { + } else if (!IS_24XX(isp)) { ISP_WRITE(isp, BIU2100_CSR, 0); } /* * Reset RISC Processor */ - ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); - USEC_DELAY(100); - /* Clear semaphore register (just to be sure) */ - ISP_WRITE(isp, BIU_SEMA, 0); + if (IS_24XX(isp)) { + ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_RESET); + ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_RELEASE); + ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_RESET); + } else { + ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); + USEC_DELAY(100); + ISP_WRITE(isp, BIU_SEMA, 0); + } + /* - * Establish some initial burst rate stuff. - * (only for the 1XX0 boards). This really should - * be done later after fetching from NVRAM. + * Post-RISC Reset stuff. */ - if (IS_SCSI(isp)) { + if (IS_24XX(isp)) { + for (val = loops = 0; loops < 5000000; loops++) { + USEC_DELAY(5); + val = ISP_READ(isp, OUTMAILBOX0); + if (val == 0) { + break; + } + } + if (val != 0) { + ISP_RESET0(isp); + isp_prt(isp, ISP_LOGERR, "reset didn't clear"); + return; + } + } else if (IS_SCSI(isp)) { uint16_t tmp = isp->isp_mdvec->dv_conf1; /* * Busted FIFO. Turn off all but burst enables. @@ -540,15 +646,36 @@ again: ISP_SETBITS(isp, CDMA_CONF, DMA_ENABLE_BURST); ISP_SETBITS(isp, DDMA_CONF, DMA_ENABLE_BURST); } - ISP_WRITE(isp, RISC_MTR, 0x1212); + if (SDPARAM(isp)->isp_ptisp) { + if (SDPARAM(isp)->isp_ultramode) { + while (ISP_READ(isp, RISC_MTR) != 0x1313) { + ISP_WRITE(isp, RISC_MTR, 0x1313); + ISP_WRITE(isp, HCCR, HCCR_CMD_STEP); + } + } else { + ISP_WRITE(isp, RISC_MTR, 0x1212); + } + /* + * PTI specific register + */ + ISP_WRITE(isp, RISC_EMB, DUAL_BANK); + } else { + ISP_WRITE(isp, RISC_MTR, 0x1212); + } + ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); } else { ISP_WRITE(isp, RISC_MTR2100, 0x1212); if (IS_2200(isp) || IS_23XX(isp)) { ISP_WRITE(isp, HCCR, HCCR_2X00_DISABLE_PARITY_PAUSE); } + ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); } - ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); /* release paused processor */ + ISP_WRITE(isp, isp->isp_rqstinrp, 0); + ISP_WRITE(isp, isp->isp_rqstoutrp, 0); + ISP_WRITE(isp, isp->isp_respinrp, 0); + ISP_WRITE(isp, isp->isp_respoutrp, 0); + /* * Do MD specific post initialization @@ -561,13 +688,14 @@ again: * Avoid doing this on the 2312 because you can generate a PCI * parity error (chip breakage). */ - if (IS_23XX(isp)) { - USEC_DELAY(5); + if (IS_2312(isp)) { + USEC_DELAY(100); } else { loops = MBOX_DELAY_COUNT; while (ISP_READ(isp, OUTMAILBOX0) == MBOX_BUSY) { USEC_DELAY(100); if (--loops < 0) { + ISP_RESET0(isp); isp_prt(isp, ISP_LOGERR, "MBOX_BUSY never cleared on reset"); return; @@ -586,12 +714,14 @@ again: */ MEMZERO(&mbs, sizeof (mbs)); mbs.param[0] = MBOX_NO_OP; - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + ISP_RESET0(isp); return; } - if (IS_SCSI(isp)) { + if (IS_SCSI(isp) || IS_24XX(isp)) { MEMZERO(&mbs, sizeof (mbs)); mbs.param[0] = MBOX_MAILBOX_REG_TEST; mbs.param[1] = 0xdead; @@ -599,13 +729,18 @@ again: mbs.param[3] = 0xffff; mbs.param[4] = 0x1111; mbs.param[5] = 0xa5a5; - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.param[6] = 0x0000; + mbs.param[7] = 0x0000; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + ISP_RESET0(isp); return; } if (mbs.param[1] != 0xdead || mbs.param[2] != 0xbeef || mbs.param[3] != 0xffff || mbs.param[4] != 0x1111 || mbs.param[5] != 0xa5a5) { + ISP_RESET0(isp); isp_prt(isp, ISP_LOGERR, "Register Test Failed (0x%x 0x%x 0x%x 0x%x 0x%x)", mbs.param[1], mbs.param[2], mbs.param[3], @@ -629,12 +764,173 @@ again: dodnld = 0; } - if (IS_23XX(isp)) { + if (IS_24XX(isp)) { + code_org = ISP_CODE_ORG_2400; + } else if (IS_23XX(isp)) { code_org = ISP_CODE_ORG_2300; } else { code_org = ISP_CODE_ORG; } - if (dodnld) { + + if (dodnld && IS_24XX(isp)) { + uint32_t *ptr = isp->isp_mdvec->dv_ispfw; + + /* + * NB: Whatever you do do, do *not* issue the VERIFY FIRMWARE + * NB: command to the 2400 while loading new firmware. This + * NB: causes the new f/w to start and immediately crash back + * NB: to the ROM. + */ + + /* + * Keep loading until we run out of f/w. + */ + code_org = ptr[2]; /* 1st load address is our start addr */ + + for (;;) { + uint32_t la, wi, wl; + + isp_prt(isp, ISP_LOGDEBUG0, + "load 0x%x words of code at load address 0x%x", + ptr[3], ptr[2]); + + wi = 0; + la = ptr[2]; + wl = ptr[3]; + + while (wi < ptr[3]) { + uint32_t *cp; + uint32_t nw; + + nw = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)) >> 2; + if (nw > wl) { + nw = wl; + } + cp = isp->isp_rquest; + for (i = 0; i < nw; i++) { + cp[i] = ptr[wi++]; + wl--; + } + MEMORYBARRIER(isp, SYNC_REQUEST, + 0, ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp))); + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_LOAD_RISC_RAM; + mbs.param[1] = la; + mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); + mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); + mbs.param[4] = nw >> 16; + mbs.param[5] = nw; + mbs.param[6] = DMA_WD3(isp->isp_rquest_dma); + mbs.param[7] = DMA_WD2(isp->isp_rquest_dma); + mbs.param[8] = la >> 16; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, + "F/W Risc Ram Load Failed"); + ISP_RESET0(isp); + return; + } + la += nw; + } + + if (ptr[1] == 0) { + break; + } + ptr += ptr[3]; + } + isp->isp_loaded_fw = 1; + } else if (dodnld && IS_23XX(isp)) { + uint16_t *ptr = isp->isp_mdvec->dv_ispfw; + uint16_t wi, wl, segno; + uint32_t la; + + la = code_org; + segno = 0; + + for (;;) { + uint32_t nxtaddr; + + isp_prt(isp, ISP_LOGDEBUG0, + "load 0x%x words of code at load address 0x%x", + ptr[3], la); + + wi = 0; + wl = ptr[3]; + + while (wi < ptr[3]) { + uint16_t *cp; + uint32_t nw; + + nw = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)) >> 1; + if (nw > wl) { + nw = wl; + } + if (nw > (1 << 15)) { + nw = 1 << 15; + } + cp = isp->isp_rquest; + for (i = 0; i < nw; i++) { + cp[i] = ptr[wi++]; + wl--; + } + MEMORYBARRIER(isp, SYNC_REQUEST, + 0, ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp))); + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_LOAD_RISC_RAM; + mbs.param[1] = la; + mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); + mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); + mbs.param[4] = nw; + mbs.param[6] = DMA_WD3(isp->isp_rquest_dma); + mbs.param[7] = DMA_WD2(isp->isp_rquest_dma); + mbs.param[8] = la >> 16; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, + "F/W Risc Ram Load Failed"); + ISP_RESET0(isp); + return; + } + la += nw; + } + + if (!IS_2322(isp)) { + /* + * Verify that it downloaded correctly. + */ + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_VERIFY_CHECKSUM; + mbs.param[1] = code_org; + mbs.logval = MBLOGNONE; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, dcrc); + ISP_RESET0(isp); + return; + } + break; + } + + if (++segno == 3) { + break; + } + + /* + * If we're a 2322, the firmware actually comes in + * three chunks. We loaded the first at the code_org + * address. The other two chunks, which follow right + * after each other in memory here, get loaded at + * addresses specfied at offset 0x9..0xB. + */ + + nxtaddr = ptr[3]; + ptr = &ptr[nxtaddr]; + la = ptr[5] | ((ptr[4] & 0x3f) << 16); + } + isp->isp_loaded_fw = 1; + } else if (dodnld) { uint16_t *ptr = isp->isp_mdvec->dv_ispfw; isp->isp_mbxworkp = &ptr[1]; @@ -644,76 +940,27 @@ again: mbs.param[0] = MBOX_WRITE_RAM_WORD; mbs.param[1] = code_org; mbs.param[2] = ptr[0]; - isp_mboxcmd(isp, &mbs, MBLOGNONE); + mbs.logval = MBLOGNONE; + isp_mboxcmd(isp, &mbs); 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; + ISP_RESET0(isp); + return; } - /* - * If we're a 2322, the firmware actually comes in three chunks. - * We loaded the first at the code_org address. The other two - * chunks, which follow right after each other in memory here, - * get loaded at addresses specfied at offset 0x9..0xB. + * Verify that it downloaded correctly. */ - if (IS_2322(isp)) { - uint32_t nxtaddr; - uint32_t offset; - - nxtaddr = ptr[3]; - ptr = &ptr[nxtaddr]; - offset = ptr[5] | (((uint32_t)(ptr[4] & 0x3f)) << 16); - isp->isp_mbxworkp = &ptr[1]; - isp->isp_mbxwrk0 = ptr[3] - 1; - isp->isp_mbxwrk1 = offset + 1; - isp->isp_mbxwrk8 = (offset + 1) >> 16; - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_WRITE_RAM_WORD_EXTENDED; - mbs.param[1] = offset; - mbs.param[2] = ptr[0]; - mbs.param[8] = offset >> 16; - isp_mboxcmd(isp, &mbs, MBLOGNONE); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGERR, - "Receive Sequencer F/W Load Failed"); - return; - } - - nxtaddr = ptr[3]; - ptr = &ptr[nxtaddr]; - offset = ptr[5] | (((uint32_t)(ptr[4] & 0x3f)) << 16); - isp->isp_mbxworkp = &ptr[1]; - isp->isp_mbxwrk0 = ptr[3] - 1; - isp->isp_mbxwrk1 = (offset + 1); - isp->isp_mbxwrk8 = (offset + 1) >> 16; - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_WRITE_RAM_WORD_EXTENDED; - mbs.param[1] = offset; - mbs.param[2] = ptr[0]; - mbs.param[8] = offset >> 16; - isp_mboxcmd(isp, &mbs, MBLOGNONE); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGERR, - "Transmit Sequencer F/W Load Failed"); - return; - } - } else { - /* - * Verify that it downloaded correctly. - */ - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_VERIFY_CHECKSUM; - mbs.param[1] = code_org; - isp_mboxcmd(isp, &mbs, MBLOGNONE); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGERR, - "Downloaded RISC Code Checksum Failure"); - return; - } - + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_VERIFY_CHECKSUM; + mbs.param[1] = code_org; + mbs.logval = MBLOGNONE; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, dcrc); + ISP_RESET0(isp); + return; } isp->isp_loaded_fw = 1; } else { @@ -730,28 +977,40 @@ again: MEMZERO(&mbs, sizeof (mbs)); + mbs.timeout = 1000000; mbs.param[0] = MBOX_EXEC_FIRMWARE; - mbs.param[1] = code_org; - if (IS_2322(isp) || IS_24XX(isp)) { + if (IS_24XX(isp)) { + mbs.param[1] = code_org >> 16; + mbs.param[2] = code_org; + if (isp->isp_loaded_fw) { + mbs.param[3] = 0; + } else { + mbs.param[3] = 1; + } + } else if (IS_2322(isp)) { + mbs.param[1] = code_org; if (isp->isp_loaded_fw) { mbs.param[2] = 0; } else { mbs.param[2] = 1; } + } else { + mbs.param[1] = code_org; } - isp_mboxcmd(isp, &mbs, MBLOGNONE); + + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (IS_2322(isp) || IS_24XX(isp)) { if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGERR, "EXEC F/W failed: 0x%x", - mbs.param[0]); + ISP_RESET0(isp); return; } } /* - * Give it a chance to start. + * Give it a chance to finish starting up. */ - USEC_DELAY(500); + USEC_DELAY(250000); if (IS_SCSI(isp)) { /* @@ -760,15 +1019,24 @@ again: if (isp->isp_clock) { mbs.param[0] = MBOX_SET_CLOCK_RATE; mbs.param[1] = isp->isp_clock; - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGNONE; + isp_mboxcmd(isp, &mbs); /* we will try not to care if this fails */ } } MEMZERO(&mbs, sizeof (mbs)); mbs.param[0] = MBOX_ABOUT_FIRMWARE; - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + ISP_RESET0(isp); + return; + } + + if (IS_24XX(isp) && mbs.param[1] == 0xdead) { + isp_prt(isp, ISP_LOGERR, "f/w didn't *really* start"); + ISP_RESET0(isp); return; } @@ -794,7 +1062,7 @@ again: isp->isp_fwrev[2] = mbs.param[3]; } - isp_prt(isp, ISP_LOGCONFIG, + isp_prt(isp, ISP_LOGALL, "Board Type %s, Chip Revision 0x%x, %s F/W Revision %d.%d.%d", btype, isp->isp_revision, dodnld? "loaded" : "resident", isp->isp_fwrev[0], isp->isp_fwrev[1], isp->isp_fwrev[2]); @@ -805,9 +1073,9 @@ again: * than 1.17.0, unless it's the firmware we specifically * are loading. * - * Note that all 22XX and 23XX f/w is greater than 1.X.0. + * Note that all 22XX and later f/w is greater than 1.X.0. */ - if (!(ISP_FW_NEWER_THAN(isp, 1, 17, 0))) { + if ((ISP_FW_OLDER_THAN(isp, 1, 17, 1))) { #ifdef USE_SMALLER_2100_FIRMWARE FCPARAM(isp)->isp_fwattr = ISP_FW_ATTR_SCCLUN; #else @@ -818,7 +1086,26 @@ again: isp_prt(isp, ISP_LOGDEBUG0, "Firmware Attributes = 0x%x", mbs.param[6]); } - if (IS_2KLOGIN(isp)) { + FCPARAM(isp)->isp_2klogin = 0; + FCPARAM(isp)->isp_sccfw = 0; + FCPARAM(isp)->isp_tmode = 0; + if (IS_24XX(isp)) { + FCPARAM(isp)->isp_2klogin = 1; + FCPARAM(isp)->isp_sccfw = 1; + FCPARAM(isp)->isp_tmode = 1; + } else { + if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) { + FCPARAM(isp)->isp_sccfw = 1; + } + if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_2KLOGINS) { + FCPARAM(isp)->isp_2klogin = 1; + FCPARAM(isp)->isp_sccfw = 1; + } + if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_TMODE) { + FCPARAM(isp)->isp_tmode = 1; + } + } + if (FCPARAM(isp)->isp_2klogin) { isp_prt(isp, ISP_LOGCONFIG, "2K Logins Supported"); } } @@ -830,24 +1117,23 @@ again: isp->isp_romfw_rev[2]); } - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_GET_FIRMWARE_STATUS; - isp_mboxcmd(isp, &mbs, MBLOGALL); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - return; + if (!IS_24XX(isp)) { + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_GET_FIRMWARE_STATUS; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + ISP_RESET0(isp); + return; + } + if (isp->isp_maxcmds >= mbs.param[2]) { + isp->isp_maxcmds = mbs.param[2]; + } } - isp->isp_maxcmds = mbs.param[2]; - isp_prt(isp, ISP_LOGINFO, - "%d max I/O commands supported", mbs.param[2]); + isp_prt(isp, ISP_LOGCONFIG, + "%d max I/O command limit set", isp->isp_maxcmds); isp_fw_state(isp); - /* - * Set up DMA for the request and result mailboxes. - */ - if (ISP_MBOXDMASETUP(isp) != 0) { - isp_prt(isp, ISP_LOGERR, "Cannot setup DMA"); - return; - } isp->isp_state = ISP_RESETSTATE; /* @@ -878,12 +1164,20 @@ again: isp->isp_maxluns = 8; } } else { - if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) { + if (FCPARAM(isp)->isp_sccfw) { isp->isp_maxluns = 16384; } else { isp->isp_maxluns = 16; } } + /* + * Must do this first to get defaults established. + */ + isp_setdfltparm(isp, 0); + if (IS_DUALBUS(isp)) { + isp_setdfltparm(isp, 1); + } + } /* @@ -895,15 +1189,21 @@ again: void isp_init(ispsoftc_t *isp) { - /* - * Must do this first to get defaults established. - */ - isp_setdfltparm(isp, 0); - if (IS_DUALBUS(isp)) { - isp_setdfltparm(isp, 1); - } if (IS_FC(isp)) { - isp_fibre_init(isp); + /* + * Do this *before* initializing the firmware. + */ + ISP_MARK_PORTDB(isp, 0); + FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; + FCPARAM(isp)->isp_loopstate = LOOP_NIL; + + if (isp->isp_role != ISP_ROLE_NONE) { + if (IS_24XX(isp)) { + isp_fibre_init_2400(isp); + } else { + isp_fibre_init(isp); + } + } } else { isp_scsi_init(isp); } @@ -947,8 +1247,8 @@ isp_scsi_init(ispsoftc_t *isp) mbs.param[2] = sdp_chan0->isp_retry_delay; mbs.param[6] = sdp_chan1->isp_retry_count; mbs.param[7] = sdp_chan1->isp_retry_delay; - - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; } @@ -960,7 +1260,8 @@ isp_scsi_init(ispsoftc_t *isp) mbs.param[0] = MBOX_SET_ASYNC_DATA_SETUP_TIME; mbs.param[1] = sdp_chan0->isp_async_data_setup; mbs.param[2] = sdp_chan1->isp_async_data_setup; - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; } @@ -976,9 +1277,8 @@ isp_scsi_init(ispsoftc_t *isp) mbs.param[2] = (sdp_chan1->isp_req_ack_active_neg << 4) | (sdp_chan1->isp_data_line_active_neg << 5); - - MEMZERO(&mbs, sizeof (mbs)); - isp_mboxcmd(isp, &mbs, MBLOGNONE); + mbs.logval = MBLOGNONE; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { isp_prt(isp, ISP_LOGERR, "failed to set active negation state (%d,%d), (%d,%d)", @@ -998,7 +1298,8 @@ isp_scsi_init(ispsoftc_t *isp) mbs.param[0] = MBOX_SET_TAG_AGE_LIMIT; mbs.param[1] = sdp_chan0->isp_tag_aging; mbs.param[2] = sdp_chan1->isp_tag_aging; - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { isp_prt(isp, ISP_LOGERR, "failed to set tag age limit (%d,%d)", sdp_chan0->isp_tag_aging, sdp_chan1->isp_tag_aging); @@ -1012,7 +1313,8 @@ isp_scsi_init(ispsoftc_t *isp) mbs.param[0] = MBOX_SET_SELECT_TIMEOUT; mbs.param[1] = sdp_chan0->isp_selection_timeout; mbs.param[2] = sdp_chan1->isp_selection_timeout; - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; } @@ -1035,7 +1337,8 @@ isp_scsi_init(ispsoftc_t *isp) mbs.param[4] = 0; mbs.param[6] = DMA_WD3(isp->isp_result_dma); mbs.param[7] = DMA_WD2(isp->isp_result_dma); - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; } @@ -1049,7 +1352,8 @@ isp_scsi_init(ispsoftc_t *isp) mbs.param[5] = 0; mbs.param[6] = DMA_WD3(isp->isp_result_dma); mbs.param[7] = DMA_WD2(isp->isp_result_dma); - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; } @@ -1061,7 +1365,8 @@ isp_scsi_init(ispsoftc_t *isp) mbs.param[2] = DMA_WD1(isp->isp_result_dma); mbs.param[3] = DMA_WD0(isp->isp_result_dma); mbs.param[4] = 0; - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; } @@ -1073,7 +1378,8 @@ isp_scsi_init(ispsoftc_t *isp) mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); mbs.param[5] = 0; - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; } @@ -1103,7 +1409,8 @@ isp_scsi_init(ispsoftc_t *isp) #endif if (mbs.param[1] != 0) { uint16_t sfeat = mbs.param[1]; - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { isp_prt(isp, ISP_LOGINFO, "Enabled FW features (0x%x)", sfeat); @@ -1132,7 +1439,8 @@ isp_scsi_channel_init(ispsoftc_t *isp, int channel) MEMZERO(&mbs, sizeof (mbs)); mbs.param[0] = MBOX_SET_INIT_SCSI_ID; mbs.param[1] = (channel << 7) | sdp->isp_initiator_id; - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return; } @@ -1188,7 +1496,8 @@ isp_scsi_channel_init(ispsoftc_t *isp, int channel) "Initial Settings bus%d tgt%d flags 0x%x off 0x%x per 0x%x", channel, tgt, mbs.param[2], mbs.param[3] >> 8, mbs.param[3] & 0xff); - isp_mboxcmd(isp, &mbs, MBLOGNONE); + mbs.logval = MBLOGNONE; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { sdf = DPARM_SAFE_DFLT; MEMZERO(&mbs, sizeof (mbs)); @@ -1196,7 +1505,8 @@ isp_scsi_channel_init(ispsoftc_t *isp, int channel) mbs.param[1] = (tgt << 8) | (channel << 15); mbs.param[2] = sdf; mbs.param[3] = 0; - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { continue; } @@ -1220,7 +1530,8 @@ isp_scsi_channel_init(ispsoftc_t *isp, int channel) mbs.param[1] = (channel << 15) | (tgt << 8) | lun; mbs.param[2] = sdp->isp_max_queue_depth; mbs.param[3] = sdp->isp_devparam[tgt].exc_throttle; - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { break; } @@ -1237,8 +1548,6 @@ isp_scsi_channel_init(ispsoftc_t *isp, int channel) /* * Fibre Channel specific initialization. - * - * Locks are held before coming here. */ static void isp_fibre_init(ispsoftc_t *isp) @@ -1246,28 +1555,14 @@ isp_fibre_init(ispsoftc_t *isp) fcparam *fcp; isp_icb_t local, *icbp = &local; mbreg_t mbs; - int loopid; + int ownloopid; uint64_t nwwn, pwwn; fcp = isp->isp_param; - /* - * Do this *before* initializing the firmware. - */ - isp_mark_getpdb_all(isp); - fcp->isp_fwstate = FW_CONFIG_WAIT; - fcp->isp_loopstate = LOOP_NIL; - - /* - * If we have no role (neither target nor initiator), return. - */ - if (isp->isp_role == ISP_ROLE_NONE) { - return; - } - - loopid = fcp->isp_loopid; MEMZERO(icbp, sizeof (*icbp)); icbp->icb_version = ICB_VERSION1; + icbp->icb_fwoptions = fcp->isp_fwoptions; /* * Firmware Options are either retrieved from NVRAM or @@ -1279,8 +1574,8 @@ isp_fibre_init(ispsoftc_t *isp) /* * If this is a 2100 < revision 5, we have to turn off FAIRNESS. */ - if ((isp->isp_type == ISP_HA_FC_2100) && isp->isp_revision < 5) { - fcp->isp_fwoptions &= ~ICBOPT_FAIRNESS; + if (IS_2100(isp) && isp->isp_revision < 5) { + icbp->icb_fwoptions &= ~ICBOPT_FAIRNESS; } /* @@ -1289,33 +1584,29 @@ isp_fibre_init(ispsoftc_t *isp) * a LIP- this is a known f/w bug for 2100 f/w less than 1.17.0. */ if (!ISP_FW_NEWER_THAN(isp, 1, 17, 0)) { - fcp->isp_fwoptions |= ICBOPT_FULL_LOGIN; + icbp->icb_fwoptions |= ICBOPT_FULL_LOGIN; } /* * Insist on Port Database Update Async notifications */ - fcp->isp_fwoptions |= ICBOPT_PDBCHANGE_AE; + icbp->icb_fwoptions |= ICBOPT_PDBCHANGE_AE; /* * Make sure that target role reflects into fwoptions. */ if (isp->isp_role & ISP_ROLE_TARGET) { - fcp->isp_fwoptions |= ICBOPT_TGT_ENABLE; + icbp->icb_fwoptions |= ICBOPT_TGT_ENABLE; } else { - fcp->isp_fwoptions &= ~ICBOPT_TGT_ENABLE; + icbp->icb_fwoptions &= ~ICBOPT_TGT_ENABLE; } if (isp->isp_role & ISP_ROLE_INITIATOR) { - fcp->isp_fwoptions &= ~ICBOPT_INI_DISABLE; + icbp->icb_fwoptions &= ~ICBOPT_INI_DISABLE; } else { - fcp->isp_fwoptions |= ICBOPT_INI_DISABLE; + icbp->icb_fwoptions |= ICBOPT_INI_DISABLE; } - /* - * Propagate all of this into the ICB structure. - */ - icbp->icb_fwoptions = fcp->isp_fwoptions; icbp->icb_maxfrmlen = fcp->isp_maxfrmlen; if (icbp->icb_maxfrmlen < ICB_MIN_FRMLEN || icbp->icb_maxfrmlen > ICB_MAX_FRMLEN) { @@ -1339,24 +1630,18 @@ isp_fibre_init(ispsoftc_t *isp) } icbp->icb_retry_delay = fcp->isp_retry_delay; icbp->icb_retry_count = fcp->isp_retry_count; - icbp->icb_hardaddr = loopid; + icbp->icb_hardaddr = fcp->isp_loopid; + ownloopid = (isp->isp_confopts & ISP_CFG_OWNLOOPID) != 0; if (icbp->icb_hardaddr > 125) { - /* - * We end up with these Loop IDs for F-Port topologies - */ - if (icbp->icb_hardaddr != 0xff && icbp->icb_hardaddr != 0x800) { - isp_prt(isp, ISP_LOGERR, - "bad hard address %u- resetting to zero", - icbp->icb_hardaddr); - } icbp->icb_hardaddr = 0; + ownloopid = 0; } /* * Our life seems so much better with 2200s and later with * the latest f/w if we set Hard Address. */ - if (ISP_FW_NEWER_THAN(isp, 2, 2, 5)) { + if (ownloopid || ISP_FW_NEWER_THAN(isp, 2, 2, 5)) { icbp->icb_fwoptions |= ICBOPT_HARD_ADDRESS; } @@ -1434,7 +1719,11 @@ isp_fibre_init(ispsoftc_t *isp) mbs.param[1] = 0xb; mbs.param[2] = 0; mbs.param[3] = 0; - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + return; + } } icbp->icb_logintime = ICB_LOGIN_TOV; icbp->icb_lunetimeout = ICB_LUN_ENABLE_TOV; @@ -1451,9 +1740,16 @@ isp_fibre_init(ispsoftc_t *isp) ((uint32_t) (nwwn & 0xffffffff)), ((uint32_t) (pwwn >> 32)), ((uint32_t) (pwwn & 0xffffffff))); + } else if (pwwn) { + icbp->icb_fwoptions &= ~ICBOPT_BOTH_WWNS; + MAKE_NODE_NAME_FROM_WWN(icbp->icb_portname, pwwn); + isp_prt(isp, ISP_LOGDEBUG1, + "Setting ICB Port 0x%08x%08x", + ((uint32_t) (pwwn >> 32)), + ((uint32_t) (pwwn & 0xffffffff))); } else { - isp_prt(isp, ISP_LOGDEBUG1, "Not using any WWNs"); - icbp->icb_fwoptions &= ~(ICBOPT_BOTH_WWNS|ICBOPT_FULL_LOGIN); + isp_prt(isp, ISP_LOGERR, "No valid WWNs to use"); + return; } icbp->icb_rqstqlen = RQUEST_QUEUE_LEN(isp); if (icbp->icb_rqstqlen < 1) { @@ -1488,18 +1784,21 @@ isp_fibre_init(ispsoftc_t *isp) mbs.param[3] = DMA_WD0(fcp->isp_scdma); mbs.param[6] = DMA_WD3(fcp->isp_scdma); mbs.param[7] = DMA_WD2(fcp->isp_scdma); + mbs.logval = MBLOGALL; + mbs.timeout = 30 * 1000000; isp_prt(isp, ISP_LOGDEBUG0, "INIT F/W from %p (%08x%08x)", fcp->isp_scratch, (uint32_t) ((uint64_t)fcp->isp_scdma >> 32), (uint32_t) fcp->isp_scdma); MEMORYBARRIER(isp, SYNC_SFORDEV, 0, sizeof (*icbp)); - isp_mboxcmd(isp, &mbs, MBLOGALL); + isp_mboxcmd(isp, &mbs); FC_SCRATCH_RELEASE(isp); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_print_bytes(isp, "isp_fibre_init", sizeof (*icbp), icbp); return; } - isp->isp_reqidx = isp->isp_reqodx = 0; + isp->isp_reqidx = 0; + isp->isp_reqodx = 0; isp->isp_residx = 0; - isp->isp_sendmarker = 1; /* * Whatever happens, we're now committed to being here. @@ -1507,59 +1806,532 @@ isp_fibre_init(ispsoftc_t *isp) isp->isp_state = ISP_INITSTATE; } -/* - * Fibre Channel Support- get the port database for the id. - * - * Locks are held before coming here. Return 0 if success, - * else failure. - */ - -static int -isp_getmap(ispsoftc_t *isp, fcpos_map_t *map) +static void +isp_fibre_init_2400(ispsoftc_t *isp) { - fcparam *fcp = (fcparam *) isp->isp_param; + fcparam *fcp; + isp_icb_2400_t local, *icbp = &local; mbreg_t mbs; + int ownloopid; + uint64_t nwwn, pwwn; + + fcp = isp->isp_param; + + /* + * Turn on LIP F8 async event (1) + */ + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_SET_FIRMWARE_OPTIONS; + mbs.param[1] = 1; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + return; + } + + /* + * XXX: This should be applied to icb- not fwoptions + */ + if (isp->isp_role & ISP_ROLE_TARGET) { + fcp->isp_fwoptions |= ICB2400_OPT1_TGT_ENABLE; + } else { + fcp->isp_fwoptions &= ~ICB2400_OPT1_TGT_ENABLE; + } + + if (isp->isp_role & ISP_ROLE_INITIATOR) { + fcp->isp_fwoptions &= ~ICB2400_OPT1_INI_DISABLE; + } else { + fcp->isp_fwoptions |= ICB2400_OPT1_INI_DISABLE; + } + + MEMZERO(icbp, sizeof (*icbp)); + icbp->icb_version = ICB_VERSION1; + icbp->icb_maxfrmlen = fcp->isp_maxfrmlen; + if (icbp->icb_maxfrmlen < ICB_MIN_FRMLEN || + icbp->icb_maxfrmlen > ICB_MAX_FRMLEN) { + isp_prt(isp, ISP_LOGERR, + "bad frame length (%d) from NVRAM- using %d", + fcp->isp_maxfrmlen, ICB_DFLT_FRMLEN); + icbp->icb_maxfrmlen = ICB_DFLT_FRMLEN; + } + + icbp->icb_execthrottle = fcp->isp_execthrottle; + if (icbp->icb_execthrottle < 1) { + isp_prt(isp, ISP_LOGERR, + "bad execution throttle of %d- using 16", + fcp->isp_execthrottle); + icbp->icb_execthrottle = ICB_DFLT_THROTTLE; + } + + if (isp->isp_role & ISP_ROLE_TARGET) { + /* + * Get current resource count + */ + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_GET_RESOURCE_COUNT; + mbs.obits = 0x4cf; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + return; + } + icbp->icb_xchgcnt = mbs.param[3]; + } + + icbp->icb_fwoptions1 = fcp->isp_fwoptions; + + icbp->icb_hardaddr = fcp->isp_loopid; + ownloopid = (isp->isp_confopts & ISP_CFG_OWNLOOPID) != 0; + if (icbp->icb_hardaddr > 125) { + icbp->icb_hardaddr = 0; + ownloopid = 0; + } + if (ownloopid) { + icbp->icb_fwoptions1 |= ICB2400_OPT1_HARD_ADDRESS; + } + + icbp->icb_fwoptions2 = fcp->isp_xfwoptions; + switch(isp->isp_confopts & ISP_CFG_PORT_PREF) { + case ISP_CFG_NPORT: + icbp->icb_fwoptions2 &= ~ICB2400_OPT2_TOPO_MASK; + icbp->icb_fwoptions2 |= ICB2400_OPT2_PTP_2_LOOP; + break; + case ISP_CFG_NPORT_ONLY: + icbp->icb_fwoptions2 &= ~ICB2400_OPT2_TOPO_MASK; + icbp->icb_fwoptions2 |= ICB2400_OPT2_PTP_ONLY; + break; + case ISP_CFG_LPORT_ONLY: + icbp->icb_fwoptions2 &= ~ICB2400_OPT2_TOPO_MASK; + icbp->icb_fwoptions2 |= ICB2400_OPT2_LOOP_ONLY; + break; + default: + icbp->icb_fwoptions2 &= ~ICB2400_OPT2_TOPO_MASK; + icbp->icb_fwoptions2 |= ICB2400_OPT2_LOOP_2_PTP; + break; + } + + switch (icbp->icb_fwoptions2 & ICB2400_OPT2_TIMER_MASK) { + case ICB2400_OPT2_ZIO: + case ICB2400_OPT2_ZIO1: + icbp->icb_idelaytimer = 0; + break; + case 0: + break; + default: + isp_prt(isp, ISP_LOGWARN, "bad value %x in fwopt2 timer field", + icbp->icb_fwoptions2 & ICB2400_OPT2_TIMER_MASK); + icbp->icb_fwoptions2 &= ~ICB2400_OPT2_TIMER_MASK; + break; + } + icbp->icb_fwoptions3 = fcp->isp_zfwoptions; + icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_AUTO; + if (isp->isp_confopts & ISP_CFG_ONEGB) { + icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_ONEGB; + } else if (isp->isp_confopts & ISP_CFG_TWOGB) { + icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_TWOGB; + } else if (isp->isp_confopts & ISP_CFG_FOURGB) { + icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_FOURGB; + } else { + icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_AUTO; + } + + if ((isp->isp_confopts & ISP_CFG_OWNLOOPID) == 0) { + icbp->icb_fwoptions3 |= ICB2400_OPT3_SOFTID; + } + icbp->icb_logintime = ICB_LOGIN_TOV; + + nwwn = ISP_NODEWWN(isp); + pwwn = ISP_PORTWWN(isp); + + if (nwwn && pwwn) { + icbp->icb_fwoptions1 |= ICB2400_OPT1_BOTH_WWNS; + MAKE_NODE_NAME_FROM_WWN(icbp->icb_nodename, nwwn); + MAKE_NODE_NAME_FROM_WWN(icbp->icb_portname, pwwn); + isp_prt(isp, ISP_LOGDEBUG1, + "Setting ICB Node 0x%08x%08x Port 0x%08x%08x", + ((uint32_t) (nwwn >> 32)), + ((uint32_t) (nwwn & 0xffffffff)), + ((uint32_t) (pwwn >> 32)), + ((uint32_t) (pwwn & 0xffffffff))); + } else if (pwwn) { + icbp->icb_fwoptions1 &= ~ICB2400_OPT1_BOTH_WWNS; + MAKE_NODE_NAME_FROM_WWN(icbp->icb_portname, pwwn); + isp_prt(isp, ISP_LOGDEBUG1, + "Setting ICB Port 0x%08x%08x", + ((uint32_t) (pwwn >> 32)), + ((uint32_t) (pwwn & 0xffffffff))); + } else { + isp_prt(isp, ISP_LOGERR, "No valid WWNs to use"); + return; + } + icbp->icb_retry_count = fcp->isp_retry_count; + + icbp->icb_rqstqlen = RQUEST_QUEUE_LEN(isp); + if (icbp->icb_rqstqlen < 8) { + isp_prt(isp, ISP_LOGERR, "bad request queue length %d", + icbp->icb_rqstqlen); + return; + } + icbp->icb_rsltqlen = RESULT_QUEUE_LEN(isp); + if (icbp->icb_rsltqlen < 8) { + isp_prt(isp, ISP_LOGERR, "bad result queue length %d", + icbp->icb_rsltqlen); + return; + } + icbp->icb_rqstaddr[RQRSP_ADDR0015] = DMA_WD0(isp->isp_rquest_dma); + icbp->icb_rqstaddr[RQRSP_ADDR1631] = DMA_WD1(isp->isp_rquest_dma); + icbp->icb_rqstaddr[RQRSP_ADDR3247] = DMA_WD2(isp->isp_rquest_dma); + icbp->icb_rqstaddr[RQRSP_ADDR4863] = DMA_WD3(isp->isp_rquest_dma); + + icbp->icb_respaddr[RQRSP_ADDR0015] = DMA_WD0(isp->isp_result_dma); + icbp->icb_respaddr[RQRSP_ADDR1631] = DMA_WD1(isp->isp_result_dma); + icbp->icb_respaddr[RQRSP_ADDR3247] = DMA_WD2(isp->isp_result_dma); + icbp->icb_respaddr[RQRSP_ADDR4863] = DMA_WD3(isp->isp_result_dma); + +#ifdef ISP_TARGET_MODE + if (isp->isp_role & ISP_ROLE_TARGET) { + icbp->icb_atioqlen = RESULT_QUEUE_LEN(isp); + if (icbp->icb_atioqlen < 8) { + isp_prt(isp, ISP_LOGERR, "bad ATIO queue length %d", + icbp->icb_atioqlen); + return; + } + icbp->icb_atioqaddr[RQRSP_ADDR0015] = DMA_WD0(isp->isp_atioq_dma); + icbp->icb_atioqaddr[RQRSP_ADDR1631] = DMA_WD1(isp->isp_atioq_dma); + icbp->icb_atioqaddr[RQRSP_ADDR3247] = DMA_WD2(isp->isp_atioq_dma); + icbp->icb_atioqaddr[RQRSP_ADDR4863] = DMA_WD3(isp->isp_atioq_dma); + isp_prt(isp, ISP_LOGDEBUG0, + "isp_fibre_init_2400: atioq %04x%04x%04x%04x", + DMA_WD3(isp->isp_atioq_dma), DMA_WD2(isp->isp_atioq_dma), + DMA_WD1(isp->isp_atioq_dma), DMA_WD0(isp->isp_atioq_dma)); + } +#endif + + isp_prt(isp, ISP_LOGDEBUG0, + "isp_fibre_init_2400: fwopt1 0x%x fwopt2 0x%x fwopt3 0x%x", + icbp->icb_fwoptions1, icbp->icb_fwoptions2, icbp->icb_fwoptions3); + + isp_prt(isp, ISP_LOGDEBUG0, + "isp_fibre_init_2400: rqst %04x%04x%04x%04x rsp %04x%04x%04x%04x", + DMA_WD3(isp->isp_rquest_dma), DMA_WD2(isp->isp_rquest_dma), + DMA_WD1(isp->isp_rquest_dma), DMA_WD0(isp->isp_rquest_dma), + DMA_WD3(isp->isp_result_dma), DMA_WD2(isp->isp_result_dma), + DMA_WD1(isp->isp_result_dma), DMA_WD0(isp->isp_result_dma)); + + if (isp->isp_dblev & ISP_LOGDEBUG1) { + isp_print_bytes(isp, "isp_fibre_init_2400", sizeof (*icbp), + icbp); + } + FC_SCRATCH_ACQUIRE(isp); + isp_put_icb_2400(isp, icbp, fcp->isp_scratch); + + + /* + * Init the firmware + */ MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_GET_FC_AL_POSITION_MAP; + mbs.param[0] = MBOX_INIT_FIRMWARE; mbs.param[2] = DMA_WD1(fcp->isp_scdma); mbs.param[3] = DMA_WD0(fcp->isp_scdma); mbs.param[6] = DMA_WD3(fcp->isp_scdma); mbs.param[7] = DMA_WD2(fcp->isp_scdma); - FC_SCRATCH_ACQUIRE(isp); - MEMORYBARRIER(isp, SYNC_SFORDEV, 0, sizeof (fcpos_map_t)); - 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); - } + mbs.logval = MBLOGALL; + mbs.timeout = 30 * 1000000; + isp_prt(isp, ISP_LOGDEBUG0, "INIT F/W from %04x%04x%04x%04x", + DMA_WD3(fcp->isp_scdma), DMA_WD2(fcp->isp_scdma), + DMA_WD1(fcp->isp_scdma), DMA_WD0(fcp->isp_scdma)); + MEMORYBARRIER(isp, SYNC_SFORDEV, 0, sizeof (*icbp)); + isp_mboxcmd(isp, &mbs); FC_SCRATCH_RELEASE(isp); - return (-1); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + return; + } + isp->isp_reqidx = 0; + isp->isp_reqodx = 0; + isp->isp_residx = 0; + + /* + * Whatever happens, we're now committed to being here. + */ + isp->isp_state = ISP_INITSTATE; } static void -isp_mark_getpdb_all(ispsoftc_t *isp) +isp_mark_portdb(ispsoftc_t *isp, int onprobation) { fcparam *fcp = (fcparam *) isp->isp_param; int i; + for (i = 0; i < MAX_FC_TARG; i++) { - fcp->portdb[i].valid = fcp->portdb[i].fabric_dev = 0; + if (onprobation == 0) { + MEMZERO(&fcp->portdb[i], sizeof (fcportdb_t)); + } else { + switch (fcp->portdb[i].state) { + case FC_PORTDB_STATE_CHANGED: + case FC_PORTDB_STATE_PENDING_VALID: + case FC_PORTDB_STATE_VALID: + case FC_PORTDB_STATE_PROBATIONAL: + fcp->portdb[i].state = + FC_PORTDB_STATE_PROBATIONAL; + break; + case FC_PORTDB_STATE_ZOMBIE: + break; + case FC_PORTDB_STATE_NIL: + default: + MEMZERO(&fcp->portdb[i], sizeof (fcportdb_t)); + fcp->portdb[i].state = + FC_PORTDB_STATE_NIL; + break; + } + } } } +/* + * Perform an IOCB PLOGI or LOGO via EXECUTE IOCB A64 for 24XX cards + * or via FABRIC LOGIN/FABRIC LOGOUT for other cards. + */ static int -isp_getpdb(ispsoftc_t *isp, int id, isp_pdb_t *pdbp) +isp_plogx(ispsoftc_t *isp, uint16_t handle, uint32_t portid, int flags, int gs) +{ + mbreg_t mbs; + uint8_t q[QENTRY_LEN]; + isp_plogx_t *plp; + uint8_t *scp; + uint32_t sst, parm1; + int rval; + + if (!IS_24XX(isp)) { + int action = flags & PLOGX_FLG_CMD_MASK; + if (action == PLOGX_FLG_CMD_PLOGI) { + return (isp_port_login(isp, handle, portid)); + } else if (action == PLOGX_FLG_CMD_LOGO) { + return (isp_port_logout(isp, handle, portid)); + } else { + return (MBOX_INVALID_COMMAND); + } + } + + MEMZERO(q, QENTRY_LEN); + plp = (isp_plogx_t *) q; + plp->plogx_header.rqs_entry_count = 1; + plp->plogx_header.rqs_entry_type = RQSTYPE_LOGIN; + plp->plogx_handle = 0xffffffff; + plp->plogx_nphdl = handle; + plp->plogx_portlo = portid; + plp->plogx_rspsz_porthi = (portid >> 16) & 0xff; + plp->plogx_flags = flags; + + if (isp->isp_dblev & ISP_LOGDEBUG1) { + isp_print_bytes(isp, "IOCB LOGX", QENTRY_LEN, plp); + } + + if (gs == 0) { + FC_SCRATCH_ACQUIRE(isp); + } + scp = FCPARAM(isp)->isp_scratch; + isp_put_plogx(isp, plp, (isp_plogx_t *) scp); + + + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_EXEC_COMMAND_IOCB_A64; + mbs.param[1] = QENTRY_LEN; + mbs.param[2] = DMA_WD1(FCPARAM(isp)->isp_scdma); + mbs.param[3] = DMA_WD0(FCPARAM(isp)->isp_scdma); + mbs.param[6] = DMA_WD3(FCPARAM(isp)->isp_scdma); + mbs.param[7] = DMA_WD2(FCPARAM(isp)->isp_scdma); + mbs.timeout = 500000; + mbs.logval = MBLOGALL; + MEMORYBARRIER(isp, SYNC_SFORDEV, 0, QENTRY_LEN); + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + rval = mbs.param[0]; + goto out; + } + MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN); + scp += QENTRY_LEN; + isp_get_plogx(isp, (isp_plogx_t *) scp, plp); + if (isp->isp_dblev & ISP_LOGDEBUG1) { + isp_print_bytes(isp, "IOCB LOGX response", QENTRY_LEN, plp); + } + + if (plp->plogx_status == PLOGX_STATUS_OK) { + rval = 0; + goto out; + } else if (plp->plogx_status != PLOGX_STATUS_IOCBERR) { + isp_prt(isp, ISP_LOGWARN, "status 0x%x on port login IOCB", + plp->plogx_status); + rval = -1; + goto out; + } + + sst = plp->plogx_ioparm[0].lo16 | (plp->plogx_ioparm[0].hi16 << 16); + parm1 = plp->plogx_ioparm[1].lo16 | (plp->plogx_ioparm[1].hi16 << 16); + + rval = -1; + + switch (sst) { + case PLOGX_IOCBERR_NOLINK: + isp_prt(isp, ISP_LOGERR, "PLOGX failed- no link"); + break; + case PLOGX_IOCBERR_NOIOCB: + isp_prt(isp, ISP_LOGERR, "PLOGX failed- no IOCB buffer"); + break; + case PLOGX_IOCBERR_NOXGHG: + isp_prt(isp, ISP_LOGERR, + "PLOGX failed- no Exchange Control Block"); + break; + case PLOGX_IOCBERR_FAILED: + isp_prt(isp, ISP_LOGERR, + "PLOGX(0x%x) of Port 0x%06x failed: reason 0x%x (last LOGIN" + " state 0x%x)", flags, portid, parm1 & 0xff, + (parm1 >> 8) & 0xff); + break; + case PLOGX_IOCBERR_NOFABRIC: + isp_prt(isp, ISP_LOGERR, "PLOGX failed- no fabric"); + break; + case PLOGX_IOCBERR_NOTREADY: + isp_prt(isp, ISP_LOGERR, "PLOGX failed- f/w not ready"); + break; + case PLOGX_IOCBERR_NOLOGIN: + isp_prt(isp, ISP_LOGERR, + "PLOGX failed- not logged in (last LOGIN state 0x%x)", + parm1); + rval = MBOX_NOT_LOGGED_IN; + break; + case PLOGX_IOCBERR_REJECT: + isp_prt(isp, ISP_LOGERR, "PLOGX failed: LS_RJT = 0x%x", parm1); + break; + case PLOGX_IOCBERR_NOPCB: + isp_prt(isp, ISP_LOGERR, "PLOGX failed- no PCB allocated"); + break; + case PLOGX_IOCBERR_EINVAL: + isp_prt(isp, ISP_LOGERR, + "PLOGX failed: invalid parameter at offset 0x%x", parm1); + break; + case PLOGX_IOCBERR_PORTUSED: + isp_prt(isp, ISP_LOGDEBUG0, + "portid 0x%x already logged in with N-port handle 0x%x", + portid, parm1); + rval = MBOX_PORT_ID_USED | (handle << 16); + break; + case PLOGX_IOCBERR_HNDLUSED: + isp_prt(isp, ISP_LOGDEBUG0, + "N-port handle 0x%x already used for portid 0x%x", + handle, parm1); + rval = MBOX_LOOP_ID_USED; + break; + case PLOGX_IOCBERR_NOHANDLE: + isp_prt(isp, ISP_LOGERR, "PLOGX failed- no handle allocated"); + break; + case PLOGX_IOCBERR_NOFLOGI: + isp_prt(isp, ISP_LOGERR, "PLOGX failed- no FLOGI_ACC"); + break; + default: + isp_prt(isp, ISP_LOGERR, "status %x from %x", plp->plogx_status, + flags); + rval = -1; + break; + } +out: + if (gs == 0) { + FC_SCRATCH_RELEASE(isp); + } + return (rval); +} + +static int +isp_port_login(ispsoftc_t *isp, uint16_t handle, uint32_t portid) +{ + mbreg_t mbs; + + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_FABRIC_LOGIN; + if (FCPARAM(isp)->isp_2klogin) { + mbs.param[1] = handle; + mbs.ibits = (1 << 10); + } else { + mbs.param[1] = handle << 8; + } + mbs.param[2] = portid >> 16; + mbs.param[3] = portid; + mbs.logval = MBLOGNONE; + mbs.timeout = 500000; + isp_mboxcmd(isp, &mbs); + + switch (mbs.param[0]) { + case MBOX_PORT_ID_USED: + isp_prt(isp, ISP_LOGDEBUG0, + "isp_plogi_old: portid 0x%06x already logged in as %u", + portid, mbs.param[1]); + return (MBOX_PORT_ID_USED | (mbs.param[1] << 16)); + + case MBOX_LOOP_ID_USED: + isp_prt(isp, ISP_LOGDEBUG0, + "isp_plogi_old: handle %u in use for port id 0x%02xXXXX", + handle, mbs.param[1] & 0xff); + return (MBOX_LOOP_ID_USED); + + case MBOX_COMMAND_COMPLETE: + return (0); + + case MBOX_COMMAND_ERROR: + isp_prt(isp, ISP_LOGINFO, + "isp_plogi_old: error 0x%x in PLOGI to port 0x%06x", + mbs.param[1], portid); + return (MBOX_COMMAND_ERROR); + + case MBOX_ALL_IDS_USED: + isp_prt(isp, ISP_LOGINFO, + "isp_plogi_old: all IDs used for fabric login"); + return (MBOX_ALL_IDS_USED); + + default: + isp_prt(isp, ISP_LOGINFO, + "isp_plogi_old: error 0x%x on port login of 0x%06x@0x%0x", + mbs.param[0], portid, handle); + return (mbs.param[0]); + } +} + +static int +isp_port_logout(ispsoftc_t *isp, uint16_t handle, uint32_t portid) +{ + mbreg_t mbs; + + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_FABRIC_LOGOUT; + if (FCPARAM(isp)->isp_2klogin) { + mbs.param[1] = handle; + mbs.ibits = (1 << 10); + } else { + mbs.param[1] = handle << 8; + } + mbs.logval = MBLOGNONE; + mbs.timeout = 100000; + isp_mboxcmd(isp, &mbs); + return (mbs.param[0] == MBOX_COMMAND_COMPLETE? 0 : mbs.param[0]); +} + +static int +isp_getpdb(ispsoftc_t *isp, uint16_t id, isp_pdb_t *pdb, int dolock) { fcparam *fcp = (fcparam *) isp->isp_param; mbreg_t mbs; + union { + isp_pdb_21xx_t fred; + isp_pdb_24xx_t bill; + } un; MEMZERO(&mbs, sizeof (mbs)); mbs.param[0] = MBOX_GET_PORT_DB; - if (IS_2KLOGIN(isp)) { + if (IS_24XX(isp)) { + mbs.ibits = 0x3ff; + mbs.param[1] = id; + } else if (FCPARAM(isp)->isp_2klogin) { mbs.param[1] = id; - mbs.ibits |= (1 << 10); + mbs.ibits = (1 << 10); } else { mbs.param[1] = id << 8; } @@ -1567,29 +2339,51 @@ isp_getpdb(ispsoftc_t *isp, int id, isp_pdb_t *pdbp) mbs.param[3] = DMA_WD0(fcp->isp_scdma); mbs.param[6] = DMA_WD3(fcp->isp_scdma); mbs.param[7] = DMA_WD2(fcp->isp_scdma); - FC_SCRATCH_ACQUIRE(isp); - MEMORYBARRIER(isp, SYNC_SFORDEV, 0, sizeof (isp_pdb_t)); - 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); + mbs.timeout = 250000; + mbs.logval = MBLOGALL & ~MBOX_COMMAND_PARAM_ERROR; + if (dolock) { + FC_SCRATCH_ACQUIRE(isp); + } + MEMORYBARRIER(isp, SYNC_SFORDEV, 0, sizeof (un)); + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + if (dolock) { + FC_SCRATCH_RELEASE(isp); + } + return (-1); + } + if (IS_24XX(isp)) { + isp_get_pdb_24xx(isp, fcp->isp_scratch, &un.bill); + pdb->handle = un.bill.pdb_handle; + pdb->s3_role = un.bill.pdb_prli_svc3; + pdb->portid = BITS2WORD_24XX(un.bill.pdb_portid_bits); + MEMCPY(pdb->portname, un.bill.pdb_portname, 8); + MEMCPY(pdb->nodename, un.bill.pdb_nodename, 8); + } else { + isp_get_pdb_21xx(isp, fcp->isp_scratch, &un.fred); + pdb->handle = un.fred.pdb_loopid; + pdb->s3_role = un.fred.pdb_prli_svc3; + pdb->portid = BITS2WORD(un.fred.pdb_portid_bits); + MEMCPY(pdb->portname, un.fred.pdb_portname, 8); + MEMCPY(pdb->nodename, un.fred.pdb_nodename, 8); + } + if (dolock) { FC_SCRATCH_RELEASE(isp); - return (0); } - FC_SCRATCH_RELEASE(isp); - return (-1); + return (0); } static uint64_t isp_get_portname(ispsoftc_t *isp, int loopid, int nodename) { - uint64_t wwn = 0; + uint64_t wwn = (uint64_t) -1; mbreg_t mbs; MEMZERO(&mbs, sizeof (mbs)); mbs.param[0] = MBOX_GET_PORT_NAME; - if (IS_2KLOGIN(isp)) { + if (FCPARAM(isp)->isp_2klogin || IS_24XX(isp)) { mbs.param[1] = loopid; - mbs.ibits |= (1 << 10); + mbs.ibits = (1 << 10); if (nodename) { mbs.param[10] = 1; } @@ -1599,8 +2393,22 @@ isp_get_portname(ispsoftc_t *isp, int loopid, int nodename) mbs.param[1] |= 1; } } - isp_mboxcmd(isp, &mbs, MBLOGALL & ~MBOX_COMMAND_PARAM_ERROR); - if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { + mbs.logval = MBLOGALL & ~MBOX_COMMAND_PARAM_ERROR; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + return (wwn); + } + if (IS_24XX(isp)) { + wwn = + (((uint64_t)(mbs.param[2] >> 8)) << 56) | + (((uint64_t)(mbs.param[2] & 0xff)) << 48) | + (((uint64_t)(mbs.param[3] >> 8)) << 40) | + (((uint64_t)(mbs.param[3] & 0xff)) << 32) | + (((uint64_t)(mbs.param[6] >> 8)) << 24) | + (((uint64_t)(mbs.param[6] & 0xff)) << 16) | + (((uint64_t)(mbs.param[7] >> 8)) << 8) | + (((uint64_t)(mbs.param[7] & 0xff))); + } else { wwn = (((uint64_t)(mbs.param[2] & 0xff)) << 56) | (((uint64_t)(mbs.param[2] >> 8)) << 48) | @@ -1615,13 +2423,13 @@ isp_get_portname(ispsoftc_t *isp, int loopid, int nodename) } /* - * Make sure we have good FC link and know our Loop ID. + * Make sure we have good FC link. */ static int isp_fclink_test(ispsoftc_t *isp, int usdelay) { - static char *toponames[] = { + static const char *toponames[] = { "Private Loop", "FL Port", "N-Port to N-Port", @@ -1631,17 +2439,15 @@ isp_fclink_test(ispsoftc_t *isp, int usdelay) mbreg_t mbs; int count, check_for_fabric; uint8_t lwfs; + int loopid; fcparam *fcp; - struct lportdb *lp; + fcportdb_t *lp; isp_pdb_t pdb; fcp = isp->isp_param; - isp_prt(isp, ISP_LOGDEBUG0, "FC Link Test Entry"); - - /* - * XXX: Here is where we would start a 'loop dead' timeout - */ + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "FC Link Test Entry"); + ISP_MARK_PORTDB(isp, 1); /* * Wait up to N microseconds for F/W to go to a ready state. @@ -1656,9 +2462,10 @@ isp_fclink_test(ispsoftc_t *isp, int usdelay) GET_NANOTIME(&hra); isp_fw_state(isp); if (lwfs != fcp->isp_fwstate) { - isp_prt(isp, ISP_LOGINFO, "Firmware State <%s->%s>", - isp2100_fw_statename((int)lwfs), - isp2100_fw_statename((int)fcp->isp_fwstate)); + isp_prt(isp, ISP_LOGCONFIG|ISP_LOGSANCFG, + "Firmware State <%s->%s>", + ispfc_fw_statename((int)lwfs), + ispfc_fw_statename((int)fcp->isp_fwstate)); lwfs = fcp->isp_fwstate; } if (fcp->isp_fwstate == FW_READY) { @@ -1710,50 +2517,39 @@ isp_fclink_test(ispsoftc_t *isp, int usdelay) * If we haven't gone to 'ready' state, return. */ if (fcp->isp_fwstate != FW_READY) { + isp_prt(isp, ISP_LOGSANCFG, + "isp_fclink_test: not at FW_READY state"); return (-1); } /* - * Get our Loop ID (if possible). We really need to have it. + * Get our Loop ID and Port ID. */ MEMZERO(&mbs, sizeof (mbs)); mbs.param[0] = MBOX_GET_LOOP_ID; - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { return (-1); } - if (IS_2KLOGIN(isp)) { + + if (FCPARAM(isp)->isp_2klogin) { fcp->isp_loopid = mbs.param[1]; } else { fcp->isp_loopid = mbs.param[1] & 0xff; } - if (fcp->isp_loopid == 0xffff) { /* happens with 2k login f/w */ - fcp->isp_loopid = MAX_FC_TARG-1; - } else if (fcp->isp_loopid >= MAX_FC_TARG) { - isp_prt(isp, ISP_LOGWARN, "bad initiator loopid (0x%x)", fcp->isp_loopid); - fcp->isp_loopid = MAX_FC_TARG-1; - } - if (IS_2200(isp) || IS_23XX(isp)) { + + if (IS_2100(isp)) { + fcp->isp_topo = TOPO_NL_PORT; + } else { int topo = (int) mbs.param[6]; - if (topo < TOPO_NL_PORT || topo > TOPO_PTP_STUB) + if (topo < TOPO_NL_PORT || topo > TOPO_PTP_STUB) { topo = TOPO_PTP_STUB; + } fcp->isp_topo = topo; - } else { - fcp->isp_topo = TOPO_NL_PORT; } - /* - * Get the port id. - */ fcp->isp_portid = mbs.param[2] | (mbs.param[3] << 16); - /* - * Check to see if we're on a fabric by trying to see if we - * can talk to the fabric name server. This can be a bit - * tricky because if we're a 2100, we should check always - * (in case we're connected to a server doing aliasing). - */ - fcp->isp_onfabric = 0; - if (IS_2100(isp)) { /* * Don't bother with fabric if we are using really old @@ -1767,123 +2563,92 @@ isp_fclink_test(ispsoftc_t *isp, int usdelay) } else if (fcp->isp_topo == TOPO_FL_PORT || fcp->isp_topo == TOPO_F_PORT) { check_for_fabric = 1; - } else + } else { check_for_fabric = 0; + } - if (check_for_fabric && isp_getpdb(isp, FL_PORT_ID, &pdb) == 0) { - int loopid = FL_PORT_ID; + if (IS_24XX(isp)) { + loopid = NPH_FL_ID; + } else { + loopid = FL_ID; + } + + if (check_for_fabric && isp_getpdb(isp, loopid, &pdb, 1) == 0) { + int r; if (IS_2100(isp)) { fcp->isp_topo = TOPO_FL_PORT; } - - if (BITS2WORD(pdb.pdb_portid_bits) == 0) { + if (pdb.portid == 0) { /* * Crock. */ fcp->isp_topo = TOPO_NL_PORT; goto not_on_fabric; } - fcp->isp_portid = mbs.param[2] | ((int) mbs.param[3] << 16); /* * Save the Fabric controller's port database entry. */ - lp = &fcp->portdb[loopid]; - lp->node_wwn = - (((uint64_t)pdb.pdb_nodename[0]) << 56) | - (((uint64_t)pdb.pdb_nodename[1]) << 48) | - (((uint64_t)pdb.pdb_nodename[2]) << 40) | - (((uint64_t)pdb.pdb_nodename[3]) << 32) | - (((uint64_t)pdb.pdb_nodename[4]) << 24) | - (((uint64_t)pdb.pdb_nodename[5]) << 16) | - (((uint64_t)pdb.pdb_nodename[6]) << 8) | - (((uint64_t)pdb.pdb_nodename[7])); - lp->port_wwn = - (((uint64_t)pdb.pdb_portname[0]) << 56) | - (((uint64_t)pdb.pdb_portname[1]) << 48) | - (((uint64_t)pdb.pdb_portname[2]) << 40) | - (((uint64_t)pdb.pdb_portname[3]) << 32) | - (((uint64_t)pdb.pdb_portname[4]) << 24) | - (((uint64_t)pdb.pdb_portname[5]) << 16) | - (((uint64_t)pdb.pdb_portname[6]) << 8) | - (((uint64_t)pdb.pdb_portname[7])); - lp->roles = - (pdb.pdb_prli_svc3 & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT; - lp->portid = BITS2WORD(pdb.pdb_portid_bits); - lp->loopid = pdb.pdb_loopid; - lp->loggedin = lp->valid = 1; - fcp->isp_onfabric = 1; - (void) isp_async(isp, ISPASYNC_PROMENADE, &loopid); - isp_register_fc4_type(isp); + lp = &fcp->portdb[FL_ID]; + lp->state = FC_PORTDB_STATE_PENDING_VALID; + MAKE_WWN_FROM_NODE_NAME(lp->node_wwn, pdb.nodename); + MAKE_WWN_FROM_NODE_NAME(lp->port_wwn, pdb.portname); + lp->roles = (pdb.s3_role & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT; + lp->portid = pdb.portid; + lp->handle = pdb.handle; + lp->new_portid = lp->portid; + lp->new_roles = lp->roles; + if (IS_24XX(isp)) { + r = isp_register_fc4_type_24xx(isp); + } else { + r = isp_register_fc4_type(isp); + } + if (r) { + isp_prt(isp, ISP_LOGSANCFG, + "isp_fclink_test: register fc4 type failed"); + return (-1); + } } else { not_on_fabric: - fcp->isp_onfabric = 0; - fcp->portdb[FL_PORT_ID].valid = 0; + fcp->portdb[FL_ID].state = FC_PORTDB_STATE_NIL; } fcp->isp_gbspeed = 1; - if (IS_23XX(isp)) { + if (IS_23XX(isp) || IS_24XX(isp)) { MEMZERO(&mbs, sizeof (mbs)); mbs.param[0] = MBOX_GET_SET_DATA_RATE; mbs.param[1] = MBGSD_GET_RATE; /* mbs.param[2] undefined if we're just getting rate */ - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + mbs.timeout = 3000000; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { - if (mbs.param[1] == MBGSD_TWOGB) { + if (mbs.param[1] == MBGSD_FOURGB) { + isp_prt(isp, ISP_LOGINFO, "4Gb link speed/s"); + fcp->isp_gbspeed = 4; + } if (mbs.param[1] == MBGSD_TWOGB) { isp_prt(isp, ISP_LOGINFO, "2Gb link speed/s"); fcp->isp_gbspeed = 2; } } } - isp_prt(isp, ISP_LOGCONFIG, topology, fcp->isp_loopid, - fcp->isp_portid, fcp->isp_loopstate, toponames[fcp->isp_topo]); - /* - * Announce ourselves, too. This involves synthesizing an entry. + * Announce ourselves, too. */ - if (fcp->isp_iid_set == 0) { - fcp->isp_iid_set = 1; - fcp->isp_iid = fcp->isp_loopid; - lp = &fcp->portdb[fcp->isp_iid]; - } else { - lp = &fcp->portdb[fcp->isp_iid]; - if (fcp->isp_portid != lp->portid || - fcp->isp_loopid != lp->loopid || - fcp->isp_nodewwn != ISP_NODEWWN(isp) || - fcp->isp_portwwn != ISP_PORTWWN(isp)) { - lp->valid = 0; - count = fcp->isp_iid; - (void) isp_async(isp, ISPASYNC_PROMENADE, &count); - } - } - lp->loopid = fcp->isp_loopid; - lp->portid = fcp->isp_portid; - lp->node_wwn = ISP_NODEWWN(isp); - lp->port_wwn = ISP_PORTWWN(isp); - switch (isp->isp_role) { - case ISP_ROLE_NONE: - lp->roles = 0; - break; - case ISP_ROLE_TARGET: - lp->roles = SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT; - break; - case ISP_ROLE_INITIATOR: - lp->roles = SVC3_INI_ROLE >> SVC3_ROLE_SHIFT; - break; - case ISP_ROLE_BOTH: - lp->roles = (SVC3_INI_ROLE|SVC3_TGT_ROLE) >> SVC3_ROLE_SHIFT; - break; - } - lp->loggedin = lp->valid = 1; - count = fcp->isp_iid; - (void) isp_async(isp, ISPASYNC_PROMENADE, &count); - isp_prt(isp, ISP_LOGDEBUG0, "FC Link Test Complete"); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGCONFIG, topology, fcp->isp_portid, + fcp->isp_loopid, toponames[fcp->isp_topo]); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGCONFIG, ourwwn, + (uint32_t) (ISP_NODEWWN(isp) >> 32), + (uint32_t) ISP_NODEWWN(isp), + (uint32_t) (ISP_PORTWWN(isp) >> 32), + (uint32_t) ISP_PORTWWN(isp)); + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "FC Link Test Complete"); return (0); } static const char * -isp2100_fw_statename(int state) +ispfc_fw_statename(int state) { switch(state) { case FW_CONFIG_WAIT: return "Config Wait"; @@ -1899,17 +2664,35 @@ isp2100_fw_statename(int state) } /* - * Synchronize our soft copy of the port database with what the f/w thinks - * (with a view toward possibly for a specific target....) + * Complete the synchronization of our Port Database. + * + * At this point, we've scanned the local loop (if any) and the fabric + * and performed fabric logins on all new devices. + * + * Our task here is to go through our port database and remove any entities + * that are still marked probational (issuing PLOGO for ones which we had + * PLOGI'd into) or are dead. + * + * Our task here is to also check policy to decide whether devices which + * have *changed* in some way should still be kept active. For example, + * if a device has just changed PortID, we can either elect to treat it + * as an old device or as a newly arrived device (and notify the outer + * layer appropriately). + * + * We also do initiator map target id assignment here for new initiator + * devices and refresh old ones ot make sure that they point to the corret + * entities. */ - static int isp_pdb_sync(ispsoftc_t *isp) { - struct lportdb *lp; fcparam *fcp = isp->isp_param; - isp_pdb_t pdb; - int loopid, base, lim; + fcportdb_t *lp; + uint16_t dbidx; + + if (fcp->isp_loopstate == LOOP_READY) { + return (0); + } /* * Make sure we're okay for doing this right now. @@ -1917,306 +2700,127 @@ isp_pdb_sync(ispsoftc_t *isp) if (fcp->isp_loopstate != LOOP_PDB_RCVD && fcp->isp_loopstate != LOOP_FSCAN_DONE && fcp->isp_loopstate != LOOP_LSCAN_DONE) { + isp_prt(isp, ISP_LOGWARN, "isp_pdb_sync: bad loopstate %d", + fcp->isp_loopstate); return (-1); } - if (fcp->isp_topo == TOPO_FL_PORT || fcp->isp_topo == TOPO_NL_PORT || + if (fcp->isp_topo == TOPO_FL_PORT || + fcp->isp_topo == TOPO_NL_PORT || fcp->isp_topo == TOPO_N_PORT) { if (fcp->isp_loopstate < LOOP_LSCAN_DONE) { if (isp_scan_loop(isp) != 0) { + isp_prt(isp, ISP_LOGWARN, + "isp_pdb_sync: isp_scan_loop failed"); return (-1); } } } - fcp->isp_loopstate = LOOP_SYNCING_PDB; - - /* - * If we get this far, we've settled our differences with the f/w - * (for local loop device) and we can say that the loop state is ready. - */ - - if (fcp->isp_topo == TOPO_NL_PORT) { - fcp->loop_seen_once = 1; - fcp->isp_loopstate = LOOP_READY; - return (0); - } - /* - * Find all Fabric Entities that didn't make it from one scan to the - * next and let the world know they went away. Scan the whole database. - */ - for (lp = &fcp->portdb[0]; lp < &fcp->portdb[MAX_FC_TARG]; lp++) { - if (lp->was_fabric_dev && lp->fabric_dev == 0) { - loopid = lp - fcp->portdb; - lp->valid = 0; /* should already be set */ - (void) isp_async(isp, ISPASYNC_PROMENADE, &loopid); - MEMZERO((void *) lp, sizeof (*lp)); - continue; + if (fcp->isp_topo == TOPO_F_PORT || fcp->isp_topo == TOPO_FL_PORT) { + if (fcp->isp_loopstate < LOOP_FSCAN_DONE) { + if (isp_scan_fabric(isp) != 0) { + isp_prt(isp, ISP_LOGWARN, + "isp_pdb_sync: isp_scan_fabric failed"); + return (-1); + } } - lp->was_fabric_dev = lp->fabric_dev; } - if (fcp->isp_topo == TOPO_FL_PORT) - base = FC_SNS_ID+1; - else - base = 0; + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Synchronizing PDBs"); - if (fcp->isp_topo == TOPO_N_PORT) - lim = 1; - else - lim = MAX_FC_TARG; - - /* - * Now log in any fabric devices that the outer layer has - * left for us to see. This seems the most sane policy - * for the moment. - */ - for (lp = &fcp->portdb[base]; lp < &fcp->portdb[lim]; lp++) { - uint32_t portid; - mbreg_t mbs; - - loopid = lp - fcp->portdb; - if (loopid >= FL_PORT_ID && loopid <= FC_SNS_ID) { - continue; - } + fcp->isp_loopstate = LOOP_SYNCING_PDB; - /* - * Anything here? - */ - if (lp->port_wwn == 0) { - continue; - } + for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { + lp = &fcp->portdb[dbidx]; - /* - * Don't try to log into yourself. - */ - if ((portid = lp->portid) == fcp->isp_portid) { + if (lp->state == FC_PORTDB_STATE_NIL) { continue; } - - /* - * If we'd been logged in- see if we still are and we haven't - * changed. If so, no need to log ourselves out, etc.. - * - * Unfortunately, our charming Qlogic f/w has decided to - * return a valid port database entry for a fabric device - * that has, in fact, gone away. And it hangs trying to - * log it out. - */ - if (lp->loggedin && lp->force_logout == 0 && - isp_getpdb(isp, lp->loopid, &pdb) == 0) { - int nrole; - uint64_t nwwnn, nwwpn; - nwwnn = - (((uint64_t)pdb.pdb_nodename[0]) << 56) | - (((uint64_t)pdb.pdb_nodename[1]) << 48) | - (((uint64_t)pdb.pdb_nodename[2]) << 40) | - (((uint64_t)pdb.pdb_nodename[3]) << 32) | - (((uint64_t)pdb.pdb_nodename[4]) << 24) | - (((uint64_t)pdb.pdb_nodename[5]) << 16) | - (((uint64_t)pdb.pdb_nodename[6]) << 8) | - (((uint64_t)pdb.pdb_nodename[7])); - nwwpn = - (((uint64_t)pdb.pdb_portname[0]) << 56) | - (((uint64_t)pdb.pdb_portname[1]) << 48) | - (((uint64_t)pdb.pdb_portname[2]) << 40) | - (((uint64_t)pdb.pdb_portname[3]) << 32) | - (((uint64_t)pdb.pdb_portname[4]) << 24) | - (((uint64_t)pdb.pdb_portname[5]) << 16) | - (((uint64_t)pdb.pdb_portname[6]) << 8) | - (((uint64_t)pdb.pdb_portname[7])); - nrole = (pdb.pdb_prli_svc3 & SVC3_ROLE_MASK) >> - SVC3_ROLE_SHIFT; - if (pdb.pdb_loopid == lp->loopid && lp->portid == - (uint32_t) BITS2WORD(pdb.pdb_portid_bits) && - nwwnn == lp->node_wwn && nwwpn == lp->port_wwn && - lp->roles == nrole && lp->force_logout == 0) { - lp->loggedin = lp->valid = 1; - isp_prt(isp, ISP_LOGCONFIG, lretained, - (int) (lp - fcp->portdb), - (int) lp->loopid, lp->portid); - continue; - } - } - - if (fcp->isp_fwstate != FW_READY || - fcp->isp_loopstate != LOOP_SYNCING_PDB) { - return (-1); - } - - /* - * Force a logout if we were logged in. - */ - if (lp->loggedin) { - if (lp->force_logout || - isp_getpdb(isp, lp->loopid, &pdb) == 0) { - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_FABRIC_LOGOUT; - if (IS_2KLOGIN(isp)) { - mbs.param[1] = lp->loopid; - mbs.ibits |= (1 << 10); - } else { - mbs.param[1] = lp->loopid << 8; - } - isp_mboxcmd(isp, &mbs, MBLOGNONE); - isp_prt(isp, ISP_LOGINFO, plogout, - (int) (lp - fcp->portdb), lp->loopid, - lp->portid); - } - lp->force_logout = lp->loggedin = 0; - if (fcp->isp_fwstate != FW_READY || - fcp->isp_loopstate != LOOP_SYNCING_PDB) { - return (-1); + if (lp->state == FC_PORTDB_STATE_VALID) { + if (dbidx != FL_ID) { + isp_prt(isp, + ISP_LOGERR, "portdb idx %d already valid", + dbidx); } + continue; } - /* - * And log in.... - */ - loopid = lp - fcp->portdb; - lp->loopid = FL_PORT_ID; - do { - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_FABRIC_LOGIN; - if (IS_2KLOGIN(isp)) { - mbs.param[1] = loopid; - mbs.ibits |= (1 << 10); + switch (lp->state) { + case FC_PORTDB_STATE_PROBATIONAL: + case FC_PORTDB_STATE_DEAD: + /* + * It's up to the outer layers to clear isp_ini_map. + */ + lp->state = FC_PORTDB_STATE_NIL; + isp_async(isp, ISPASYNC_DEV_GONE, lp); + if (lp->autologin == 0) { + (void) isp_plogx(isp, lp->handle, lp->portid, + PLOGX_FLG_CMD_LOGO | + PLOGX_FLG_IMPLICIT | + PLOGX_FLG_FREE_NPHDL, 0); } else { - mbs.param[1] = loopid << 8; + lp->autologin = 0; } - mbs.param[2] = portid >> 16; - mbs.param[3] = portid & 0xffff; - isp_mboxcmd(isp, &mbs, MBLOGALL & ~(MBOX_LOOP_ID_USED | - MBOX_PORT_ID_USED | MBOX_COMMAND_ERROR)); - if (fcp->isp_fwstate != FW_READY || - fcp->isp_loopstate != LOOP_SYNCING_PDB) { - return (-1); + lp->new_roles = 0; + lp->new_portid = 0; + /* + * Note that we might come out of this with our state + * set to FC_PORTDB_STATE_ZOMBIE. + */ + break; + case FC_PORTDB_STATE_NEW: + /* + * It's up to the outer layers to assign a virtual + * target id in isp_ini_map (if any). + */ + lp->portid = lp->new_portid; + lp->roles = lp->new_roles; + lp->state = FC_PORTDB_STATE_VALID; + isp_async(isp, ISPASYNC_DEV_ARRIVED, lp); + lp->new_roles = 0; + lp->new_portid = 0; + lp->reserved = 0; + lp->new_reserved = 0; + break; + case FC_PORTDB_STATE_CHANGED: +/* + * XXXX FIX THIS + */ + lp->state = FC_PORTDB_STATE_VALID; + isp_async(isp, ISPASYNC_DEV_CHANGED, lp); + lp->new_roles = 0; + lp->new_portid = 0; + lp->reserved = 0; + lp->new_reserved = 0; + break; + case FC_PORTDB_STATE_PENDING_VALID: + lp->portid = lp->new_portid; + lp->roles = lp->new_roles; + if (lp->ini_map_idx) { + int t = lp->ini_map_idx - 1; + fcp->isp_ini_map[t] = dbidx + 1; } - switch (mbs.param[0]) { - case MBOX_LOOP_ID_USED: - /* - * Try the next available loop id. - */ - loopid++; - break; - case MBOX_PORT_ID_USED: - /* - * This port is already logged in. - * Snaffle the loop id it's using if it's - * nonzero, otherwise we're hosed. - */ - if (mbs.param[1] != 0) { - loopid = mbs.param[1]; - if (loopid >= MAX_FC_TARG) { - loopid = MAX_FC_TARG; - break; - } - isp_prt(isp, ISP_LOGINFO, retained, - loopid, (int) (lp - fcp->portdb), - lp->portid); - } else { - loopid = MAX_FC_TARG; - break; - } - /* FALLTHROUGH */ - case MBOX_COMMAND_COMPLETE: - lp->loggedin = 1; - lp->loopid = loopid; - break; - case MBOX_COMMAND_ERROR: - isp_prt(isp, ISP_LOGINFO, plogierr, - portid, mbs.param[1]); - /* FALLTHROUGH */ - case MBOX_ALL_IDS_USED: /* We're outta IDs */ - default: - loopid = MAX_FC_TARG; - break; + lp->state = FC_PORTDB_STATE_VALID; + isp_async(isp, ISPASYNC_DEV_STAYED, lp); + if (dbidx != FL_ID) { + lp->new_roles = 0; + lp->new_portid = 0; } - } while (lp->loopid == FL_PORT_ID && loopid < MAX_FC_TARG); - - /* - * If we get here and we haven't set a Loop ID, - * we failed to log into this device. - */ - - if (lp->loopid == FL_PORT_ID) { - lp->loopid = 0; - continue; - } - - /* - * Make sure we can get the approriate port information. - */ - if (isp_getpdb(isp, lp->loopid, &pdb) != 0) { - isp_prt(isp, ISP_LOGWARN, nopdb, lp->portid); - goto dump_em; - } - - if (fcp->isp_fwstate != FW_READY || - fcp->isp_loopstate != LOOP_SYNCING_PDB) { - return (-1); - } - - if (pdb.pdb_loopid != lp->loopid) { - isp_prt(isp, ISP_LOGWARN, pdbmfail1, - lp->portid, pdb.pdb_loopid); - goto dump_em; - } - - if (lp->portid != (uint32_t) BITS2WORD(pdb.pdb_portid_bits)) { - isp_prt(isp, ISP_LOGWARN, pdbmfail2, - lp->portid, BITS2WORD(pdb.pdb_portid_bits)); - goto dump_em; - } - - lp->roles = - (pdb.pdb_prli_svc3 & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT; - lp->node_wwn = - (((uint64_t)pdb.pdb_nodename[0]) << 56) | - (((uint64_t)pdb.pdb_nodename[1]) << 48) | - (((uint64_t)pdb.pdb_nodename[2]) << 40) | - (((uint64_t)pdb.pdb_nodename[3]) << 32) | - (((uint64_t)pdb.pdb_nodename[4]) << 24) | - (((uint64_t)pdb.pdb_nodename[5]) << 16) | - (((uint64_t)pdb.pdb_nodename[6]) << 8) | - (((uint64_t)pdb.pdb_nodename[7])); - lp->port_wwn = - (((uint64_t)pdb.pdb_portname[0]) << 56) | - (((uint64_t)pdb.pdb_portname[1]) << 48) | - (((uint64_t)pdb.pdb_portname[2]) << 40) | - (((uint64_t)pdb.pdb_portname[3]) << 32) | - (((uint64_t)pdb.pdb_portname[4]) << 24) | - (((uint64_t)pdb.pdb_portname[5]) << 16) | - (((uint64_t)pdb.pdb_portname[6]) << 8) | - (((uint64_t)pdb.pdb_portname[7])); - /* - * Check to make sure this all makes sense. - */ - if (lp->node_wwn && lp->port_wwn) { - lp->valid = 1; - loopid = lp - fcp->portdb; - (void) isp_async(isp, ISPASYNC_PROMENADE, &loopid); - continue; - } -dump_em: - lp->valid = 0; - isp_prt(isp, ISP_LOGINFO, - ldumped, loopid, lp->loopid, lp->portid); - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_FABRIC_LOGOUT; - if (IS_2KLOGIN(isp)) { - mbs.param[1] = lp->loopid; - mbs.ibits |= (1 << 10); - } else { - mbs.param[1] = lp->loopid << 8; - } - isp_mboxcmd(isp, &mbs, MBLOGNONE); - if (fcp->isp_fwstate != FW_READY || - fcp->isp_loopstate != LOOP_SYNCING_PDB) { - return (-1); + lp->reserved = 0; + lp->new_reserved = 0; + break; + case FC_PORTDB_STATE_ZOMBIE: + break; + default: + isp_prt(isp, ISP_LOGWARN, + "isp_scan_loop: state %d for idx %d", + lp->state, dbidx); + isp_dump_portdb(isp); } } + /* * If we get here, we've for sure seen not only a valid loop * but know what is or isn't on it, so mark this for usage @@ -2227,807 +2831,969 @@ dump_em: return (0); } +/* + * Scan local loop for devices. + */ static int isp_scan_loop(ispsoftc_t *isp) { - struct lportdb *lp; + fcportdb_t *lp, tmp; fcparam *fcp = isp->isp_param; + int i; isp_pdb_t pdb; - int loopid, lim, hival; + uint16_t handle, lim = 0; + if (fcp->isp_fwstate < FW_READY || + fcp->isp_loopstate < LOOP_PDB_RCVD) { + return (-1); + } + + if (fcp->isp_loopstate > LOOP_SCANNING_LOOP) { + return (0); + } + + /* + * Check our connection topology. + * + * If we're a public or private loop, we scan 0..125 as handle values. + * The firmware has (typically) peformed a PLOGI for us. + * + * If we're a N-port connection, we treat this is a short loop (0..1). + * + * If we're in target mode, we can all possible handles to see who + * might have logged into us. + */ switch (fcp->isp_topo) { case TOPO_NL_PORT: - hival = FL_PORT_ID; + case TOPO_FL_PORT: + lim = LOCAL_LOOP_LIM; break; case TOPO_N_PORT: - hival = 2; - break; - case TOPO_FL_PORT: - hival = FC_PORT_ID; + lim = 2; break; default: isp_prt(isp, ISP_LOGDEBUG0, "no loop topology to scan"); fcp->isp_loopstate = LOOP_LSCAN_DONE; return (0); } - fcp->isp_loopstate = LOOP_SCANNING_LOOP; - isp_prt(isp, ISP_LOGDEBUG0, "scanning local loop 0..%d", hival); + fcp->isp_loopstate = LOOP_SCANNING_LOOP; + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "FC scan loop 0..%d", lim-1); - /* - * make sure the temp port database is clean... - */ - MEMZERO((void *)fcp->tport, sizeof (fcp->tport)); /* - * Run through the local loop ports and get port database info - * for each loop ID. - * - * There's a somewhat unexplained situation where the f/w passes back - * the wrong database entity- if that happens, just restart (up to - * FL_PORT_ID times). + * Run through the list and get the port database info for each one. */ - for (lim = loopid = 0; loopid < hival; loopid++) { - lp = &fcp->tport[loopid]; - + for (handle = 0; handle < lim; handle++) { /* - * Don't even try for ourselves... + * But don't even try for ourselves... */ - if (loopid == fcp->isp_loopid) { + if (handle == fcp->isp_loopid) { continue; } + /* + * In older cards with older f/w GET_PORT_DATABASE has been + * known to hang. This trick gets around that problem. + */ if (IS_2100(isp) || IS_2200(isp)) { - lp->node_wwn = isp_get_portname(isp, loopid, 1); + uint64_t node_wwn = isp_get_portname(isp, handle, 1); if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) { return (-1); } - if (lp->node_wwn == 0) { + if (node_wwn == 0) { continue; } } /* - * Get an entry.... + * Get the port database entity for this index. */ - if (isp_getpdb(isp, loopid, &pdb) != 0) { + if (isp_getpdb(isp, handle, &pdb, 1) != 0) { if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) { + ISP_MARK_PORTDB(isp, 1); return (-1); } continue; } if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) { + ISP_MARK_PORTDB(isp, 1); return (-1); } /* - * If the returned database element doesn't match what we - * asked for, restart the process entirely (up to a point...). + * On *very* old 2100 firmware we would end up sometimes + * with the firmware returning the port database entry + * for something else. We used to restart this, but + * now we just punt. */ - if (pdb.pdb_loopid != loopid) { - loopid = 0; - if (lim++ < hival) { - continue; - } + if (IS_2100(isp) && pdb.handle != handle) { isp_prt(isp, ISP_LOGWARN, "giving up on synchronizing the port database"); + ISP_MARK_PORTDB(isp, 1); return (-1); } /* * Save the pertinent info locally. */ - lp->node_wwn = - (((uint64_t)pdb.pdb_nodename[0]) << 56) | - (((uint64_t)pdb.pdb_nodename[1]) << 48) | - (((uint64_t)pdb.pdb_nodename[2]) << 40) | - (((uint64_t)pdb.pdb_nodename[3]) << 32) | - (((uint64_t)pdb.pdb_nodename[4]) << 24) | - (((uint64_t)pdb.pdb_nodename[5]) << 16) | - (((uint64_t)pdb.pdb_nodename[6]) << 8) | - (((uint64_t)pdb.pdb_nodename[7])); - lp->port_wwn = - (((uint64_t)pdb.pdb_portname[0]) << 56) | - (((uint64_t)pdb.pdb_portname[1]) << 48) | - (((uint64_t)pdb.pdb_portname[2]) << 40) | - (((uint64_t)pdb.pdb_portname[3]) << 32) | - (((uint64_t)pdb.pdb_portname[4]) << 24) | - (((uint64_t)pdb.pdb_portname[5]) << 16) | - (((uint64_t)pdb.pdb_portname[6]) << 8) | - (((uint64_t)pdb.pdb_portname[7])); - lp->roles = - (pdb.pdb_prli_svc3 & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT; - lp->portid = BITS2WORD(pdb.pdb_portid_bits); - lp->loopid = pdb.pdb_loopid; - } - - /* - * Mark all of the permanent local loop database entries as invalid - * (except our own entry). - */ - for (loopid = 0; loopid < hival; loopid++) { - if (loopid == fcp->isp_iid) { - fcp->portdb[loopid].valid = 1; - fcp->portdb[loopid].loopid = fcp->isp_loopid; - continue; - } - fcp->portdb[loopid].valid = 0; - } - - /* - * Now merge our local copy of the port database into our saved copy. - * Notify the outer layers of new devices arriving. - */ - for (loopid = 0; loopid < hival; loopid++) { - int i; + MAKE_WWN_FROM_NODE_NAME(tmp.node_wwn, pdb.nodename); + MAKE_WWN_FROM_NODE_NAME(tmp.port_wwn, pdb.portname); + tmp.roles = (pdb.s3_role & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT; + tmp.portid = pdb.portid; + tmp.handle = pdb.handle; /* - * If we don't have a non-zero Port WWN, we're not here. + * Check to make sure it's still a valid entry. The 24XX seems + * to return a portid but not a WWPN/WWNN or role for devices + * which shift on a loop. */ - if (fcp->tport[loopid].port_wwn == 0) { - continue; - } - - /* - * Skip ourselves. - */ - if (loopid == fcp->isp_iid) { + if (tmp.node_wwn == 0 || tmp.port_wwn == 0 || tmp.portid == 0) { + int a, b, c; + a = (tmp.node_wwn == 0); + b = (tmp.port_wwn == 0); + c = (tmp.portid == 0); + isp_prt(isp, ISP_LOGWARN, + "bad pdb (%1d%1d%1d) @ handle 0x%x", a, b, c, + handle); + isp_dump_portdb(isp); continue; } /* - * For the purposes of deciding whether this is the - * 'same' device or not, we only search for an identical - * Port WWN. Node WWNs may or may not be the same as - * the Port WWN, and there may be multiple different - * Port WWNs with the same Node WWN. It would be chaos - * to have multiple identical Port WWNs, so we don't - * allow that. + * Now search the entire port database + * for the same Port and Node WWN. */ - - for (i = 0; i < hival; i++) { - int j; - if (fcp->portdb[i].port_wwn == 0) + for (i = 0; i < MAX_FC_TARG; i++) { + lp = &fcp->portdb[i]; + if (lp->state == FC_PORTDB_STATE_NIL) { continue; - if (fcp->portdb[i].port_wwn != - fcp->tport[loopid].port_wwn) + } + if (lp->node_wwn != tmp.node_wwn) { continue; + } + if (lp->port_wwn != tmp.port_wwn) { + continue; + } + /* - * We found this WWN elsewhere- it's changed - * loopids then. We don't change it's actual - * position in our cached port database- we - * just change the actual loop ID we'd use. + * Okay- we've found a non-nil entry that matches. + * Check to make sure it's probational or a zombie. */ - if (fcp->portdb[i].loopid != loopid) { - isp_prt(isp, ISP_LOGINFO, portshift, i, - fcp->portdb[i].loopid, - fcp->portdb[i].portid, loopid, - fcp->tport[loopid].portid); + if (lp->state != FC_PORTDB_STATE_PROBATIONAL && + lp->state != FC_PORTDB_STATE_ZOMBIE) { + isp_prt(isp, ISP_LOGERR, + "[%d] not probational/zombie (0x%x)", + i, lp->state); + isp_dump_portdb(isp); + ISP_MARK_PORTDB(isp, 1); + return (-1); } - fcp->portdb[i].portid = fcp->tport[loopid].portid; - fcp->portdb[i].loopid = loopid; - fcp->portdb[i].valid = 1; - fcp->portdb[i].roles = fcp->tport[loopid].roles; /* - * Now make sure this Port WWN doesn't exist elsewhere - * in the port database. + * Mark the device as something the f/w logs into + * automatically. */ - for (j = i+1; j < hival; j++) { - if (fcp->portdb[i].port_wwn != - fcp->portdb[j].port_wwn) { - continue; - } - isp_prt(isp, ISP_LOGWARN, portdup, j, i); - /* - * Invalidate the 'old' *and* 'new' ones. - * This is really harsh and not quite right, - * but if this happens, we really don't know - * who is what at this point. - */ - fcp->portdb[i].valid = 0; - fcp->portdb[j].valid = 0; + lp->autologin = 1; + + /* + * Check to make see if really still the same + * device. If it is, we mark it pending valid. + */ + if (lp->portid == tmp.portid && + lp->handle == tmp.handle && + lp->roles == tmp.roles) { + lp->new_portid = tmp.portid; + lp->new_roles = tmp.roles; + lp->state = FC_PORTDB_STATE_PENDING_VALID; + isp_prt(isp, ISP_LOGSANCFG, + "Loop Port 0x%02x@0x%x Pending Valid", + tmp.portid, tmp.handle); + break; } + + /* + * We can wipe out the old handle value + * here because it's no longer valid. + */ + lp->handle = tmp.handle; + + /* + * Claim that this has changed and let somebody else + * decide what to do. + */ + isp_prt(isp, ISP_LOGSANCFG, + "Loop Port 0x%02x@0x%x changed", + tmp.portid, tmp.handle); + lp->state = FC_PORTDB_STATE_CHANGED; + lp->new_portid = tmp.portid; + lp->new_roles = tmp.roles; break; } /* - * If we didn't traverse the entire port database, - * then we found (and remapped) an existing entry. - * No need to notify anyone- go for the next one. + * Did we find and update an old entry? */ - if (i < hival) { - isp_prt(isp, ISP_LOGINFO, retained, - fcp->portdb[i].loopid, i, fcp->portdb[i].portid); + if (i < MAX_FC_TARG) { continue; } /* - * We've not found this Port WWN anywhere. It's a new entry. - * See if we can leave it where it is (with target == loopid). + * Ah. A new device entry. Find an empty slot + * for it and save info for later disposition. */ - if (fcp->portdb[loopid].port_wwn != 0) { - for (lim = 0; lim < hival; lim++) { - if (fcp->portdb[lim].port_wwn == 0) - break; - } - /* "Cannot Happen" */ - if (lim == hival) { - isp_prt(isp, ISP_LOGWARN, "Remap Overflow"); - continue; + for (i = 0; i < MAX_FC_TARG; i++) { + if (fcp->portdb[i].state == FC_PORTDB_STATE_NIL) { + break; } - i = lim; - } else { - i = loopid; } - - /* - * NB: The actual loopid we use here is loopid- we may - * in fact be at a completely different index (target). - */ - fcp->portdb[i].loopid = loopid; - fcp->portdb[i].port_wwn = fcp->tport[loopid].port_wwn; - fcp->portdb[i].node_wwn = fcp->tport[loopid].node_wwn; - fcp->portdb[i].roles = fcp->tport[loopid].roles; - fcp->portdb[i].portid = fcp->tport[loopid].portid; - fcp->portdb[i].valid = 1; - - /* - * Tell the outside world we've arrived. - */ - (void) isp_async(isp, ISPASYNC_PROMENADE, &i); - } - - /* - * Now find all previously used targets that are now invalid and - * notify the outer layers that they're gone. - */ - for (lp = &fcp->portdb[0]; lp < &fcp->portdb[hival]; lp++) { - if (lp->valid || lp->port_wwn == 0) { + if (i == MAX_FC_TARG) { + isp_prt(isp, ISP_LOGERR, "out of portdb entries"); continue; } + lp = &fcp->portdb[i]; - /* - * Tell the outside world we've gone - * away and erase our pdb entry. - * - */ - loopid = lp - fcp->portdb; - (void) isp_async(isp, ISPASYNC_PROMENADE, &loopid); - MEMZERO((void *) lp, sizeof (*lp)); + MEMZERO(lp, sizeof (fcportdb_t)); + lp->autologin = 1; + lp->state = FC_PORTDB_STATE_NEW; + lp->new_portid = tmp.portid; + lp->new_roles = tmp.roles; + lp->handle = tmp.handle; + lp->port_wwn = tmp.port_wwn; + lp->node_wwn = tmp.node_wwn; + isp_prt(isp, ISP_LOGSANCFG, + "Loop Port 0x%02x@0x%x is New Entry", + tmp.portid, tmp.handle); } fcp->isp_loopstate = LOOP_LSCAN_DONE; return (0); } +/* + * Scan the fabric for devices and add them to our port database. + * + * Use the GID_FT command to get all Port IDs for FC4 SCSI devices it knows. + * + * For 2100-23XX cards, we can use the SNS mailbox command to pass simple + * name server commands to the switch management server via the QLogic f/w. + * + * For the 24XX card, we have to use CT-Pass through run via the Execute IOCB + * mailbox command. + * + * The net result is to leave the list of Port IDs setting untranslated in + * offset IGPOFF of the FC scratch area, whereupon we'll canonicalize it to + * host order at OGPOFF. + */ + +/* + * Take less than half of our scratch area to store Port IDs + */ +#define GIDLEN ((ISP2100_SCRLEN >> 1) - 16 - SNS_GID_FT_REQ_SIZE) +#define NGENT ((GIDLEN - 16) >> 2) + +#define IGPOFF (2 * QENTRY_LEN) +#define OGPOFF (ISP2100_SCRLEN >> 1) +#define ZTXOFF (ISP2100_SCRLEN - (1 * QENTRY_LEN)) +#define CTXOFF (ISP2100_SCRLEN - (2 * QENTRY_LEN)) +#define XTXOFF (ISP2100_SCRLEN - (3 * QENTRY_LEN)) static int -isp_fabric_mbox_cmd(ispsoftc_t *isp, mbreg_t *mbp) +isp_gid_ft_sns(ispsoftc_t *isp) { - /* the caller sets up the mailbox */ - 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); - } + union { + sns_gid_ft_req_t _x; + uint8_t _y[SNS_GID_FT_REQ_SIZE]; + } un; + fcparam *fcp = FCPARAM(isp); + sns_gid_ft_req_t *rq = &un._x; + mbreg_t mbs; - if (FCPARAM(isp)->isp_fwstate != FW_READY || - FCPARAM(isp)->isp_loopstate < LOOP_SCANNING_FABRIC) { - return (-1); + isp_prt(isp, ISP_LOGDEBUG0, "scanning fabric (GID_FT) via SNS"); + + MEMZERO(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 = FC4_SCSI; + + isp_put_gid_ft_request(isp, rq, fcp->isp_scratch); + MEMORYBARRIER(isp, SYNC_SFORDEV, 0, SNS_GID_FT_REQ_SIZE); + + MEMZERO(&mbs, sizeof (mbs)); + 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); + mbs.param[6] = DMA_WD3(fcp->isp_scdma); + mbs.param[7] = DMA_WD2(fcp->isp_scdma); + mbs.logval = MBLOGALL; + mbs.timeout = 10000000; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + if (mbs.param[0] == MBOX_INVALID_COMMAND) { + return (1); + } else { + return (-1); + } } - return(0); + return (0); } -#ifdef ISP_USE_GA_NXT static int -isp_scan_fabric(ispsoftc_t *isp, int ftype) +isp_gid_ft_ct_passthru(ispsoftc_t *isp) { - fcparam *fcp = isp->isp_param; - uint32_t portid, first_portid, last_portid; - int hicap, last_port_same; - - if (fcp->isp_onfabric == 0) { - fcp->isp_loopstate = LOOP_FSCAN_DONE; - return (0); - } + mbreg_t mbs; + fcparam *fcp = FCPARAM(isp); + union { + isp_ct_pt_t plocal; + ct_hdr_t clocal; + uint8_t q[QENTRY_LEN]; + } un; + isp_ct_pt_t *pt; + ct_hdr_t *ct; + uint32_t *rp; + uint8_t *scp = fcp->isp_scratch; - isp_prt(isp, ISP_LOGDEBUG0, "scanning fabric (GA_NXT)"); + isp_prt(isp, ISP_LOGDEBUG0, "scanning fabric (GID_FT) via CT"); - FC_SCRATCH_ACQUIRE(isp); + if (!IS_24XX(isp)) { + return (1); + } /* - * Since Port IDs are 24 bits, we can check against having seen - * anything yet with this value. + * Build a Passthrough IOCB in memory. */ - last_port_same = 0; - last_portid = 0xffffffff; /* not a port */ - first_portid = portid = fcp->isp_portid; - fcp->isp_loopstate = LOOP_SCANNING_FABRIC; - - for (hicap = 0; hicap < GA_NXT_MAX; hicap++) { - mbreg_t mbs; - sns_screq_t *rq; - sns_ga_nxt_rsp_t *rs0, *rs1; - struct lportdb lcl; - uint8_t sc[SNS_GA_NXT_RESP_SIZE]; + pt = &un.plocal; + MEMZERO(un.q, QENTRY_LEN); + pt->ctp_header.rqs_entry_count = 1; + pt->ctp_header.rqs_entry_type = RQSTYPE_CT_PASSTHRU; + pt->ctp_handle = 0xffffffff; + pt->ctp_nphdl = NPH_SNS_ID; + pt->ctp_cmd_cnt = 1; + pt->ctp_time = 30; + pt->ctp_rsp_cnt = 1; + pt->ctp_rsp_bcnt = GIDLEN; + pt->ctp_cmd_bcnt = sizeof (*ct) + sizeof (uint32_t); + pt->ctp_dataseg[0].ds_base = DMA_LO32(fcp->isp_scdma+XTXOFF); + pt->ctp_dataseg[0].ds_basehi = DMA_HI32(fcp->isp_scdma+XTXOFF); + pt->ctp_dataseg[0].ds_count = sizeof (*ct) + sizeof (uint32_t); + pt->ctp_dataseg[1].ds_base = DMA_LO32(fcp->isp_scdma+IGPOFF); + pt->ctp_dataseg[1].ds_basehi = DMA_HI32(fcp->isp_scdma+IGPOFF); + pt->ctp_dataseg[1].ds_count = GIDLEN; + if (isp->isp_dblev & ISP_LOGDEBUG1) { + isp_print_bytes(isp, "ct IOCB", QENTRY_LEN, pt); + } + isp_put_ct_pt(isp, pt, (isp_ct_pt_t *) &scp[CTXOFF]); - rq = (sns_screq_t *)sc; - 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_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_GA_NXT_REQ_SIZE); - MEMZERO(&mbs, sizeof (mbs)); - mbs.param[0] = MBOX_SEND_SNS; - 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); - /* - * 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); - } - MEMORYBARRIER(isp, SYNC_SFORCPU, 0x100, SNS_GA_NXT_RESP_SIZE); - rs1 = (sns_ga_nxt_rsp_t *) sc; - rs0 = (sns_ga_nxt_rsp_t *) ((uint8_t *)fcp->isp_scratch+0x100); - isp_get_ga_nxt_response(isp, rs0, rs1); - if (rs1->snscb_cthdr.ct_response != FS_ACC) { - int level; - if (rs1->snscb_cthdr.ct_reason == 9 && - rs1->snscb_cthdr.ct_explanation == 7) - level = ISP_LOGDEBUG0; - else - level = ISP_LOGWARN; - isp_prt(isp, level, 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); - } - portid = - (((uint32_t) rs1->snscb_port_id[0]) << 16) | - (((uint32_t) rs1->snscb_port_id[1]) << 8) | - (((uint32_t) rs1->snscb_port_id[2])); + /* + * Build the CT header and command in memory. + * + * Note that the CT header has to end up as Big Endian format in memory. + */ + ct = &un.clocal; + MEMZERO(ct, sizeof (*ct)); + ct->ct_revision = CT_REVISION; + ct->ct_fcs_type = CT_FC_TYPE_FC; + ct->ct_fcs_subtype = CT_FC_SUBTYPE_NS; + ct->ct_cmd_resp = SNS_GID_FT; + ct->ct_bcnt_resid = (GIDLEN - 16) >> 2; - /* - * XXX: We should check to make sure that this entry - * XXX: supports the type(s) we are interested in. - */ - /* - * 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 = - (((uint64_t)rs1->snscb_nodename[0]) << 56) | - (((uint64_t)rs1->snscb_nodename[1]) << 48) | - (((uint64_t)rs1->snscb_nodename[2]) << 40) | - (((uint64_t)rs1->snscb_nodename[3]) << 32) | - (((uint64_t)rs1->snscb_nodename[4]) << 24) | - (((uint64_t)rs1->snscb_nodename[5]) << 16) | - (((uint64_t)rs1->snscb_nodename[6]) << 8) | - (((uint64_t)rs1->snscb_nodename[7])); - lcl.port_wwn = - (((uint64_t)rs1->snscb_portname[0]) << 56) | - (((uint64_t)rs1->snscb_portname[1]) << 48) | - (((uint64_t)rs1->snscb_portname[2]) << 40) | - (((uint64_t)rs1->snscb_portname[3]) << 32) | - (((uint64_t)rs1->snscb_portname[4]) << 24) | - (((uint64_t)rs1->snscb_portname[5]) << 16) | - (((uint64_t)rs1->snscb_portname[6]) << 8) | - (((uint64_t)rs1->snscb_portname[7])); + isp_put_ct_hdr(isp, ct, (ct_hdr_t *) &scp[XTXOFF]); + rp = (uint32_t *) &scp[XTXOFF+sizeof (*ct)]; + ISP_IOZPUT_32(isp, FC4_SCSI, rp); + if (isp->isp_dblev & ISP_LOGDEBUG1) { + isp_print_bytes(isp, "CT HDR + payload after put", + sizeof (*ct) + sizeof (uint32_t), &scp[XTXOFF]); + } + MEMZERO(&scp[ZTXOFF], QENTRY_LEN); + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_EXEC_COMMAND_IOCB_A64; + mbs.param[1] = QENTRY_LEN; + mbs.param[2] = DMA_WD1(fcp->isp_scdma + CTXOFF); + mbs.param[3] = DMA_WD0(fcp->isp_scdma + CTXOFF); + mbs.param[6] = DMA_WD3(fcp->isp_scdma + CTXOFF); + mbs.param[7] = DMA_WD2(fcp->isp_scdma + CTXOFF); + mbs.timeout = 500000; + mbs.logval = MBLOGALL; + MEMORYBARRIER(isp, SYNC_SFORDEV, XTXOFF, 2 * QENTRY_LEN); + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + return (-1); + } + MEMORYBARRIER(isp, SYNC_SFORCPU, ZTXOFF, QENTRY_LEN); + pt = &un.plocal; + isp_get_ct_pt(isp, (isp_ct_pt_t *) &scp[ZTXOFF], pt); + if (isp->isp_dblev & ISP_LOGDEBUG1) { + isp_print_bytes(isp, "IOCB response", QENTRY_LEN, pt); + } - /* - * 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) { - if (last_port_same++ > 20) { - isp_prt(isp, ISP_LOGWARN, - "tangled fabric database detected"); - break; - } - } else { - last_port_same = 0 ; - last_portid = portid; - } + if (pt->ctp_status && pt->ctp_status != RQCS_DATA_UNDERRUN) { + isp_prt(isp, ISP_LOGWARN, "CT Passthrough returned 0x%x", + pt->ctp_status); + return (-1); } - FC_SCRATCH_RELEASE(isp); - if (hicap >= GA_NXT_MAX) { - isp_prt(isp, ISP_LOGWARN, "fabric too big (> %d)", GA_NXT_MAX); + MEMORYBARRIER(isp, SYNC_SFORCPU, IGPOFF, GIDLEN + 16); + if (isp->isp_dblev & ISP_LOGDEBUG1) { + isp_print_bytes(isp, "CT response", GIDLEN+16, &scp[IGPOFF]); } - fcp->isp_loopstate = LOOP_FSCAN_DONE; return (0); } -#else -#define GIDLEN ((ISP2100_SCRLEN >> 1) + 16) -#define NGENT ((GIDLEN - 16) >> 2) - -#define IGPOFF (ISP2100_SCRLEN - GIDLEN) -#define GXOFF (256) static int -isp_scan_fabric(ispsoftc_t *isp, int ftype) +isp_scan_fabric(ispsoftc_t *isp) { fcparam *fcp = FCPARAM(isp); - mbreg_t mbs; - int i; - sns_gid_ft_req_t *rq; + uint32_t portid; + uint16_t handle, oldhandle; + int portidx, portlim, r; sns_gid_ft_rsp_t *rs0, *rs1; - if (fcp->isp_onfabric == 0) { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "FC Scan Fabric"); + if (fcp->isp_fwstate != FW_READY || + fcp->isp_loopstate < LOOP_LSCAN_DONE) { + return (-1); + } + if (fcp->isp_loopstate > LOOP_SCANNING_FABRIC) { + return (0); + } + if (fcp->isp_topo != TOPO_FL_PORT && fcp->isp_topo != TOPO_F_PORT) { fcp->isp_loopstate = LOOP_FSCAN_DONE; + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "FC Scan Fabric Done (no fabric)"); return (0); } - isp_prt(isp, ISP_LOGDEBUG0, "scanning fabric (GID_FT)"); - 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); - MEMZERO(&mbs, sizeof (mbs)); - 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); + if (IS_24XX(isp)) { + r = isp_gid_ft_ct_passthru(isp); + } else { + r = isp_gid_ft_sns(isp); + } - /* - * 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; - } + if (r > 0) { + fcp->isp_loopstate = LOOP_FSCAN_DONE; FC_SCRATCH_RELEASE(isp); - return (-1); + return (0); + } else if (r < 0) { + fcp->isp_loopstate = LOOP_PDB_RCVD; /* try again */ + FC_SCRATCH_RELEASE(isp); + return (0); } 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 *) ((uint8_t *)fcp->isp_scratch+IGPOFF); + rs1 = (sns_gid_ft_rsp_t *) ((uint8_t *)fcp->isp_scratch+OGPOFF); isp_get_gid_ft_response(isp, rs0, rs1, NGENT); - if (rs1->snscb_cthdr.ct_response != FS_ACC) { + if (rs1->snscb_cthdr.ct_cmd_resp != LS_ACC) { int level; if (rs1->snscb_cthdr.ct_reason == 9 && - rs1->snscb_cthdr.ct_explanation == 7) - level = ISP_LOGDEBUG0; - else + rs1->snscb_cthdr.ct_explanation == 7) { + level = ISP_LOGSANCFG|ISP_LOGDEBUG0; + } else { level = ISP_LOGWARN; - isp_prt(isp, level, swrej, "GID_FT", - rs1->snscb_cthdr.ct_reason, - rs1->snscb_cthdr.ct_explanation, 0); + } + isp_prt(isp, level, "Fabric Nameserver rejected GID_FT " + "(Reason=0x%x Expl=0x%x)", rs1->snscb_cthdr.ct_reason, + rs1->snscb_cthdr.ct_explanation); FC_SCRATCH_RELEASE(isp); fcp->isp_loopstate = LOOP_FSCAN_DONE; return (0); } + + /* + * If we get this far, we certainly still have the fabric controller. + */ + fcp->portdb[FL_ID].state = FC_PORTDB_STATE_PENDING_VALID; + /* - * 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. + * Prime the handle we will start using. + */ + oldhandle = NIL_HANDLE; + + /* + * Okay, we now have a list of Port IDs for all FC4 SCSI devices + * that the Fabric Name server knows about. Go through the list + * and remove duplicate port ids. + */ + + portlim = 0; + portidx = 0; + for (portidx = 0; portidx < NGENT-1; portidx++) { + if (rs1->snscb_ports[portidx].control & 0x80) { + break; + } + } + + /* + * If we're not at the last entry, our list wasn't big enough. + */ + if ((rs1->snscb_ports[portidx].control & 0x80) == 0) { + isp_prt(isp, ISP_LOGWARN, + "fabric too big for scratch area: increase ISP2100_SCRLEN"); + } + portlim = portidx + 1; + isp_prt(isp, ISP_LOGSANCFG, + "got %d ports back from name server", portlim); + + for (portidx = 0; portidx < portlim; portidx++) { + int npidx; + + portid = + ((rs1->snscb_ports[portidx].portid[0]) << 16) | + ((rs1->snscb_ports[portidx].portid[1]) << 8) | + ((rs1->snscb_ports[portidx].portid[2])); + + for (npidx = portidx + 1; npidx < portlim; npidx++) { + uint32_t new_portid = + ((rs1->snscb_ports[npidx].portid[0]) << 16) | + ((rs1->snscb_ports[npidx].portid[1]) << 8) | + ((rs1->snscb_ports[npidx].portid[2])); + if (new_portid == portid) { + break; + } + } + + if (npidx < portlim) { + rs1->snscb_ports[npidx].portid[0] = 0; + rs1->snscb_ports[npidx].portid[1] = 0; + rs1->snscb_ports[npidx].portid[2] = 0; + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "removing duplicate PortID 0x%x entry from list", + portid); + } + } + + /* + * Okay, we now have a list of Port IDs for all FC4 SCSI devices + * that the Fabric Name server knows about. + * + * For each entry on this list go through our port database looking + * for probational entries- if we find one, then an old entry is + * is maybe still this one. We get some information to find out. * - * The lportdb structure is adequate for this. + * Otherwise, it's a new fabric device, and we log into it + * (unconditionally). After searching the entire database + * again to make sure that we never ever ever ever have more + * than one entry that has the same PortID or the same + * WWNN/WWPN duple, we enter the device into our database. */ - 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 = - (((uint32_t) rs1->snscb_ports[i].portid[0]) << 16) | - (((uint32_t) rs1->snscb_ports[i].portid[1]) << 8) | - (((uint32_t) rs1->snscb_ports[i].portid[2])); + for (portidx = 0; portidx < portlim; portidx++) { + fcportdb_t *lp; + isp_pdb_t pdb; + uint64_t wwnn, wwpn; + int dbidx, r, nr; + + portid = + ((rs1->snscb_ports[portidx].portid[0]) << 16) | + ((rs1->snscb_ports[portidx].portid[1]) << 8) | + ((rs1->snscb_ports[portidx].portid[2])); + + if (portid == 0) { + isp_prt(isp, ISP_LOGSANCFG, + "skipping null PortID at idx %d", portidx); + continue; + } - 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); - MEMZERO(&mbs, sizeof (mbs)); - 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 + * Skip ourselves... */ - 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 (portid == fcp->isp_portid) { + isp_prt(isp, ISP_LOGSANCFG, + "skip ourselves @ PortID 0x%06x", portid); + continue; } - if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { - FC_SCRATCH_RELEASE(isp); - return (-1); + isp_prt(isp, ISP_LOGSANCFG, + "Checking Fabric Port 0x%06x", portid); + + /* + * We now search our Port Database for any + * probational entries with this PortID. We don't + * look for zombies here- only probational + * entries (we've already logged out of zombies). + */ + for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { + lp = &fcp->portdb[dbidx]; + + if (lp->state != FC_PORTDB_STATE_PROBATIONAL) { + continue; + } + if (lp->portid == portid) { + break; + } } - MEMORYBARRIER(isp, SYNC_SFORCPU, GXOFF, SNS_GXN_ID_RESP_SIZE); - gs0 = (sns_gxn_id_rsp_t *) ((uint8_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); + + /* + * We found a probational entry with this Port ID. + */ + if (dbidx < MAX_FC_TARG) { + int handle_changed = 0; + + lp = &fcp->portdb[dbidx]; + + /* + * See if we're still logged into it. + * + * If we aren't, mark it as a dead device and + * leave the new portid in the database entry + * for somebody further along to decide what to + * do (policy choice). + * + * If we are, check to see if it's the same + * device still (it should be). If for some + * reason it isn't, mark it as a changed device + * and leave the new portid and role in the + * database entry for somebody further along to + * decide what to do (policy choice). + * + */ + + r = isp_getpdb(isp, lp->handle, &pdb, 0); if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { FC_SCRATCH_RELEASE(isp); + ISP_MARK_PORTDB(isp, 1); return (-1); } + if (r != 0) { + lp->new_portid = portid; + lp->state = FC_PORTDB_STATE_DEAD; + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Fabric Port 0x%06x considered dead", + portid); + continue; + } + + + /* + * Check to make sure that handle, portid, WWPN and + * WWNN agree. If they don't, then the association + * between this PortID and the stated handle has been + * broken by the firmware. + */ + MAKE_WWN_FROM_NODE_NAME(wwnn, pdb.nodename); + MAKE_WWN_FROM_NODE_NAME(wwpn, pdb.portname); + if (pdb.handle != lp->handle || + pdb.portid != portid || + wwpn != lp->port_wwn || + wwnn != lp->node_wwn) { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + fconf, dbidx, pdb.handle, pdb.portid, + (uint32_t) (wwnn >> 32), (uint32_t) wwnn, + (uint32_t) (wwpn >> 32), (uint32_t) wwpn, + lp->handle, portid, + (uint32_t) (lp->node_wwn >> 32), + (uint32_t) lp->node_wwn, + (uint32_t) (lp->port_wwn >> 32), + (uint32_t) lp->port_wwn); + /* + * Try to re-login to this device using a + * new handle. If that fails, mark it dead. + * + * isp_login_device will check for handle and + * portid consistency after re-login. + * + */ + if (isp_login_device(isp, portid, &pdb, + &oldhandle)) { + lp->new_portid = portid; + lp->state = FC_PORTDB_STATE_DEAD; + if (fcp->isp_loopstate != + LOOP_SCANNING_FABRIC) { + FC_SCRATCH_RELEASE(isp); + ISP_MARK_PORTDB(isp, 1); + return (-1); + } + continue; + } + MAKE_WWN_FROM_NODE_NAME(wwnn, pdb.nodename); + MAKE_WWN_FROM_NODE_NAME(wwpn, pdb.portname); + if (wwpn != lp->port_wwn || + wwnn != lp->node_wwn) { + isp_prt(isp, ISP_LOGWARN, "changed WWN" + " after relogin"); + lp->new_portid = portid; + lp->state = FC_PORTDB_STATE_DEAD; + continue; + } + + lp->handle = pdb.handle; + handle_changed++; + } + + nr = (pdb.s3_role & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT; + + /* + * Check to see whether the portid and roles have + * stayed the same. If they have stayed the same, + * we believe that this is the same device and it + * hasn't become disconnected and reconnected, so + * mark it as pending valid. + * + * If they aren't the same, mark the device as a + * changed device and save the new port id and role + * and let somebody else decide. + */ + + lp->new_portid = portid; + lp->new_roles = nr; + if (pdb.portid != lp->portid || nr != lp->roles || + handle_changed) { + isp_prt(isp, ISP_LOGSANCFG, + "Fabric Port 0x%06x changed", portid); + lp->state = FC_PORTDB_STATE_CHANGED; + } else { + isp_prt(isp, ISP_LOGSANCFG, + "Fabric Port 0x%06x Now Pending Valid", + portid); + lp->state = FC_PORTDB_STATE_PENDING_VALID; + } continue; } - lcl.port_wwn = - (((uint64_t)gs1->snscb_wwn[0]) << 56) | - (((uint64_t)gs1->snscb_wwn[1]) << 48) | - (((uint64_t)gs1->snscb_wwn[2]) << 40) | - (((uint64_t)gs1->snscb_wwn[3]) << 32) | - (((uint64_t)gs1->snscb_wwn[4]) << 24) | - (((uint64_t)gs1->snscb_wwn[5]) << 16) | - (((uint64_t)gs1->snscb_wwn[6]) << 8) | - (((uint64_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); - MEMZERO(&mbs, sizeof (mbs)); - 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 + * Ah- a new entry. Search the database again for all non-NIL + * entries to make sure we never ever make a new database entry + * with the same port id. While we're at it, mark where the + * last free entry was. */ - 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; + + dbidx = MAX_FC_TARG; + for (lp = fcp->portdb; lp < &fcp->portdb[MAX_FC_TARG]; lp++) { + if (lp >= &fcp->portdb[FL_ID] && + lp <= &fcp->portdb[SNS_ID]) { + continue; } - 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 *) ((uint8_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); + if (lp->state == FC_PORTDB_STATE_NIL) { + if (dbidx == MAX_FC_TARG) { + dbidx = lp - fcp->portdb; + } + continue; + } + if (lp->state == FC_PORTDB_STATE_ZOMBIE) { + continue; } + if (lp->portid == portid) { + break; + } + } + + if (lp < &fcp->portdb[MAX_FC_TARG]) { + isp_prt(isp, ISP_LOGWARN, + "PortID 0x%06x already at %d handle %d state %d", + portid, dbidx, lp->handle, lp->state); continue; } - lcl.node_wwn = - (((uint64_t)gs1->snscb_wwn[0]) << 56) | - (((uint64_t)gs1->snscb_wwn[1]) << 48) | - (((uint64_t)gs1->snscb_wwn[2]) << 40) | - (((uint64_t)gs1->snscb_wwn[3]) << 32) | - (((uint64_t)gs1->snscb_wwn[4]) << 24) | - (((uint64_t)gs1->snscb_wwn[5]) << 16) | - (((uint64_t)gs1->snscb_wwn[6]) << 8) | - (((uint64_t)gs1->snscb_wwn[7])); /* - * The QLogic f/w is bouncing this with a parameter error. + * We should have the index of the first free entry seen. */ -#if 0 + if (dbidx == MAX_FC_TARG) { + isp_prt(isp, ISP_LOGERR, + "port database too small to login PortID 0x%06x" + "- increase MAX_FC_TARG", portid); + continue; + } + /* - * Try and get FC4 Features (FC-GS-3 only). - * We can use the sns_gxn_id_req_t for this request. + * Otherwise, point to our new home. */ - 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); - MEMZERO(&mbs, sizeof (mbs)); - 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); + lp = &fcp->portdb[dbidx]; + /* - * Leave 4 and 5 alone + * Try to see if we are logged into this device, + * and maybe log into it. + * + * isp_login_device will check for handle and + * portid consistency after login. */ - 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 *) ((uint8_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 (isp_login_device(isp, portid, &pdb, &oldhandle)) { if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { FC_SCRATCH_RELEASE(isp); + ISP_MARK_PORTDB(isp, 1); 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); + continue; + } + + handle = pdb.handle; + MAKE_WWN_FROM_NODE_NAME(wwnn, pdb.nodename); + MAKE_WWN_FROM_NODE_NAME(wwpn, pdb.portname); + nr = (pdb.s3_role & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT; + + /* + * And go through the database *one* more time to make sure + * that we do not make more than one entry that has the same + * WWNN/WWPN duple + */ + for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { + if (dbidx >= FL_ID && dbidx <= SNS_ID) { + continue; } - if (fc4_fval & 0x2) { - lcl.roles |= - (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT); + if (fcp->portdb[dbidx].state == FC_PORTDB_STATE_NIL) { + continue; + } + if (fcp->portdb[dbidx].node_wwn == wwnn && + fcp->portdb[dbidx].port_wwn == wwpn) { + break; } } -#endif + + if (dbidx == MAX_FC_TARG) { + MEMZERO(lp, sizeof (fcportdb_t)); + lp->handle = handle; + lp->node_wwn = wwnn; + lp->port_wwn = wwpn; + lp->new_portid = portid; + lp->new_roles = nr; + lp->state = FC_PORTDB_STATE_NEW; + isp_prt(isp, ISP_LOGSANCFG, + "Fabric Port 0x%06x is New Entry", portid); + continue; + } + + if (fcp->portdb[dbidx].state != FC_PORTDB_STATE_ZOMBIE) { + isp_prt(isp, ISP_LOGWARN, + "PortID 0x%x 0x%08x%08x/0x%08x%08x %ld already at " + "idx %d, state 0x%x", portid, + (uint32_t) (wwnn >> 32), (uint32_t) wwnn, + (uint32_t) (wwpn >> 32), (uint32_t) wwpn, + (long) (lp - fcp->portdb), dbidx, + fcp->portdb[dbidx].state); + continue; + } /* - * 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; + * We found a zombie entry that matches us. + * Revive it. We know that WWN and WWPN + * are the same. For fabric devices, we + * don't care that handle is different + * as we assign that. If role or portid + * are different, it maybe a changed device. */ - if (rs1->snscb_ports[i].control & 0x80) { - lcl.last_fabric_dev = 1; + lp = &fcp->portdb[dbidx]; + lp->handle = handle; + lp->new_portid = portid; + lp->new_roles = nr; + if (lp->portid != portid || lp->roles != nr) { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Zombie Fabric Port 0x%06x Now Changed", portid); + lp->state = FC_PORTDB_STATE_CHANGED; } else { - lcl.last_fabric_dev = 0; + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Zombie Fabric Port 0x%06x Now Pending Valid", + portid); + lp->state = FC_PORTDB_STATE_PENDING_VALID; } - (void) isp_async(isp, ISPASYNC_FABRIC_DEV, &lcl); + } + + FC_SCRATCH_RELEASE(isp); + if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) { + ISP_MARK_PORTDB(isp, 1); + return (-1); + } + fcp->isp_loopstate = LOOP_FSCAN_DONE; + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "FC Scan Fabric Done"); + return (0); +} - } while ((rs1->snscb_ports[i].control & 0x80) == 0 && i < NGENT-1); +/* + * Find an unused handle and try and use to login to a port. + */ +static int +isp_login_device(ispsoftc_t *isp, uint32_t portid, isp_pdb_t *p, uint16_t *ohp) +{ + int lim, i, r; + uint16_t handle; + + if (FCPARAM(isp)->isp_2klogin) { + lim = NPH_MAX_2K; + } else { + lim = NPH_MAX; + } + + handle = isp_nxt_handle(isp, *ohp); + for (i = 0; i < lim; i++) { + /* + * See if we're still logged into something with + * this handle and that something agrees with this + * port id. + */ + r = isp_getpdb(isp, handle, p, 0); + if (r == 0 && p->portid != portid) { + (void) isp_plogx(isp, handle, portid, + PLOGX_FLG_CMD_LOGO | PLOGX_FLG_IMPLICIT, 1); + } else if (r == 0) { + break; + } + if (FCPARAM(isp)->isp_loopstate != LOOP_SCANNING_FABRIC) { + return (-1); + } + /* + * Now try and log into the device + */ + r = isp_plogx(isp, handle, portid, PLOGX_FLG_CMD_PLOGI, 1); + if (FCPARAM(isp)->isp_loopstate != LOOP_SCANNING_FABRIC) { + return (-1); + } + if (r == 0) { + *ohp = handle; + break; + } else if ((r & 0xffff) == MBOX_PORT_ID_USED) { + handle = r >> 16; + break; + } else if (r != MBOX_LOOP_ID_USED) { + i = lim; + break; + } else { + *ohp = handle; + handle = isp_nxt_handle(isp, *ohp); + } + } + + if (i == lim) { + isp_prt(isp, ISP_LOGWARN, "PLOGI 0x%06x failed", portid); + return (-1); + } /* - * If we're not at the last entry, our list isn't big enough. + * If we successfully logged into it, get the PDB for it + * so we can crosscheck that it is still what we think it + * is and that we also have the role it plays */ - if ((rs1->snscb_ports[i].control & 0x80) == 0) { - isp_prt(isp, ISP_LOGWARN, "fabric too big for scratch area"); + r = isp_getpdb(isp, handle, p, 0); + if (FCPARAM(isp)->isp_loopstate != LOOP_SCANNING_FABRIC) { + return (-1); + } + if (r != 0) { + isp_prt(isp, ISP_LOGERR, "new device 0x%06x@0x%x disappeared", + portid, handle); + return (-1); } - FC_SCRATCH_RELEASE(isp); - fcp->isp_loopstate = LOOP_FSCAN_DONE; + if (p->handle != handle || p->portid != portid) { + isp_prt(isp, ISP_LOGERR, + "new device 0x%06x@0x%x changed (0x%06x@0x%0x)", + portid, handle, p->portid, p->handle); + return (-1); + } return (0); } -#endif -static void +static int isp_register_fc4_type(ispsoftc_t *isp) { fcparam *fcp = isp->isp_param; @@ -3046,9 +3812,6 @@ isp_register_fc4_type(ispsoftc_t *isp) reqp->snscb_data[4] = fcp->isp_portid & 0xffff; reqp->snscb_data[5] = (fcp->isp_portid >> 16) & 0xff; reqp->snscb_data[6] = (1 << FC4_SCSI); -#if 0 - 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); MEMZERO(&mbs, sizeof (mbs)); @@ -3056,19 +3819,167 @@ isp_register_fc4_type(ispsoftc_t *isp) 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); - /* - * Leave 4 and 5 alone - */ mbs.param[6] = DMA_WD3(fcp->isp_scdma); mbs.param[7] = DMA_WD2(fcp->isp_scdma); + mbs.logval = MBLOGALL; + mbs.timeout = 10000000; MEMORYBARRIER(isp, SYNC_SFORDEV, 0, SNS_RFT_ID_REQ_SIZE); - isp_mboxcmd(isp, &mbs, MBLOGALL); + isp_mboxcmd(isp, &mbs); FC_SCRATCH_RELEASE(isp); if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGDEBUG0, "Register FC4 types succeeded"); + return (0); + } else { + return (-1); + } +} + +static int +isp_register_fc4_type_24xx(ispsoftc_t *isp) +{ + mbreg_t mbs; + fcparam *fcp = FCPARAM(isp); + union { + isp_ct_pt_t plocal; + rft_id_t clocal; + uint8_t q[QENTRY_LEN]; + } un; + isp_ct_pt_t *pt; + ct_hdr_t *ct; + rft_id_t *rp; + uint8_t *scp = fcp->isp_scratch; + + FC_SCRATCH_ACQUIRE(isp); + /* + * Build a Passthrough IOCB in memory. + */ + MEMZERO(un.q, QENTRY_LEN); + pt = &un.plocal; + pt->ctp_header.rqs_entry_count = 1; + pt->ctp_header.rqs_entry_type = RQSTYPE_CT_PASSTHRU; + pt->ctp_handle = 0xffffffff; + pt->ctp_nphdl = NPH_SNS_ID; + pt->ctp_cmd_cnt = 1; + pt->ctp_time = 1; + pt->ctp_rsp_cnt = 1; + pt->ctp_rsp_bcnt = sizeof (ct_hdr_t); + pt->ctp_cmd_bcnt = sizeof (rft_id_t); + pt->ctp_dataseg[0].ds_base = DMA_LO32(fcp->isp_scdma+XTXOFF); + pt->ctp_dataseg[0].ds_basehi = DMA_HI32(fcp->isp_scdma+XTXOFF); + pt->ctp_dataseg[0].ds_count = sizeof (rft_id_t); + pt->ctp_dataseg[1].ds_base = DMA_LO32(fcp->isp_scdma+IGPOFF); + pt->ctp_dataseg[1].ds_basehi = DMA_HI32(fcp->isp_scdma+IGPOFF); + pt->ctp_dataseg[1].ds_count = sizeof (ct_hdr_t); + isp_put_ct_pt(isp, pt, (isp_ct_pt_t *) &scp[CTXOFF]); + + /* + * Build the CT header and command in memory. + * + * Note that the CT header has to end up as Big Endian format in memory. + */ + MEMZERO(&un.clocal, sizeof (un.clocal)); + ct = &un.clocal.rftid_hdr; + ct->ct_revision = CT_REVISION; + ct->ct_fcs_type = CT_FC_TYPE_FC; + ct->ct_fcs_subtype = CT_FC_SUBTYPE_NS; + ct->ct_cmd_resp = SNS_RFT_ID; + ct->ct_bcnt_resid = (sizeof (rft_id_t) - sizeof (ct_hdr_t)) >> 2; + rp = &un.clocal; + rp->rftid_portid[0] = fcp->isp_portid >> 16; + rp->rftid_portid[1] = fcp->isp_portid >> 8; + rp->rftid_portid[2] = fcp->isp_portid; + rp->rftid_fc4types[FC4_SCSI >> 5] = 1 << (FC4_SCSI & 0x1f); + isp_put_rft_id(isp, rp, (rft_id_t *) &scp[XTXOFF]); + + MEMZERO(&scp[ZTXOFF], sizeof (ct_hdr_t)); + + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_EXEC_COMMAND_IOCB_A64; + mbs.param[1] = QENTRY_LEN; + mbs.param[2] = DMA_WD1(fcp->isp_scdma + CTXOFF); + mbs.param[3] = DMA_WD0(fcp->isp_scdma + CTXOFF); + mbs.param[6] = DMA_WD3(fcp->isp_scdma + CTXOFF); + mbs.param[7] = DMA_WD2(fcp->isp_scdma + CTXOFF); + mbs.timeout = 500000; + mbs.logval = MBLOGALL; + MEMORYBARRIER(isp, SYNC_SFORDEV, XTXOFF, 2 * QENTRY_LEN); + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + FC_SCRATCH_RELEASE(isp); + return (-1); + } + MEMORYBARRIER(isp, SYNC_SFORCPU, ZTXOFF, QENTRY_LEN); + pt = &un.plocal; + isp_get_ct_pt(isp, (isp_ct_pt_t *) &scp[ZTXOFF], pt); + if (isp->isp_dblev & ISP_LOGDEBUG1) { + isp_print_bytes(isp, "IOCB response", QENTRY_LEN, pt); + } + if (pt->ctp_status) { + FC_SCRATCH_RELEASE(isp); + isp_prt(isp, ISP_LOGWARN, "CT Passthrough returned 0x%x", + pt->ctp_status); + return (-1); + } + + isp_get_ct_hdr(isp, (ct_hdr_t *) &scp[IGPOFF], ct); + FC_SCRATCH_RELEASE(isp); + + if (ct->ct_cmd_resp == LS_RJT) { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Register FC4 Type rejected"); + return (-1); + } else if (ct->ct_cmd_resp == LS_ACC) { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, + "Register FC4 Type accepted"); + return(0); + } else { + isp_prt(isp, ISP_LOGWARN, + "Register FC4 Type: 0x%x", ct->ct_cmd_resp); + return (-1); } } +static uint16_t +isp_nxt_handle(ispsoftc_t *isp, uint16_t handle) +{ + int i; + if (handle == NIL_HANDLE) { + if (FCPARAM(isp)->isp_topo == TOPO_F_PORT) { + handle = 0; + } else { + handle = SNS_ID+1; + } + } else { + handle += 1; + if (handle >= FL_ID && handle <= SNS_ID) { + handle = SNS_ID+1; + } + if (handle >= NPH_RESERVED && handle <= NPH_FL_ID) { + handle = NPH_FL_ID+1; + } + if (FCPARAM(isp)->isp_2klogin) { + if (handle == NPH_MAX_2K) { + handle = 0; + } + } else { + if (handle == NPH_MAX) { + handle = 0; + } + } + } + if (handle == FCPARAM(isp)->isp_loopid) { + return (isp_nxt_handle(isp, handle)); + } + for (i = 0; i < MAX_FC_TARG; i++) { + if (FCPARAM(isp)->portdb[i].state == FC_PORTDB_STATE_NIL) { + continue; + } + if (FCPARAM(isp)->portdb[i].handle == handle) { + return (isp_nxt_handle(isp, handle)); + } + } + return (handle); +} + /* * Start a command. Locking is assumed done in the caller. */ @@ -3077,10 +3988,13 @@ int isp_start(XS_T *xs) { ispsoftc_t *isp; - uint16_t nxti, optr, handle; + uint32_t nxti, optr, handle, isr; + uint16_t sema, mbox; uint8_t local[QENTRY_LEN]; ispreq_t *reqp, *qep; - int target, i; + void *cdbp; + uint16_t *tptr; + int target, i, hdlidx = 0; XS_INITERR(xs); isp = XS_ISP(xs); @@ -3119,198 +4033,52 @@ isp_start(XS_T *xs) } /* - * Check to see whether we have good firmware state still or - * need to refresh our port database for this target. + * Translate the target to device handle as appropriate, checking + * for correct device state as well. */ target = XS_TGT(xs); if (IS_FC(isp)) { fcparam *fcp = isp->isp_param; - struct lportdb *lp; -#ifdef HANDLE_LOOPSTATE_IN_OUTER_LAYERS - if (fcp->isp_fwstate != FW_READY || - fcp->isp_loopstate != LOOP_READY) { - return (CMD_RQLATER); - } - - /* - * If we're not on a Fabric, we can't have a target - * above FL_PORT_ID-1. - * - * If we're on a fabric and *not* connected as an F-port, - * we can't have a target less than FC_SNS_ID+1. This - * keeps us from having to sort out the difference between - * local public loop devices and those which we might get - * from a switch's database. - */ - if (fcp->isp_onfabric == 0) { - if (target >= FL_PORT_ID) { - XS_SETERR(xs, HBA_SELTIMEOUT); - return (CMD_COMPLETE); - } - } else { - if (target >= FL_PORT_ID && target <= FC_SNS_ID) { - XS_SETERR(xs, HBA_SELTIMEOUT); - return (CMD_COMPLETE); - } - /* - * We used to exclude having local loop ports - * at the same time that we have fabric ports. - * That is, we used to exclude having ports - * at < FL_PORT_ID if we're FL-port. - * - * That's wrong. The only thing that could be - * dicey is if the switch you're connected to - * has these local loop ports appear on the - * fabric and we somehow attach them twice. - */ - } -#else - /* - * Check for f/w being in ready state. If the f/w - * isn't in ready state, then we don't know our - * loop ID and the f/w hasn't completed logging - * into all targets on the loop. If this is the - * case, then bounce the command. We pretend this is - * a SELECTION TIMEOUT error if we've never gone to - * FW_READY state at all- in this case we may not - * be hooked to a loop at all and we shouldn't hang - * the machine for this. Otherwise, defer this command - * until later. - */ - if (fcp->isp_fwstate != FW_READY) { - /* - * Give ourselves at most a 250ms delay. - */ - if (isp_fclink_test(isp, 250000)) { - XS_SETERR(xs, HBA_SELTIMEOUT); - if (fcp->loop_seen_once) { - return (CMD_RQLATER); - } else { - return (CMD_COMPLETE); - } - } - } /* - * If we're not on a Fabric, we can't have a target - * above FL_PORT_ID-1. - * - * If we're on a fabric and *not* connected as an F-port, - * we can't have a target less than FC_SNS_ID+1. This - * keeps us from having to sort out the difference between - * local public loop devices and those which we might get - * from a switch's database. + * Try again later. */ - if (fcp->isp_onfabric == 0) { - if (target >= FL_PORT_ID) { - XS_SETERR(xs, HBA_SELTIMEOUT); - return (CMD_COMPLETE); - } - } else { - if (target >= FL_PORT_ID && target <= FC_SNS_ID) { - XS_SETERR(xs, HBA_SELTIMEOUT); - return (CMD_COMPLETE); - } - if (fcp->isp_topo != TOPO_F_PORT && - target < FL_PORT_ID) { - XS_SETERR(xs, HBA_SELTIMEOUT); - return (CMD_COMPLETE); - } - } - - /* - * If our loop state is such that we haven't yet received - * a "Port Database Changed" notification (after a LIP or - * a Loop Reset or firmware initialization), then defer - * sending commands for a little while, but only if we've - * seen a valid loop at one point (otherwise we can get - * stuck at initialization time). - */ - if (fcp->isp_loopstate < LOOP_PDB_RCVD) { - XS_SETERR(xs, HBA_SELTIMEOUT); - if (fcp->loop_seen_once) { - return (CMD_RQLATER); - } else { - return (CMD_COMPLETE); - } - } - - /* - * If we're in the middle of loop or fabric scanning - * or merging the port databases, retry this command later. - */ - if (fcp->isp_loopstate == LOOP_SCANNING_FABRIC || - fcp->isp_loopstate == LOOP_SCANNING_LOOP || - fcp->isp_loopstate == LOOP_SYNCING_PDB) { + if (fcp->isp_fwstate != FW_READY || + fcp->isp_loopstate != LOOP_READY) { return (CMD_RQLATER); } - /* - * If our loop state is now such that we've just now - * received a Port Database Change notification, then - * we have to go off and (re)scan the fabric. We back - * out and try again later if this doesn't work. - */ - if (fcp->isp_loopstate == LOOP_PDB_RCVD && fcp->isp_onfabric) { - if (isp_scan_fabric(isp, FC4_SCSI)) { - return (CMD_RQLATER); - } - if (fcp->isp_fwstate != FW_READY || - fcp->isp_loopstate < LOOP_FSCAN_DONE) { - return (CMD_RQLATER); - } - } - - /* - * If our loop state is now such that we've just now - * received a Port Database Change notification, then - * we have to go off and (re)synchronize our port - * database. - */ - if (fcp->isp_loopstate < LOOP_READY) { - if (isp_pdb_sync(isp)) { - return (CMD_RQLATER); - } - if (fcp->isp_fwstate != FW_READY || - fcp->isp_loopstate != LOOP_READY) { - return (CMD_RQLATER); - } + if (XS_TGT(xs) >= MAX_FC_TARG) { + XS_SETERR(xs, HBA_SELTIMEOUT); + return (CMD_COMPLETE); } - /* - * XXX: Here's were we would cancel any loop_dead flag - * XXX: also cancel in dead_loop timeout that's running - */ -#endif - - /* - * Now check whether we should even think about pursuing this. - */ - lp = &fcp->portdb[target]; - if (lp->valid == 0) { + hdlidx = fcp->isp_ini_map[XS_TGT(xs)] - 1; + isp_prt(isp, ISP_LOGDEBUG1, "XS_TGT(xs)=%d- handle value %d", + XS_TGT(xs), hdlidx); + if (hdlidx < 0 || hdlidx >= MAX_FC_TARG) { XS_SETERR(xs, HBA_SELTIMEOUT); return (CMD_COMPLETE); } - if ((lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT)) == 0) { - isp_prt(isp, ISP_LOGDEBUG2, - "Target %d does not have target service", target); + if (fcp->portdb[hdlidx].state == FC_PORTDB_STATE_ZOMBIE) { + return (CMD_RQLATER); + } + if (fcp->portdb[hdlidx].state != FC_PORTDB_STATE_VALID) { XS_SETERR(xs, HBA_SELTIMEOUT); return (CMD_COMPLETE); } - /* - * Now turn target into what the actual Loop ID is. - */ - target = lp->loopid; + target = fcp->portdb[hdlidx].handle; } /* - * Next check to see if any HBA or Device - * parameters need to be updated. + * Next check to see if any HBA or Device parameters need to be updated. */ if (isp->isp_update != 0) { isp_update(isp); } + start_again: + if (isp_getrqentry(isp, &nxti, &optr, (void *)&qep)) { isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow"); XS_SETERR(xs, HBA_BOTCH); @@ -3324,34 +4092,40 @@ isp_start(XS_T *xs) */ reqp = (ispreq_t *) local; if (isp->isp_sendmarker) { - uint8_t n = (IS_DUALBUS(isp)? 2: 1); - /* - * Check ports to send markers for... - */ - for (i = 0; i < n; i++) { - if ((isp->isp_sendmarker & (1 << i)) == 0) { - continue; - } - MEMZERO((void *) reqp, QENTRY_LEN); - reqp->req_header.rqs_entry_count = 1; - reqp->req_header.rqs_entry_type = RQSTYPE_MARKER; - reqp->req_modifier = SYNC_ALL; - reqp->req_target = i << 7; /* insert bus number */ - isp_put_request(isp, reqp, qep); + if (IS_24XX(isp)) { + isp_marker_24xx_t *m = (isp_marker_24xx_t *) qep; + MEMZERO(m, QENTRY_LEN); + m->mrk_header.rqs_entry_count = 1; + m->mrk_header.rqs_entry_type = RQSTYPE_MARKER; + m->mrk_modifier = SYNC_ALL; + isp_put_marker_24xx(isp, m, (isp_marker_24xx_t *)qep); ISP_ADD_REQUEST(isp, nxti); - isp->isp_sendmarker &= ~(1 << i); - if (isp_getrqentry(isp, &nxti, &optr, (void *) &qep)) { - isp_prt(isp, ISP_LOGDEBUG0, - "Request Queue Overflow+"); - XS_SETERR(xs, HBA_BOTCH); - return (CMD_EAGAIN); + isp->isp_sendmarker = 0; + goto start_again; + } else { + for (i = 0; i < (IS_DUALBUS(isp)? 2: 1); i++) { + isp_marker_t *m = (isp_marker_t *) qep; + if ((isp->isp_sendmarker & (1 << i)) == 0) { + continue; + } + MEMZERO(m, QENTRY_LEN); + m->mrk_header.rqs_entry_count = 1; + m->mrk_header.rqs_entry_type = RQSTYPE_MARKER; + m->mrk_target = (i << 7); /* bus # */ + m->mrk_modifier = SYNC_ALL; + isp_put_marker(isp, m, (isp_marker_t *) qep); + ISP_ADD_REQUEST(isp, nxti); + isp->isp_sendmarker &= ~(1 << i); + goto start_again; } } } MEMZERO((void *)reqp, QENTRY_LEN); reqp->req_header.rqs_entry_count = 1; - if (IS_FC(isp)) { + if (IS_24XX(isp)) { + reqp->req_header.rqs_entry_type = RQSTYPE_T7RQS; + } else if (IS_FC(isp)) { reqp->req_header.rqs_entry_type = RQSTYPE_T2RQS; } else { if (XS_CDBLEN(xs) > 12) @@ -3361,7 +4135,26 @@ isp_start(XS_T *xs) } /* reqp->req_header.rqs_flags = 0; */ /* reqp->req_header.rqs_seqno = 0; */ - if (IS_FC(isp)) { + if (IS_24XX(isp)) { + int ttype; + if (XS_TAG_P(xs)) { + ttype = XS_TAG_TYPE(xs); + } else { + if (XS_CDBP(xs)[0] == 0x3) { + ttype = REQFLAG_HTAG; + } else { + ttype = REQFLAG_STAG; + } + } + if (ttype == REQFLAG_OTAG) { + ttype = FCP_CMND_TASK_ATTR_ORDERED; + } else if (ttype == REQFLAG_HTAG) { + ttype = FCP_CMND_TASK_ATTR_HEAD; + } else { + ttype = FCP_CMND_TASK_ATTR_SIMPLE; + } + ((ispreqt7_t *)reqp)->req_task_attribute = ttype; + } else if (IS_FC(isp)) { /* * See comment in isp_intr */ @@ -3392,25 +4185,45 @@ isp_start(XS_T *xs) reqp->req_flags = XS_TAG_TYPE(xs); } } + cdbp = reqp->req_cdb; + tptr = &reqp->req_time; + if (IS_SCSI(isp)) { reqp->req_target = target | (XS_CHANNEL(xs) << 7); reqp->req_lun_trn = XS_LUN(xs); reqp->req_cdblen = XS_CDBLEN(xs); - } else if (IS_2KLOGIN(isp)) { + } else if (IS_24XX(isp)) { + fcportdb_t *lp; + + lp = &FCPARAM(isp)->portdb[hdlidx]; + ((ispreqt7_t *)reqp)->req_nphdl = target; + ((ispreqt7_t *)reqp)->req_tidlo = lp->portid; + ((ispreqt7_t *)reqp)->req_tidhi = lp->portid >> 16; + if (XS_LUN(xs) > 256) { + ((ispreqt7_t *)reqp)->req_lun[0] = XS_LUN(xs) >> 8; + ((ispreqt7_t *)reqp)->req_lun[0] |= 0x40; + } + ((ispreqt7_t *)reqp)->req_lun[1] = XS_LUN(xs); + cdbp = ((ispreqt7_t *)reqp)->req_cdb; + tptr = &((ispreqt7_t *)reqp)->req_time; + } else if (FCPARAM(isp)->isp_2klogin) { ((ispreqt2e_t *)reqp)->req_target = target; ((ispreqt2e_t *)reqp)->req_scclun = XS_LUN(xs); - } else if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) { + } else if (FCPARAM(isp)->isp_sccfw) { ((ispreqt2_t *)reqp)->req_target = target; ((ispreqt2_t *)reqp)->req_scclun = XS_LUN(xs); } else { ((ispreqt2_t *)reqp)->req_target = target; ((ispreqt2_t *)reqp)->req_lun_trn = XS_LUN(xs); } - MEMCPY(reqp->req_cdb, XS_CDBP(xs), XS_CDBLEN(xs)); + MEMCPY(cdbp, XS_CDBP(xs), XS_CDBLEN(xs)); - reqp->req_time = XS_TIME(xs) / 1000; - if (reqp->req_time == 0 && XS_TIME(xs)) { - reqp->req_time = 1; + *tptr = XS_TIME(xs) / 1000; + if (*tptr == 0 && XS_TIME(xs)) { + *tptr = 1; + } + if (IS_24XX(isp) && *tptr > 0x1999) { + *tptr = 0x1999; } if (isp_save_xs(isp, xs, &handle)) { @@ -3418,6 +4231,7 @@ isp_start(XS_T *xs) XS_SETERR(xs, HBA_BOTCH); return (CMD_EAGAIN); } + /* Whew. Thankfully the same for type 7 requests */ reqp->req_handle = handle; /* @@ -3440,6 +4254,11 @@ isp_start(XS_T *xs) (long) XS_XFRLEN(xs)); ISP_ADD_REQUEST(isp, nxti); isp->isp_nactive++; + if (IS_23XX(isp) || IS_24XX(isp)) { + if (ISP_READ_ISR(isp, &isr, &sema, &mbox)) { + isp_intr(isp, isr, sema, mbox); + } + } return (CMD_QUEUED); } @@ -3454,7 +4273,7 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, void *arg) XS_T *xs; mbreg_t mbs; int bus, tgt; - uint16_t handle; + uint32_t handle; MEMZERO(&mbs, sizeof (mbs)); @@ -3467,10 +4286,14 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, void *arg) /* * Issue a bus reset. */ - mbs.param[0] = MBOX_BUS_RESET; - if (IS_SCSI(isp)) { - mbs.param[1] = - ((sdparam *) isp->isp_param)->isp_bus_reset_delay; + if (IS_24XX(isp)) { + isp_prt(isp, ISP_LOGWARN, "RESET BUS NOT IMPLETENTED"); + break; + } else if (IS_FC(isp)) { + mbs.param[1] = 10; + bus = 0; + } else { + mbs.param[1] = SDPARAM(isp)->isp_bus_reset_delay; if (mbs.param[1] < 2) { mbs.param[1] = 2; } @@ -3478,12 +4301,11 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, void *arg) if (IS_DUALBUS(isp)) { mbs.param[2] = bus; } - } else { - mbs.param[1] = 10; - bus = 0; } + mbs.param[0] = MBOX_BUS_RESET; isp->isp_sendmarker |= (1 << bus); - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { break; } @@ -3493,20 +4315,25 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, void *arg) case ISPCTL_RESET_DEV: tgt = (*((int *) arg)) & 0xffff; - bus = (*((int *) arg)) >> 16; - mbs.param[0] = MBOX_ABORT_TARGET; - if (IS_SCSI(isp)) { - mbs.param[1] = (tgt << 8) | (bus << 15); - } else { - if (IS_2KLOGIN(isp)) { + if (IS_24XX(isp)) { + isp_prt(isp, ISP_LOGWARN, "RESET DEV NOT IMPLETENTED"); + break; + } else if (IS_FC(isp)) { + if (FCPARAM(isp)->isp_2klogin) { mbs.param[1] = tgt; - mbs.ibits |= (1 << 10); + mbs.ibits = (1 << 10); } else { mbs.param[1] = (tgt << 8); } + bus = 0; + } else { + bus = (*((int *) arg)) >> 16; + mbs.param[1] = (bus << 15) | (tgt << 8); } + mbs.param[0] = MBOX_ABORT_TARGET; mbs.param[2] = 3; /* 'delay', in seconds */ - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { break; } @@ -3518,17 +4345,19 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, void *arg) case ISPCTL_ABORT_CMD: xs = (XS_T *) arg; tgt = XS_TGT(xs); + handle = isp_find_handle(isp, xs); if (handle == 0) { isp_prt(isp, ISP_LOGWARN, "cannot find handle for command to abort"); break; } - bus = XS_CHANNEL(xs); - mbs.param[0] = MBOX_ABORT; - if (IS_FC(isp)) { - if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) { - if (IS_2KLOGIN(isp)) { + if (IS_24XX(isp)) { + isp_prt(isp, ISP_LOGWARN, "ABORT CMD NOT IMPLETENTED"); + break; + } else if (IS_FC(isp)) { + if (FCPARAM(isp)->isp_sccfw) { + if (FCPARAM(isp)->isp_2klogin) { mbs.param[1] = tgt; } else { mbs.param[1] = tgt << 8; @@ -3538,19 +4367,17 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, void *arg) mbs.param[1] = tgt << 8 | XS_LUN(xs); } } else { - mbs.param[1] = - (bus << 15) | (XS_TGT(xs) << 8) | XS_LUN(xs); + bus = XS_CHANNEL(xs); + mbs.param[1] = (bus << 15) | (tgt << 8) | XS_LUN(xs); } + mbs.param[0] = MBOX_ABORT; mbs.param[2] = handle; - isp_mboxcmd(isp, &mbs, MBLOGALL & ~MBOX_COMMAND_ERROR); - if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { - return (0); + mbs.logval = MBLOGALL & ~MBOX_COMMAND_ERROR; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + break; } - /* - * XXX: Look for command in the REQUEST QUEUE. That is, - * XXX: It hasen't been picked up by firmware yet. - */ - break; + return (0); case ISPCTL_UPDATE_PARAMS: @@ -3571,8 +4398,7 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, void *arg) case ISPCTL_SCAN_FABRIC: if (IS_FC(isp)) { - int ftype = (arg)? *((int *) arg) : FC4_SCSI; - return (isp_scan_fabric(isp, ftype)); + return (isp_scan_fabric(isp)); } break; @@ -3592,39 +4418,64 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, void *arg) case ISPCTL_SEND_LIP: - if (IS_FC(isp)) { + if (IS_FC(isp) && !IS_24XX(isp)) { mbs.param[0] = MBOX_INIT_LIP; - if (IS_2KLOGIN(isp)) { - mbs.ibits |= (1 << 10); + if (FCPARAM(isp)->isp_2klogin) { + mbs.ibits = (1 << 10); } - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { return (0); } } break; - case ISPCTL_GET_POSMAP: - - if (IS_FC(isp) && arg) { - return (isp_getmap(isp, arg)); - } - break; - - case ISPCTL_GET_PDB: if (IS_FC(isp) && arg) { int id = *((int *)arg); isp_pdb_t *pdb = arg; - return (isp_getpdb(isp, id, pdb)); + return (isp_getpdb(isp, id, pdb, 1)); } break; + case ISPCTL_GET_PORTNAME: + { + uint64_t *wwnp = arg; + int loopid = *wwnp; + *wwnp = isp_get_portname(isp, loopid, 0); + if (*wwnp == (uint64_t) -1) { + break; + } else { + return (0); + } + } case ISPCTL_RUN_MBOXCMD: - isp_mboxcmd(isp, arg, MBLOGALL); + isp_mboxcmd(isp, arg); return(0); + case ISPCTL_PLOGX: + { + isp_plcmd_t *p = arg; + int r; + + if ((p->flags & PLOGX_FLG_CMD_MASK) != PLOGX_FLG_CMD_PLOGI || + (p->handle != NIL_HANDLE)) { + return (isp_plogx(isp, p->handle, p->portid, + p->flags, 0)); + } + do { + p->handle = isp_nxt_handle(isp, p->handle); + r = isp_plogx(isp, p->handle, p->portid, p->flags, 0); + if ((r & 0xffff) == MBOX_PORT_ID_USED) { + p->handle = r >> 16; + r = 0; + break; + } + } while ((r & 0xffff) == MBOX_LOOP_ID_USED); + return (r); + } #ifdef ISP_TARGET_MODE case ISPCTL_TOGGLE_TMODE: { @@ -3638,7 +4489,8 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, void *arg) mbs.param[0] = MBOX_ENABLE_TARGET_MODE; mbs.param[1] = param & 0xffff; mbs.param[2] = param >> 16; - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { break; } @@ -3662,17 +4514,18 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, void *arg) * of completions on a request queue at any one time. */ #ifndef MAX_REQUESTQ_COMPLETIONS -#define MAX_REQUESTQ_COMPLETIONS 64 +#define MAX_REQUESTQ_COMPLETIONS 32 #endif void -isp_intr(ispsoftc_t *isp, uint16_t isr, uint16_t sema, uint16_t mbox) +isp_intr(ispsoftc_t *isp, uint32_t isr, uint16_t sema, uint16_t mbox) { XS_T *complist[MAX_REQUESTQ_COMPLETIONS], *xs; - uint16_t iptr, optr, junk; + uint32_t iptr, optr, junk; int i, nlooked = 0, ndone = 0; again: + optr = isp->isp_residx; /* * Is this a mailbox related interrupt? * The mailbox semaphore will be nonzero if so. @@ -3698,17 +4551,14 @@ again: MBOX_NOTIFY_COMPLETE(isp); } else { isp_prt(isp, ISP_LOGWARN, - "Mbox Command Async (0x%x) with no waiters", - mbox); + "mailbox cmd (0x%x) with no waiters", mbox); } } else if (isp_parse_async(isp, mbox) < 0) { return; } if ((IS_FC(isp) && mbox != ASYNC_RIO_RESP) || isp->isp_state != ISP_RUNSTATE) { - ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT); - ISP_WRITE(isp, BIU_SEMA, 0); - return; + goto out; } } @@ -3716,32 +4566,72 @@ again: * We can't be getting this now. */ if (isp->isp_state != ISP_RUNSTATE) { - isp_prt(isp, ISP_LOGWARN, + isp_prt(isp, ISP_LOGINFO, "interrupt (ISR=%x SEMA=%x) when not ready", isr, sema); /* * Thank you very much! *Burrrp*! */ - WRITE_RESPONSE_QUEUE_OUT_POINTER(isp, - READ_RESPONSE_QUEUE_IN_POINTER(isp)); + ISP_WRITE(isp, isp->isp_respoutrp, + ISP_READ(isp, isp->isp_respinrp)); + if (IS_24XX(isp)) { + ISP_DISABLE_INTS(isp); + } + goto out; + } - ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT); - ISP_WRITE(isp, BIU_SEMA, 0); - return; +#ifdef ISP_TARGET_MODE + /* + * Check for ATIO Queue entries. + */ + if (isp->isp_rspbsy == 0 && (isp->isp_role & ISP_ROLE_TARGET) && + IS_24XX(isp)) { + iptr = ISP_READ(isp, isp->isp_atioinrp); + optr = ISP_READ(isp, isp->isp_atiooutrp); + + isp->isp_rspbsy = 1; + while (optr != iptr) { + uint8_t qe[QENTRY_LEN]; + isphdr_t *hp; + uint32_t oop; + void *addr; + + oop = optr; + MEMORYBARRIER(isp, SYNC_ATIOQ, oop, QENTRY_LEN); + addr = ISP_QUEUE_ENTRY(isp->isp_atioq, oop); + isp_get_hdr(isp, addr, (isphdr_t *)qe); + hp = (isphdr_t *)qe; + switch (hp->rqs_entry_type) { + case RQSTYPE_NOTIFY: + case RQSTYPE_ATIO: + (void) isp_target_notify(isp, addr, &oop); + break; + default: + isp_print_qentry(isp, "?ATIOQ entry?", + oop, addr); + break; + } + optr = ISP_NXT_QENTRY(oop, RESULT_QUEUE_LEN(isp)); + ISP_WRITE(isp, isp->isp_atiooutrp, optr); + } + isp->isp_rspbsy = 0; } +#endif /* * Get the current Response Queue Out Pointer. * - * If we're a 2300, we can ask what hardware what it thinks. + * If we're a 2300 or 2400, we can ask what hardware what it thinks. */ - if (IS_23XX(isp)) { + if (IS_23XX(isp) || IS_24XX(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", + isp_prt(isp, ISP_LOGINFO, + "isp_intr: hard optr=%x, soft optr %x", optr, isp->isp_residx); + isp->isp_residx = optr; } } else { optr = isp->isp_residx; @@ -3756,19 +4646,18 @@ again: if (IS_2100(isp) || (IS_2300(isp) && isp->isp_revision < 2)) { i = 0; do { - iptr = READ_RESPONSE_QUEUE_IN_POINTER(isp); - junk = READ_RESPONSE_QUEUE_IN_POINTER(isp); + iptr = ISP_READ(isp, isp->isp_respinrp); + junk = ISP_READ(isp, isp->isp_respinrp); } while (junk != iptr && ++i < 1000); if (iptr != junk) { - ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT); isp_prt(isp, ISP_LOGWARN, "Response Queue Out Pointer Unstable (%x, %x)", iptr, junk); - return; + goto out; } } else { - iptr = READ_RESPONSE_QUEUE_IN_POINTER(isp); + iptr = ISP_READ(isp, isp->isp_respinrp); } isp->isp_resodx = iptr; @@ -3782,15 +4671,17 @@ again: * make sure the old interrupt went away (to avoid 'ringing' * effects), but that didn't stop this from occurring. */ - if (IS_23XX(isp)) { + if (IS_24XX(isp)) { + junk = 0; + } else if (IS_23XX(isp)) { USEC_DELAY(100); - iptr = READ_RESPONSE_QUEUE_IN_POINTER(isp); + iptr = ISP_READ(isp, isp->isp_respinrp); junk = ISP_READ(isp, BIU_R2HSTSLO); } else { junk = ISP_READ(isp, BIU_ISR); } if (optr == iptr) { - if (IS_23XX(isp)) { + if (IS_23XX(isp) || IS_24XX(isp)) { ; } else { sema = ISP_READ(isp, BIU_SEMA); @@ -3806,43 +4697,75 @@ again: } } isp->isp_resodx = iptr; - ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT); - ISP_WRITE(isp, BIU_SEMA, 0); + if (isp->isp_rspbsy) { - return; + goto out; } isp->isp_rspbsy = 1; - while (optr != iptr) { - ispstatusreq_t local, *sp = &local; + uint8_t qe[QENTRY_LEN]; + ispstatusreq_t *sp = (ispstatusreq_t *) qe; isphdr_t *hp; - int type; + int buddaboom, etype, scsi_status, completion_status; + int req_status_flags, req_state_flags; + uint8_t *snsp, *resp; + uint32_t rlen, slen; + long resid; uint16_t oop; - int buddaboom = 0; hp = (isphdr_t *) ISP_QUEUE_ENTRY(isp->isp_result, optr); oop = optr; optr = ISP_NXT_QENTRY(optr, RESULT_QUEUE_LEN(isp)); nlooked++; read_again: + buddaboom = req_status_flags = req_state_flags = 0; + resid = 0L; + /* * Synchronize our view of this response queue entry. */ MEMORYBARRIER(isp, SYNC_RESULT, oop, QENTRY_LEN); + isp_get_hdr(isp, hp, &sp->req_header); + etype = sp->req_header.rqs_entry_type; - type = isp_get_response_type(isp, hp); - - if (type == RQSTYPE_RESPONSE) { + if (IS_24XX(isp) && etype == RQSTYPE_T7RQS) { + isp24xx_statusreq_t *sp2 = (isp24xx_statusreq_t *)qe; + isp_get_24xx_response(isp, + (isp24xx_statusreq_t *)hp, sp2); + if (isp->isp_dblev & ISP_LOGDEBUG1) { + isp_print_bytes(isp, + "Response Queue Entry", QENTRY_LEN, sp2); + } + scsi_status = sp2->req_scsi_status; + completion_status = sp2->req_completion_status; + req_state_flags = 0; + resid = sp2->req_resid; + } else if (etype == 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_dblev & ISP_LOGDEBUG1) { + isp_print_bytes(isp, + "Response Queue Entry", QENTRY_LEN, sp); + } + scsi_status = sp->req_scsi_status; + completion_status = sp->req_completion_status; + req_status_flags = sp->req_status_flags; + req_state_flags = sp->req_state_flags; + resid = sp->req_resid; + } else if (etype == RQSTYPE_RIO2) { + isp_rio2_t *rio = (isp_rio2_t *)qe; + isp_get_rio2(isp, (isp_rio2_t *) hp, rio); + if (isp->isp_dblev & ISP_LOGDEBUG1) { + isp_print_bytes(isp, + "Response Queue Entry", QENTRY_LEN, 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; } - if (isp->isp_fpcchiwater < rio.req_header.rqs_seqno) - isp->isp_fpcchiwater = rio.req_header.rqs_seqno; MEMZERO(hp, QENTRY_LEN); /* PERF */ continue; } else { @@ -3851,10 +4774,12 @@ again: * may have updated the response queue pointers for * us, so we reload our goal index. */ - int i = isp_handle_other_response(isp, type, hp, &optr); - if (i < 0) { + int r; + r = isp_handle_other_response(isp, etype, hp, &optr); + if (r < 0) { goto read_again; - } else if (i > 0) { + } + if (r > 0) { iptr = isp->isp_resodx; MEMZERO(hp, QENTRY_LEN); /* PERF */ continue; @@ -3865,34 +4790,33 @@ again: * we don't know how to deal with the rest of the * response. */ - isp_get_response(isp, (ispstatusreq_t *) hp, sp); /* * It really has to be a bounced request just copied * from the request queue to the response queue. If * not, something bad has happened. */ - if (sp->req_header.rqs_entry_type != RQSTYPE_REQUEST) { + if (etype != RQSTYPE_REQUEST) { isp_prt(isp, ISP_LOGERR, notresp, - sp->req_header.rqs_entry_type, oop, optr, - nlooked); - if (isp->isp_dblev & ISP_LOGDEBUG0) { - isp_print_bytes(isp, "Queue Entry", - QENTRY_LEN, sp); - } + etype, oop, optr, nlooked); + isp_print_bytes(isp, + "Reqeonse Queue Entry", QENTRY_LEN, sp); MEMZERO(hp, QENTRY_LEN); /* PERF */ continue; } buddaboom = 1; + scsi_status = sp->req_scsi_status; + completion_status = sp->req_completion_status; + req_status_flags = sp->req_status_flags; + req_state_flags = sp->req_state_flags; + resid = sp->req_resid; } - if (sp->req_header.rqs_flags & 0xf) { -#define _RQS_OFLAGS \ - ~(RQSFLAG_CONTINUATION|RQSFLAG_FULL|RQSFLAG_BADHEADER|RQSFLAG_BADPACKET) + if (sp->req_header.rqs_flags & RQSFLAG_MASK) { if (sp->req_header.rqs_flags & RQSFLAG_CONTINUATION) { isp_prt(isp, ISP_LOGWARN, "continuation segment"); - WRITE_RESPONSE_QUEUE_OUT_POINTER(isp, optr); + ISP_WRITE(isp, isp->isp_respoutrp, optr); continue; } if (sp->req_header.rqs_flags & RQSFLAG_FULL) { @@ -3903,53 +4827,47 @@ again: */ } if (sp->req_header.rqs_flags & RQSFLAG_BADHEADER) { - isp_prt(isp, ISP_LOGERR, "bad header flag"); + isp_print_bytes(isp, "bad header flag", + QENTRY_LEN, sp); buddaboom++; } if (sp->req_header.rqs_flags & RQSFLAG_BADPACKET) { - isp_prt(isp, ISP_LOGERR, "bad request packet"); + isp_print_bytes(isp, "bad request packet", + QENTRY_LEN, sp); buddaboom++; } - if (sp->req_header.rqs_flags & _RQS_OFLAGS) { - isp_prt(isp, ISP_LOGERR, - "unknown flags (0x%x) in response", - sp->req_header.rqs_flags); - buddaboom++; - } -#undef _RQS_OFLAGS } + if (sp->req_handle > isp->isp_maxcmds || sp->req_handle < 1) { - MEMZERO(hp, QENTRY_LEN); /* PERF */ isp_prt(isp, ISP_LOGERR, - "bad request handle %d (type 0x%x, flags 0x%x)", - sp->req_handle, sp->req_header.rqs_entry_type, - sp->req_header.rqs_flags); - WRITE_RESPONSE_QUEUE_OUT_POINTER(isp, optr); + "bad request handle %d (type 0x%x)", + sp->req_handle, etype); + MEMZERO(hp, QENTRY_LEN); /* PERF */ + ISP_WRITE(isp, isp->isp_respoutrp, optr); continue; } xs = isp_find_xs(isp, sp->req_handle); if (xs == NULL) { - uint8_t ts = sp->req_completion_status & 0xff; - MEMZERO(hp, QENTRY_LEN); /* PERF */ + uint8_t ts = completion_status & 0xff; /* * Only whine if this isn't the expected fallout of * aborting the command. */ - if (sp->req_header.rqs_entry_type != RQSTYPE_RESPONSE) { + if (etype != RQSTYPE_RESPONSE) { isp_prt(isp, ISP_LOGERR, "cannot find handle 0x%x (type 0x%x)", - sp->req_handle, - sp->req_header.rqs_entry_type); + sp->req_handle, etype); } else if (ts != RQCS_ABORTED) { isp_prt(isp, ISP_LOGERR, "cannot find handle 0x%x (status 0x%x)", sp->req_handle, ts); } - WRITE_RESPONSE_QUEUE_OUT_POINTER(isp, optr); + MEMZERO(hp, QENTRY_LEN); /* PERF */ + ISP_WRITE(isp, isp->isp_respoutrp, optr); continue; } isp_destroy_handle(isp, sp->req_handle); - if (sp->req_status_flags & RQSTF_BUS_RESET) { + if (req_status_flags & RQSTF_BUS_RESET) { XS_SETERR(xs, HBA_BUSRESET); isp->isp_sendmarker |= (1 << XS_CHANNEL(xs)); } @@ -3957,39 +4875,71 @@ again: XS_SETERR(xs, HBA_BOTCH); } - if (IS_FC(isp) && (sp->req_scsi_status & RQCS_SV)) { + resp = NULL; + rlen = 0; + snsp = NULL; + slen = 0; + if (IS_24XX(isp) && (scsi_status & RQCS_RV) != 0) { + resp = ((isp24xx_statusreq_t *)sp)->req_rsp_sense; + rlen = ((isp24xx_statusreq_t *)sp)->req_response_len; + } else if (IS_FC(isp) && (scsi_status & RQCS_RV) != 0) { + resp = sp->req_response; + rlen = sp->req_response_len; + } + if (IS_FC(isp) && (scsi_status & RQCS_SV) != 0) { /* * Fibre Channel F/W doesn't say we got status * if there's Sense Data instead. I guess they * think it goes w/o saying. */ - sp->req_state_flags |= RQSF_GOT_STATUS; + req_state_flags |= RQSF_GOT_STATUS|RQSF_GOT_SENSE; + if (IS_24XX(isp)) { + snsp = + ((isp24xx_statusreq_t *)sp)->req_rsp_sense; + snsp += rlen; + slen = + ((isp24xx_statusreq_t *)sp)->req_sense_len; + } else { + snsp = sp->req_sense_data; + slen = sp->req_sense_len; + } + } else if (IS_SCSI(isp) && (req_state_flags & RQSF_GOT_SENSE)) { + snsp = sp->req_sense_data; + slen = sp->req_sense_len; } - if (sp->req_state_flags & RQSF_GOT_STATUS) { - *XS_STSP(xs) = sp->req_scsi_status & 0xff; + if (req_state_flags & RQSF_GOT_STATUS) { + *XS_STSP(xs) = scsi_status & 0xff; } - switch (sp->req_header.rqs_entry_type) { + switch (etype) { case RQSTYPE_RESPONSE: XS_SET_STATE_STAT(isp, xs, sp); - isp_parse_status(isp, sp, xs); + if (resp && rlen >= 4 && + resp[FCP_RSPNS_CODE_OFFSET] != 0) { + isp_prt(isp, ISP_LOGWARN, + "%d.%d FCP RESPONSE: 0x%x", + XS_TGT(xs), XS_LUN(xs), + resp[FCP_RSPNS_CODE_OFFSET]); + XS_SETERR(xs, HBA_BOTCH); + } + if (IS_24XX(isp)) { + isp_parse_status_24xx(isp, + (isp24xx_statusreq_t *)sp, xs, &resid); + } else { + isp_parse_status(isp, (void *)sp, xs, &resid); + } if ((XS_NOERR(xs) || XS_ERR(xs) == HBA_NOERROR) && (*XS_STSP(xs) == SCSI_BUSY)) { XS_SETERR(xs, HBA_TGTBSY); } if (IS_SCSI(isp)) { - XS_RESID(xs) = sp->req_resid; - if ((sp->req_state_flags & RQSF_GOT_STATUS) && - (*XS_STSP(xs) == SCSI_CHECK) && - (sp->req_state_flags & RQSF_GOT_SENSE)) { - XS_SAVE_SENSE(xs, sp); - } + XS_RESID(xs) = resid; /* * A new synchronous rate was negotiated for * this target. Mark state such that we'll go * look up that which has changed later. */ - if (sp->req_status_flags & RQSTF_NEGOTIATION) { + if (req_status_flags & RQSTF_NEGOTIATION) { int t = XS_TGT(xs); sdparam *sdp = isp->isp_param; sdp += XS_CHANNEL(xs); @@ -3998,27 +4948,26 @@ again: (1 << XS_CHANNEL(xs)); } } else { - if (sp->req_status_flags & RQSF_XFER_COMPLETE) { + if (req_status_flags & RQSF_XFER_COMPLETE) { XS_RESID(xs) = 0; - } else if (sp->req_scsi_status & RQCS_RESID) { - XS_RESID(xs) = sp->req_resid; + } else if (scsi_status & RQCS_RESID) { + XS_RESID(xs) = resid; } else { XS_RESID(xs) = 0; } - if ((sp->req_state_flags & RQSF_GOT_STATUS) && - (*XS_STSP(xs) == SCSI_CHECK) && - (sp->req_scsi_status & RQCS_SV)) { - XS_SAVE_SENSE(xs, sp); - /* solely for the benefit of debug */ - sp->req_state_flags |= RQSF_GOT_SENSE; - } + } + if (snsp && slen) { + XS_SAVE_SENSE(xs, snsp, slen); } isp_prt(isp, ISP_LOGDEBUG2, "asked for %ld got raw resid %ld settled for %ld", - (long) XS_XFRLEN(xs), (long) sp->req_resid, - (long) XS_RESID(xs)); + (long) XS_XFRLEN(xs), resid, (long) XS_RESID(xs)); break; case RQSTYPE_REQUEST: + case RQSTYPE_A64: + case RQSTYPE_T2RQS: + case RQSTYPE_T3RQS: + case RQSTYPE_T7RQS: if (sp->req_header.rqs_flags & RQSFLAG_FULL) { /* * Force Queue Full status. @@ -4029,16 +4978,19 @@ again: /* * ???? */ + XS_SETERR(xs, HBA_BOTCH); isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Entry bounced back"); - XS_SETERR(xs, HBA_BOTCH); + if ((isp->isp_dblev & ISP_LOGDEBUG1) == 0) { + isp_print_bytes(isp, "Bounced Request", + QENTRY_LEN, qe); + } } XS_RESID(xs) = XS_XFRLEN(xs); break; default: - isp_prt(isp, ISP_LOGWARN, - "unhandled response queue type 0x%x", - sp->req_header.rqs_entry_type); + isp_print_bytes(isp, "Unhandled Response Type", + QENTRY_LEN, qe); if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_BOTCH); } @@ -4056,7 +5008,7 @@ again: ((isp->isp_dblev & ISP_LOGDEBUG1) && ((!XS_NOERR(xs)) || (*XS_STSP(xs) != SCSI_GOOD)))) { char skey; - if (sp->req_state_flags & RQSF_GOT_SENSE) { + if (req_state_flags & RQSF_GOT_SENSE) { skey = XS_SNSKEY(xs) & 0xf; if (skey < 10) skey += '0'; @@ -4087,13 +5039,23 @@ again: * ISP's notion of what we've seen so far. */ if (nlooked) { - WRITE_RESPONSE_QUEUE_OUT_POINTER(isp, optr); + ISP_WRITE(isp, isp->isp_respoutrp, optr); /* * 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_reqodx = ISP_READ(isp, isp->isp_rqstoutrp); + if (isp->isp_rscchiwater < ndone) { isp->isp_rscchiwater = ndone; + } + } + +out: + + if (IS_24XX(isp)) { + ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_RISC_INT); + } else { + ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT); + ISP_WRITE(isp, BIU_SEMA, 0); } isp->isp_residx = optr; @@ -4128,8 +5090,9 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) case ASYNC_BUS_RESET: isp->isp_sendmarker |= (1 << bus); #ifdef ISP_TARGET_MODE - if (isp_target_async(isp, bus, mbox)) + if (isp_target_async(isp, bus, mbox)) { rval = -1; + } #endif isp_async(isp, ISPASYNC_BUS_RESET, &bus); break; @@ -4179,7 +5142,7 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) * We don't need to be chatty about this- just unlatch things * and move on. */ - mbox = READ_REQUEST_QUEUE_OUT_POINTER(isp); + mbox = ISP_READ(isp, isp->isp_rqstoutrp); break; case ASYNC_TIMEOUT_RESET: @@ -4187,8 +5150,9 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) "timeout initiated SCSI bus reset of bus %d", bus); isp->isp_sendmarker |= (1 << bus); #ifdef ISP_TARGET_MODE - if (isp_target_async(isp, bus, mbox)) + if (isp_target_async(isp, bus, mbox)) { rval = -1; + } #endif break; @@ -4196,8 +5160,9 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) isp_prt(isp, ISP_LOGINFO, "device reset on bus %d", bus); isp->isp_sendmarker |= (1 << bus); #ifdef ISP_TARGET_MODE - if (isp_target_async(isp, bus, mbox)) + if (isp_target_async(isp, bus, mbox)) { rval = -1; + } #endif break; @@ -4300,16 +5265,18 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) #endif break; } + case ASYNC_LIP_ERROR: case ASYNC_LIP_F8: case ASYNC_LIP_OCCURRED: FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; FCPARAM(isp)->isp_loopstate = LOOP_LIP_RCVD; isp->isp_sendmarker = 1; - isp_mark_getpdb_all(isp); + ISP_MARK_PORTDB(isp, 1); isp_async(isp, ISPASYNC_LIP, NULL); #ifdef ISP_TARGET_MODE - if (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 @@ -4340,7 +5307,7 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) isp->isp_sendmarker = 1; FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; FCPARAM(isp)->isp_loopstate = LOOP_LIP_RCVD; - isp_mark_getpdb_all(isp); + ISP_MARK_PORTDB(isp, 1); isp_async(isp, ISPASYNC_LOOP_UP, NULL); #ifdef ISP_TARGET_MODE if (isp_target_async(isp, bus, mbox)) { @@ -4353,7 +5320,7 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) isp->isp_sendmarker = 1; FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; FCPARAM(isp)->isp_loopstate = LOOP_NIL; - isp_mark_getpdb_all(isp); + ISP_MARK_PORTDB(isp, 1); isp_async(isp, ISPASYNC_LOOP_DOWN, NULL); #ifdef ISP_TARGET_MODE if (isp_target_async(isp, bus, mbox)) { @@ -4366,7 +5333,7 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) isp->isp_sendmarker = 1; FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; FCPARAM(isp)->isp_loopstate = LOOP_NIL; - isp_mark_getpdb_all(isp); + ISP_MARK_PORTDB(isp, 1); isp_async(isp, ISPASYNC_LOOP_RESET, NULL); #ifdef ISP_TARGET_MODE if (isp_target_async(isp, bus, mbox)) { @@ -4378,39 +5345,37 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) case ASYNC_PDB_CHANGED: isp->isp_sendmarker = 1; FCPARAM(isp)->isp_loopstate = LOOP_PDB_RCVD; - isp_mark_getpdb_all(isp); + ISP_MARK_PORTDB(isp, 1); isp_async(isp, ISPASYNC_CHANGE_NOTIFY, ISPASYNC_CHANGE_PDB); break; case ASYNC_CHANGE_NOTIFY: - /* - * Not correct, but it will force us to rescan the loop. - */ - FCPARAM(isp)->isp_loopstate = LOOP_PDB_RCVD; - isp_mark_getpdb_all(isp); + if (FCPARAM(isp)->isp_topo == TOPO_F_PORT) { + FCPARAM(isp)->isp_loopstate = LOOP_LSCAN_DONE; + } else { + FCPARAM(isp)->isp_loopstate = LOOP_PDB_RCVD; + } + ISP_MARK_PORTDB(isp, 1); isp_async(isp, ISPASYNC_CHANGE_NOTIFY, ISPASYNC_CHANGE_SNS); break; case ASYNC_PTPMODE: - if (FCPARAM(isp)->isp_onfabric) - FCPARAM(isp)->isp_topo = TOPO_F_PORT; - else - FCPARAM(isp)->isp_topo = TOPO_N_PORT; - isp_mark_getpdb_all(isp); + ISP_MARK_PORTDB(isp, 1); isp->isp_sendmarker = 1; FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT; FCPARAM(isp)->isp_loopstate = LOOP_LIP_RCVD; isp_async(isp, ISPASYNC_CHANGE_NOTIFY, ISPASYNC_CHANGE_OTHER); #ifdef ISP_TARGET_MODE - if (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; case ASYNC_CONNMODE: mbox = ISP_READ(isp, OUTMAILBOX1); - isp_mark_getpdb_all(isp); + ISP_MARK_PORTDB(isp, 1); switch (mbox) { case ISP_CONN_LOOP: isp_prt(isp, ISP_LOGINFO, @@ -4449,6 +5414,15 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) FCPARAM(isp)->isp_loopstate = LOOP_LIP_RCVD; break; + case ASYNC_RJT_SENT: /* same as ASYNC_QFULL_SENT */ + if (IS_24XX(isp)) { + isp_prt(isp, ISP_LOGTDEBUG0, "LS_RJT sent"); + break; + } else if (IS_2200(isp)) { + isp_prt(isp, ISP_LOGTDEBUG0, "QFULL sent"); + break; + } + /* FALLTHROUGH */ default: isp_prt(isp, ISP_LOGWARN, "Unknown Async Code 0x%x", mbox); break; @@ -4469,8 +5443,9 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) isp_prt(isp, ISP_LOGDEBUG3, "fast post completion of %u", handles[i]); } - if (isp->isp_fpcchiwater < nh) + if (isp->isp_fpcchiwater < nh) { isp->isp_fpcchiwater = nh; + } } else { isp->isp_intoasync++; } @@ -4485,11 +5460,14 @@ isp_parse_async(ispsoftc_t *isp, uint16_t mbox) static int isp_handle_other_response(ispsoftc_t *isp, int type, - isphdr_t *hp, uint16_t *optrp) + isphdr_t *hp, uint32_t *optrp) { switch (type) { case RQSTYPE_STATUS_CONT: - isp_prt(isp, ISP_LOGINFO, "Ignored Continuation Response"); + isp_prt(isp, ISP_LOGDEBUG0, "Ignored Continuation Response"); + return (1); + case RQSTYPE_MARKER: + isp_prt(isp, ISP_LOGDEBUG0, "Marker Response"); return (1); case RQSTYPE_ATIO: case RQSTYPE_CTIO: @@ -4501,6 +5479,9 @@ isp_handle_other_response(ispsoftc_t *isp, int type, case RQSTYPE_ATIO2: case RQSTYPE_CTIO2: case RQSTYPE_CTIO3: + case RQSTYPE_CTIO7: + case RQSTYPE_ABTS_RCVD: + case RQSTYPE_ABTS_RSP: isp->isp_rsltccmplt++; /* count as a response completion */ #ifdef ISP_TARGET_MODE if (isp_target_notify(isp, (ispstatusreq_t *) hp, optrp)) { @@ -4534,7 +5515,7 @@ isp_handle_other_response(ispsoftc_t *isp, int type, } static void -isp_parse_status(ispsoftc_t *isp, ispstatusreq_t *sp, XS_T *xs) +isp_parse_status(ispsoftc_t *isp, ispstatusreq_t *sp, XS_T *xs, long *rp) { switch (sp->req_completion_status & 0xff) { case RQCS_COMPLETE: @@ -4550,6 +5531,7 @@ isp_parse_status(ispsoftc_t *isp, ispstatusreq_t *sp, XS_T *xs) XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs)); if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_SELTIMEOUT); + *rp = XS_XFRLEN(xs); } return; } @@ -4562,6 +5544,7 @@ isp_parse_status(ispsoftc_t *isp, ispstatusreq_t *sp, XS_T *xs) case RQCS_DMA_ERROR: isp_prt(isp, ISP_LOGERR, "DMA error for command on %d.%d.%d", XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs)); + *rp = XS_XFRLEN(xs); break; case RQCS_TRANSPORT_ERROR: @@ -4617,6 +5600,7 @@ isp_parse_status(ispsoftc_t *isp, ispstatusreq_t *sp, XS_T *xs) isp_prt(isp, ISP_LOGERR, "%s", buf); isp_prt(isp, ISP_LOGERR, "transport error for %d.%d.%d:\n%s", XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs), buf); + *rp = XS_XFRLEN(xs); break; } case RQCS_RESET_OCCURRED: @@ -4627,6 +5611,7 @@ isp_parse_status(ispsoftc_t *isp, ispstatusreq_t *sp, XS_T *xs) if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_BUSRESET); } + *rp = XS_XFRLEN(xs); return; case RQCS_ABORTED: @@ -4642,15 +5627,8 @@ isp_parse_status(ispsoftc_t *isp, ispstatusreq_t *sp, XS_T *xs) isp_prt(isp, ISP_LOGWARN, "command timed out for %d.%d.%d", XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs)); /* - * Check to see if we logged out the device. + * XXX: Check to see if we logged out of the device. */ - if (IS_FC(isp)) { - if ((sp->req_completion_status & RQSTF_LOGOUT) && - FCPARAM(isp)->portdb[XS_TGT(xs)].valid && - FCPARAM(isp)->portdb[XS_TGT(xs)].fabric_dev) { - FCPARAM(isp)->portdb[XS_TGT(xs)].relogin = 1; - } - } if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_CMDTIMEOUT); } @@ -4857,43 +5835,193 @@ isp_parse_status(ispsoftc_t *isp, ispstatusreq_t *sp, XS_T *xs) * No such port on the loop. Moral equivalent of SELTIMEO */ case RQCS_PORT_LOGGED_OUT: + { + char *reason; + uint8_t sts = sp->req_completion_status & 0xff; + /* * It was there (maybe)- treat as a selection timeout. */ - 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 (sts == RQCS_PORT_UNAVAILABLE) { + reason = "unavailable"; + } else { + reason = "logout"; + } + + isp_prt(isp, ISP_LOGINFO, "port %s for target %d", + reason, 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. + * then we'll have to log in again as a matter of course. */ if (FCPARAM(isp)->isp_topo == TOPO_NL_PORT || FCPARAM(isp)->isp_topo == TOPO_FL_PORT) { mbreg_t mbs; MEMZERO(&mbs, sizeof (mbs)); mbs.param[0] = MBOX_INIT_LIP; - if (IS_2KLOGIN(isp)) { - mbs.ibits |= (1 << 10); + if (FCPARAM(isp)->isp_2klogin) { + mbs.ibits = (1 << 10); } + mbs.logval = MBLOGALL; isp_mboxcmd_qnw(isp, &mbs, 1); } + if (XS_NOERR(xs)) { + XS_SETERR(xs, HBA_SELTIMEOUT); + } + return; + } + case RQCS_PORT_CHANGED: + isp_prt(isp, ISP_LOGWARN, + "port changed for target %d", XS_TGT(xs)); + if (XS_NOERR(xs)) { + XS_SETERR(xs, HBA_SELTIMEOUT); + } + return; + + case RQCS_PORT_BUSY: + isp_prt(isp, ISP_LOGWARN, + "port busy for target %d", XS_TGT(xs)); + if (XS_NOERR(xs)) { + XS_SETERR(xs, HBA_TGTBSY); + } + return; + + default: + isp_prt(isp, ISP_LOGERR, "Unknown Completion Status 0x%x", + sp->req_completion_status); + break; + } + if (XS_NOERR(xs)) { + XS_SETERR(xs, HBA_BOTCH); + } +} + +static void +isp_parse_status_24xx(ispsoftc_t *isp, isp24xx_statusreq_t *sp, + XS_T *xs, long *rp) +{ + switch (sp->req_completion_status) { + case RQCS_COMPLETE: + if (XS_NOERR(xs)) { + XS_SETERR(xs, HBA_NOERROR); + } + return; + + case RQCS_DMA_ERROR: + isp_prt(isp, ISP_LOGERR, "DMA error for command on %d.%d.%d", + XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs)); + break; + + case RQCS_TRANSPORT_ERROR: + isp_prt(isp, ISP_LOGERR, "transport error for %d.%d.%d", + XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs)); + break; + + case RQCS_RESET_OCCURRED: + isp_prt(isp, ISP_LOGWARN, + "bus reset destroyed command for %d.%d.%d", + XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs)); + isp->isp_sendmarker |= (1 << XS_CHANNEL(xs)); + if (XS_NOERR(xs)) { + XS_SETERR(xs, HBA_BUSRESET); + } + return; + + case RQCS_ABORTED: + isp_prt(isp, ISP_LOGERR, "command aborted for %d.%d.%d", + XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs)); + isp->isp_sendmarker |= (1 << XS_CHANNEL(xs)); + if (XS_NOERR(xs)) { + XS_SETERR(xs, HBA_ABORTED); + } + return; + + case RQCS_TIMEOUT: + isp_prt(isp, ISP_LOGWARN, "command timed out for %d.%d.%d", + XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs)); + if (XS_NOERR(xs)) { + XS_SETERR(xs, HBA_CMDTIMEOUT); + } + return; + + case RQCS_DATA_OVERRUN: + XS_RESID(xs) = sp->req_resid; + isp_prt(isp, ISP_LOGERR, "data overrun for command on %d.%d.%d", + XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs)); + if (XS_NOERR(xs)) { + XS_SETERR(xs, HBA_DATAOVR); + } + return; + + case RQCS_24XX_DRE: /* data reassembly error */ + isp_prt(isp, ISP_LOGERR, "data reassembly error for target %d", + XS_TGT(xs)); + if (XS_NOERR(xs)) { + XS_SETERR(xs, HBA_ABORTED); + } + *rp = XS_XFRLEN(xs); + return; + + case RQCS_24XX_TABORT: /* aborted by target */ + isp_prt(isp, ISP_LOGERR, "target %d sent ABTS", + XS_TGT(xs)); + if (XS_NOERR(xs)) { + XS_SETERR(xs, HBA_ABORTED); + } + return; + + case RQCS_DATA_UNDERRUN: + XS_RESID(xs) = sp->req_resid; + if (XS_NOERR(xs)) { + XS_SETERR(xs, HBA_NOERROR); + } + return; + + case RQCS_PORT_UNAVAILABLE: /* - * Probably overkill. + * No such port on the loop. Moral equivalent of SELTIMEO */ - 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); + case RQCS_PORT_LOGGED_OUT: + { + char *reason; + uint8_t sts = sp->req_completion_status & 0xff; + + /* + * It was there (maybe)- treat as a selection timeout. + */ + if (sts == RQCS_PORT_UNAVAILABLE) { + reason = "unavailable"; + } else { + reason = "logout"; + } + + isp_prt(isp, ISP_LOGINFO, "port %s for target %d", + reason, 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 log in again as a matter of course. + */ + if (FCPARAM(isp)->isp_topo == TOPO_NL_PORT || + FCPARAM(isp)->isp_topo == TOPO_FL_PORT) { + mbreg_t mbs; + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_INIT_LIP; + if (FCPARAM(isp)->isp_2klogin) { + mbs.ibits = (1 << 10); + } + mbs.logval = MBLOGALL; + isp_mboxcmd_qnw(isp, &mbs, 1); + } if (XS_NOERR(xs)) { XS_SETERR(xs, HBA_SELTIMEOUT); } return; - + } case RQCS_PORT_CHANGED: isp_prt(isp, ISP_LOGWARN, "port changed for target %d", XS_TGT(xs)); @@ -4902,10 +6030,22 @@ isp_parse_status(ispsoftc_t *isp, ispstatusreq_t *sp, XS_T *xs) } return; - case RQCS_PORT_BUSY: + + case RQCS_24XX_ENOMEM: /* f/w resource unavailable */ isp_prt(isp, ISP_LOGWARN, - "port busy for target %d", XS_TGT(xs)); + "f/w resource unavailable for target %d", XS_TGT(xs)); + if (XS_NOERR(xs)) { + *XS_STSP(xs) = SCSI_BUSY; + XS_SETERR(xs, HBA_TGTBSY); + } + return; + + case RQCS_24XX_TMO: /* task management overrun */ + isp_prt(isp, ISP_LOGWARN, + "command for target %d overlapped task management", + XS_TGT(xs)); if (XS_NOERR(xs)) { + *XS_STSP(xs) = SCSI_BUSY; XS_SETERR(xs, HBA_TGTBSY); } return; @@ -4977,8 +6117,12 @@ isp_mbox_continue(ispsoftc_t *isp) /* * Clear the previous interrupt. */ - ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT); - ISP_WRITE(isp, BIU_SEMA, 0); + if (IS_24XX(isp)) { + ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_RISC_INT); + } else { + ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT); + ISP_WRITE(isp, BIU_SEMA, 0); + } /* * Continue with next word. @@ -4996,7 +6140,7 @@ isp_mbox_continue(ispsoftc_t *isp) break; case MBOX_WRITE_RAM_WORD_EXTENDED: offset = isp->isp_mbxwrk1; - offset |= ((uint32_t) isp->isp_mbxwrk8 << 16); + offset |= isp->isp_mbxwrk8 << 16; mbs.param[2] = *ptr++;; mbs.param[1] = offset; @@ -5006,7 +6150,7 @@ isp_mbox_continue(ispsoftc_t *isp) break; case MBOX_READ_RAM_WORD_EXTENDED: offset = isp->isp_mbxwrk1; - offset |= ((uint32_t) isp->isp_mbxwrk8 << 16); + offset |= isp->isp_mbxwrk8 << 16; *ptr++ = isp->isp_mboxtmp[2]; mbs.param[1] = offset; @@ -5018,11 +6162,11 @@ isp_mbox_continue(ispsoftc_t *isp) isp->isp_mbxworkp = ptr; isp->isp_mbxwrk0--; mbs.param[0] = isp->isp_lastmbxcmd; + mbs.logval = MBLOGALL; isp_mboxcmd_qnw(isp, &mbs, 0); return (0); } - #define HIWRD(x) ((x) >> 16) #define LOWRD(x) ((x) & 0xffff) #define ISPOPMAP(a, b) (((a) << 16) | (b)) @@ -5111,7 +6255,7 @@ static const uint32_t mbpscsi[] = { ISPOPMAP(0xdf, 0xdf), /* 0x51: DUMP RAM A64 */ ISPOPMAP(0xdf, 0xff), /* 0x52: INITIALIZE REQUEST QUEUE A64 */ ISPOPMAP(0xef, 0xff), /* 0x53: INITIALIZE RESPONSE QUEUE A64 */ - ISPOPMAP(0xcf, 0x01), /* 0x54: EXECUTE IOCB A64 */ + ISPOPMAP(0xcf, 0x01), /* 0x54: EXECUCUTE COMMAND IOCB A64 */ ISPOPMAP(0x07, 0x01), /* 0x55: ENABLE TARGET MODE */ ISPOPMAP(0x03, 0x0f), /* 0x56: GET TARGET STATUS */ ISPOPMAP(0x00, 0x00), /* 0x57: */ @@ -5123,7 +6267,6 @@ static const uint32_t mbpscsi[] = { ISPOPMAP(0x01, 0x01) /* 0x5d: GET NOST DATA */ }; -#ifndef ISP_STRIPPED static char *scsi_mbcmd_names[] = { "NO-OP", "LOAD RAM", @@ -5220,23 +6363,22 @@ static char *scsi_mbcmd_names[] = { "SET HOST DATA", "GET NOST DATA", }; -#endif static const uint32_t mbpfc[] = { ISPOPMAP(0x01, 0x01), /* 0x00: MBOX_NO_OP */ ISPOPMAP(0x1f, 0x01), /* 0x01: MBOX_LOAD_RAM */ - ISPOPMAP(0x07, 0x01), /* 0x02: MBOX_EXEC_FIRMWARE */ + ISPOPMAP(0x0f, 0x01), /* 0x02: MBOX_EXEC_FIRMWARE */ ISPOPMAP(0xdf, 0x01), /* 0x03: MBOX_DUMP_RAM */ ISPOPMAP(0x07, 0x07), /* 0x04: MBOX_WRITE_RAM_WORD */ ISPOPMAP(0x03, 0x07), /* 0x05: MBOX_READ_RAM_WORD */ ISPOPMAP(0xff, 0xff), /* 0x06: MBOX_MAILBOX_REG_TEST */ - ISPOPMAP(0x03, 0x05), /* 0x07: MBOX_VERIFY_CHECKSUM */ + ISPOPMAP(0x03, 0x07), /* 0x07: MBOX_VERIFY_CHECKSUM */ ISPOPMAP(0x01, 0x4f), /* 0x08: MBOX_ABOUT_FIRMWARE */ - ISPOPMAP(0xdf, 0x01), /* 0x09: LOAD RAM */ + ISPOPMAP(0xdf, 0x01), /* 0x09: MBOX_LOAD_RISC_RAM_2100 */ ISPOPMAP(0xdf, 0x01), /* 0x0a: DUMP RAM */ - ISPOPMAP(0x00, 0x00), /* 0x0b: */ + ISPOPMAP(0x1ff, 0x01), /* 0x0b: MBOX_LOAD_RISC_RAM */ ISPOPMAP(0x00, 0x00), /* 0x0c: */ - ISPOPMAP(0x10f, 0x01), /* 0x0d: MBOX_WRITE_RAM_WORD_EXTENDED) */ + ISPOPMAP(0x10f, 0x01), /* 0x0d: MBOX_WRITE_RAM_WORD_EXTENDED */ ISPOPMAP(0x01, 0x05), /* 0x0e: MBOX_CHECK_FIRMWARE */ ISPOPMAP(0x10f, 0x05), /* 0x0f: MBOX_READ_RAM_WORD_EXTENDED */ ISPOPMAP(0x1f, 0x11), /* 0x10: MBOX_INIT_REQ_QUEUE */ @@ -5289,8 +6431,8 @@ static const uint32_t mbpfc[] = { ISPOPMAP(0x00, 0x00), /* 0x3f: */ ISPOPMAP(0x03, 0x01), /* 0x40: MBOX_LOOP_PORT_BYPASS */ ISPOPMAP(0x03, 0x01), /* 0x41: MBOX_LOOP_PORT_ENABLE */ - ISPOPMAP(0x03, 0x07), /* 0x42: MBOX_GET_RESOURCE_COUNTS */ - ISPOPMAP(0x01, 0x01), /* 0x43: MBOX_REQUEST_NON_PARTICIPATING_MODE */ + ISPOPMAP(0x03, 0x07), /* 0x42: MBOX_GET_RESOURCE_COUNT */ + ISPOPMAP(0x01, 0x01), /* 0x43: MBOX_REQUEST_OFFLINE_MODE */ ISPOPMAP(0x00, 0x00), /* 0x44: */ ISPOPMAP(0x00, 0x00), /* 0x45: */ ISPOPMAP(0x00, 0x00), /* 0x46: */ @@ -5319,7 +6461,7 @@ static const uint32_t mbpfc[] = { ISPOPMAP(0x07, 0x03), /* 0x5d: MBOX_GET_SET_DATA_RATE */ ISPOPMAP(0x00, 0x00), /* 0x5e: */ ISPOPMAP(0x00, 0x00), /* 0x5f: */ - ISPOPMAP(0xcd, 0x31), /* 0x60: MBOX_INIT_FIRMWARE */ + ISPOPMAP(0xcd, 0x01), /* 0x60: MBOX_INIT_FIRMWARE */ ISPOPMAP(0x00, 0x00), /* 0x61: */ ISPOPMAP(0x01, 0x01), /* 0x62: MBOX_INIT_LIP */ ISPOPMAP(0xcd, 0x03), /* 0x63: MBOX_GET_FC_AL_POSITION_MAP */ @@ -5360,7 +6502,6 @@ static const uint32_t mbpfc[] = { * is that we won't overflow. */ -#ifndef ISP_STRIPPED static char *fc_mbcmd_names[] = { "NO-OP", "LOAD RAM", @@ -5428,7 +6569,7 @@ static char *fc_mbcmd_names[] = { NULL, "LOOP PORT BYPASS", "LOOP PORT ENABLE", - "GET RESOURCE COUNTS", + "GET RESOURCE COUNT", "REQUEST NON PARTICIPATING MODE", NULL, NULL, @@ -5490,7 +6631,6 @@ static char *fc_mbcmd_names[] = { "SEND LFA", "Lun RESET" }; -#endif static void isp_mboxcmd_qnw(ispsoftc_t *isp, mbreg_t *mbp, int nodelay) @@ -5521,19 +6661,23 @@ isp_mboxcmd_qnw(ispsoftc_t *isp, mbreg_t *mbp, int nodelay) isp->isp_obits = obits; isp->isp_mboxbsy = 1; } - ISP_WRITE(isp, HCCR, HCCR_CMD_SET_HOST_INT); + if (IS_24XX(isp)) { + ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_SET_HOST_INT); + } else { + 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(100); + USEC_DELAY(1000); } } static void -isp_mboxcmd(ispsoftc_t *isp, mbreg_t *mbp, int logmask) +isp_mboxcmd(ispsoftc_t *isp, mbreg_t *mbp) { char *cname, *xname, tname[16], mname[16]; unsigned int lim, ibits, obits, box, opcode; @@ -5571,11 +6715,14 @@ isp_mboxcmd(ispsoftc_t *isp, mbreg_t *mbp, int logmask) /* * Get exclusive usage of mailbox registers. */ - MBOX_ACQUIRE(isp); + if (MBOX_ACQUIRE(isp)) { + mbp->param[0] = MBOX_REGS_BUSY; + goto out; + } for (box = 0; box < MAX_MAILBOX(isp); box++) { if (ibits & (1 << box)) { - isp_prt(isp, ISP_LOGDEBUG1, "IN mbox %d = 0x%x", box, + isp_prt(isp, ISP_LOGDEBUG1, "IN mbox %d = 0x%04x", box, mbp->param[box]); ISP_WRITE(isp, MBOX_OFF(box), mbp->param[box]); } @@ -5593,20 +6740,23 @@ isp_mboxcmd(ispsoftc_t *isp, mbreg_t *mbp, int logmask) /* * Set Host Interrupt condition so that RISC will pick up mailbox regs. */ - ISP_WRITE(isp, HCCR, HCCR_CMD_SET_HOST_INT); + if (IS_24XX(isp)) { + ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_SET_HOST_INT); + } else { + ISP_WRITE(isp, HCCR, HCCR_CMD_SET_HOST_INT); + } /* * While we haven't finished the command, spin our wheels here. */ - MBOX_WAIT_COMPLETE(isp); + MBOX_WAIT_COMPLETE(isp, mbp); /* * Did the command time out? */ - if (isp->isp_mboxbsy) { - isp->isp_mboxbsy = 0; + if (mbp->param[0] == MBOX_TIMEOUT) { MBOX_RELEASE(isp); - return; + goto out; } /* @@ -5615,21 +6765,18 @@ isp_mboxcmd(ispsoftc_t *isp, mbreg_t *mbp, int logmask) for (box = 0; box < MAX_MAILBOX(isp); box++) { if (obits & (1 << box)) { mbp->param[box] = isp->isp_mboxtmp[box]; - isp_prt(isp, ISP_LOGDEBUG1, "OUT mbox %d = 0x%x", box, + isp_prt(isp, ISP_LOGDEBUG1, "OUT mbox %d = 0x%04x", box, mbp->param[box]); } } MBOX_RELEASE(isp); - - if (logmask == 0 || opcode == MBOX_EXEC_FIRMWARE) { + out: + isp->isp_mboxbsy = 0; + if (mbp->logval == 0 || opcode == MBOX_EXEC_FIRMWARE) { return; } -#ifdef ISP_STRIPPED - cname = NULL; -#else cname = (IS_FC(isp))? fc_mbcmd_names[opcode] : scsi_mbcmd_names[opcode]; -#endif if (cname == NULL) { cname = tname; SNPRINTF(tname, sizeof tname, "opcode %x", opcode); @@ -5643,46 +6790,49 @@ isp_mboxcmd(ispsoftc_t *isp, mbreg_t *mbp, int logmask) case MBOX_COMMAND_COMPLETE: break; case MBOX_INVALID_COMMAND: - if (logmask & MBLOGMASK(MBOX_COMMAND_COMPLETE)) { + if (mbp->logval & MBLOGMASK(MBOX_COMMAND_COMPLETE)) { xname = "INVALID COMMAND"; } break; case MBOX_HOST_INTERFACE_ERROR: - if (logmask & MBLOGMASK(MBOX_HOST_INTERFACE_ERROR)) { + if (mbp->logval & MBLOGMASK(MBOX_HOST_INTERFACE_ERROR)) { xname = "HOST INTERFACE ERROR"; } break; case MBOX_TEST_FAILED: - if (logmask & MBLOGMASK(MBOX_TEST_FAILED)) { + if (mbp->logval & MBLOGMASK(MBOX_TEST_FAILED)) { xname = "TEST FAILED"; } break; case MBOX_COMMAND_ERROR: - if (logmask & MBLOGMASK(MBOX_COMMAND_ERROR)) { + if (mbp->logval & MBLOGMASK(MBOX_COMMAND_ERROR)) { xname = "COMMAND ERROR"; } break; case MBOX_COMMAND_PARAM_ERROR: - if (logmask & MBLOGMASK(MBOX_COMMAND_PARAM_ERROR)) { + if (mbp->logval & MBLOGMASK(MBOX_COMMAND_PARAM_ERROR)) { xname = "COMMAND PARAMETER ERROR"; } break; case MBOX_LOOP_ID_USED: - if (logmask & MBLOGMASK(MBOX_LOOP_ID_USED)) { + if (mbp->logval & MBLOGMASK(MBOX_LOOP_ID_USED)) { xname = "LOOP ID ALREADY IN USE"; } break; case MBOX_PORT_ID_USED: - if (logmask & MBLOGMASK(MBOX_PORT_ID_USED)) { + if (mbp->logval & MBLOGMASK(MBOX_PORT_ID_USED)) { xname = "PORT ID ALREADY IN USE"; } break; case MBOX_ALL_IDS_USED: - if (logmask & MBLOGMASK(MBOX_ALL_IDS_USED)) { + if (mbp->logval & MBLOGMASK(MBOX_ALL_IDS_USED)) { xname = "ALL LOOP IDS IN USE"; } break; - case 0: /* special case */ + case MBOX_REGS_BUSY: + xname = "REGISTERS BUSY"; + break; + case MBOX_TIMEOUT: xname = "TIMEOUT"; break; default: @@ -5705,7 +6855,8 @@ isp_fw_state(ispsoftc_t *isp) MEMZERO(&mbs, sizeof (mbs)); mbs.param[0] = MBOX_GET_FW_STATE; - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { fcp->isp_fwstate = mbs.param[1]; } @@ -5767,17 +6918,16 @@ isp_update_bus(ispsoftc_t *isp, int bus) */ if (sdp->isp_devparam[tgt].dev_refresh) { mbs.param[0] = MBOX_GET_TARGET_PARAMS; - sdp->isp_devparam[tgt].dev_refresh = 0; get = 1; } else if (sdp->isp_devparam[tgt].dev_update) { mbs.param[0] = MBOX_SET_TARGET_PARAMS; + /* * Make sure goal_flags has "Renegotiate on Error" * on and "Freeze Queue on Error" off. */ sdp->isp_devparam[tgt].goal_flags |= DPARM_RENEG; sdp->isp_devparam[tgt].goal_flags &= ~DPARM_QFRZ; - mbs.param[2] = sdp->isp_devparam[tgt].goal_flags; /* @@ -5811,26 +6961,31 @@ isp_update_bus(ispsoftc_t *isp, int bus) "bus %d set tgt %d flags 0x%x off 0x%x period 0x%x", bus, tgt, mbs.param[2], mbs.param[3] >> 8, mbs.param[3] & 0xff); - sdp->isp_devparam[tgt].dev_update = 0; - sdp->isp_devparam[tgt].dev_refresh = 1; get = 0; } else { continue; } mbs.param[1] = (bus << 15) | (tgt << 8); - isp_mboxcmd(isp, &mbs, MBLOGALL); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + continue; + } if (get == 0) { isp->isp_sendmarker |= (1 << bus); - continue; + sdp->isp_devparam[tgt].dev_update = 0; + sdp->isp_devparam[tgt].dev_refresh = 1; + } else { + sdp->isp_devparam[tgt].dev_refresh = 0; + flags = mbs.param[2]; + period = mbs.param[3] & 0xff; + offset = mbs.param[3] >> 8; + sdp->isp_devparam[tgt].actv_flags = flags; + sdp->isp_devparam[tgt].actv_period = period; + sdp->isp_devparam[tgt].actv_offset = offset; + get = (bus << 16) | tgt; + (void) isp_async(isp, ISPASYNC_NEW_TGT_PARAMS, &get); } - flags = mbs.param[2]; - period = mbs.param[3] & 0xff; - offset = mbs.param[3] >> 8; - sdp->isp_devparam[tgt].actv_flags = flags; - sdp->isp_devparam[tgt].actv_period = period; - sdp->isp_devparam[tgt].actv_offset = offset; - get = (bus << 16) | tgt; - (void) isp_async(isp, ISPASYNC_NEW_TGT_PARAMS, &get); } for (tgt = 0; tgt < MAX_TARGETS; tgt++) { @@ -5871,15 +7026,16 @@ isp_setdfltparm(ispsoftc_t *isp, int channel) fcp->isp_retry_count = ICB_DFLT_RCOUNT; /* Platform specific.... */ fcp->isp_loopid = DEFAULT_LOOPID(isp); - fcp->isp_nodewwn = DEFAULT_NODEWWN(isp); - fcp->isp_portwwn = DEFAULT_PORTWWN(isp); + fcp->isp_wwnn_nvram = DEFAULT_NODEWWN(isp); + fcp->isp_wwpn_nvram = DEFAULT_PORTWWN(isp); fcp->isp_fwoptions = 0; fcp->isp_fwoptions |= ICBOPT_FAIRNESS; fcp->isp_fwoptions |= ICBOPT_PDBCHANGE_AE; fcp->isp_fwoptions |= ICBOPT_HARD_ADDRESS; fcp->isp_fwoptions |= ICBOPT_FAST_POST; - if (isp->isp_confopts & ISP_CFG_FULL_DUPLEX) + if (isp->isp_confopts & ISP_CFG_FULL_DUPLEX) { fcp->isp_fwoptions |= ICBOPT_FULL_DUPLEX; + } /* * Make sure this is turned off now until we get @@ -5889,7 +7045,7 @@ isp_setdfltparm(ispsoftc_t *isp, int channel) /* * Now try and read NVRAM unless told to not do so. - * This will set fcparam's isp_nodewwn && isp_portwwn. + * This will set fcparam's isp_wwnn_nvram && isp_wwpn_nvram. */ if ((isp->isp_confopts & ISP_CFG_NONVRAM) == 0) { nvfail = isp_read_nvram(isp); @@ -5918,10 +7074,10 @@ isp_setdfltparm(ispsoftc_t *isp, int channel) * We always start out with values derived * from NVRAM or our platform default. */ - ISP_NODEWWN(isp) = fcp->isp_nodewwn; - if (fcp->isp_nodewwn == 0) { + ISP_NODEWWN(isp) = fcp->isp_wwnn_nvram; + if (fcp->isp_wwnn_nvram == 0) { isp_prt(isp, ISP_LOGCONFIG, - "bad WWNN- using default\n"); + "bad WWNN- using default"); ISP_NODEWWN(isp) = DEFAULT_NODEWWN(isp); } } @@ -5935,10 +7091,10 @@ isp_setdfltparm(ispsoftc_t *isp, int channel) * We always start out with values derived * from NVRAM or our platform default. */ - ISP_PORTWWN(isp) = fcp->isp_portwwn; - if (fcp->isp_portwwn == 0) { + ISP_PORTWWN(isp) = fcp->isp_wwpn_nvram; + if (fcp->isp_wwpn_nvram == 0) { isp_prt(isp, ISP_LOGCONFIG, - "bad WWPN- using default\n"); + "bad WWPN- using default"); ISP_PORTWWN(isp) = DEFAULT_PORTWWN(isp); } } @@ -6005,7 +7161,8 @@ isp_setdfltparm(ispsoftc_t *isp, int channel) MEMZERO(&mbs, sizeof (mbs)); mbs.param[0] = MBOX_GET_ACT_NEG_STATE; - isp_mboxcmd(isp, &mbs, MBLOGNONE); + mbs.logval = MBLOGNONE; + isp_mboxcmd(isp, &mbs); if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { sdp->isp_req_ack_active_neg = 1; sdp->isp_data_line_active_neg = 1; @@ -6082,18 +7239,16 @@ isp_setdfltparm(ispsoftc_t *isp, int channel) * Re-initialize the ISP and complete all orphaned commands * with a 'botched' notice. The reset/init routines should * not disturb an already active list of commands. - * - * Locks held prior to coming here. */ void isp_reinit(ispsoftc_t *isp) { XS_T *xs; - int i; + uint32_t tmp; if (IS_FC(isp)) { - isp_mark_getpdb_all(isp); + ISP_MARK_PORTDB(isp, 0); } isp_reset(isp); if (isp->isp_state != ISP_RESETSTATE) { @@ -6106,17 +7261,36 @@ isp_reinit(ispsoftc_t *isp) if (isp->isp_state != ISP_RUNSTATE) { isp_prt(isp, ISP_LOGERR, "isp_reinit cannot restart card"); + ISP_DISABLE_INTS(isp); } - } + } else { + ISP_DISABLE_INTS(isp); + if (IS_FC(isp)) { + /* + * If we're in ISP_ROLE_NONE, turn off the lasers. + */ + if (!IS_24XX(isp)) { + ISP_WRITE(isp, BIU2100_CSR, BIU2100_FPM0_REGS); + ISP_WRITE(isp, FPM_DIAG_CONFIG, FPM_SOFT_RESET); + ISP_WRITE(isp, BIU2100_CSR, BIU2100_FB_REGS); + ISP_WRITE(isp, FBM_CMD, FBMCMD_FIFO_RESET_ALL); + ISP_WRITE(isp, BIU2100_CSR, BIU2100_RISC_REGS); + } + } + } isp->isp_nactive = 0; - for (i = 0; i < isp->isp_maxcmds; i++) { - uint16_t handle; - xs = isp->isp_xflist[i]; + for (tmp = 0; tmp < isp->isp_maxcmds; tmp++) { + uint32_t handle; + + xs = isp->isp_xflist[tmp]; if (xs == NULL) { continue; } - handle = isp_index_handle(i); + handle = isp_find_handle(isp, xs); + if (handle == 0) { + continue; + } isp_destroy_handle(isp, handle); if (XS_XFRLEN(xs)) { ISP_DMAFREE(isp, xs, handle); @@ -6127,6 +7301,9 @@ isp_reinit(ispsoftc_t *isp) XS_SETERR(xs, HBA_BUSRESET); isp_done(xs); } +#ifdef ISP_TARGET_MODE + MEMZERO(isp->isp_tgtlist, isp->isp_maxcmds * sizeof (void **)); +#endif } /* @@ -6144,7 +7321,9 @@ isp_read_nvram(ispsoftc_t *isp) #define nvram_data _n._x #define nvram_words _n._s - if (IS_FC(isp)) { + if (IS_24XX(isp)) { + return (isp_read_nvram_2400(isp)); + } else if (IS_FC(isp)) { amt = ISP2100_NVRAM_SIZE; minversion = 1; } else if (IS_ULTRA2(isp)) { @@ -6155,13 +7334,10 @@ isp_read_nvram(ispsoftc_t *isp) minversion = 2; } - /* - * Just read the first two words first to see if we have a valid - * NVRAM to continue reading the rest with. - */ - for (i = 0; i < 2; i++) { + for (i = 0; i < amt>>1; i++) { isp_rdnvram_word(isp, i, &nvram_words[i]); } + if (nvram_data[0] != 'I' || nvram_data[1] != 'S' || nvram_data[2] != 'P') { if (isp->isp_bustype != ISP_BT_SBUS) { @@ -6172,9 +7348,7 @@ isp_read_nvram(ispsoftc_t *isp) retval = -1; goto out; } - for (i = 2; i < amt>>1; i++) { - isp_rdnvram_word(isp, i, &nvram_words[i]); - } + for (csum = 0, i = 0; i < amt; i++) { csum += nvram_data[i]; } @@ -6183,6 +7357,7 @@ isp_read_nvram(ispsoftc_t *isp) retval = -1; goto out; } + if (ISP_NVRAM_VERSION(nvram_data) < minversion) { isp_prt(isp, ISP_LOGWARN, "version %d NVRAM not understood", ISP_NVRAM_VERSION(nvram_data)); @@ -6211,6 +7386,43 @@ out: #undef nvram_words } +static int +isp_read_nvram_2400(ispsoftc_t *isp) +{ + uint8_t *nvram_data = FCPARAM(isp)->isp_scratch; + int retval = 0; + uint32_t addr, csum, lwrds, *dptr; + + if (isp->isp_port) { + addr = ISP2400_NVRAM_PORT1_ADDR; + } else { + addr = ISP2400_NVRAM_PORT0_ADDR; + } + + dptr = (uint32_t *) nvram_data; + for (lwrds = 0; lwrds < ISP2400_NVRAM_SIZE >> 2; lwrds++) { + isp_rd_2400_nvram(isp, addr++, dptr++); + } + if (nvram_data[0] != 'I' || nvram_data[1] != 'S' || + nvram_data[2] != 'P') { + isp_prt(isp, ISP_LOGWARN, "invalid NVRAM header"); + retval = -1; + goto out; + } + dptr = (uint32_t *) nvram_data; + for (csum = 0, lwrds = 0; lwrds < ISP2400_NVRAM_SIZE >> 2; lwrds++) { + csum += dptr[lwrds]; + } + if (csum != 0) { + isp_prt(isp, ISP_LOGWARN, "invalid NVRAM checksum"); + retval = -1; + goto out; + } + isp_parse_nvram_2400(isp, nvram_data); +out: + return (retval); +} + static void isp_rdnvram_word(ispsoftc_t *isp, int wo, uint16_t *rp) { @@ -6283,6 +7495,29 @@ isp_rdnvram_word(ispsoftc_t *isp, int wo, uint16_t *rp) } static void +isp_rd_2400_nvram(ispsoftc_t *isp, uint32_t addr, uint32_t *rp) +{ + int loops = 0; + const uint32_t base = 0x7ffe0000; + uint32_t tmp; + + ISP_WRITE(isp, BIU2400_FLASH_ADDR, base | addr); + for (loops = 0; loops < 5000; loops++) { + USEC_DELAY(10); + tmp = ISP_READ(isp, BIU2400_FLASH_ADDR); + if ((tmp & (1U << 31)) != 0) { + break; + } + } + if (tmp & (1U << 31)) { + tmp = ISP_READ(isp, BIU2400_FLASH_DATA); + *rp = tmp; + } else { + *rp = 0xffffffff; + } +} + +static void isp_parse_nvram_1020(ispsoftc_t *isp, uint8_t *nvram_data) { sdparam *sdp = (sdparam *) isp->isp_param; @@ -6592,9 +7827,41 @@ isp_parse_nvram_12160(ispsoftc_t *isp, int bus, uint8_t *nvram_data) } static void +isp_fix_nvram_wwns(ispsoftc_t *isp) +{ + fcparam *fcp = FCPARAM(isp); + + /* + * Make sure we have both Node and Port as non-zero values. + */ + if (fcp->isp_wwnn_nvram != 0 && fcp->isp_wwpn_nvram == 0) { + fcp->isp_wwpn_nvram = fcp->isp_wwnn_nvram; + } else if (fcp->isp_wwnn_nvram == 0 && fcp->isp_wwpn_nvram != 0) { + fcp->isp_wwnn_nvram = fcp->isp_wwpn_nvram; + } + + /* + * Make the Node and Port values sane if they're NAA == 2. + * This means to clear bits 48..56 for the Node WWN and + * make sure that there's some non-zero value in 48..56 + * for the Port WWN. + */ + if (fcp->isp_wwnn_nvram && fcp->isp_wwpn_nvram) { + if ((fcp->isp_wwnn_nvram & (((uint64_t) 0xfff) << 48)) != 0 && + (fcp->isp_wwnn_nvram >> 60) == 2) { + fcp->isp_wwnn_nvram &= ~((uint64_t) 0xfff << 48); + } + if ((fcp->isp_wwpn_nvram & (((uint64_t) 0xfff) << 48)) == 0 && + (fcp->isp_wwpn_nvram >> 60) == 2) { + fcp->isp_wwpn_nvram |= ((uint64_t) 1 << 56); + } + } +} + +static void isp_parse_nvram_2100(ispsoftc_t *isp, uint8_t *nvram_data) { - fcparam *fcp = (fcparam *) isp->isp_param; + fcparam *fcp = FCPARAM(isp); uint64_t wwn; /* @@ -6616,7 +7883,7 @@ isp_parse_nvram_2100(ispsoftc_t *isp, uint8_t *nvram_data) wwn |= (((uint64_t) 2)<< 60); } } - fcp->isp_portwwn = wwn; + fcp->isp_wwpn_nvram = wwn; if (IS_2200(isp) || IS_23XX(isp)) { wwn = ISP2100_NVRAM_NODE_NAME(nvram_data); if (wwn) { @@ -6630,54 +7897,28 @@ isp_parse_nvram_2100(ispsoftc_t *isp, uint8_t *nvram_data) } else { wwn &= ~((uint64_t) 0xfff << 48); } - fcp->isp_nodewwn = wwn; + fcp->isp_wwnn_nvram = wwn; - /* - * Make sure we have both Node and Port as non-zero values. - */ - if (fcp->isp_nodewwn != 0 && fcp->isp_portwwn == 0) { - fcp->isp_portwwn = fcp->isp_nodewwn; - } else if (fcp->isp_nodewwn == 0 && fcp->isp_portwwn != 0) { - fcp->isp_nodewwn = fcp->isp_portwwn; - } + isp_fix_nvram_wwns(isp); - /* - * Make the Node and Port values sane if they're NAA == 2. - * This means to clear bits 48..56 for the Node WWN and - * make sure that there's some non-zero value in 48..56 - * for the Port WWN. - */ - if (fcp->isp_nodewwn && fcp->isp_portwwn) { - if ((fcp->isp_nodewwn & (((uint64_t) 0xfff) << 48)) != 0 && - (fcp->isp_nodewwn >> 60) == 2) { - fcp->isp_nodewwn &= ~((uint64_t) 0xfff << 48); - } - if ((fcp->isp_portwwn & (((uint64_t) 0xfff) << 48)) == 0 && - (fcp->isp_portwwn >> 60) == 2) { - fcp->isp_portwwn |= ((uint64_t) 1 << 56); - } + fcp->isp_maxalloc = ISP2100_NVRAM_MAXIOCBALLOCATION(nvram_data); + if ((isp->isp_confopts & ISP_CFG_OWNFSZ) == 0) { + fcp->isp_maxfrmlen = ISP2100_NVRAM_MAXFRAMELENGTH(nvram_data); } - - fcp->isp_maxalloc = - ISP2100_NVRAM_MAXIOCBALLOCATION(nvram_data); - if ((isp->isp_confopts & ISP_CFG_OWNFSZ) == 0) - fcp->isp_maxfrmlen = - ISP2100_NVRAM_MAXFRAMELENGTH(nvram_data); - fcp->isp_retry_delay = - ISP2100_NVRAM_RETRY_DELAY(nvram_data); - fcp->isp_retry_count = - ISP2100_NVRAM_RETRY_COUNT(nvram_data); - if ((isp->isp_confopts & ISP_CFG_OWNLOOPID) == 0) - fcp->isp_loopid = - ISP2100_NVRAM_HARDLOOPID(nvram_data); - if ((isp->isp_confopts & ISP_CFG_OWNEXCTHROTTLE) == 0) + fcp->isp_retry_delay = ISP2100_NVRAM_RETRY_DELAY(nvram_data); + fcp->isp_retry_count = ISP2100_NVRAM_RETRY_COUNT(nvram_data); + if ((isp->isp_confopts & ISP_CFG_OWNLOOPID) == 0) { + fcp->isp_loopid = ISP2100_NVRAM_HARDLOOPID(nvram_data); + } + if ((isp->isp_confopts & ISP_CFG_OWNEXCTHROTTLE) == 0) { fcp->isp_execthrottle = ISP2100_NVRAM_EXECUTION_THROTTLE(nvram_data); + } fcp->isp_fwoptions = ISP2100_NVRAM_OPTIONS(nvram_data); isp_prt(isp, ISP_LOGDEBUG0, "NVRAM 0x%08x%08x 0x%08x%08x maxalloc %d maxframelen %d", - (uint32_t) (fcp->isp_nodewwn >> 32), (uint32_t) fcp->isp_nodewwn, - (uint32_t) (fcp->isp_portwwn >> 32), (uint32_t) fcp->isp_portwwn, + (uint32_t) (fcp->isp_wwnn_nvram >> 32), (uint32_t) fcp->isp_wwnn_nvram, + (uint32_t) (fcp->isp_wwpn_nvram >> 32), (uint32_t) fcp->isp_wwpn_nvram, ISP2100_NVRAM_MAXIOCBALLOCATION(nvram_data), ISP2100_NVRAM_MAXFRAMELENGTH(nvram_data)); isp_prt(isp, ISP_LOGDEBUG0, @@ -6693,6 +7934,64 @@ isp_parse_nvram_2100(ispsoftc_t *isp, uint8_t *nvram_data) ISP2100_XFW_OPTIONS(nvram_data), ISP2100_ZFW_OPTIONS(nvram_data)); } +static void +isp_parse_nvram_2400(ispsoftc_t *isp, uint8_t *nvram_data) +{ + fcparam *fcp = FCPARAM(isp); + uint64_t wwn; + + isp_prt(isp, ISP_LOGDEBUG0, + "NVRAM 0x%08x%08x 0x%08x%08x exchg_cnt %d maxframelen %d", + (uint32_t) (ISP2400_NVRAM_NODE_NAME(nvram_data) >> 32), + (uint32_t) (ISP2400_NVRAM_NODE_NAME(nvram_data)), + (uint32_t) (ISP2400_NVRAM_PORT_NAME(nvram_data) >> 32), + (uint32_t) (ISP2400_NVRAM_PORT_NAME(nvram_data)), + ISP2400_NVRAM_EXCHANGE_COUNT(nvram_data), + ISP2400_NVRAM_MAXFRAMELENGTH(nvram_data)); + isp_prt(isp, ISP_LOGDEBUG0, + "NVRAM execthr %d loopid %d fwopt1 0x%x fwopt2 0x%x fwopt3 0x%x", + ISP2400_NVRAM_EXECUTION_THROTTLE(nvram_data), + ISP2400_NVRAM_HARDLOOPID(nvram_data), + ISP2400_NVRAM_FIRMWARE_OPTIONS1(nvram_data), + ISP2400_NVRAM_FIRMWARE_OPTIONS2(nvram_data), + ISP2400_NVRAM_FIRMWARE_OPTIONS3(nvram_data)); + + wwn = ISP2400_NVRAM_PORT_NAME(nvram_data); + if (wwn) { + if ((wwn >> 60) != 2 && (wwn >> 60) != 5) { + wwn = 0; + } + } + fcp->isp_wwpn_nvram = wwn; + + wwn = ISP2400_NVRAM_NODE_NAME(nvram_data); + if (wwn) { + if ((wwn >> 60) != 2 && (wwn >> 60) != 5) { + wwn = 0; + } + } + fcp->isp_wwnn_nvram = wwn; + + isp_fix_nvram_wwns(isp); + + if (ISP2400_NVRAM_EXCHANGE_COUNT(nvram_data)) { + fcp->isp_maxalloc = ISP2400_NVRAM_EXCHANGE_COUNT(nvram_data); + } + if ((isp->isp_confopts & ISP_CFG_OWNFSZ) == 0) { + fcp->isp_maxfrmlen = ISP2400_NVRAM_MAXFRAMELENGTH(nvram_data); + } + if ((isp->isp_confopts & ISP_CFG_OWNLOOPID) == 0) { + fcp->isp_loopid = ISP2400_NVRAM_HARDLOOPID(nvram_data); + } + if ((isp->isp_confopts & ISP_CFG_OWNEXCTHROTTLE) == 0) { + fcp->isp_execthrottle = + ISP2400_NVRAM_EXECUTION_THROTTLE(nvram_data); + } + fcp->isp_fwoptions = ISP2400_NVRAM_FIRMWARE_OPTIONS1(nvram_data); + fcp->isp_xfwoptions = ISP2400_NVRAM_FIRMWARE_OPTIONS2(nvram_data); + fcp->isp_zfwoptions = ISP2400_NVRAM_FIRMWARE_OPTIONS3(nvram_data); +} + #ifdef ISP_FW_CRASH_DUMP static void isp2200_fw_dump(ispsoftc_t *); static void isp2300_fw_dump(ispsoftc_t *); @@ -6823,7 +8122,7 @@ isp2200_fw_dump(ispsoftc_t *isp) break; } } - ENABLE_INTS(isp); + ISP_ENABLE_INTS(isp); mbs.param[0] = MBOX_READ_RAM_WORD; mbs.param[1] = 0x1000; isp->isp_mbxworkp = (void *) ptr; @@ -6966,7 +8265,7 @@ isp2300_fw_dump(ispsoftc_t *isp) isp_prt(isp, ISP_LOGERR, "Board Would Not Reset"); return; } - ENABLE_INTS(isp); + ISP_ENABLE_INTS(isp); MEMZERO(&mbs, sizeof (mbs)); mbs.param[0] = MBOX_READ_RAM_WORD; mbs.param[1] = 0x800; @@ -7008,5 +8307,8 @@ isp_fw_dump(ispsoftc_t *isp) isp2200_fw_dump(isp); else if (IS_23XX(isp)) isp2300_fw_dump(isp); + else if (IS_24XX(isp)) + isp_prt(isp, ISP_LOGERR, "24XX dump method undefined"); + } #endif |
