summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authormjacob <mjacob@cvs.openbsd.org>1999-03-17 05:26:10 +0000
committermjacob <mjacob@cvs.openbsd.org>1999-03-17 05:26:10 +0000
commit45819d403e389eec8c222b4bb1d6f9e69a3b1c81 (patch)
tree58b38f4f25ec6f48e1acd3aa4c658cca44d241f4 /sys/dev
parentff2af7542270ca4ea643938ce7bfa439193412ba (diff)
complete update of ISP driver- includes 2100 FC support
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/isp.c3992
-rw-r--r--sys/dev/ic/isp_openbsd.c438
-rw-r--r--sys/dev/ic/isp_openbsd.h274
-rw-r--r--sys/dev/ic/ispmbox.h779
-rw-r--r--sys/dev/ic/ispreg.h299
-rw-r--r--sys/dev/ic/ispvar.h386
6 files changed, 5448 insertions, 720 deletions
diff --git a/sys/dev/ic/isp.c b/sys/dev/ic/isp.c
index d051a824bd4..4af2fbcea8a 100644
--- a/sys/dev/ic/isp.c
+++ b/sys/dev/ic/isp.c
@@ -1,14 +1,14 @@
-/* $NetBSD: isp.c,v 1.7 1997/06/08 06:31:52 thorpej Exp $ */
-
+/* $OpenBSD: isp.c,v 1.4 1999/03/17 05:26:08 mjacob Exp $ */
+/* release_03_16_99 */
/*
- * Machine Independent (well, as best as possible)
+ * Machine and OS Independent (well, as best as possible)
* code for the Qlogic ISP SCSI adapters.
*
- * Specific probe attach and support routines for Qlogic ISP SCSI adapters.
- *
- * Copyright (c) 1997 by Matthew Jacob
- * NASA AMES Research Center.
+ *---------------------------------------
+ * Copyright (c) 1997, 1998 by Matthew Jacob
+ * NASA/Ames Research Center
* All rights reserved.
+ *---------------------------------------
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,142 +37,373 @@
/*
* Inspiration and ideas about this driver are from Erik Moe's Linux driver
- * (qlogicisp.c) and Dave Miller's SBus version of same (qlogicisp.c)
+ * (qlogicisp.c) and Dave Miller's SBus version of same (qlogicisp.c). Some
+ * ideas dredged from the Solaris driver.
*/
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/errno.h>
-#include <sys/ioctl.h>
-#include <sys/device.h>
-#include <sys/malloc.h>
-#include <sys/buf.h>
-#include <sys/proc.h>
-#include <sys/user.h>
-
-
-#include <scsi/scsi_all.h>
-#include <scsi/scsiconf.h>
-
-#include <scsi/scsi_message.h>
-#include <scsi/scsi_debug.h>
-#include <scsi/scsiconf.h>
+/*
+ * Include header file appropriate for platform we're building on.
+ */
-#include <vm/vm.h>
-#include <vm/vm_param.h>
-#include <vm/pmap.h>
+#ifdef __NetBSD__
+#include <dev/ic/isp_netbsd.h>
+#endif
+#ifdef __FreeBSD__
+#include <dev/isp/isp_freebsd.h>
+#endif
+#ifdef __OpenBSD__
+#include <dev/ic/isp_openbsd.h>
+#endif
+#ifdef __linux__
+#include "isp_linux.h"
+#endif
-#include <dev/ic/ispreg.h>
-#include <dev/ic/ispvar.h>
-#include <dev/ic/ispmbox.h>
+/*
+ * General defines
+ */
#define MBOX_DELAY_COUNT 1000000 / 100
-struct cfdriver isp_cd = {
- NULL, "isp", DV_DULL
-};
-
-static void ispminphys __P((struct buf *));
-static int32_t ispscsicmd __P((struct scsi_xfer *xs));
-static int isp_mboxcmd __P((struct ispsoftc *, mbreg_t *));
-
-static struct scsi_adapter isp_switch = {
- ispscsicmd, ispminphys, 0, 0
+/*
+ * Local static data
+ */
+#ifdef ISP_TARGET_MODE
+static const char tgtiqd[36] = {
+ 0x03, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x51, 0x4C, 0x4F, 0x47, 0x49, 0x43, 0x20, 0x20,
+#ifdef __NetBSD__
+ 0x4E, 0x45, 0x54, 0x42, 0x53, 0x44, 0x20, 0x20,
+#else
+# ifdef __FreeBSD__
+ 0x46, 0x52, 0x45, 0x45, 0x42, 0x52, 0x44, 0x20,
+# else
+# ifdef __OpenBSD__
+ 0x4F, 0x50, 0x45, 0x4E, 0x42, 0x52, 0x44, 0x20,
+# else
+# ifdef linux
+ 0x4C, 0x49, 0x4E, 0x55, 0x58, 0x20, 0x20, 0x20,
+# else
+# endif
+# endif
+# endif
+#endif
+ 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x31
};
+#endif
-static struct scsi_device isp_dev = { NULL, NULL, NULL, NULL };
-static int isp_poll __P((struct ispsoftc *, struct scsi_xfer *, int));
-static int isp_parse_status __P((struct ispsoftc *, ispstatusreq_t *));
-static void isp_lostcmd __P((struct ispsoftc *, struct scsi_xfer *));
+/*
+ * Local function prototypes.
+ */
+static int isp_parse_async __P((struct ispsoftc *, int));
+static int isp_handle_other_response
+__P((struct ispsoftc *, ispstatusreq_t *, u_int8_t *));
+#ifdef ISP_TARGET_MODE
+static int isp_modify_lun __P((struct ispsoftc *, int, int, int));
+static void isp_notify_ack __P((struct ispsoftc *, void *));
+static void isp_handle_atio __P((struct ispsoftc *, void *));
+static void isp_handle_atio2 __P((struct ispsoftc *, void *));
+static void isp_handle_ctio __P((struct ispsoftc *, void *));
+static void isp_handle_ctio2 __P((struct ispsoftc *, void *));
+#endif
+static void isp_parse_status
+__P((struct ispsoftc *, ispstatusreq_t *, ISP_SCSI_XFER_T *));
+static void isp_fastpost_complete __P((struct ispsoftc *, int));
+static void isp_fibre_init __P((struct ispsoftc *));
+static void isp_mark_getpdb_all __P((struct ispsoftc *));
+static int isp_getpdb __P((struct ispsoftc *, int, isp_pdb_t *));
+static int isp_fclink_test __P((struct ispsoftc *));
+static void isp_fw_state __P((struct ispsoftc *));
+static void isp_dumpregs __P((struct ispsoftc *, const char *));
+static void isp_dumpxflist __P((struct ispsoftc *));
+static void isp_mboxcmd __P((struct ispsoftc *, mbreg_t *));
+
+static void isp_update __P((struct ispsoftc *));
+static void isp_setdfltparm __P((struct ispsoftc *));
+static int isp_read_nvram __P((struct ispsoftc *));
+static void isp_rdnvram_word __P((struct ispsoftc *, int, u_int16_t *));
/*
* Reset Hardware.
*
- * Only looks at sc_dev.dv_xname, sc_iot and sc_ioh fields.
+ * Hit the chip over the head, download new f/w and set it running.
+ *
+ * Locking done elsewhere.
*/
void
isp_reset(isp)
struct ispsoftc *isp;
{
mbreg_t mbs;
- int loops, i;
- u_int8_t clock;
+ int loops, i, dodnld = 1;
+ char *revname;
isp->isp_state = ISP_NILSTATE;
+
/*
- * Do MD specific pre initialization
+ * Basic types (SCSI, FibreChannel and PCI or SBus)
+ * have been set in the MD code. We figure out more
+ * here.
*/
- ISP_RESET0(isp);
+ isp->isp_dblev = DFLT_DBLEVEL;
/*
- * Try and get old clock rate out before we hit the
- * chip over the head- but if and only if we don't
- * know our desired clock rate.
+ * After we've fired this chip up, zero out the conf1 register
+ * for SCSI adapters and other settings for the 2100.
*/
- clock = isp->isp_mdvec->dv_clock;
- if (clock == 0) {
- mbs.param[0] = MBOX_GET_CLOCK_RATE;
- (void) isp_mboxcmd(isp, &mbs);
- if (mbs.param[0] == MBOX_COMMAND_COMPLETE) {
- clock = mbs.param[1];
- printf("board-clock 0x%x ", clock);
+
+ /*
+ * Get the current running firmware revision out of the
+ * chip before we hit it over the head (if this is our
+ * first time through). Note that we store this as the
+ * 'ROM' firmware revision- which it may not be. In any
+ * case, we don't really use this yet, but we may in
+ * the future.
+ */
+ if (isp->isp_used == 0) {
+ /*
+ * Just in case it was paused...
+ */
+ ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE);
+ mbs.param[0] = MBOX_ABOUT_FIRMWARE;
+ isp_mboxcmd(isp, &mbs);
+ if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+ /*
+ * If this fails, it probably means we're running
+ * an old prom, if anything at all...
+ */
+ isp->isp_romfw_rev = 0;
} else {
- clock = 0;
+ isp->isp_romfw_rev =
+ (((u_int16_t) mbs.param[1]) << 10) + mbs.param[2];
}
+ isp->isp_used = 1;
}
/*
- * Hit the chip over the head with hammer.
+ * Put it into PAUSE mode.
*/
+ ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE);
+
+ if (IS_FC(isp)) {
+ revname = "2100";
+ } else if (IS_1080(isp)) {
+ sdparam *sdp = isp->isp_param;
+ revname = "1080";
+ sdp->isp_clock = 0; /* don't set clock */
+ sdp->isp_diffmode = 1;
+ sdp->isp_ultramode = 1;
+ } else {
+ sdparam *sdp = isp->isp_param;
+ i = ISP_READ(isp, BIU_CONF0) & BIU_CONF0_HW_MASK;
+ switch (i) {
+ default:
+ PRINTF("%s: unknown chip rev. 0x%x- assuming a 1020\n",
+ isp->isp_name, i);
+ /* FALLTHROUGH */
+ case 1:
+ revname = "1020";
+ isp->isp_type = ISP_HA_SCSI_1020;
+ sdp->isp_clock = 40;
+ break;
+ case 2:
+ /*
+ * Some 1020A chips are Ultra Capable, but don't
+ * run the clock rate up for that unless told to
+ * do so by the Ultra Capable bits being set.
+ */
+ revname = "1020A";
+ isp->isp_type = ISP_HA_SCSI_1020A;
+ sdp->isp_clock = 40;
+ break;
+ case 3:
+ revname = "1040";
+ isp->isp_type = ISP_HA_SCSI_1040;
+ sdp->isp_clock = 60;
+ break;
+ case 4:
+ revname = "1040A";
+ isp->isp_type = ISP_HA_SCSI_1040A;
+ sdp->isp_clock = 60;
+ break;
+ case 5:
+ revname = "1040B";
+ isp->isp_type = ISP_HA_SCSI_1040B;
+ sdp->isp_clock = 60;
+ break;
+ }
+ /*
+ * Now, while we're at it, gather info about ultra
+ * and/or differential mode.
+ */
+ if (ISP_READ(isp, SXP_PINS_DIFF) & SXP_PINS_DIFF_MODE) {
+ PRINTF("%s: Differential Mode\n", isp->isp_name);
+ sdp->isp_diffmode = 1;
+ } else {
+ sdp->isp_diffmode = 0;
+ }
+ i = ISP_READ(isp, RISC_PSR);
+ if (isp->isp_bustype == ISP_BT_SBUS) {
+ i &= RISC_PSR_SBUS_ULTRA;
+ } else {
+ i &= RISC_PSR_PCI_ULTRA;
+ }
+ if (i != 0) {
+ PRINTF("%s: Ultra Mode Capable\n", isp->isp_name);
+ sdp->isp_ultramode = 1;
+ /*
+ * If we're in Ultra Mode, we have to be 60Mhz clock-
+ * even for the SBus version.
+ */
+ sdp->isp_clock = 60;
+ } else {
+ sdp->isp_ultramode = 0;
+ /*
+ * Clock is known. Gronk.
+ */
+ }
+
+ /*
+ * Machine dependent clock (if set) overrides
+ * our generic determinations.
+ */
+ if (isp->isp_mdvec->dv_clock) {
+ if (isp->isp_mdvec->dv_clock < sdp->isp_clock) {
+ sdp->isp_clock = isp->isp_mdvec->dv_clock;
+ }
+ }
+
+ }
- ISP_WRITE(isp, BIU_ICR, BIU_ICR_SOFT_RESET);
/*
- * Give the ISP a chance to recover...
+ * Do MD specific pre initialization
*/
- delay(100);
+ ISP_RESET0(isp);
+
+again:
/*
- * Clear data && control DMA engines.
+ * Hit the chip over the head with hammer,
+ * and give the ISP a chance to recover.
*/
- ISP_WRITE(isp, CDMA_CONTROL,
+
+ if (IS_SCSI(isp)) {
+ ISP_WRITE(isp, BIU_ICR, BIU_ICR_SOFT_RESET);
+ /*
+ * A slight delay...
+ */
+ SYS_DELAY(100);
+
+#if 0
+ PRINTF("%s: mbox0-5: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ isp->isp_name, ISP_READ(isp, OUTMAILBOX0),
+ ISP_READ(isp, OUTMAILBOX1), ISP_READ(isp, OUTMAILBOX2),
+ ISP_READ(isp, OUTMAILBOX3), ISP_READ(isp, OUTMAILBOX4),
+ ISP_READ(isp, OUTMAILBOX5));
+#endif
+
+ /*
+ * Clear data && control DMA engines.
+ */
+ ISP_WRITE(isp, CDMA_CONTROL,
DMA_CNTRL_CLEAR_CHAN | DMA_CNTRL_RESET_INT);
- ISP_WRITE(isp, DDMA_CONTROL,
+ ISP_WRITE(isp, DDMA_CONTROL,
DMA_CNTRL_CLEAR_CHAN | DMA_CNTRL_RESET_INT);
+
+
+ } else {
+ ISP_WRITE(isp, BIU2100_CSR, BIU2100_SOFT_RESET);
+ /*
+ * A slight delay...
+ */
+ SYS_DELAY(100);
+
+ /*
+ * Clear data && control DMA engines.
+ */
+ ISP_WRITE(isp, CDMA2100_CONTROL,
+ DMA_CNTRL2100_CLEAR_CHAN | DMA_CNTRL2100_RESET_INT);
+ ISP_WRITE(isp, TDMA2100_CONTROL,
+ DMA_CNTRL2100_CLEAR_CHAN | DMA_CNTRL2100_RESET_INT);
+ ISP_WRITE(isp, RDMA2100_CONTROL,
+ DMA_CNTRL2100_CLEAR_CHAN | DMA_CNTRL2100_RESET_INT);
+ }
+
/*
* Wait for ISP to be ready to go...
*/
loops = MBOX_DELAY_COUNT;
- while ((ISP_READ(isp, BIU_ICR) & BIU_ICR_SOFT_RESET) != 0) {
- delay(100);
+ for (;;) {
+ if (isp->isp_type & ISP_HA_SCSI) {
+ if (!(ISP_READ(isp, BIU_ICR) & BIU_ICR_SOFT_RESET))
+ break;
+ } else {
+ if (!(ISP_READ(isp, BIU2100_CSR) & BIU2100_SOFT_RESET))
+ break;
+ }
+ SYS_DELAY(100);
if (--loops < 0) {
- printf("chip reset timed out\n", isp->isp_name);
+ isp_dumpregs(isp, "chip reset timed out");
return;
}
}
+
/*
- * More initialization
+ * After we've fired this chip up, zero out the conf1 register
+ * for SCSI adapters and other settings for the 2100.
*/
- ISP_WRITE(isp, BIU_CONF1, 0);
+ if (IS_SCSI(isp)) {
+ ISP_WRITE(isp, BIU_CONF1, 0);
+ } else {
+ ISP_WRITE(isp, BIU2100_CSR, 0);
+ }
+
+ /*
+ * Reset RISC Processor
+ */
ISP_WRITE(isp, HCCR, HCCR_CMD_RESET);
- delay(100);
+ SYS_DELAY(100);
- if (isp->isp_mdvec->dv_conf1) {
- ISP_SETBITS(isp, BIU_CONF1, isp->isp_mdvec->dv_conf1);
- if (isp->isp_mdvec->dv_conf1 & BIU_BURST_ENABLE) {
+ /*
+ * Establish some initial burst rate stuff.
+ * (only for the 1XX0 boards). This really should
+ * be done later after fetching from NVRAM.
+ */
+ if (IS_SCSI(isp)) {
+ u_int16_t tmp = isp->isp_mdvec->dv_conf1;
+ /*
+ * Busted FIFO. Turn off all but burst enables.
+ */
+ if (isp->isp_type == ISP_HA_SCSI_1040A) {
+ tmp &= BIU_BURST_ENABLE;
+ }
+ ISP_SETBITS(isp, BIU_CONF1, tmp);
+ if (tmp & BIU_BURST_ENABLE) {
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);
+ }
+ } 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
} else {
- ISP_WRITE(isp, BIU_CONF1, 0);
+ ISP_WRITE(isp, RISC_MTR2100, 0x1212);
}
-#if 0
- ISP_WRITE(isp, RISC_MTR, 0x1212); /* FM */
-#endif
ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); /* release paused processor */
/*
@@ -183,258 +414,333 @@ isp_reset(isp)
/*
* Enable interrupts
*/
- ISP_WRITE(isp, BIU_ICR,
- BIU_ICR_ENABLE_RISC_INT | BIU_ICR_ENABLE_ALL_INTS);
+ ENABLE_INTS(isp);
/*
- * Do some sanity checking.
+ * Wait for everything to finish firing up...
*/
-
- mbs.param[0] = MBOX_NO_OP;
- (void) isp_mboxcmd(isp, &mbs);
- if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- printf("NOP test failed\n");
- return;
+ loops = MBOX_DELAY_COUNT;
+ while (ISP_READ(isp, OUTMAILBOX0) == MBOX_BUSY) {
+ SYS_DELAY(100);
+ if (--loops < 0) {
+ PRINTF("%s: MBOX_BUSY never cleared on reset\n",
+ isp->isp_name);
+ return;
+ }
}
- mbs.param[0] = MBOX_MAILBOX_REG_TEST;
- mbs.param[1] = 0xdead;
- mbs.param[2] = 0xbeef;
- mbs.param[3] = 0xffff;
- mbs.param[4] = 0x1111;
- mbs.param[5] = 0xa5a5;
- (void) isp_mboxcmd(isp, &mbs);
+ /*
+ * Up until this point we've done everything by just reading or
+ * setting registers. From this point on we rely on at least *some*
+ * kind of firmware running in the card.
+ */
+
+ /*
+ * Do some sanity checking.
+ */
+ mbs.param[0] = MBOX_NO_OP;
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- printf("Mailbox Register test didn't complete\n");
- return;
- }
- i = 0;
- if (mbs.param[1] != 0xdead) {
- printf("Register Test Failed @reg %d (got %x)\n",
- 1, mbs.param[1]);
- i++;
- }
- if (mbs.param[2] != 0xbeef) {
- printf("Register Test Failed @reg %d (got %x)\n",
- 2, mbs.param[2]);
- i++;
- }
- if (mbs.param[3] != 0xffff) {
- printf("Register Test Failed @reg %d (got %x)\n",
- 3, mbs.param[3]);
- i++;
- }
- if (mbs.param[4] != 0x1111) {
- printf("Register Test Failed @reg %d (got %x)\n",
- 4, mbs.param[4]);
- i++;
- }
- if (mbs.param[5] != 0xa5a5) {
- printf("Register Test Failed @reg %d (got %x)\n",
- 5, mbs.param[5]);
- i++;
- }
- if (i) {
+ isp_dumpregs(isp, "NOP test failed");
return;
}
- /*
- * Download new Firmware
- */
- for (i = 0; i < isp->isp_mdvec->dv_fwlen; i++) {
- mbs.param[0] = MBOX_WRITE_RAM_WORD;
- mbs.param[1] = isp->isp_mdvec->dv_codeorg + i;
- mbs.param[2] = isp->isp_mdvec->dv_ispfw[i];
- (void) isp_mboxcmd(isp, &mbs);
+ if (isp->isp_type & ISP_HA_SCSI) {
+ mbs.param[0] = MBOX_MAILBOX_REG_TEST;
+ mbs.param[1] = 0xdead;
+ mbs.param[2] = 0xbeef;
+ mbs.param[3] = 0xffff;
+ mbs.param[4] = 0x1111;
+ mbs.param[5] = 0xa5a5;
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- printf("f/w download failed\n");
+ isp_dumpregs(isp,
+ "Mailbox Register test didn't complete");
+ return;
+ }
+ if (mbs.param[1] != 0xdead || mbs.param[2] != 0xbeef ||
+ mbs.param[3] != 0xffff || mbs.param[4] != 0x1111 ||
+ mbs.param[5] != 0xa5a5) {
+ isp_dumpregs(isp, "Register Test Failed");
return;
}
+
}
/*
- * Verify that it downloaded correctly.
+ * Download new Firmware, unless requested not to do so.
+ * This is made slightly trickier in some cases where the
+ * firmware of the ROM revision is newer than the revision
+ * compiled into the driver. So, where we used to compare
+ * versions of our f/w and the ROM f/w, now we just see
+ * whether we have f/w at all and whether a config flag
+ * has disabled our download.
*/
- mbs.param[0] = MBOX_VERIFY_CHECKSUM;
- mbs.param[1] = isp->isp_mdvec->dv_codeorg;
- (void) isp_mboxcmd(isp, &mbs);
- if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- printf("ram checksum failure\n");
- return;
+ if ((isp->isp_mdvec->dv_fwlen == 0) ||
+ (isp->isp_confopts & ISP_CFG_NORELOAD)) {
+ dodnld = 0;
}
- /*
- * Now start it rolling...
- */
+ if (dodnld && isp->isp_mdvec->dv_fwlen) {
+ for (i = 0; i < isp->isp_mdvec->dv_fwlen; i++) {
+ mbs.param[0] = MBOX_WRITE_RAM_WORD;
+ mbs.param[1] = isp->isp_mdvec->dv_codeorg + i;
+ mbs.param[2] = isp->isp_mdvec->dv_ispfw[i];
+ isp_mboxcmd(isp, &mbs);
+ if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+ PRINTF("%s: F/W download failed at word %d\n",
+ isp->isp_name, i);
+ dodnld = 0;
+ goto again;
+ }
+ }
- mbs.param[0] = MBOX_EXEC_FIRMWARE;
- mbs.param[1] = isp->isp_mdvec->dv_codeorg;
- (void) isp_mboxcmd(isp, &mbs);
+ /*
+ * Verify that it downloaded correctly.
+ */
+ mbs.param[0] = MBOX_VERIFY_CHECKSUM;
+ mbs.param[1] = isp->isp_mdvec->dv_codeorg;
+ isp_mboxcmd(isp, &mbs);
+ if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+ isp_dumpregs(isp, "ram checksum failure");
+ return;
+ }
+ } else {
+ IDPRINTF(3, ("%s: skipping f/w download\n", isp->isp_name));
+ }
/*
- * Set CLOCK RATE
+ * Now start it rolling.
+ *
+ * If we didn't actually download f/w,
+ * we still need to (re)start it.
*/
- if (clock) {
- mbs.param[0] = MBOX_SET_CLOCK_RATE;
- mbs.param[1] = clock;
- (void) isp_mboxcmd(isp, &mbs);
- if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- printf("failed to set CLOCKRATE\n");
- return;
+
+ mbs.param[0] = MBOX_EXEC_FIRMWARE;
+ if (isp->isp_mdvec->dv_codeorg)
+ mbs.param[1] = isp->isp_mdvec->dv_codeorg;
+ else
+ mbs.param[1] = 0x1000;
+ isp_mboxcmd(isp, &mbs);
+
+ if (isp->isp_type & ISP_HA_SCSI) {
+ sdparam *sdp = isp->isp_param;
+ /*
+ * Set CLOCK RATE, but only if asked to.
+ */
+ if (sdp->isp_clock) {
+ mbs.param[0] = MBOX_SET_CLOCK_RATE;
+ mbs.param[1] = sdp->isp_clock;
+ isp_mboxcmd(isp, &mbs);
+ if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+ isp_dumpregs(isp, "failed to set CLOCKRATE");
+ /* but continue */
+ } else {
+ IDPRINTF(3, ("%s: setting input clock to %d\n",
+ isp->isp_name, sdp->isp_clock));
+ }
}
}
mbs.param[0] = MBOX_ABOUT_FIRMWARE;
- (void) isp_mboxcmd(isp, &mbs);
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- printf("ABOUT FIRMWARE command failed\n");
+ isp_dumpregs(isp, "ABOUT FIRMWARE command failed");
return;
}
- printf("F/W rev %d.%d ", mbs.param[1], mbs.param[2]);
+ PRINTF("%s: Board Revision %s, %s F/W Revision %d.%d\n",
+ isp->isp_name, revname, dodnld? "loaded" : "resident",
+ mbs.param[1], mbs.param[2]);
+ if (isp->isp_type & ISP_HA_FC) {
+ if (ISP_READ(isp, BIU2100_CSR) & BIU2100_PCI64) {
+ PRINTF("%s: in 64-Bit PCI slot\n", isp->isp_name);
+ }
+ }
+ isp->isp_fwrev = (((u_int16_t) mbs.param[1]) << 10) + mbs.param[2];
+ if (isp->isp_romfw_rev && dodnld) {
+ PRINTF("%s: Last F/W revision was %d.%d\n", isp->isp_name,
+ isp->isp_romfw_rev >> 10, isp->isp_romfw_rev & 0x3ff);
+ }
+ isp_fw_state(isp);
isp->isp_state = ISP_RESETSTATE;
}
/*
- * Initialize Hardware to known state
+ * Initialize Parameters of Hardware to a known state.
+ *
+ * Locks are held before coming here.
*/
+
void
isp_init(isp)
struct ispsoftc *isp;
{
+ sdparam *sdp;
mbreg_t mbs;
- int s, i, l;
+ int tgt;
/*
- * Set Default Host Adapter Parameters
- * XXX: Should try and get them out of NVRAM
- */
-
- isp->isp_adapter_enabled = 1;
- isp->isp_req_ack_active_neg = 1;
- isp->isp_data_line_active_neg = 1;
- isp->isp_cmd_dma_burst_enable = 1;
- isp->isp_data_dma_burst_enabl = 1;
- isp->isp_fifo_threshold = 2;
- isp->isp_initiator_id = 7;
- isp->isp_async_data_setup = 6;
- isp->isp_selection_timeout = 250;
- isp->isp_max_queue_depth = 256;
- isp->isp_tag_aging = 8;
- isp->isp_bus_reset_delay = 3;
- isp->isp_retry_count = 0;
- isp->isp_retry_delay = 1;
- for (i = 0; i < MAX_TARGETS; i++) {
- isp->isp_devparam[i].dev_flags = DPARM_DEFAULT;
- isp->isp_devparam[i].exc_throttle = 16;
- isp->isp_devparam[i].sync_period = 25;
- isp->isp_devparam[i].sync_offset = 12;
- isp->isp_devparam[i].dev_enable = 1;
- }
+ * Must do first.
+ */
+ isp_setdfltparm(isp);
+ /*
+ * Set up DMA for the request and result mailboxes.
+ */
+ if (ISP_MBOXDMASETUP(isp) != 0) {
+ PRINTF("%s: can't setup dma mailboxes\n", isp->isp_name);
+ return;
+ }
+
+ /*
+ * If we're fibre, we have a completely different
+ * initialization method.
+ */
+ if (IS_FC(isp)) {
+ isp_fibre_init(isp);
+ return;
+ }
+ sdp = isp->isp_param;
- s = splbio();
+ /*
+ * If we have fast memory timing enabled, turn it on.
+ */
+ if (sdp->isp_fast_mttr) {
+ ISP_WRITE(isp, RISC_MTR, 0x1313);
+ }
+ /*
+ * Set (possibly new) Initiator ID.
+ */
mbs.param[0] = MBOX_SET_INIT_SCSI_ID;
- mbs.param[1] = isp->isp_initiator_id;
- (void) isp_mboxcmd(isp, &mbs);
+ mbs.param[1] = sdp->isp_initiator_id;
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- (void) splx(s);
- printf("%s: failed to set initiator id\n", isp->isp_name);
+ isp_dumpregs(isp, "failed to set initiator id");
return;
}
+ /*
+ * Set Retry Delay and Count
+ */
mbs.param[0] = MBOX_SET_RETRY_COUNT;
- mbs.param[1] = isp->isp_retry_count;
- mbs.param[2] = isp->isp_retry_delay;
- (void) isp_mboxcmd(isp, &mbs);
+ mbs.param[1] = sdp->isp_retry_count;
+ mbs.param[2] = sdp->isp_retry_delay;
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- (void) splx(s);
- printf("%s: failed to set retry count and delay\n",
- isp->isp_name);
+ isp_dumpregs(isp, "failed to set retry count and delay");
return;
}
+ /*
+ * Set ASYNC DATA SETUP time. This is very important.
+ */
mbs.param[0] = MBOX_SET_ASYNC_DATA_SETUP_TIME;
- mbs.param[1] = isp->isp_async_data_setup;
- (void) isp_mboxcmd(isp, &mbs);
+ mbs.param[1] = sdp->isp_async_data_setup;
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- (void) splx(s);
- printf("%s: failed to set async data setup time\n",
- isp->isp_name);
+ isp_dumpregs(isp, "failed to set async data setup time");
return;
}
+ /*
+ * Set ACTIVE Negation State.
+ */
mbs.param[0] = MBOX_SET_ACTIVE_NEG_STATE;
mbs.param[1] =
- (isp->isp_req_ack_active_neg << 4) |
- (isp->isp_data_line_active_neg << 5);
- (void) isp_mboxcmd(isp, &mbs);
+ (sdp->isp_req_ack_active_neg << 4) |
+ (sdp->isp_data_line_active_neg << 5);
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- (void) splx(s);
- printf("%s: failed to set active negation state\n",
- isp->isp_name);
+ isp_dumpregs(isp, "failed to set active neg state");
return;
}
+ /*
+ * Set the Tag Aging limit
+ */
mbs.param[0] = MBOX_SET_TAG_AGE_LIMIT;
- mbs.param[1] = isp->isp_tag_aging;
- (void) isp_mboxcmd(isp, &mbs);
+ mbs.param[1] = sdp->isp_tag_aging;
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- (void) splx(s);
- printf("%s: failed to set tag age limit\n", isp->isp_name);
+ isp_dumpregs(isp, "failed to set tag age limit");
return;
}
+ /*
+ * Set selection timeout.
+ */
+
mbs.param[0] = MBOX_SET_SELECT_TIMEOUT;
- mbs.param[1] = isp->isp_selection_timeout;
- (void) isp_mboxcmd(isp, &mbs);
+ mbs.param[1] = sdp->isp_selection_timeout;
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- (void) splx(s);
- printf("%s: failed to set selection timeout\n", isp->isp_name);
+ isp_dumpregs(isp, "failed to set selection timeout");
return;
}
- for (i = 0; i < MAX_TARGETS; i++) {
- if (isp->isp_devparam[i].dev_enable == 0)
+ /*
+ * Set current per-target parameters to a safe minimum.
+ */
+ for (tgt = 0; tgt < MAX_TARGETS; tgt++) {
+ int maxlun, lun;
+ u_int16_t sdf;
+
+ if (sdp->isp_devparam[tgt].dev_enable == 0)
continue;
+ sdf = DPARM_SAFE_DFLT;
+ /*
+ * It is not quite clear when this changed over so that
+ * we could force narrow and async, so assume >= 7.55.
+ *
+ * Otherwise, a SCSI bus reset issued below will force
+ * the back to the narrow, async state (but see note
+ * below also). Technically we should also do without
+ * Parity.
+ */
+ if (isp->isp_fwrev >= ISP_FW_REV(7, 55)) {
+ sdf |= DPARM_NARROW | DPARM_ASYNC;
+ }
+
mbs.param[0] = MBOX_SET_TARGET_PARAMS;
- mbs.param[1] = i << 8;
- mbs.param[2] = isp->isp_devparam[i].dev_flags << 8;
- mbs.param[3] =
- (isp->isp_devparam[i].sync_offset << 8) |
- (isp->isp_devparam[i].sync_period);
- (void) isp_mboxcmd(isp, &mbs);
+ mbs.param[1] = tgt << 8;
+ mbs.param[2] = sdf;
+ mbs.param[3] = 0;
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- (void) splx(s);
- printf("%s: failed to set target parameters\n",
- isp->isp_name);
- return;
+ sdf = DPARM_SAFE_DFLT;
+ mbs.param[0] = MBOX_SET_TARGET_PARAMS;
+ mbs.param[1] = tgt << 8;
+ mbs.param[2] = sdf;
+ mbs.param[3] = 0;
+ isp_mboxcmd(isp, &mbs);
+ if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+ PRINTF("%s: failed even to set defaults for "
+ "target %d\n", isp->isp_name, tgt);
+ continue;
+ }
}
+ sdp->isp_devparam[tgt].cur_dflags = sdf;
- for (l = 0; l < MAX_LUNS; l++) {
+ maxlun = (isp->isp_fwrev >= ISP_FW_REV(7, 55))? 32 : 8;
+ for (lun = 0; lun < maxlun; lun++) {
mbs.param[0] = MBOX_SET_DEV_QUEUE_PARAMS;
- mbs.param[1] = (i << 8) | l;
- mbs.param[2] = isp->isp_max_queue_depth;
- mbs.param[3] = isp->isp_devparam[i].exc_throttle;
- (void) isp_mboxcmd(isp, &mbs);
+ mbs.param[1] = (tgt << 8) | lun;
+ mbs.param[2] = sdp->isp_max_queue_depth;
+ mbs.param[3] = sdp->isp_devparam[tgt].exc_throttle;
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- (void) splx(s);
- printf("%s: failed to set device queue "
- "parameters\n", isp->isp_name);
- return;
+ PRINTF("%s: failed to set device queue "
+ "parameters for target %d, lun %d\n",
+ isp->isp_name, tgt, lun);
+ break;
}
}
- }
-
-
- /*
- * Set up DMA for the request and result mailboxes.
- */
- if (ISP_MBOXDMASETUP(isp)) {
- (void) splx(s);
- printf("%s: can't setup DMA for mailboxes\n", isp->isp_name);
- return;
+ /*
+ * And mark this as an unannounced device
+ */
+ sdp->isp_devparam[tgt].dev_announced = 0;
}
mbs.param[0] = MBOX_INIT_RES_QUEUE;
@@ -443,10 +749,9 @@ isp_init(isp)
mbs.param[3] = (u_int16_t) (isp->isp_result_dma & 0xffff);
mbs.param[4] = 0;
mbs.param[5] = 0;
- (void) isp_mboxcmd(isp, &mbs);
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- (void) splx(s);
- printf("%s: set of response queue failed\n", isp->isp_name);
+ isp_dumpregs(isp, "set of response queue failed");
return;
}
isp->isp_residx = 0;
@@ -456,280 +761,778 @@ isp_init(isp)
mbs.param[2] = (u_int16_t) (isp->isp_rquest_dma >> 16);
mbs.param[3] = (u_int16_t) (isp->isp_rquest_dma & 0xffff);
mbs.param[4] = 0;
- (void) isp_mboxcmd(isp, &mbs);
+ mbs.param[5] = 0;
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- (void) splx(s);
- printf("%s: set of request queue failed\n", isp->isp_name);
+ isp_dumpregs(isp, "set of request queue failed");
return;
}
- isp->isp_reqidx = 0;
+ isp->isp_reqidx = isp->isp_reqodx = 0;
- /*
- * Unfortunately, this is the only way right now for
- * forcing a sync renegotiation. If we boot off of
- * an Alpha, it's put the chip in SYNC mode, but we
- * haven't necessarily set up the parameters the
- * same, so we'll have to yank the reset line to
- * get everyone to renegotiate.
+ /*
+ * Turn on Fast Posting
*/
+#ifndef ISP_NO_FASTPOST_SCSI
+ if (isp->isp_fwrev >= ISP_FW_REV(7, 55)) {
+ mbs.param[0] = MBOX_SET_FW_FEATURES;
+ mbs.param[1] = FW_FEATURE_FAST_POST;
+ isp_mboxcmd(isp, &mbs);
+ if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+ PRINTF("%s: unable to enable FAST Posting\n",
+ isp->isp_name);
+ }
+ }
+#endif
-
+ /*
+ * Let the outer layers decide whether to issue a SCSI bus reset.
+ */
+#if 0
+ /*
+ * XXX: See whether or not for 7.55 F/W or later we
+ * XXX: can do without this, and see whether we should
+ * XXX: honor the NVRAM SCSI_RESET_DISABLE token.
+ */
mbs.param[0] = MBOX_BUS_RESET;
- mbs.param[1] = 2;
- (void) isp_mboxcmd(isp, &mbs);
+ mbs.param[1] = 3;
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- (void) splx(s);
- printf("%s: SCSI bus reset failed\n", isp->isp_name);
+ isp_dumpregs(isp, "SCSI bus reset failed");
}
+ /*
+ * This is really important to have set after a bus reset.
+ */
isp->isp_sendmarker = 1;
- (void) splx(s);
+#endif
isp->isp_state = ISP_INITSTATE;
}
/*
- * Complete attachment of Hardware, include subdevices.
+ * Fibre Channel specific initialization.
+ *
+ * Locks are held before coming here.
*/
-void
-isp_attach(isp)
+static void
+isp_fibre_init(isp)
struct ispsoftc *isp;
{
- isp->isp_state = ISP_RUNSTATE;
- isp->isp_link.adapter_softc = isp;
- isp->isp_link.adapter_target = isp->isp_initiator_id;
- isp->isp_link.adapter = &isp_switch;
- isp->isp_link.device = &isp_dev;
- isp->isp_link.openings = RQUEST_QUEUE_LEN / (MAX_TARGETS - 1);
- isp->isp_link.adapter_buswidth = MAX_TARGETS;
- config_found((void *)isp, &isp->isp_link, scsiprint);
-}
+ fcparam *fcp;
+ isp_icb_t *icbp;
+ mbreg_t mbs;
+ int count, loopid;
+
+ fcp = isp->isp_param;
+
+ /*
+ * For systems that don't have BIOS methods for which
+ * we can easily change the NVRAM based loopid, we'll
+ * override that here. Note that when we initialize
+ * the firmware we may get back a different loopid than
+ * we asked for anyway. XXX This is probably not the
+ * best way to figure this out XXX
+ */
+#ifndef __i386__
+ loopid = DEFAULT_LOOPID;
+#else
+ loopid = fcp->isp_loopid;
+#endif
+
+#if defined(ISP2100_FABRIC) && defined(ISP2100_SCCLUN)
+ PRINTF("%s: Fabric Support, Expanded Lun Support\n", isp->isp_name);
+#endif
+#if defined(ISP2100_FABRIC) && !defined(ISP2100_SCCLUN)
+ PRINTF("%s: Fabric Support\n", isp->isp_name);
+#endif
+#if !defined(ISP2100_FABRIC) && defined(ISP2100_SCCLUN)
+ PRINTF("%s: Expanded Lun Support\n", isp->isp_name);
+#endif
+ icbp = (isp_icb_t *) fcp->isp_scratch;
+ MEMZERO(icbp, sizeof (*icbp));
+
+ icbp->icb_version = ICB_VERSION1;
+#ifdef ISP_TARGET_MODE
+ fcp->isp_fwoptions = ICBOPT_TGT_ENABLE|ICBOPT_INI_TGTTYPE;
+#else
+ fcp->isp_fwoptions = 0;
+#endif
+ fcp->isp_fwoptions |= ICBOPT_INI_ADISC|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
+#ifdef CHECKME
+ fcp->isp_fwoptions |= ICBOPT_USE_PORTNAME;
+#endif
+#ifdef ISP2100_FABRIC
+ fcp->isp_fwoptions |= ICBOPT_FULL_LOGIN;
+#endif
+
+ 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) {
+ PRINTF("%s: bad frame length (%d) from NVRAM- using %d\n",
+ isp->isp_name, fcp->isp_maxfrmlen, ICB_DFLT_FRMLEN);
+ }
+ icbp->icb_maxalloc = fcp->isp_maxalloc;
+ icbp->icb_execthrottle = fcp->isp_execthrottle;
+ icbp->icb_retry_delay = fcp->isp_retry_delay;
+ icbp->icb_retry_count = fcp->isp_retry_count;
+ icbp->icb_hardaddr = loopid;
+
+ MAKE_NODE_NAME_FROM_WWN(icbp->icb_nodename, fcp->isp_wwn);
+ if (icbp->icb_fwoptions & ICBOPT_USE_PORTNAME) {
+ u_int64_t portname = fcp->isp_wwn | (2LL << 56);
+ MAKE_NODE_NAME_FROM_WWN(icbp->icb_nodename, portname);
+ }
+ icbp->icb_rqstqlen = RQUEST_QUEUE_LEN;
+ icbp->icb_rsltqlen = RESULT_QUEUE_LEN;
+ icbp->icb_rqstaddr[RQRSP_ADDR0015] =
+ (u_int16_t) (isp->isp_rquest_dma & 0xffff);
+ icbp->icb_rqstaddr[RQRSP_ADDR1631] =
+ (u_int16_t) (isp->isp_rquest_dma >> 16);
+ icbp->icb_respaddr[RQRSP_ADDR0015] =
+ (u_int16_t) (isp->isp_result_dma & 0xffff);
+ icbp->icb_respaddr[RQRSP_ADDR1631] =
+ (u_int16_t) (isp->isp_result_dma >> 16);
+ MemoryBarrier();
+
+ for (count = 0; count < 10; count++) {
+ mbs.param[0] = MBOX_INIT_FIRMWARE;
+ mbs.param[1] = 0;
+ mbs.param[2] = (u_int16_t) (fcp->isp_scdma >> 16);
+ mbs.param[3] = (u_int16_t) (fcp->isp_scdma & 0xffff);
+ mbs.param[4] = 0;
+ mbs.param[5] = 0;
+ mbs.param[6] = 0;
+ mbs.param[7] = 0;
+
+ isp_mboxcmd(isp, &mbs);
+
+ switch (mbs.param[0]) {
+ case MBOX_COMMAND_COMPLETE:
+ count = 10;
+ break;
+ case ASYNC_PDB_CHANGED:
+ isp_mark_getpdb_all(isp);
+ /* FALL THROUGH */
+ case ASYNC_LIP_OCCURRED:
+ case ASYNC_LOOP_UP:
+ case ASYNC_LOOP_DOWN:
+ case ASYNC_LOOP_RESET:
+ case ASYNC_CHANGE_NOTIFY:
+ if (count > 9) {
+ PRINTF("%s: too many retries to get going- "
+ "giving up\n", isp->isp_name);
+ return;
+ }
+ break;
+ default:
+ isp_dumpregs(isp, "INIT FIRMWARE failed");
+ return;
+ }
+ }
+ isp->isp_reqidx = isp->isp_reqodx = 0;
+ isp->isp_residx = 0;
+ isp->isp_sendmarker = 1;
+
+ /*
+ * Whatever happens, we're now committed to being here.
+ */
+ isp->isp_state = ISP_INITSTATE;
+ fcp->isp_fwstate = FW_CONFIG_WAIT;
+
+#ifdef ISP_TARGET_MODE
+ if (isp_modify_lun(isp, 0, 1, 1)) {
+ PRINTF("%s: failed to enable target mode\n", isp->isp_name);
+ }
+#endif
+}
/*
- * Free any associated resources prior to decommissioning.
+ * Fibre Channel Support- get the port database for the id.
+ *
+ * Locks are held before coming here. Return 0 if success,
+ * else failure.
*/
-void
-isp_uninit(isp)
+
+static void
+isp_mark_getpdb_all(isp)
struct ispsoftc *isp;
{
+ isp_pdb_t *p;
+ fcparam *fcp = (fcparam *) isp->isp_param;
+ for (p = &fcp->isp_pdb[0]; p < &fcp->isp_pdb[MAX_FC_TARG]; p++) {
+ p->pdb_options = INVALID_PDB_OPTIONS;
+ }
+}
+
+static int
+isp_getpdb(isp, id, pdbp)
+ struct ispsoftc *isp;
+ int id;
+ isp_pdb_t *pdbp;
+{
+#ifdef GETPDB_WORKING_YET
+ fcparam *fcp = (fcparam *) isp->isp_param;
+ mbreg_t mbs;
+
+ /*
+ * Get Port Queue Parameters first- this is
+ * a Q&D way to see whether we're logged into
+ * this port.
+ */
+ mbs.param[0] = MBOX_GET_DEV_QUEUE_PARAMS;
+ mbs.param[1] = id << 8;
+ mbs.param[2] = 0;
+#ifdef ISP2100_SCCLUN
+ mbs.param[3] = 0;
+#endif
+ isp_mboxcmd(isp, &mbs);
+ if (mbs.param[0] != MBOX_COMMAND_COMPLETE)
+ return (-1);
+
+ mbs.param[0] = MBOX_GET_PORT_DB;
+ mbs.param[1] = id << 8;
+ mbs.param[2] = (u_int16_t) (fcp->isp_scdma >> 16);
+ mbs.param[3] = (u_int16_t) (fcp->isp_scdma & 0xffff);
+ mbs.param[4] = 0;
+ mbs.param[5] = 0;
+ mbs.param[6] = 0;
+ mbs.param[7] = 0;
+ isp_mboxcmd(isp, &mbs);
+ switch (mbs.param[0]) {
+ case MBOX_COMMAND_COMPLETE:
+ MemoryBarrier();
+ MEMCPY(pdbp, fcp->isp_scratch, sizeof (isp_pdb_t));
+ break;
+ case MBOX_HOST_INTERFACE_ERROR:
+ PRINTF("%s: DMA error getting port database\n", isp->isp_name);
+ return (-1);
+ case MBOX_COMMAND_PARAM_ERROR:
+ /* Not Logged In */
+ IDPRINTF(3, ("%s: Comand Param Error on Get Port Database\n",
+ isp->isp_name));
+ return (-1);
+ default:
+ PRINTF("%s: error 0x%x getting port database for ID %d\n",
+ isp->isp_name, mbs.param[0], id);
+ return (-1);
+ }
+#else
+ pdbp->pdb_options = 1;
+#endif
+ return (0);
}
/*
- * minphys our xfers
+ * Make sure we have good FC link and know our Loop ID.
*/
-static void
-ispminphys(bp)
- struct buf *bp;
+static int
+isp_fclink_test(isp)
+ struct ispsoftc *isp;
{
+ mbreg_t mbs;
+ int count;
+ u_int8_t lwfs;
+ fcparam *fcp;
+
+ fcp = isp->isp_param;
+
+ /*
+ * Wait up to N microseconds for F/W to go to a ready state.
+ * This is a platform specific
+ */
+ lwfs = FW_CONFIG_WAIT;
+ for (count = 0; count < FC_FW_READY_DELAY; count += 100) {
+ isp_fw_state(isp);
+ if (lwfs != fcp->isp_fwstate) {
+ PRINTF("%s: Firmware State %s -> %s\n",
+ isp->isp_name, isp2100_fw_statename((int)lwfs),
+ isp2100_fw_statename((int)fcp->isp_fwstate));
+ lwfs = fcp->isp_fwstate;
+ }
+ if (fcp->isp_fwstate == FW_READY) {
+ break;
+ }
+ SYS_DELAY(100); /* wait 100 microseconds */
+ }
+
+ /*
+ * If we haven't gone to 'ready' state, return.
+ */
+ if (fcp->isp_fwstate != FW_READY) {
+ return (-1);
+ }
/*
- * XX: Only the 1020 has a 24 bit limit.
+ * Get our Loop ID (if possible). We really need to have it.
*/
- if (bp->b_bcount >= (1 << 24)) {
- bp->b_bcount = (1 << 24) - 1;
+ mbs.param[0] = MBOX_GET_LOOP_ID;
+ isp_mboxcmd(isp, &mbs);
+ if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+ PRINTF("%s: GET LOOP ID failed\n", isp->isp_name);
+ return (-1);
}
- minphys(bp);
+ fcp->isp_loopid = mbs.param[1];
+ fcp->isp_alpa = mbs.param[2];
+ PRINTF("%s: Loop ID %d, ALPA 0x%x\n", isp->isp_name,
+ fcp->isp_loopid, fcp->isp_alpa);
+ return (0);
+
}
/*
- * start an xfer
+ * Start a command. Locking is assumed done in the caller.
*/
-static int32_t
+
+int32_t
ispscsicmd(xs)
- struct scsi_xfer *xs;
+ ISP_SCSI_XFER_T *xs;
{
struct ispsoftc *isp;
u_int8_t iptr, optr;
- ispreq_t *req;
- int s, i;
+ union {
+ ispreq_t *_reqp;
+ ispreqt2_t *_t2reqp;
+ } _u;
+#define reqp _u._reqp
+#define t2reqp _u._t2reqp
+#define UZSIZE max(sizeof (ispreq_t), sizeof (ispreqt2_t))
+ int i, rqidx;
+
+ XS_INITERR(xs);
+ isp = XS_ISP(xs);
+
+ if (isp->isp_state != ISP_RUNSTATE) {
+ PRINTF("%s: adapter not ready\n", isp->isp_name);
+ XS_SETERR(xs, HBA_BOTCH);
+ return (CMD_COMPLETE);
+ }
+
+ /*
+ * We *could* do the different sequence type that has close
+ * to the whole Queue Entry for the command,...
+ */
+
+ if (XS_CDBLEN(xs) > ((isp->isp_type & ISP_HA_FC)? 16 : 12)) {
+ PRINTF("%s: unsupported cdb length (%d)\n",
+ isp->isp_name, XS_CDBLEN(xs));
+ XS_SETERR(xs, HBA_BOTCH);
+ return (CMD_COMPLETE);
+ }
+
+ /*
+ * Check to see whether we have good firmware state still or
+ * need to refresh our port database for this target.
+ */
+ if (IS_FC(isp)) {
+ fcparam *fcp = isp->isp_param;
+ isp_pdb_t *pdbp = &fcp->isp_pdb[XS_TGT(xs)];
+
+ /*
+ * Check for f/w being in ready state. Well, okay,
+ * our cached copy of it...
+ */
+ if (fcp->isp_fwstate != FW_READY) {
+ if (isp_fclink_test(isp)) {
+ XS_SETERR(xs, HBA_SELTIMEOUT);
+ return (CMD_COMPLETE);
+ }
+ }
+ /*
+ * Here's the spot we would need to find out whether
+ * the port names have changed, whether it's still
+ * a target role, etc..
+ */
+ if (pdbp->pdb_options == INVALID_PDB_OPTIONS) {
+ /*
+ * If we don't know what it is- don't talk to it.
+ * This also handles cases where it's not logged
+ * into this port/target.
+ */
+ if (isp_getpdb(isp, XS_TGT(xs), pdbp)) {
+ XS_SETERR(xs, HBA_SELTIMEOUT);
+ return (CMD_COMPLETE);
+#ifdef GETPDB_WORKING_YET
+ } else {
+ isp_async(isp, ISPASYNC_PDB_CHANGE_COMPLETE,
+ (void *) (long) XS_TGT(xs));
+#endif
+ }
+ }
+ }
- isp = xs->sc_link->adapter_softc;
+ /*
+ * Next check to see if any HBA or Device
+ * parameters need to be updated.
+ */
+ if (isp->isp_update) {
+ isp_update(isp);
+ }
- optr = ISP_READ(isp, OUTMAILBOX4);
+ optr = isp->isp_reqodx = ISP_READ(isp, OUTMAILBOX4);
iptr = isp->isp_reqidx;
- req = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, iptr);
- iptr = (iptr + 1) & (RQUEST_QUEUE_LEN - 1);
+ reqp = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, iptr);
+ iptr = ISP_NXT_QENTRY(iptr, RQUEST_QUEUE_LEN);
if (iptr == optr) {
- printf("%s: Request Queue Overflow\n", isp->isp_name);
- xs->error = XS_DRIVER_STUFFUP;
- return (TRY_AGAIN_LATER);
+ IDPRINTF(2, ("%s: Request Queue Overflow\n", isp->isp_name));
+ XS_SETERR(xs, HBA_BOTCH);
+ return (CMD_EAGAIN);
}
- s = splbio();
if (isp->isp_sendmarker) {
- ipsmarkreq_t *marker = (ipsmarkreq_t *) req;
+ u_int8_t niptr;
+ ispmarkreq_t *marker = (ispmarkreq_t *) reqp;
- bzero((void *) marker, sizeof (*marker));
+ MEMZERO((void *) marker, sizeof (*marker));
marker->req_header.rqs_entry_count = 1;
marker->req_header.rqs_entry_type = RQSTYPE_MARKER;
marker->req_modifier = SYNC_ALL;
- isp->isp_sendmarker = 0;
-
- if (((iptr + 1) & (RQUEST_QUEUE_LEN - 1)) == optr) {
- ISP_WRITE(isp, INMAILBOX4, iptr);
- isp->isp_reqidx = iptr;
- (void) splx(s);
- printf("%s: Request Queue Overflow+\n", isp->isp_name);
- xs->error = XS_DRIVER_STUFFUP;
- return (TRY_AGAIN_LATER);
+ /*
+ * Unconditionally update the input pointer anyway.
+ */
+ ISP_WRITE(isp, INMAILBOX4, iptr);
+ isp->isp_reqidx = iptr;
+
+ niptr = ISP_NXT_QENTRY(iptr, RQUEST_QUEUE_LEN);
+ if (niptr == optr) {
+ IDPRINTF(2, ("%s: Request Queue Overflow+\n",
+ isp->isp_name));
+ XS_SETERR(xs, HBA_BOTCH);
+ return (CMD_EAGAIN);
}
- req = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, iptr);
- iptr = (iptr + 1) & (RQUEST_QUEUE_LEN - 1);
+ reqp = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, iptr);
+ iptr = niptr;
}
+ MEMZERO((void *) reqp, UZSIZE);
+ reqp->req_header.rqs_entry_count = 1;
+ if (isp->isp_type & ISP_HA_FC) {
+ reqp->req_header.rqs_entry_type = RQSTYPE_T2RQS;
+ } else {
+ reqp->req_header.rqs_entry_type = RQSTYPE_REQUEST;
+ }
+ reqp->req_header.rqs_flags = 0;
+ reqp->req_header.rqs_seqno = isp->isp_seqno++;
- bzero((void *) req, sizeof (*req));
- req->req_header.rqs_entry_count = 1;
- req->req_header.rqs_entry_type = RQSTYPE_REQUEST;
- req->req_header.rqs_flags = 0;
- req->req_header.rqs_seqno = isp->isp_seqno++;
-
- for (i = 0; i < RQUEST_QUEUE_LEN; i++) {
- if (isp->isp_xflist[i] == NULL)
+ for (rqidx = 0; rqidx < RQUEST_QUEUE_LEN; rqidx++) {
+ if (isp->isp_xflist[rqidx] == NULL)
break;
}
- if (i == RQUEST_QUEUE_LEN) {
- panic("%s: ran out of xflist pointers", isp->isp_name);
- /* NOTREACHED */
+ if (rqidx == RQUEST_QUEUE_LEN) {
+ IDPRINTF(2, ("%s: out of xflist pointers\n", isp->isp_name));
+ XS_SETERR(xs, HBA_BOTCH);
+ return (CMD_EAGAIN);
} else {
- isp->isp_xflist[i] = xs;
- req->req_handle = i;
+ /*
+ * Never have a handle that is zero, so
+ * set req_handle off by one.
+ */
+ isp->isp_xflist[rqidx] = xs;
+ reqp->req_handle = rqidx+1;
}
- req->req_flags = 0;
- req->req_lun_trn = xs->sc_link->lun;
- req->req_target = xs->sc_link->target;
- req->req_cdblen = xs->cmdlen;
- bcopy((void *)xs->cmd, req->req_cdb, xs->cmdlen);
-
-#if 0
- printf("%s(%d.%d): START%d cmd 0x%x datalen %d\n", isp->isp_name,
- xs->sc_link->target, xs->sc_link->lun,
- req->req_header.rqs_seqno, *(u_char *) xs->cmd, xs->datalen);
+ if (isp->isp_type & ISP_HA_FC) {
+ /*
+ * See comment in isp_intr
+ */
+ XS_RESID(xs) = 0;
+ /*
+ * Fibre Channel always requires some kind of tag.
+ * If we're marked as "Can't Tag", just do simple
+ * instead of ordered tags. It's pretty clear to me
+ * that we shouldn't do head of queue tagging in
+ * this case.
+ */
+ if (XS_CANTAG(xs)) {
+ t2reqp->req_flags = XS_KINDOF_TAG(xs);
+ } else {
+ t2reqp->req_flags = REQFLAG_STAG;
+ }
+ } else {
+ sdparam *sdp = (sdparam *)isp->isp_param;
+ if ((sdp->isp_devparam[XS_TGT(xs)].cur_dflags & DPARM_TQING) &&
+ XS_CANTAG(xs)) {
+ reqp->req_flags = XS_KINDOF_TAG(xs);
+ } else {
+ reqp->req_flags = 0;
+ }
+ }
+ reqp->req_target = XS_TGT(xs);
+ if (isp->isp_type & ISP_HA_SCSI) {
+ reqp->req_lun_trn = XS_LUN(xs);
+ reqp->req_cdblen = XS_CDBLEN(xs);
+ } else {
+#ifdef ISP2100_SCCLUN
+ reqp->req_scclun = XS_LUN(xs);
+#else
+ reqp->req_lun_trn = XS_LUN(xs);
#endif
- req->req_time = xs->timeout / 1000;
- req->req_seg_count = 0;
- if (ISP_DMASETUP(isp, xs, req, &iptr, optr)) {
- (void) splx(s);
- xs->error = XS_DRIVER_STUFFUP;
- return (COMPLETE);
- }
- xs->error = 0;
- ISP_WRITE(isp, INMAILBOX4, iptr);
- isp->isp_reqidx = iptr;
- (void) splx(s);
- if ((xs->flags & SCSI_POLL) == 0) {
- return (SUCCESSFULLY_QUEUED);
}
+ MEMCPY(reqp->req_cdb, XS_CDBP(xs), XS_CDBLEN(xs));
+
+ IDPRINTF(5, ("%s(%d.%d): START%d cmd 0x%x datalen %d\n", isp->isp_name,
+ XS_TGT(xs), XS_LUN(xs), reqp->req_header.rqs_seqno,
+ reqp->req_cdb[0], XS_XFRLEN(xs)));
+
+ reqp->req_time = XS_TIME(xs) / 1000;
+ if (reqp->req_time == 0 && XS_TIME(xs))
+ reqp->req_time = 1;
/*
- * If we can't use interrupts, poll on completion.
+ * Always give a bit more leeway to commands after a bus reset.
*/
- if (isp_poll(isp, xs, xs->timeout)) {
-#if 0
- /* XXX try to abort it, or whatever */
- if (isp_poll(isp, xs, xs->timeout) {
- /* XXX really nuke it */
- }
-#endif
+ if (isp->isp_sendmarker && reqp->req_time < 5)
+ reqp->req_time = 5;
+
+ i = ISP_DMASETUP(isp, xs, reqp, &iptr, optr);
+ if (i != CMD_QUEUED) {
/*
- * If no other error occurred but we didn't finish,
- * something bad happened.
+ * Take memory of it away...
*/
- if ((xs->flags & ITSDONE) == 0 && xs->error == XS_NOERROR) {
- isp_lostcmd(isp, xs);
- xs->error = XS_DRIVER_STUFFUP;
- }
+ isp->isp_xflist[rqidx] = NULL;
+ /*
+ * dmasetup sets actual error in packet, and
+ * return what we were given to return.
+ */
+ return (i);
}
- return (COMPLETE);
+ XS_SETERR(xs, HBA_NOERROR);
+ MemoryBarrier();
+ ISP_WRITE(isp, INMAILBOX4, iptr);
+ isp->isp_reqidx = iptr;
+ isp->isp_nactive++;
+ if (isp->isp_sendmarker)
+ isp->isp_sendmarker = 0;
+ return (CMD_QUEUED);
+#undef reqp
+#undef t2reqp
}
/*
- * Interrupt Service Routine(s)
+ * isp control
+ * Locks (ints blocked) assumed held.
*/
int
-isp_poll(isp, xs, mswait)
+isp_control(isp, ctl, arg)
struct ispsoftc *isp;
- struct scsi_xfer *xs;
- int mswait;
+ ispctl_t ctl;
+ void *arg;
{
+ ISP_SCSI_XFER_T *xs;
+ mbreg_t mbs;
+ int i;
- while (mswait) {
- /* Try the interrupt handling routine */
- (void)isp_intr((void *)isp);
+ switch (ctl) {
+ default:
+ PRINTF("%s: isp_control unknown control op %x\n",
+ isp->isp_name, ctl);
+ break;
- /* See if the xs is now done */
- if (xs->flags & ITSDONE)
- return (0);
- delay(1000); /* wait one millisecond */
- mswait--;
+ case ISPCTL_RESET_BUS:
+ /*
+ * This is really important to have set after a bus reset.
+ */
+ isp->isp_sendmarker = 1;
+
+ /*
+ * Issue a bus reset.
+ */
+ mbs.param[0] = MBOX_BUS_RESET;
+ if (isp->isp_type & ISP_HA_SCSI) {
+ mbs.param[1] =
+ ((sdparam *) isp->isp_param)->isp_bus_reset_delay;
+ if (mbs.param[1] < 2)
+ mbs.param[1] = 2;
+ } else {
+ /*
+ * Unparameterized.
+ */
+ mbs.param[1] = 5;
+ }
+ isp_mboxcmd(isp, &mbs);
+ if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+ isp_dumpregs(isp, "isp_control SCSI bus reset failed");
+ break;
+ }
+ PRINTF("%s: driver initiated bus reset\n", isp->isp_name);
+ return (0);
+
+ case ISPCTL_RESET_DEV:
+ mbs.param[0] = MBOX_ABORT_TARGET;
+ mbs.param[1] = ((long)arg) << 8;
+ mbs.param[2] = 3; /* 'delay', in seconds */
+ isp_mboxcmd(isp, &mbs);
+ if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+ isp_dumpregs(isp, "Target Reset Failed");
+ break;
+ }
+ PRINTF("%s: Target %d Reset Succeeded\n", isp->isp_name,
+ (int) ((long) arg));
+ isp->isp_sendmarker = 1;
+ return (0);
+
+ case ISPCTL_ABORT_CMD:
+ xs = (ISP_SCSI_XFER_T *) arg;
+ for (i = 0; i < RQUEST_QUEUE_LEN; i++) {
+ if (xs == isp->isp_xflist[i]) {
+ break;
+ }
+ }
+ if (i == RQUEST_QUEUE_LEN) {
+ PRINTF("%s: isp_control- cannot find command to abort "
+ "in active list\n", isp->isp_name);
+ break;
+ }
+ mbs.param[0] = MBOX_ABORT;
+#ifdef ISP2100_SCCLUN
+ if (isp->isp_type & ISP_HA_FC) {
+ mbs.param[1] = XS_TGT(xs) << 8;
+ mbs.param[4] = 0;
+ mbs.param[5] = 0;
+ mbs.param[6] = XS_LUN(xs);
+ } else {
+ mbs.param[1] = XS_TGT(xs) << 8 | XS_LUN(xs);
+ }
+#else
+ mbs.param[1] = XS_TGT(xs) << 8 | XS_LUN(xs);
+#endif
+ mbs.param[2] = (i+1) >> 16;
+ mbs.param[3] = (i+1) & 0xffff;
+ isp_mboxcmd(isp, &mbs);
+ if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+ PRINTF("%s: isp_control MBOX_ABORT failure (code %x)\n",
+ isp->isp_name, mbs.param[0]);
+ break;
+ }
+ PRINTF("%s: command for target %d lun %d was aborted\n",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ return (0);
+
+ case ISPCTL_UPDATE_PARAMS:
+ isp_update(isp);
+ return(0);
+
+ case ISPCTL_FCLINK_TEST:
+ return (isp_fclink_test(isp));
}
- return (1);
+ return (-1);
}
+/*
+ * Interrupt Service Routine(s).
+ *
+ * External (OS) framework has done the appropriate locking,
+ * and the locking will be held throughout this function.
+ */
+
int
isp_intr(arg)
void *arg;
{
- struct scsi_xfer *xs;
+ ISP_SCSI_XFER_T *complist[RESULT_QUEUE_LEN], *xs;
struct ispsoftc *isp = arg;
- u_int16_t iptr, optr, isr;
+ u_int8_t iptr, optr;
+ u_int16_t isr;
+ int i, nlooked = 0, ndone = 0;
isr = ISP_READ(isp, BIU_ISR);
- if (isr == 0 || (isr & BIU_ISR_RISC_INT) == 0) {
-#if 0
- if (isr) {
- printf("%s: isp_intr isr=%x\n", isp->isp_name, isr);
+ if (isp->isp_type & ISP_HA_FC) {
+ if (isr == 0 || (isr & BIU2100_ISR_RISC_INT) == 0) {
+ if (isr) {
+ IDPRINTF(4, ("%s: isp_intr isr=%x\n",
+ isp->isp_name, isr));
+ }
+ return (0);
+ }
+ } else {
+ if (isr == 0 || (isr & BIU_ISR_RISC_INT) == 0) {
+ if (isr) {
+ IDPRINTF(4, ("%s: isp_intr isr=%x\n",
+ isp->isp_name, isr));
+ }
+ return (0);
}
-#endif
- return (0);
}
+ if (ISP_READ(isp, BIU_SEMA) & 1) {
+ u_int16_t mbox = ISP_READ(isp, OUTMAILBOX0);
+ if (mbox & 0x4000) {
+ if (mbox != MBOX_COMMAND_COMPLETE) {
+ PRINTF("%s: isp_intr sees 0x%x\n",
+ isp->isp_name,mbox);
+ }
+ ISP_WRITE(isp, BIU_SEMA, 0);
+ } else {
+ u_int32_t fhandle = isp_parse_async(isp, (int) mbox);
+ ISP_WRITE(isp, BIU_SEMA, 0);
+ if (fhandle < 0) {
+ return (1);
+ } else if (fhandle > 0) {
+ xs = (ISP_SCSI_XFER_T *)
+ isp->isp_xflist[fhandle - 1];
+ isp->isp_xflist[fhandle - 1] = NULL;
+ /*
+ * Since we don't have a result queue entry
+ * item, we must believe that SCSI status is
+ * zero and that all data transferred.
+ */
+ XS_RESID(xs) = 0;
+ XS_STS(xs) = 0;
+ if (XS_XFRLEN(xs)) {
+ ISP_DMAFREE(isp, xs, fhandle - 1);
+ }
+ if (isp->isp_nactive > 0)
+ isp->isp_nactive--;
+ complist[ndone++] = xs;
+ }
+ }
+ }
+ ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT);
+
optr = isp->isp_residx;
iptr = ISP_READ(isp, OUTMAILBOX5);
- ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT);
- ISP_WRITE(isp, BIU_ICR,
- BIU_ICR_ENABLE_RISC_INT | BIU_ICR_ENABLE_ALL_INTS);
- if (ISP_READ(isp, BIU_SEMA) & 1) {
- u_int16_t mbox0 = ISP_READ(isp, OUTMAILBOX0);
- switch (mbox0) {
- case ASYNC_BUS_RESET:
- case ASYNC_TIMEOUT_RESET:
- printf("%s: bus or timeout reset\n", isp->isp_name);
- isp->isp_sendmarker = 1;
- break;
- default:
- printf("%s: async %x\n", isp->isp_name, mbox0);
- break;
- }
- ISP_WRITE(isp, BIU_SEMA, 0);
-#if 0
- } else {
- if (optr == iptr) {
- printf("why'd we interrupt? isr %x iptr %x optr %x\n",
- isr, optr, iptr);
- }
-#endif
+ if (optr == iptr) {
+ IDPRINTF(4, ("why intr? isr %x iptr %x optr %x\n",
+ isr, optr, iptr));
}
+ ENABLE_INTS(isp);
while (optr != iptr) {
ispstatusreq_t *sp;
+ u_int8_t oop;
int buddaboom = 0;
sp = (ispstatusreq_t *) ISP_QUEUE_ENTRY(isp->isp_result, optr);
-
- optr = (optr + 1) & (RESULT_QUEUE_LEN-1);
+ oop = optr;
+ optr = ISP_NXT_QENTRY(optr, RESULT_QUEUE_LEN);
+ nlooked++;
+ MemoryBarrier();
if (sp->req_header.rqs_entry_type != RQSTYPE_RESPONSE) {
- printf("%s: not RESPONSE in RESPONSE Queue (0x%x)\n",
- isp->isp_name, sp->req_header.rqs_entry_type);
+ if (isp_handle_other_response(isp, sp, &optr) == 0) {
+ ISP_WRITE(isp, INMAILBOX5, optr);
+ continue;
+ }
+ /*
+ * It really has to be a bounced request just copied
+ * from the request queue to the response queue.
+ */
+
if (sp->req_header.rqs_entry_type != RQSTYPE_REQUEST) {
ISP_WRITE(isp, INMAILBOX5, optr);
continue;
}
+ PRINTF("%s: not RESPONSE in RESPONSE Queue "
+ "(type 0x%x) @ idx %d (next %d)\n", isp->isp_name,
+ sp->req_header.rqs_entry_type, oop, optr);
buddaboom = 1;
}
@@ -738,68 +1541,148 @@ isp_intr(arg)
ISP_WRITE(isp, INMAILBOX5, optr);
continue;
}
- printf("%s: rqs_flags=%x\n", isp->isp_name,
+ PRINTF("%s: rqs_flags=%x", isp->isp_name,
sp->req_header.rqs_flags & 0xf);
+ if (sp->req_header.rqs_flags & RQSFLAG_FULL) {
+ PRINTF("%s: internal queues full\n",
+ isp->isp_name);
+ /* XXXX: this command *could* get restarted */
+ buddaboom++;
+ }
+ if (sp->req_header.rqs_flags & RQSFLAG_BADHEADER) {
+ PRINTF("%s: bad header\n", isp->isp_name);
+ buddaboom++;
+ }
+ if (sp->req_header.rqs_flags & RQSFLAG_BADPACKET) {
+ PRINTF("%s: bad request packet\n",
+ isp->isp_name);
+ buddaboom++;
+ }
}
- if (sp->req_handle >= RQUEST_QUEUE_LEN) {
- printf("%s: bad request handle %d\n", isp->isp_name,
+ if (sp->req_handle > RQUEST_QUEUE_LEN || sp->req_handle < 1) {
+ PRINTF("%s: bad request handle %d\n", isp->isp_name,
sp->req_handle);
ISP_WRITE(isp, INMAILBOX5, optr);
continue;
}
- xs = (struct scsi_xfer *) isp->isp_xflist[sp->req_handle];
+ xs = (ISP_SCSI_XFER_T *) isp->isp_xflist[sp->req_handle - 1];
if (xs == NULL) {
- printf("%s: NULL xs in xflist\n", isp->isp_name);
+ PRINTF("%s: NULL xs in xflist (handle %x)\n",
+ isp->isp_name, sp->req_handle);
+ isp_dumpxflist(isp);
ISP_WRITE(isp, INMAILBOX5, optr);
continue;
}
- isp->isp_xflist[sp->req_handle] = NULL;
+ isp->isp_xflist[sp->req_handle - 1] = NULL;
if (sp->req_status_flags & RQSTF_BUS_RESET) {
isp->isp_sendmarker = 1;
}
if (buddaboom) {
- xs->error = XS_DRIVER_STUFFUP;
+ XS_SETERR(xs, HBA_BOTCH);
}
- if (sp->req_state_flags & RQSF_GOT_SENSE) {
- bcopy(sp->req_sense_data, &xs->sense,
- sizeof (xs->sense));
- xs->error = XS_SENSE;
+ XS_STS(xs) = sp->req_scsi_status & 0xff;
+ if (isp->isp_type & ISP_HA_SCSI) {
+ if (sp->req_state_flags & RQSF_GOT_SENSE) {
+ MEMCPY(XS_SNSP(xs), sp->req_sense_data,
+ XS_SNSLEN(xs));
+ XS_SNS_IS_VALID(xs);
+ }
+ /*
+ * 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) {
+ sdparam *sdp = isp->isp_param;
+ isp->isp_update = 1;
+ sdp->isp_devparam[XS_TGT(xs)].dev_refresh = 1;
+ }
+ } else {
+ if (XS_STS(xs) == SCSI_CHECK) {
+ XS_SNS_IS_VALID(xs);
+ MEMCPY(XS_SNSP(xs), sp->req_sense_data,
+ XS_SNSLEN(xs));
+ sp->req_state_flags |= RQSF_GOT_SENSE;
+ }
+ }
+ if (XS_NOERR(xs) && XS_STS(xs) == SCSI_BUSY) {
+ XS_SETERR(xs, HBA_TGTBSY);
}
- xs->status = sp->req_scsi_status;
- if (xs->error == 0 && xs->status == SCSI_BUSY)
- xs->error = XS_BUSY;
if (sp->req_header.rqs_entry_type == RQSTYPE_RESPONSE) {
- if (xs->error == 0)
- xs->error = isp_parse_status(isp, sp);
+ if (XS_NOERR(xs)) {
+ if (sp->req_completion_status != RQCS_COMPLETE) {
+ isp_parse_status(isp, sp, xs);
+ } else {
+ XS_SETERR(xs, HBA_NOERROR);
+ }
+ }
} else {
- printf("%s: unknown return %x\n", isp->isp_name,
+ PRINTF("%s: unknown return %x\n", isp->isp_name,
sp->req_header.rqs_entry_type);
- if (xs->error == 0)
- xs->error = XS_DRIVER_STUFFUP;
+ if (XS_NOERR(xs)) {
+ XS_SETERR(xs, HBA_BOTCH);
+ }
}
- xs->resid = sp->req_resid;
- xs->flags |= ITSDONE;
- if (xs->datalen) {
- ISP_DMAFREE(isp, xs, sp->req_handle);
+ if (isp->isp_type & ISP_HA_SCSI) {
+ XS_RESID(xs) = sp->req_resid;
+ } else if (sp->req_scsi_status & RQCS_RU) {
+ XS_RESID(xs) = sp->req_resid;
+ IDPRINTF(4, ("%s: cnt %d rsd %d\n", isp->isp_name,
+ XS_XFRLEN(xs), sp->req_resid));
}
-#if 0
- printf("%s(%d.%d): FINISH%d cmd 0x%x resid %d STS %x",
- isp->isp_name, xs->sc_link->target, xs->sc_link->lun,
- sp->req_header.rqs_seqno, *(u_char *) xs->cmd,
- xs->resid, xs->status);
- if (sp->req_state_flags & RQSF_GOT_SENSE) {
- printf(" Skey: %x", xs->sense.flags);
- if (xs->error != XS_SENSE) {
- printf(" BUT NOT SET");
+ if (XS_XFRLEN(xs)) {
+ ISP_DMAFREE(isp, xs, sp->req_handle - 1);
+ }
+ /*
+ * XXX: If we have a check condition, but no Sense Data,
+ * XXX: mark it as an error (ARQ failed). We need to
+ * XXX: to do a more distinct job because there may
+ * XXX: cases where ARQ is disabled.
+ */
+ if (XS_STS(xs) == SCSI_CHECK && !(XS_IS_SNS_VALID(xs))) {
+ if (XS_NOERR(xs)) {
+ PRINTF("%s: ARQ failure for target %d lun %d\n",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ XS_SETERR(xs, HBA_ARQFAIL);
}
}
- printf(" xs->error %d\n", xs->error);
-#endif
+ if ((isp->isp_dblev >= 5) ||
+ (isp->isp_dblev > 2 && !XS_NOERR(xs))) {
+ PRINTF("%s(%d.%d): FIN%d dl%d resid%d STS %x",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs),
+ sp->req_header.rqs_seqno, XS_XFRLEN(xs),
+ XS_RESID(xs), XS_STS(xs));
+ if (sp->req_state_flags & RQSF_GOT_SENSE) {
+ PRINTF(" Skey: %x", XS_SNSKEY(xs));
+ if (!(XS_IS_SNS_VALID(xs))) {
+ PRINTF(" BUT NOT SET");
+ }
+ }
+ PRINTF(" XS_ERR=0x%x\n", (unsigned int) XS_ERR(xs));
+ }
+
+ if (isp->isp_nactive > 0)
+ isp->isp_nactive--;
+ complist[ndone++] = xs; /* defer completion call until later */
+ }
+
+ /*
+ * If we looked at any commands, then it's valid to find out
+ * what the outpointer is. It also is a trigger to update the
+ * ISP's notion of what we've seen so far.
+ */
+ if (nlooked) {
ISP_WRITE(isp, INMAILBOX5, optr);
- scsi_done(xs);
+ isp->isp_reqodx = ISP_READ(isp, OUTMAILBOX4);
}
isp->isp_residx = optr;
+ for (i = 0; i < ndone; i++) {
+ xs = complist[i];
+ if (xs) {
+ XS_CMD_DONE(xs);
+ }
+ }
return (1);
}
@@ -808,153 +1691,1284 @@ isp_intr(arg)
*/
static int
-isp_parse_status(isp, sp)
+isp_parse_async(isp, mbox)
+ struct ispsoftc *isp;
+ int mbox;
+{
+ u_int32_t fast_post_handle = 0;
+
+ switch (mbox) {
+ case MBOX_COMMAND_COMPLETE: /* sometimes these show up */
+ break;
+ case ASYNC_BUS_RESET:
+ isp_async(isp, ISPASYNC_BUS_RESET, NULL);
+ isp->isp_sendmarker = 1;
+#ifdef ISP_TARGET_MODE
+ isp_notify_ack(isp, NULL);
+#endif
+ break;
+
+ case ASYNC_SYSTEM_ERROR:
+ mbox = ISP_READ(isp, OUTMAILBOX1);
+ PRINTF("%s: Internal FW Error @ RISC Addr 0x%x\n",
+ isp->isp_name, mbox);
+ isp_restart(isp);
+ /* no point continuing after this */
+ return (-1);
+
+ case ASYNC_RQS_XFER_ERR:
+ PRINTF("%s: Request Queue Transfer Error\n", isp->isp_name);
+ break;
+
+ case ASYNC_RSP_XFER_ERR:
+ PRINTF("%s: Response Queue Transfer Error\n", isp->isp_name);
+ break;
+
+ case ASYNC_QWAKEUP:
+ /* don't need to be chatty */
+ mbox = ISP_READ(isp, OUTMAILBOX4);
+ break;
+
+ case ASYNC_TIMEOUT_RESET:
+ PRINTF("%s: timeout initiated SCSI bus reset\n", isp->isp_name);
+ isp->isp_sendmarker = 1;
+#ifdef ISP_TARGET_MODE
+ isp_notify_ack(isp, NULL);
+#endif
+ break;
+
+ case ASYNC_DEVICE_RESET:
+ isp->isp_sendmarker = 1;
+ PRINTF("%s: device reset\n", isp->isp_name);
+#ifdef ISP_TARGET_MODE
+ isp_notify_ack(isp, NULL);
+#endif
+ break;
+
+ case ASYNC_EXTMSG_UNDERRUN:
+ PRINTF("%s: extended message underrun\n", isp->isp_name);
+ break;
+
+ case ASYNC_SCAM_INT:
+ PRINTF("%s: SCAM interrupt\n", isp->isp_name);
+ break;
+
+ case ASYNC_HUNG_SCSI:
+ PRINTF("%s: stalled SCSI Bus after DATA Overrun\n",
+ isp->isp_name);
+ /* XXX: Need to issue SCSI reset at this point */
+ break;
+
+ case ASYNC_KILLED_BUS:
+ PRINTF("%s: SCSI Bus reset after DATA Overrun\n",
+ isp->isp_name);
+ break;
+
+ case ASYNC_BUS_TRANSIT:
+ PRINTF("%s: LBD->HVD Transition 0x%x\n",
+ isp->isp_name, ISP_READ(isp, OUTMAILBOX1));
+ break;
+
+ case ASYNC_CMD_CMPLT:
+ fast_post_handle = (ISP_READ(isp, OUTMAILBOX2) << 16) |
+ ISP_READ(isp, OUTMAILBOX1);
+ IDPRINTF(3, ("%s: fast post completion of %u\n", isp->isp_name,
+ fast_post_handle));
+ break;
+
+ case ASYNC_CTIO_DONE:
+ /* Should only occur when Fast Posting Set for 2100s */
+ PRINTF("%s: CTIO done\n", isp->isp_name);
+ break;
+
+ case ASYNC_LIP_OCCURRED:
+ isp->isp_sendmarker = 1;
+ PRINTF("%s: LIP occurred\n", isp->isp_name);
+ break;
+
+ case ASYNC_LOOP_UP:
+ isp->isp_sendmarker = 1;
+ isp_async(isp, ISPASYNC_LOOP_UP, NULL);
+ break;
+
+ case ASYNC_LOOP_DOWN:
+ isp_async(isp, ISPASYNC_LOOP_DOWN, NULL);
+ break;
+
+ case ASYNC_LOOP_RESET:
+ isp->isp_sendmarker = 1;
+ PRINTF("%s: Loop RESET\n", isp->isp_name);
+#ifdef ISP_TARGET_MODE
+ isp_notify_ack(isp, NULL);
+#endif
+ break;
+
+ case ASYNC_PDB_CHANGED:
+ isp->isp_sendmarker = 1;
+ isp_mark_getpdb_all(isp);
+ PRINTF("%s: Port Database Changed\n", isp->isp_name);
+ break;
+
+ case ASYNC_CHANGE_NOTIFY:
+ break;
+
+ default:
+ PRINTF("%s: unknown async code 0x%x\n", isp->isp_name, mbox);
+ break;
+ }
+ return (fast_post_handle);
+}
+
+static int
+isp_handle_other_response(isp, sp, optrp)
+ struct ispsoftc *isp;
+ ispstatusreq_t *sp;
+ u_int8_t *optrp;
+{
+ u_int8_t iptr, optr;
+ int reqsize = 0;
+ void *ireqp = NULL;
+#ifdef ISP_TARGET_MODE
+ union {
+ at_entry_t *atio;
+ at2_entry_t *at2io;
+ ct_entry_t *ctio;
+ ct2_entry_t *ct2io;
+ lun_entry_t *lunen;
+ in_entry_t *inot;
+ in_fcentry_t *inot_fc;
+ na_entry_t *nack;
+ na_fcentry_t *nack_fc;
+ void *voidp;
+#define atio un.atio
+#define at2io un.at2io
+#define ctio un.ctio
+#define ct2io un.ct2io
+#define lunen un.lunen
+#define inot un.inot
+#define inot_fc un.inot_fc
+#define nack un.nack
+#define nack_fc un.nack_fc
+ } un;
+
+ un.voidp = sp;
+#endif
+
+
+ switch (sp->req_header.rqs_entry_type) {
+ case RQSTYPE_REQUEST:
+ return (-1);
+#ifdef ISP_TARGET_MODE
+ case RQSTYPE_NOTIFY_ACK:
+ {
+ static const char *f =
+ "%s: Notify Ack Status 0x%x Sequence Id 0x%x\n"
+ /*
+ * The ISP is acknowleding our ack of an Immediate Notify.
+ */
+ if (isp->isp_type & ISP_HA_FC) {
+ PRINTF(f, isp->isp_name,
+ nack_fc->na-status, nack_fc->na_seqid);
+ } else {
+ PRINTF(f, isp->isp_name,
+ nack->na_status, nack->na_seqid);
+ }
+ break;
+ }
+ case RQSTYPE_NOTIFY:
+ {
+ u_int16_t seqid, status;
+
+ /*
+ * Either the ISP received a SCSI message it cannot handle
+ * or some other out of band condition (e.g., Port Logout)
+ * or it is returning an Immediate Notify entry we sent.
+ */
+ if (isp->isp_type & ISP_HA_FC) {
+ status = inot_fc->status;
+ seqid = inot_fc->in_seqid;
+ } else {
+ status = inot->status;
+ seqid = inot->seqid & 0xff;
+ }
+ PRINTF("%s: Immediate Notify Status 0x%x Sequence Id 0x%x\n",
+ isp->isp_name, status, seqid);
+
+ switch (status) {
+ case IN_MSG_RECEIVED:
+ case IN_IDE_RECEIVED:
+ ptisp_got_msg(ptp, &inot);
+ break;
+ case IN_RSRC_UNAVAIL:
+ PRINTF("%s: Firmware out of ATIOs\n", isp->isp_name);
+ break;
+ case IN_ABORT_TASK:
+ PRINTF("%s: Abort Task iid %d rx_id 0x%x\n",
+ inot_fc->in_iid, seqid);
+ break;
+ case IN_PORT_LOGOUT:
+ PRINTF("%s: Port Logout for Initiator %d\n",
+ isp->isp_name, inot_fc->in_iid);
+ break;
+ default:
+ PRINTF("%s: bad status (0x%x) in Immediate Notify\n",
+ isp->isp_name, status);
+ break;
+
+ }
+ isp_notify_ack(isp, un.voidp);
+ reqsize = 0;
+ break;
+ }
+ case RQSTYPE_ENABLE_LUN:
+ case RQSTYPE_MODIFY_LUN:
+ if (lunen->req_status != 1) {
+ PRINTF("%s: ENABLE/MODIFY LUN returned status 0x%x\n",
+ isp->isp_name, lunen->req_status);
+ }
+ break;
+ case RQSTYPE_ATIO2:
+ {
+ fcparam *fcp = isp->isp_param;
+ ispctiot2_t local, *ct2 = NULL;
+ ispatiot2_t *at2 = (ispatiot2_t *) sp;
+ int s, lun;
+
+#ifdef ISP2100_SCCLUN
+ lun = at2->req_scclun;
+#else
+ lun = at2->req_lun;
+#endif
+ PRINTF("%s: atio2 loopid %d for lun %d rxid 0x%x flags0x%x "
+ "tflags0x%x ecodes0x%x rqstatus0x%x\n", isp->isp_name,
+ at2->req_initiator, lun, at2->req_rxid,
+ at2->req_flags, at2->req_taskflags, at2->req_execodes,
+ at2->req_status);
+
+ switch (at2->req_status & ~ATIO_SENSEVALID) {
+ case ATIO_PATH_INVALID:
+ PRINTF("%s: ATIO2 Path Invalid\n", isp->isp_name);
+ break;
+ case ATIO_NOCAP:
+ PRINTF("%s: ATIO2 No Cap\n", isp->isp_name);
+ break;
+ case ATIO_BDR_MSG:
+ PRINTF("%s: ATIO2 BDR Received\n", isp->isp_name);
+ break;
+ case ATIO_CDB_RECEIVED:
+ ct2 = &local;
+ break;
+ default:
+ PRINTF("%s: unknown req_status 0x%x\n", isp->isp_name,
+ at2->req_status);
+ break;
+ }
+ if (ct2 == NULL) {
+ /*
+ * Just do an ACCEPT on this fellow.
+ */
+ at2->req_header.rqs_entry_type = RQSTYPE_ATIO2;
+ at2->req_header.rqs_flags = 0;
+ at2->req_flags = 1;
+ ireqp = at2;
+ reqsize = sizeof (*at2);
+ break;
+ }
+ PRINTF("%s: datalen %d cdb0=0x%x\n", isp->isp_name,
+ at2->req_datalen, at2->req_cdb[0]);
+ MEMZERO((void *) ct2, sizeof (*ct2));
+ ct2->req_header.rqs_entry_type = RQSTYPE_CTIO2;
+ ct2->req_header.rqs_entry_count = 1;
+ ct2->req_header.rqs_flags = 0;
+ ct2->req_header.rqs_seqno = isp->isp_seqno++;
+ ct2->req_handle = (at2->req_initiator << 16) | lun;
+#ifndef ISP2100_SCCLUN
+ ct2->req_lun = lun;
+#endif
+ ct2->req_initiator = at2->req_initiator;
+ ct2->req_rxid = at2->req_rxid;
+
+ ct2->req_flags = CTIO_SEND_STATUS;
+ switch (at2->req_cdb[0]) {
+ case 0x0: /* TUR */
+ ct2->req_flags |= CTIO_NODATA | CTIO2_SMODE0;
+ ct2->req_m.mode0.req_scsi_status = CTIO2_STATUS_VALID;
+ break;
+
+ case 0x3: /* REQUEST SENSE */
+ case 0x12: /* INQUIRE */
+ ct2->req_flags |= CTIO_SEND_DATA | CTIO2_SMODE0;
+ ct2->req_m.mode0.req_scsi_status = CTIO2_STATUS_VALID;
+ ct2->req_seg_count = 1;
+ if (at2->req_cdb[0] == 0x12) {
+ s = sizeof(tgtiqd);
+ MEMCPY(fcp->isp_scratch, tgtiqd, s);
+ } else {
+ s = at2->req_datalen;
+ MEMZERO(fcp->isp_scratch, s);
+ }
+ ct2->req_m.mode0.req_dataseg[0].ds_base =
+ fcp->isp_scdma;
+ ct2->req_m.mode0.req_dataseg[0].ds_count = s;
+ ct2->req_m.mode0.req_datalen = s;
+#if 1
+ if (at2->req_datalen < s) {
+ ct2->req_m.mode1.req_scsi_status |=
+ CTIO2_RESP_VALID|CTIO2_RSPOVERUN;
+ } else if (at2->req_datalen > s) {
+ ct2->req_m.mode1.req_scsi_status |=
+ CTIO2_RESP_VALID|CTIO2_RSPUNDERUN;
+ }
+#endif
+ break;
+
+ default: /* ALL OTHERS */
+ ct2->req_flags |= CTIO_NODATA | CTIO2_SMODE1;
+ ct2->req_m.mode1.req_scsi_status = 0;
+#if 1
+ if (at2->req_datalen) {
+ ct2->req_m.mode1.req_scsi_status |=
+ CTIO2_RSPUNDERUN;
+#if BYTE_ORDER == BIG_ENDIAN
+ ct2->req_resid[1] = at2->req_datalen & 0xff;
+ ct2->req_resid[0] =
+ (at2->req_datalen >> 8) & 0xff;
+ ct2->req_resid[3] =
+ (at2->req_datalen >> 16) & 0xff;
+ ct2->req_resid[2] =
+ (at2->req_datalen >> 24) & 0xff;
+#else
+ ct2->req_resid[0] = at2->req_datalen & 0xff;
+ ct2->req_resid[1] =
+ (at2->req_datalen >> 8) & 0xff;
+ ct2->req_resid[2] =
+ (at2->req_datalen >> 16) & 0xff;
+ ct2->req_resid[3] =
+ (at2->req_datalen >> 24) & 0xff;
+#endif
+ }
+#endif
+ if ((at2->req_status & ATIO_SENSEVALID) == 0) {
+ ct2->req_m.mode1.req_sense_len = 18;
+ ct2->req_m.mode1.req_scsi_status |= 2;
+ ct2->req_m.mode1.req_response[0] = 0x70;
+ ct2->req_m.mode1.req_response[2] = 0x2;
+ } else {
+ ct2->req_m.mode1.req_sense_len = 18;
+ ct2->req_m.mode1.req_scsi_status |=
+ at2->req_scsi_status;
+ MEMCPY(ct2->req_m.mode1.req_response,
+ at2->req_sense, sizeof (at2->req_sense));
+ }
+ break;
+ }
+ reqsize = sizeof (*ct2);
+ ireqp = ct2;
+ break;
+ }
+ case RQSTYPE_CTIO2:
+ {
+ ispatiot2_t *at2;
+ ispctiot2_t *ct2 = (ispctiot2_t *) sp;
+ PRINTF("%s: CTIO2 returned status 0x%x\n", isp->isp_name,
+ ct2->req_status);
+ /*
+ * Return the ATIO to the board.
+ */
+ at2 = (ispatiot2_t *) sp;
+ at2->req_header.rqs_entry_type = RQSTYPE_ATIO2;
+ at2->req_header.rqs_entry_count = 1;
+ at2->req_header.rqs_flags = 0;
+ at2->req_header.rqs_seqno = isp->isp_seqno++;
+ at2->req_status = 1;
+ reqsize = sizeof (*at2);
+ ireqp = at2;
+ break;
+ }
+#undef atio
+#undef at2io
+#undef ctio
+#undef ct2io
+#undef lunen
+#undef inot
+#undef inot_fc
+#undef nack
+#undef nack_fc
+#endif
+ default:
+ PRINTF("%s: other response type %x\n", isp->isp_name,
+ sp->req_header.rqs_entry_type);
+ break;
+ }
+ if (reqsize) {
+ void *reqp;
+ optr = isp->isp_reqodx = ISP_READ(isp, OUTMAILBOX4);
+ iptr = isp->isp_reqidx;
+ reqp = (void *) ISP_QUEUE_ENTRY(isp->isp_rquest, iptr);
+ iptr = ISP_NXT_QENTRY(iptr, RQUEST_QUEUE_LEN);
+ if (iptr == optr) {
+ PRINTF("%s: Request Queue Overflow other response\n",
+ isp->isp_name);
+ } else {
+ MEMCPY(reqp, ireqp, reqsize);
+ ISP_WRITE(isp, INMAILBOX4, iptr);
+ isp->isp_reqidx = iptr;
+ }
+ }
+ return (0);
+}
+
+#ifdef ISP_TARGET_MODE
+
+static void isp_tmd_newcmd_dflt __P((void *, tmd_cmd_t *));
+static void isp_tmd_event_dflt __P((void *, int));
+static void isp_tmd_notify_dflt __P((void *, tmd_notify_t *));
+
+static void isp_tgt_data_xfer __P ((tmd_cmd_t *));
+static void isp_tgt_endcmd __P ((tmd_cmd_t *, u_int8_t));
+static void isp_tgt_done __P ((tmd_cmd_t *));
+
+static void
+isp_tmd_newcmd_dflt(arg0, cmdp)
+ void *arg0;
+ tmd_cmd_t *cmdp;
+{
+}
+
+static void
+isp_tmd_event_dflt(arg0, event)
+ void *arg0;
+ int event;
+{
+}
+
+static void
+isp_tmd_notify_dflt(arg0, npt)
+ void *arg0;
+ tmd_notify_t *npt;
+{
+}
+
+/*
+ * Locks held, and ints disabled (if FC).
+ *
+ * XXX: SETUP ONLY FOR INITIAL ENABLING RIGHT NOW
+ */
+static int
+isp_modify_lun(isp, lun, icnt, ccnt)
+ struct ispsoftc *isp;
+ int lun; /* logical unit to enable, modify, or disable */
+ int icnt; /* immediate notify count */
+ int ccnt; /* command count */
+{
+ isplun_t *ip = NULL;
+ u_int8_t iptr, optr;
+
+ optr = isp->isp_reqodx = ISP_READ(isp, OUTMAILBOX4);
+ iptr = isp->isp_reqidx;
+ ip = (isplun_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, iptr);
+ iptr = ISP_NXT_QENTRY(iptr, RQUEST_QUEUE_LEN);
+ if (iptr == optr) {
+ PRINTF("%s: Request Queue Overflow in isp_modify_lun\n",
+ isp->isp_name);
+ return (-1);
+ }
+
+ MEMZERO((void *) ip, sizeof (*ip));
+ ip->req_header.rqs_entry_type = RQSTYPE_ENABLE_LUN;
+ ip->req_header.rqs_entry_count = 1;
+ ip->req_header.rqs_seqno = isp->isp_seqno++;
+ ip->req_handle = RQSTYPE_ENABLE_LUN;
+ if (isp->isp_type & ISP_HA_SCSI) {
+ ip->req_lun = lun;
+ }
+ ip->req_cmdcount = ccnt;
+ ip->req_imcount = icnt;
+ ip->req_timeout = 0; /* default 30 seconds */
+ ISP_WRITE(isp, INMAILBOX4, iptr);
+ isp->isp_reqidx = iptr;
+ return (0);
+}
+
+static void
+isp_notify_ack(isp, ptrp)
+ struct ispsoftc *isp;
+ void *ptrp;
+{
+ void *reqp;
+ u_int8_t iptr, optr;
+ union {
+ na_fcentry_t _naf;
+ na_entry_t _nas;
+ } un;
+
+ MEMZERO((caddr_t)&un, sizeof (un));
+ un._nas.na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK;
+ un._nas.na_header.rqs_entry_count = 1;
+
+ if (isp->isp_type & ISP_HA_FC) {
+ na_fcentry_t *na = &un._nas;
+ if (ptrp) {
+ in_fcentry_t *inp = ptrp;
+ na->na_iid = inp->in_iid;
+ na->na_lun = inp->in_lun;
+ na->na_task_flags = inp->in_task_flags;
+ na->na_seqid = inp->in_seqid;
+ na->na_status = inp->in_status;
+ } else {
+ na->na_flags = NAFC_RST_CLRD;
+ }
+ } else {
+ na_entry_t *na = &un._nas;
+ if (ptrp) {
+ in_entry_t *inp = ptrp;
+ na->na_iid = inp->in_iid;
+ na->na_lun = inp->in_lun;
+ na->na_tgt = inp->in_tgt;
+ na->na_seqid = inp->in_seqid;
+ } else {
+ na->na_flags = NA_RST_CLRD;
+ }
+ }
+ optr = isp->isp_reqodx = ISP_READ(isp, OUTMAILBOX4);
+ iptr = isp->isp_reqidx;
+ reqp = (void *) ISP_QUEUE_ENTRY(isp->isp_rquest, iptr);
+ iptr = ISP_NXT_QENTRY(iptr, RQUEST_QUEUE_LEN);
+ if (iptr == optr) {
+ PRINTF("%s: Request Queue Overflow For isp_notify_ack\n",
+ isp->isp_name);
+ } else {
+ MEMCPY(reqp, ireqp, sizeof (un));
+ ISP_WRITE(isp, INMAILBOX4, iptr);
+ isp->isp_reqidx = iptr;
+ }
+}
+
+/*
+ * These are dummy stubs for now until the outside framework is plugged in.
+ */
+
+static void
+isp_handle_atio (isp, aep)
+ struct ispsoftc *isp;
+ at_entry_t *aep;
+{
+ int status, connected;
+ tmd_cmd_t local, *cdp = &local;
+
+ /*
+ * Get the ATIO status and see if we're still connected.
+ */
+ status = aep->at_status;
+ connected = ((aep->at_flags & AT_NODISC) != 0);
+
+ PRINTF("%s: ATIO status=0x%x, connected=%d\n", isp->isp_name,
+ status, connected);
+
+ /*
+ * The firmware status (except for the SenseValid bit) indicates
+ * why this ATIO was sent to us.
+ * If SenseValid is set, the firware has recommended Sense Data.
+ * If the Disconnects Disabled bit is set in the flags field,
+ * we're still connected on the SCSI bus - i.e. the initiator
+ * did not set DiscPriv in the identify message. We don't care
+ * about this so it's ignored.
+ */
+ switch(status & ~TGTSVALID) {
+ case AT_PATH_INVALID:
+ /*
+ * ATIO rejected by the firmware due to disabled lun.
+ */
+ PRINTF("%s: Firmware rejected ATIO for disabled lun %d\n",
+ isp->isp_name, aep->at_lun);
+ break;
+
+ case AT_PHASE_ERROR:
+ /*
+ * Bus Pase Sequence error.
+ *
+ * The firmware should have filled in the correct
+ * sense data.
+ */
+
+
+ if (status & TGTSVALID) {
+ MEMCPY(&cdp->cd_sensedata, aep->at_sense,
+ sizeof (cdp->cd_sensedata));
+ PRINTF("%s: Bus Phase Sequence error key 0x%x\n",
+ isp->isp_name, cdp->cd_sensedata[2] & 0xf);
+ } else {
+ PRINTF("%s: Bus Phase Sequence With No Sense\n",
+ isp->isp_name);
+ }
+ (*isp->isp_tmd_newcmd)(isp, cdp);
+ break;
+
+ case AT_NOCAP:
+ /*
+ * Requested Capability not available
+ * We sent an ATIO that overflowed the firmware's
+ * command resource count.
+ */
+ PRINTF("%s: Firmware rejected ATIO, command count overflow\n",
+ isp->isp_name);
+ break;
+
+ case AT_BDR_MSG:
+ /*
+ * If we send an ATIO to the firmware to increment
+ * its command resource count, and the firmware is
+ * recovering from a Bus Device Reset, it returns
+ * the ATIO with this status.
+ */
+ PRINTF("%s: ATIO returned with BDR received\n", isp->isp_name);
+ break;
+
+ case AT_CDB:
+ /*
+ * New CDB
+ */
+ cdp->cd_hba = isp;
+ cdp->cd_iid = aep->at_iid;
+ cdp->cd_tgt = aep->at_tgt;
+ cdp->cd_lun = aep->at_lun;
+ cdp->cd_tagtype = aep->at_tag_type;
+ cdp->cd_tagval = aep->at_tag_val;
+ MEMCPY(cdp->cd_cdb, aep->at_cdb, 16);
+ PRINTF("%s: CDB 0x%x itl %d/%d/%d\n", isp->isp_name,
+ cdp->cd_cdb[0], cdp->cd_iid, cdp->cd_tgt, cdp->cd_lun);
+ (*isp->isp_tmd_newcmd)(isp, cdp);
+ break;
+
+ default:
+ PRINTF("%s: Unknown status (0x%x) in ATIO\n",
+ isp->isp_name, status);
+ cdp->cd_hba = isp;
+ cdp->cd_iid = aep->at_iid;
+ cdp->cd_tgt = aep->at_tgt;
+ cdp->cd_lun = aep->at_lun;
+ cdp->cd_tagtype = aep->at_tag_type;
+ cdp->cd_tagval = aep->at_tag_val;
+ isp_tgtcmd_done(cdp);
+ break;
+ }
+}
+
+static void
+isp_handle_atio2(isp, aep)
+ struct ispsoftc *isp;
+ at2_entry_t *aep;
+{
+ int status;
+ tmd_cmd_t local, *cdp = &local;
+
+ /*
+ * Get the ATIO2 status.
+ */
+ status = aep->at_status;
+ PRINTD("%s: ATIO2 status=0x%x\n", status);
+
+ /*
+ * The firmware status (except for the SenseValid bit) indicates
+ * why this ATIO was sent to us.
+ * If SenseValid is set, the firware has recommended Sense Data.
+ */
+ switch(status & ~TGTSVALID) {
+ case AT_PATH_INVALID:
+ /*
+ * ATIO rejected by the firmware due to disabled lun.
+ */
+ PRINTF("%s: Firmware rejected ATIO2 for disabled lun %d\n",
+ isp->isp_name, aep->at_lun);
+ break;
+
+ case AT_NOCAP:
+ /*
+ * Requested Capability not available
+ * We sent an ATIO that overflowed the firmware's
+ * command resource count.
+ */
+ PRINTF("%s: Firmware rejected ATIO2, command count overflow\n",
+ isp->isp_name);
+ break;
+
+ case AT_BDR_MSG:
+ /*
+ * If we send an ATIO to the firmware to increment
+ * its command resource count, and the firmware is
+ * recovering from a Bus Device Reset, it returns
+ * the ATIO with this status.
+ */
+ PRINTF("%s: ATIO2 returned with BDR rcvd\n", isp->isp_name);
+ break;
+
+ case AT_CDB:
+ /*
+ * New CDB
+ */
+ cdp->cd_hba = isp;
+ cdp->cd_iid = aep->at_iid;
+ cdp->cd_tgt = 0;
+ cdp->cd_lun = aep->at_lun;
+ MEMCPY(cdp->cd_cdb, aep->at_cdb, 16);
+ cdp->cd_rxid = aep->at_rxid;
+ cdp->cp_origdlen = aep->at_datalen;
+ cdp->cp_totbytes = 0;
+ PRINTF("%s: CDB 0x%x rx_id 0x%x itl %d/%d/%d dlen %d\n",
+ isp->isp_name, cdp->cd_cdb[0], cdp->cd_tagval, cdp->cd_iid,
+ cdp->cd_tgt, cdp->cd_lun, aep->at_datalen);
+ (*isp->isp_tmd_newcmd)(isp, cdp);
+ break;
+
+ default:
+ PRINTF("%s: Unknown status (0x%x) in ATIO2\n",
+ isp->isp_name, status);
+ cdp->cd_hba = isp;
+ cdp->cd_iid = aep->at_iid;
+ cdp->cd_tgt = aep->at_tgt;
+ cdp->cd_lun = aep->at_lun;
+ cdp->cp_rxid = aep->at_rxid;
+ isp_tgtcmd_done(cdp);
+ break;
+ }
+}
+
+static void
+isp_handle_ctio(isp, cep)
+ struct ispsoftc *isp;
+ ct_entry_t *aep;
+{
+}
+
+static void
+isp_handle_ctio2(isp, cep)
+ struct ispsoftc *isp;
+ at2_entry_t *aep;
+{
+}
+#endif
+
+static void
+isp_parse_status(isp, sp, xs)
struct ispsoftc *isp;
ispstatusreq_t *sp;
+ ISP_SCSI_XFER_T *xs;
{
switch (sp->req_completion_status) {
case RQCS_COMPLETE:
- return (XS_NOERROR);
- break;
+ XS_SETERR(xs, HBA_NOERROR);
+ return;
+
case RQCS_INCOMPLETE:
if ((sp->req_state_flags & RQSF_GOT_TARGET) == 0) {
- return (XS_SELTIMEOUT);
+ IDPRINTF(3, ("%s: Selection Timeout for target %d\n",
+ isp->isp_name, XS_TGT(xs)));
+ XS_SETERR(xs, HBA_SELTIMEOUT);
+ return;
}
- printf("%s: incomplete, state %x\n",
- isp->isp_name, sp->req_state_flags);
+ PRINTF("%s: command incomplete for target %d lun %d, state "
+ "0x%x\n", isp->isp_name, XS_TGT(xs), XS_LUN(xs),
+ sp->req_state_flags);
break;
- case RQCS_DATA_UNDERRUN:
- return (XS_NOERROR);
- case RQCS_TIMEOUT:
- return (XS_TIMEOUT);
+
+ case RQCS_DMA_ERROR:
+ PRINTF("%s: DMA error for command on target %d, lun %d\n",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ break;
+
+ case RQCS_TRANSPORT_ERROR:
+ PRINTF("%s: transport error\n", isp->isp_name);
+ isp_prtstst(sp);
+ break;
+
case RQCS_RESET_OCCURRED:
- printf("%s: reset occurred\n", isp->isp_name);
+ IDPRINTF(2, ("%s: bus reset destroyed command for target %d "
+ "lun %d\n", isp->isp_name, XS_TGT(xs), XS_LUN(xs)));
isp->isp_sendmarker = 1;
- break;
+ XS_SETERR(xs, HBA_BUSRESET);
+ return;
+
case RQCS_ABORTED:
- printf("%s: command aborted\n", isp->isp_name);
+ PRINTF("%s: command aborted for target %d lun %d\n",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs));
isp->isp_sendmarker = 1;
+ XS_SETERR(xs, HBA_ABORTED);
+ return;
+
+ case RQCS_TIMEOUT:
+ IDPRINTF(2, ("%s: command timed out for target %d lun %d\n",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs)));
+ XS_SETERR(xs, HBA_CMDTIMEOUT);
+ return;
+
+ case RQCS_DATA_OVERRUN:
+ if (isp->isp_type & ISP_HA_FC) {
+ XS_RESID(xs) = sp->req_resid;
+ break;
+ }
+ XS_SETERR(xs, HBA_DATAOVR);
+ return;
+
+ case RQCS_COMMAND_OVERRUN:
+ PRINTF("%s: command overrun for command on target %d, lun %d\n",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ break;
+
+ case RQCS_STATUS_OVERRUN:
+ PRINTF("%s: status overrun for command on target %d, lun %d\n",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ break;
+
+ case RQCS_BAD_MESSAGE:
+ PRINTF("%s: message not COMMAND COMPLETE after status on "
+ "target %d, lun %d\n", isp->isp_name, XS_TGT(xs),
+ XS_LUN(xs));
+ break;
+
+ case RQCS_NO_MESSAGE_OUT:
+ PRINTF("%s: No MESSAGE OUT phase after selection on "
+ "target %d, lun %d\n", isp->isp_name, XS_TGT(xs),
+ XS_LUN(xs));
+ break;
+
+ case RQCS_EXT_ID_FAILED:
+ PRINTF("%s: EXTENDED IDENTIFY failed on target %d, lun %d\n",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ break;
+
+ case RQCS_IDE_MSG_FAILED:
+ PRINTF("%s: target %d lun %d rejected INITIATOR DETECTED "
+ "ERROR message\n", isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ break;
+
+ case RQCS_ABORT_MSG_FAILED:
+ PRINTF("%s: target %d lun %d rejected ABORT message\n",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ break;
+
+ case RQCS_REJECT_MSG_FAILED:
+ PRINTF("%s: target %d lun %d rejected MESSAGE REJECT message\n",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ break;
+
+ case RQCS_NOP_MSG_FAILED:
+ PRINTF("%s: target %d lun %d rejected NOP message\n",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ break;
+
+ case RQCS_PARITY_ERROR_MSG_FAILED:
+ PRINTF("%s: target %d lun %d rejected MESSAGE PARITY ERROR "
+ "message\n", isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ break;
+
+ case RQCS_DEVICE_RESET_MSG_FAILED:
+ PRINTF("%s: target %d lun %d rejected BUS DEVICE RESET "
+ "message\n", isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ break;
+
+ case RQCS_ID_MSG_FAILED:
+ PRINTF("%s: target %d lun %d rejected IDENTIFY "
+ "message\n", isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ break;
+
+ case RQCS_UNEXP_BUS_FREE:
+ PRINTF("%s: target %d lun %d had an unexpected bus free\n",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ break;
+
+ case RQCS_DATA_UNDERRUN:
+ if (isp->isp_type & ISP_HA_FC) {
+ XS_RESID(xs) = sp->req_resid;
+ /* an UNDERRUN is not a botch ??? */
+ }
+ XS_SETERR(xs, HBA_NOERROR);
+ return;
+
+ case RQCS_XACT_ERR1:
+ PRINTF("%s: HBA attempted queued transaction with disconnect "
+ "not set for target %d lun %d\n", isp->isp_name, XS_TGT(xs),
+ XS_LUN(xs));
+ break;
+
+ case RQCS_XACT_ERR2:
+ PRINTF("%s: HBA attempted queued transaction to target "
+ "routine %d on target %d\n", isp->isp_name, XS_LUN(xs),
+ XS_TGT(xs));
+ break;
+
+ case RQCS_XACT_ERR3:
+ PRINTF("%s: HBA attempted queued transaction for target %d lun "
+ "%d when queueing disabled\n", isp->isp_name, XS_TGT(xs),
+ XS_LUN(xs));
+ break;
+
+ case RQCS_BAD_ENTRY:
+ PRINTF("%s: invalid IOCB entry type detected\n", isp->isp_name);
+ break;
+
+ case RQCS_QUEUE_FULL:
+ PRINTF("%s: internal queues full for target %d lun %d "
+ "status 0x%x\n", isp->isp_name, XS_TGT(xs), XS_LUN(xs),
+ XS_STS(xs));
+ /*
+ * If QFULL or some other status byte is set, then this
+ * isn't an error, per se.
+ */
+ if (XS_STS(xs) != 0) {
+ XS_SETERR(xs, HBA_NOERROR);
+ return;
+ }
+ break;
+
+ case RQCS_PHASE_SKIPPED:
+ PRINTF("%s: SCSI phase skipped (e.g., COMMAND COMPLETE w/o "
+ "STATUS phase) for target %d lun %d\n", isp->isp_name,
+ XS_TGT(xs), XS_LUN(xs));
+ break;
+
+ case RQCS_ARQS_FAILED:
+ PRINTF("%s: Auto Request Sense failed for target %d lun %d\n",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ XS_SETERR(xs, HBA_ARQFAIL);
+ return;
+
+ case RQCS_WIDE_FAILED:
+ PRINTF("%s: Wide Negotiation failed for target %d lun %d\n",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ if (isp->isp_type & ISP_HA_SCSI) {
+ sdparam *sdp = isp->isp_param;
+ isp->isp_update = 1;
+ sdp->isp_devparam[XS_TGT(xs)].dev_flags &= ~DPARM_WIDE;
+ sdp->isp_devparam[XS_TGT(xs)].dev_update = 1;
+ }
+ XS_SETERR(xs, HBA_NOERROR);
+ return;
+
+ case RQCS_SYNCXFER_FAILED:
+ PRINTF("%s: SDTR Message failed for target %d lun %d\n",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ if (isp->isp_type & ISP_HA_SCSI) {
+ sdparam *sdp = isp->isp_param;
+ isp->isp_update = 1;
+ sdp->isp_devparam[XS_TGT(xs)].dev_flags &= ~DPARM_SYNC;
+ sdp->isp_devparam[XS_TGT(xs)].dev_update = 1;
+ }
+ break;
+
+ case RQCS_LVD_BUSERR:
+ PRINTF("%s: Bad LVD Bus condition while talking to target %d "
+ "lun %d\n", isp->isp_name, XS_TGT(xs), XS_LUN(xs));
break;
+
+ case RQCS_PORT_UNAVAILABLE:
+ /*
+ * No such port on the loop. Moral equivalent of SELTIMEO
+ */
+ IDPRINTF(3, ("%s: Port Unavailable for target %d\n",
+ isp->isp_name, XS_TGT(xs)));
+ XS_SETERR(xs, HBA_SELTIMEOUT);
+ return;
+
+ case RQCS_PORT_LOGGED_OUT:
+ /*
+ * It was there (maybe)- treat as a selection timeout.
+ */
+ PRINTF("%s: port logout for target %d\n",
+ isp->isp_name, XS_TGT(xs));
+ XS_SETERR(xs, HBA_SELTIMEOUT);
+ return;
+
+ case RQCS_PORT_CHANGED:
+ PRINTF("%s: port changed for target %d\n",
+ isp->isp_name, XS_TGT(xs));
+ break;
+
+ case RQCS_PORT_BUSY:
+ PRINTF("%s: port busy for target %d\n",
+ isp->isp_name, XS_TGT(xs));
+ XS_SETERR(xs, HBA_TGTBSY);
+ return;
+
default:
- printf("%s: comp status %x\n", isp->isp_name,
+ PRINTF("%s: comp status %x\n", isp->isp_name,
sp->req_completion_status);
break;
}
- return (XS_DRIVER_STUFFUP);
+ XS_SETERR(xs, HBA_BOTCH);
+}
+
+static void
+isp_fastpost_complete(isp, fph)
+ struct ispsoftc *isp;
+ int fph;
+{
+ ISP_SCSI_XFER_T *xs;
+
+ if (fph < 1)
+ return;
+ xs = (ISP_SCSI_XFER_T *) isp->isp_xflist[fph - 1];
+ isp->isp_xflist[fph - 1] = NULL;
+ if (xs == NULL) {
+ PRINTF("%s: fast posting handle 0x%x not found\n",
+ isp->isp_name, fph - 1);
+ return;
+ }
+ /*
+ * Since we don't have a result queue entry item,
+ * we must believe that SCSI status is zero and
+ * that all data transferred.
+ */
+ XS_RESID(xs) = 0;
+ XS_STS(xs) = 0;
+ if (XS_XFRLEN(xs)) {
+ ISP_DMAFREE(isp, xs, fph - 1);
+ }
+ XS_CMD_DONE(xs);
}
#define HINIB(x) ((x) >> 0x4)
#define LONIB(x) ((x) & 0xf)
#define MAKNIB(a, b) (((a) << 4) | (b))
static u_int8_t mbpcnt[] = {
- MAKNIB(1, 1), /* MBOX_NO_OP */
- MAKNIB(5, 5), /* MBOX_LOAD_RAM */
- MAKNIB(2, 0), /* MBOX_EXEC_FIRMWARE */
- MAKNIB(5, 5), /* MBOX_DUMP_RAM */
- MAKNIB(3, 3), /* MBOX_WRITE_RAM_WORD */
- MAKNIB(2, 3), /* MBOX_READ_RAM_WORD */
- MAKNIB(6, 6), /* MBOX_MAILBOX_REG_TEST */
- MAKNIB(2, 3), /* MBOX_VERIFY_CHECKSUM */
- MAKNIB(1, 3), /* MBOX_ABOUT_FIRMWARE */
- MAKNIB(0, 0), /* 0x0009 */
- MAKNIB(0, 0), /* 0x000a */
- MAKNIB(0, 0), /* 0x000b */
- MAKNIB(0, 0), /* 0x000c */
- MAKNIB(0, 0), /* 0x000d */
- MAKNIB(1, 2), /* MBOX_CHECK_FIRMWARE */
- MAKNIB(0, 0), /* 0x000f */
- MAKNIB(5, 5), /* MBOX_INIT_REQ_QUEUE */
- MAKNIB(6, 6), /* MBOX_INIT_RES_QUEUE */
- MAKNIB(4, 4), /* MBOX_EXECUTE_IOCB */
- MAKNIB(2, 2), /* MBOX_WAKE_UP */
- MAKNIB(1, 6), /* MBOX_STOP_FIRMWARE */
- MAKNIB(4, 4), /* MBOX_ABORT */
- MAKNIB(2, 2), /* MBOX_ABORT_DEVICE */
- MAKNIB(3, 3), /* MBOX_ABORT_TARGET */
- MAKNIB(2, 2), /* MBOX_BUS_RESET */
- MAKNIB(2, 3), /* MBOX_STOP_QUEUE */
- MAKNIB(2, 3), /* MBOX_START_QUEUE */
- MAKNIB(2, 3), /* MBOX_SINGLE_STEP_QUEUE */
- MAKNIB(2, 3), /* MBOX_ABORT_QUEUE */
- MAKNIB(2, 4), /* MBOX_GET_DEV_QUEUE_STATUS */
- MAKNIB(0, 0), /* 0x001e */
- MAKNIB(1, 3), /* MBOX_GET_FIRMWARE_STATUS */
- MAKNIB(1, 2), /* MBOX_GET_INIT_SCSI_ID */
- MAKNIB(1, 2), /* MBOX_GET_SELECT_TIMEOUT */
- MAKNIB(1, 3), /* MBOX_GET_RETRY_COUNT */
- MAKNIB(1, 2), /* MBOX_GET_TAG_AGE_LIMIT */
- MAKNIB(1, 2), /* MBOX_GET_CLOCK_RATE */
- MAKNIB(1, 2), /* MBOX_GET_ACT_NEG_STATE */
- MAKNIB(1, 2), /* MBOX_GET_ASYNC_DATA_SETUP_TIME */
- MAKNIB(1, 3), /* MBOX_GET_PCI_PARAMS */
- MAKNIB(2, 4), /* MBOX_GET_TARGET_PARAMS */
- MAKNIB(2, 4), /* MBOX_GET_DEV_QUEUE_PARAMS */
- MAKNIB(0, 0), /* 0x002a */
- MAKNIB(0, 0), /* 0x002b */
- MAKNIB(0, 0), /* 0x002c */
- MAKNIB(0, 0), /* 0x002d */
- MAKNIB(0, 0), /* 0x002e */
- MAKNIB(0, 0), /* 0x002f */
- MAKNIB(2, 2), /* MBOX_SET_INIT_SCSI_ID */
- MAKNIB(2, 2), /* MBOX_SET_SELECT_TIMEOUT */
- MAKNIB(3, 3), /* MBOX_SET_RETRY_COUNT */
- MAKNIB(2, 2), /* MBOX_SET_TAG_AGE_LIMIT */
- MAKNIB(2, 2), /* MBOX_SET_CLOCK_RATE */
- MAKNIB(2, 2), /* MBOX_SET_ACTIVE_NEG_STATE */
- MAKNIB(2, 2), /* MBOX_SET_ASYNC_DATA_SETUP_TIME */
- MAKNIB(3, 3), /* MBOX_SET_PCI_CONTROL_PARAMS */
- MAKNIB(4, 4), /* MBOX_SET_TARGET_PARAMS */
- MAKNIB(4, 4), /* MBOX_SET_DEV_QUEUE_PARAMS */
- MAKNIB(0, 0), /* 0x003a */
- MAKNIB(0, 0), /* 0x003b */
- MAKNIB(0, 0), /* 0x003c */
- MAKNIB(0, 0), /* 0x003d */
- MAKNIB(0, 0), /* 0x003e */
- MAKNIB(0, 0), /* 0x003f */
- MAKNIB(1, 2), /* MBOX_RETURN_BIOS_BLOCK_ADDR */
- MAKNIB(6, 1), /* MBOX_WRITE_FOUR_RAM_WORDS */
- MAKNIB(2, 3) /* MBOX_EXEC_BIOS_IOCB */
+ MAKNIB(1, 1), /* 0x00: MBOX_NO_OP */
+ MAKNIB(5, 5), /* 0x01: MBOX_LOAD_RAM */
+ MAKNIB(2, 0), /* 0x02: MBOX_EXEC_FIRMWARE */
+ MAKNIB(5, 5), /* 0x03: MBOX_DUMP_RAM */
+ MAKNIB(3, 3), /* 0x04: MBOX_WRITE_RAM_WORD */
+ MAKNIB(2, 3), /* 0x05: MBOX_READ_RAM_WORD */
+ MAKNIB(6, 6), /* 0x06: MBOX_MAILBOX_REG_TEST */
+ MAKNIB(2, 3), /* 0x07: MBOX_VERIFY_CHECKSUM */
+ MAKNIB(1, 3), /* 0x08: MBOX_ABOUT_FIRMWARE */
+ MAKNIB(0, 0), /* 0x09: */
+ MAKNIB(0, 0), /* 0x0a: */
+ MAKNIB(0, 0), /* 0x0b: */
+ MAKNIB(0, 0), /* 0x0c: */
+ MAKNIB(0, 0), /* 0x0d: */
+ MAKNIB(1, 2), /* 0x0e: MBOX_CHECK_FIRMWARE */
+ MAKNIB(0, 0), /* 0x0f: */
+ MAKNIB(5, 5), /* 0x10: MBOX_INIT_REQ_QUEUE */
+ MAKNIB(6, 6), /* 0x11: MBOX_INIT_RES_QUEUE */
+ MAKNIB(4, 4), /* 0x12: MBOX_EXECUTE_IOCB */
+ MAKNIB(2, 2), /* 0x13: MBOX_WAKE_UP */
+ MAKNIB(1, 6), /* 0x14: MBOX_STOP_FIRMWARE */
+ MAKNIB(4, 4), /* 0x15: MBOX_ABORT */
+ MAKNIB(2, 2), /* 0x16: MBOX_ABORT_DEVICE */
+ MAKNIB(3, 3), /* 0x17: MBOX_ABORT_TARGET */
+ MAKNIB(2, 2), /* 0x18: MBOX_BUS_RESET */
+ MAKNIB(2, 3), /* 0x19: MBOX_STOP_QUEUE */
+ MAKNIB(2, 3), /* 0x1a: MBOX_START_QUEUE */
+ MAKNIB(2, 3), /* 0x1b: MBOX_SINGLE_STEP_QUEUE */
+ MAKNIB(2, 3), /* 0x1c: MBOX_ABORT_QUEUE */
+ MAKNIB(2, 4), /* 0x1d: MBOX_GET_DEV_QUEUE_STATUS */
+ MAKNIB(0, 0), /* 0x1e: */
+ MAKNIB(1, 3), /* 0x1f: MBOX_GET_FIRMWARE_STATUS */
+ MAKNIB(1, 3), /* 0x20: MBOX_GET_INIT_SCSI_ID, MBOX_GET_LOOP_ID */
+ MAKNIB(1, 2), /* 0x21: MBOX_GET_SELECT_TIMEOUT */
+ MAKNIB(1, 3), /* 0x22: MBOX_GET_RETRY_COUNT */
+ MAKNIB(1, 2), /* 0x23: MBOX_GET_TAG_AGE_LIMIT */
+ MAKNIB(1, 2), /* 0x24: MBOX_GET_CLOCK_RATE */
+ MAKNIB(1, 2), /* 0x25: MBOX_GET_ACT_NEG_STATE */
+ MAKNIB(1, 2), /* 0x26: MBOX_GET_ASYNC_DATA_SETUP_TIME */
+ MAKNIB(1, 3), /* 0x27: MBOX_GET_PCI_PARAMS */
+ MAKNIB(2, 4), /* 0x28: MBOX_GET_TARGET_PARAMS */
+ MAKNIB(2, 4), /* 0x29: MBOX_GET_DEV_QUEUE_PARAMS */
+ MAKNIB(0, 0), /* 0x2a: */
+ MAKNIB(0, 0), /* 0x2b: */
+ MAKNIB(0, 0), /* 0x2c: */
+ MAKNIB(0, 0), /* 0x2d: */
+ MAKNIB(0, 0), /* 0x2e: */
+ MAKNIB(0, 0), /* 0x2f: */
+ MAKNIB(2, 2), /* 0x30: MBOX_SET_INIT_SCSI_ID */
+ MAKNIB(2, 2), /* 0x31: MBOX_SET_SELECT_TIMEOUT */
+ MAKNIB(3, 3), /* 0x32: MBOX_SET_RETRY_COUNT */
+ MAKNIB(2, 2), /* 0x33: MBOX_SET_TAG_AGE_LIMIT */
+ MAKNIB(2, 2), /* 0x34: MBOX_SET_CLOCK_RATE */
+ MAKNIB(2, 2), /* 0x35: MBOX_SET_ACTIVE_NEG_STATE */
+ MAKNIB(2, 2), /* 0x36: MBOX_SET_ASYNC_DATA_SETUP_TIME */
+ MAKNIB(3, 3), /* 0x37: MBOX_SET_PCI_CONTROL_PARAMS */
+ MAKNIB(4, 4), /* 0x38: MBOX_SET_TARGET_PARAMS */
+ MAKNIB(4, 4), /* 0x39: MBOX_SET_DEV_QUEUE_PARAMS */
+ MAKNIB(0, 0), /* 0x3a: */
+ MAKNIB(0, 0), /* 0x3b: */
+ MAKNIB(0, 0), /* 0x3c: */
+ MAKNIB(0, 0), /* 0x3d: */
+ MAKNIB(0, 0), /* 0x3e: */
+ MAKNIB(0, 0), /* 0x3f: */
+ MAKNIB(1, 2), /* 0x40: MBOX_RETURN_BIOS_BLOCK_ADDR */
+ MAKNIB(6, 1), /* 0x41: MBOX_WRITE_FOUR_RAM_WORDS */
+ MAKNIB(2, 3), /* 0x42: MBOX_EXEC_BIOS_IOCB */
+ MAKNIB(0, 0), /* 0x43: */
+ MAKNIB(0, 0), /* 0x44: */
+ MAKNIB(0, 0), /* 0x45: */
+ MAKNIB(0, 0), /* 0x46: */
+ MAKNIB(0, 0), /* 0x47: */
+ MAKNIB(0, 0), /* 0x48: */
+ MAKNIB(0, 0), /* 0x49: */
+ MAKNIB(2, 1), /* 0x4a: MBOX_SET_FIRMWARE_FEATURES */
+ MAKNIB(1, 2), /* 0x4b: MBOX_GET_FIRMWARE_FEATURES */
+ MAKNIB(0, 0), /* 0x4c: */
+ MAKNIB(0, 0), /* 0x4d: */
+ MAKNIB(0, 0), /* 0x4e: */
+ MAKNIB(0, 0), /* 0x4f: */
+ MAKNIB(0, 0), /* 0x50: */
+ MAKNIB(0, 0), /* 0x51: */
+ MAKNIB(0, 0), /* 0x52: */
+ MAKNIB(0, 0), /* 0x53: */
+ MAKNIB(8, 0), /* 0x54: MBOX_EXEC_COMMAND_IOCB_A64 */
+ MAKNIB(0, 0), /* 0x55: */
+ MAKNIB(0, 0), /* 0x56: */
+ MAKNIB(0, 0), /* 0x57: */
+ MAKNIB(0, 0), /* 0x58: */
+ MAKNIB(0, 0), /* 0x59: */
+ MAKNIB(0, 0), /* 0x5a: */
+ MAKNIB(0, 0), /* 0x5b: */
+ MAKNIB(0, 0), /* 0x5c: */
+ MAKNIB(0, 0), /* 0x5d: */
+ MAKNIB(0, 0), /* 0x5e: */
+ MAKNIB(0, 0), /* 0x5f: */
+ MAKNIB(8, 6), /* 0x60: MBOX_INIT_FIRMWARE */
+ MAKNIB(0, 0), /* 0x60: MBOX_GET_INIT_CONTROL_BLOCK (FORMAT?) */
+ MAKNIB(2, 1), /* 0x62: MBOX_INIT_LIP */
+ MAKNIB(8, 1), /* 0x63: MBOX_GET_FC_AL_POSITION_MAP */
+ MAKNIB(8, 1), /* 0x64: MBOX_GET_PORT_DB */
+ MAKNIB(3, 1), /* 0x65: MBOX_CLEAR_ACA */
+ MAKNIB(3, 1), /* 0x66: MBOX_TARGET_RESET */
+ MAKNIB(3, 1), /* 0x67: MBOX_CLEAR_TASK_SET */
+ MAKNIB(3, 1), /* 0x68: MBOX_ABORT_TASK_SET */
+ MAKNIB(1, 2), /* 0x69: MBOX_GET_FW_STATE */
+ MAKNIB(2, 8), /* 0x6a: MBOX_GET_PORT_NAME */
+ MAKNIB(8, 1), /* 0x6b: MBOX_GET_LINK_STATUS */
+ MAKNIB(4, 4), /* 0x6c: MBOX_INIT_LIP_RESET */
+ MAKNIB(0, 0), /* 0x6d: */
+ MAKNIB(0, 0), /* 0x6e: */
+ MAKNIB(0, 0), /* 0x6f: */
+ MAKNIB(0, 0), /* 0x70: */
+ MAKNIB(0, 0), /* 0x71: */
+ MAKNIB(4, 1) /* 0x72: MBOX_INIT_LIP_LOGIN */
};
#define NMBCOM (sizeof (mbpcnt) / sizeof (mbpcnt[0]))
-static int
+static void
isp_mboxcmd(isp, mbp)
struct ispsoftc *isp;
mbreg_t *mbp;
{
int outparam, inparam;
- int loops;
-
- if (mbp->param[0] > NMBCOM) {
- printf("%s: bad command %x\n", isp->isp_name, mbp->param[0]);
- return (-1);
+ int loops, dld = 0;
+ u_int8_t opcode;
+
+ if (mbp->param[0] == ISP2100_SET_PCI_PARAM) {
+ opcode = mbp->param[0] = MBOX_SET_PCI_PARAMETERS;
+ inparam = 4;
+ outparam = 4;
+ goto command_known;
+ } else if (mbp->param[0] > NMBCOM) {
+ PRINTF("%s: bad command %x\n", isp->isp_name, mbp->param[0]);
+ return;
}
+ opcode = mbp->param[0];
inparam = HINIB(mbpcnt[mbp->param[0]]);
outparam = LONIB(mbpcnt[mbp->param[0]]);
+
if (inparam == 0 && outparam == 0) {
- printf("%s: no parameters for %x\n", isp->isp_name,
+ PRINTF("%s: no parameters for %x\n", isp->isp_name,
mbp->param[0]);
- return (-1);
+ return;
}
+
+ /*
+ * Check for variants
+ */
+#ifdef ISP2100_SCCLUN
+ if (isp->isp_type & ISP_HA_FC) {
+ switch (mbp->param[0]) {
+ case MBOX_ABORT:
+ inparam = 7;
+ break;
+ case MBOX_ABORT_DEVICE:
+ case MBOX_START_QUEUE:
+ case MBOX_STOP_QUEUE:
+ case MBOX_SINGLE_STEP_QUEUE:
+ case MBOX_ABORT_QUEUE:
+ case MBOX_GET_DEV_QUEUE_STATUS:
+ inparam = 3;
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+
+command_known:
+
+#define NEW_MB_WAY 1
+#ifdef NEW_MB_WAY
/*
- * Make sure we can send some words..
+ * Set semaphore on mailbox registers to win any races to acquire them.
+ */
+ ISP_WRITE(isp, BIU_SEMA, 1);
+#endif
+
+
+ /*
+ * Make sure we can send some words. Check to see id there's
+ * an async mbox event pending.
*/
loops = MBOX_DELAY_COUNT;
while ((ISP_READ(isp, HCCR) & HCCR_HOST_INT) != 0) {
- delay(100);
+ SYS_DELAY(100);
+ if (ISP_READ(isp, BIU_SEMA) & 1) {
+ int fph;
+ u_int16_t mbox = ISP_READ(isp, OUTMAILBOX0);
+ /*
+ * We have a pending MBOX async event.
+ */
+ if (mbox & 0x8000) {
+ fph = isp_parse_async(isp, (int) mbox);
+ ISP_WRITE(isp, BIU_SEMA, 0);
+ ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT);
+ if (fph < 0) {
+ return;
+ } else if (fph > 0) {
+ isp_fastpost_complete(isp, fph);
+ }
+ SYS_DELAY(100);
+ goto command_known;
+ }
+ /*
+ * We have a pending MBOX completion? Might be
+ * from a previous command. We can't (sometimes)
+ * just clear HOST INTERRUPT, so we'll just silently
+ * eat this here.
+ */
+ if (mbox == MBOX_COMMAND_COMPLETE) {
+ ISP_WRITE(isp, BIU_SEMA, 0);
+ ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT);
+ SYS_DELAY(100);
+ goto command_known;
+ }
+ }
if (--loops < 0) {
- printf("%s: isp_mboxcmd timeout #1\n", isp->isp_name);
- return (-1);
+ if (dld++ > 10) {
+ PRINTF("%s: isp_mboxcmd could not get command "
+ "started\n", isp->isp_name);
+ return;
+ }
+ ISP_WRITE(isp, BIU_SEMA, 0);
+ ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT);
+ goto command_known;
}
}
/*
- * Write input parameters
+ * Write input parameters.
*/
switch (inparam) {
+ case 8: ISP_WRITE(isp, INMAILBOX7, mbp->param[7]); mbp->param[7] = 0;
+ case 7: ISP_WRITE(isp, INMAILBOX6, mbp->param[6]); mbp->param[6] = 0;
case 6: ISP_WRITE(isp, INMAILBOX5, mbp->param[5]); mbp->param[5] = 0;
case 5: ISP_WRITE(isp, INMAILBOX4, mbp->param[4]); mbp->param[4] = 0;
case 4: ISP_WRITE(isp, INMAILBOX3, mbp->param[3]); mbp->param[3] = 0;
@@ -964,29 +2978,35 @@ isp_mboxcmd(isp, mbp)
}
/*
- * Clear semaphore on mailbox registers
+ * Clear RISC int condition.
*/
- ISP_WRITE(isp, BIU_SEMA, 0);
+ ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT);
/*
- * Clear RISC int condition.
+ * Clear semaphore on mailbox registers so that the Qlogic
+ * may update outgoing registers.
*/
- ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT);
+ ISP_WRITE(isp, BIU_SEMA, 0);
+ ENABLE_INTS(isp);
/*
* Set Host Interrupt condition so that RISC will pick up mailbox regs.
*/
ISP_WRITE(isp, HCCR, HCCR_CMD_SET_HOST_INT);
+#ifndef NEW_MB_WAY
/*
- * Wait until RISC int is set
+ * Wait until RISC int is set, except 2100
*/
- loops = MBOX_DELAY_COUNT;
- while ((ISP_READ(isp, BIU_ISR) & BIU_ISR_RISC_INT) != 0) {
- delay(100);
- if (--loops < 0) {
- printf("%s: isp_mboxcmd timeout #2\n", isp->isp_name);
- return (-1);
+ if ((isp->isp_type & ISP_HA_FC) == 0) {
+ loops = MBOX_DELAY_COUNT;
+ while ((ISP_READ(isp, BIU_ISR) & BIU_ISR_RISC_INT) == 0) {
+ SYS_DELAY(100);
+ if (--loops < 0) {
+ PRINTF("%s: isp_mboxcmd timeout #2\n",
+ isp->isp_name);
+ return;
+ }
}
}
@@ -995,30 +3015,91 @@ isp_mboxcmd(isp, mbp)
*/
loops = MBOX_DELAY_COUNT;
while ((ISP_READ(isp, BIU_SEMA) & 1) == 0) {
- delay(100);
+ SYS_DELAY(100);
+ /*
+ * Wierd- I've seen the case where the semaphore register
+ * isn't getting set- sort of a violation of the protocol..
+ */
+ if (ISP_READ(isp, OUTMAILBOX0) & 0x4000)
+ break;
+ if (--loops < 0) {
+ PRINTF("%s: isp_mboxcmd timeout #3\n", isp->isp_name);
+ return;
+ }
+ }
+#else
+ /*
+ * Wait until HOST INT has gone away (meaning that the Qlogic
+ * has picked up the mailbox command. Wait a long time.
+ */
+ loops = MBOX_DELAY_COUNT * 5;
+ while ((ISP_READ(isp, HCCR) & HCCR_CMD_CLEAR_RISC_INT) != 0) {
+ SYS_DELAY(100);
if (--loops < 0) {
- printf("%s: isp_mboxcmd timeout #3\n", isp->isp_name);
- return (-1);
+ PRINTF("%s: isp_mboxcmd timeout #2\n", isp->isp_name);
+ return;
}
}
/*
- * Make sure that the MBOX_BUSY has gone away
+ * While the Semaphore registers isn't set, wait for the Qlogic
+ * to process the mailbox command. Again- wait a long time.
*/
- loops = MBOX_DELAY_COUNT;
- while (ISP_READ(isp, OUTMAILBOX0) == MBOX_BUSY) {
- delay(100);
+ loops = MBOX_DELAY_COUNT * 5;
+ while ((ISP_READ(isp, BIU_SEMA) & 1) == 0) {
+ SYS_DELAY(100);
+ /*
+ * Wierd- I've seen the case where the semaphore register
+ * isn't getting set- sort of a violation of the protocol..
+ */
+ if (ISP_READ(isp, OUTMAILBOX0) & 0x4000)
+ break;
if (--loops < 0) {
- printf("%s: isp_mboxcmd timeout #4\n", isp->isp_name);
- return (-1);
+ PRINTF("%s: isp_mboxcmd timeout #3\n", isp->isp_name);
+ return;
}
}
+#endif
+ /*
+ * Make sure that the MBOX_BUSY has gone away
+ */
+ loops = MBOX_DELAY_COUNT;
+ for (;;) {
+ u_int16_t mbox = ISP_READ(isp, OUTMAILBOX0);
+ if (mbox == MBOX_BUSY) {
+ if (--loops < 0) {
+ PRINTF("%s: isp_mboxcmd timeout #4\n",
+ isp->isp_name);
+ return;
+ }
+ SYS_DELAY(100);
+ continue;
+ }
+ /*
+ * We have a pending MBOX async event.
+ */
+ if (mbox & 0x8000) {
+ int fph = isp_parse_async(isp, (int) mbox);
+ ISP_WRITE(isp, BIU_SEMA, 0);
+ ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT);
+ if (fph < 0) {
+ return;
+ } else if (fph > 0) {
+ isp_fastpost_complete(isp, fph);
+ }
+ SYS_DELAY(100);
+ continue;
+ }
+ break;
+ }
/*
* Pick up output parameters.
*/
switch (outparam) {
+ case 8: mbp->param[7] = ISP_READ(isp, OUTMAILBOX7);
+ case 7: mbp->param[6] = ISP_READ(isp, OUTMAILBOX6);
case 6: mbp->param[5] = ISP_READ(isp, OUTMAILBOX5);
case 5: mbp->param[4] = ISP_READ(isp, OUTMAILBOX4);
case 4: mbp->param[3] = ISP_READ(isp, OUTMAILBOX3);
@@ -1036,33 +3117,778 @@ isp_mboxcmd(isp, mbp)
* Release semaphore on mailbox registers
*/
ISP_WRITE(isp, BIU_SEMA, 0);
- return (0);
+
+ /*
+ * Just to be chatty here...
+ */
+ switch(mbp->param[0]) {
+ case MBOX_COMMAND_COMPLETE:
+ break;
+ case MBOX_INVALID_COMMAND:
+ IDPRINTF(2, ("%s: mbox cmd %x failed with INVALID_COMMAND\n",
+ isp->isp_name, opcode));
+ break;
+ case MBOX_HOST_INTERFACE_ERROR:
+ PRINTF("%s: mbox cmd %x failed with HOST_INTERFACE_ERROR\n",
+ isp->isp_name, opcode);
+ break;
+ case MBOX_TEST_FAILED:
+ PRINTF("%s: mbox cmd %x failed with TEST_FAILED\n",
+ isp->isp_name, opcode);
+ break;
+ case MBOX_COMMAND_ERROR:
+ PRINTF("%s: mbox cmd %x failed with COMMAND_ERROR\n",
+ isp->isp_name, opcode);
+ break;
+ case MBOX_COMMAND_PARAM_ERROR:
+ switch (opcode) {
+ case MBOX_GET_PORT_DB:
+ case MBOX_GET_PORT_NAME:
+ case MBOX_GET_DEV_QUEUE_PARAMS:
+ break;
+ default:
+ PRINTF("%s: mbox cmd %x failed with "
+ "COMMAND_PARAM_ERROR\n", isp->isp_name, opcode);
+ }
+ break;
+
+ /*
+ * Be silent about these...
+ */
+
+ case ASYNC_LIP_OCCURRED:
+ case ASYNC_LOOP_UP:
+ case ASYNC_LOOP_DOWN:
+ case ASYNC_LOOP_RESET:
+ case ASYNC_CHANGE_NOTIFY:
+ break;
+ case ASYNC_PDB_CHANGED:
+ isp_mark_getpdb_all(isp);
+ break;
+
+ default:
+ /*
+ * The expected return of EXEC_FIRMWARE is zero.
+ */
+ if ((opcode == MBOX_EXEC_FIRMWARE && mbp->param[0] != 0) ||
+ (opcode != MBOX_EXEC_FIRMWARE)) {
+ PRINTF("%s: mbox cmd %x failed with error %x\n",
+ isp->isp_name, opcode, mbp->param[0]);
+ }
+ break;
+ }
}
-static void
-isp_lostcmd(struct ispsoftc *isp, struct scsi_xfer *xs)
+void
+isp_lostcmd(isp, xs)
+ struct ispsoftc *isp;
+ ISP_SCSI_XFER_T *xs;
{
mbreg_t mbs;
- mbs.param[0] = MBOX_GET_FIRMWARE_STATUS;
- (void) isp_mboxcmd(isp, &mbs);
+ mbs.param[0] = MBOX_GET_FIRMWARE_STATUS;
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- printf("%s: couldn't GET FIRMWARE STATUS\n", isp->isp_name);
+ isp_dumpregs(isp, "couldn't GET FIRMWARE STATUS");
return;
}
- printf("%s: lost command, %d commands active of total %d\n",
- isp->isp_name, mbs.param[1], mbs.param[2]);
- if (xs == NULL || xs->sc_link == NULL)
+ if (mbs.param[1]) {
+ PRINTF("%s: %d commands on completion queue\n",
+ isp->isp_name, mbs.param[1]);
+ }
+ if (XS_NULL(xs))
return;
mbs.param[0] = MBOX_GET_DEV_QUEUE_STATUS;
- mbs.param[1] = xs->sc_link->target << 8 | xs->sc_link->lun;
- (void) isp_mboxcmd(isp, &mbs);
+ mbs.param[1] = (XS_TGT(xs) << 8) | XS_LUN(xs);
+ isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- printf("%s: couldn't GET DEVICE STATUS\n", isp->isp_name);
+ isp_dumpregs(isp, "couldn't GET DEVICE QUEUE STATUS");
return;
}
- printf("%s: lost command, target %d lun %d, State: %x\n",
- isp->isp_name, mbs.param[1] >> 8, mbs.param[1] & 0x7,
- mbs.param[2] & 0xff);
+ PRINTF("%s: lost command for target %d lun %d, %d active of %d, "
+ "Queue State: %x\n", isp->isp_name, XS_TGT(xs),
+ XS_LUN(xs), mbs.param[2], mbs.param[3], mbs.param[1]);
+
+ isp_dumpregs(isp, "lost command");
+ /*
+ * XXX: Need to try and do something to recover.
+ */
+}
+
+static void
+isp_dumpregs(isp, msg)
+ struct ispsoftc *isp;
+ const char *msg;
+{
+ PRINTF("%s: %s\n", isp->isp_name, msg);
+ if (isp->isp_type & ISP_HA_SCSI)
+ PRINTF(" biu_conf1=%x", ISP_READ(isp, BIU_CONF1));
+ else
+ PRINTF(" biu_csr=%x", ISP_READ(isp, BIU2100_CSR));
+ PRINTF(" biu_icr=%x biu_isr=%x biu_sema=%x ", ISP_READ(isp, BIU_ICR),
+ ISP_READ(isp, BIU_ISR), ISP_READ(isp, BIU_SEMA));
+ PRINTF("risc_hccr=%x\n", ISP_READ(isp, HCCR));
+
+
+ if (isp->isp_type & ISP_HA_SCSI) {
+ ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE);
+ PRINTF(" cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n",
+ ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS),
+ ISP_READ(isp, CDMA_FIFO_STS));
+ PRINTF(" ddma_conf=%x ddma_sts=%x ddma_fifostat=%x\n",
+ ISP_READ(isp, DDMA_CONF), ISP_READ(isp, DDMA_STATUS),
+ ISP_READ(isp, DDMA_FIFO_STS));
+ PRINTF(" sxp_int=%x sxp_gross=%x sxp(scsi_ctrl)=%x\n",
+ ISP_READ(isp, SXP_INTERRUPT),
+ ISP_READ(isp, SXP_GROSS_ERR),
+ ISP_READ(isp, SXP_PINS_CONTROL));
+ ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE);
+ }
+ PRINTF(" mbox regs: %x %x %x %x %x\n",
+ ISP_READ(isp, OUTMAILBOX0), ISP_READ(isp, OUTMAILBOX1),
+ ISP_READ(isp, OUTMAILBOX2), ISP_READ(isp, OUTMAILBOX3),
+ ISP_READ(isp, OUTMAILBOX4));
+ ISP_DUMPREGS(isp);
+}
+
+static void
+isp_dumpxflist(isp)
+ struct ispsoftc *isp;
+{
+ volatile ISP_SCSI_XFER_T *xs;
+ int i, hdp;
+
+ for (hdp = i = 0; i < RQUEST_QUEUE_LEN; i++) {
+ xs = isp->isp_xflist[i];
+ if (xs == NULL) {
+ continue;
+ }
+ if (hdp == 0) {
+ PRINTF("%s: active requests\n", isp->isp_name);
+ hdp++;
+ }
+ PRINTF(" Active Handle %d: tgt %d lun %d dlen %d\n",
+ i+1, XS_TGT(xs), XS_LUN(xs), XS_XFRLEN(xs));
+ }
+}
+
+static void
+isp_fw_state(isp)
+ struct ispsoftc *isp;
+{
+ mbreg_t mbs;
+ if (isp->isp_type & ISP_HA_FC) {
+ int once = 0;
+ fcparam *fcp = isp->isp_param;
+again:
+ mbs.param[0] = MBOX_GET_FW_STATE;
+ isp_mboxcmd(isp, &mbs);
+ if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+ switch (mbs.param[0]) {
+ case ASYNC_PDB_CHANGED:
+ isp_mark_getpdb_all(isp);
+ /* FALL THROUGH */
+ case ASYNC_LIP_OCCURRED:
+ case ASYNC_LOOP_UP:
+ case ASYNC_LOOP_DOWN:
+ case ASYNC_LOOP_RESET:
+ case ASYNC_CHANGE_NOTIFY:
+ if (once++ < 2) {
+ goto again;
+ }
+ break;
+ }
+ isp_dumpregs(isp, "GET FIRMWARE STATE failed");
+ return;
+ }
+ fcp->isp_fwstate = mbs.param[1];
+ }
+}
+
+static void
+isp_update(isp)
+ struct ispsoftc *isp;
+{
+ int tgt;
+ mbreg_t mbs;
+ sdparam *sdp;
+
+ isp->isp_update = 0;
+
+ if (isp->isp_type & ISP_HA_FC) {
+ return;
+ }
+
+ sdp = isp->isp_param;
+ for (tgt = 0; tgt < MAX_TARGETS; tgt++) {
+ u_int16_t flags, period, offset, changed;
+ int get;
+
+ if (sdp->isp_devparam[tgt].dev_enable == 0) {
+ continue;
+ }
+
+ if (sdp->isp_devparam[tgt].dev_update) {
+ mbs.param[0] = MBOX_SET_TARGET_PARAMS;
+ mbs.param[2] = sdp->isp_devparam[tgt].dev_flags;
+ mbs.param[3] =
+ (sdp->isp_devparam[tgt].sync_offset << 8) |
+ (sdp->isp_devparam[tgt].sync_period);
+ sdp->isp_devparam[tgt].dev_update = 0;
+ sdp->isp_devparam[tgt].dev_refresh = 1;
+ isp->isp_update = 1;
+ get = 0;
+ } else if (sdp->isp_devparam[tgt].dev_refresh) {
+ mbs.param[0] = MBOX_GET_TARGET_PARAMS;
+ sdp->isp_devparam[tgt].dev_refresh = 0;
+ get = 1;
+ } else {
+ continue;
+ }
+ mbs.param[1] = tgt << 8;
+ isp_mboxcmd(isp, &mbs);
+ if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+ PRINTF("%s: failed to %cet SCSI parameters for "
+ "target %d\n", isp->isp_name, (get)? 'g' : 's',
+ tgt);
+ continue;
+ }
+
+ if (get == 0) {
+ /*
+ * XXX: Need a SYNC_TARGET for efficiency...
+ */
+ isp->isp_sendmarker = 1;
+ sdp->isp_devparam[tgt].cur_dflags =
+ sdp->isp_devparam[tgt].dev_flags;
+ continue;
+ }
+ flags = mbs.param[2];
+ period = mbs.param[3] & 0xff;
+ offset = mbs.param[3] >> 8;
+ if (sdp->isp_devparam[tgt].cur_dflags != flags ||
+ sdp->isp_devparam[tgt].sync_period != period ||
+ sdp->isp_devparam[tgt].sync_offset != offset) {
+ IDPRINTF(3, ("%s: tgt %d flags 0x%x period %d "
+ "off %d\n", isp->isp_name, tgt, flags,
+ period, offset));
+ changed = 1;
+ } else {
+ changed = 0;
+ }
+
+ sdp->isp_devparam[tgt].cur_dflags = flags;
+ sdp->isp_devparam[tgt].dev_flags = flags;
+ sdp->isp_devparam[tgt].sync_period = period;
+ sdp->isp_devparam[tgt].sync_offset = offset;
+ if (sdp->isp_devparam[tgt].dev_announced == 0 || changed) {
+ if (isp_async(isp, ISPASYNC_NEW_TGT_PARAMS, &tgt))
+ sdp->isp_devparam[tgt].dev_announced = 0;
+ else
+ sdp->isp_devparam[tgt].dev_announced = 1;
+ }
+ }
+}
+
+static void
+isp_setdfltparm(isp)
+ struct ispsoftc *isp;
+{
+ int i;
+ mbreg_t mbs;
+ sdparam *sdp;
+
+ /*
+ * Been there, done that, got the T-shirt...
+ */
+ if (isp->isp_gotdparms) {
+ IDPRINTF(3, ("%s: already have dparms\n", isp->isp_name));
+ return;
+ }
+ isp->isp_gotdparms = 1;
+
+ if ((isp->isp_confopts & ISP_CFG_NONVRAM) == 0 &&
+ (isp_read_nvram(isp) == 0)) {
+ return;
+ }
+ if (IS_FC(isp)) {
+ fcparam *fcp = (fcparam *) isp->isp_param;
+ fcp->isp_maxfrmlen = ICB_DFLT_FRMLEN;
+ fcp->isp_maxalloc = 256;
+ fcp->isp_execthrottle = 16;
+ fcp->isp_retry_delay = 5;
+ fcp->isp_retry_count = 0;
+ /*
+ * It would be nice to fake up a WWN in case we don't
+ * get one out of NVRAM. Solaris does this for SOCAL
+ * cards that don't have SBus properties- it sets up
+ * a WWN based upon the system MAC Address.
+ */
+ fcp->isp_wwn = 0;
+ return;
+ }
+
+ sdp = (sdparam *) isp->isp_param;
+ mbs.param[0] = MBOX_GET_ACT_NEG_STATE;
+ isp_mboxcmd(isp, &mbs);
+ if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+ IDPRINTF(2, ("could not GET ACT NEG STATE\n"));
+ sdp->isp_req_ack_active_neg = 1;
+ sdp->isp_data_line_active_neg = 1;
+ } else {
+ sdp->isp_req_ack_active_neg = (mbs.param[1] >> 4) & 0x1;
+ sdp->isp_data_line_active_neg = (mbs.param[1] >> 5) & 0x1;
+ }
+
+ for (i = 0; i < MAX_TARGETS; i++) {
+ sdp->isp_devparam[i].dev_flags = DPARM_DEFAULT;
+ sdp->isp_devparam[i].cur_dflags = DPARM_SAFE_DFLT;
+ if (isp->isp_type < ISP_HA_SCSI_1040 ||
+ (sdp->isp_clock && sdp->isp_clock < 60)) {
+ sdp->isp_devparam[i].sync_offset =
+ ISP_10M_SYNCPARMS >> 8;
+ sdp->isp_devparam[i].sync_period =
+ ISP_10M_SYNCPARMS & 0xff;
+ } else {
+ sdp->isp_devparam[i].sync_offset =
+ ISP_20M_SYNCPARMS >> 8;
+ sdp->isp_devparam[i].sync_period =
+ ISP_20M_SYNCPARMS & 0xff;
+ }
+
+ /*
+ * Don't get current target parameters if we've been
+ * told not to use NVRAM- it's really the same thing.
+ */
+ if (isp->isp_confopts & ISP_CFG_NONVRAM)
+ continue;
+
+ mbs.param[0] = MBOX_GET_TARGET_PARAMS;
+ mbs.param[1] = i << 8;
+ isp_mboxcmd(isp, &mbs);
+ if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+ continue;
+ }
+ sdp->isp_devparam[i].dev_flags = mbs.param[2];
+ /*
+ * The maximum period we can really see
+ * here is 100 (decimal), or 400 ns.
+ * For some unknown reason we sometimes
+ * get back wildass numbers from the
+ * boot device's parameters.
+ *
+ * XXX: Hmm- this may be based on a different
+ * XXX: clock rate.
+ */
+ if ((mbs.param[3] & 0xff) <= 0x64) {
+ sdp->isp_devparam[i].sync_period = mbs.param[3] & 0xff;
+ sdp->isp_devparam[i].sync_offset = mbs.param[3] >> 8;
+ }
+
+ /*
+ * It is not safe to run Ultra Mode with a clock < 60.
+ */
+ if (((sdp->isp_clock && sdp->isp_clock < 60) ||
+ (isp->isp_type < ISP_HA_SCSI_1020A)) &&
+ (sdp->isp_devparam[i].sync_period ==
+ (ISP_20M_SYNCPARMS & 0xff))) {
+ sdp->isp_devparam[i].sync_offset =
+ ISP_10M_SYNCPARMS >> 8;
+ sdp->isp_devparam[i].sync_period =
+ ISP_10M_SYNCPARMS & 0xff;
+ }
+ }
+
+ /*
+ * Set Default Host Adapter Parameters
+ */
+ sdp->isp_cmd_dma_burst_enable = 1;
+ sdp->isp_data_dma_burst_enabl = 1;
+ sdp->isp_fifo_threshold = 0;
+ sdp->isp_initiator_id = 7;
+ if (isp->isp_type >= ISP_HA_SCSI_1040) {
+ sdp->isp_async_data_setup = 9;
+ } else {
+ sdp->isp_async_data_setup = 6;
+ }
+ sdp->isp_selection_timeout = 250;
+ sdp->isp_max_queue_depth = 128;
+ sdp->isp_tag_aging = 8;
+ sdp->isp_bus_reset_delay = 3;
+ sdp->isp_retry_count = 0;
+ sdp->isp_retry_delay = 1;
+
+ for (i = 0; i < MAX_TARGETS; i++) {
+ sdp->isp_devparam[i].exc_throttle = 16;
+ sdp->isp_devparam[i].dev_enable = 1;
+ }
+}
+
+/*
+ * Re-initialize the ISP and complete all orphaned commands
+ * with a 'botched' notice.
+ *
+ * Locks held prior to coming here.
+ */
+
+void
+isp_restart(isp)
+ struct ispsoftc *isp;
+{
+ ISP_SCSI_XFER_T *tlist[RQUEST_QUEUE_LEN], *xs;
+ int i;
+
+ for (i = 0; i < RQUEST_QUEUE_LEN; i++) {
+ tlist[i] = (ISP_SCSI_XFER_T *) isp->isp_xflist[i];
+ isp->isp_xflist[i] = NULL;
+ }
+ isp_reset(isp);
+ if (isp->isp_state == ISP_RESETSTATE) {
+ isp_init(isp);
+ if (isp->isp_state == ISP_INITSTATE) {
+ isp->isp_state = ISP_RUNSTATE;
+ }
+ }
+ if (isp->isp_state != ISP_RUNSTATE) {
+ PRINTF("%s: isp_restart cannot restart ISP\n", isp->isp_name);
+ }
+
+ for (i = 0; i < RQUEST_QUEUE_LEN; i++) {
+ xs = tlist[i];
+ if (XS_NULL(xs)) {
+ continue;
+ }
+ if (isp->isp_nactive > 0)
+ isp->isp_nactive--;
+ XS_RESID(xs) = XS_XFRLEN(xs);
+ XS_SETERR(xs, HBA_BUSRESET);
+ XS_CMD_DONE(xs);
+ }
+}
+
+/*
+ * NVRAM Routines
+ */
+
+static int
+isp_read_nvram(isp)
+ struct ispsoftc *isp;
+{
+ int i, amt;
+ u_int8_t csum, minversion;
+ union {
+ u_int8_t _x[ISP2100_NVRAM_SIZE];
+ u_int16_t _s[ISP2100_NVRAM_SIZE>>1];
+ } _n;
+#define nvram_data _n._x
+#define nvram_words _n._s
+
+ if (IS_FC(isp)) {
+ amt = ISP2100_NVRAM_SIZE;
+ minversion = 1;
+ } else {
+ amt = ISP_NVRAM_SIZE;
+ 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++) {
+ 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) {
+ PRINTF("%s: invalid NVRAM header\n", isp->isp_name);
+ }
+ return (-1);
+ }
+ for (i = 2; i < amt>>1; i++) {
+ isp_rdnvram_word(isp, i, &nvram_words[i]);
+ }
+ for (csum = 0, i = 0; i < amt; i++) {
+ csum += nvram_data[i];
+ }
+ if (csum != 0) {
+ PRINTF("%s: invalid NVRAM checksum\n", isp->isp_name);
+ return (-1);
+ }
+ if (ISP_NVRAM_VERSION(nvram_data) < minversion) {
+ PRINTF("%s: version %d NVRAM not understood\n", isp->isp_name,
+ ISP_NVRAM_VERSION(nvram_data));
+ return (-1);
+ }
+
+ if (isp->isp_type & ISP_HA_SCSI) {
+ sdparam *sdp = (sdparam *) isp->isp_param;
+
+ sdp->isp_fifo_threshold =
+ ISP_NVRAM_FIFO_THRESHOLD(nvram_data) |
+ (ISP_NVRAM_FIFO_THRESHOLD_128(nvram_data) << 2);
+
+ sdp->isp_initiator_id =
+ ISP_NVRAM_INITIATOR_ID(nvram_data);
+
+ sdp->isp_bus_reset_delay =
+ ISP_NVRAM_BUS_RESET_DELAY(nvram_data);
+
+ sdp->isp_retry_count =
+ ISP_NVRAM_BUS_RETRY_COUNT(nvram_data);
+
+ sdp->isp_retry_delay =
+ ISP_NVRAM_BUS_RETRY_DELAY(nvram_data);
+
+ sdp->isp_async_data_setup =
+ ISP_NVRAM_ASYNC_DATA_SETUP_TIME(nvram_data);
+
+ if (isp->isp_type >= ISP_HA_SCSI_1040) {
+ if (sdp->isp_async_data_setup < 9) {
+ sdp->isp_async_data_setup = 9;
+ }
+ } else {
+ if (sdp->isp_async_data_setup != 6) {
+ sdp->isp_async_data_setup = 6;
+ }
+ }
+
+ sdp->isp_req_ack_active_neg =
+ ISP_NVRAM_REQ_ACK_ACTIVE_NEGATION(nvram_data);
+
+ sdp->isp_data_line_active_neg =
+ ISP_NVRAM_DATA_LINE_ACTIVE_NEGATION(nvram_data);
+
+ sdp->isp_data_dma_burst_enabl =
+ ISP_NVRAM_DATA_DMA_BURST_ENABLE(nvram_data);
+
+ sdp->isp_cmd_dma_burst_enable =
+ ISP_NVRAM_CMD_DMA_BURST_ENABLE(nvram_data);
+
+ sdp->isp_tag_aging =
+ ISP_NVRAM_TAG_AGE_LIMIT(nvram_data);
+
+ sdp->isp_selection_timeout =
+ ISP_NVRAM_SELECTION_TIMEOUT(nvram_data);
+
+ sdp->isp_max_queue_depth =
+ ISP_NVRAM_MAX_QUEUE_DEPTH(nvram_data);
+
+ sdp->isp_fast_mttr = ISP_NVRAM_FAST_MTTR_ENABLE(nvram_data);
+ if (isp->isp_dblev > 2) {
+ static char *true = "true";
+ static char *false = "false";
+ PRINTF("%s: NVRAM values:\n", isp->isp_name);
+ PRINTF(" Fifo Threshold = 0x%x\n",
+ sdp->isp_fifo_threshold);
+ PRINTF(" Bus Reset Delay = %d\n",
+ sdp->isp_bus_reset_delay);
+ PRINTF(" Retry Count = %d\n",
+ sdp->isp_retry_count);
+ PRINTF(" Retry Delay = %d\n",
+ sdp->isp_retry_delay);
+ PRINTF(" Tag Age Limit = %d\n",
+ sdp->isp_tag_aging);
+ PRINTF(" Selection Timeout = %d\n",
+ sdp->isp_selection_timeout);
+ PRINTF(" Max Queue Depth = %d\n",
+ sdp->isp_max_queue_depth);
+ PRINTF(" Async Data Setup = 0x%x\n",
+ sdp->isp_async_data_setup);
+ PRINTF(" REQ/ACK Active Negation = %s\n",
+ sdp->isp_req_ack_active_neg? true : false);
+ PRINTF(" Data Line Active Negation = %s\n",
+ sdp->isp_data_line_active_neg? true : false);
+ PRINTF(" Data DMA Burst Enable = %s\n",
+ sdp->isp_data_dma_burst_enabl? true : false);
+ PRINTF(" Cmd DMA Burst Enable = %s\n",
+ sdp->isp_cmd_dma_burst_enable? true : false);
+ PRINTF(" Fast MTTR = %s\n",
+ sdp->isp_fast_mttr? true : false);
+ }
+ for (i = 0; i < MAX_TARGETS; i++) {
+ sdp->isp_devparam[i].dev_enable =
+ ISP_NVRAM_TGT_DEVICE_ENABLE(nvram_data, i);
+ sdp->isp_devparam[i].exc_throttle =
+ ISP_NVRAM_TGT_EXEC_THROTTLE(nvram_data, i);
+ sdp->isp_devparam[i].sync_offset =
+ ISP_NVRAM_TGT_SYNC_OFFSET(nvram_data, i);
+ sdp->isp_devparam[i].sync_period =
+ ISP_NVRAM_TGT_SYNC_PERIOD(nvram_data, i);
+
+ if (isp->isp_type < ISP_HA_SCSI_1040) {
+ /*
+ * If we're not ultra, we can't possibly
+ * be a shorter period than this.
+ */
+ if (sdp->isp_devparam[i].sync_period < 0x19) {
+ sdp->isp_devparam[i].sync_period =
+ 0x19;
+ }
+ if (sdp->isp_devparam[i].sync_offset > 0xc) {
+ sdp->isp_devparam[i].sync_offset =
+ 0x0c;
+ }
+ } else {
+ if (sdp->isp_devparam[i].sync_offset > 0x8) {
+ sdp->isp_devparam[i].sync_offset = 0x8;
+ }
+ }
+ sdp->isp_devparam[i].dev_flags = 0;
+ if (ISP_NVRAM_TGT_RENEG(nvram_data, i))
+ sdp->isp_devparam[i].dev_flags |= DPARM_RENEG;
+ if (ISP_NVRAM_TGT_QFRZ(nvram_data, i)) {
+ PRINTF("%s: not supporting QFRZ option for "
+ "target %d\n", isp->isp_name, i);
+ }
+ sdp->isp_devparam[i].dev_flags |= DPARM_ARQ;
+ if (ISP_NVRAM_TGT_ARQ(nvram_data, i) == 0) {
+ PRINTF("%s: not disabling ARQ option for "
+ "target %d\n", isp->isp_name, i);
+ }
+ if (ISP_NVRAM_TGT_TQING(nvram_data, i))
+ sdp->isp_devparam[i].dev_flags |= DPARM_TQING;
+ if (ISP_NVRAM_TGT_SYNC(nvram_data, i))
+ sdp->isp_devparam[i].dev_flags |= DPARM_SYNC;
+ if (ISP_NVRAM_TGT_WIDE(nvram_data, i))
+ sdp->isp_devparam[i].dev_flags |= DPARM_WIDE;
+ if (ISP_NVRAM_TGT_PARITY(nvram_data, i))
+ sdp->isp_devparam[i].dev_flags |= DPARM_PARITY;
+ if (ISP_NVRAM_TGT_DISC(nvram_data, i))
+ sdp->isp_devparam[i].dev_flags |= DPARM_DISC;
+ if (isp->isp_dblev > 2) {
+ PRINTF(" Target %d: Enabled %d Throttle %d "
+ "Offset %d Period %d Flags 0x%x\n", i,
+ sdp->isp_devparam[i].dev_enable,
+ sdp->isp_devparam[i].exc_throttle,
+ sdp->isp_devparam[i].sync_offset,
+ sdp->isp_devparam[i].sync_period,
+ sdp->isp_devparam[i].dev_flags);
+ }
+ }
+ } else {
+ fcparam *fcp = (fcparam *) isp->isp_param;
+ union {
+ struct {
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int32_t hi32;
+ u_int32_t lo32;
+#else
+ u_int32_t lo32;
+ u_int32_t hi32;
+#endif
+ } wds;
+ u_int64_t full64;
+ } wwnstore;
+
+ wwnstore.full64 = ISP2100_NVRAM_NODE_NAME(nvram_data);
+ PRINTF("%s: Adapter WWN 0x%08x%08x\n", isp->isp_name,
+ wwnstore.wds.hi32, wwnstore.wds.lo32);
+ fcp->isp_wwn = wwnstore.full64;
+ wwnstore.full64 = ISP2100_NVRAM_BOOT_NODE_NAME(nvram_data);
+ if (wwnstore.full64 != 0) {
+ PRINTF("%s: BOOT DEVICE WWN 0x%08x%08x\n",
+ isp->isp_name, wwnstore.wds.hi32,
+ wwnstore.wds.lo32);
+ }
+ fcp->isp_maxalloc =
+ ISP2100_NVRAM_MAXIOCBALLOCATION(nvram_data);
+ 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);
+ fcp->isp_loopid =
+ ISP2100_NVRAM_HARDLOOPID(nvram_data);
+ fcp->isp_execthrottle =
+ ISP2100_NVRAM_EXECUTION_THROTTLE(nvram_data);
+ fcp->isp_fwoptions = ISP2100_NVRAM_OPTIONS(nvram_data);
+ if (isp->isp_dblev > 2) {
+ PRINTF("%s: NVRAM values:\n", isp->isp_name);
+ PRINTF(" Max IOCB Allocation = %d\n",
+ fcp->isp_maxalloc);
+ PRINTF(" Max Frame Length = %d\n",
+ fcp->isp_maxfrmlen);
+ PRINTF(" Execution Throttle = %d\n",
+ fcp->isp_execthrottle);
+ PRINTF(" Retry Count = %d\n",
+ fcp->isp_retry_count);
+ PRINTF(" Retry Delay = %d\n",
+ fcp->isp_retry_delay);
+ PRINTF(" Hard Loop ID = %d\n",
+ fcp->isp_loopid);
+ PRINTF(" Options = 0x%x\n",
+ fcp->isp_fwoptions);
+ PRINTF(" HBA Options = 0x%x\n",
+ ISP2100_NVRAM_HBA_OPTIONS(nvram_data));
+ }
+ }
+ IDPRINTF(3, ("%s: NVRAM is valid\n", isp->isp_name));
+ return (0);
+}
+
+static void
+isp_rdnvram_word(isp, wo, rp)
+ struct ispsoftc *isp;
+ int wo;
+ u_int16_t *rp;
+{
+ int i, cbits;
+ u_int16_t bit, rqst;
+
+ ISP_WRITE(isp, BIU_NVRAM, BIU_NVRAM_SELECT);
+ SYS_DELAY(2);
+ ISP_WRITE(isp, BIU_NVRAM, BIU_NVRAM_SELECT|BIU_NVRAM_CLOCK);
+ SYS_DELAY(2);
+
+ if (isp->isp_type & ISP_HA_FC) {
+ wo &= ((ISP2100_NVRAM_SIZE >> 1) - 1);
+ rqst = (ISP_NVRAM_READ << 8) | wo;
+ cbits = 10;
+ } else {
+ wo &= ((ISP_NVRAM_SIZE >> 1) - 1);
+ rqst = (ISP_NVRAM_READ << 6) | wo;
+ cbits = 8;
+ }
+
+ /*
+ * Clock the word select request out...
+ */
+ for (i = cbits; i >= 0; i--) {
+ if ((rqst >> i) & 1) {
+ bit = BIU_NVRAM_SELECT | BIU_NVRAM_DATAOUT;
+ } else {
+ bit = BIU_NVRAM_SELECT;
+ }
+ ISP_WRITE(isp, BIU_NVRAM, bit);
+ SYS_DELAY(2);
+ ISP_WRITE(isp, BIU_NVRAM, bit | BIU_NVRAM_CLOCK);
+ SYS_DELAY(2);
+ ISP_WRITE(isp, BIU_NVRAM, bit);
+ SYS_DELAY(2);
+ }
+ /*
+ * Now read the result back in (bits come back in MSB format).
+ */
+ *rp = 0;
+ for (i = 0; i < 16; i++) {
+ u_int16_t rv;
+ *rp <<= 1;
+ ISP_WRITE(isp, BIU_NVRAM, BIU_NVRAM_SELECT|BIU_NVRAM_CLOCK);
+ SYS_DELAY(2);
+ rv = ISP_READ(isp, BIU_NVRAM);
+ if (rv & BIU_NVRAM_DATAIN) {
+ *rp |= 1;
+ }
+ SYS_DELAY(2);
+ ISP_WRITE(isp, BIU_NVRAM, BIU_NVRAM_SELECT);
+ SYS_DELAY(2);
+ }
+ ISP_WRITE(isp, BIU_NVRAM, 0);
+ SYS_DELAY(2);
+#if BYTE_ORDER == BIG_ENDIAN
+ *rp = ((*rp >> 8) | ((*rp & 0xff) << 8));
+#endif
}
diff --git a/sys/dev/ic/isp_openbsd.c b/sys/dev/ic/isp_openbsd.c
new file mode 100644
index 00000000000..cf83909bccc
--- /dev/null
+++ b/sys/dev/ic/isp_openbsd.c
@@ -0,0 +1,438 @@
+/* $OpenBSD: isp_openbsd.c,v 1.1 1999/03/17 05:26:09 mjacob Exp $ */
+/* release_03_16_99 */
+/*
+ * Platform (OpenBSD) dependent common attachment code for Qlogic adapters.
+ *
+ *---------------------------------------
+ * Copyright (c) 1997, 1998, 1999 by Matthew Jacob
+ * NASA/Ames Research Center
+ * 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. 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.
+ * 3. 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.
+ *
+ * The author may be reached via electronic communications at
+ *
+ * mjacob@nas.nasa.gov
+ * mjacob@feral.com
+ *
+ * or, via United States Postal Address
+ *
+ * Matthew Jacob
+ * Feral Software
+ * 2339 3rd Street
+ * Suite 24
+ * San Francisco, CA, 94107
+ */
+
+#include <dev/ic/isp_openbsd.h>
+
+static void ispminphys __P((struct buf *));
+static int32_t ispcmd __P((ISP_SCSI_XFER_T *));
+
+static struct scsi_device isp_dev = { NULL, NULL, NULL, NULL };
+static int isp_poll __P((struct ispsoftc *, ISP_SCSI_XFER_T *, int));
+static void isp_watch __P((void *));
+
+struct cfdriver isp_cd = {
+ NULL, "isp", DV_DULL
+};
+
+
+#define FC_OPENINGS RQUEST_QUEUE_LEN / (MAX_FC_TARG-1)
+#define PI_OPENINGS RQUEST_QUEUE_LEN / (MAX_TARGETS-1)
+
+/*
+ * Complete attachment of hardware, include subdevices.
+ */
+void
+isp_attach(isp)
+ struct ispsoftc *isp;
+{
+ isp->isp_osinfo._adapter.scsi_cmd = ispcmd;
+ isp->isp_osinfo._adapter.scsi_minphys = ispminphys;
+
+ isp->isp_state = ISP_RUNSTATE;
+ /*
+ * OpenBSD will lose on the 1240 support because you don't
+ * get multiple SCSI busses per adapter instance.
+ */
+#if 0
+ isp->isp_osinfo._link.channel = SCSI_CHANNEL_ONLY_ONE;
+#endif
+ isp->isp_osinfo._link.adapter_softc = isp;
+ isp->isp_osinfo._link.device = &isp_dev;
+ isp->isp_osinfo._link.adapter = &isp->isp_osinfo._adapter;
+
+ if (isp->isp_type & ISP_HA_FC) {
+ isp->isp_osinfo._link.openings = FC_OPENINGS;
+ isp->isp_osinfo._link.adapter_buswidth = MAX_FC_TARG;
+ /* We can set max lun width here */
+ isp->isp_osinfo._link.adapter_target =
+ ((fcparam *)isp->isp_param)->isp_loopid;
+ } else {
+ isp->isp_osinfo._link.openings = PI_OPENINGS;
+ isp->isp_osinfo._link.adapter_buswidth = MAX_TARGETS;
+ /* We can set max lun width here */
+ isp->isp_osinfo._link.adapter_target =
+ ((sdparam *)isp->isp_param)->isp_initiator_id;
+ }
+ if (isp->isp_osinfo._link.openings < 2)
+ isp->isp_osinfo._link.openings = 2;
+
+ /*
+ * Send a SCSI Bus Reset (used to be done as part of attach,
+ * but now left to the OS outer layers).
+ *
+ * XXX: For now, skip resets for FC because the method by which
+ * XXX: we deal with loop down after issuing resets (which causes
+ * XXX: port logouts for all devices) needs interrupts to run so
+ * XXX: that async events happen.
+ */
+ if (IS_SCSI(isp)) {
+ (void) isp_control(isp, ISPCTL_RESET_BUS, NULL);
+ /*
+ * Wait for it to settle.
+ */
+ delay(2 * 1000000);
+ }
+
+ /*
+ * Start the watchdog.
+ *
+ * The wathdog will, ridiculously enough, also enable Sync negotiation.
+ */
+ isp->isp_dogactive = 1;
+ timeout(isp_watch, isp, 30 * hz);
+
+ /*
+ * And attach children (if any).
+ */
+ config_found((void *)isp, &isp->isp_osinfo._link, scsiprint);
+}
+
+/*
+ * minphys our xfers
+ *
+ * Unfortunately, the buffer pointer describes the target device- not the
+ * adapter device, so we can't use the pointer to find out what kind of
+ * adapter we are and adjust accordingly.
+ */
+
+static void
+ispminphys(bp)
+ struct buf *bp;
+{
+ /*
+ * XX: Only the 1020 has a 24 bit limit.
+ */
+ if (bp->b_bcount >= (1 << 24)) {
+ bp->b_bcount = (1 << 24);
+ }
+ minphys(bp);
+}
+
+static int
+ispcmd(xs)
+ ISP_SCSI_XFER_T *xs;
+{
+ struct ispsoftc *isp;
+ int result;
+ int s;
+
+ isp = xs->sc_link->adapter_softc;
+ s = splbio();
+
+ if (isp->isp_state < ISP_RUNSTATE) {
+ DISABLE_INTS(isp);
+ isp_init(isp);
+ if (isp->isp_state != ISP_INITSTATE) {
+ ENABLE_INTS(isp);
+ (void) splx(s);
+ XS_SETERR(xs, HBA_BOTCH);
+ return (CMD_COMPLETE);
+ }
+ isp->isp_state = ISP_RUNSTATE;
+ ENABLE_INTS(isp);
+ }
+ DISABLE_INTS(isp);
+ result = ispscsicmd(xs);
+ ENABLE_INTS(isp);
+ if (result != CMD_QUEUED || (xs->flags & SCSI_POLL) == 0) {
+ (void) splx(s);
+ return (result);
+ }
+
+ /*
+ * If we can't use interrupts, poll on completion.
+ */
+ if (isp_poll(isp, xs, xs->timeout)) {
+ /*
+ * If no other error occurred but we didn't finish,
+ * something bad happened.
+ */
+ if ((xs->flags & ITSDONE) == 0) {
+ isp->isp_nactive--;
+ if (isp->isp_nactive < 0)
+ isp->isp_nactive = 0;
+ if (xs->error == XS_NOERROR) {
+ isp_lostcmd(isp, xs);
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ }
+ }
+ (void) splx(s);
+ return (COMPLETE);
+}
+
+static int
+isp_poll(isp, xs, mswait)
+ struct ispsoftc *isp;
+ ISP_SCSI_XFER_T *xs;
+ int mswait;
+{
+
+ while (mswait) {
+ /* Try the interrupt handling routine */
+ (void)isp_intr((void *)isp);
+
+ /* See if the xs is now done */
+ if (XS_IS_CMD_DONE(xs)) {
+ return (0);
+ }
+ delay(1000); /* wait one millisecond */
+ mswait--;
+ }
+ return (1);
+}
+
+#define DTHR 2
+
+static void
+isp_watch(arg)
+ void *arg;
+{
+ static int delay_throttle_count = DTHR;
+ int i;
+ struct ispsoftc *isp = arg;
+ ISP_SCSI_XFER_T *xs;
+ int s = splbio();
+
+ /*
+ * Look for completely dead commands.
+ */
+ for (i = 0; i < RQUEST_QUEUE_LEN; i++) {
+ if ((xs = (ISP_SCSI_XFER_T *) isp->isp_xflist[i]) == NULL) {
+ continue;
+ }
+ if (XS_TIME(xs) == 0) {
+ continue;
+ }
+ XS_TIME(xs) -= (WATCH_INTERVAL * 1000);
+ /*
+ * Avoid later thinking that this
+ * transaction is not being timed.
+ * Then give ourselves to watchdog
+ * periods of grace.
+ */
+ if (xs->timeout == 0) {
+ xs->timeout = 1;
+ } else if (xs->timeout > -(2 * WATCH_INTERVAL * 1000)) {
+ continue;
+ }
+ delay_throttle_count = DTHR;
+ if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) {
+ printf("%s: isp_watch failed to abort command\n",
+ isp->isp_name);
+ isp_restart(isp);
+ break;
+ }
+ }
+
+ if (delay_throttle_count) {
+ if (--delay_throttle_count == 0) {
+ sdparam *sdp = isp->isp_param;
+ for (i = 0; i < MAX_TARGETS; i++) {
+ sdp->isp_devparam[i].dev_flags |=
+ DPARM_WIDE|DPARM_SYNC|DPARM_TQING;
+ sdp->isp_devparam[i].dev_update = 1;
+ }
+ isp->isp_update = 1;
+ }
+ }
+ timeout(isp_watch, isp, WATCH_INTERVAL * hz);
+ isp->isp_dogactive = 1;
+ (void) splx(s);
+}
+
+/*
+ * Free any associated resources prior to decommissioning and
+ * set the card to a known state (so it doesn't wake up and kick
+ * us when we aren't expecting it to).
+ *
+ * Locks are held before coming here.
+ */
+void
+isp_uninit(isp)
+ struct ispsoftc *isp;
+{
+ int s = splbio();
+ /*
+ * Leave with interrupts disabled.
+ */
+ DISABLE_INTS(isp);
+
+ /*
+ * Turn off the watchdog (if active).
+ */
+ if (isp->isp_dogactive) {
+ untimeout(isp_watch, isp);
+ isp->isp_dogactive = 0;
+ }
+
+ splx(s);
+}
+
+int
+isp_async(isp, cmd, arg)
+ struct ispsoftc *isp;
+ ispasync_t cmd;
+ void *arg;
+{
+ int s = splbio();
+ switch (cmd) {
+ case ISPASYNC_NEW_TGT_PARAMS:
+ if (IS_SCSI(isp)) {
+ sdparam *sdp = isp->isp_param;
+ char *wt;
+ int ns, flags, tgt;
+
+ tgt = *((int *) arg);
+
+ flags = sdp->isp_devparam[tgt].dev_flags;
+ if (flags & DPARM_SYNC) {
+ ns = sdp->isp_devparam[tgt].sync_period * 4;
+ } else {
+ ns = 0;
+ }
+ switch (flags & (DPARM_WIDE|DPARM_TQING)) {
+ case DPARM_WIDE:
+ wt = ", 16 bit wide\n";
+ break;
+ case DPARM_TQING:
+ wt = ", Tagged Queueing Enabled\n";
+ break;
+ case DPARM_WIDE|DPARM_TQING:
+ wt = ", 16 bit wide, Tagged Queueing Enabled\n";
+ break;
+ default:
+ wt = "\n";
+ break;
+ }
+ if (ns) {
+ printf("%s: Target %d at %dMHz Max Offset %d%s",
+ isp->isp_name, tgt, 1000 / ns,
+ sdp->isp_devparam[tgt].sync_offset, wt);
+ } else {
+ printf("%s: Target %d Async Mode%s",
+ isp->isp_name, tgt, wt);
+ }
+ }
+ break;
+ case ISPASYNC_BUS_RESET:
+ printf("%s: SCSI bus reset detected\n", isp->isp_name);
+ break;
+ case ISPASYNC_LOOP_DOWN:
+ printf("%s: Loop DOWN\n", isp->isp_name);
+ break;
+ case ISPASYNC_LOOP_UP:
+ printf("%s: Loop UP\n", isp->isp_name);
+ break;
+ case ISPASYNC_PDB_CHANGE_COMPLETE:
+#if 0
+ if (isp->isp_type & ISP_HA_FC) {
+ int i;
+ static char *roles[4] = {
+ "No", "Target", "Initiator", "Target/Initiator"
+ };
+ for (i = 0; i < MAX_FC_TARG; i++) {
+ isp_pdb_t *pdbp =
+ &((fcparam *)isp->isp_param)->isp_pdb[i];
+ if (pdbp->pdb_options == INVALID_PDB_OPTIONS)
+ continue;
+ printf("%s: Loop ID %d, %s role\n",
+ isp->isp_name, pdbp->pdb_loopid,
+ roles[(pdbp->pdb_prli_svc3 >> 4) & 0x3]);
+ printf(" Node Address 0x%x WWN 0x"
+ "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ BITS2WORD(pdbp->pdb_portid_bits),
+ pdbp->pdb_portname[0], pdbp->pdb_portname[1],
+ pdbp->pdb_portname[2], pdbp->pdb_portname[3],
+ pdbp->pdb_portname[4], pdbp->pdb_portname[5],
+ pdbp->pdb_portname[6], pdbp->pdb_portname[7]);
+ if (pdbp->pdb_options & PDB_OPTIONS_ADISC)
+ printf(" Hard Address 0x%x WWN 0x"
+ "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ BITS2WORD(pdbp->pdb_hardaddr_bits),
+ pdbp->pdb_nodename[0],
+ pdbp->pdb_nodename[1],
+ pdbp->pdb_nodename[2],
+ pdbp->pdb_nodename[3],
+ pdbp->pdb_nodename[4],
+ pdbp->pdb_nodename[5],
+ pdbp->pdb_nodename[6],
+ pdbp->pdb_nodename[7]);
+ switch (pdbp->pdb_prli_svc3 & SVC3_ROLE_MASK) {
+ case SVC3_TGT_ROLE|SVC3_INI_ROLE:
+ printf(" Master State=%s, Slave State=%s\n",
+ isp2100_pdb_statename(pdbp->pdb_mstate),
+ isp2100_pdb_statename(pdbp->pdb_sstate));
+ break;
+ case SVC3_TGT_ROLE:
+ printf(" Master State=%s\n",
+ isp2100_pdb_statename(pdbp->pdb_mstate));
+ break;
+ case SVC3_INI_ROLE:
+ printf(" Slave State=%s\n",
+ isp2100_pdb_statename(pdbp->pdb_sstate));
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+#else
+ break;
+#endif
+ case ISPASYNC_CHANGE_NOTIFY:
+ printf("%s: Name Server Database Changed\n", isp->isp_name);
+ break;
+ default:
+ break;
+ }
+ (void) splx(s);
+ return (0);
+}
diff --git a/sys/dev/ic/isp_openbsd.h b/sys/dev/ic/isp_openbsd.h
new file mode 100644
index 00000000000..03e1d29cffa
--- /dev/null
+++ b/sys/dev/ic/isp_openbsd.h
@@ -0,0 +1,274 @@
+/* $OpenBSD: isp_openbsd.h,v 1.1 1999/03/17 05:26:09 mjacob Exp $ */
+/* release_03_16_99 */
+/*
+ * OpenBSD Specific definitions for the Qlogic ISP Host Adapter
+ *
+ *---------------------------------------
+ * Copyright (c) 1997, 1998, 1999 by Matthew Jacob
+ * NASA/Ames Research Center
+ * 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. 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.
+ * 3. 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.
+ *
+ */
+
+#ifndef _ISP_OPENBSD_H
+#define _ISP_OPENBSD_H
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <scsi/scsi_message.h>
+#include <scsi/scsi_debug.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+#define ISP_PLATFORM_VERSION_MAJOR 0
+#define ISP_PLATFORM_VERSION_MINOR 1
+
+#define ISP_SCSI_XFER_T struct scsi_xfer
+struct isposinfo {
+ struct device _dev;
+ struct scsi_link _link;
+ struct scsi_adapter _adapter;
+};
+
+#define MAXISPREQUEST 64
+
+#include <dev/ic/ispreg.h>
+#include <dev/ic/ispvar.h>
+#include <dev/ic/ispmbox.h>
+
+#define PRINTF printf
+#define IDPRINTF(lev, x) if (isp->isp_dblev >= lev) printf x
+
+#define MEMZERO bzero
+#define MEMCPY(dst, src, count) bcopy((src), (dst), (count))
+
+#ifdef __alpha__
+#define MemoryBarrier alpha_mb
+#else
+#define MemoryBarrier()
+#endif
+
+#if defined(SCSIDEBUG)
+#define DFLT_DBLEVEL 3
+#else
+#if defined(DEBUG)
+#define DFLT_DBLEVEL 2
+#else
+#define DFLT_DBLEVEL 1
+#endif
+#endif
+
+#define ISP_LOCKVAL_DECL int isp_spl_save
+#define ISP_ILOCKVAL_DECL ISP_LOCKVAL_DECL
+#define ISP_LOCK(x) isp_spl_save = splbio()
+#define ISP_UNLOCK(x) (void) splx(isp_spl_save)
+#define ISP_ILOCK ISP_LOCK
+#define ISP_IUNLOCK ISP_UNLOCK
+
+
+#define XS_NULL(xs) xs == NULL || xs->sc_link == NULL
+#define XS_ISP(xs) (xs)->sc_link->adapter_softc
+#define XS_LUN(xs) ((int) (xs)->sc_link->lun)
+#define XS_TGT(xs) ((int) (xs)->sc_link->target)
+#define XS_RESID(xs) (xs)->resid
+#define XS_XFRLEN(xs) (xs)->datalen
+#define XS_CDBLEN(xs) (xs)->cmdlen
+#define XS_CDBP(xs) (xs)->cmd
+#define XS_STS(xs) (xs)->status
+#define XS_TIME(xs) (xs)->timeout
+#define XS_SNSP(xs) (&(xs)->sense)
+#define XS_SNSLEN(xs) (sizeof (xs)->sense)
+#define XS_SNSKEY(xs) ((xs)->sense.flags)
+
+#define HBA_NOERROR XS_NOERROR
+#define HBA_BOTCH XS_DRIVER_STUFFUP
+#define HBA_CMDTIMEOUT XS_TIMEOUT
+#define HBA_SELTIMEOUT XS_SELTIMEOUT
+#define HBA_TGTBSY XS_BUSY
+#ifdef XS_RESET
+#define HBA_BUSRESET XS_RESET
+#else
+#define HBA_BUSRESET XS_DRIVER_STUFFUP
+#endif
+#define HBA_ABORTED XS_DRIVER_STUFFUP
+#define HBA_DATAOVR XS_DRIVER_STUFFUP
+#define HBA_ARQFAIL XS_DRIVER_STUFFUP
+
+#define XS_SNS_IS_VALID(xs) (xs)->error = XS_SENSE
+#define XS_IS_SNS_VALID(xs) ((xs)->error == XS_SENSE)
+
+#define XS_INITERR(xs) (xs)->error = 0
+#define XS_SETERR(xs, v) (xs)->error = v
+#define XS_ERR(xs) (xs)->error
+#define XS_NOERR(xs) (xs)->error == XS_NOERROR
+
+#define XS_CMD_DONE(xs) (xs)->flags |= ITSDONE, scsi_done(xs)
+#define XS_IS_CMD_DONE(xs) (((xs)->flags & ITSDONE) != 0)
+
+/*
+ * We use whether or not we're a polled command to decide about tagging.
+ */
+#define XS_CANTAG(xs) (((xs)->flags & SCSI_POLL) != 0)
+
+/*
+ * This is our default tag (ordered).
+ */
+#define XS_KINDOF_TAG(xs) REQFLAG_STAG
+
+#define CMD_COMPLETE COMPLETE
+#define CMD_EAGAIN TRY_AGAIN_LATER
+#define CMD_QUEUED SUCCESSFULLY_QUEUED
+
+#define isp_name isp_osinfo._dev.dv_xname
+
+#define FC_FW_READY_DELAY (12 * 1000000)
+
+#define SYS_DELAY(x) delay(x)
+
+#define WATCH_INTERVAL 30
+
+extern void isp_attach __P((struct ispsoftc *));
+extern void isp_uninit __P((struct ispsoftc *));
+
+static inline void isp_prtstst __P((ispstatusreq_t *));
+static inline const char *isp2100_fw_statename __P((int));
+static inline const char * isp2100_pdb_statename __P((int));
+
+static inline void
+isp_prtstst(sp)
+ ispstatusreq_t *sp;
+{
+ char buf[128];
+ sprintf(buf, "states->");
+ if (sp->req_state_flags & RQSF_GOT_BUS)
+ sprintf(buf, "%s%s", buf, "GOT_BUS ");
+ if (sp->req_state_flags & RQSF_GOT_TARGET)
+ sprintf(buf, "%s%s", buf, "GOT_TGT ");
+ if (sp->req_state_flags & RQSF_SENT_CDB)
+ sprintf(buf, "%s%s", buf, "SENT_CDB ");
+ if (sp->req_state_flags & RQSF_XFRD_DATA)
+ sprintf(buf, "%s%s", buf, "XFRD_DATA ");
+ if (sp->req_state_flags & RQSF_GOT_STATUS)
+ sprintf(buf, "%s%s", buf, "GOT_STS ");
+ if (sp->req_state_flags & RQSF_GOT_SENSE)
+ sprintf(buf, "%s%s", buf, "GOT_SNS ");
+ if (sp->req_state_flags & RQSF_XFER_COMPLETE)
+ sprintf(buf, "%s%s", buf, "XFR_CMPLT ");
+ sprintf(buf, "%s%s", buf, "\n");
+ sprintf(buf, "%s%s", buf, "status->");
+ if (sp->req_status_flags & RQSTF_DISCONNECT)
+ sprintf(buf, "%s%s", buf, "Disconnect ");
+ if (sp->req_status_flags & RQSTF_SYNCHRONOUS)
+ sprintf(buf, "%s%s", buf, "Sync_xfr ");
+ if (sp->req_status_flags & RQSTF_PARITY_ERROR)
+ sprintf(buf, "%s%s", buf, "Parity ");
+ if (sp->req_status_flags & RQSTF_BUS_RESET)
+ sprintf(buf, "%s%s", buf, "Bus_Reset ");
+ if (sp->req_status_flags & RQSTF_DEVICE_RESET)
+ sprintf(buf, "%s%s", buf, "Device_Reset ");
+ if (sp->req_status_flags & RQSTF_ABORTED)
+ sprintf(buf, "%s%s", buf, "Aborted ");
+ if (sp->req_status_flags & RQSTF_TIMEOUT)
+ sprintf(buf, "%s%s", buf, "Timeout ");
+ if (sp->req_status_flags & RQSTF_NEGOTIATION)
+ sprintf(buf, "%s%s", buf, "Negotiation ");
+ sprintf(buf, "%s%s", buf, "\n");
+ printf(buf);
+}
+
+static inline const char *
+isp2100_fw_statename(state)
+ int state;
+{
+ static char buf[16];
+ switch(state) {
+ case FW_CONFIG_WAIT: return "Config Wait";
+ case FW_WAIT_AL_PA: return "Waiting for AL_PA";
+ case FW_WAIT_LOGIN: return "Wait Login";
+ case FW_READY: return "Ready";
+ case FW_LOSS_OF_SYNC: return "Loss Of Sync";
+ case FW_ERROR: return "Error";
+ case FW_REINIT: return "Re-Init";
+ case FW_NON_PART: return "Non-Participating";
+ default:
+ sprintf(buf, "0x%x", state);
+ return buf;
+ }
+}
+
+static inline const char *
+isp2100_pdb_statename(pdb_state)
+ int pdb_state;
+{
+ static char buf[16];
+ switch(pdb_state) {
+ case PDB_STATE_DISCOVERY: return "Port Discovery";
+ case PDB_STATE_WDISC_ACK: return "Waiting Port Discovery ACK";
+ case PDB_STATE_PLOGI: return "Port Login";
+ case PDB_STATE_PLOGI_ACK: return "Wait Port Login ACK";
+ case PDB_STATE_PRLI: return "Process Login";
+ case PDB_STATE_PRLI_ACK: return "Wait Process Login ACK";
+ case PDB_STATE_LOGGED_IN: return "Logged In";
+ case PDB_STATE_PORT_UNAVAIL: return "Port Unavailable";
+ case PDB_STATE_PRLO: return "Process Logout";
+ case PDB_STATE_PRLO_ACK: return "Wait Process Logout ACK";
+ case PDB_STATE_PLOGO: return "Port Logout";
+ case PDB_STATE_PLOG_ACK: return "Wait Port Logout ACK";
+ default:
+ sprintf(buf, "0x%x", pdb_state);
+ return buf;
+ }
+}
+
+/*
+ * Keep these off for now...
+ */
+
+#define ISP_NO_FASTPOST_SCSI 1
+#define ISP_NO_FASTPOST_FC 1
+
+#define ISP_DISABLE_1080_SUPPORT 1
+
+#endif /* _ISP_OPENBSD_H */
diff --git a/sys/dev/ic/ispmbox.h b/sys/dev/ic/ispmbox.h
index 0905106f742..950f7dadca5 100644
--- a/sys/dev/ic/ispmbox.h
+++ b/sys/dev/ic/ispmbox.h
@@ -1,11 +1,13 @@
-/* $NetBSD: ispmbox.h,v 1.1.1.1 1997/03/12 20:44:51 cgd Exp $ */
-
+/* $OpenBSD: ispmbox.h,v 1.2 1999/03/17 05:26:09 mjacob Exp $ */
+/* release_03_16_99 */
/*
- * Mailbox and Command Definitions for for Qlogic ISP SCSI adapters.
+ * Mailbox and Queue Entry Definitions for for Qlogic ISP SCSI adapters.
*
- * Copyright (c) 1997 by Matthew Jacob
+ *---------------------------------------
+ * Copyright (c) 1997, 1998 by Matthew Jacob
* NASA/Ames Research Center
* All rights reserved.
+ *---------------------------------------
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,8 +32,8 @@
* 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.
+ *
*/
-
#ifndef _ISPMBOX_H
#define _ISPMBOX_H
@@ -95,6 +97,7 @@
#define MBOX_SET_ACTIVE_NEG_STATE 0x0035
#define MBOX_SET_ASYNC_DATA_SETUP_TIME 0x0036
#define MBOX_SET_SBUS_CONTROL_PARAMS 0x0037
+#define MBOX_SET_PCI_PARAMETERS 0x0037
#define MBOX_SET_TARGET_PARAMS 0x0038
#define MBOX_SET_DEV_QUEUE_PARAMS 0x0039
/* 3a */
@@ -106,14 +109,74 @@
#define MBOX_RETURN_BIOS_BLOCK_ADDR 0x0040
#define MBOX_WRITE_FOUR_RAM_WORDS 0x0041
#define MBOX_EXEC_BIOS_IOCB 0x0042
+#define MBOX_SET_FW_FEATURES 0x004a
+#define MBOX_GET_FW_FEATURES 0x004b
+#define FW_FEATURE_LVD_NOTIFY 0x2
+#define FW_FEATURE_FAST_POST 0x1
+
+/* These are for the ISP2100 FC cards */
+#define MBOX_GET_LOOP_ID 0x20
+#define MBOX_EXEC_COMMAND_IOCB_A64 0x54
+#define MBOX_INIT_FIRMWARE 0x60
+#define MBOX_GET_INIT_CONTROL_BLOCK 0x61
+#define MBOX_INIT_LIP 0x62
+#define MBOX_GET_FC_AL_POSITION_MAP 0x63
+#define MBOX_GET_PORT_DB 0x64
+#define MBOX_CLEAR_ACA 0x65
+#define MBOX_TARGET_RESET 0x66
+#define MBOX_CLEAR_TASK_SET 0x67
+#define MBOX_ABORT_TASK_SET 0x68
+#define MBOX_GET_FW_STATE 0x69
+#define MBOX_GET_PORT_NAME 0x6a
+#define MBOX_GET_LINK_STATUS 0x6b
+#define MBOX_INIT_LIP_RESET 0x6c
+#define MBOX_INIT_LIP_LOGIN 0x72
+
+#define ISP2100_SET_PCI_PARAM 0x00ff
#define MBOX_BUSY 0x04
typedef struct {
- u_int16_t param[6];
+ u_int16_t param[8];
} mbreg_t;
/*
+ * Mailbox Command Complete Status Codes
+ */
+#define MBOX_COMMAND_COMPLETE 0x4000
+#define MBOX_INVALID_COMMAND 0x4001
+#define MBOX_HOST_INTERFACE_ERROR 0x4002
+#define MBOX_TEST_FAILED 0x4003
+#define MBOX_COMMAND_ERROR 0x4005
+#define MBOX_COMMAND_PARAM_ERROR 0x4006
+
+/*
+ * Asynchronous event status codes
+ */
+#define ASYNC_BUS_RESET 0x8001
+#define ASYNC_SYSTEM_ERROR 0x8002
+#define ASYNC_RQS_XFER_ERR 0x8003
+#define ASYNC_RSP_XFER_ERR 0x8004
+#define ASYNC_QWAKEUP 0x8005
+#define ASYNC_TIMEOUT_RESET 0x8006
+#define ASYNC_DEVICE_RESET 0x8007
+#define ASYNC_EXTMSG_UNDERRUN 0x800A
+#define ASYNC_SCAM_INT 0x800B
+#define ASYNC_HUNG_SCSI 0x800C
+#define ASYNC_KILLED_BUS 0x800D
+#define ASYNC_BUS_TRANSIT 0x800E /* LVD -> HVD, eg. */
+#define ASYNC_CMD_CMPLT 0x8020
+#define ASYNC_CTIO_DONE 0x8021
+
+/* for ISP2100 only */
+#define ASYNC_LIP_OCCURRED 0x8010
+#define ASYNC_LOOP_UP 0x8011
+#define ASYNC_LOOP_DOWN 0x8012
+#define ASYNC_LOOP_RESET 0x8013
+#define ASYNC_PDB_CHANGED 0x8014
+#define ASYNC_CHANGE_NOTIFY 0x8015
+
+/*
* Command Structure Definitions
*/
@@ -141,12 +204,33 @@ typedef struct {
#define RQSFLAG_FULL 0x02
#define RQSFLAG_BADHEADER 0x04
#define RQSFLAG_BADPACKET 0x08
+
/* RQS entry_type definitions */
-#define RQSTYPE_REQUEST 1
-#define RQSTYPE_DATASEG 2
-#define RQSTYPE_RESPONSE 3
-#define RQSTYPE_MARKER 4
-#define RQSTYPE_CMDONLY 5
+#define RQSTYPE_REQUEST 0x01
+#define RQSTYPE_DATASEG 0x02
+#define RQSTYPE_RESPONSE 0x03
+#define RQSTYPE_MARKER 0x04
+#define RQSTYPE_CMDONLY 0x05
+#define RQSTYPE_ATIO 0x06 /* Target Mode */
+#define RQSTYPE_CTIO0 0x07 /* Target Mode */
+#define RQSTYPE_SCAM 0x08
+#define RQSTYPE_A64 0x09
+#define RQSTYPE_A64_CONT 0x0a
+#define RQSTYPE_ENABLE_LUN 0x0b /* Target Mode */
+#define RQSTYPE_MODIFY_LUN 0x0c /* Target Mode */
+#define RQSTYPE_NOTIFY 0x0d /* Target Mode */
+#define RQSTYPE_NOTIFY_ACK 0x0e /* Target Mode */
+#define RQSTYPE_CTIO1 0x0f /* Target Mode */
+#define RQSTYPE_STATUS_CONT 0x10
+#define RQSTYPE_T2RQS 0x11
+
+#define RQSTYPE_T4RQS 0x15
+#define RQSTYPE_ATIO2 0x16
+#define RQSTYPE_CTIO2 0x17
+#define RQSTYPE_CSET0 0x18
+#define RQSTYPE_T3RQS 0x19
+
+#define RQSTYPE_CTIO3 0x1f
#define ISP_RQDSEG 4
@@ -163,13 +247,34 @@ typedef struct {
u_int16_t req_cdblen;
#define req_modifier req_cdblen /* marker packet */
u_int16_t req_flags;
- u_int16_t _res1;
+ u_int16_t req_reserved;
u_int16_t req_time;
u_int16_t req_seg_count;
u_int8_t req_cdb[12];
ispds_t req_dataseg[ISP_RQDSEG];
} ispreq_t;
+#define ISP_RQDSEG_T2 3
+typedef struct {
+ isphdr_t req_header;
+ u_int32_t req_handle;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t req_target;
+ u_int8_t req_lun_trn;
+#else
+ u_int8_t req_lun_trn;
+ u_int8_t req_target;
+#endif
+ u_int16_t req_scclun;
+ u_int16_t req_flags;
+ u_int16_t _res2;
+ u_int16_t req_time;
+ u_int16_t req_seg_count;
+ u_int32_t req_cdb[4];
+ u_int32_t req_totalcnt;
+ ispds_t req_dataseg[ISP_RQDSEG_T2];
+} ispreqt2_t;
+
/* req_flag values */
#define REQFLAG_NODISCON 0x0001
#define REQFLAG_HTAG 0x0002
@@ -183,6 +288,13 @@ typedef struct {
#define REQFLAG_DATA_UNKNOWN 0x0060
#define REQFLAG_DISARQ 0x0100
+#define REQFLAG_FRC_ASYNC 0x0200
+#define REQFLAG_FRC_SYNC 0x0400
+#define REQFLAG_FRC_WIDE 0x0800
+#define REQFLAG_NOPARITY 0x1000
+#define REQFLAG_STOPQ 0x2000
+#define REQFLAG_XTRASNS 0x4000
+#define REQFLAG_PRIORITY 0x8000
typedef struct {
isphdr_t req_header;
@@ -223,7 +335,7 @@ typedef struct {
u_int8_t req_modifier;
u_int8_t _res2;
#endif
-} ipsmarkreq_t;
+} ispmarkreq_t;
#define SYNC_DEVICE 0
#define SYNC_TARGET 1
@@ -243,6 +355,18 @@ typedef struct {
u_int8_t req_sense_data[32];
} ispstatusreq_t;
+/*
+ * For Qlogic 2100, the high order byte of SCSI status has
+ * additional meaning.
+ */
+#define RQCS_RU 0x800 /* Residual Under */
+#define RQCS_RO 0x400 /* Residual Over */
+#define RQCS_SV 0x200 /* Sense Length Valid */
+#define RQCS_RV 0x100 /* Residual Valid */
+
+/*
+ * Completion Status Codes.
+ */
#define RQCS_COMPLETE 0x0000
#define RQCS_INCOMPLETE 0x0001
#define RQCS_DMA_ERROR 0x0002
@@ -265,15 +389,37 @@ typedef struct {
#define RQCS_ID_MSG_FAILED 0x0013
#define RQCS_UNEXP_BUS_FREE 0x0014
#define RQCS_DATA_UNDERRUN 0x0015
+#define RQCS_XACT_ERR1 0x0018
+#define RQCS_XACT_ERR2 0x0019
+#define RQCS_XACT_ERR3 0x001A
+#define RQCS_BAD_ENTRY 0x001B
+#define RQCS_QUEUE_FULL 0x001C
+#define RQCS_PHASE_SKIPPED 0x001D
+#define RQCS_ARQS_FAILED 0x001E
+#define RQCS_WIDE_FAILED 0x001F
+#define RQCS_SYNCXFER_FAILED 0x0020
+#define RQCS_LVD_BUSERR 0x0021
+/* 2100 Only Completion Codes */
+#define RQCS_PORT_UNAVAILABLE 0x0028
+#define RQCS_PORT_LOGGED_OUT 0x0029
+#define RQCS_PORT_CHANGED 0x002A
+#define RQCS_PORT_BUSY 0x002B
+/*
+ * State Flags (not applicable to 2100)
+ */
#define RQSF_GOT_BUS 0x0100
#define RQSF_GOT_TARGET 0x0200
#define RQSF_SENT_CDB 0x0400
-#define RQSF_TRANFERRED_DATA 0x0800
+#define RQSF_XFRD_DATA 0x0800
#define RQSF_GOT_STATUS 0x1000
#define RQSF_GOT_SENSE 0x2000
+#define RQSF_XFER_COMPLETE 0x4000
+/*
+ * Status Flags (not applicable to 2100)
+ */
#define RQSTF_DISCONNECT 0x0001
#define RQSTF_SYNCHRONOUS 0x0002
#define RQSTF_PARITY_ERROR 0x0004
@@ -283,4 +429,609 @@ typedef struct {
#define RQSTF_TIMEOUT 0x0040
#define RQSTF_NEGOTIATION 0x0080
+/*
+ * FC (ISP2100) specific data structures
+ */
+
+/*
+ * Initialization Control Block
+ *
+ * Version One format.
+ */
+typedef struct {
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t _reserved0;
+ u_int8_t icb_version;
+#else
+ u_int8_t icb_version;
+ u_int8_t _reserved0;
+#endif
+ u_int16_t icb_fwoptions;
+ u_int16_t icb_maxfrmlen;
+ u_int16_t icb_maxalloc;
+ u_int16_t icb_execthrottle;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t icb_retry_delay;
+ u_int8_t icb_retry_count;
+#else
+ u_int8_t icb_retry_count;
+ u_int8_t icb_retry_delay;
+#endif
+ u_int8_t icb_nodename[8];
+ u_int16_t icb_hardaddr;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t _reserved1;
+ u_int8_t icb_iqdevtype;
+#else
+ u_int8_t icb_iqdevtype;
+ u_int8_t _reserved1;
+#endif
+ u_int8_t icb_portname[8];
+ u_int16_t icb_rqstout;
+ u_int16_t icb_rspnsin;
+ u_int16_t icb_rqstqlen;
+ u_int16_t icb_rsltqlen;
+ u_int16_t icb_rqstaddr[4];
+ u_int16_t icb_respaddr[4];
+} isp_icb_t;
+#define ICB_VERSION1 1
+
+#define ICBOPT_HARD_ADDRESS (1<<0)
+#define ICBOPT_FAIRNESS (1<<1)
+#define ICBOPT_FULL_DUPLEX (1<<2)
+#define ICBOPT_FAST_POST (1<<3)
+#define ICBOPT_TGT_ENABLE (1<<4)
+#define ICBOPT_INI_DISABLE (1<<5)
+#define ICBOPT_INI_ADISC (1<<6)
+#define ICBOPT_INI_TGTTYPE (1<<7)
+#define ICBOPT_PDBCHANGE_AE (1<<8)
+#define ICBOPT_NOLIP (1<<9)
+#define ICBOPT_SRCHDOWN (1<<10)
+#define ICBOPT_PREVLOOP (1<<11)
+#define ICBOPT_STOP_ON_QFULL (1<<12)
+#define ICBOPT_FULL_LOGIN (1<<13)
+#define ICBOPT_USE_PORTNAME (1<<14)
+
+
+#define ICB_MIN_FRMLEN 256
+#define ICB_MAX_FRMLEN 2112
+#define ICB_DFLT_FRMLEN 1024
+
+#define RQRSP_ADDR0015 0
+#define RQRSP_ADDR1631 1
+#define RQRSP_ADDR3247 2
+#define RQRSP_ADDR4863 3
+
+
+#define ICB_NNM0 7
+#define ICB_NNM1 6
+#define ICB_NNM2 5
+#define ICB_NNM3 4
+#define ICB_NNM4 3
+#define ICB_NNM5 2
+#define ICB_NNM6 1
+#define ICB_NNM7 0
+
+#define MAKE_NODE_NAME_FROM_WWN(array, wwn) \
+ array[ICB_NNM0] = (u_int8_t) ((wwn >> 0) & 0xff), \
+ array[ICB_NNM1] = (u_int8_t) ((wwn >> 8) & 0xff), \
+ array[ICB_NNM2] = (u_int8_t) ((wwn >> 16) & 0xff), \
+ array[ICB_NNM3] = (u_int8_t) ((wwn >> 24) & 0xff), \
+ array[ICB_NNM4] = (u_int8_t) ((wwn >> 32) & 0xff), \
+ array[ICB_NNM5] = (u_int8_t) ((wwn >> 40) & 0xff), \
+ array[ICB_NNM6] = (u_int8_t) ((wwn >> 48) & 0xff), \
+ array[ICB_NNM7] = (u_int8_t) ((wwn >> 56) & 0xff)
+
+/*
+ * Port Data Base Element
+ */
+
+typedef struct {
+ u_int16_t pdb_options;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t pdb_sstate;
+ u_int8_t pdb_mstate;
+#else
+ u_int8_t pdb_mstate;
+ u_int8_t pdb_sstate;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+#define BITS2WORD(x) \
+ (x)[1] << 16 | (x)[2] << 8 | (x)[3]
+#else
+#define BITS2WORD(x) \
+ (x)[0] << 16 | (x)[3] << 8 | (x)[2]
+#endif
+ u_int8_t pdb_hardaddr_bits[4];
+ u_int8_t pdb_portid_bits[4];
+ u_int8_t pdb_nodename[8];
+ u_int8_t pdb_portname[8];
+ u_int16_t pdb_execthrottle;
+ u_int16_t pdb_exec_count;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t pdb_retry_delay;
+ u_int8_t pdb_retry_count;
+#else
+ u_int8_t pdb_retry_count;
+ u_int8_t pdb_retry_delay;
+#endif
+ u_int16_t pdb_resalloc;
+ u_int16_t pdb_curalloc;
+ u_int16_t pdb_qhead;
+ u_int16_t pdb_qtail;
+ u_int16_t pdb_tl_next;
+ u_int16_t pdb_tl_last;
+ u_int16_t pdb_features; /* PLOGI, Common Service */
+ u_int16_t pdb_pconcurrnt; /* PLOGI, Common Service */
+ u_int16_t pdb_roi; /* PLOGI, Common Service */
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int8_t pdb_initiator; /* PLOGI, Class 3 Control Flags */
+ u_int8_t pdb_target;
+#else
+ u_int8_t pdb_target;
+ u_int8_t pdb_initiator; /* PLOGI, Class 3 Control Flags */
+#endif
+ u_int16_t pdb_rdsiz; /* PLOGI, Class 3 */
+ u_int16_t pdb_ncseq; /* PLOGI, Class 3 */
+ u_int16_t pdb_noseq; /* PLOGI, Class 3 */
+ u_int16_t pdb_labrtflg;
+ u_int16_t pdb_lstopflg;
+ u_int16_t pdb_sqhead;
+ u_int16_t pdb_sqtail;
+ u_int16_t pdb_ptimer;
+ u_int16_t pdb_nxt_seqid;
+ u_int16_t pdb_fcount;
+ u_int16_t pdb_prli_len;
+ u_int16_t pdb_prli_svc0;
+ u_int16_t pdb_prli_svc3;
+ u_int16_t pdb_loopid;
+ u_int16_t pdb_il_ptr;
+ u_int16_t pdb_sl_ptr;
+} isp_pdb_t;
+
+#define INVALID_PDB_OPTIONS 0xDEAD
+
+#define PDB_OPTIONS_XMITTING (1<<11)
+#define PDB_OPTIONS_LNKXMIT (1<<10)
+#define PDB_OPTIONS_ABORTED (1<<9)
+#define PDB_OPTIONS_ADISC (1<<1)
+
+#define PDB_STATE_DISCOVERY 0
+#define PDB_STATE_WDISC_ACK 1
+#define PDB_STATE_PLOGI 2
+#define PDB_STATE_PLOGI_ACK 3
+#define PDB_STATE_PRLI 4
+#define PDB_STATE_PRLI_ACK 5
+#define PDB_STATE_LOGGED_IN 6
+#define PDB_STATE_PORT_UNAVAIL 7
+#define PDB_STATE_PRLO 8
+#define PDB_STATE_PRLO_ACK 9
+#define PDB_STATE_PLOGO 10
+#define PDB_STATE_PLOG_ACK 11
+
+#define SVC3_TGT_ROLE 0x10
+#define SVC3_INI_ROLE 0x20
+#define SVC3_ROLE_MASK 0x30
+
+/*
+ * Target Mode Structures
+ */
+#define TGTSVALID 0x80 /* scsi status & sense data valid */
+#define SUGGSENSELEN 18
+
+/*
+ * Structure for Enable Lun and Modify Lun queue entries
+ */
+typedef struct {
+ isphdr_t le_header;
+ u_int32_t le_reserved2;
+#if BYTE_ORDER == BIG_ENDIAN
+#else
+ u_int8_t le_lun;
+ u_int8_t le_rsvd;
+ u_int8_t le_ops; /* Modify LUN only */
+ u_int8_t le_tgt; /* Not for FC */
+#endif
+ u_int32_t le_flags; /* Not for FC */
+#if BYTE_ORDER == BIG_ENDIAN
+#else
+ u_int8_t le_status;
+ u_int8_t le_rsvd2;
+ u_int8_t le_cmd_count;
+ u_int8_t le_in_count;
+ u_int8_t le_cdb6len; /* Not for FC */
+ u_int8_t le_cdb7len; /* Not for FC */
+#endif
+ u_int16_t le_timeout;
+ u_int16_t le_reserved[20];
+} lun_entry_t;
+
+/*
+ * le_flags values
+ */
+#define LUN_TQAE 0x00000001 /* Tagged Queue Action Enable */
+#define LUN_DSSM 0x01000000 /* Disable Sending SDP Message */
+#define LUN_DM 0x40000000 /* Disconnects Mandatory */
+
+/*
+ * le_ops values
+ */
+#define LUN_CCINCR 0x01 /* increment command count */
+#define LUN_CCDECR 0x02 /* decrement command count */
+#define LUN_ININCR 0x40 /* increment immed. notify count */
+#define LUN_INDECR 0x80 /* decrement immed. notify count */
+
+/*
+ * le_status values
+ */
+#define LUN_ERR 0x04 /* request completed with error */
+#define LUN_INVAL 0x06 /* invalid request */
+#define LUN_NOCAP 0x16 /* can't provide requested capability */
+#define LUN_ENABLED 0x3E /* LUN already enabled */
+
+/*
+ * Immediate Notify Entry structure
+ */
+#define IN_MSGLEN 8 /* 8 bytes */
+#define IN_RSVDLEN 8 /* 8 words */
+typedef struct {
+ isphdr_t in_header;
+ u_int32_t in_reserved2;
+#if BYTE_ORDER == BIG_ENDIAN
+#else
+ u_int8_t in_lun; /* lun */
+ u_int8_t in_iid; /* initiator */
+ u_int8_t in_rsvd;
+ u_int8_t in_tgt; /* target */
+#endif
+ u_int32_t in_flags;
+#if BYTE_ORDER == BIG_ENDIAN
+#else
+ u_int8_t in_status;
+ u_int8_t in_rsvd2;
+ u_int8_t in_tag_val; /* tag value */
+ u_int8_t in_tag_type; /* tag type */
+#endif
+ u_int16_t in_seqid; /* sequence id */
+ u_int8_t in_msg[IN_MSGLEN]; /* SCSI message bytes */
+ u_int16_t in_reserved[IN_RSVDLEN];
+ u_int8_t in_sense[SUGGSENSELEN]; /* suggested sense data */
+} in_entry_t;
+
+typedef struct {
+ isphdr_t in_header;
+ u_int32_t in_reserved2;
+#if BYTE_ORDER == BIG_ENDIAN
+#else
+ u_int8_t in_lun; /* lun */
+ u_int8_t in_iid; /* initiator */
+#endif
+ u_int16_t in_rsvd;
+ u_int32_t in_rsvd2;
+ u_int16_t in_status;
+ u_int16_t in_task_flags;
+ u_int16_t in_seqid; /* sequence id */
+} in_fcentry_t;
+
+/*
+ * Values for the in_status field
+ */
+#define IN_NO_RCAP 0x16 /* requested capability not available */
+#define IN_IDE_RECEIVED 0x33 /* Initiator Detected Error msg received */
+#define IN_RSRC_UNAVAIL 0x34 /* resource unavailable */
+#define IN_MSG_RECEIVED 0x36 /* SCSI message received */
+#define IN_PORT_LOGOUT 0x29 /* port has logged out (FC) */
+#define IN_ABORT_TASK 0x20 /* task named in RX_ID is being aborted (FC) */
+
+/*
+ * Notify Acknowledge Entry structure
+ */
+#define NA_RSVDLEN 22
+typedef struct {
+ isphdr_t na_header;
+ u_int32_t na_reserved2;
+#if BYTE_ORDER == BIG_ENDIAN
+#else
+ u_int8_t na_lun; /* lun */
+ u_int8_t na_iid; /* initiator */
+ u_int8_t na_rsvd;
+ u_int8_t na_tgt; /* target */
+#endif
+ u_int32_t na_flags;
+#if BYTE_ORDER == BIG_ENDIAN
+#else
+ u_int8_t na_status;
+ u_int8_t na_event;
+#endif
+ u_int16_t na_seqid; /* sequence id */
+ u_int16_t na_reserved[NA_RSVDLEN];
+} na_entry_t;
+
+/*
+ * Value for the na_event field
+ */
+#define NA_RST_CLRD 0x80 /* Clear an async event notification */
+
+#define NA2_RSVDLEN 21
+typedef struct {
+ isphdr_t na_header;
+ u_int32_t na_reserved2;
+#if BYTE_ORDER == BIG_ENDIAN
+#else
+ u_int8_t na_lun; /* lun */
+ u_int8_t na_iid; /* initiator */
+#endif
+ u_int16_t na_rsvd;
+ u_int16_t na_flags;
+ u_int16_t na_rsvd2;
+ u_int16_t na_status;
+ u_int16_t na_task_flags;
+ u_int16_t na_seqid; /* sequence id */
+ u_int16_t na_reserved[NA2_RSVDLEN];
+} na_fcentry_t;
+#define NAFC_RST_CLRD 0x40
+
+/*
+ * Value for the na_event field
+ */
+#define NA_RST_CLRD 0x80 /* Clear an async event notification */
+/*
+ * Accept Target I/O Entry structure
+ */
+#define ATIO_CDBLEN 26
+
+typedef struct {
+ isphdr_t at_header;
+ u_int32_t at_reserved2;
+#if BYTE_ORDER == BIG_ENDIAN
+#else
+ u_int8_t at_lun; /* lun */
+ u_int8_t at_iid; /* initiator */
+ u_int8_t at_cdblen; /* cdb length */
+ u_int8_t at_tgt; /* target */
+#endif
+ u_int32_t at_flags;
+#if BYTE_ORDER == BIG_ENDIAN
+#else
+ u_int8_t at_status; /* firmware status */
+ u_int8_t at_scsi_status; /* scsi status */
+ u_int8_t at_tag_val; /* tag value */
+ u_int8_t at_tag_type; /* tag type */
+#endif
+ u_int8_t at_cdb[ATIO_CDBLEN]; /* received CDB */
+ u_int8_t at_sense[SUGGSENSELEN]; /* suggested sense data */
+} at_entry_t;
+
+/*
+ * at_flags values
+ */
+#define AT_NODISC 0x00008000 /* disconnect disabled */
+#define AT_TQAE 0x00000001 /* Tagged Queue Action enabled */
+
+/*
+ * at_status values
+ */
+#define AT_PATH_INVALID 0x07 /* ATIO sent to firmware for disabled lun */
+#define AT_PHASE_ERROR 0x14 /* Bus phase sequence error */
+#define AT_NOCAP 0x16 /* Requested capability not available */
+#define AT_BDR_MSG 0x17 /* Bus Device Reset msg received */
+#define AT_CDB 0x3D /* CDB received */
+
+/*
+ * Accept Target I/O Entry structure, Type 2
+ */
+#define ATIO2_CDBLEN 16
+
+typedef struct {
+ isphdr_t at_header;
+ u_int32_t at_reserved2;
+#if BYTE_ORDER == BIG_ENDIAN
+#else
+ u_int8_t at_lun; /* lun */
+ u_int8_t at_iid; /* initiator */
+#endif
+ u_int16_t at_rxid; /* response ID */
+ u_int16_t at_flags;
+ u_int16_t at_status; /* firmware status */
+#if BYTE_ORDER == BIG_ENDIAN
+#else
+ u_int8_t at_reserved1;
+ u_int8_t at_taskcodes;
+ u_int8_t at_taskflags;
+ u_int8_t at_execodes;
+#endif
+ u_int8_t at_cdb[ATIO2_CDBLEN]; /* received CDB */
+ u_int32_t at_datalen; /* allocated data len */
+ u_int16_t at_scclun;
+ u_int16_t at_reserved3;
+ u_int16_t at_scsi_status;
+ u_int8_t at_sense[SUGGSENSELEN]; /* suggested sense data */
+} at2_entry_t;
+
+#define ATIO2_TC_ATTR_MASK 0x7
+#define ATIO2_TC_ATTR_SIMPLEQ 0
+#define ATIO2_TC_ATTR_HEADOFQ 1
+#define ATIO2_TC_ATTR_ORDERED 2
+#define ATIO2_TC_ATTR_ACAQ 4
+#define ATIO2_TC_ATTR_UNTAGGED 5
+#define TC2TT(code) \
+ (((code) == ATIO2_TC_ATTR_SIMPLEQ)? 0x20 : \
+ (((code) == ATIO2_TC_ATTR_HEADOFQ)? 0x21 : \
+ (((code) == ATIO2_TC_ATTR_ORDERED)? 0x22 : \
+ (((code) == ATIO2_TC_ATTR_ACAQ)? 0x24 : 0))))
+
+
+/*
+ * Continue Target I/O Entry structure
+ * Request from driver. The response from the
+ * ISP firmware is the same except that the last 18
+ * bytes are overwritten by suggested sense data if
+ * the 'autosense valid' bit is set in the status byte.
+ */
+typedef struct {
+ isphdr_t ct_header;
+ u_int32_t ct_reserved;
+#if BYTE_ORDER == BIG_ENDIAN
+#else
+ u_int8_t ct_lun; /* lun */
+ u_int8_t ct_iid; /* initiator id */
+ u_int8_t ct_rsvd;
+ u_int8_t ct_tgt; /* our target id */
+#endif
+ u_int32_t ct_flags;
+#if BYTE_ORDER == BIG_ENDIAN
+#else
+ u_int8_t ct_status; /* isp status */
+ u_int8_t ct_scsi_status; /* scsi status */
+ u_int8_t ct_tag_val; /* tag value */
+ u_int8_t ct_tag_type; /* tag type */
+#endif
+ u_int32_t ct_xfrlen; /* transfer length */
+ u_int32_t ct_resid; /* residual length */
+ u_int16_t ct_timeout;
+ u_int16_t ct_seg_count;
+ ispds_t ct_dataseg[ISP_RQDSEG];
+} ct_entry_t;
+
+/*
+ * ct_flags values
+ */
+#define CT_TQAE 0x00000001 /* Tagged Queue Action enable */
+#define CT_DATA_IN 0x00000040 /* Data direction */
+#define CT_DATA_OUT 0x00000080 /* Data direction */
+#define CT_NO_DATA 0x000000C0 /* Data direction */
+#define CT_DATAMASK 0x000000C0 /* Data direction */
+#define CT_NODISC 0x00008000 /* Disconnects disabled */
+#define CT_DSDP 0x01000000 /* Disable Save Data Pointers */
+#define CT_SENDRDP 0x04000000 /* Send Restore Pointers msg */
+#define CT_SENDSTATUS 0x80000000 /* Send SCSI status byte */
+
+/*
+ * ct_status values
+ * - set by the firmware when it returns the CTIO
+ */
+#define CT_OK 0x01 /* completed without error */
+#define CT_ABORTED 0x02 /* aborted by host */
+#define CT_ERR 0x04 /* see sense data for error */
+#define CT_INVAL 0x06 /* request for disabled lun */
+#define CT_NOPATH 0x07 /* invalid ITL nexus */
+#define CT_INVRXID 0x08 /* (FC only) Invalid RX_ID */
+#define CT_RSELTMO 0x0A /* reselection timeout after 2 tries */
+#define CT_TIMEOUT 0x0B /* timed out */
+#define CT_RESET 0x0E /* SCSI Bus Reset occurred */
+#define CT_PHASE_ERROR 0x14 /* Bus phase sequence error */
+#define CT_BDR_MSG 0x17 /* Bus Device Reset msg received */
+#define CT_TERMINATED 0x19 /* due to Terminate Transfer mbox cmd */
+#define CT_LOGOUT 0x29 /* port logout not acknowledged yet */
+#define CT_NOACK 0x35 /* Outstanding Immed. Notify. entry */
+
+/*
+ * When the firmware returns a CTIO entry, it may overwrite the last
+ * part of the structure with sense data. This starts at offset 0x2E
+ * into the entry, which is in the middle of ct_dataseg[1]. Rather
+ * than define a new struct for this, I'm just using the sense data
+ * offset.
+ */
+#define CTIO_SENSE_OFFSET 0x2E
+
+/*
+ * Entry length in u_longs. All entries are the same size so
+ * any one will do as the numerator.
+ */
+#define UINT32_ENTRY_SIZE (sizeof(at_entry_t)/sizeof(u_int32_t))
+
+/*
+ * QLA2100 CTIO (type 2) entry
+ */
+#define MAXRESPLEN 26
+typedef struct {
+ isphdr_t ct_header;
+ u_int32_t ct_reserved;
+#if BYTE_ORDER == BIG_ENDIAN
+#else
+ u_int8_t ct_lun; /* lun */
+ u_int8_t ct_iid; /* initiator id */
+#endif
+ u_int16_t ct_rxid; /* response ID */
+ u_int16_t ct_flags;
+ u_int16_t ct_status; /* isp status */
+ u_int16_t ct_timeout;
+ u_int16_t ct_seg_count;
+ u_int32_t ct_reloff; /* relative offset */
+ u_int32_t ct_resid; /* residual length */
+ union {
+ /*
+ * The three different modes that the target driver
+ * can set the CTIO2 up as.
+ *
+ * The first is for sending FCP_DATA_IUs as well as
+ * (optionally) sending a terminal SCSI status FCP_RSP_IU.
+ *
+ * The second is for sending SCSI sense data in an FCP_RSP_IU.
+ * Note that no FCP_DATA_IUs will be sent.
+ *
+ * The third is for sending FCP_RSP_IUs as built specifically
+ * in system memory as located by the isp_dataseg.
+ */
+ struct {
+ u_int32_t _reserved;
+ u_int16_t _reserved2;
+ u_int16_t ct_scsi_status;
+ u_int32_t ct_xfrlen;
+ ispds_t ct_dataseg[ISP_RQDSEG_T2];
+ } m0;
+ struct {
+ u_int16_t _reserved;
+ u_int16_t _reserved2;
+ u_int16_t ct_senselen;
+ u_int16_t ct_scsi_status;
+ u_int16_t ct_resplen;
+ u_int8_t ct_resp[MAXRESPLEN];
+ } m1;
+ struct {
+ u_int32_t _reserved;
+ u_int16_t _reserved2;
+ u_int16_t _reserved3;
+ u_int32_t ct_datalen;
+ ispds_t ct_fcp_rsp_iudata;
+ } m2;
+ /*
+ * CTIO2 returned from F/W...
+ */
+ struct {
+ u_int32_t _reserved[4];
+ u_int16_t ct_scsi_status;
+ u_int8_t ct_sense[SUGGSENSELEN];
+ } fw;
+ } rsp;
+} ct2_entry_t;
+/*
+ * ct_flags values for CTIO2
+ */
+#define CT2_FLAG_MMASK 0x0003
+#define CT2_FLAG_MODE0 0x0000
+#define CT2_FLAG_MODE1 0x0001
+#define CT2_FLAG_MODE2 0x0002
+#define CT2_DATA_IN CT_DATA_IN
+#define CT2_DATA_OUT CT_DATA_OUT
+#define CT2_NO_DATA CT_NO_DATA
+#define CT2_DATAMASK CT_DATA_MASK
+#define CT2_CCINCR 0x0100
+#define CT2_FASTPOST 0x0200
+#define CT2_SENDSTATUS 0x8000
+
+/*
+ * ct_status values are (mostly) the same as that for ct_entry.
+ */
+
+/*
+ * ct_scsi_status values- the low 8 bits are the normal SCSI status
+ * we know and love. The upper 8 bits are validity markers for FCP_RSP_IU
+ * fields.
+ */
+#define CT2_RSPLEN_VALID 0x0100
+#define CT2_SNSLEN_VALID 0x0200
+#define CT2_DATA_OVER 0x0400
+#define CT2_DATA_UNDER 0x0800
+
#endif /* _ISPMBOX_H */
diff --git a/sys/dev/ic/ispreg.h b/sys/dev/ic/ispreg.h
index 3f5a1943285..1699af8e25a 100644
--- a/sys/dev/ic/ispreg.h
+++ b/sys/dev/ic/ispreg.h
@@ -1,13 +1,14 @@
-/* $NetBSD: ispreg.h,v 1.1.1.1 1997/03/12 20:44:51 cgd Exp $ */
-
+/* $OpenBSD: ispreg.h,v 1.2 1999/03/17 05:26:09 mjacob Exp $ */
+/* release_03_16_99 */
/*
* Machine Independent (well, as best as possible) register
* definitions for Qlogic ISP SCSI adapters.
*
+ *---------------------------------------
* Copyright (c) 1997 by Matthew Jacob
* NASA/Ames Research Center
* All rights reserved.
- *
+ *---------------------------------------
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -32,7 +33,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-
#ifndef _ISPREG_H
#define _ISPREG_H
@@ -57,62 +57,84 @@
* Sad but true, different architectures have different offsets.
*/
-#define BIU_REGS_OFF 0x00
+#define BIU_REGS_OFF 0x00
-#define PCI_MBOX_REGS_OFF 0x70
+#define PCI_MBOX_REGS_OFF 0x70
+#define PCI_MBOX_REGS2100_OFF 0x10
#define SBUS_MBOX_REGS_OFF 0x80
-#define PCI_SXP_REGS_OFF 0x80
+#define PCI_SXP_REGS_OFF 0x80
#define SBUS_SXP_REGS_OFF 0x200
-#define PCI_RISC_REGS_OFF 0x80
+#define PCI_RISC_REGS_OFF 0x80
#define SBUS_RISC_REGS_OFF 0x400
+/* Bless me! Chip designers have putzed it again! */
+#define ISP1080_DMA_REGS_OFF 0x60
+#define DMA_REGS_OFF 0x00 /* same as BIU block */
+
/*
* NB: The *_BLOCK definitions have no specific hardware meaning.
* They serve simply to note to the MD layer which block of
* registers offsets are being accessed.
*/
+#define _NREG_BLKS 5
+#define _BLK_REG_SHFT 13
+#define _BLK_REG_MASK (7 << _BLK_REG_SHFT)
+#define BIU_BLOCK (0 << _BLK_REG_SHFT)
+#define MBOX_BLOCK (1 << _BLK_REG_SHFT)
+#define SXP_BLOCK (2 << _BLK_REG_SHFT)
+#define RISC_BLOCK (3 << _BLK_REG_SHFT)
+#define DMA_BLOCK (4 << _BLK_REG_SHFT)
/*
* Bus Interface Block Register Offsets
*/
-#define BIU_BLOCK 0x0100
+
#define BIU_ID_LO BIU_BLOCK+0x0 /* R : Bus ID, Low */
+#define BIU2100_FLASH_ADDR BIU_BLOCK+0x0
#define BIU_ID_HI BIU_BLOCK+0x2 /* R : Bus ID, High */
+#define BIU2100_FLASH_DATA BIU_BLOCK+0x2
#define BIU_CONF0 BIU_BLOCK+0x4 /* R : Bus Configuration #0 */
#define BIU_CONF1 BIU_BLOCK+0x6 /* R : Bus Configuration #1 */
+#define BIU2100_CSR BIU_BLOCK+0x6
#define BIU_ICR BIU_BLOCK+0x8 /* RW : Bus Interface Ctrl */
#define BIU_ISR BIU_BLOCK+0xA /* R : Bus Interface Status */
#define BIU_SEMA BIU_BLOCK+0xC /* RW : Bus Semaphore */
#define BIU_NVRAM BIU_BLOCK+0xE /* RW : Bus NVRAM */
-#define CDMA_CONF BIU_BLOCK+0x20 /* RW*: DMA Configuration */
-#define CDMA_CONTROL BIU_BLOCK+0x22 /* RW*: DMA Control */
-#define CDMA_STATUS BIU_BLOCK+0x24 /* R : DMA Status */
-#define CDMA_FIFO_STS BIU_BLOCK+0x26 /* R : DMA FIFO Status */
-#define CDMA_COUNT BIU_BLOCK+0x28 /* RW*: DMA Transfer Count */
-#define CDMA_ADDR0 BIU_BLOCK+0x2C /* RW*: DMA Address, Word 0 */
-#define CDMA_ADDR1 BIU_BLOCK+0x2E /* RW*: DMA Address, Word 1 */
-/* these are for the 1040A cards */
-#define CDMA_ADDR2 BIU_BLOCK+0x30 /* RW*: DMA Address, Word 2 */
-#define CDMA_ADDR3 BIU_BLOCK+0x32 /* RW*: DMA Address, Word 3 */
-
-#define DDMA_CONF BIU_BLOCK+0x40 /* RW*: DMA Configuration */
-#define DDMA_CONTROL BIU_BLOCK+0x42 /* RW*: DMA Control */
-#define DDMA_STATUS BIU_BLOCK+0x44 /* R : DMA Status */
-#define DDMA_FIFO_STS BIU_BLOCK+0x46 /* R : DMA FIFO Status */
-#define DDMA_COUNT_LO BIU_BLOCK+0x48 /* RW*: DMA Xfer Count, Low */
-#define DDMA_COUNT_HI BIU_BLOCK+0x4A /* RW*: DMA Xfer Count, High */
-#define DDMA_ADDR0 BIU_BLOCK+0x4C /* RW*: DMA Address, Word 0 */
-#define DDMA_ADDR1 BIU_BLOCK+0x4E /* RW*: DMA Address, Word 1 */
-/* these are for the 1040A cards */
-#define DDMA_ADDR2 BIU_BLOCK+0x50 /* RW*: DMA Address, Word 2 */
-#define DDMA_ADDR3 BIU_BLOCK+0x52 /* RW*: DMA Address, Word 3 */
-
#define DFIFO_COMMAND BIU_BLOCK+0x60 /* RW : Command FIFO Port */
+#define RDMA2100_CONTROL DFIFO_COMMAND
#define DFIFO_DATA BIU_BLOCK+0x62 /* RW : Data FIFO Port */
/*
+ * Putzed DMA register layouts.
+ */
+#define CDMA_CONF DMA_BLOCK+0x20 /* RW*: DMA Configuration */
+#define CDMA2100_CONTROL CDMA_CONF
+#define CDMA_CONTROL DMA_BLOCK+0x22 /* RW*: DMA Control */
+#define CDMA_STATUS DMA_BLOCK+0x24 /* R : DMA Status */
+#define CDMA_FIFO_STS DMA_BLOCK+0x26 /* R : DMA FIFO Status */
+#define CDMA_COUNT DMA_BLOCK+0x28 /* RW*: DMA Transfer Count */
+#define CDMA_ADDR0 DMA_BLOCK+0x2C /* RW*: DMA Address, Word 0 */
+#define CDMA_ADDR1 DMA_BLOCK+0x2E /* RW*: DMA Address, Word 1 */
+#define CDMA_ADDR2 DMA_BLOCK+0x30 /* RW*: DMA Address, Word 2 */
+#define CDMA_ADDR3 DMA_BLOCK+0x32 /* RW*: DMA Address, Word 3 */
+
+#define DDMA_CONF DMA_BLOCK+0x40 /* RW*: DMA Configuration */
+#define TDMA2100_CONTROL DDMA_CONF
+#define DDMA_CONTROL DMA_BLOCK+0x42 /* RW*: DMA Control */
+#define DDMA_STATUS DMA_BLOCK+0x44 /* R : DMA Status */
+#define DDMA_FIFO_STS DMA_BLOCK+0x46 /* R : DMA FIFO Status */
+#define DDMA_COUNT_LO DMA_BLOCK+0x48 /* RW*: DMA Xfer Count, Low */
+#define DDMA_COUNT_HI DMA_BLOCK+0x4A /* RW*: DMA Xfer Count, High */
+#define DDMA_ADDR0 DMA_BLOCK+0x4C /* RW*: DMA Address, Word 0 */
+#define DDMA_ADDR1 DMA_BLOCK+0x4E /* RW*: DMA Address, Word 1 */
+/* these are for the 1040A cards */
+#define DDMA_ADDR2 DMA_BLOCK+0x50 /* RW*: DMA Address, Word 2 */
+#define DDMA_ADDR3 DMA_BLOCK+0x52 /* RW*: DMA Address, Word 3 */
+
+
+/*
* Bus Interface Block Register Definitions
*/
/* BUS CONFIGURATION REGISTER #0 */
@@ -134,6 +156,22 @@
#define BIU_SBUS_CONF1_BURST8 0x0008 /* Enable 8-byte bursts */
#define BIU_PCI_CONF1_SXP 0x0008 /* SXP register select */
+#define BIU_PCI1080_CONF1_SXP 0x0100 /* SXP bank select */
+#define BIU_PCI1080_CONF1_DMA 0x0300 /* DMA bank select */
+
+ /* ISP2100 Bus Control/Status Register */
+
+#define BIU2100_ICSR_REGBSEL 0x30 /* RW: register bank select */
+#define BIU2100_RISC_REGS (0 << 4) /* RISC Regs */
+#define BIU2100_FB_REGS (1 << 4) /* FrameBuffer Regs */
+#define BIU2100_FPM0_REGS (2 << 4) /* FPM 0 Regs */
+#define BIU2100_FPM1_REGS (3 << 4) /* FPM 1 Regs */
+#define BIU2100_PCI64 0x04 /* R: 64 Bit PCI slot */
+#define BIU2100_FLASH_ENABLE 0x02 /* RW: Enable Flash RAM */
+#define BIU2100_SOFT_RESET 0x01
+/* SOFT RESET FOR ISP2100 is same bit, but in this register, not ICR */
+
+
/* BUS CONTROL REGISTER */
#define BIU_ICR_ENABLE_DMA_INT 0x0020 /* Enable DMA interrupts */
#define BIU_ICR_ENABLE_CDMA_INT 0x0010 /* Enable CDMA interrupts */
@@ -142,6 +180,25 @@
#define BIU_ICR_ENABLE_ALL_INTS 0x0002 /* Global enable all inter */
#define BIU_ICR_SOFT_RESET 0x0001 /* Soft Reset of ISP */
+#define BIU2100_ICR_ENABLE_ALL_INTS 0x8000
+#define BIU2100_ICR_ENA_FPM_INT 0x0020
+#define BIU2100_ICR_ENA_FB_INT 0x0010
+#define BIU2100_ICR_ENA_RISC_INT 0x0008
+#define BIU2100_ICR_ENA_CDMA_INT 0x0004
+#define BIU2100_ICR_ENABLE_RXDMA_INT 0x0002
+#define BIU2100_ICR_ENABLE_TXDMA_INT 0x0001
+#define BIU2100_ICR_DISABLE_ALL_INTS 0x0000
+
+#define ENABLE_INTS(isp) (isp->isp_type & ISP_HA_SCSI)? \
+ ISP_WRITE(isp, BIU_ICR, BIU_ICR_ENABLE_RISC_INT | BIU_ICR_ENABLE_ALL_INTS) : \
+ ISP_WRITE(isp, BIU_ICR, BIU2100_ICR_ENA_RISC_INT | BIU2100_ICR_ENABLE_ALL_INTS)
+
+#define INTS_ENABLED(isp) ((isp->isp_type & ISP_HA_SCSI)? \
+ (ISP_READ(isp, BIU_ICR) & (BIU_ICR_ENABLE_RISC_INT|BIU_ICR_ENABLE_ALL_INTS)) :\
+ (ISP_READ(isp, BIU_ICR) & \
+ (BIU2100_ICR_ENA_RISC_INT|BIU2100_ICR_ENABLE_ALL_INTS)))
+
+#define DISABLE_INTS(isp) ISP_WRITE(isp, BIU_ICR, 0)
/* BUS STATUS REGISTER */
#define BIU_ISR_DMA_INT 0x0020 /* DMA interrupt pending */
@@ -150,11 +207,25 @@
#define BIU_ISR_RISC_INT 0x0004 /* Risc interrupt pending */
#define BIU_ISR_IPEND 0x0002 /* Global interrupt pending */
+#define BIU2100_ISR_INT_PENDING 0x8000 /* Global interrupt pending */
+#define BIU2100_ISR_FPM_INT 0x0020 /* FPM interrupt pending */
+#define BIU2100_ISR_FB_INT 0x0010 /* FB interrupt pending */
+#define BIU2100_ISR_RISC_INT 0x0008 /* Risc interrupt pending */
+#define BIU2100_ISR_CDMA_INT 0x0004 /* CDMA interrupt pending */
+#define BIU2100_ISR_RXDMA_INT_PENDING 0x0002 /* Global interrupt pending */
+#define BIU2100_ISR_TXDMA_INT_PENDING 0x0001 /* Global interrupt pending */
+
/* BUS SEMAPHORE REGISTER */
#define BIU_SEMA_STATUS 0x0002 /* Semaphore Status Bit */
#define BIU_SEMA_LOCK 0x0001 /* Semaphore Lock Bit */
+/* NVRAM SEMAPHORE REGISTER */
+#define BIU_NVRAM_CLOCK 0x0001
+#define BIU_NVRAM_SELECT 0x0002
+#define BIU_NVRAM_DATAOUT 0x0004
+#define BIU_NVRAM_DATAIN 0x0008
+#define ISP_NVRAM_READ 6
/* COMNMAND && DATA DMA CONFIGURATION REGISTER */
#define DMA_ENABLE_SXP_DMA 0x0008 /* Enable SXP to DMA Data */
@@ -176,6 +247,13 @@
#define DMA_CNTRL_RESET_INT 0x0002 /* Clear DMA interrupt */
#define DMA_CNTRL_STROBE 0x0001 /* Start DMA transfer */
+/*
+ * Variants of same for 2100
+ */
+#define DMA_CNTRL2100_CLEAR_CHAN 0x0004
+#define DMA_CNTRL2100_RESET_INT 0x0002
+
+
/* DMA STATUS REGISTER */
#define DMA_SBUS_STATUS_PIPE_MASK 0x00C0 /* DMA Pipeline status mask */
@@ -232,13 +310,14 @@
* Mailbox Block Register Offsets
*/
-#define MBOX_BLOCK 0x0200
#define INMAILBOX0 MBOX_BLOCK+0x0
#define INMAILBOX1 MBOX_BLOCK+0x2
#define INMAILBOX2 MBOX_BLOCK+0x4
#define INMAILBOX3 MBOX_BLOCK+0x6
#define INMAILBOX4 MBOX_BLOCK+0x8
#define INMAILBOX5 MBOX_BLOCK+0xA
+#define INMAILBOX6 MBOX_BLOCK+0xC
+#define INMAILBOX7 MBOX_BLOCK+0xE
#define OUTMAILBOX0 MBOX_BLOCK+0x0
#define OUTMAILBOX1 MBOX_BLOCK+0x2
@@ -246,31 +325,17 @@
#define OUTMAILBOX3 MBOX_BLOCK+0x6
#define OUTMAILBOX4 MBOX_BLOCK+0x8
#define OUTMAILBOX5 MBOX_BLOCK+0xA
+#define OUTMAILBOX6 MBOX_BLOCK+0xC
+#define OUTMAILBOX7 MBOX_BLOCK+0xE
-/*
- * Mailbox Command Complete Status Codes
- */
-#define MBOX_COMMAND_COMPLETE 0x4000
-#define MBOX_INVALID_COMMAND 0x4001
-#define MBOX_HOST_INTERFACE_ERROR 0x4002
-#define MBOX_TEST_FAILED 0x4003
-#define MBOX_COMMAND_ERROR 0x4005
-#define MBOX_COMMAND_PARAM_ERROR 0x4006
-
-/*
- * Asynchronous event status codes
- */
-#define ASYNC_BUS_RESET 0x8001
-#define ASYNC_SYSTEM_ERROR 0x8002
-#define ASYNC_RQS_XFER_ERR 0x8003
-#define ASYNC_RSP_XFER_ERR 0x8004
-#define ASYNC_QWAKEUP 0x8005
-#define ASYNC_TIMEOUT_RESET 0x8006
+#define OMBOX_OFFN(n) (MBOX_BLOCK + (n * 2))
+#define NMBOX(isp) \
+ (((((isp)->isp_type & ISP_HA_SCSI) >= ISP_HA_SCSI_1040A) || \
+ ((isp)->isp_type & ISP_HA_FC))? 8 : 6)
/*
* SXP Block Register Offsets
*/
-#define SXP_BLOCK 0x0400
#define SXP_PART_ID SXP_BLOCK+0x0 /* R : Part ID Code */
#define SXP_CONFIG1 SXP_BLOCK+0x2 /* RW*: Configuration Reg #1 */
#define SXP_CONFIG2 SXP_BLOCK+0x4 /* RW*: Configuration Reg #2 */
@@ -441,7 +506,6 @@
/*
* RISC and Host Command and Control Block Register Offsets
*/
-#define RISC_BLOCK 0x0800
#define RISC_ACC RISC_BLOCK+0x0 /* RW*: Accumulator */
#define RISC_R1 RISC_BLOCK+0x2 /* RW*: GP Reg R1 */
@@ -467,7 +531,10 @@
#define RISC_LCR RISC_BLOCK+0x2a /* RW*: Loop Counter */
#define RISC_PC RISC_BLOCK+0x2c /* R : Program Counter */
#define RISC_MTR RISC_BLOCK+0x2e /* RW*: Memory Timing */
+#define RISC_MTR2100 RISC_BLOCK+0x30
+
#define RISC_EMB RISC_BLOCK+0x30 /* RW*: Ext Mem Boundary */
+#define DUAL_BANK 8
#define RISC_SP RISC_BLOCK+0x32 /* RW*: Stack Pointer */
#define RISC_HRL RISC_BLOCK+0x3e /* R *: Hardware Rev Level */
#define HCCR RISC_BLOCK+0x40 /* RW : Host Command & Ctrl */
@@ -486,6 +553,10 @@
#define RISC_PSR_ALU_MSB 0x0400
#define RISC_PSR_ALU_CARRY 0x0200
#define RISC_PSR_ALU_ZERO 0x0100
+
+#define RISC_PSR_PCI_ULTRA 0x0080
+#define RISC_PSR_SBUS_ULTRA 0x0020
+
#define RISC_PSR_DMA_INT 0x0010
#define RISC_PSR_SXP_INT 0x0008
#define RISC_PSR_HOST_INT 0x0004
@@ -508,6 +579,11 @@
#define PCI_HCCR_CMD_PARITY_ERR 0xE000 /* Generate parity error */
#define HCCR_CMD_TEST_MODE 0xF000 /* Set Test Mode */
+#define ISP2100_HCCR_PARITY_ENABLE_2 0x0400
+#define ISP2100_HCCR_PARITY_ENABLE_1 0x0200
+#define ISP2100_HCCR_PARITY_ENABLE_0 0x0100
+#define ISP2100_HCCR_PARITY 0x0001
+
#define PCI_HCCR_PARITY 0x0400 /* Parity error flag */
#define PCI_HCCR_PARITY_ENABLE_1 0x0200 /* Parity enable bank 1 */
#define PCI_HCCR_PARITY_ENABLE_0 0x0100 /* Parity enable bank 0 */
@@ -517,4 +593,119 @@
#define HCCR_PAUSE 0x0020 /* R : RISC paused */
#define PCI_HCCR_BIOS 0x0001 /* W : BIOS enable */
+
+/*
+ * Qlogic 1XXX NVRAM is an array of 128 bytes.
+ *
+ * Some portion of the front of this is for general host adapter properties
+ * This is followed by an array of per-target parameters, and is tailed off
+ * with a checksum xor byte at offset 127. For non-byte entities data is
+ * stored in Little Endian order.
+ */
+
+#define ISP_NVRAM_SIZE 128
+
+#define ISPBSMX(c, byte, shift, mask) \
+ (((c)[(byte)] >> (shift)) & (mask))
+
+#define ISP_NVRAM_VERSION(c) (c)[4]
+#define ISP_NVRAM_FIFO_THRESHOLD(c) ISPBSMX(c, 5, 0, 0x03)
+#define ISP_NVRAM_BIOS_DISABLE(c) ISPBSMX(c, 5, 2, 0x01)
+#define ISP_NVRAM_HBA_ENABLE(c) ISPBSMX(c, 5, 3, 0x01)
+#define ISP_NVRAM_INITIATOR_ID(c) ISPBSMX(c, 5, 4, 0x0f)
+#define ISP_NVRAM_BUS_RESET_DELAY(c) (c)[6]
+#define ISP_NVRAM_BUS_RETRY_COUNT(c) (c)[7]
+#define ISP_NVRAM_BUS_RETRY_DELAY(c) (c)[8]
+#define ISP_NVRAM_ASYNC_DATA_SETUP_TIME(c) ISPBSMX(c, 9, 0, 0x0f)
+#define ISP_NVRAM_REQ_ACK_ACTIVE_NEGATION(c) ISPBSMX(c, 9, 4, 0x01)
+#define ISP_NVRAM_DATA_LINE_ACTIVE_NEGATION(c) ISPBSMX(c, 9, 5, 0x01)
+#define ISP_NVRAM_DATA_DMA_BURST_ENABLE(c) ISPBSMX(c, 9, 6, 0x01)
+#define ISP_NVRAM_CMD_DMA_BURST_ENABLE(c) ISPBSMX(c, 9, 7, 0x01)
+#define ISP_NVRAM_TAG_AGE_LIMIT(c) (c)[10]
+#define ISP_NVRAM_LOWTRM_ENABLE(c) ISPBSMX(c, 11, 0, 0x01)
+#define ISP_NVRAM_HITRM_ENABLE(c) ISPBSMX(c, 11, 1, 0x01)
+#define ISP_NVRAM_PCMC_BURST_ENABLE(c) ISPBSMX(c, 11, 2, 0x01)
+#define ISP_NVRAM_ENABLE_60_MHZ(c) ISPBSMX(c, 11, 3, 0x01)
+#define ISP_NVRAM_SCSI_RESET_DISABLE(c) ISPBSMX(c, 11, 4, 0x01)
+#define ISP_NVRAM_ENABLE_AUTO_TERM(c) ISPBSMX(c, 11, 5, 0x01)
+#define ISP_NVRAM_FIFO_THRESHOLD_128(c) ISPBSMX(c, 11, 6, 0x01)
+#define ISP_NVRAM_AUTO_TERM_SUPPORT(c) ISPBSMX(c, 11, 7, 0x01)
+#define ISP_NVRAM_SELECTION_TIMEOUT(c) (((c)[12]) | ((c)[13] << 8))
+#define ISP_NVRAM_MAX_QUEUE_DEPTH(c) (((c)[14]) | ((c)[15] << 8))
+#define ISP_NVRAM_SCSI_BUS_SIZE(c) ISPBSMX(c, 16, 0, 0x01)
+#define ISP_NVRAM_SCSI_BUS_TYPE(c) ISPBSMX(c, 16, 1, 0x01)
+#define ISP_NVRAM_ADAPTER_CLK_SPEED(c) ISPBSMX(c, 16, 2, 0x01)
+#define ISP_NVRAM_SOFT_TERM_SUPPORT(c) ISPBSMX(c, 16, 3, 0x01)
+#define ISP_NVRAM_FLASH_ONBOARD(c) ISPBSMX(c, 16, 4, 0x01)
+#define ISP_NVRAM_FAST_MTTR_ENABLE(c) ISPBSMX(c, 22, 0, 0x01)
+
+#define ISP_NVRAM_TARGOFF 28
+#define ISP_NVARM_TARGSIZE 6
+#define _IxT(tgt, tidx) \
+ (ISP_NVRAM_TARGOFF + (ISP_NVARM_TARGSIZE * (tgt)) + (tidx))
+#define ISP_NVRAM_TGT_RENEG(c, t) ISPBSMX(c, _IxT(t, 0), 0, 0x01)
+#define ISP_NVRAM_TGT_QFRZ(c, t) ISPBSMX(c, _IxT(t, 0), 1, 0x01)
+#define ISP_NVRAM_TGT_ARQ(c, t) ISPBSMX(c, _IxT(t, 0), 2, 0x01)
+#define ISP_NVRAM_TGT_TQING(c, t) ISPBSMX(c, _IxT(t, 0), 3, 0x01)
+#define ISP_NVRAM_TGT_SYNC(c, t) ISPBSMX(c, _IxT(t, 0), 4, 0x01)
+#define ISP_NVRAM_TGT_WIDE(c, t) ISPBSMX(c, _IxT(t, 0), 5, 0x01)
+#define ISP_NVRAM_TGT_PARITY(c, t) ISPBSMX(c, _IxT(t, 0), 6, 0x01)
+#define ISP_NVRAM_TGT_DISC(c, t) ISPBSMX(c, _IxT(t, 0), 7, 0x01)
+#define ISP_NVRAM_TGT_EXEC_THROTTLE(c, t) ISPBSMX(c, _IxT(t, 1), 0, 0xff)
+#define ISP_NVRAM_TGT_SYNC_PERIOD(c, t) ISPBSMX(c, _IxT(t, 2), 0, 0xff)
+#define ISP_NVRAM_TGT_SYNC_OFFSET(c, t) ISPBSMX(c, _IxT(t, 3), 0, 0x0f)
+#define ISP_NVRAM_TGT_DEVICE_ENABLE(c, t) ISPBSMX(c, _IxT(t, 3), 4, 0x01)
+#define ISP_NVRAM_TGT_LUN_DISABLE(c, t) ISPBSMX(c, _IxT(t, 3), 5, 0x01)
+
+/*
+ * Qlogic 2XXX NVRAM is an array of 256 bytes.
+ *
+ * Some portion of the front of this is for general RISC engine parameters,
+ * mostly reflecting the state of the last INITIALIZE FIRMWARE mailbox command.
+ *
+ * This is followed by some general host adapter parameters, and ends with
+ * a checksum xor byte at offset 255. For non-byte entities data is stored
+ * in Little Endian order.
+ */
+#define ISP2100_NVRAM_SIZE 256
+/* ISP_NVRAM_VERSION is in same overall place */
+#define ISP2100_NVRAM_RISCVER(c) (c)[6]
+#define ISP2100_NVRAM_OPTIONS(c) (c)[8]
+#define ISP2100_NVRAM_MAXFRAMELENGTH(c) (((c)[10]) | ((c)[11] << 8))
+#define ISP2100_NVRAM_MAXIOCBALLOCATION(c) (((c)[12]) | ((c)[13] << 8))
+#define ISP2100_NVRAM_EXECUTION_THROTTLE(c) (((c)[14]) | ((c)[15] << 8))
+#define ISP2100_NVRAM_RETRY_COUNT(c) (c)[16]
+#define ISP2100_NVRAM_RETRY_DELAY(c) (c)[17]
+
+#define ISP2100_NVRAM_NODE_NAME(c) ( \
+ (((u_int64_t)(c)[18]) << 56) | \
+ (((u_int64_t)(c)[19]) << 48) | \
+ (((u_int64_t)(c)[20]) << 40) | \
+ (((u_int64_t)(c)[21]) << 32) | \
+ (((u_int64_t)(c)[22]) << 24) | \
+ (((u_int64_t)(c)[23]) << 16) | \
+ (((u_int64_t)(c)[24]) << 8) | \
+ (((u_int64_t)(c)[25]) << 0))
+#define ISP2100_NVRAM_HARDLOOPID(c) (c)[26]
+
+#define ISP2100_NVRAM_HBA_OPTIONS(c) (c)[70]
+#define ISP2100_NVRAM_HBA_DISABLE(c) ISPBSMX(c, 70, 0, 0x01)
+#define ISP2100_NVRAM_BIOS_DISABLE(c) ISPBSMX(c, 70, 1, 0x01)
+#define ISP2100_NVRAM_LUN_DISABLE(c) ISPBSMX(c, 70, 2, 0x01)
+#define ISP2100_NVRAM_ENABLE_SELECT_BOOT(c) ISPBSMX(c, 70, 3, 0x01)
+#define ISP2100_NVRAM_DISABLE_CODELOAD(c) ISPBSMX(c, 70, 4, 0x01)
+#define ISP2100_NVRAM_SET_CACHELINESZ(c) ISPBSMX(c, 70, 5, 0x01)
+
+#define ISP2100_NVRAM_BOOT_NODE_NAME(c) ( \
+ (((u_int64_t)(c)[72]) << 56) | \
+ (((u_int64_t)(c)[73]) << 48) | \
+ (((u_int64_t)(c)[74]) << 40) | \
+ (((u_int64_t)(c)[75]) << 32) | \
+ (((u_int64_t)(c)[76]) << 24) | \
+ (((u_int64_t)(c)[77]) << 16) | \
+ (((u_int64_t)(c)[78]) << 8) | \
+ (((u_int64_t)(c)[79]) << 0))
+
+#define ISP2100_NVRAM_BOOT_LUN(c) (c)[80]
+
#endif /* _ISPREG_H */
diff --git a/sys/dev/ic/ispvar.h b/sys/dev/ic/ispvar.h
index 01199e01ece..ab587d5c2fa 100644
--- a/sys/dev/ic/ispvar.h
+++ b/sys/dev/ic/ispvar.h
@@ -1,12 +1,13 @@
-/* $NetBSD: ispvar.h,v 1.4 1997/04/05 02:48:36 mjacob Exp $ */
-
+/* $OpenBSD: ispvar.h,v 1.2 1999/03/17 05:26:09 mjacob Exp $ */
+/* release_03_16_99 */
/*
* Soft Definitions for for Qlogic ISP SCSI adapters.
*
- * Copyright (c) 1997 by Matthew Jacob
+ *---------------------------------------
+ * Copyright (c) 1997, 1998 by Matthew Jacob
* NASA/Ames Research Center
* All rights reserved.
- *
+ *---------------------------------------
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -30,15 +31,27 @@
* 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.
+ *
*/
#ifndef _ISPVAR_H
#define _ISPVAR_H
+#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <dev/ic/ispmbox.h>
+#endif
+#ifdef __FreeBSD__
+#include <dev/isp/ispmbox.h>
+#endif
+#ifdef __linux__
+#include "ispmbox.h"
+#endif
+
+#define ISP_CORE_VERSION_MAJOR 1
+#define ISP_CORE_VERSION_MINOR 6
/*
- * Vector for MD code to provide specific services.
+ * Vector for bus specific code to provide specific services.
*/
struct ispsoftc;
struct ispmdvec {
@@ -46,14 +59,16 @@ struct ispmdvec {
void (*dv_wr_reg) __P((struct ispsoftc *, int, u_int16_t));
int (*dv_mbxdma) __P((struct ispsoftc *));
int (*dv_dmaset) __P((struct ispsoftc *,
- struct scsi_xfer *, ispreq_t *, u_int8_t *, u_int8_t));
+ ISP_SCSI_XFER_T *, ispreq_t *, u_int8_t *, u_int8_t));
void (*dv_dmaclr)
- __P((struct ispsoftc *, struct scsi_xfer *, u_int32_t));
+ __P((struct ispsoftc *, ISP_SCSI_XFER_T *, u_int32_t));
void (*dv_reset0) __P((struct ispsoftc *));
void (*dv_reset1) __P((struct ispsoftc *));
+ void (*dv_dregs) __P((struct ispsoftc *));
const u_int16_t *dv_ispfw; /* ptr to f/w */
u_int16_t dv_fwlen; /* length of f/w */
u_int16_t dv_codeorg; /* code ORG for f/w */
+ u_int16_t dv_fwrev; /* f/w revision */
/*
* Initial values for conf1 register
*/
@@ -62,74 +77,246 @@ struct ispmdvec {
};
#define MAX_TARGETS 16
-#define MAX_LUNS 8
+#ifdef ISP2100_FABRIC
+#define MAX_FC_TARG 256
+#else
+#define MAX_FC_TARG 126
+#endif
+#define DEFAULT_LOOPID 113
+
+/* queue length must be a power of two */
+#define QENTRY_LEN 64
+#define RQUEST_QUEUE_LEN MAXISPREQUEST
+#define RESULT_QUEUE_LEN (MAXISPREQUEST/2)
+#define ISP_QUEUE_ENTRY(q, idx) ((q) + ((idx) * QENTRY_LEN))
+#define ISP_QUEUE_SIZE(n) ((n) * QENTRY_LEN)
+#define ISP_NXT_QENTRY(idx, qlen) (((idx) + 1) & ((qlen)-1))
+#define ISP_QAVAIL(in, out, qlen) \
+ ((in == out)? (qlen - 1) : ((in > out)? \
+ ((qlen - 1) - (in - out)) : (out - in - 1)))
+/*
+ * SCSI Specific Host Adapter Parameters
+ */
+
+typedef struct {
+ u_int isp_req_ack_active_neg : 1,
+ isp_data_line_active_neg: 1,
+ isp_cmd_dma_burst_enable: 1,
+ isp_data_dma_burst_enabl: 1,
+ isp_fifo_threshold : 3,
+ isp_ultramode : 1,
+ isp_diffmode : 1,
+ isp_fast_mttr : 1,
+ isp_initiator_id : 4,
+ isp_async_data_setup : 4;
+ u_int16_t isp_selection_timeout;
+ u_int16_t isp_max_queue_depth;
+ u_int16_t isp_clock;
+ u_int8_t isp_tag_aging;
+ u_int8_t isp_bus_reset_delay;
+ u_int8_t isp_retry_count;
+ u_int8_t isp_retry_delay;
+ struct {
+ u_int
+ dev_enable : 1,
+ dev_announced : 1,
+ dev_update : 1,
+ dev_refresh : 1,
+ exc_throttle : 7,
+ sync_offset : 4,
+ sync_period : 8;
+ u_int16_t dev_flags; /* persistent device flags */
+ u_int16_t cur_dflags; /* current device flags */
+ } isp_devparam[MAX_TARGETS];
+} sdparam; /* scsi device parameters */
+
+/*
+ * Device Flags
+ */
+#define DPARM_DISC 0x8000
+#define DPARM_PARITY 0x4000
+#define DPARM_WIDE 0x2000
+#define DPARM_SYNC 0x1000
+#define DPARM_TQING 0x0800
+#define DPARM_ARQ 0x0400
+#define DPARM_QFRZ 0x0200
+#define DPARM_RENEG 0x0100
+#define DPARM_NARROW 0x0080 /* Possibly only available with >= 7.55 fw */
+#define DPARM_ASYNC 0x0040 /* Possibly only available with >= 7.55 fw */
+#define DPARM_DEFAULT (0xFF00 & ~DPARM_QFRZ)
+#define DPARM_SAFE_DFLT (DPARM_DEFAULT & ~(DPARM_WIDE|DPARM_SYNC|DPARM_TQING))
+
+
+#define ISP_20M_SYNCPARMS 0x080c
+#define ISP_10M_SYNCPARMS 0x0c19
+#define ISP_08M_SYNCPARMS 0x0c25
+#define ISP_05M_SYNCPARMS 0x0c32
+#define ISP_04M_SYNCPARMS 0x0c41
+
+/*
+ * Fibre Channel Specifics
+ */
+typedef struct {
+ u_int64_t isp_wwn; /* WWN of adapter */
+ u_int8_t isp_loopid; /* hard loop id */
+ u_int8_t isp_alpa; /* ALPA */
+ u_int8_t isp_execthrottle;
+ u_int8_t isp_retry_delay;
+ u_int8_t isp_retry_count;
+ u_int8_t isp_fwstate; /* ISP F/W state */
+ u_int16_t isp_maxalloc;
+ u_int16_t isp_maxfrmlen;
+ u_int16_t isp_fwoptions;
+ /*
+ * Port Data Base
+ */
+ isp_pdb_t isp_pdb[MAX_FC_TARG];
+
+ /*
+ * Scratch DMA mapped in area to fetch Port Database stuff, etc.
+ */
+ volatile caddr_t isp_scratch;
+ u_int32_t isp_scdma;
+} fcparam;
+
+#define ISP2100_SCRLEN 0x100
+
+#define FW_CONFIG_WAIT 0x0000
+#define FW_WAIT_AL_PA 0x0001
+#define FW_WAIT_LOGIN 0x0002
+#define FW_READY 0x0003
+#define FW_LOSS_OF_SYNC 0x0004
+#define FW_ERROR 0x0005
+#define FW_REINIT 0x0006
+#define FW_NON_PART 0x0007
+
+#ifdef ISP_TARGET_MODE
+/*
+ * Some temporary Target Mode definitions
+ */
+typedef struct tmd_cmd {
+ u_int8_t cd_iid; /* initiator */
+ u_int8_t cd_tgt; /* target */
+ u_int8_t cd_lun; /* LUN for this command */
+ u_int8_t cd_state;
+ u_int8_t cd_cdb[16]; /* command bytes */
+ u_int8_t cd_sensedata[20];
+ u_int16_t cd_rxid;
+ u_int32_t cd_datalen;
+ u_int32_t cd_totbytes;
+ void * cd_hba;
+} tmd_cmd_t;
-#define RQUEST_QUEUE_LEN 256
-#define RESULT_QUEUE_LEN (RQUEST_QUEUE_LEN >> 3)
-#define QENTRY_LEN 64
+/*
+ * Async Target Mode Event Definitions
+ */
+#define TMD_BUS_RESET 0
+#define TMD_BDR 1
-#define ISP_QUEUE_ENTRY(q, idx) ((q) + ((idx) * QENTRY_LEN))
-#define ISP_QUEUE_SIZE(n) ((n) * QENTRY_LEN)
+/*
+ * Immediate Notify data structure.
+ */
+#define NOTIFY_MSGLEN 5
+typedef struct {
+ u_int8_t nt_iid; /* initiator */
+ u_int8_t nt_tgt; /* target */
+ u_int8_t nt_lun; /* LUN for this command */
+ u_int8_t nt_msg[NOTIFY_MSGLEN]; /* SCSI message byte(s) */
+} tmd_notify_t;
+
+#endif
/*
* Soft Structure per host adapter
*/
struct ispsoftc {
- struct device isp_dev;
+ /*
+ * Platform (OS) specific data
+ */
+ struct isposinfo isp_osinfo;
+
+ /*
+ * Pointer to bus specific data
+ */
struct ispmdvec * isp_mdvec;
-#define isp_name isp_dev.dv_xname
- struct scsi_link isp_link;
- u_int8_t isp_max_target;
- u_int8_t isp_state;
+
/*
- * Host Adapter Parameters, nominally stored in NVRAM
+ * Mostly nonvolatile state, debugging, etc..
*/
- u_int16_t isp_adapter_enabled : 1,
- isp_req_ack_active_neg : 1,
- isp_data_line_active_neg: 1,
- isp_cmd_dma_burst_enable: 1,
- isp_data_dma_burst_enabl: 1,
- isp_fifo_threshold : 2,
- : 1,
- isp_initiator_id : 4,
- isp_async_data_setup : 4;
- u_int16_t isp_selection_timeout;
- u_int16_t isp_max_queue_depth;
- u_int8_t isp_tag_aging;
- u_int8_t isp_bus_reset_delay;
- u_int8_t isp_retry_count;
- u_int8_t isp_retry_delay;
- struct {
- u_int8_t dev_flags; /* Device Flags - see below */
- u_int8_t exc_throttle;
- u_int8_t sync_period;
- u_int8_t sync_offset : 4,
- dev_enable : 1;
- } isp_devparam[MAX_TARGETS];
+
+ u_int : 8,
+ isp_confopts : 8,
+ : 1,
+ isp_used : 1,
+ isp_dblev : 3,
+ isp_gotdparms : 1,
+ isp_dogactive : 1,
+ isp_bustype : 1, /* BUS Implementation */
+ isp_type : 8; /* HBA Type and Revision */
+
+ u_int16_t isp_fwrev; /* Running F/W revision */
+ u_int16_t isp_romfw_rev; /* 'ROM' F/W revision */
+ void * isp_param;
+
+ /*
+ * Volatile state
+ */
+
+ volatile u_int
+ : 19,
+ isp_state : 3,
+ isp_sendmarker : 1, /* send a marker entry */
+ isp_update : 1, /* update parameters */
+ isp_nactive : 9; /* how many commands active */
+
/*
- * Result and Request Queues.
+ * Result and Request Queue indices.
*/
+ volatile u_int8_t isp_reqodx; /* index of last ISP pickup */
volatile u_int8_t isp_reqidx; /* index of next request */
volatile u_int8_t isp_residx; /* index of next result */
- volatile u_int8_t isp_sendmarker;
- volatile u_int8_t isp_seqno;
+ volatile u_int8_t isp_seqno; /* rolling sequence # */
+
/*
* Sheer laziness, but it gets us around the problem
* where we don't have a clean way of remembering
- * which scsi_xfer is bound to which ISP queue entry.
+ * which transaction is bound to which ISP queue entry.
*
* There are other more clever ways to do this, but,
* jeez, so I blow a couple of KB per host adapter...
* and it *is* faster.
*/
- volatile struct scsi_xfer *isp_xflist[RQUEST_QUEUE_LEN];
+ ISP_SCSI_XFER_T *isp_xflist[RQUEST_QUEUE_LEN];
+
/*
- * request/result queue
+ * request/result queues and dma handles for them.
*/
volatile caddr_t isp_rquest;
volatile caddr_t isp_result;
u_int32_t isp_rquest_dma;
u_int32_t isp_result_dma;
+
+#ifdef ISP_TARGET_MODE
+ /*
+ * Vectors for handling target mode support.
+ *
+ * isp_tmd_newcmd is for feeding a newly arrived command to some
+ * upper layer.
+ *
+ * isp_tmd_event is for notifying some upper layer that an event has
+ * occurred that is not necessarily tied to any target (e.g., a SCSI
+ * Bus Reset).
+ *
+ * isp_tmd_notify is for notifying some upper layer that some
+ * event is now occurring that is either pertinent for a specific
+ * device or for a specific command (e.g., BDR or ABORT TAG).
+ *
+ * It is left undefined (for now) how pools of commands are managed.
+ */
+ void (*isp_tmd_newcmd) __P((void *, tmd_cmd_t *));
+ void (*isp_tmd_event) __P((void *, int));
+ void (*isp_tmd_notify) __P((void *, tmd_notify_t *));
+#endif
};
/*
@@ -140,24 +327,40 @@ struct ispsoftc {
#define ISP_INITSTATE 2
#define ISP_RUNSTATE 3
-
/*
- * Device Flags
+ * ISP Configuration Options
*/
-#define DPARM_DISC 0x80
-#define DPARM_PARITY 0x40
-#define DPARM_WIDE 0x20
-#define DPARM_SYNC 0x10
-#define DPARM_TQING 0x08
-#define DPARM_ARQ 0x04
-#define DPARM_QFRZ 0x02
-#define DPARM_RENEG 0x01
+#define ISP_CFG_NORELOAD 0x80 /* don't download f/w */
+#define ISP_CFG_NONVRAM 0x40 /* ignore NVRAM */
-#define DPARM_DEFAULT (0xff & ~DPARM_QFRZ)
+#define ISP_FW_REV(maj, min) ((maj) << 10| (min))
+/*
+ * Bus (implementation) types
+ */
+#define ISP_BT_PCI 0 /* PCI Implementations */
+#define ISP_BT_SBUS 1 /* SBus Implementations */
+
+/*
+ * Chip Types
+ */
+#define ISP_HA_SCSI 0xf
+#define ISP_HA_SCSI_UNKNOWN 0x1
+#define ISP_HA_SCSI_1020 0x2
+#define ISP_HA_SCSI_1020A 0x3
+#define ISP_HA_SCSI_1040 0x4
+#define ISP_HA_SCSI_1040A 0x5
+#define ISP_HA_SCSI_1040B 0x6
+#define ISP_HA_SCSI_1080 0xe
+#define ISP_HA_FC 0xf0
+#define ISP_HA_FC_2100 0x10
+
+#define IS_SCSI(isp) (isp->isp_type & ISP_HA_SCSI)
+#define IS_1080(isp) (isp->isp_type == ISP_HA_SCSI_1080)
+#define IS_FC(isp) (isp->isp_type & ISP_HA_FC)
/*
- * Macros to read, write ISP registers through MD code
+ * Macros to read, write ISP registers through bus specific code.
*/
#define ISP_READ(isp, reg) \
@@ -180,7 +383,8 @@ struct ispsoftc {
if ((isp)->isp_mdvec->dv_reset0) (*(isp)->isp_mdvec->dv_reset0)((isp))
#define ISP_RESET1(isp) \
if ((isp)->isp_mdvec->dv_reset1) (*(isp)->isp_mdvec->dv_reset1)((isp))
-
+#define ISP_DUMPREGS(isp) \
+ if ((isp)->isp_mdvec->dv_dregs) (*(isp)->isp_mdvec->dv_dregs)((isp))
#define ISP_SETBITS(isp, reg, val) \
(*(isp)->isp_mdvec->dv_wr_reg)((isp), (reg), ISP_READ((isp), (reg)) | (val))
@@ -191,10 +395,10 @@ struct ispsoftc {
/*
* Function Prototypes
*/
+
/*
- * Reset Hardware.
- *
- * Only looks at sc_dev.dv_xname, sc_iot and sc_ioh fields.
+ * Reset Hardware. Totally. Assumes that you'll follow this with
+ * a call to isp_init.
*/
void isp_reset __P((struct ispsoftc *));
@@ -204,21 +408,65 @@ void isp_reset __P((struct ispsoftc *));
void isp_init __P((struct ispsoftc *));
/*
- * Complete attachment of Hardware
+ * Reset the ISP and call completion for any orphaned commands.
*/
-void isp_attach __P((struct ispsoftc *));
+void isp_restart __P((struct ispsoftc *));
/*
- * Free any associated resources prior to decommissioning.
+ * Interrupt Service Routine
*/
-void isp_uninit __P((struct ispsoftc *));
+int isp_intr __P((void *));
/*
- * Interrupt Service Routine
+ * Command Entry Point
+ */
+int32_t ispscsicmd __P((ISP_SCSI_XFER_T *));
+
+/*
+ * Platform Dependent to External to Internal Control Function
+ *
+ * For: Aborting a running command - arg is an ISP_SCSI_XFER_T *
+ * Resetting a Device - arg is target to reset
+ * Resetting a BUS - arg is ignored
+ * Updating parameters - arg is ignored
+ *
+ * First argument is this instance's softc pointer.
+ * Second argument is an index into xflist array.
+ * Assumes all locks must be held already.
+ */
+typedef enum {
+ ISPCTL_RESET_BUS,
+ ISPCTL_RESET_DEV,
+ ISPCTL_ABORT_CMD,
+ ISPCTL_UPDATE_PARAMS,
+ ISPCTL_FCLINK_TEST
+} ispctl_t;
+int isp_control __P((struct ispsoftc *, ispctl_t, void *));
+
+
+/*
+ * Platform Dependent to Internal to External Control Function
+ * (each platform must provide such a function)
+ *
+ * For: Announcing Target Paramter Changes (arg is target)
+ *
+ * Assumes all locks are held.
*/
-int isp_intr __P((void *));
+typedef enum {
+ ISPASYNC_NEW_TGT_PARAMS,
+ ISPASYNC_BUS_RESET, /* Bus Reset */
+ ISPASYNC_LOOP_DOWN, /* Obvious FC only */
+ ISPASYNC_LOOP_UP, /* "" */
+ ISPASYNC_PDB_CHANGE_COMPLETE, /* "" */
+ ISPASYNC_CHANGE_NOTIFY /* "" */
+} ispasync_t;
+int isp_async __P((struct ispsoftc *, ispasync_t, void *));
+/*
+ * lost command routine (XXXX IN TRANSITION XXXX)
+ */
+void isp_lostcmd __P((struct ispsoftc *, ISP_SCSI_XFER_T *));
#endif /* _ISPVAR_H */