summaryrefslogtreecommitdiff
path: root/sys/dev/ic/isp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ic/isp.c')
-rw-r--r--sys/dev/ic/isp.c5707
1 files changed, 3656 insertions, 2051 deletions
diff --git a/sys/dev/ic/isp.c b/sys/dev/ic/isp.c
index 8ccfe47c05f..2d0f10fdd18 100644
--- a/sys/dev/ic/isp.c
+++ b/sys/dev/ic/isp.c
@@ -1,33 +1,35 @@
-/* $OpenBSD: isp.c,v 1.45 2009/06/03 05:11:09 krw Exp $ */
+/* $OpenBSD: isp.c,v 1.46 2009/06/24 11:00:53 krw Exp $ */
/* $FreeBSD: src/sys/dev/isp/isp.c,v 1.150 2008/12/15 21:42:38 marius Exp $*/
+/*-
+ * Copyright (c) 1997-2007 by Matthew Jacob
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
/*
* Machine and OS Independent (well, as best as possible)
- * code for the QLogic ISP SCSI adapters.
- *
- * Copyright (c) 1997, 1998, 1999, 2000, 2001 by Matthew Jacob
- * Feral Software
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice immediately at the beginning of the file, without modification,
- * this list of conditions, and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * code for the Qlogic ISP SCSI and FC-SCSI adapters.
*/
/*
@@ -39,11 +41,14 @@
/*
* Include header file appropriate for platform we're building on.
*/
-
#ifdef __NetBSD__
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
#include <dev/ic/isp_netbsd.h>
#endif
#ifdef __FreeBSD__
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/isp/isp.c,v 1.149 2007/07/10 07:55:04 mjacob Exp $");
#include <dev/isp/isp_freebsd.h>
#endif
#ifdef __OpenBSD__
@@ -61,30 +66,16 @@
*/
#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[] =
@@ -96,11 +87,11 @@ static const char xact3[] =
static const char pskip[] =
"SCSI phase skipped for target %d.%d.%d";
static const char topology[] =
- "Loop ID %d, AL_PA 0x%x, Port ID 0x%x, Loop State 0x%x, Topology '%s'";
-static const char swrej[] =
- "Fabric Nameserver rejected %s (Reason=0x%x Expl=0x%x) for Port ID 0x%x";
+ "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 %lu STS 0x%x SKEY %c XS_ERR=0x%x";
+ "%d.%d.%d: FIN dl%d resid %d STS 0x%x SKEY %c XS_ERR=0x%x";
static const char sc0[] =
"%s CHAN %d FTHRSH %d IID %d RESETD %d RETRYC %d RETRYD %d ASD 0x%x";
static const char sc1[] =
@@ -114,40 +105,54 @@ static const char bun[] =
/*
* Local function prototypes.
*/
-static int isp_parse_async(struct ispsoftc *, u_int16_t);
-static int isp_handle_other_response(struct ispsoftc *, int, isphdr_t *,
- u_int16_t *);
-static void
-isp_parse_status(struct ispsoftc *, ispstatusreq_t *, XS_T *);
-static void isp_fastpost_complete(struct ispsoftc *, u_int16_t);
-static int isp_mbox_continue(struct ispsoftc *);
-static void isp_scsi_init(struct ispsoftc *);
-static void isp_scsi_channel_init(struct ispsoftc *, int);
-static void isp_fibre_init(struct ispsoftc *);
-static void isp_mark_getpdb_all(struct ispsoftc *);
-static int isp_getmap(struct ispsoftc *, fcpos_map_t *);
-static int isp_getpdb(struct ispsoftc *, int, isp_pdb_t *);
-static u_int64_t isp_get_portname(struct ispsoftc *, int, int);
-static int isp_fclink_test(struct ispsoftc *, int);
-static char *isp2100_fw_statename(int);
-static int isp_pdb_sync(struct ispsoftc *);
-static int isp_scan_loop(struct ispsoftc *);
-static int isp_fabric_mbox_cmd(struct ispsoftc *, mbreg_t *);
-static int isp_scan_fabric(struct ispsoftc *, int);
-static void isp_register_fc4_type(struct ispsoftc *);
-static void isp_fw_state(struct ispsoftc *);
-static void isp_mboxcmd_qnw(struct ispsoftc *, mbreg_t *, int);
-static void isp_mboxcmd(struct ispsoftc *, mbreg_t *, int);
-
-static void isp_update(struct ispsoftc *);
-static void isp_update_bus(struct ispsoftc *, int);
-static void isp_setdfltparm(struct ispsoftc *, int);
-static int isp_read_nvram(struct ispsoftc *);
-static void isp_rdnvram_word(struct ispsoftc *, int, u_int16_t *);
-static void isp_parse_nvram_1020(struct ispsoftc *, u_int8_t *);
-static void isp_parse_nvram_1080(struct ispsoftc *, int, u_int8_t *);
-static void isp_parse_nvram_12160(struct ispsoftc *, int, u_int8_t *);
-static void isp_parse_nvram_2100(struct ispsoftc *, u_int8_t *);
+int isp_parse_async(struct ispsoftc *, u_int16_t);
+int isp_handle_other_response(struct ispsoftc *, int, isphdr_t *,
+ u_int32_t *);
+void
+isp_parse_status(struct ispsoftc *, ispstatusreq_t *, XS_T *, long *);
+void
+isp_parse_status_24xx(struct ispsoftc *, isp24xx_statusreq_t *, XS_T *, long *);
+void isp_fastpost_complete(struct ispsoftc *, u_int16_t);
+int isp_mbox_continue(struct ispsoftc *);
+void isp_scsi_init(struct ispsoftc *);
+void isp_scsi_channel_init(struct ispsoftc *, int);
+void isp_fibre_init(struct ispsoftc *);
+void isp_fibre_init_2400(struct ispsoftc *);
+void isp_mark_portdb(struct ispsoftc *, int);
+int isp_plogx(struct ispsoftc *, u_int16_t, u_int32_t, int, int);
+int isp_port_login(struct ispsoftc *, u_int16_t, u_int32_t);
+int isp_port_logout(struct ispsoftc *, u_int16_t, u_int32_t);
+int isp_getpdb(struct ispsoftc *, u_int16_t, isp_pdb_t *, int);
+u_int64_t isp_get_portname(struct ispsoftc *, int, int);
+int isp_fclink_test(struct ispsoftc *, int);
+const char *ispfc_fw_statename(int);
+int isp_pdb_sync(struct ispsoftc *);
+int isp_scan_loop(struct ispsoftc *);
+int isp_gid_ft_sns(struct ispsoftc *);
+int isp_gid_ft_ct_passthru(struct ispsoftc *);
+int isp_scan_fabric(struct ispsoftc *);
+int isp_login_device(struct ispsoftc *, u_int32_t, isp_pdb_t *, u_int16_t *);
+int isp_register_fc4_type(struct ispsoftc *);
+int isp_register_fc4_type_24xx(struct ispsoftc *);
+u_int16_t isp_nxt_handle(struct ispsoftc *, u_int16_t);
+void isp_fw_state(struct ispsoftc *);
+void isp_mboxcmd_qnw(struct ispsoftc *, mbreg_t *, int);
+void isp_mboxcmd(struct ispsoftc *, mbreg_t *);
+
+void isp_update(struct ispsoftc *);
+void isp_update_bus(struct ispsoftc *, int);
+void isp_setdfltparm(struct ispsoftc *, int);
+void isp_setdfltfcparm(struct ispsoftc *);
+int isp_read_nvram(struct ispsoftc *);
+int isp_read_nvram_2400(struct ispsoftc *);
+void isp_rdnvram_word(struct ispsoftc *, int, u_int16_t *);
+void isp_rd_2400_nvram(struct ispsoftc *, u_int32_t, u_int32_t *);
+void isp_parse_nvram_1020(struct ispsoftc *, u_int8_t *);
+void isp_parse_nvram_1080(struct ispsoftc *, int, u_int8_t *);
+void isp_parse_nvram_12160(struct ispsoftc *, int, u_int8_t *);
+void isp_fix_nvram_wwns(struct ispsoftc *);
+void isp_parse_nvram_2100(struct ispsoftc *, u_int8_t *);
+void isp_parse_nvram_2400(struct ispsoftc *, u_int8_t *);
/*
* Reset Hardware.
@@ -161,9 +166,10 @@ void
isp_reset(struct ispsoftc *isp)
{
mbreg_t mbs;
- u_int16_t code_org;
+ u_int32_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;
@@ -203,10 +209,16 @@ isp_reset(struct ispsoftc *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];
@@ -216,13 +228,47 @@ isp_reset(struct ispsoftc *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;
@@ -238,7 +284,13 @@ isp_reset(struct ispsoftc *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) {
@@ -254,17 +306,27 @@ isp_reset(struct ispsoftc *isp)
case ISP_HA_FC_2312:
btype = "2312";
break;
+ case ISP_HA_FC_2322:
+ btype = "2322";
+ break;
+ 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";
@@ -447,8 +509,6 @@ isp_reset(struct ispsoftc *isp)
*/
ISP_RESET0(isp);
-again:
-
/*
* Hit the chip over the head with hammer,
* and give the ISP a chance to recover.
@@ -470,6 +530,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);
/*
@@ -494,8 +592,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;
@@ -503,6 +606,7 @@ again:
USEC_DELAY(100);
if (--loops < 0) {
ISP_DUMPREGS(isp, "chip reset timed out");
+ ISP_RESET0(isp);
return;
}
}
@@ -514,24 +618,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)) {
u_int16_t tmp = isp->isp_mdvec->dv_conf1;
/*
* Busted FIFO. Turn off all but burst enables.
@@ -544,30 +665,36 @@ again:
ISP_SETBITS(isp, CDMA_CONF, DMA_ENABLE_BURST);
ISP_SETBITS(isp, DDMA_CONF, DMA_ENABLE_BURST);
}
-#ifdef PTI_CARDS
- if (((sdparam *) isp->isp_param)->isp_ultramode) {
- while (ISP_READ(isp, RISC_MTR) != 0x1313) {
- ISP_WRITE(isp, RISC_MTR, 0x1313);
- ISP_WRITE(isp, HCCR, HCCR_CMD_STEP);
+ 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);
}
- /*
- * PTI specific register
- */
- ISP_WRITE(isp, RISC_EMB, DUAL_BANK)
-#else
- ISP_WRITE(isp, RISC_MTR, 0x1212);
-#endif
+ 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
@@ -580,13 +707,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;
@@ -605,12 +733,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;
@@ -618,13 +748,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],
@@ -648,26 +783,193 @@ 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
+ } else {
code_org = ISP_CODE_ORG;
+ }
+
+ if (dodnld && IS_24XX(isp)) {
+ const u_int32_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 (;;) {
+ u_int32_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]) {
+ u_int32_t *cp;
+ u_int32_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++) {
+ ISP_IOXPUT_32(isp, ptr[wi++], &cp[i]);
+ 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)) {
+ const u_int16_t *ptr = isp->isp_mdvec->dv_ispfw;
+ u_int16_t wi, wl, segno;
+ u_int32_t la;
+
+ la = code_org;
+ segno = 0;
+
+ for (;;) {
+ u_int32_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]) {
+ u_int16_t *cp;
+ u_int32_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++) {
+ ISP_IOXPUT_16(isp, ptr[wi++], &cp[i]);
+ 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.
+ */
- if (dodnld) {
- isp->isp_mbxworkp = (void *) &isp->isp_mdvec->dv_ispfw[1];
- isp->isp_mbxwrk0 = isp->isp_mdvec->dv_ispfw[3] - 1;
+ nxtaddr = ptr[3];
+ ptr = &ptr[nxtaddr];
+ la = ptr[5] | ((ptr[4] & 0x3f) << 16);
+ }
+ isp->isp_loaded_fw = 1;
+ } else if (dodnld) {
+ union {
+ const u_int16_t *cp;
+ u_int16_t *np;
+ } u;
+ u.cp = isp->isp_mdvec->dv_ispfw;
+ isp->isp_mbxworkp = &u.np[1];
+ isp->isp_mbxwrk0 = u.np[3] - 1;
isp->isp_mbxwrk1 = code_org + 1;
MEMZERO(&mbs, sizeof (mbs));
mbs.param[0] = MBOX_WRITE_RAM_WORD;
mbs.param[1] = code_org;
- mbs.param[2] = isp->isp_mdvec->dv_ispfw[0];
- isp_mboxcmd(isp, &mbs, MBLOGNONE);
+ mbs.param[2] = u.np[0];
+ 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;
}
/*
* Verify that it downloaded correctly.
@@ -675,9 +977,11 @@ again:
MEMZERO(&mbs, sizeof (mbs));
mbs.param[0] = MBOX_VERIFY_CHECKSUM;
mbs.param[1] = code_org;
- isp_mboxcmd(isp, &mbs, MBLOGNONE);
+ mbs.logval = MBLOGNONE;
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- isp_prt(isp, ISP_LOGERR, "Ram Checksum Failure");
+ isp_prt(isp, ISP_LOGERR, dcrc);
+ ISP_RESET0(isp);
return;
}
isp->isp_loaded_fw = 1;
@@ -695,13 +999,40 @@ again:
MEMZERO(&mbs, sizeof (mbs));
+ mbs.timeout = 1000000;
mbs.param[0] = MBOX_EXEC_FIRMWARE;
- mbs.param[1] = code_org;
- isp_mboxcmd(isp, &mbs, MBLOGNONE);
+ 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;
+ }
+
+ mbs.logval = MBLOGALL;
+ isp_mboxcmd(isp, &mbs);
+ if (IS_2322(isp) || IS_24XX(isp)) {
+ if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+ 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)) {
/*
@@ -711,15 +1042,24 @@ again:
MEMZERO(&mbs, sizeof (mbs));
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;
}
@@ -744,7 +1084,8 @@ again:
isp->isp_fwrev[1] = mbs.param[2];
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]);
@@ -755,9 +1096,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
@@ -768,9 +1109,27 @@ again:
isp_prt(isp, ISP_LOGDEBUG0,
"Firmware Attributes = 0x%x", mbs.param[6]);
}
- if (ISP_READ(isp, BIU2100_CSR) & BIU2100_PCI64) {
- isp_prt(isp, ISP_LOGCONFIG,
- "Installed in 64-Bit PCI slot");
+ 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");
}
}
@@ -781,24 +1140,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;
/*
@@ -829,12 +1187,24 @@ 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.
+ */
+ if (IS_SCSI(isp)) {
+ isp_setdfltparm(isp, 0);
+ if (IS_DUALBUS(isp)) {
+ isp_setdfltparm(isp, 1);
+ }
+ } else {
+ isp_setdfltfcparm(isp);
+ }
+
}
/*
@@ -846,21 +1216,27 @@ again:
void
isp_init(struct ispsoftc *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);
}
}
-static void
+void
isp_scsi_init(struct ispsoftc *isp)
{
sdparam *sdp_chan0, *sdp_chan1;
@@ -898,8 +1274,8 @@ isp_scsi_init(struct ispsoftc *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;
}
@@ -911,7 +1287,8 @@ isp_scsi_init(struct ispsoftc *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;
}
@@ -927,8 +1304,8 @@ isp_scsi_init(struct ispsoftc *isp)
mbs.param[2] =
(sdp_chan1->isp_req_ack_active_neg << 4) |
(sdp_chan1->isp_data_line_active_neg << 5);
-
- 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)",
@@ -948,7 +1325,8 @@ isp_scsi_init(struct ispsoftc *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);
@@ -962,7 +1340,8 @@ isp_scsi_init(struct ispsoftc *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;
}
@@ -985,7 +1364,8 @@ isp_scsi_init(struct ispsoftc *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;
}
@@ -999,7 +1379,8 @@ isp_scsi_init(struct ispsoftc *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;
}
@@ -1011,7 +1392,8 @@ isp_scsi_init(struct ispsoftc *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;
}
@@ -1023,7 +1405,8 @@ isp_scsi_init(struct ispsoftc *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;
}
@@ -1048,14 +1431,13 @@ isp_scsi_init(struct ispsoftc *isp)
if (IS_ULTRA2(isp) || IS_1240(isp))
mbs.param[1] |= FW_FEATURE_RIO_16BIT;
#else
-#ifndef ISP_NO_FASTPOST
if (IS_ULTRA2(isp) || IS_1240(isp))
mbs.param[1] |= FW_FEATURE_FAST_POST;
#endif
-#endif
if (mbs.param[1] != 0) {
u_int16_t sfeat = mbs.param[1];
- isp_mboxcmd(isp, &mbs, MBLOGALL);
+ 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);
@@ -1068,7 +1450,7 @@ isp_scsi_init(struct ispsoftc *isp)
isp->isp_state = ISP_INITSTATE;
}
-static void
+void
isp_scsi_channel_init(struct ispsoftc *isp, int channel)
{
sdparam *sdp;
@@ -1084,7 +1466,8 @@ isp_scsi_channel_init(struct ispsoftc *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;
}
@@ -1140,7 +1523,8 @@ isp_scsi_channel_init(struct ispsoftc *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));
@@ -1148,7 +1532,8 @@ isp_scsi_channel_init(struct ispsoftc *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;
}
@@ -1172,7 +1557,8 @@ isp_scsi_channel_init(struct ispsoftc *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;
}
@@ -1189,37 +1575,21 @@ isp_scsi_channel_init(struct ispsoftc *isp, int channel)
/*
* Fibre Channel specific initialization.
- *
- * Locks are held before coming here.
*/
-static void
+void
isp_fibre_init(struct ispsoftc *isp)
{
fcparam *fcp;
isp_icb_t local, *icbp = &local;
mbreg_t mbs;
- int loopid;
+ int ownloopid;
u_int64_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
@@ -1231,8 +1601,8 @@ isp_fibre_init(struct ispsoftc *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;
}
/*
@@ -1241,27 +1611,29 @@ isp_fibre_init(struct ispsoftc *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) {
+ icbp->icb_fwoptions &= ~ICBOPT_INI_DISABLE;
+ } else {
+ 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) {
@@ -1285,7 +1657,21 @@ isp_fibre_init(struct ispsoftc *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) {
+ 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 (ownloopid || ISP_FW_NEWER_THAN(isp, 2, 2, 5)) {
+ icbp->icb_fwoptions |= ICBOPT_HARD_ADDRESS;
+ }
+
/*
* Right now we just set extended options to prefer point-to-point
* over loop based upon some soft config options.
@@ -1311,26 +1697,21 @@ isp_fibre_init(struct ispsoftc *isp)
icbp->icb_xfwoptions |= ICBXOPT_LOOP_2_PTP;
break;
}
- if (IS_23XX(isp)) {
+ if (IS_2200(isp)) {
+ icbp->icb_fwoptions &= ~ICBOPT_FAST_POST;
+ } else {
/*
* QLogic recommends that FAST Posting be turned
* off for 23XX cards and instead allow the HBA
* to write response queue entries and interrupt
* after a delay (ZIO).
- *
- * If we set ZIO, it will disable fast posting,
- * so we don't need to clear it in fwoptions.
- */
- icbp->icb_xfwoptions |= ICBXOPT_ZIO;
-#if 0
- /*
- * Values, in 100us increments. The default
- * is 2 (200us) if a value 0 (default) is
- * selected.
*/
- icbp->icb_idelaytimer = 2;
-#endif
-
+ icbp->icb_fwoptions &= ~ICBOPT_FAST_POST;
+ if ((fcp->isp_xfwoptions & ICBXOPT_TIMER_MASK) ==
+ ICBXOPT_ZIO) {
+ icbp->icb_xfwoptions |= ICBXOPT_ZIO;
+ icbp->icb_idelaytimer = 10;
+ }
if (isp->isp_confopts & ISP_CFG_ONEGB) {
icbp->icb_zfwoptions |= ICBZOPT_RATE_ONEGB;
} else if (isp->isp_confopts & ISP_CFG_TWOGB) {
@@ -1338,32 +1719,15 @@ isp_fibre_init(struct ispsoftc *isp)
} else {
icbp->icb_zfwoptions |= ICBZOPT_RATE_AUTO;
}
+ if (fcp->isp_zfwoptions & ICBZOPT_50_OHM) {
+ icbp->icb_zfwoptions |= ICBZOPT_50_OHM;
+ }
}
}
-#ifndef ISP_NO_RIO_FC
- /*
- * RIO seems to be enabled in 2100s for fw >= 1.17.0.
- *
- * I've had some questionable problems with RIO on 2200.
- * More specifically, on a 2204 I had problems with RIO
- * on a Linux system where I was dropping commands right
- * and left. It's not clear to me what the actual problem
- * was.
- *
- * 23XX Cards do not support RIO. Instead they support ZIO.
- */
-#if 0
- if (!IS_23XX(isp) && ISP_FW_NEWER_THAN(isp, 1, 17, 0)) {
- icbp->icb_xfwoptions |= ICBXOPT_RIO_16BIT;
- icbp->icb_racctimer = 4;
- icbp->icb_idelaytimer = 8;
- }
-#endif
-#endif
/*
- * For 22XX > 2.1.26 && 23XX, set someoptions.
+ * For 22XX > 2.1.26 && 23XX, set some options.
* XXX: Probably okay for newer 2100 f/w too.
*/
if (ISP_FW_NEWER_THAN(isp, 2, 26, 0)) {
@@ -1377,16 +1741,14 @@ isp_fibre_init(struct ispsoftc *isp)
mbs.param[1] = 0xb;
mbs.param[2] = 0;
mbs.param[3] = 0;
- isp_mboxcmd(isp, &mbs, MBLOGALL);
- }
- icbp->icb_logintime = 30; /* 30 second login timeout */
-
- if (IS_23XX(isp)) {
- ISP_WRITE(isp, isp->isp_rqstinrp, 0);
- ISP_WRITE(isp, isp->isp_rqstoutrp, 0);
- ISP_WRITE(isp, isp->isp_respinrp, 0);
- ISP_WRITE(isp, isp->isp_respoutrp, 0);
+ 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;
nwwn = ISP_NODEWWN(isp);
pwwn = ISP_PORTWWN(isp);
@@ -1400,12 +1762,25 @@ isp_fibre_init(struct ispsoftc *isp)
((u_int32_t) (nwwn & 0xffffffff)),
((u_int32_t) (pwwn >> 32)),
((u_int32_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",
+ ((u_int32_t) (pwwn >> 32)),
+ ((u_int32_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) {
+ isp_prt(isp, ISP_LOGERR, "bad request queue length");
+ }
icbp->icb_rsltqlen = RESULT_QUEUE_LEN(isp);
+ if (icbp->icb_rsltqlen < 1) {
+ isp_prt(isp, ISP_LOGERR, "bad result queue length");
+ }
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);
@@ -1414,6 +1789,7 @@ isp_fibre_init(struct ispsoftc *isp)
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);
+
isp_prt(isp, ISP_LOGDEBUG0,
"isp_fibre_init: fwopt 0x%x xfwopt 0x%x zfwopt 0x%x",
icbp->icb_fwoptions, icbp->icb_xfwoptions, icbp->icb_zfwoptions);
@@ -1430,17 +1806,21 @@ isp_fibre_init(struct ispsoftc *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);
- isp_mboxcmd(isp, &mbs, MBLOGALL);
+ fcp->isp_scratch, (u_int32_t) ((u_int64_t)fcp->isp_scdma >> 32),
+ (u_int32_t) fcp->isp_scdma);
+ MEMORYBARRIER(isp, SYNC_SFORDEV, 0, sizeof (*icbp));
+ 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.
@@ -1448,84 +1828,615 @@ isp_fibre_init(struct ispsoftc *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(struct ispsoftc *isp, fcpos_map_t *map)
+void
+isp_fibre_init_2400(struct ispsoftc *isp)
{
- fcparam *fcp = (fcparam *) isp->isp_param;
+ fcparam *fcp;
+ isp_icb_2400_t local, *icbp = &local;
mbreg_t mbs;
+ int ownloopid;
+ u_int64_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];
+ }
- MEMZERO(&mbs, sizeof (mbs));
- mbs.param[0] = MBOX_GET_FC_AL_POSITION_MAP;
+ 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",
+ ((u_int32_t) (nwwn >> 32)),
+ ((u_int32_t) (nwwn & 0xffffffff)),
+ ((u_int32_t) (pwwn >> 32)),
+ ((u_int32_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",
+ ((u_int32_t) (pwwn >> 32)),
+ ((u_int32_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_INIT_FIRMWARE;
mbs.param[2] = DMA_WD1(fcp->isp_scdma);
mbs.param[3] = DMA_WD0(fcp->isp_scdma);
- FC_SCRATCH_ACQUIRE(isp);
- isp_mboxcmd(isp, &mbs, MBLOGALL & ~MBOX_COMMAND_PARAM_ERROR);
- if (mbs.param[0] == MBOX_COMMAND_COMPLETE) {
- MEMCPY(map, fcp->isp_scratch, sizeof (fcpos_map_t));
- map->fwmap = mbs.param[1] != 0;
- FC_SCRATCH_RELEASE(isp);
- return (0);
- }
+ 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 %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(struct ispsoftc *isp)
+void
+isp_mark_portdb(struct ispsoftc *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.
+ */
+int
+isp_plogx(struct ispsoftc *isp, u_int16_t handle, u_int32_t portid, int flags, int gs)
+{
+ mbreg_t mbs;
+ u_int8_t q[QENTRY_LEN];
+ isp_plogx_t *plp;
+ u_int8_t *scp;
+ u_int32_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_getpdb(struct ispsoftc *isp, int id, isp_pdb_t *pdbp)
+int
+isp_port_login(struct ispsoftc *isp, u_int16_t handle, u_int32_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]);
+ }
+}
+
+int
+isp_port_logout(struct ispsoftc *isp, u_int16_t handle, u_int32_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]);
+}
+
+int
+isp_getpdb(struct ispsoftc *isp, u_int16_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));
+ MEMZERO(&mbs, sizeof (mbs));
mbs.param[0] = MBOX_GET_PORT_DB;
- mbs.param[1] = id << 8;
+ 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);
+ } else {
+ mbs.param[1] = id << 8;
+ }
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);
- 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 u_int64_t
+u_int64_t
isp_get_portname(struct ispsoftc *isp, int loopid, int nodename)
{
- u_int64_t wwn = 0;
+ u_int64_t wwn = (u_int64_t) -1;
mbreg_t mbs;
- MEMZERO(&mbs, sizeof (mbs));
+ MEMZERO(&mbs, sizeof (mbs));
mbs.param[0] = MBOX_GET_PORT_NAME;
- mbs.param[1] = loopid << 8;
- if (nodename)
- mbs.param[1] |= 1;
- isp_mboxcmd(isp, &mbs, MBLOGALL & ~MBOX_COMMAND_PARAM_ERROR);
- if (mbs.param[0] == MBOX_COMMAND_COMPLETE) {
+ if (FCPARAM(isp)->isp_2klogin || IS_24XX(isp)) {
+ mbs.param[1] = loopid;
+ mbs.ibits = (1 << 10);
+ if (nodename) {
+ mbs.param[10] = 1;
+ }
+ } else {
+ mbs.param[1] = loopid << 8;
+ if (nodename) {
+ mbs.param[1] |= 1;
+ }
+ }
+ 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 =
- (((u_int64_t)(mbs.param[2] & 0xff)) << 56) |
+ (((u_int64_t)(mbs.param[2] >> 8)) << 56) |
+ (((u_int64_t)(mbs.param[2] & 0xff)) << 48) |
+ (((u_int64_t)(mbs.param[3] >> 8)) << 40) |
+ (((u_int64_t)(mbs.param[3] & 0xff)) << 32) |
+ (((u_int64_t)(mbs.param[6] >> 8)) << 24) |
+ (((u_int64_t)(mbs.param[6] & 0xff)) << 16) |
+ (((u_int64_t)(mbs.param[7] >> 8)) << 8) |
+ (((u_int64_t)(mbs.param[7] & 0xff)));
+ } else {
+ wwn =
+ (((u_int64_t)(mbs.param[2] & 0xff)) << 56) |
(((u_int64_t)(mbs.param[2] >> 8)) << 48) |
(((u_int64_t)(mbs.param[3] & 0xff)) << 40) |
(((u_int64_t)(mbs.param[3] >> 8)) << 32) |
@@ -1538,13 +2449,13 @@ isp_get_portname(struct ispsoftc *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
+int
isp_fclink_test(struct ispsoftc *isp, int usdelay)
{
- static char *toponames[] = {
+ static const char *toponames[] = {
"Private Loop",
"FL Port",
"N-Port to N-Port",
@@ -1554,15 +2465,15 @@ isp_fclink_test(struct ispsoftc *isp, int usdelay)
mbreg_t mbs;
int count, check_for_fabric;
u_int8_t lwfs;
+ int loopid;
fcparam *fcp;
- struct lportdb *lp;
+ fcportdb_t *lp;
isp_pdb_t pdb;
fcp = isp->isp_param;
- /*
- * 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.
@@ -1577,12 +2488,14 @@ isp_fclink_test(struct ispsoftc *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) {
+ if (fcp->isp_fwstate == FW_READY &&
+ fcp->isp_loopstate >= LOOP_PDB_RCVD) {
break;
}
GET_NANOTIME(&hrb);
@@ -1631,36 +2544,38 @@ isp_fclink_test(struct ispsoftc *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);
}
- fcp->isp_loopid = mbs.param[1];
- if (IS_2200(isp) || IS_23XX(isp)) {
+
+ if (FCPARAM(isp)->isp_2klogin) {
+ fcp->isp_loopid = mbs.param[1];
+ } else {
+ fcp->isp_loopid = mbs.param[1] & 0xff;
+ }
+
+ 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;
}
- fcp->isp_portid = fcp->isp_alpa = mbs.param[2] & 0xff;
-
- /*
- * 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;
+ fcp->isp_portid = mbs.param[2] | (mbs.param[3] << 16);
if (IS_2100(isp)) {
/*
@@ -1675,122 +2590,92 @@ isp_fclink_test(struct ispsoftc *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 =
- (((u_int64_t)pdb.pdb_nodename[0]) << 56) |
- (((u_int64_t)pdb.pdb_nodename[1]) << 48) |
- (((u_int64_t)pdb.pdb_nodename[2]) << 40) |
- (((u_int64_t)pdb.pdb_nodename[3]) << 32) |
- (((u_int64_t)pdb.pdb_nodename[4]) << 24) |
- (((u_int64_t)pdb.pdb_nodename[5]) << 16) |
- (((u_int64_t)pdb.pdb_nodename[6]) << 8) |
- (((u_int64_t)pdb.pdb_nodename[7]));
- lp->port_wwn =
- (((u_int64_t)pdb.pdb_portname[0]) << 56) |
- (((u_int64_t)pdb.pdb_portname[1]) << 48) |
- (((u_int64_t)pdb.pdb_portname[2]) << 40) |
- (((u_int64_t)pdb.pdb_portname[3]) << 32) |
- (((u_int64_t)pdb.pdb_portname[4]) << 24) |
- (((u_int64_t)pdb.pdb_portname[5]) << 16) |
- (((u_int64_t)pdb.pdb_portname[6]) << 8) |
- (((u_int64_t)pdb.pdb_portname[7]));
- lp->roles =
- (pdb.pdb_prli_svc3 & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT;
- lp->portid = BITS2WORD(pdb.pdb_portid_bits);
- lp->loopid = pdb.pdb_loopid;
- 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)) {
- MEMZERO(&mbs, sizeof (mbs));
+ 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_alpa,
- 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_LOGSANCFG|ISP_LOGCONFIG, topology, fcp->isp_portid,
+ fcp->isp_loopid, toponames[fcp->isp_topo]);
+ isp_prt(isp, ISP_LOGSANCFG|ISP_LOGCONFIG, ourwwn,
+ (u_int32_t) (ISP_NODEWWN(isp) >> 32),
+ (u_int32_t) ISP_NODEWWN(isp),
+ (u_int32_t) (ISP_PORTWWN(isp) >> 32),
+ (u_int32_t) ISP_PORTWWN(isp));
+ isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "FC Link Test Complete");
return (0);
}
-static char *
-isp2100_fw_statename(int state)
+const char *
+ispfc_fw_statename(int state)
{
switch(state) {
case FW_CONFIG_WAIT: return "Config Wait";
@@ -1806,17 +2691,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
+int
isp_pdb_sync(struct ispsoftc *isp)
{
- struct lportdb *lp;
fcparam *fcp = isp->isp_param;
- isp_pdb_t pdb;
- int loopid, base, lim;
+ fcportdb_t *lp;
+ u_int16_t dbidx;
+
+ if (fcp->isp_loopstate == LOOP_READY) {
+ return (0);
+ }
/*
* Make sure we're okay for doing this right now.
@@ -1824,289 +2727,127 @@ isp_pdb_sync(struct ispsoftc *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;
-
- 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++) {
- u_int32_t portid;
- mbreg_t mbs;
+ isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Synchronizing PDBs");
- 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;
- u_int64_t nwwnn, nwwpn;
- nwwnn =
- (((u_int64_t)pdb.pdb_nodename[0]) << 56) |
- (((u_int64_t)pdb.pdb_nodename[1]) << 48) |
- (((u_int64_t)pdb.pdb_nodename[2]) << 40) |
- (((u_int64_t)pdb.pdb_nodename[3]) << 32) |
- (((u_int64_t)pdb.pdb_nodename[4]) << 24) |
- (((u_int64_t)pdb.pdb_nodename[5]) << 16) |
- (((u_int64_t)pdb.pdb_nodename[6]) << 8) |
- (((u_int64_t)pdb.pdb_nodename[7]));
- nwwpn =
- (((u_int64_t)pdb.pdb_portname[0]) << 56) |
- (((u_int64_t)pdb.pdb_portname[1]) << 48) |
- (((u_int64_t)pdb.pdb_portname[2]) << 40) |
- (((u_int64_t)pdb.pdb_portname[3]) << 32) |
- (((u_int64_t)pdb.pdb_portname[4]) << 24) |
- (((u_int64_t)pdb.pdb_portname[5]) << 16) |
- (((u_int64_t)pdb.pdb_portname[6]) << 8) |
- (((u_int64_t)pdb.pdb_portname[7]));
- nrole = (pdb.pdb_prli_svc3 & SVC3_ROLE_MASK) >>
- SVC3_ROLE_SHIFT;
- if (pdb.pdb_loopid == lp->loopid && lp->portid ==
- (u_int32_t) BITS2WORD(pdb.pdb_portid_bits) &&
- nwwnn == lp->node_wwn && nwwpn == lp->port_wwn &&
- lp->roles == nrole && lp->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 (lp->state == FC_PORTDB_STATE_VALID) {
+ if (dbidx != FL_ID) {
+ isp_prt(isp,
+ ISP_LOGERR, "portdb idx %d already valid",
+ dbidx);
}
+ 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;
- 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);
+ 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 {
+ lp->autologin = 0;
}
- lp->force_logout = lp->loggedin = 0;
- 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;
}
- }
-
- /*
- * And log in....
- */
- loopid = lp - fcp->portdb;
- lp->loopid = FL_PORT_ID;
- do {
- MEMZERO(&mbs, sizeof (mbs));
- mbs.param[0] = MBOX_FABRIC_LOGIN;
- mbs.param[1] = loopid << 8;
- 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->state = FC_PORTDB_STATE_VALID;
+ isp_async(isp, ISPASYNC_DEV_STAYED, lp);
+ if (dbidx != FL_ID) {
+ lp->new_roles = 0;
+ lp->new_portid = 0;
}
- switch (mbs.param[0]) {
- case MBOX_LOOP_ID_USED:
- /*
- * Try the next available loop id.
- */
- loopid++;
- break;
- case MBOX_PORT_ID_USED:
- /*
- * This port is already logged in.
- * Snaffle the loop id it's using if it's
- * nonzero, otherwise we're hosed.
- */
- if (mbs.param[1] != 0) {
- loopid = mbs.param[1];
- isp_prt(isp, ISP_LOGINFO, retained,
- loopid, (int) (lp - fcp->portdb),
- lp->portid);
- } else {
- loopid = MAX_FC_TARG;
- break;
- }
- /* 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;
- }
- } 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 appropriate 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 != (u_int32_t) BITS2WORD(pdb.pdb_portid_bits)) {
- isp_prt(isp, ISP_LOGWARN, pdbmfail2,
- lp->portid, BITS2WORD(pdb.pdb_portid_bits));
- goto dump_em;
- }
-
- lp->roles =
- (pdb.pdb_prli_svc3 & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT;
- lp->node_wwn =
- (((u_int64_t)pdb.pdb_nodename[0]) << 56) |
- (((u_int64_t)pdb.pdb_nodename[1]) << 48) |
- (((u_int64_t)pdb.pdb_nodename[2]) << 40) |
- (((u_int64_t)pdb.pdb_nodename[3]) << 32) |
- (((u_int64_t)pdb.pdb_nodename[4]) << 24) |
- (((u_int64_t)pdb.pdb_nodename[5]) << 16) |
- (((u_int64_t)pdb.pdb_nodename[6]) << 8) |
- (((u_int64_t)pdb.pdb_nodename[7]));
- lp->port_wwn =
- (((u_int64_t)pdb.pdb_portname[0]) << 56) |
- (((u_int64_t)pdb.pdb_portname[1]) << 48) |
- (((u_int64_t)pdb.pdb_portname[2]) << 40) |
- (((u_int64_t)pdb.pdb_portname[3]) << 32) |
- (((u_int64_t)pdb.pdb_portname[4]) << 24) |
- (((u_int64_t)pdb.pdb_portname[5]) << 16) |
- (((u_int64_t)pdb.pdb_portname[6]) << 8) |
- (((u_int64_t)pdb.pdb_portname[7]));
- /*
- * 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;
- mbs.param[1] = lp->loopid << 8;
- mbs.param[2] = 0;
- mbs.param[3] = 0;
- isp_mboxcmd(isp, &mbs, MBLOGNONE);
- if (fcp->isp_fwstate != FW_READY ||
- fcp->isp_loopstate != LOOP_SYNCING_PDB) {
- return (-1);
+ 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
@@ -2117,799 +2858,969 @@ dump_em:
return (0);
}
-static int
+/*
+ * Scan local loop for devices.
+ */
+int
isp_scan_loop(struct ispsoftc *isp)
{
- struct lportdb *lp;
+ fcportdb_t *lp, tmp;
fcparam *fcp = isp->isp_param;
+ int i;
isp_pdb_t pdb;
- int loopid, lim, hival;
+ u_int16_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;
- /*
- * make sure the temp port database is clean...
- */
- MEMZERO((void *)fcp->tport, sizeof (fcp->tport));
+ isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "FC scan loop 0..%d", lim-1);
+
/*
- * Run through the local loop ports and get port database info
- * for each loop ID.
- *
- * There's a somewhat unexplained situation where the f/w passes back
- * the wrong database entity- if that happens, just restart (up to
- * FL_PORT_ID times).
+ * 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;
+ }
- lp->node_wwn = isp_get_portname(isp, loopid, 1);
- if (fcp->isp_loopstate < LOOP_SCANNING_LOOP)
- return (-1);
- if (lp->node_wwn == 0)
- continue;
- lp->port_wwn = isp_get_portname(isp, loopid, 0);
- if (fcp->isp_loopstate < LOOP_SCANNING_LOOP)
- return (-1);
- if (lp->port_wwn == 0) {
- lp->node_wwn = 0;
- continue;
+ /*
+ * 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)) {
+ u_int64_t node_wwn = isp_get_portname(isp, handle, 1);
+ if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) {
+ return (-1);
+ }
+ if (node_wwn == 0) {
+ continue;
+ }
}
/*
- * Get an entry....
+ * Get the port database entity for this index.
*/
- if (isp_getpdb(isp, loopid, &pdb) != 0) {
- if (fcp->isp_loopstate < LOOP_SCANNING_LOOP)
+ 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 =
- (((u_int64_t)pdb.pdb_nodename[0]) << 56) |
- (((u_int64_t)pdb.pdb_nodename[1]) << 48) |
- (((u_int64_t)pdb.pdb_nodename[2]) << 40) |
- (((u_int64_t)pdb.pdb_nodename[3]) << 32) |
- (((u_int64_t)pdb.pdb_nodename[4]) << 24) |
- (((u_int64_t)pdb.pdb_nodename[5]) << 16) |
- (((u_int64_t)pdb.pdb_nodename[6]) << 8) |
- (((u_int64_t)pdb.pdb_nodename[7]));
- lp->port_wwn =
- (((u_int64_t)pdb.pdb_portname[0]) << 56) |
- (((u_int64_t)pdb.pdb_portname[1]) << 48) |
- (((u_int64_t)pdb.pdb_portname[2]) << 40) |
- (((u_int64_t)pdb.pdb_portname[3]) << 32) |
- (((u_int64_t)pdb.pdb_portname[4]) << 24) |
- (((u_int64_t)pdb.pdb_portname[5]) << 16) |
- (((u_int64_t)pdb.pdb_portname[6]) << 8) |
- (((u_int64_t)pdb.pdb_portname[7]));
- lp->roles =
- (pdb.pdb_prli_svc3 & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT;
- lp->portid = BITS2WORD(pdb.pdb_portid_bits);
- lp->loopid = pdb.pdb_loopid;
- }
-
- /*
- * Mark all of the permanent local loop database entries as invalid
- * (except our own entry).
- */
- for (loopid = 0; loopid < hival; loopid++) {
- if (loopid == fcp->isp_iid) {
- fcp->portdb[loopid].valid = 1;
- fcp->portdb[loopid].loopid = fcp->isp_loopid;
- continue;
- }
- fcp->portdb[loopid].valid = 0;
- }
-
- /*
- * Now merge our local copy of the port database into our saved copy.
- * Notify the outer layers of new devices arriving.
- */
- for (loopid = 0; loopid < hival; loopid++) {
- int i;
-
- /*
- * If we don't have a non-zero Port WWN, we're not here.
- */
- if (fcp->tport[loopid].port_wwn == 0) {
- continue;
- }
+ 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;
/*
- * Skip ourselves.
+ * 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 (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 its 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(struct ispsoftc *isp, mbreg_t *mbp)
+int
+isp_gid_ft_sns(struct ispsoftc *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;
+ u_int8_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(struct ispsoftc *isp, int ftype)
+int
+isp_gid_ft_ct_passthru(struct ispsoftc *isp)
{
- fcparam *fcp = isp->isp_param;
- u_int32_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;
+ u_int8_t q[QENTRY_LEN];
+ } un;
+ isp_ct_pt_t *pt;
+ ct_hdr_t *ct;
+ u_int32_t *rp;
+ u_int8_t *scp = fcp->isp_scratch;
+
+ isp_prt(isp, ISP_LOGDEBUG0, "scanning fabric (GID_FT) via CT");
+
+ if (!IS_24XX(isp)) {
+ return (1);
}
- FC_SCRATCH_ACQUIRE(isp);
-
/*
- * 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;
- u_int8_t sc[SNS_GA_NXT_RESP_SIZE];
-
- 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 *) ((u_int8_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 =
- (((u_int32_t) rs1->snscb_port_id[0]) << 16) |
- (((u_int32_t) rs1->snscb_port_id[1]) << 8) |
- (((u_int32_t) rs1->snscb_port_id[2]));
+ 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 (u_int32_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 (u_int32_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]);
- /*
- * 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 =
- (((u_int64_t)rs1->snscb_nodename[0]) << 56) |
- (((u_int64_t)rs1->snscb_nodename[1]) << 48) |
- (((u_int64_t)rs1->snscb_nodename[2]) << 40) |
- (((u_int64_t)rs1->snscb_nodename[3]) << 32) |
- (((u_int64_t)rs1->snscb_nodename[4]) << 24) |
- (((u_int64_t)rs1->snscb_nodename[5]) << 16) |
- (((u_int64_t)rs1->snscb_nodename[6]) << 8) |
- (((u_int64_t)rs1->snscb_nodename[7]));
- lcl.port_wwn =
- (((u_int64_t)rs1->snscb_portname[0]) << 56) |
- (((u_int64_t)rs1->snscb_portname[1]) << 48) |
- (((u_int64_t)rs1->snscb_portname[2]) << 40) |
- (((u_int64_t)rs1->snscb_portname[3]) << 32) |
- (((u_int64_t)rs1->snscb_portname[4]) << 24) |
- (((u_int64_t)rs1->snscb_portname[5]) << 16) |
- (((u_int64_t)rs1->snscb_portname[6]) << 8) |
- (((u_int64_t)rs1->snscb_portname[7]));
+ /*
+ * 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;
+
+ isp_put_ct_hdr(isp, ct, (ct_hdr_t *) &scp[XTXOFF]);
+ rp = (u_int32_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 (u_int32_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(struct ispsoftc *isp, int ftype)
+int
+isp_scan_fabric(struct ispsoftc *isp)
{
fcparam *fcp = FCPARAM(isp);
- mbreg_t mbs;
- int i;
- sns_gid_ft_req_t *rq;
+ u_int32_t portid;
+ u_int16_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);
}
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 *) ((u_int8_t *)fcp->isp_scratch+IGPOFF);
+ rs1 = (sns_gid_ft_rsp_t *) ((u_int8_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);
}
+
/*
- * 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.
+ * If we get this far, we certainly still have the fabric controller.
+ */
+ fcp->portdb[FL_ID].state = FC_PORTDB_STATE_PENDING_VALID;
+
+ /*
+ * 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++) {
+ u_int32_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 =
- (((u_int32_t) rs1->snscb_ports[i].portid[0]) << 16) |
- (((u_int32_t) rs1->snscb_ports[i].portid[1]) << 8) |
- (((u_int32_t) rs1->snscb_ports[i].portid[2]));
-
- MEMZERO((void *) gq, sizeof (sns_gxn_id_req_t));
- gq->snscb_rblen = SNS_GXN_ID_RESP_SIZE >> 1;
- gq->snscb_addr[RQRSP_ADDR0015] = DMA_WD0(fcp->isp_scdma+GXOFF);
- gq->snscb_addr[RQRSP_ADDR1631] = DMA_WD1(fcp->isp_scdma+GXOFF);
- gq->snscb_addr[RQRSP_ADDR3247] = DMA_WD2(fcp->isp_scdma+GXOFF);
- gq->snscb_addr[RQRSP_ADDR4863] = DMA_WD3(fcp->isp_scdma+GXOFF);
- gq->snscb_sblen = 6;
- gq->snscb_cmd = SNS_GPN_ID;
- gq->snscb_portid = lcl.portid;
- isp_put_gxn_id_request(isp, gq,
- (sns_gxn_id_req_t *) fcp->isp_scratch);
- MEMORYBARRIER(isp, SYNC_SFORDEV, 0, SNS_GXN_ID_REQ_SIZE);
- 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);
+ for (portidx = 0; portidx < portlim; portidx++) {
+ fcportdb_t *lp;
+ isp_pdb_t pdb;
+ u_int64_t wwnn, wwpn;
+ int dbidx, 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;
+ }
+
/*
- * 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 *) ((u_int8_t *)fcp->isp_scratch+GXOFF);
- isp_get_gxn_id_response(isp, gs0, gs1);
- if (gs1->snscb_cthdr.ct_response != FS_ACC) {
- isp_prt(isp, ISP_LOGWARN, swrej, "GPN_ID",
- gs1->snscb_cthdr.ct_reason,
- gs1->snscb_cthdr.ct_explanation, lcl.portid);
+
+ /*
+ * 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,
+ (u_int32_t) (wwnn >> 32), (u_int32_t) wwnn,
+ (u_int32_t) (wwpn >> 32), (u_int32_t) wwpn,
+ lp->handle, portid,
+ (u_int32_t) (lp->node_wwn >> 32),
+ (u_int32_t) lp->node_wwn,
+ (u_int32_t) (lp->port_wwn >> 32),
+ (u_int32_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 =
- (((u_int64_t)gs1->snscb_wwn[0]) << 56) |
- (((u_int64_t)gs1->snscb_wwn[1]) << 48) |
- (((u_int64_t)gs1->snscb_wwn[2]) << 40) |
- (((u_int64_t)gs1->snscb_wwn[3]) << 32) |
- (((u_int64_t)gs1->snscb_wwn[4]) << 24) |
- (((u_int64_t)gs1->snscb_wwn[5]) << 16) |
- (((u_int64_t)gs1->snscb_wwn[6]) << 8) |
- (((u_int64_t)gs1->snscb_wwn[7]));
-
- MEMZERO((void *) gq, sizeof (sns_gxn_id_req_t));
- gq->snscb_rblen = SNS_GXN_ID_RESP_SIZE >> 1;
- gq->snscb_addr[RQRSP_ADDR0015] = DMA_WD0(fcp->isp_scdma+GXOFF);
- gq->snscb_addr[RQRSP_ADDR1631] = DMA_WD1(fcp->isp_scdma+GXOFF);
- gq->snscb_addr[RQRSP_ADDR3247] = DMA_WD2(fcp->isp_scdma+GXOFF);
- gq->snscb_addr[RQRSP_ADDR4863] = DMA_WD3(fcp->isp_scdma+GXOFF);
- gq->snscb_sblen = 6;
- gq->snscb_cmd = SNS_GNN_ID;
- gq->snscb_portid = lcl.portid;
- isp_put_gxn_id_request(isp, gq,
- (sns_gxn_id_req_t *) fcp->isp_scratch);
- MEMORYBARRIER(isp, SYNC_SFORDEV, 0, SNS_GXN_ID_REQ_SIZE);
- 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 *) ((u_int8_t *)fcp->isp_scratch+GXOFF);
- isp_get_gxn_id_response(isp, gs0, gs1);
- if (gs1->snscb_cthdr.ct_response != FS_ACC) {
- isp_prt(isp, ISP_LOGWARN, swrej, "GNN_ID",
- gs1->snscb_cthdr.ct_reason,
- gs1->snscb_cthdr.ct_explanation, lcl.portid);
- if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) {
- FC_SCRATCH_RELEASE(isp);
- return (-1);
+ 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 =
- (((u_int64_t)gs1->snscb_wwn[0]) << 56) |
- (((u_int64_t)gs1->snscb_wwn[1]) << 48) |
- (((u_int64_t)gs1->snscb_wwn[2]) << 40) |
- (((u_int64_t)gs1->snscb_wwn[3]) << 32) |
- (((u_int64_t)gs1->snscb_wwn[4]) << 24) |
- (((u_int64_t)gs1->snscb_wwn[5]) << 16) |
- (((u_int64_t)gs1->snscb_wwn[6]) << 8) |
- (((u_int64_t)gs1->snscb_wwn[7]));
/*
- * The QLogic f/w is bouncing this with a parameter error.
+ * 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 *) ((u_int8_t *)fcp->isp_scratch+GXOFF);
- isp_get_gff_id_response(isp, fs0, fs1);
- if (fs1->snscb_cthdr.ct_response != FS_ACC) {
- isp_prt(isp, /* ISP_LOGDEBUG0 */ ISP_LOGWARN,
- swrej, "GFF_ID",
- fs1->snscb_cthdr.ct_reason,
- fs1->snscb_cthdr.ct_explanation, lcl.portid);
+ if (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 (fcp->portdb[dbidx].state == FC_PORTDB_STATE_NIL) {
+ continue;
}
- if (fc4_fval & 0x2) {
- lcl.roles |=
- (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT);
+ 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,
+ (u_int32_t) (wwnn >> 32), (u_int32_t) wwnn,
+ (u_int32_t) (wwpn >> 32), (u_int32_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);
+ }
- } while ((rs1->snscb_ports[i].control & 0x80) == 0 && i < NGENT-1);
+ 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);
+}
+
+/*
+ * Find an unused handle and try and use to login to a port.
+ */
+int
+isp_login_device(struct ispsoftc *isp, u_int32_t portid, isp_pdb_t *p, u_int16_t *ohp)
+{
+ int lim, i, r;
+ u_int16_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
+int
isp_register_fc4_type(struct ispsoftc *isp)
{
fcparam *fcp = isp->isp_param;
@@ -2928,9 +3839,6 @@ isp_register_fc4_type(struct ispsoftc *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));
@@ -2938,18 +3846,167 @@ isp_register_fc4_type(struct ispsoftc *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);
- isp_mboxcmd(isp, &mbs, MBLOGALL);
+ mbs.logval = MBLOGALL;
+ mbs.timeout = 10000000;
+ MEMORYBARRIER(isp, SYNC_SFORDEV, 0, SNS_RFT_ID_REQ_SIZE);
+ 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);
}
}
+int
+isp_register_fc4_type_24xx(struct ispsoftc *isp)
+{
+ mbreg_t mbs;
+ fcparam *fcp = FCPARAM(isp);
+ union {
+ isp_ct_pt_t plocal;
+ rft_id_t clocal;
+ u_int8_t q[QENTRY_LEN];
+ } un;
+ isp_ct_pt_t *pt;
+ ct_hdr_t *ct;
+ rft_id_t *rp;
+ u_int8_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);
+ }
+}
+
+u_int16_t
+isp_nxt_handle(struct ispsoftc *isp, u_int16_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.
*/
@@ -2958,10 +4015,12 @@ int
isp_start(XS_T *xs)
{
struct ispsoftc *isp;
- u_int16_t nxti, optr, handle;
+ u_int32_t nxti, optr, handle;
u_int8_t local[QENTRY_LEN];
ispreq_t *reqp, *qep;
- int target, i;
+ void *cdbp;
+ u_int16_t *tptr;
+ int target, i, hdlidx = 0;
XS_INITERR(xs);
isp = XS_ISP(xs);
@@ -3000,201 +4059,54 @@ 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- hdlidx 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;
- xs->sc_link->node_wwn = lp->node_wwn;
- xs->sc_link->port_wwn = lp->port_wwn;
-
+ target = fcp->portdb[hdlidx].handle;
+ xs->sc_link->node_wwn = fcp->portdb[hdlidx].node_wwn;
+ xs->sc_link->port_wwn = fcp->portdb[hdlidx].port_wwn;
}
/*
- * 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);
@@ -3208,34 +4120,40 @@ isp_start(XS_T *xs)
*/
reqp = (ispreq_t *) local;
if (isp->isp_sendmarker) {
- u_int8_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)
@@ -3245,7 +4163,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
*/
@@ -3253,7 +4190,7 @@ isp_start(XS_T *xs)
/*
* Fibre Channel always requires some kind of tag.
- * The QLogic drivers seem be happy not to use a tag,
+ * The Qlogic drivers seem be happy not to use a tag,
* but this breaks for some devices (IBM drives).
*/
if (XS_TAG_P(xs)) {
@@ -3276,21 +4213,45 @@ isp_start(XS_T *xs)
reqp->req_flags = XS_TAG_TYPE(xs);
}
}
- reqp->req_target = target | (XS_CHANNEL(xs) << 7);
+ 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_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_sccfw) {
+ ((ispreqt2_t *)reqp)->req_target = target;
+ ((ispreqt2_t *)reqp)->req_scclun = XS_LUN(xs);
} else {
- if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN)
- ((ispreqt2_t *)reqp)->req_scclun = XS_LUN(xs);
- else
- ((ispreqt2_t *)reqp)->req_lun_trn = XS_LUN(xs);
+ ((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)) {
@@ -3298,11 +4259,12 @@ 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;
/*
* Set up DMA and/or do any bus swizzling of the request entry
- * so that the QLogic F/W understands what is being asked of it.
+ * so that the Qlogic F/W understands what is being asked of it.
*/
i = ISP_DMASETUP(isp, xs, reqp, &nxti, optr);
if (i != CMD_QUEUED) {
@@ -3314,7 +4276,7 @@ isp_start(XS_T *xs)
return (i);
}
XS_SETERR(xs, HBA_NOERROR);
- isp_prt(isp, ISP_LOGDEBUG2,
+ isp_prt(isp, ISP_LOGDEBUG0,
"START cmd for %d.%d.%d cmd 0x%x datalen %ld",
XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs), XS_CDBP(xs)[0],
(long) XS_XFRLEN(xs));
@@ -3334,7 +4296,9 @@ isp_control(struct ispsoftc *isp, ispctl_t ctl, void *arg)
XS_T *xs;
mbreg_t mbs;
int bus, tgt;
- u_int16_t handle;
+ u_int32_t handle;
+
+ MEMZERO(&mbs, sizeof (mbs));
switch (ctl) {
default:
@@ -3345,22 +4309,26 @@ isp_control(struct ispsoftc *isp, ispctl_t ctl, void *arg)
/*
* Issue a bus reset.
*/
- MEMZERO(&mbs, sizeof (mbs));
- mbs.param[0] = MBOX_BUS_RESET;
- if (IS_SCSI(isp)) {
- mbs.param[1] =
- ((sdparam *) isp->isp_param)->isp_bus_reset_delay;
- if (mbs.param[1] < 2)
+ if (IS_24XX(isp)) {
+ isp_prt(isp, ISP_LOGWARN, "RESET BUS NOT IMPLEMENTED");
+ 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;
+ }
bus = *((int *) arg);
- if (IS_DUALBUS(isp))
+ 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;
}
@@ -3370,12 +4338,25 @@ isp_control(struct ispsoftc *isp, ispctl_t ctl, void *arg)
case ISPCTL_RESET_DEV:
tgt = (*((int *) arg)) & 0xffff;
- bus = (*((int *) arg)) >> 16;
- MEMZERO(&mbs, sizeof (mbs));
+ if (IS_24XX(isp)) {
+ isp_prt(isp, ISP_LOGWARN, "RESET DEV NOT IMPLEMENTED");
+ break;
+ } else if (IS_FC(isp)) {
+ if (FCPARAM(isp)->isp_2klogin) {
+ mbs.param[1] = tgt;
+ 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[1] = (tgt << 8) | (bus << 15);
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;
}
@@ -3387,38 +4368,39 @@ isp_control(struct ispsoftc *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);
- MEMZERO(&mbs, sizeof (mbs));
- mbs.param[0] = MBOX_ABORT;
- if (IS_FC(isp)) {
- if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) {
- mbs.param[1] = tgt << 8;
- mbs.param[4] = 0;
- mbs.param[5] = 0;
+ if (IS_24XX(isp)) {
+ isp_prt(isp, ISP_LOGWARN, "ABORT CMD NOT IMPLEMENTED");
+ 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;
+ }
mbs.param[6] = XS_LUN(xs);
} else {
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 hasn't been picked up by firmware yet.
- */
- break;
+ return (0);
case ISPCTL_UPDATE_PARAMS:
@@ -3428,7 +4410,10 @@ isp_control(struct ispsoftc *isp, ispctl_t ctl, void *arg)
case ISPCTL_FCLINK_TEST:
if (IS_FC(isp)) {
- int usdelay = (arg)? *((int *) arg) : 250000;
+ int usdelay = *((int *) arg);
+ if (usdelay == 0) {
+ usdelay = 250000;
+ }
return (isp_fclink_test(isp, usdelay));
}
break;
@@ -3436,8 +4421,7 @@ isp_control(struct ispsoftc *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;
@@ -3457,28 +4441,64 @@ isp_control(struct ispsoftc *isp, ispctl_t ctl, void *arg)
case ISPCTL_SEND_LIP:
- if (IS_FC(isp)) {
- MEMZERO(&mbs, sizeof (mbs));
+ if (IS_FC(isp) && !IS_24XX(isp)) {
mbs.param[0] = MBOX_INIT_LIP;
- isp_mboxcmd(isp, &mbs, MBLOGALL);
+ if (FCPARAM(isp)->isp_2klogin) {
+ mbs.ibits = (1 << 10);
+ }
+ mbs.logval = MBLOGALL;
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] == MBOX_COMMAND_COMPLETE) {
return (0);
}
}
break;
- case ISPCTL_GET_POSMAP:
-
+ case ISPCTL_GET_PDB:
if (IS_FC(isp) && arg) {
- return (isp_getmap(isp, arg));
+ int id = *((int *)arg);
+ isp_pdb_t *pdb = arg;
+ return (isp_getpdb(isp, id, pdb, 1));
}
break;
+ case ISPCTL_GET_PORTNAME:
+ {
+ u_int64_t *wwnp = arg;
+ int loopid = *wwnp;
+ *wwnp = isp_get_portname(isp, loopid, 0);
+ if (*wwnp == (u_int64_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:
{
@@ -3489,11 +4509,11 @@ isp_control(struct ispsoftc *isp, ispctl_t ctl, void *arg)
*/
if (IS_SCSI(isp)) {
int param = *(int *)arg;
- MEMZERO(&mbs, sizeof (mbs));
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;
}
@@ -3517,17 +4537,18 @@ isp_control(struct ispsoftc *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(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox)
+isp_intr(struct ispsoftc *isp, u_int32_t isr, u_int16_t sema, u_int16_t mbox)
{
XS_T *complist[MAX_REQUESTQ_COMPLETIONS], *xs;
- u_int16_t iptr, optr, junk;
+ u_int32_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.
@@ -3538,7 +4559,7 @@ again:
if (isp->isp_mboxbsy) {
int obits = isp->isp_obits;
isp->isp_mboxtmp[0] = mbox;
- for (i = 1; i < MAX_MAILBOX; i++) {
+ for (i = 1; i < MAX_MAILBOX(isp); i++) {
if ((obits & (1 << i)) == 0) {
continue;
}
@@ -3553,17 +4574,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;
}
}
@@ -3571,32 +4589,73 @@ 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) {
+ u_int8_t qe[QENTRY_LEN];
+ isphdr_t *hp;
+ u_int32_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;
+ optr = isp->isp_residx;
}
+#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;
@@ -3611,19 +4670,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;
@@ -3637,15 +4695,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);
@@ -3661,42 +4721,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;
+ u_int8_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;
+ u_int8_t *snsp, *resp;
+ u_int32_t rlen, slen;
+ long resid;
u_int16_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);
-
- type = isp_get_response_type(isp, hp);
-
- if (type == RQSTYPE_RESPONSE) {
+ isp_get_hdr(isp, hp, &sp->req_header);
+ etype = sp->req_header.rqs_entry_type;
+
+ if (IS_24XX(isp) && etype == RQSTYPE_RESPONSE) {
+ 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 {
@@ -3705,7 +4798,12 @@ again:
* may have updated the response queue pointers for
* us, so we reload our goal index.
*/
- if (isp_handle_other_response(isp, type, hp, &optr)) {
+ int r;
+ r = isp_handle_other_response(isp, etype, hp, &optr);
+ if (r < 0) {
+ goto read_again;
+ }
+ if (r > 0) {
iptr = isp->isp_resodx;
MEMZERO(hp, QENTRY_LEN); /* PERF */
continue;
@@ -3716,34 +4814,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,
+ "Request 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) {
@@ -3754,53 +4851,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) {
- u_int8_t ts = sp->req_completion_status & 0xff;
- MEMZERO(hp, QENTRY_LEN); /* PERF */
+ u_int8_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));
}
@@ -3808,39 +4899,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|RQCS_SV)) != 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.%d FCP RESPONSE: 0x%x",
+ XS_CHANNEL(xs), 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);
@@ -3849,26 +4972,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 resid %ld", (long) XS_XFRLEN(xs),
- (long) sp->req_resid);
+ "asked for %ld got raw resid %ld settled for %ld",
+ (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.
@@ -3879,16 +5002,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);
}
@@ -3896,17 +5022,18 @@ again:
}
/*
- * Free any dma resources. As a side effect, this may
- * also do any cache flushing necessary for data coherence. */
+ * Free any DMA resources. As a side effect, this may
+ * also do any cache flushing necessary for data coherence.
+ */
if (XS_XFRLEN(xs)) {
ISP_DMAFREE(isp, xs, sp->req_handle);
}
if (((isp->isp_dblev & (ISP_LOGDEBUG2|ISP_LOGDEBUG3))) ||
- ((isp->isp_dblev & ISP_LOGDEBUG1) && ((!XS_NOERR(xs)) ||
+ ((isp->isp_dblev & ISP_LOGDEBUG0) && ((!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';
@@ -3918,8 +5045,7 @@ again:
skey = '.';
}
isp_prt(isp, ISP_LOGALL, finmsg, XS_CHANNEL(xs),
- XS_TGT(xs), XS_LUN(xs), XS_XFRLEN(xs),
- (ulong)XS_RESID(xs),
+ XS_TGT(xs), XS_LUN(xs), XS_XFRLEN(xs), XS_RESID(xs),
*XS_STSP(xs), skey, XS_ERR(xs));
}
@@ -3938,13 +5064,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 request queue out pointer.
+ * While we're at it, read the requst queue out pointer.
*/
- isp->isp_reqodx = READ_REQUEST_QUEUE_OUT_POINTER(isp);
- if (isp->isp_rscchiwater < ndone)
+ isp->isp_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;
@@ -3962,7 +5098,7 @@ again:
* Support routines.
*/
-static int
+int
isp_parse_async(struct ispsoftc *isp, u_int16_t mbox)
{
int rval = 0;
@@ -3979,26 +5115,32 @@ isp_parse_async(struct ispsoftc *isp, u_int16_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;
case ASYNC_SYSTEM_ERROR:
-#ifdef ISP_FW_CRASH_DUMP
+ isp->isp_state = ISP_CRASHED;
+ if (IS_FC(isp)) {
+ FCPARAM(isp)->isp_loopstate = LOOP_NIL;
+ FCPARAM(isp)->isp_fwstate = FW_CONFIG_WAIT;
+ }
/*
- * If we have crash dumps enabled, it's up to the handler
- * for isp_async to reinit stuff and restart the firmware
- * after performing the crash dump. The reason we do things
- * this way is that we may need to activate a kernel thread
- * to do all the crash dump goop.
+ * Were we waiting for a mailbox command to complete?
+ * If so, it's dead, so wake up the waiter.
+ */
+ if (isp->isp_mboxbsy) {
+ isp->isp_obits = 1;
+ isp->isp_mboxtmp[0] = MBOX_HOST_INTERFACE_ERROR;
+ MBOX_NOTIFY_COMPLETE(isp);
+ }
+ /*
+ * It's up to the handler for isp_async to reinit stuff and
+ * restart the firmware
*/
isp_async(isp, ISPASYNC_FW_CRASH, NULL);
-#else
- isp_async(isp, ISPASYNC_FW_CRASH, NULL);
- isp_reinit(isp);
- isp_async(isp, ISPASYNC_FW_RESTARTED, NULL);
-#endif
rval = -1;
break;
@@ -4016,7 +5158,7 @@ isp_parse_async(struct ispsoftc *isp, u_int16_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:
@@ -4024,8 +5166,9 @@ isp_parse_async(struct ispsoftc *isp, u_int16_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;
@@ -4033,8 +5176,9 @@ isp_parse_async(struct ispsoftc *isp, u_int16_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;
@@ -4125,29 +5269,33 @@ isp_parse_async(struct ispsoftc *isp, u_int16_t mbox)
int handle =
(ISP_READ(isp, OUTMAILBOX2) << 16) |
(ISP_READ(isp, OUTMAILBOX1));
- if (isp_target_async(isp, handle, mbox))
+ if (isp_target_async(isp, handle, mbox)) {
rval = -1;
+ } else {
+ /* count it as a fast posting intr */
+ isp->isp_fphccmplt++;
+ }
#else
isp_prt(isp, ISP_LOGINFO, "Fast Posting CTIO done");
-#endif
isp->isp_fphccmplt++; /* count it as a fast posting intr */
+#endif
break;
}
+ case ASYNC_LIP_ERROR:
case ASYNC_LIP_F8:
case ASYNC_LIP_OCCURRED:
- FCPARAM(isp)->isp_lipseq =
- ISP_READ(isp, OUTMAILBOX1);
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 occurring on
+ * We've had problems with data corruption occuring on
* commands that complete (with no apparent error) after
* we receive a LIP. This has been observed mostly on
* Local Loop topologies. To be safe, let's just mark
@@ -4175,11 +5323,12 @@ isp_parse_async(struct ispsoftc *isp, u_int16_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))
+ if (isp_target_async(isp, bus, mbox)) {
rval = -1;
+ }
#endif
break;
@@ -4187,11 +5336,12 @@ isp_parse_async(struct ispsoftc *isp, u_int16_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))
+ if (isp_target_async(isp, bus, mbox)) {
rval = -1;
+ }
#endif
break;
@@ -4199,50 +5349,49 @@ isp_parse_async(struct ispsoftc *isp, u_int16_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))
+ if (isp_target_async(isp, bus, mbox)) {
rval = -1;
+ }
#endif
break;
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,
@@ -4258,13 +5407,7 @@ isp_parse_async(struct ispsoftc *isp, u_int16_t mbox)
break;
case ISP_CONN_FATAL:
isp_prt(isp, ISP_LOGERR, "FATAL CONNECTION ERROR");
-#ifdef ISP_FW_CRASH_DUMP
isp_async(isp, ISPASYNC_FW_CRASH, NULL);
-#else
- isp_async(isp, ISPASYNC_FW_CRASH, NULL);
- isp_reinit(isp);
- isp_async(isp, ISPASYNC_FW_RESTARTED, NULL);
-#endif
return (-1);
case ISP_CONN_LOOPBACK:
isp_prt(isp, ISP_LOGWARN,
@@ -4281,6 +5424,15 @@ isp_parse_async(struct ispsoftc *isp, u_int16_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;
@@ -4288,9 +5440,9 @@ isp_parse_async(struct ispsoftc *isp, u_int16_t mbox)
if (bus & 0x100) {
int i, nh;
- u_int16_t handles[5];
+ u_int16_t handles[16];
- for (nh = 0, i = 1; i < MAX_MAILBOX; i++) {
+ for (nh = 0, i = 1; i < MAX_MAILBOX(isp); i++) {
if ((bus & (1 << i)) == 0) {
continue;
}
@@ -4301,8 +5453,9 @@ isp_parse_async(struct ispsoftc *isp, u_int16_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++;
}
@@ -4315,13 +5468,16 @@ isp_parse_async(struct ispsoftc *isp, u_int16_t mbox)
* this is not used currently.
*/
-static int
+int
isp_handle_other_response(struct ispsoftc *isp, int type,
- isphdr_t *hp, u_int16_t *optrp)
+ isphdr_t *hp, u_int32_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:
@@ -4333,6 +5489,9 @@ isp_handle_other_response(struct ispsoftc *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)) {
@@ -4342,17 +5501,31 @@ isp_handle_other_response(struct ispsoftc *isp, int type,
/* FALLTHROUGH */
case RQSTYPE_REQUEST:
default:
- if (isp_async(isp, ISPASYNC_UNHANDLED_RESPONSE, hp)) {
- return (1);
+ USEC_DELAY(100);
+ if (type != isp_get_response_type(isp, hp)) {
+ /*
+ * This is questionable- we're just papering over
+ * something we've seen on SMP linux in target
+ * mode- we don't really know what's happening
+ * here that causes us to think we've gotten
+ * an entry, but that either the entry isn't
+ * filled out yet or our CPU read data is stale.
+ */
+ isp_prt(isp, ISP_LOGINFO,
+ "unstable type in response queue");
+ return (-1);
}
isp_prt(isp, ISP_LOGWARN, "Unhandled Response Type 0x%x",
isp_get_response_type(isp, hp));
+ if (isp_async(isp, ISPASYNC_UNHANDLED_RESPONSE, hp)) {
+ return (1);
+ }
return (0);
}
}
-static void
-isp_parse_status(struct ispsoftc *isp, ispstatusreq_t *sp, XS_T *xs)
+void
+isp_parse_status(struct ispsoftc *isp, ispstatusreq_t *sp, XS_T *xs, long *rp)
{
switch (sp->req_completion_status & 0xff) {
case RQCS_COMPLETE:
@@ -4368,6 +5541,7 @@ isp_parse_status(struct ispsoftc *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;
}
@@ -4380,6 +5554,7 @@ isp_parse_status(struct ispsoftc *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:
@@ -4435,6 +5610,7 @@ isp_parse_status(struct ispsoftc *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:
@@ -4445,6 +5621,7 @@ isp_parse_status(struct ispsoftc *isp, ispstatusreq_t *sp, XS_T *xs)
if (XS_NOERR(xs)) {
XS_SETERR(xs, HBA_BUSRESET);
}
+ *rp = XS_XFRLEN(xs);
return;
case RQCS_ABORTED:
@@ -4460,15 +5637,8 @@ isp_parse_status(struct ispsoftc *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);
}
@@ -4675,40 +5845,214 @@ isp_parse_status(struct ispsoftc *isp, ispstatusreq_t *sp, XS_T *xs)
* No such port on the loop. Moral equivalent of SELTIMEO
*/
case RQCS_PORT_LOGGED_OUT:
+ {
+ const char *reason;
+ u_int8_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 (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);
+ }
+}
+
+void
+isp_parse_status_24xx(struct ispsoftc *isp, isp24xx_statusreq_t *sp,
+ XS_T *xs, long *rp)
+{
+ int ru_marked, sv_marked;
+ 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:
+ ru_marked = (sp->req_scsi_status & RQCS_RU) != 0;
/*
- * Probably overkill.
+ * We can get an underrun w/o things being marked
+ * if we got a non-zero status.
*/
- 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);
+ sv_marked = (sp->req_scsi_status & (RQCS_SV|RQCS_RV)) != 0;
+ if ((ru_marked == 0 && sv_marked == 0) ||
+ (sp->req_resid > XS_XFRLEN(xs))) {
+ isp_prt(isp, ISP_LOGWARN, bun, XS_TGT(xs),
+ XS_LUN(xs), XS_XFRLEN(xs), sp->req_resid,
+ (ru_marked)? "marked" : "not marked");
+ if (XS_NOERR(xs)) {
+ XS_SETERR(xs, HBA_BOTCH);
+ }
+ return;
+ }
+ XS_RESID(xs) = sp->req_resid;
+ isp_prt(isp, ISP_LOGDEBUG0,
+ "%d.%d.%d data underrun (%d) for command 0x%x",
+ XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs),
+ sp->req_resid, XS_CDBP(xs)[0] & 0xff);
if (XS_NOERR(xs)) {
- XS_SETERR(xs, HBA_SELTIMEOUT);
+ XS_SETERR(xs, HBA_NOERROR);
}
return;
+ case RQCS_PORT_UNAVAILABLE:
+ /*
+ * No such port on the loop. Moral equivalent of SELTIMEO
+ */
+ case RQCS_PORT_LOGGED_OUT:
+ {
+ const char *reason;
+ u_int8_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));
@@ -4717,10 +6061,22 @@ isp_parse_status(struct ispsoftc *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;
@@ -4735,7 +6091,7 @@ isp_parse_status(struct ispsoftc *isp, ispstatusreq_t *sp, XS_T *xs)
}
}
-static void
+void
isp_fastpost_complete(struct ispsoftc *isp, u_int16_t fph)
{
XS_T *xs;
@@ -4745,7 +6101,7 @@ isp_fastpost_complete(struct ispsoftc *isp, u_int16_t fph)
}
xs = isp_find_xs(isp, fph);
if (xs == NULL) {
- isp_prt(isp, ISP_LOGWARN,
+ isp_prt(isp, ISP_LOGDEBUG1,
"Command for fast post handle 0x%x not found", fph);
return;
}
@@ -4768,15 +6124,17 @@ isp_fastpost_complete(struct ispsoftc *isp, u_int16_t fph)
isp_done(xs);
}
-static int
+int
isp_mbox_continue(struct ispsoftc *isp)
{
mbreg_t mbs;
u_int16_t *ptr;
+ u_int32_t offset;
switch (isp->isp_lastmbxcmd) {
case MBOX_WRITE_RAM_WORD:
case MBOX_READ_RAM_WORD:
+ case MBOX_WRITE_RAM_WORD_EXTENDED:
case MBOX_READ_RAM_WORD_EXTENDED:
break;
default:
@@ -4787,12 +6145,15 @@ isp_mbox_continue(struct ispsoftc *isp)
return (-1);
}
-
/*
* 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.
@@ -4801,27 +6162,46 @@ isp_mbox_continue(struct ispsoftc *isp)
ptr = isp->isp_mbxworkp;
switch (isp->isp_lastmbxcmd) {
case MBOX_WRITE_RAM_WORD:
- mbs.param[2] = *ptr++;
- mbs.param[1] = isp->isp_mbxwrk1++;
+ mbs.param[1] = isp->isp_mbxwrk1++;;
+ mbs.param[2] = *ptr++;;
break;
case MBOX_READ_RAM_WORD:
- case MBOX_READ_RAM_WORD_EXTENDED:
*ptr++ = isp->isp_mboxtmp[2];
mbs.param[1] = isp->isp_mbxwrk1++;
break;
+ case MBOX_WRITE_RAM_WORD_EXTENDED:
+ offset = isp->isp_mbxwrk1;
+ offset |= isp->isp_mbxwrk8 << 16;
+
+ mbs.param[2] = *ptr++;;
+ mbs.param[1] = offset;
+ mbs.param[8] = offset >> 16;
+ isp->isp_mbxwrk1 = ++offset;
+ isp->isp_mbxwrk8 = offset >> 16;
+ break;
+ case MBOX_READ_RAM_WORD_EXTENDED:
+ offset = isp->isp_mbxwrk1;
+ offset |= isp->isp_mbxwrk8 << 16;
+
+ *ptr++ = isp->isp_mboxtmp[2];
+ mbs.param[1] = offset;
+ mbs.param[8] = offset >> 16;
+ isp->isp_mbxwrk1 = ++offset;
+ isp->isp_mbxwrk8 = offset >> 16;
+ break;
}
isp->isp_mbxworkp = ptr;
+ isp->isp_mbxwrk0--;
mbs.param[0] = isp->isp_lastmbxcmd;
- isp->isp_mbxwrk0 -= 1;
+ mbs.logval = MBLOGALL;
isp_mboxcmd_qnw(isp, &mbs, 0);
return (0);
}
-
-#define HIBYT(x) ((x) >> 0x8)
-#define LOBYT(x) ((x) & 0xff)
-#define ISPOPMAP(a, b) (((a) << 8) | (b))
-static const u_int16_t mbpscsi[] = {
+#define HIWRD(x) ((x) >> 16)
+#define LOWRD(x) ((x) & 0xffff)
+#define ISPOPMAP(a, b) (((a) << 16) | (b))
+static const u_int32_t mbpscsi[] = {
ISPOPMAP(0x01, 0x01), /* 0x00: MBOX_NO_OP */
ISPOPMAP(0x1f, 0x01), /* 0x01: MBOX_LOAD_RAM */
ISPOPMAP(0x03, 0x01), /* 0x02: MBOX_EXEC_FIRMWARE */
@@ -4829,7 +6209,7 @@ static const u_int16_t mbpscsi[] = {
ISPOPMAP(0x07, 0x07), /* 0x04: MBOX_WRITE_RAM_WORD */
ISPOPMAP(0x03, 0x07), /* 0x05: MBOX_READ_RAM_WORD */
ISPOPMAP(0x3f, 0x3f), /* 0x06: MBOX_MAILBOX_REG_TEST */
- ISPOPMAP(0x03, 0x07), /* 0x07: MBOX_VERIFY_CHECKSUM */
+ ISPOPMAP(0x07, 0x07), /* 0x07: MBOX_VERIFY_CHECKSUM */
ISPOPMAP(0x01, 0x0f), /* 0x08: MBOX_ABOUT_FIRMWARE */
ISPOPMAP(0x00, 0x00), /* 0x09: */
ISPOPMAP(0x00, 0x00), /* 0x0a: */
@@ -4906,7 +6286,7 @@ static const u_int16_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: */
@@ -4922,8 +6302,8 @@ static const u_int16_t mbpscsi[] = {
#define ISP_STRIPPED
#endif
-#ifndef ISP_STRIPPED
-static char *scsi_mbcmd_names[] = {
+#ifndef ISP_STRIPPED
+static const char *scsi_mbcmd_names[] = {
"NO-OP",
"LOAD RAM",
"EXEC FIRMWARE",
@@ -5021,23 +6401,23 @@ static char *scsi_mbcmd_names[] = {
};
#endif
-static const u_int16_t mbpfc[] = {
+static const u_int32_t mbpfc[] = {
ISPOPMAP(0x01, 0x01), /* 0x00: MBOX_NO_OP */
ISPOPMAP(0x1f, 0x01), /* 0x01: MBOX_LOAD_RAM */
- ISPOPMAP(0x03, 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(0x00, 0x00), /* 0x0d: */
+ ISPOPMAP(0x10f, 0x01), /* 0x0d: MBOX_WRITE_RAM_WORD_EXTENDED */
ISPOPMAP(0x01, 0x05), /* 0x0e: MBOX_CHECK_FIRMWARE */
- ISPOPMAP(0x03, 0x07), /* 0x0f: MBOX_READ_RAM_WORD_EXTENDED(1) */
+ ISPOPMAP(0x10f, 0x05), /* 0x0f: MBOX_READ_RAM_WORD_EXTENDED */
ISPOPMAP(0x1f, 0x11), /* 0x10: MBOX_INIT_REQ_QUEUE */
ISPOPMAP(0x2f, 0x21), /* 0x11: MBOX_INIT_RES_QUEUE */
ISPOPMAP(0x0f, 0x01), /* 0x12: MBOX_EXECUTE_IOCB */
@@ -5088,8 +6468,8 @@ static const u_int16_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: */
@@ -5118,7 +6498,7 @@ static const u_int16_t mbpfc[] = {
ISPOPMAP(0x07, 0x03), /* 0x5d: MBOX_GET_SET_DATA_RATE */
ISPOPMAP(0x00, 0x00), /* 0x5e: */
ISPOPMAP(0x00, 0x00), /* 0x5f: */
- ISPOPMAP(0xfd, 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 */
@@ -5148,18 +6528,19 @@ static const u_int16_t mbpfc[] = {
ISPOPMAP(0x00, 0x00), /* 0x7b: */
ISPOPMAP(0x4f, 0x03), /* 0x7c: Get ID List */
ISPOPMAP(0xcf, 0x01), /* 0x7d: SEND LFA */
- ISPOPMAP(0x07, 0x01) /* 0x7e: Lun RESET */
+ ISPOPMAP(0x0f, 0x01) /* 0x7e: LUN RESET */
};
/*
* Footnotes
*
* (1): this sets bits 21..16 in mailbox register #8, which we nominally
* do not access at this time in the core driver. The caller is
- * responsible for setting this register first (Gross!).
+ * responsible for setting this register first (Gross!). The assumption
+ * is that we won't overflow.
*/
-#ifndef ISP_STRIPPED
-static char *fc_mbcmd_names[] = {
+#ifndef ISP_STRIPPED
+static const char *fc_mbcmd_names[] = {
"NO-OP",
"LOAD RAM",
"EXEC FIRMWARE",
@@ -5171,7 +6552,7 @@ static char *fc_mbcmd_names[] = {
"ABOUT FIRMWARE",
"LOAD RAM",
"DUMP RAM",
- NULL,
+ "WRITE RAM WORD EXTENDED",
NULL,
"READ RAM WORD EXTENDED",
"CHECK FIRMWARE",
@@ -5226,12 +6607,12 @@ static char *fc_mbcmd_names[] = {
NULL,
"LOOP PORT BYPASS",
"LOOP PORT ENABLE",
- "GET RESOURCE COUNTS",
+ "GET RESOURCE COUNT",
"REQUEST NON PARTICIPATING MODE",
NULL,
NULL,
NULL,
- "GET PORT DATABASE,, ENHANCED",
+ "GET PORT DATABASE ENHANCED",
NULL,
NULL,
NULL,
@@ -5290,26 +6671,24 @@ static char *fc_mbcmd_names[] = {
};
#endif
-static void
+void
isp_mboxcmd_qnw(struct ispsoftc *isp, mbreg_t *mbp, int nodelay)
{
- unsigned int lim, ibits, obits, box, opcode;
- const u_int16_t *mcp;
+ unsigned int ibits, obits, box, opcode;
+ const u_int32_t *mcp;
if (IS_FC(isp)) {
mcp = mbpfc;
- lim = (sizeof (mbpfc) / sizeof (mbpfc[0]));
} else {
mcp = mbpscsi;
- lim = (sizeof (mbpscsi) / sizeof (mbpscsi[0]));
}
opcode = mbp->param[0];
- ibits = HIBYT(mcp[opcode]) & NMBOX_BMASK(isp);
- obits = LOBYT(mcp[opcode]) & NMBOX_BMASK(isp);
- for (box = 0; box < MAX_MAILBOX; box++) {
+ ibits = HIWRD(mcp[opcode]) & NMBOX_BMASK(isp);
+ obits = LOWRD(mcp[opcode]) & NMBOX_BMASK(isp);
+ ibits |= mbp->ibits;
+ obits |= mbp->obits;
+ for (box = 0; box < MAX_MAILBOX(isp); box++) {
if (ibits & (1 << box)) {
- isp_prt(isp, ISP_LOGDEBUG1, "IN mbox %d = 0x%x", box,
- mbp->param[box]);
ISP_WRITE(isp, MBOX_OFF(box), mbp->param[box]);
}
if (nodelay == 0) {
@@ -5321,7 +6700,11 @@ isp_mboxcmd_qnw(struct ispsoftc *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
@@ -5332,12 +6715,13 @@ isp_mboxcmd_qnw(struct ispsoftc *isp, mbreg_t *mbp, int nodelay)
}
}
-static void
-isp_mboxcmd(struct ispsoftc *isp, mbreg_t *mbp, int logmask)
+void
+isp_mboxcmd(struct ispsoftc *isp, mbreg_t *mbp)
{
- char *cname, *xname, tname[16], mname[16];
+ const char *cname, *xname;
+ char tname[16], mname[16];
unsigned int lim, ibits, obits, box, opcode;
- const u_int16_t *mcp;
+ const u_int32_t *mcp;
if (IS_FC(isp)) {
mcp = mbpfc;
@@ -5353,8 +6737,14 @@ isp_mboxcmd(struct ispsoftc *isp, mbreg_t *mbp, int logmask)
return;
}
- ibits = HIBYT(mcp[opcode]) & NMBOX_BMASK(isp);
- obits = LOBYT(mcp[opcode]) & NMBOX_BMASK(isp);
+ ibits = HIWRD(mcp[opcode]) & NMBOX_BMASK(isp);
+ obits = LOWRD(mcp[opcode]) & NMBOX_BMASK(isp);
+
+ /*
+ * Pick up any additional bits that the caller might have set.
+ */
+ ibits |= mbp->ibits;
+ obits |= mbp->obits;
if (ibits == 0 && obits == 0) {
mbp->param[0] = MBOX_COMMAND_PARAM_ERROR;
@@ -5365,10 +6755,15 @@ isp_mboxcmd(struct ispsoftc *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; box++) {
+ for (box = 0; box < MAX_MAILBOX(isp); box++) {
if (ibits & (1 << box)) {
+ isp_prt(isp, ISP_LOGDEBUG1, "IN mbox %d = 0x%04x", box,
+ mbp->param[box]);
ISP_WRITE(isp, MBOX_OFF(box), mbp->param[box]);
}
isp->isp_mboxtmp[box] = mbp->param[box] = 0;
@@ -5385,39 +6780,43 @@ isp_mboxcmd(struct ispsoftc *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);
- if (isp->isp_mboxbsy) {
- /*
- * Command timed out.
- */
- isp->isp_mboxbsy = 0;
+ /*
+ * Did the command time out?
+ */
+ if (mbp->param[0] == MBOX_TIMEOUT) {
MBOX_RELEASE(isp);
- return;
+ goto out;
}
/*
* Copy back output registers.
*/
- for (box = 0; box < MAX_MAILBOX; box++) {
+ 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
+#ifdef ISP_STRIPPED
cname = NULL;
#else
cname = (IS_FC(isp))? fc_mbcmd_names[opcode] : scsi_mbcmd_names[opcode];
@@ -5435,38 +6834,49 @@ isp_mboxcmd(struct ispsoftc *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 MBOX_REGS_BUSY:
+ xname = "REGISTERS BUSY";
break;
- case 0: /* special case */
+ case MBOX_TIMEOUT:
xname = "TIMEOUT";
break;
default:
@@ -5474,12 +6884,13 @@ isp_mboxcmd(struct ispsoftc *isp, mbreg_t *mbp, int logmask)
xname = mname;
break;
}
- if (xname)
+ if (xname) {
isp_prt(isp, ISP_LOGALL, "Mailbox Command '%s' failed (%s)",
cname, xname);
+ }
}
-static void
+void
isp_fw_state(struct ispsoftc *isp)
{
if (IS_FC(isp)) {
@@ -5488,14 +6899,15 @@ isp_fw_state(struct ispsoftc *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];
}
}
}
-static void
+void
isp_update(struct ispsoftc *isp)
{
int bus, upmask;
@@ -5508,7 +6920,7 @@ isp_update(struct ispsoftc *isp)
}
}
-static void
+void
isp_update_bus(struct ispsoftc *isp, int bus)
{
int tgt;
@@ -5550,17 +6962,16 @@ isp_update_bus(struct ispsoftc *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;
/*
@@ -5594,26 +7005,31 @@ isp_update_bus(struct ispsoftc *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++) {
@@ -5625,100 +7041,16 @@ isp_update_bus(struct ispsoftc *isp, int bus)
}
}
-#ifndef DEFAULT_FRAMESIZE
-#define DEFAULT_FRAMESIZE(isp) ICB_DFLT_FRMLEN
-#endif
#ifndef DEFAULT_EXEC_THROTTLE
#define DEFAULT_EXEC_THROTTLE(isp) ISP_EXEC_THROTTLE
#endif
-static void
+void
isp_setdfltparm(struct ispsoftc *isp, int channel)
{
int tgt;
sdparam *sdp;
- if (IS_FC(isp)) {
- fcparam *fcp = (fcparam *) isp->isp_param;
- int nvfail;
-
- fcp += channel;
- if (fcp->isp_gotdparms) {
- return;
- }
- fcp->isp_gotdparms = 1;
- fcp->isp_maxfrmlen = DEFAULT_FRAMESIZE(isp);
- fcp->isp_maxalloc = ICB_DFLT_ALLOC;
- fcp->isp_execthrottle = DEFAULT_EXEC_THROTTLE(isp);
- fcp->isp_retry_delay = ICB_DFLT_RDELAY;
- 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_fwoptions = 0;
- fcp->isp_fwoptions |= ICBOPT_FAIRNESS;
- fcp->isp_fwoptions |= ICBOPT_PDBCHANGE_AE;
- fcp->isp_fwoptions |= ICBOPT_HARD_ADDRESS;
-#ifndef ISP_NO_FASTPOST_FC
- fcp->isp_fwoptions |= ICBOPT_FAST_POST;
-#endif
- if (isp->isp_confopts & ISP_CFG_FULL_DUPLEX)
- fcp->isp_fwoptions |= ICBOPT_FULL_DUPLEX;
-
- /*
- * Make sure this is turned off now until we get
- * extended options from NVRAM
- */
- fcp->isp_fwoptions &= ~ICBOPT_EXTENDED;
-
- /*
- * Now try and read NVRAM unless told to not do so.
- * This will set fcparam's isp_nodewwn && isp_portwwn.
- */
- if ((isp->isp_confopts & ISP_CFG_NONVRAM) == 0) {
- nvfail = isp_read_nvram(isp);
- if (nvfail)
- isp->isp_confopts |= ISP_CFG_NONVRAM;
- } else {
- nvfail = 1;
- }
- /*
- * Set node && port to override platform set defaults
- * unless the nvram read failed (or none was done),
- * or the platform code wants to use what had been
- * set in the defaults.
- */
- if (nvfail) {
- isp->isp_confopts |= ISP_CFG_OWNWWPN|ISP_CFG_OWNWWNN;
- }
- if (isp->isp_confopts & ISP_CFG_OWNWWNN) {
- isp_prt(isp, ISP_LOGCONFIG, "Using Node WWN 0x%08x%08x",
- (u_int32_t) (DEFAULT_NODEWWN(isp) >> 32),
- (u_int32_t) (DEFAULT_NODEWWN(isp) & 0xffffffff));
- ISP_NODEWWN(isp) = DEFAULT_NODEWWN(isp);
- } else {
- /*
- * We always start out with values derived
- * from NVRAM or our platform default.
- */
- ISP_NODEWWN(isp) = fcp->isp_nodewwn;
- }
- if (isp->isp_confopts & ISP_CFG_OWNWWPN) {
- isp_prt(isp, ISP_LOGCONFIG, "Using Port WWN 0x%08x%08x",
- (u_int32_t) (DEFAULT_PORTWWN(isp) >> 32),
- (u_int32_t) (DEFAULT_PORTWWN(isp) & 0xffffffff));
- ISP_PORTWWN(isp) = DEFAULT_PORTWWN(isp);
- } else {
- /*
- * We always start out with values derived
- * from NVRAM or our platform default.
- */
- ISP_PORTWWN(isp) = fcp->isp_portwwn;
- }
- return;
- }
-
sdp = (sdparam *) isp->isp_param;
sdp += channel;
@@ -5729,7 +7061,7 @@ isp_setdfltparm(struct ispsoftc *isp, int channel)
return;
}
sdp->isp_gotdparms = 1;
-
+ sdp->isp_bad_nvram = 0;
/*
* Establish some default parameters.
*/
@@ -5769,6 +7101,7 @@ isp_setdfltparm(struct ispsoftc *isp, int channel)
if (isp_read_nvram(isp) == 0) {
return;
}
+ sdp->isp_bad_nvram = 1;
}
/*
@@ -5779,7 +7112,8 @@ isp_setdfltparm(struct ispsoftc *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;
@@ -5817,7 +7151,7 @@ isp_setdfltparm(struct ispsoftc *isp, int channel)
/*
* We default to Wide/Fast for versions less than a 1040
- * (unless its SBus).
+ * (unless it's SBus).
*/
if (IS_ULTRA3(isp)) {
off = ISP_80M_SYNCPARMS >> 8;
@@ -5852,20 +7186,125 @@ isp_setdfltparm(struct ispsoftc *isp, int channel)
}
}
+#ifndef DEFAULT_FRAMESIZE
+#define DEFAULT_FRAMESIZE(isp) ICB_DFLT_FRMLEN
+#endif
+void
+isp_setdfltfcparm(struct ispsoftc *isp)
+{
+ fcparam *fcp = FCPARAM(isp);
+
+ if (fcp->isp_gotdparms) {
+ return;
+ }
+ fcp->isp_gotdparms = 1;
+ fcp->isp_bad_nvram = 0;
+ fcp->isp_maxfrmlen = DEFAULT_FRAMESIZE(isp);
+ fcp->isp_maxalloc = ICB_DFLT_ALLOC;
+ fcp->isp_execthrottle = DEFAULT_EXEC_THROTTLE(isp);
+ fcp->isp_retry_delay = ICB_DFLT_RDELAY;
+ fcp->isp_retry_count = ICB_DFLT_RCOUNT;
+ /* Platform specific.... */
+ fcp->isp_loopid = DEFAULT_LOOPID(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) {
+ fcp->isp_fwoptions |= ICBOPT_FULL_DUPLEX;
+ }
+
+ /*
+ * Make sure this is turned off now until we get
+ * extended options from NVRAM
+ */
+ fcp->isp_fwoptions &= ~ICBOPT_EXTENDED;
+
+ /*
+ * Now try and read NVRAM unless told to not do so.
+ * This will set fcparam's isp_wwnn_nvram && isp_wwpn_nvram.
+ */
+ if ((isp->isp_confopts & ISP_CFG_NONVRAM) == 0) {
+ int i, j = 0;
+ /*
+ * Give a couple of tries at reading NVRAM.
+ */
+ for (i = 0; i < 2; i++) {
+ j = isp_read_nvram(isp);
+ if (j == 0) {
+ break;
+ }
+ }
+ if (j) {
+ fcp->isp_bad_nvram = 1;
+ isp->isp_confopts |= ISP_CFG_NONVRAM;
+ isp->isp_confopts |= ISP_CFG_OWNWWPN;
+ isp->isp_confopts |= ISP_CFG_OWNWWNN;
+ }
+ } else {
+ isp->isp_confopts |= ISP_CFG_OWNWWPN|ISP_CFG_OWNWWNN;
+ }
+
+ /*
+ * Set node && port to override platform set defaults
+ * unless the nvram read failed (or none was done),
+ * or the platform code wants to use what had been
+ * set in the defaults.
+ */
+ if (isp->isp_confopts & ISP_CFG_OWNWWNN) {
+ isp_prt(isp, ISP_LOGCONFIG, "Using Node WWN 0x%08x%08x",
+ (u_int32_t) (DEFAULT_NODEWWN(isp) >> 32),
+ (u_int32_t) (DEFAULT_NODEWWN(isp) & 0xffffffff));
+ ISP_NODEWWN(isp) = DEFAULT_NODEWWN(isp);
+ } else {
+ /*
+ * We always start out with values derived
+ * from NVRAM or our platform default.
+ */
+ ISP_NODEWWN(isp) = fcp->isp_wwnn_nvram;
+ if (fcp->isp_wwnn_nvram == 0) {
+ isp_prt(isp, ISP_LOGCONFIG,
+ "bad WWNN- using default");
+ ISP_NODEWWN(isp) = DEFAULT_NODEWWN(isp);
+ }
+ }
+ if (isp->isp_confopts & ISP_CFG_OWNWWPN) {
+ isp_prt(isp, ISP_LOGCONFIG, "Using Port WWN 0x%08x%08x",
+ (u_int32_t) (DEFAULT_PORTWWN(isp) >> 32),
+ (u_int32_t) (DEFAULT_PORTWWN(isp) & 0xffffffff));
+ ISP_PORTWWN(isp) = DEFAULT_PORTWWN(isp);
+ } else {
+ /*
+ * We always start out with values derived
+ * from NVRAM or our platform default.
+ */
+ ISP_PORTWWN(isp) = fcp->isp_wwpn_nvram;
+ if (fcp->isp_wwpn_nvram == 0) {
+ isp_prt(isp, ISP_LOGCONFIG,
+ "bad WWPN- using default");
+ ISP_PORTWWN(isp) = DEFAULT_PORTWWN(isp);
+ }
+ }
+}
+
/*
* 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(struct ispsoftc *isp)
{
XS_T *xs;
- u_int16_t handle;
+ u_int32_t tmp;
+ if (IS_FC(isp)) {
+ ISP_MARK_PORTDB(isp, 0);
+ }
isp_reset(isp);
if (isp->isp_state != ISP_RESETSTATE) {
isp_prt(isp, ISP_LOGERR, "isp_reinit cannot reset card");
@@ -5877,15 +7316,36 @@ isp_reinit(struct ispsoftc *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 (handle = 1; (int) handle <= isp->isp_maxcmds; handle++) {
- xs = isp_find_xs(isp, handle);
+ for (tmp = 0; tmp < isp->isp_maxcmds; tmp++) {
+ u_int32_t handle;
+
+ xs = isp->isp_xflist[tmp];
if (xs == NULL) {
continue;
}
+ handle = isp_find_handle(isp, xs);
+ if (handle == 0) {
+ continue;
+ }
isp_destroy_handle(isp, handle);
if (XS_XFRLEN(xs)) {
ISP_DMAFREE(isp, xs, handle);
@@ -5896,15 +7356,18 @@ isp_reinit(struct ispsoftc *isp)
XS_SETERR(xs, HBA_BUSRESET);
isp_done(xs);
}
+#ifdef ISP_TARGET_MODE
+ MEMZERO(isp->isp_tgtlist, isp->isp_maxcmds * sizeof (void **));
+#endif
}
/*
* NVRAM Routines
*/
-static int
+int
isp_read_nvram(struct ispsoftc *isp)
{
- int i, amt;
+ int i, amt, retval;
u_int8_t csum, minversion;
union {
u_int8_t _x[ISP2100_NVRAM_SIZE];
@@ -5913,7 +7376,9 @@ isp_read_nvram(struct ispsoftc *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)) {
@@ -5924,13 +7389,10 @@ isp_read_nvram(struct ispsoftc *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) {
@@ -5938,22 +7400,24 @@ isp_read_nvram(struct ispsoftc *isp)
isp_prt(isp, ISP_LOGDEBUG0, "%x %x %x",
nvram_data[0], nvram_data[1], nvram_data[2]);
}
- return (-1);
- }
- for (i = 2; i < amt>>1; i++) {
- isp_rdnvram_word(isp, i, &nvram_words[i]);
+ retval = -1;
+ goto out;
}
+
for (csum = 0, i = 0; i < amt; i++) {
csum += nvram_data[i];
}
if (csum != 0) {
isp_prt(isp, ISP_LOGWARN, "invalid NVRAM checksum");
- return (-1);
+ 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));
- return (-1);
+ retval = -1;
+ goto out;
}
if (IS_ULTRA3(isp)) {
@@ -5970,24 +7434,66 @@ isp_read_nvram(struct ispsoftc *isp)
} else {
isp_parse_nvram_2100(isp, nvram_data);
}
- return (0);
+ retval = 0;
+out:
+ return (retval);
#undef nvram_data
#undef nvram_words
}
-static void
+int
+isp_read_nvram_2400(struct ispsoftc *isp)
+{
+ u_int8_t *nvram_data = FCPARAM(isp)->isp_scratch;
+ int retval = 0;
+ u_int32_t addr, csum, lwrds, *dptr;
+
+ if (isp->isp_port) {
+ addr = ISP2400_NVRAM_PORT1_ADDR;
+ } else {
+ addr = ISP2400_NVRAM_PORT0_ADDR;
+ }
+
+ dptr = (u_int32_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 (%x %x %x)",
+ nvram_data[0], nvram_data[1], nvram_data[2]);
+ retval = -1;
+ goto out;
+ }
+ dptr = (u_int32_t *) nvram_data;
+ for (csum = 0, lwrds = 0; lwrds < ISP2400_NVRAM_SIZE >> 2; lwrds++) {
+ u_int32_t tmp;
+ ISP_IOXGET_32(isp, &dptr[lwrds], tmp);
+ csum += tmp;
+ }
+ 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);
+}
+
+void
isp_rdnvram_word(struct ispsoftc *isp, int wo, u_int16_t *rp)
{
int i, cbits;
- u_int16_t bit, rqst;
+ u_int16_t bit, rqst, junk;
ISP_WRITE(isp, BIU_NVRAM, BIU_NVRAM_SELECT);
- USEC_DELAY(2);
+ USEC_DELAY(10);
ISP_WRITE(isp, BIU_NVRAM, BIU_NVRAM_SELECT|BIU_NVRAM_CLOCK);
- USEC_DELAY(2);
+ USEC_DELAY(10);
if (IS_FC(isp)) {
- wo &= ((ISP2100_NVRAM_SIZE >> 1) - 1);
+ wo &= ((ISP2100_NVRAM_SIZE >> 1) - 1);
if (IS_2312(isp) && isp->isp_port) {
wo += 128;
}
@@ -6013,11 +7519,14 @@ isp_rdnvram_word(struct ispsoftc *isp, int wo, u_int16_t *rp)
bit = BIU_NVRAM_SELECT;
}
ISP_WRITE(isp, BIU_NVRAM, bit);
- USEC_DELAY(2);
+ USEC_DELAY(10);
+ junk = ISP_READ(isp, BIU_NVRAM); /* force PCI flush */
ISP_WRITE(isp, BIU_NVRAM, bit | BIU_NVRAM_CLOCK);
- USEC_DELAY(2);
+ USEC_DELAY(10);
+ junk = ISP_READ(isp, BIU_NVRAM); /* force PCI flush */
ISP_WRITE(isp, BIU_NVRAM, bit);
- USEC_DELAY(2);
+ USEC_DELAY(10);
+ junk = ISP_READ(isp, BIU_NVRAM); /* force PCI flush */
}
/*
* Now read the result back in (bits come back in MSB format).
@@ -6027,21 +7536,46 @@ isp_rdnvram_word(struct ispsoftc *isp, int wo, u_int16_t *rp)
u_int16_t rv;
*rp <<= 1;
ISP_WRITE(isp, BIU_NVRAM, BIU_NVRAM_SELECT|BIU_NVRAM_CLOCK);
- USEC_DELAY(2);
+ USEC_DELAY(10);
rv = ISP_READ(isp, BIU_NVRAM);
if (rv & BIU_NVRAM_DATAIN) {
*rp |= 1;
}
- USEC_DELAY(2);
+ USEC_DELAY(10);
ISP_WRITE(isp, BIU_NVRAM, BIU_NVRAM_SELECT);
- USEC_DELAY(2);
+ USEC_DELAY(10);
+ junk = ISP_READ(isp, BIU_NVRAM); /* force PCI flush */
}
ISP_WRITE(isp, BIU_NVRAM, 0);
- USEC_DELAY(2);
+ USEC_DELAY(10);
+ junk = ISP_READ(isp, BIU_NVRAM); /* force PCI flush */
ISP_SWIZZLE_NVRAM_WORD(isp, rp);
}
-static void
+void
+isp_rd_2400_nvram(struct ispsoftc *isp, u_int32_t addr, u_int32_t *rp)
+{
+ int loops = 0;
+ const u_int32_t base = 0x7ffe0000;
+ u_int32_t tmp = 0;
+
+ 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)) {
+ *rp = ISP_READ(isp, BIU2400_FLASH_DATA);
+ ISP_SWIZZLE_NVRAM_LONG(isp, rp);
+ } else {
+ *rp = 0xffffffff;
+ }
+}
+
+void
isp_parse_nvram_1020(struct ispsoftc *isp, u_int8_t *nvram_data)
{
sdparam *sdp = (sdparam *) isp->isp_param;
@@ -6167,7 +7701,7 @@ isp_parse_nvram_1020(struct ispsoftc *isp, u_int8_t *nvram_data)
}
}
-static void
+void
isp_parse_nvram_1080(struct ispsoftc *isp, int bus, u_int8_t *nvram_data)
{
sdparam *sdp = (sdparam *) isp->isp_param;
@@ -6259,7 +7793,7 @@ isp_parse_nvram_1080(struct ispsoftc *isp, int bus, u_int8_t *nvram_data)
}
}
-static void
+void
isp_parse_nvram_12160(struct ispsoftc *isp, int bus, u_int8_t *nvram_data)
{
sdparam *sdp = (sdparam *) isp->isp_param;
@@ -6350,10 +7884,42 @@ isp_parse_nvram_12160(struct ispsoftc *isp, int bus, u_int8_t *nvram_data)
}
}
-static void
+void
+isp_fix_nvram_wwns(struct ispsoftc *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 & (((u_int64_t) 0xfff) << 48)) != 0 &&
+ (fcp->isp_wwnn_nvram >> 60) == 2) {
+ fcp->isp_wwnn_nvram &= ~((u_int64_t) 0xfff << 48);
+ }
+ if ((fcp->isp_wwpn_nvram & (((u_int64_t) 0xfff) << 48)) == 0 &&
+ (fcp->isp_wwpn_nvram >> 60) == 2) {
+ fcp->isp_wwpn_nvram |= ((u_int64_t) 1 << 56);
+ }
+ }
+}
+
+void
isp_parse_nvram_2100(struct ispsoftc *isp, u_int8_t *nvram_data)
{
- fcparam *fcp = (fcparam *) isp->isp_param;
+ fcparam *fcp = FCPARAM(isp);
u_int64_t wwn;
/*
@@ -6362,7 +7928,7 @@ isp_parse_nvram_2100(struct ispsoftc *isp, u_int8_t *nvram_data)
* I can find. However, we should account for this being set
* at some point in the future.
*
- * QLogic WWNs have an NAA of 2, but usually nothing shows up in
+ * Qlogic WWNs have an NAA of 2, but usually nothing shows up in
* bits 48..60. In the case of the 2202, it appears that they do
* use bit 48 to distinguish between the two instances on the card.
* The 2204, which I've never seen, *probably* extends this method.
@@ -6375,9 +7941,9 @@ isp_parse_nvram_2100(struct ispsoftc *isp, u_int8_t *nvram_data)
wwn |= (((u_int64_t) 2)<< 60);
}
}
- fcp->isp_portwwn = wwn;
+ fcp->isp_wwpn_nvram = wwn;
if (IS_2200(isp) || IS_23XX(isp)) {
- wwn = ISP2200_NVRAM_NODE_NAME(nvram_data);
+ wwn = ISP2100_NVRAM_NODE_NAME(nvram_data);
if (wwn) {
isp_prt(isp, ISP_LOGCONFIG, "NVRAM Node WWN 0x%08x%08x",
(u_int32_t) (wwn >> 32),
@@ -6389,70 +7955,113 @@ isp_parse_nvram_2100(struct ispsoftc *isp, u_int8_t *nvram_data)
} else {
wwn &= ~((u_int64_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);
+
+ 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_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",
+ (u_int32_t) (fcp->isp_wwnn_nvram >> 32), (u_int32_t) fcp->isp_wwnn_nvram,
+ (u_int32_t) (fcp->isp_wwpn_nvram >> 32), (u_int32_t) fcp->isp_wwpn_nvram,
+ ISP2100_NVRAM_MAXIOCBALLOCATION(nvram_data),
+ ISP2100_NVRAM_MAXFRAMELENGTH(nvram_data));
+ isp_prt(isp, ISP_LOGDEBUG0,
+ "execthrottle %d fwoptions 0x%x hardloop %d tov %d",
+ ISP2100_NVRAM_EXECUTION_THROTTLE(nvram_data),
+ ISP2100_NVRAM_OPTIONS(nvram_data),
+ ISP2100_NVRAM_HARDLOOPID(nvram_data),
+ ISP2100_NVRAM_TOV(nvram_data));
+ fcp->isp_xfwoptions = ISP2100_XFW_OPTIONS(nvram_data);
+ fcp->isp_zfwoptions = ISP2100_ZFW_OPTIONS(nvram_data);
+ isp_prt(isp, ISP_LOGDEBUG0,
+ "xfwoptions 0x%x zfw options 0x%x",
+ ISP2100_XFW_OPTIONS(nvram_data), ISP2100_ZFW_OPTIONS(nvram_data));
+}
- /*
- * 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 & (((u_int64_t) 0xfff) << 48)) != 0 &&
- (fcp->isp_nodewwn >> 60) == 2) {
- fcp->isp_nodewwn &= ~((u_int64_t) 0xfff << 48);
+void
+isp_parse_nvram_2400(struct ispsoftc *isp, u_int8_t *nvram_data)
+{
+ fcparam *fcp = FCPARAM(isp);
+ u_int64_t wwn;
+
+ isp_prt(isp, ISP_LOGDEBUG0,
+ "NVRAM 0x%08x%08x 0x%08x%08x exchg_cnt %d maxframelen %d",
+ (u_int32_t) (ISP2400_NVRAM_NODE_NAME(nvram_data) >> 32),
+ (u_int32_t) (ISP2400_NVRAM_NODE_NAME(nvram_data)),
+ (u_int32_t) (ISP2400_NVRAM_PORT_NAME(nvram_data) >> 32),
+ (u_int32_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;
}
- if ((fcp->isp_portwwn & (((u_int64_t) 0xfff) << 48)) == 0 &&
- (fcp->isp_portwwn >> 60) == 2) {
- fcp->isp_portwwn |= ((u_int64_t) 1 << 56);
+ }
+ 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_prt(isp, ISP_LOGDEBUG0,
- "NVRAM: maxfrmlen %d execthrottle %d fwoptions 0x%x loopid %x",
- ISP2100_NVRAM_MAXFRAMELENGTH(nvram_data),
- ISP2100_NVRAM_EXECUTION_THROTTLE(nvram_data),
- ISP2100_NVRAM_OPTIONS(nvram_data),
- ISP2100_NVRAM_HARDLOOPID(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)
+ 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 =
- ISP2100_NVRAM_EXECUTION_THROTTLE(nvram_data);
- fcp->isp_fwoptions = ISP2100_NVRAM_OPTIONS(nvram_data);
+ 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(struct ispsoftc *);
-static void isp2300_fw_dump(struct ispsoftc *);
+void isp2200_fw_dump(struct ispsoftc *);
+void isp2300_fw_dump(struct ispsoftc *);
-static void
+void
isp2200_fw_dump(struct ispsoftc *isp)
{
int i, j;
mbreg_t mbs;
u_int16_t *ptr;
+ MEMZERO(&mbs, sizeof (mbs));
ptr = FCPARAM(isp)->isp_dump_data;
if (ptr == NULL) {
isp_prt(isp, ISP_LOGERR,
@@ -6571,8 +8180,7 @@ isp2200_fw_dump(struct ispsoftc *isp)
break;
}
}
- ENABLE_INTS(isp);
- MEMZERO(&mbs, sizeof (mbs));
+ ISP_ENABLE_INTS(isp);
mbs.param[0] = MBOX_READ_RAM_WORD;
mbs.param[1] = 0x1000;
isp->isp_mbxworkp = (void *) ptr;
@@ -6591,13 +8199,14 @@ isp2200_fw_dump(struct ispsoftc *isp)
(void) isp_async(isp, ISPASYNC_FW_DUMPED, 0);
}
-static void
+void
isp2300_fw_dump(struct ispsoftc *isp)
{
int i, j;
mbreg_t mbs;
u_int16_t *ptr;
+ MEMZERO(&mbs, sizeof (mbs));
ptr = FCPARAM(isp)->isp_dump_data;
if (ptr == NULL) {
isp_prt(isp, ISP_LOGERR,
@@ -6714,7 +8323,7 @@ isp2300_fw_dump(struct ispsoftc *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;
@@ -6729,20 +8338,13 @@ isp2300_fw_dump(struct ispsoftc *isp)
}
ptr = isp->isp_mbxworkp; /* finish fetch of final word */
*ptr++ = isp->isp_mboxtmp[2];
-
- /*
- * We don't have access to mailbox registers 8.. onward
- * in our 'common' device model- so we have to set it
- * here and hope it stays the same!
- */
- ISP_WRITE(isp, PCI_MBOX_REGS2300_OFF + (8 << 1), 0x1);
-
MEMZERO(&mbs, sizeof (mbs));
mbs.param[0] = MBOX_READ_RAM_WORD_EXTENDED;
- mbs.param[1] = 0;
+ mbs.param[8] = 1;
isp->isp_mbxworkp = (void *) ptr;
isp->isp_mbxwrk0 = 0xffff; /* continuation count */
isp->isp_mbxwrk1 = 0x1; /* next SRAM address */
+ isp->isp_mbxwrk8 = 0x1;
isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
isp_prt(isp, ISP_LOGWARN,
@@ -6763,5 +8365,8 @@ isp_fw_dump(struct ispsoftc *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