summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authormjacob <mjacob@cvs.openbsd.org>2000-02-20 21:22:42 +0000
committermjacob <mjacob@cvs.openbsd.org>2000-02-20 21:22:42 +0000
commit843be39a687253a9894847550ed56ea58510c179 (patch)
tree5ba8385712451adffcce024f1c84487e320e5d2d /sys
parent507037610dbda92ebe936b00eda0be017503a7d8 (diff)
Add 12160 (Ultra3) support. Add files and changes for target mode support.
Do some SNS fabric suppor tchanges. Roll revision levels. Tested on GENERIC i386 && sparc.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ic/isp.c1184
-rw-r--r--sys/dev/ic/isp_inline.h23
-rw-r--r--sys/dev/ic/isp_openbsd.c76
-rw-r--r--sys/dev/ic/isp_openbsd.h8
-rw-r--r--sys/dev/ic/isp_target.c1228
-rw-r--r--sys/dev/ic/isp_target.h654
-rw-r--r--sys/dev/ic/isp_tpublic.h301
-rw-r--r--sys/dev/ic/ispmbox.h54
-rw-r--r--sys/dev/ic/ispreg.h80
-rw-r--r--sys/dev/ic/ispvar.h37
10 files changed, 3161 insertions, 484 deletions
diff --git a/sys/dev/ic/isp.c b/sys/dev/ic/isp.c
index e5eaeb54805..c7303a59778 100644
--- a/sys/dev/ic/isp.c
+++ b/sys/dev/ic/isp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: isp.c,v 1.12 2000/01/09 22:44:27 mjacob Exp $ */
+/* $OpenBSD: isp.c,v 1.13 2000/02/20 21:22:40 mjacob Exp $ */
/*
* Machine and OS Independent (well, as best as possible)
* code for the Qlogic ISP SCSI adapters.
@@ -95,6 +95,11 @@ static void isp_update_bus __P((struct ispsoftc *, int));
static void isp_setdfltparm __P((struct ispsoftc *, int));
static int isp_read_nvram __P((struct ispsoftc *));
static void isp_rdnvram_word __P((struct ispsoftc *, int, u_int16_t *));
+static void isp_parse_nvram_1020 __P((struct ispsoftc *, u_int8_t *));
+static void isp_parse_nvram_1080 __P((struct ispsoftc *, int, u_int8_t *));
+static void isp_parse_nvram_12160 __P((struct ispsoftc *, int, u_int8_t *));
+static void isp_parse_nvram_2100 __P((struct ispsoftc *, u_int8_t *));
+
/*
* Reset Hardware.
@@ -188,7 +193,15 @@ isp_reset(isp)
isp->isp_clock = 100;
- revname = "1080";
+ if (IS_1280(isp))
+ revname = "1280";
+ else if (IS_1080(isp))
+ revname = "1080";
+ else if (IS_12160(isp))
+ revname = "12160";
+ else
+ revname = "<UNKLVD>";
+
l = ISP_READ(isp, SXP_PINS_DIFF) & ISP1080_MODE_MASK;
switch (l) {
case ISP1080_LVD_MODE:
@@ -209,9 +222,8 @@ isp_reset(isp)
break;
}
- if (IS_1280(isp)) {
+ if (IS_DUALBUS(isp)) {
sdp++;
- revname[1] = '2';
l = ISP_READ(isp, SXP_PINS_DIFF|SXP_BANK1_SELECT);
l &= ISP1080_MODE_MASK;
switch(l) {
@@ -793,22 +805,16 @@ isp_scsi_init(isp)
*
* Ultra2 F/W always has had fast posting (and LVD transitions)
*
- * Ultra and older (i.e., SBus) cards may not. Assume SBus cards
- * do not, and only guess that 4.55.0 <= x < 5.0.0 (initiator
- * only) and x >= 7.55 (initiator/target) has fast posting.
+ * Ultra and older (i.e., SBus) cards may not. It's just safer
+ * to assume not for them.
*/
mbs.param[0] = MBOX_SET_FW_FEATURES;
mbs.param[1] = 0;
if (IS_ULTRA2(isp))
mbs.param[1] |= FW_FEATURE_LVD_NOTIFY;
-#ifndef ISP_NO_FASTPOST_SCSI
- if ((ISP_FW_REVX(isp->isp_fwrev) >= ISP_FW_REV(4, 55, 0) &&
- (ISP_FW_REVX(isp->isp_fwrev) < ISP_FW_REV(5, 0, 0))) ||
- (ISP_FW_REVX(isp->isp_fwrev) >= ISP_FW_REV(7, 55, 0))) {
+ if (IS_ULTRA2(isp) || IS_1240(isp))
mbs.param[1] |= FW_FEATURE_FAST_POST;
- }
-#endif
if (mbs.param[1] != 0) {
u_int16_t sfeat = mbs.param[1];
isp_mboxcmd(isp, &mbs);
@@ -1007,7 +1013,6 @@ isp_fibre_init(isp)
#else
fcp->isp_fwoptions = 0;
#endif
-
fcp->isp_fwoptions |= ICBOPT_FAIRNESS;
/*
* If this is a 2100 < revision 5, we have to turn off FAIRNESS.
@@ -1059,7 +1064,19 @@ isp_fibre_init(isp)
icbp->icb_retry_delay = fcp->isp_retry_delay;
icbp->icb_retry_count = fcp->isp_retry_count;
icbp->icb_hardaddr = loopid;
- icbp->icb_logintime = 30; /* 30 second login timeout */
+#ifdef PRET_A_PORTE
+ if (IS_2200(isp)) {
+ icbp->icb_fwoptions |= ICBOPT_EXTENDED;
+ /*
+ * Prefer or force Point-To-Point instead Loop?
+ */
+ if (isp->isp_confopts & ISP_CFG_NPORT)
+ icbp->icb_xfwoptions = ICBXOPT_PTP_2_LOOP;
+ else
+ icbp->icb_xfwoptions = ICBXOPT_LOOP_2_PTP;
+ }
+#endif
+ icbp->icb_logintime = 60; /* 60 second login timeout */
if (fcp->isp_nodewwn) {
u_int64_t pn;
@@ -1238,7 +1255,6 @@ isp_fclink_test(isp, waitdelay)
"N-Port to N-Port",
"F Port"
};
- char *tname;
mbreg_t mbs;
int count, topo = -1;
u_int8_t lwfs;
@@ -1283,19 +1299,13 @@ isp_fclink_test(isp, waitdelay)
return (-1);
}
fcp->isp_loopid = mbs.param[1];
- if (isp->isp_type == ISP_HA_FC_2200) {
- if (ISP_FW_REVX(isp->isp_fwrev) >= ISP_FW_REV(2, 0, 14)) {
- topo = (int) mbs.param[6];
- }
- } else if (isp->isp_type == ISP_HA_FC_2100) {
- if (ISP_FW_REVX(isp->isp_fwrev) >= ISP_FW_REV(1, 17, 26)) {
- topo = (int) mbs.param[6];
- }
+ if (IS_2200(isp)) {
+ topo = (int) mbs.param[6];
+ if (topo < 0 || topo > 3)
+ topo = 0;
+ } else {
+ topo = 0;
}
- if (topo < 0 || topo > 3)
- tname = "unknown";
- else
- tname = toponames[topo];
/*
* If we're not on a fabric, the low 8 bits will be our AL_PA.
@@ -1305,11 +1315,16 @@ isp_fclink_test(isp, waitdelay)
#if defined(ISP2100_FABRIC)
fcp->isp_onfabric = 0;
if (isp_getpdb(isp, FL_PORT_ID, &pdb) == 0) {
+
+ if (IS_2100(isp))
+ topo = 1;
+
fcp->isp_portid = mbs.param[2] | (((int)mbs.param[3]) << 16);
fcp->isp_onfabric = 1;
CFGPRINTF("%s: Loop ID %d, AL_PA 0x%x, Port ID 0x%x Loop State "
- "0x%x topology %s\n", isp->isp_name, fcp->isp_loopid,
- fcp->isp_alpa, fcp->isp_portid, fcp->isp_loopstate, tname);
+ "0x%x topology '%s'\n", isp->isp_name, fcp->isp_loopid,
+ fcp->isp_alpa, fcp->isp_portid, fcp->isp_loopstate,
+ toponames[topo]);
/*
* Make sure we're logged out of all fabric devices.
@@ -1329,10 +1344,9 @@ isp_fclink_test(isp, waitdelay)
}
} else
#endif
- CFGPRINTF("%s: Loop ID %d, ALPA 0x%x Loop State 0x%x topology %s\n",
+ CFGPRINTF("%s: Loop ID %d, ALPA 0x%x Loop State 0x%x topology '%s'\n",
isp->isp_name, fcp->isp_loopid, fcp->isp_alpa, fcp->isp_loopstate,
- tname);
- fcp->loop_seen_once = 1;
+ toponames[topo]);
return (0);
}
@@ -1394,6 +1408,7 @@ isp_pdb_sync(isp, target)
* FL_PORT_ID times).
*/
tport = fcp->tport;
+
/*
* make sure the temp port database is clean...
*/
@@ -1466,7 +1481,7 @@ isp_pdb_sync(isp, target)
* use) and then compare it to our saved database which
* never shifts.
*/
- if (isp_same_lportdb(lp, &fcp->portdb[target])) {
+ if (target >= 0 && isp_same_lportdb(lp, &fcp->portdb[target])) {
lp->valid = 1;
}
}
@@ -1635,8 +1650,9 @@ isp_pdb_sync(isp, target)
/*
* Now log in any fabric devices
*/
- for (lp = &fcp->portdb[FC_SNS_ID+1];
+ for (lim = FC_SNS_ID+1, lp = &fcp->portdb[FC_SNS_ID+1];
lp < &fcp->portdb[MAX_FC_TARG]; lp++) {
+ u_int32_t portid;
mbreg_t mbs;
/*
@@ -1644,67 +1660,77 @@ isp_pdb_sync(isp, target)
*/
if (lp->port_wwn == 0)
continue;
+
/*
* Don't try to log into yourself.
*/
- if (lp->portid == fcp->isp_portid)
+ if ((portid = lp->portid) == fcp->isp_portid)
continue;
/*
- * Force a logout.
+ * Force a logout if we were logged in.
*/
- lp->loopid = loopid = lp - fcp->portdb;
- mbs.param[0] = MBOX_FABRIC_LOGOUT;
- mbs.param[1] = lp->loopid << 8;
- mbs.param[2] = 0;
- mbs.param[3] = 0;
- isp_mboxcmd(isp, &mbs);
+ if (lp->valid) {
+ mbs.param[0] = MBOX_FABRIC_LOGOUT;
+ mbs.param[1] = lp->loopid << 8;
+ mbs.param[2] = 0;
+ mbs.param[3] = 0;
+ isp_mboxcmd(isp, &mbs);
+ lp->valid = 0;
+ }
/*
* And log in....
*/
- mbs.param[0] = MBOX_FABRIC_LOGIN;
- mbs.param[1] = lp->loopid << 8;
- mbs.param[2] = lp->portid >> 16;
- mbs.param[3] = lp->portid & 0xffff;
- isp_mboxcmd(isp, &mbs);
- switch (mbs.param[0]) {
- case MBOX_COMMAND_COMPLETE:
- break;
- case MBOX_COMMAND_ERROR:
- switch (mbs.param[1]) {
- case 1:
- PRINTF("%s: no loop\n", isp->isp_name);
- break;
- case 2:
- PRINTF("%s: IOCB buffer could not be alloced\n",
- isp->isp_name);
- break;
- case 3:
- PRINTF("%s: could not alloc xchange resource\n",
- isp->isp_name);
- break;
- case 4:
- PRINTF("%s: ELS timeout\n", isp->isp_name);
- break;
- case 5:
- PRINTF("%s: no fabric port\n", isp->isp_name);
+ loopid = lp - fcp->portdb;
+ lp->loopid = 0;
+ lim = 0;
+ do {
+ mbs.param[0] = MBOX_FABRIC_LOGIN;
+ mbs.param[1] = loopid << 8;
+ if (IS_2200(isp)) {
+ /* only issue a PLOGI if not logged in */
+ mbs.param[1] |= 0x1;
+ }
+ mbs.param[2] = portid >> 16;
+ mbs.param[3] = portid & 0xffff;
+ isp_mboxcmd(isp, &mbs);
+ switch (mbs.param[0]) {
+ case MBOX_LOOP_ID_USED:
+ /*
+ * Try the next available loop id.
+ */
+ loopid++;
break;
- case 6:
- PRINTF("%s: remote device cannot be a target\n",
- isp->isp_name);
+ case MBOX_PORT_ID_USED:
+ /*
+ * This port is already logged in.
+ * Snaffle the loop id it's using.
+ */
+ if ((loopid = mbs.param[1]) == 0) {
+ lim = -1;
+ }
+ /* FALLTHROUGH */
+ case MBOX_COMMAND_COMPLETE:
+ lp->loopid = loopid;
+ lim = 1;
break;
+ case MBOX_COMMAND_ERROR:
+ PRINTF("%s: command error in PLOGI (0x%x)\n",
+ isp->isp_name, mbs.param[1]);
+ /* FALLTHROUGH */
+ case MBOX_ALL_IDS_USED: /* We're outta IDs */
default:
+ lim = -1;
break;
}
+ } while (lim == 0 && loopid < MAX_FC_TARG);
+ if (lim < 0)
continue;
- default:
- continue;
- }
lp->valid = 1;
lp->fabdev = 1;
- if (isp_getpdb(isp, loopid, &pdb) != 0) {
+ if (isp_getpdb(isp, lp->loopid, &pdb) != 0) {
/*
* Be kind...
*/
@@ -1722,7 +1748,6 @@ isp_pdb_sync(isp, target)
lp->roles =
(pdb.pdb_prli_svc3 & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT;
lp->portid = BITS2WORD(pdb.pdb_portid_bits);
- lp->loopid = loopid;
lp->node_wwn =
(((u_int64_t)pdb.pdb_nodename[0]) << 56) |
(((u_int64_t)pdb.pdb_nodename[1]) << 48) |
@@ -1745,6 +1770,7 @@ isp_pdb_sync(isp, target)
* Check to make sure this all makes sense.
*/
if (lp->node_wwn && lp->port_wwn) {
+ loopid = lp - fcp->portdb;
(void) isp_async(isp, ISPASYNC_PDB_CHANGED, &loopid);
continue;
}
@@ -1758,6 +1784,12 @@ isp_pdb_sync(isp, target)
isp_mboxcmd(isp, &mbs);
}
#endif
+ /*
+ * If we get here, we've for sure seen not only a valid loop
+ * but know what is or isn't on it, so mark this for usage
+ * in ispscsicmd.
+ */
+ fcp->loop_seen_once = 1;
return (0);
}
@@ -1798,6 +1830,8 @@ isp_scan_fabric(isp)
MemoryBarrier();
isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+ IDPRINTF(1, ("%s: SNS failed (0x%x)\n", isp->isp_name,
+ mbs.param[0]));
return (-1);
}
ISP_UNSWIZZLE_SNS_RSP(isp, resp, SNS_GAN_RESP_SIZE >> 1);
@@ -1849,13 +1883,15 @@ ispscsicmd(xs)
}
/*
- * We *could* do the different sequence type that has close
- * to the whole Queue Entry for the command...
+ * Check command CDB length, etc.. We really are limited to 16 bytes
+ * for Fibre Channel, but can do up to 44 bytes in parallel SCSI,
+ * but probably only if we're running fairly new firmware (we'll
+ * let the old f/w choke on an extended command queue entry).
*/
- if (XS_CDBLEN(xs) > (IS_FC(isp) ? 16 : 12) || XS_CDBLEN(xs) == 0) {
+ if (XS_CDBLEN(xs) > (IS_FC(isp)? 16 : 44) || XS_CDBLEN(xs) == 0) {
PRINTF("%s: unsupported cdb length (%d, CDB[0]=0x%x)\n",
- isp->isp_name, XS_CDBLEN(xs), XS_CDBP(xs)[0]);
+ isp->isp_name, XS_CDBLEN(xs), XS_CDBP(xs)[0] & 0xff);
XS_SETERR(xs, HBA_BOTCH);
return (CMD_COMPLETE);
}
@@ -1908,11 +1944,17 @@ ispscsicmd(xs)
* If our loop state is such that we haven't yet received
* a "Port Database Changed" notification (after a LIP or
* a Loop Reset or firmware initialization), then defer
- * sending commands for a little while.
+ * sending commands for a little while, but only if we've
+ * seen a valid loop at one point (otherwise we can get
+ * stuck at initialization time).
*/
if (fcp->isp_loopstate < LOOP_PDB_RCVD) {
XS_SETERR(xs, HBA_SELTIMEOUT);
- return (CMD_RQLATER);
+ if (fcp->loop_seen_once) {
+ return (CMD_RQLATER);
+ } else {
+ return (CMD_COMPLETE);
+ }
}
/*
@@ -1999,7 +2041,10 @@ ispscsicmd(xs)
if (IS_FC(isp)) {
reqp->req_header.rqs_entry_type = RQSTYPE_T2RQS;
} else {
- reqp->req_header.rqs_entry_type = RQSTYPE_REQUEST;
+ if (XS_CDBLEN(xs) > 12)
+ reqp->req_header.rqs_entry_type = RQSTYPE_CMDONLY;
+ else
+ reqp->req_header.rqs_entry_type = RQSTYPE_REQUEST;
}
reqp->req_header.rqs_flags = 0;
reqp->req_header.rqs_seqno = 0;
@@ -2112,16 +2157,17 @@ isp_control(isp, ctl, arg)
* Issue a bus reset.
*/
mbs.param[0] = MBOX_BUS_RESET;
+ mbs.param[2] = 0;
if (IS_SCSI(isp)) {
mbs.param[1] =
((sdparam *) isp->isp_param)->isp_bus_reset_delay;
if (mbs.param[1] < 2)
mbs.param[1] = 2;
bus = *((int *) arg);
- mbs.param[2] = bus;
+ if (IS_DUALBUS(isp))
+ mbs.param[2] = bus;
} else {
mbs.param[1] = 10;
- mbs.param[2] = 0;
bus = 0;
}
isp->isp_sendmarker = 1 << bus;
@@ -2174,8 +2220,8 @@ isp_control(isp, ctl, arg)
mbs.param[1] =
(bus << 15) | (XS_TGT(xs) << 8) | XS_LUN(xs);
}
- mbs.param[2] = handle >> 16;
- mbs.param[3] = handle & 0xffff;
+ mbs.param[3] = handle >> 16;
+ mbs.param[2] = handle & 0xffff;
isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
PRINTF("%s: isp_control MBOX_ABORT failure (code %x)\n",
@@ -2192,12 +2238,25 @@ isp_control(isp, ctl, arg)
case ISPCTL_FCLINK_TEST:
return (isp_fclink_test(isp, FC_FW_READY_DELAY));
-#ifdef ISP_TARGET_MODE
- case ISPCTL_ENABLE_LUN:
- return (isp_modify_lun, 1, arg));
- case ISPCTL_MODIFY_LUN:
- return (isp_modify_lun, 0, arg));
+ case ISPCTL_PDB_SYNC:
+ return (isp_pdb_sync(isp, -1));
+
+#ifdef ISP_TARGET_MODE
+ case ISPCTL_TOGGLE_TMODE:
+ if (IS_SCSI(isp)) {
+ int ena = *(int *)arg;
+ mbs.param[0] = MBOX_ENABLE_TARGET_MODE;
+ mbs.param[1] = (ena)? ENABLE_TARGET_FLAG : 0;
+ isp_mboxcmd(isp, &mbs);
+ if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
+ PRINTF("%s: cannot %sable target mode (0x%x)\n",
+ isp->isp_name, ena? "en" : "dis",
+ mbs.param[0]);
+ break;
+ }
+ }
+ return (0);
#endif
}
return (-1);
@@ -2289,12 +2348,12 @@ isp_intr(arg)
MemoryBarrier();
/*
* Do any appropriate unswizzling of what the Qlogic f/w has
- * written into memory so it makes sense to us.
+ * written into memory so it makes sense to us. This is a
+ * per-platform thing.
*/
ISP_UNSWIZZLE_RESPONSE(isp, sp);
if (sp->req_header.rqs_entry_type != RQSTYPE_RESPONSE) {
if (isp_handle_other_response(isp, sp, &optr) == 0) {
- ISP_WRITE(isp, INMAILBOX5, optr);
continue;
}
/*
@@ -2303,7 +2362,6 @@ isp_intr(arg)
* not, something bad has happened.
*/
if (sp->req_header.rqs_entry_type != RQSTYPE_REQUEST) {
- ISP_WRITE(isp, INMAILBOX5, optr);
PRINTF("%s: not RESPONSE in RESPONSE Queue "
"(type 0x%x) @ idx %d (next %d)\n",
isp->isp_name,
@@ -2384,11 +2442,14 @@ isp_intr(arg)
isp->isp_update |= (1 << XS_CHANNEL(xs));
}
} else {
- if (XS_STS(xs) == SCSI_CHECK) {
+ if (sp->req_scsi_status & RQCS_SV) {
+ int amt = min(XS_SNSLEN(xs), sp->req_sense_len);
+ MEMCPY(XS_SNSP(xs), sp->req_sense_data, amt);
XS_SNS_IS_VALID(xs);
- MEMCPY(XS_SNSP(xs), sp->req_sense_data,
- XS_SNSLEN(xs));
sp->req_state_flags |= RQSF_GOT_SENSE;
+ } else if (XS_STS(xs) == SCSI_CHECK) {
+ IDPRINTF(1, ("%s: check condition with no sense"
+ " data\n", isp->isp_name));
}
}
if (XS_NOERR(xs) && XS_STS(xs) == SCSI_BUSY) {
@@ -2431,6 +2492,10 @@ isp_intr(arg)
ISP_DMAFREE(isp, xs, sp->req_handle);
}
/*
+ * Let the platforms cope.
+ */
+#if 0
+ /*
* 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
@@ -2443,6 +2508,7 @@ isp_intr(arg)
XS_SETERR(xs, HBA_ARQFAIL);
}
}
+#endif
if ((isp->isp_dblev >= 5) ||
(isp->isp_dblev > 2 && !XS_NOERR(xs))) {
PRINTF("%s(%d.%d): FIN dl%d resid%d STS %x",
@@ -2506,7 +2572,7 @@ isp_parse_async(isp, mbox)
case ASYNC_BUS_RESET:
isp->isp_sendmarker = (1 << bus);
#ifdef ISP_TARGET_MODE
- isp_target_async(isp, bus, ASYNC_BUS_RESET);
+ isp_target_async(isp, bus, mbox);
#endif
isp_async(isp, ISPASYNC_BUS_RESET, &bus);
break;
@@ -2540,7 +2606,7 @@ isp_parse_async(isp, mbox)
isp->isp_name, bus);
isp->isp_sendmarker = (1 << bus);
#ifdef ISP_TARGET_MODE
- isp_target_async(isp, bus, ASYNC_TIMEOUT_RESET);
+ isp_target_async(isp, bus, mbox);
#endif
break;
@@ -2548,7 +2614,7 @@ isp_parse_async(isp, mbox)
PRINTF("%s: device reset on bus %d\n", isp->isp_name, bus);
isp->isp_sendmarker = 1 << bus;
#ifdef ISP_TARGET_MODE
- isp_target_async(isp, bus, ASYNC_DEVICE_RESET);
+ isp_target_async(isp, bus, mbox);
#endif
break;
@@ -2626,6 +2692,9 @@ isp_parse_async(isp, mbox)
isp->isp_sendmarker = 1;
isp_mark_getpdb_all(isp);
IDPRINTF(1, ("%s: LIP occurred\n", isp->isp_name));
+#ifdef ISP_TARGET_MODE
+ isp_target_async(isp, bus, mbox);
+#endif
break;
case ASYNC_LOOP_UP:
@@ -2634,6 +2703,9 @@ isp_parse_async(isp, mbox)
((fcparam *) isp->isp_param)->isp_loopstate = LOOP_LIP_RCVD;
isp_mark_getpdb_all(isp);
isp_async(isp, ISPASYNC_LOOP_UP, NULL);
+#ifdef ISP_TARGET_MODE
+ isp_target_async(isp, bus, mbox);
+#endif
break;
case ASYNC_LOOP_DOWN:
@@ -2642,6 +2714,9 @@ isp_parse_async(isp, mbox)
((fcparam *) isp->isp_param)->isp_loopstate = LOOP_NIL;
isp_mark_getpdb_all(isp);
isp_async(isp, ISPASYNC_LOOP_DOWN, NULL);
+#ifdef ISP_TARGET_MODE
+ isp_target_async(isp, bus, mbox);
+#endif
break;
case ASYNC_LOOP_RESET:
@@ -2651,7 +2726,7 @@ isp_parse_async(isp, mbox)
isp_mark_getpdb_all(isp);
PRINTF("%s: Loop RESET\n", isp->isp_name);
#ifdef ISP_TARGET_MODE
- isp_target_async(isp, bus, ASYNC_LOOP_RESET);
+ isp_target_async(isp, bus, mbox);
#endif
break;
@@ -2671,6 +2746,37 @@ isp_parse_async(isp, mbox)
isp_async(isp, ISPASYNC_CHANGE_NOTIFY, NULL);
break;
+ case ASYNC_PTPMODE:
+ PRINTF("%s: Point-to-Point mode\n", isp->isp_name);
+ break;
+
+ case ASYNC_CONNMODE:
+ mbox = ISP_READ(isp, OUTMAILBOX1);
+ switch (mbox) {
+ case ISP_CONN_LOOP:
+ PRINTF("%s: Point-to-Point -> Loop mode\n",
+ isp->isp_name);
+ break;
+ case ISP_CONN_PTP:
+ PRINTF("%s: Loop -> Point-to-Point mode\n",
+ isp->isp_name);
+ break;
+ case ISP_CONN_BADLIP:
+ PRINTF("%s: Point-to-Point -> Loop mode (1)\n",
+ isp->isp_name);
+ break;
+ case ISP_CONN_FATAL:
+ PRINTF("%s: FATAL CONNECTION ERROR\n", isp->isp_name);
+ isp_restart(isp);
+ /* no point continuing after this */
+ return (-1);
+
+ case ISP_CONN_LOOPBACK:
+ PRINTF("%s: Looped Back in Point-to-Point mode\n",
+ isp->isp_name);
+ }
+ break;
+
default:
PRINTF("%s: unknown async code 0x%x\n", isp->isp_name, mbox);
break;
@@ -2692,7 +2798,7 @@ isp_handle_other_response(isp, sp, optrp)
{
switch (sp->req_header.rqs_entry_type) {
case RQSTYPE_ATIO:
- case RQSTYPE_CTIO0:
+ case RQSTYPE_CTIO:
case RQSTYPE_ENABLE_LUN:
case RQSTYPE_MODIFY_LUN:
case RQSTYPE_NOTIFY:
@@ -2702,7 +2808,7 @@ isp_handle_other_response(isp, sp, optrp)
case RQSTYPE_CTIO2:
case RQSTYPE_CTIO3:
#ifdef ISP_TARGET_MODE
- return (isp_target_entry(isp, sp));
+ return (isp_target_notify(isp, sp, optrp));
#else
/* FALLTHROUGH */
#endif
@@ -3094,7 +3200,7 @@ static u_int8_t mbpcnt[] = {
MAKNIB(0, 0), /* 0x52: */
MAKNIB(0, 0), /* 0x53: */
MAKNIB(8, 0), /* 0x54: MBOX_EXEC_COMMAND_IOCB_A64 */
- MAKNIB(0, 0), /* 0x55: */
+ MAKNIB(2, 1), /* 0x55: MBOX_ENABLE_TARGET_MODE */
MAKNIB(0, 0), /* 0x56: */
MAKNIB(0, 0), /* 0x57: */
MAKNIB(0, 0), /* 0x58: */
@@ -3403,6 +3509,12 @@ command_known:
}
}
+ if (IS_2200(isp)) {
+ if (opcode == MBOX_GET_LOOP_ID) {
+ mbp->param[6] = ISP_READ(isp, OUTMAILBOX6);
+ }
+ }
+
switch (outparam) {
case 8: mbp->param[7] = ISP_READ(isp, OUTMAILBOX7);
case 7: mbp->param[6] = ISP_READ(isp, OUTMAILBOX6);
@@ -3459,6 +3571,12 @@ command_known:
}
break;
+ case MBOX_LOOP_ID_USED:
+ case MBOX_PORT_ID_USED:
+ case MBOX_ALL_IDS_USED:
+ break;
+
+
/*
* Be silent about these...
*/
@@ -3826,7 +3944,14 @@ isp_setdfltparm(isp, channel)
sdp->isp_devparam[tgt].cur_period = 0;
sdp->isp_devparam[tgt].dev_flags = DPARM_DEFAULT;
sdp->isp_devparam[tgt].cur_dflags = 0;
- if (isp->isp_type < ISP_HA_SCSI_1040 ||
+ /*
+ * We default to Wide/Fast for versions less than a 1040
+ * (unless it's SBus).
+ */
+ if ((isp->isp_bustype == ISP_BT_SBUS &&
+ isp->isp_type < ISP_HA_SCSI_1020A) ||
+ (isp->isp_bustype == ISP_BT_PCI &&
+ isp->isp_type < ISP_HA_SCSI_1040) ||
(isp->isp_clock && isp->isp_clock < 60)) {
sdp->isp_devparam[tgt].sync_offset =
ISP_10M_SYNCPARMS >> 8;
@@ -3891,7 +4016,7 @@ isp_setdfltparm(isp, channel)
IDPRINTF(3, ("%s: bus %d tgt %d flags %x offset %x period %x\n",
isp->isp_name, channel, tgt,
sdp->isp_devparam[tgt].dev_flags,
- sdp->isp_devparam[tgt].sync_period,
+ sdp->isp_devparam[tgt].sync_offset,
sdp->isp_devparam[tgt].sync_period));
}
@@ -3971,13 +4096,10 @@ isp_restart(isp)
/*
* NVRAM Routines
*/
-
static int
isp_read_nvram(isp)
struct ispsoftc *isp;
{
- static char *tru = "true";
- static char *not = "false";
int i, amt;
u_int8_t csum, minversion;
union {
@@ -4030,349 +4152,23 @@ isp_read_nvram(isp)
return (-1);
}
- if (IS_ULTRA2(isp)) {
- int bus;
- sdparam *sdp = (sdparam *) isp->isp_param;
- for (bus = 0; bus < (IS_DUALBUS(isp)? 2 : 1); bus++, sdp++) {
- sdp->isp_fifo_threshold =
- ISP1080_NVRAM_FIFO_THRESHOLD(nvram_data);
-
- sdp->isp_initiator_id =
- ISP1080_NVRAM_INITIATOR_ID(nvram_data, bus);
-
- sdp->isp_bus_reset_delay =
- ISP1080_NVRAM_BUS_RESET_DELAY(nvram_data, bus);
-
- sdp->isp_retry_count =
- ISP1080_NVRAM_BUS_RETRY_COUNT(nvram_data, bus);
-
- sdp->isp_retry_delay =
- ISP1080_NVRAM_BUS_RETRY_DELAY(nvram_data, bus);
-
- sdp->isp_async_data_setup =
- ISP1080_NVRAM_ASYNC_DATA_SETUP_TIME(nvram_data,
- bus);
-
- sdp->isp_req_ack_active_neg =
- ISP1080_NVRAM_REQ_ACK_ACTIVE_NEGATION(nvram_data,
- bus);
-
- sdp->isp_data_line_active_neg =
- ISP1080_NVRAM_DATA_LINE_ACTIVE_NEGATION(nvram_data,
- bus);
-
- sdp->isp_data_dma_burst_enabl =
- ISP1080_NVRAM_BURST_ENABLE(nvram_data);
-
- sdp->isp_cmd_dma_burst_enable =
- ISP1080_NVRAM_BURST_ENABLE(nvram_data);
-
- sdp->isp_selection_timeout =
- ISP1080_NVRAM_SELECTION_TIMEOUT(nvram_data, bus);
-
- sdp->isp_max_queue_depth =
- ISP1080_NVRAM_MAX_QUEUE_DEPTH(nvram_data, bus);
-
- if (isp->isp_dblev >= 3) {
- PRINTF("%s: ISP1080 bus %d NVRAM values:\n",
- isp->isp_name, bus);
- PRINTF(" Initiator ID = %d\n",
- sdp->isp_initiator_id);
- 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? tru : not);
- PRINTF(" Data Line Active Negation = %s\n",
- sdp->isp_data_line_active_neg? tru : not);
- PRINTF(" Cmd DMA Burst Enable = %s\n",
- sdp->isp_cmd_dma_burst_enable? tru : not);
- }
- for (i = 0; i < MAX_TARGETS; i++) {
- sdp->isp_devparam[i].dev_enable =
- ISP1080_NVRAM_TGT_DEVICE_ENABLE(nvram_data, i, bus);
- sdp->isp_devparam[i].exc_throttle =
- ISP1080_NVRAM_TGT_EXEC_THROTTLE(nvram_data, i, bus);
- sdp->isp_devparam[i].sync_offset =
- ISP1080_NVRAM_TGT_SYNC_OFFSET(nvram_data, i, bus);
- sdp->isp_devparam[i].sync_period =
- ISP1080_NVRAM_TGT_SYNC_PERIOD(nvram_data, i, bus);
- sdp->isp_devparam[i].dev_flags = 0;
- if (ISP1080_NVRAM_TGT_RENEG(nvram_data, i, bus))
- sdp->isp_devparam[i].dev_flags |= DPARM_RENEG;
- if (ISP1080_NVRAM_TGT_QFRZ(nvram_data, i, bus)) {
- PRINTF("%s: not supporting QFRZ option "
- "for target %d bus %d\n",
- isp->isp_name, i, bus);
- }
- sdp->isp_devparam[i].dev_flags |= DPARM_ARQ;
- if (ISP1080_NVRAM_TGT_ARQ(nvram_data, i, bus) == 0) {
- PRINTF("%s: not disabling ARQ option "
- "for target %d bus %d\n",
- isp->isp_name, i, bus);
- }
- if (ISP1080_NVRAM_TGT_TQING(nvram_data, i, bus))
- sdp->isp_devparam[i].dev_flags |= DPARM_TQING;
- if (ISP1080_NVRAM_TGT_SYNC(nvram_data, i, bus))
- sdp->isp_devparam[i].dev_flags |= DPARM_SYNC;
- if (ISP1080_NVRAM_TGT_WIDE(nvram_data, i, bus))
- sdp->isp_devparam[i].dev_flags |= DPARM_WIDE;
- if (ISP1080_NVRAM_TGT_PARITY(nvram_data, i, bus))
- sdp->isp_devparam[i].dev_flags |= DPARM_PARITY;
- if (ISP1080_NVRAM_TGT_DISC(nvram_data, i, bus))
- sdp->isp_devparam[i].dev_flags |= DPARM_DISC;
- sdp->isp_devparam[i].cur_dflags = 0;
- if (isp->isp_dblev >= 3) {
- PRINTF(" Target %d: Ena %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);
- }
- }
- }
+ if (IS_ULTRA3(isp)) {
+ isp_parse_nvram_12160(isp, 0, nvram_data);
+ isp_parse_nvram_12160(isp, 1, nvram_data);
+ } else if (IS_1080(isp)) {
+ isp_parse_nvram_1080(isp, 0, nvram_data);
+ } else if (IS_1280(isp) || IS_1240(isp)) {
+ isp_parse_nvram_1080(isp, 0, nvram_data);
+ isp_parse_nvram_1080(isp, 1, nvram_data);
} else if (IS_SCSI(isp)) {
- 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);
-
- isp->isp_fast_mttr = ISP_NVRAM_FAST_MTTR_ENABLE(nvram_data);
- if (isp->isp_dblev > 2) {
- 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? tru : not);
- PRINTF(" Data Line Active Negation = %s\n",
- sdp->isp_data_line_active_neg? tru : not);
- PRINTF(" Data DMA Burst Enable = %s\n",
- sdp->isp_data_dma_burst_enabl? tru : not);
- PRINTF(" Cmd DMA Burst Enable = %s\n",
- sdp->isp_cmd_dma_burst_enable? tru : not);
- PRINTF(" Fast MTTR = %s\n",
- isp->isp_fast_mttr? tru : not);
- }
- 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;
- sdp->isp_devparam[i].cur_dflags = 0; /* we don't know */
- 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);
- }
- }
+ isp_parse_nvram_1020(isp, nvram_data);
} 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
- } wd;
- u_int64_t full64;
- } wwnstore;
-
- wwnstore.full64 = ISP2100_NVRAM_NODE_NAME(nvram_data);
- /*
- * Broken PTI cards with nothing in the top nibble. Pah.
- */
- if ((wwnstore.wd.hi32 >> 28) == 0) {
- wwnstore.wd.hi32 |= (2 << 28);
- CFGPRINTF("%s: (corrected) Adapter WWN 0x%08x%08x\n",
- isp->isp_name, wwnstore.wd.hi32, wwnstore.wd.lo32);
- } else {
- CFGPRINTF("%s: Adapter WWN 0x%08x%08x\n", isp->isp_name,
- wwnstore.wd.hi32, wwnstore.wd.lo32);
- }
- fcp->isp_nodewwn = wwnstore.full64;
-
- /*
- * If the Node WWN has 2 in the top nibble, we can
- * authoritatively construct a Port WWN by adding
- * our unit number (plus one to make it nonzero) and
- * putting it into bits 59..56. If the top nibble isn't
- * 2, then we just set them identically.
- */
- if ((fcp->isp_nodewwn >> 60) == 2) {
- fcp->isp_portwwn = fcp->isp_nodewwn |
- (((u_int64_t)(isp->isp_unit+1)) << 56);
- } else {
- fcp->isp_portwwn = fcp->isp_nodewwn;
- }
- 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.wd.hi32, wwnstore.wd.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));
- }
+ isp_parse_nvram_2100(isp, nvram_data);
}
IDPRINTF(3, ("%s: NVRAM is valid\n", isp->isp_name));
return (0);
+#undef nvram_data
+#undef nvram_words
}
static void
@@ -4442,3 +4238,493 @@ isp_rdnvram_word(isp, wo, rp)
*rp = ((*rp >> 8) | ((*rp & 0xff) << 8));
#endif
}
+
+static void
+isp_parse_nvram_1020(isp, nvram_data)
+ struct ispsoftc *isp;
+ u_int8_t *nvram_data;
+{
+ int i;
+ static char *tru = "true";
+ static char *not = "false";
+ 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);
+
+ isp->isp_fast_mttr = ISP_NVRAM_FAST_MTTR_ENABLE(nvram_data);
+ if (isp->isp_dblev > 2) {
+ 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? tru : not);
+ PRINTF(" Data Line Active Negation = %s\n",
+ sdp->isp_data_line_active_neg? tru : not);
+ PRINTF(" Data DMA Burst Enable = %s\n",
+ sdp->isp_data_dma_burst_enabl? tru : not);
+ PRINTF(" Cmd DMA Burst Enable = %s\n",
+ sdp->isp_cmd_dma_burst_enable? tru : not);
+ PRINTF(" Fast MTTR = %s\n",
+ isp->isp_fast_mttr? tru : not);
+ }
+ 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;
+ sdp->isp_devparam[i].cur_dflags = 0; /* we don't know */
+ 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);
+ }
+ }
+}
+
+static void
+isp_parse_nvram_1080(isp, bus, nvram_data)
+ struct ispsoftc *isp;
+ int bus;
+ u_int8_t *nvram_data;
+{
+ static char *tru = "true";
+ static char *not = "false";
+ int i;
+ sdparam *sdp = (sdparam *) isp->isp_param;
+ sdp += bus;
+
+ sdp->isp_fifo_threshold =
+ ISP1080_NVRAM_FIFO_THRESHOLD(nvram_data);
+
+ sdp->isp_initiator_id =
+ ISP1080_NVRAM_INITIATOR_ID(nvram_data, bus);
+
+ sdp->isp_bus_reset_delay =
+ ISP1080_NVRAM_BUS_RESET_DELAY(nvram_data, bus);
+
+ sdp->isp_retry_count =
+ ISP1080_NVRAM_BUS_RETRY_COUNT(nvram_data, bus);
+
+ sdp->isp_retry_delay =
+ ISP1080_NVRAM_BUS_RETRY_DELAY(nvram_data, bus);
+
+ sdp->isp_async_data_setup =
+ ISP1080_NVRAM_ASYNC_DATA_SETUP_TIME(nvram_data,
+ bus);
+
+ sdp->isp_req_ack_active_neg =
+ ISP1080_NVRAM_REQ_ACK_ACTIVE_NEGATION(nvram_data,
+ bus);
+
+ sdp->isp_data_line_active_neg =
+ ISP1080_NVRAM_DATA_LINE_ACTIVE_NEGATION(nvram_data,
+ bus);
+
+ sdp->isp_data_dma_burst_enabl =
+ ISP1080_NVRAM_BURST_ENABLE(nvram_data);
+
+ sdp->isp_cmd_dma_burst_enable =
+ ISP1080_NVRAM_BURST_ENABLE(nvram_data);
+
+ sdp->isp_selection_timeout =
+ ISP1080_NVRAM_SELECTION_TIMEOUT(nvram_data, bus);
+
+ sdp->isp_max_queue_depth =
+ ISP1080_NVRAM_MAX_QUEUE_DEPTH(nvram_data, bus);
+
+ if (isp->isp_dblev >= 3) {
+ PRINTF("%s: ISP1080 bus %d NVRAM values:\n",
+ isp->isp_name, bus);
+ PRINTF(" Initiator ID = %d\n",
+ sdp->isp_initiator_id);
+ 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? tru : not);
+ PRINTF(" Data Line Active Negation = %s\n",
+ sdp->isp_data_line_active_neg? tru : not);
+ PRINTF(" Cmd DMA Burst Enable = %s\n",
+ sdp->isp_cmd_dma_burst_enable? tru : not);
+ }
+ for (i = 0; i < MAX_TARGETS; i++) {
+ sdp->isp_devparam[i].dev_enable =
+ ISP1080_NVRAM_TGT_DEVICE_ENABLE(nvram_data, i, bus);
+ sdp->isp_devparam[i].exc_throttle =
+ ISP1080_NVRAM_TGT_EXEC_THROTTLE(nvram_data, i, bus);
+ sdp->isp_devparam[i].sync_offset =
+ ISP1080_NVRAM_TGT_SYNC_OFFSET(nvram_data, i, bus);
+ sdp->isp_devparam[i].sync_period =
+ ISP1080_NVRAM_TGT_SYNC_PERIOD(nvram_data, i, bus);
+ sdp->isp_devparam[i].dev_flags = 0;
+ if (ISP1080_NVRAM_TGT_RENEG(nvram_data, i, bus))
+ sdp->isp_devparam[i].dev_flags |= DPARM_RENEG;
+ if (ISP1080_NVRAM_TGT_QFRZ(nvram_data, i, bus)) {
+ PRINTF("%s: not supporting QFRZ option "
+ "for target %d bus %d\n",
+ isp->isp_name, i, bus);
+ }
+ sdp->isp_devparam[i].dev_flags |= DPARM_ARQ;
+ if (ISP1080_NVRAM_TGT_ARQ(nvram_data, i, bus) == 0) {
+ PRINTF("%s: not disabling ARQ option "
+ "for target %d bus %d\n",
+ isp->isp_name, i, bus);
+ }
+ if (ISP1080_NVRAM_TGT_TQING(nvram_data, i, bus))
+ sdp->isp_devparam[i].dev_flags |= DPARM_TQING;
+ if (ISP1080_NVRAM_TGT_SYNC(nvram_data, i, bus))
+ sdp->isp_devparam[i].dev_flags |= DPARM_SYNC;
+ if (ISP1080_NVRAM_TGT_WIDE(nvram_data, i, bus))
+ sdp->isp_devparam[i].dev_flags |= DPARM_WIDE;
+ if (ISP1080_NVRAM_TGT_PARITY(nvram_data, i, bus))
+ sdp->isp_devparam[i].dev_flags |= DPARM_PARITY;
+ if (ISP1080_NVRAM_TGT_DISC(nvram_data, i, bus))
+ sdp->isp_devparam[i].dev_flags |= DPARM_DISC;
+ sdp->isp_devparam[i].cur_dflags = 0;
+ if (isp->isp_dblev >= 3) {
+ PRINTF(" Target %d: Ena %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);
+ }
+ }
+}
+
+static void
+isp_parse_nvram_12160(isp, bus, nvram_data)
+ struct ispsoftc *isp;
+ int bus;
+ u_int8_t *nvram_data;
+{
+ static char *tru = "true";
+ static char *not = "false";
+ sdparam *sdp = (sdparam *) isp->isp_param;
+ int i;
+
+ sdp += bus;
+
+ sdp->isp_fifo_threshold =
+ ISP12160_NVRAM_FIFO_THRESHOLD(nvram_data);
+
+ sdp->isp_initiator_id =
+ ISP12160_NVRAM_INITIATOR_ID(nvram_data, bus);
+
+ sdp->isp_bus_reset_delay =
+ ISP12160_NVRAM_BUS_RESET_DELAY(nvram_data, bus);
+
+ sdp->isp_retry_count =
+ ISP12160_NVRAM_BUS_RETRY_COUNT(nvram_data, bus);
+
+ sdp->isp_retry_delay =
+ ISP12160_NVRAM_BUS_RETRY_DELAY(nvram_data, bus);
+
+ sdp->isp_async_data_setup =
+ ISP12160_NVRAM_ASYNC_DATA_SETUP_TIME(nvram_data,
+ bus);
+
+ sdp->isp_req_ack_active_neg =
+ ISP12160_NVRAM_REQ_ACK_ACTIVE_NEGATION(nvram_data,
+ bus);
+
+ sdp->isp_data_line_active_neg =
+ ISP12160_NVRAM_DATA_LINE_ACTIVE_NEGATION(nvram_data,
+ bus);
+
+ sdp->isp_data_dma_burst_enabl =
+ ISP12160_NVRAM_BURST_ENABLE(nvram_data);
+
+ sdp->isp_cmd_dma_burst_enable =
+ ISP12160_NVRAM_BURST_ENABLE(nvram_data);
+
+ sdp->isp_selection_timeout =
+ ISP12160_NVRAM_SELECTION_TIMEOUT(nvram_data, bus);
+
+ sdp->isp_max_queue_depth =
+ ISP12160_NVRAM_MAX_QUEUE_DEPTH(nvram_data, bus);
+
+ if (isp->isp_dblev >= 3) {
+ PRINTF("%s: ISP12160 bus %d NVRAM values:\n",
+ isp->isp_name, bus);
+ PRINTF(" Initiator ID = %d\n",
+ sdp->isp_initiator_id);
+ 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? tru : not);
+ PRINTF(" Data Line Active Negation = %s\n",
+ sdp->isp_data_line_active_neg? tru : not);
+ PRINTF(" Cmd DMA Burst Enable = %s\n",
+ sdp->isp_cmd_dma_burst_enable? tru : not);
+ }
+
+ for (i = 0; i < MAX_TARGETS; i++) {
+ sdp->isp_devparam[i].dev_enable =
+ ISP12160_NVRAM_TGT_DEVICE_ENABLE(nvram_data, i, bus);
+ sdp->isp_devparam[i].exc_throttle =
+ ISP12160_NVRAM_TGT_EXEC_THROTTLE(nvram_data, i, bus);
+ sdp->isp_devparam[i].sync_offset =
+ ISP12160_NVRAM_TGT_SYNC_OFFSET(nvram_data, i, bus);
+ sdp->isp_devparam[i].sync_period =
+ ISP12160_NVRAM_TGT_SYNC_PERIOD(nvram_data, i, bus);
+ sdp->isp_devparam[i].dev_flags = 0;
+ if (ISP12160_NVRAM_TGT_RENEG(nvram_data, i, bus))
+ sdp->isp_devparam[i].dev_flags |= DPARM_RENEG;
+ if (ISP12160_NVRAM_TGT_QFRZ(nvram_data, i, bus)) {
+ PRINTF("%s: not supporting QFRZ option "
+ "for target %d bus %d\n", isp->isp_name, i, bus);
+ }
+ sdp->isp_devparam[i].dev_flags |= DPARM_ARQ;
+ if (ISP12160_NVRAM_TGT_ARQ(nvram_data, i, bus) == 0) {
+ PRINTF("%s: not disabling ARQ option "
+ "for target %d bus %d\n", isp->isp_name, i, bus);
+ }
+ if (ISP12160_NVRAM_TGT_TQING(nvram_data, i, bus))
+ sdp->isp_devparam[i].dev_flags |= DPARM_TQING;
+ if (ISP12160_NVRAM_TGT_SYNC(nvram_data, i, bus))
+ sdp->isp_devparam[i].dev_flags |= DPARM_SYNC;
+ if (ISP12160_NVRAM_TGT_WIDE(nvram_data, i, bus))
+ sdp->isp_devparam[i].dev_flags |= DPARM_WIDE;
+ if (ISP12160_NVRAM_TGT_PARITY(nvram_data, i, bus))
+ sdp->isp_devparam[i].dev_flags |= DPARM_PARITY;
+ if (ISP12160_NVRAM_TGT_DISC(nvram_data, i, bus))
+ sdp->isp_devparam[i].dev_flags |= DPARM_DISC;
+ sdp->isp_devparam[i].cur_dflags = 0;
+ if (isp->isp_dblev >= 3) {
+ PRINTF(" Target %d: Ena %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);
+ }
+ }
+}
+
+static void
+isp_parse_nvram_2100(isp, nvram_data)
+ struct ispsoftc *isp;
+ u_int8_t *nvram_data;
+{
+ 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
+ } wd;
+ u_int64_t full64;
+ } wwnstore;
+
+ wwnstore.full64 = ISP2100_NVRAM_NODE_NAME(nvram_data);
+
+ /*
+ * Broken PTI cards with nothing in the top nibble. Pah.
+ */
+ if ((wwnstore.wd.hi32 >> 28) == 0) {
+ wwnstore.wd.hi32 |= (2 << 28);
+ CFGPRINTF("%s: (corrected) Adapter WWN 0x%08x%08x\n",
+ isp->isp_name, wwnstore.wd.hi32, wwnstore.wd.lo32);
+ } else {
+ CFGPRINTF("%s: Adapter WWN 0x%08x%08x\n", isp->isp_name,
+ wwnstore.wd.hi32, wwnstore.wd.lo32);
+ }
+ fcp->isp_nodewwn = wwnstore.full64;
+
+ /*
+ * If the Node WWN has 2 in the top nibble, we can
+ * authoritatively construct a Port WWN by adding
+ * our unit number (plus one to make it nonzero) and
+ * putting it into bits 59..56. If the top nibble isn't
+ * 2, then we just set them identically.
+ */
+ if ((fcp->isp_nodewwn >> 60) == 2) {
+ fcp->isp_portwwn = fcp->isp_nodewwn |
+ (((u_int64_t)(isp->isp_unit+1)) << 56);
+ } else {
+ fcp->isp_portwwn = fcp->isp_nodewwn;
+ }
+ 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.wd.hi32, wwnstore.wd.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));
+ }
+}
diff --git a/sys/dev/ic/isp_inline.h b/sys/dev/ic/isp_inline.h
index bedb4f70867..9e45b7d443c 100644
--- a/sys/dev/ic/isp_inline.h
+++ b/sys/dev/ic/isp_inline.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: isp_inline.h,v 1.2 1999/12/03 03:48:56 mjacob Exp $ */
+/* $OpenBSD: isp_inline.h,v 1.3 2000/02/20 21:22:41 mjacob Exp $ */
/*
* Qlogic Inline Functions
*
@@ -275,4 +275,25 @@ isp_getrqentry(isp, iptrp, optrp, resultp)
*iptrp = iptr;
return (0);
}
+
+static INLINE void
+isp_print_qentry __P((struct ispsoftc *, char *, int, void *));
+
+static INLINE void
+isp_print_qentry(isp, msg, idx, arg)
+ struct ispsoftc *isp;
+ char *msg;
+ int idx;
+ void *arg;
+{
+ int amt, i, j;
+ u_int8_t *ptr = arg;
+ PRINTF("%s %s index %d:\n", isp->isp_name, msg, idx);
+ for (amt = i = 0; i < 4; i++) {
+ for (j = 0; j < (QENTRY_LEN >> 2); j++) {
+ PRINTF(" %02x", ptr[amt++] & 0xff);
+ }
+ PRINTF("\n");
+ }
+}
#endif /* _ISP_INLINE_H */
diff --git a/sys/dev/ic/isp_openbsd.c b/sys/dev/ic/isp_openbsd.c
index f283cbe3f66..922e92b41ec 100644
--- a/sys/dev/ic/isp_openbsd.c
+++ b/sys/dev/ic/isp_openbsd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: isp_openbsd.c,v 1.6 1999/12/16 05:25:39 mjacob Exp $ */
+/* $OpenBSD: isp_openbsd.c,v 1.7 2000/02/20 21:22:41 mjacob Exp $ */
/*
* Platform (OpenBSD) dependent common attachment code for Qlogic adapters.
*
@@ -584,6 +584,9 @@ isp_async(isp, cmd, arg)
(sdp->isp_devparam[tgt].cur_offset) != 0) {
if (sdp->isp_lvdmode || period < 0xc) {
switch (period) {
+ case 0x9:
+ mhz = 80;
+ break;
case 0xa:
mhz = 40;
break;
@@ -680,16 +683,18 @@ isp_async(isp, cmd, arg)
{
int target;
struct lportdb *lp;
- sns_scrsp_t *resp = (sns_scrsp_t *) arg;
+ char *pt;
+ sns_ganrsp_t *resp = (sns_ganrsp_t *) arg;
u_int32_t portid;
- u_int64_t wwn;
+ u_int64_t wwpn, wwnn;
fcparam *fcp = isp->isp_param;
portid =
(((u_int32_t) resp->snscb_port_id[0]) << 16) |
(((u_int32_t) resp->snscb_port_id[1]) << 8) |
(((u_int32_t) resp->snscb_port_id[2]));
- wwn =
+
+ wwpn =
(((u_int64_t)resp->snscb_portname[0]) << 56) |
(((u_int64_t)resp->snscb_portname[1]) << 48) |
(((u_int64_t)resp->snscb_portname[2]) << 40) |
@@ -698,15 +703,61 @@ isp_async(isp, cmd, arg)
(((u_int64_t)resp->snscb_portname[5]) << 16) |
(((u_int64_t)resp->snscb_portname[6]) << 8) |
(((u_int64_t)resp->snscb_portname[7]));
- printf("%s: Fabric Device (Type 0x%x)@PortID 0x%x WWN "
- "0x%08x%08x\n", isp->isp_name, resp->snscb_port_type,
- portid, ((u_int32_t)(wwn >> 32)),
- ((u_int32_t)(wwn & 0xffffffff)));
- if (resp->snscb_port_type != 2)
+
+ wwnn =
+ (((u_int64_t)resp->snscb_nodename[0]) << 56) |
+ (((u_int64_t)resp->snscb_nodename[1]) << 48) |
+ (((u_int64_t)resp->snscb_nodename[2]) << 40) |
+ (((u_int64_t)resp->snscb_nodename[3]) << 32) |
+ (((u_int64_t)resp->snscb_nodename[4]) << 24) |
+ (((u_int64_t)resp->snscb_nodename[5]) << 16) |
+ (((u_int64_t)resp->snscb_nodename[6]) << 8) |
+ (((u_int64_t)resp->snscb_nodename[7]));
+ if (portid == 0 || wwpn == 0) {
+ break;
+ }
+
+ switch (resp->snscb_port_type) {
+ case 1:
+ pt = " N_Port";
+ break;
+ case 2:
+ pt = " NL_Port";
+ break;
+ case 3:
+ pt = "F/NL_Port";
+ break;
+ case 0x7f:
+ pt = " Nx_Port";
+ break;
+ case 0x81:
+ pt = " F_port";
break;
+ case 0x82:
+ pt = " FL_Port";
+ break;
+ case 0x84:
+ pt = " E_port";
+ break;
+ default:
+ pt = "?";
+ break;
+ }
+ CFGPRINTF("%s: %s @ 0x%x, Node 0x%08x%08x Port %08x%08x\n",
+ isp->isp_name, pt, portid,
+ ((u_int32_t) (wwnn >> 32)), ((u_int32_t) wwnn),
+ ((u_int32_t) (wwpn >> 32)), ((u_int32_t) wwpn));
+#if 0
+ if ((resp->snscb_fc4_types[1] & 0x1) == 0) {
+ printf("Types 0..3: 0x%x 0x%x 0x%x 0x%x\n",
+ resp->snscb_fc4_types[0], resp->snscb_fc4_types[1],
+ resp->snscb_fc4_types[3], resp->snscb_fc4_types[3]);
+ break;
+ }
+#endif
for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) {
lp = &fcp->portdb[target];
- if (lp->port_wwn == wwn)
+ if (lp->port_wwn == wwpn && lp->node_wwn == wwnn)
break;
}
if (target < MAX_FC_TARG) {
@@ -720,9 +771,10 @@ isp_async(isp, cmd, arg)
if (target == MAX_FC_TARG) {
printf("%s: no more space for fabric devices\n",
isp->isp_name);
- return (-1);
+ break;
}
- lp->port_wwn = lp->node_wwn = wwn;
+ lp->node_wwn = wwnn;
+ lp->port_wwn = wwpn;
lp->portid = portid;
break;
}
diff --git a/sys/dev/ic/isp_openbsd.h b/sys/dev/ic/isp_openbsd.h
index 8326b64c0be..8c6a23e6f65 100644
--- a/sys/dev/ic/isp_openbsd.h
+++ b/sys/dev/ic/isp_openbsd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: isp_openbsd.h,v 1.6 1999/12/16 05:23:52 mjacob Exp $ */
+/* $OpenBSD: isp_openbsd.h,v 1.7 2000/02/20 21:22:41 mjacob Exp $ */
/*
* OpenBSD Specific definitions for the Qlogic ISP Host Adapter
*
@@ -63,7 +63,7 @@
#include <vm/pmap.h>
#define ISP_PLATFORM_VERSION_MAJOR 0
-#define ISP_PLATFORM_VERSION_MINOR 6
+#define ISP_PLATFORM_VERSION_MINOR 8
#define ISP_SCSI_XFER_T struct scsi_xfer
struct isposinfo {
@@ -80,7 +80,7 @@ struct isposinfo {
struct scsi_xfer *wqf, *wqt;
};
-#define MAXISPREQUEST 64
+#define MAXISPREQUEST 256
#ifdef ISP2100_FABRIC
#define ISP2100_SCRLEN 0x400
#else
@@ -204,12 +204,14 @@ extern void isp_uninit __P((struct ispsoftc *));
bcopy(src, dest, sizeof (isp_pdb_t))
#define ISP_SWIZZLE_ICB(a, b)
#ifdef __sparc__
+#define ISP_SWIZZLE_CONTINUATION(a, b) ISP_SBUSIFY_ISPHDR(a, &(b)->req_header)
#define ISP_SWIZZLE_REQUEST(a, b) \
ISP_SBUSIFY_ISPHDR(a, &(b)->req_header); \
ISP_SBUSIFY_ISPREQ(a, b)
#define ISP_UNSWIZZLE_RESPONSE(a, b) \
ISP_SBUSIFY_ISPHDR(a, &(b)->req_header)
#else
+#define ISP_SWIZZLE_CONTINUATION(a, b)
#define ISP_SWIZZLE_REQUEST(a, b)
#define ISP_UNSWIZZLE_RESPONSE(a, b)
#endif
diff --git a/sys/dev/ic/isp_target.c b/sys/dev/ic/isp_target.c
new file mode 100644
index 00000000000..bd7a4824e2b
--- /dev/null
+++ b/sys/dev/ic/isp_target.c
@@ -0,0 +1,1228 @@
+/* $OpenBSD: isp_target.c,v 1.1 2000/02/20 21:22:40 mjacob Exp $ */
+/*
+ * Machine and OS Independent Target Mode Code for the Qlogic SCSI/FC adapters.
+ *
+ * Copyright (c) 1999 by Matthew Jacob
+ * All rights reserved.
+ * mjacob@feral.com
+ *
+ * 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.
+ */
+
+/*
+ * Include header file appropriate for platform we're building on.
+ */
+
+#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
+
+#ifdef ISP_TARGET_MODE
+int isp_tdebug = 0;
+
+static void isp_got_msg __P((struct ispsoftc *, int, in_entry_t *));
+static void isp_got_msg_fc __P((struct ispsoftc *, int, in_fcentry_t *));
+static void isp_notify_ack __P((struct ispsoftc *, void *));
+static void isp_handle_atio(struct ispsoftc *, at_entry_t *);
+static void isp_handle_atio2(struct ispsoftc *, at2_entry_t *);
+static void isp_handle_ctio(struct ispsoftc *, ct_entry_t *);
+static void isp_handle_ctio2(struct ispsoftc *, ct2_entry_t *);
+
+/*
+ * The Qlogic driver gets an interrupt to look at response queue entries.
+ * Some of these are status completions for initiatior mode commands, but
+ * if target mode is enabled, we get a whole wad of response queue entries
+ * to be handled here.
+ *
+ * Basically the split into 3 main groups: Lun Enable/Modification responses,
+ * SCSI Command processing, and Immediate Notification events.
+ *
+ * You start by writing a request queue entry to enable target mode (and
+ * establish some resource limitations which you can modify later).
+ * The f/w responds with a LUN ENABLE or LUN MODIFY response with
+ * the status of this action. If the enable was successful, you can expect...
+ *
+ * Response queue entries with SCSI commands encapsulate show up in an ATIO
+ * (Accept Target IO) type- sometimes with enough info to stop the command at
+ * this level. Ultimately the driver has to feed back to the f/w's request
+ * queue a sequence of CTIOs (continue target I/O) that describe data to
+ * be moved and/or status to be sent) and finally finishing with sending
+ * to the f/w's response queue an ATIO which then completes the handshake
+ * with the f/w for that command. There's a lot of variations on this theme,
+ * including flags you can set in the CTIO for the Qlogic 2X00 fibre channel
+ * cards that 'auto-replenish' the f/w's ATIO count, but this is the basic
+ * gist of it.
+ *
+ * The third group that can show up in the response queue are Immediate
+ * Notification events. These include things like notifications of SCSI bus
+ * resets, or Bus Device Reset messages or other messages received. This
+ * a classic oddbins area. It can get a little wierd because you then turn
+ * around and acknowledge the Immediate Notify by writing an entry onto the
+ * request queue and then the f/w turns around and gives you an acknowledgement
+ * to *your* acknowledgement on the response queue (the idea being to let
+ * the f/w tell you when the event is *really* over I guess).
+ *
+ */
+
+
+/*
+ * A new response queue entry has arrived. The interrupt service code
+ * has already swizzled it into the platform dependent from canonical form.
+ *
+ * Because of the way this driver is designed, unfortunately most of the
+ * actual synchronization work has to be done in the platform specific
+ * code- we have no synchroniation primitives in the common code.
+ */
+
+int
+isp_target_notify(isp, vptr, optrp)
+ struct ispsoftc *isp;
+ void *vptr;
+ u_int16_t *optrp;
+{
+ u_int16_t status, seqid;
+ union {
+ at_entry_t *atiop;
+ at2_entry_t *at2iop;
+ ct_entry_t *ctiop;
+ ct2_entry_t *ct2iop;
+ lun_entry_t *lunenp;
+ in_entry_t *inotp;
+ in_fcentry_t *inot_fcp;
+ na_entry_t *nackp;
+ na_fcentry_t *nack_fcp;
+ isphdr_t *hp;
+ void * *vp;
+#define atiop unp.atiop
+#define at2iop unp.at2iop
+#define ctiop unp.ctiop
+#define ct2iop unp.ct2iop
+#define lunenp unp.lunenp
+#define inotp unp.inotp
+#define inot_fcp unp.inot_fcp
+#define nackp unp.nackp
+#define nack_fcp unp.nack_fcp
+#define hdrp unp.hp
+ } unp;
+ int bus, rval = 0;
+
+ unp.vp = vptr;
+
+ ISP_TDQE(isp, "isp_target_notify", (int) *optrp, vptr);
+
+ switch(hdrp->rqs_entry_type) {
+ case RQSTYPE_ATIO:
+ isp_handle_atio(isp, atiop);
+ break;
+ case RQSTYPE_CTIO:
+ isp_handle_ctio(isp, ctiop);
+ break;
+ case RQSTYPE_ATIO2:
+ isp_handle_atio2(isp, at2iop);
+ break;
+ case RQSTYPE_CTIO2:
+ isp_handle_ctio2(isp, ct2iop);
+ break;
+ case RQSTYPE_ENABLE_LUN:
+ case RQSTYPE_MODIFY_LUN:
+ (void) isp_async(isp, ISPASYNC_TARGET_ACTION, vptr);
+ break;
+
+ case RQSTYPE_NOTIFY:
+ /*
+ * Either the ISP received a SCSI message it can't
+ * handle, or it's returning an Immed. Notify entry
+ * we sent. We can send Immed. Notify entries to
+ * increment the firmware's resource count for them
+ * (we set this initially in the Enable Lun entry).
+ */
+ bus = 0;
+ if (IS_FC(isp)) {
+ status = inot_fcp->in_status;
+ seqid = inot_fcp->in_seqid;
+ } else {
+ status = inotp->in_status & 0xff;
+ seqid = inotp->in_seqid;
+ if (IS_DUALBUS(isp)) {
+ bus = (inotp->in_iid & 0x80) >> 7;
+ inotp->in_iid &= ~0x80;
+ }
+ }
+ ITDEBUG(2, ("isp_target_notify: Immediate Notify, "
+ "status=0x%x seqid=0x%x\n", status, seqid));
+ switch (status) {
+ case IN_RESET:
+ (void) isp_async(isp, ISPASYNC_BUS_RESET, &bus);
+ break;
+ case IN_MSG_RECEIVED:
+ case IN_IDE_RECEIVED:
+ if (IS_FC(isp)) {
+ isp_got_msg_fc(isp, bus, vptr);
+ } else {
+ isp_got_msg(isp, bus, vptr);
+ }
+ break;
+ case IN_RSRC_UNAVAIL:
+ PRINTF("%s: Firmware out of ATIOs\n", isp->isp_name);
+ break;
+ case IN_ABORT_TASK:
+ PRINTF("%s: Abort Task for Initiator %d RX_ID 0x%x\n",
+ isp->isp_name, inot_fcp->in_iid, seqid);
+ break;
+ case IN_PORT_LOGOUT:
+ PRINTF("%s: Port Logout for Initiator %d RX_ID 0x%x\n",
+ isp->isp_name, inot_fcp->in_iid, seqid);
+ break;
+ case IN_PORT_CHANGED:
+ PRINTF("%s: Port Changed for Initiator %d RX_ID 0x%x\n",
+ isp->isp_name, inot_fcp->in_iid, seqid);
+ break;
+ case IN_GLOBAL_LOGO:
+ PRINTF("%s: All ports logged out\n", isp->isp_name);
+ break;
+ default:
+ PRINTF("%s: bad status (0x%x) in isp_target_notify\n",
+ isp->isp_name, status);
+ break;
+ }
+ isp_notify_ack(isp, vptr);
+ break;
+
+ case RQSTYPE_NOTIFY_ACK:
+ /*
+ * The ISP is acknowledging our acknowledgement of an
+ * Immediate Notify entry for some asynchronous event.
+ */
+ if (IS_FC(isp)) {
+ ITDEBUG(2, ("%s: Notify Ack status=0x%x seqid 0x%x\n",
+ isp->isp_name, nack_fcp->na_status,
+ nack_fcp->na_seqid));
+ } else {
+ ITDEBUG(2, ("%s: Notify Ack event 0x%x status=0x%x "
+ "seqid 0x%x\n", isp->isp_name, nackp->na_event,
+ nackp->na_status, nackp->na_seqid));
+ }
+ break;
+ default:
+ PRINTF("%s: Unknown entry type 0x%x in isp_target_notify",
+ isp->isp_name, hdrp->rqs_entry_type);
+ rval = -1;
+ break;
+ }
+#undef atiop
+#undef at2iop
+#undef ctiop
+#undef ct2iop
+#undef lunenp
+#undef inotp
+#undef inot_fcp
+#undef nackp
+#undef nack_fcp
+#undef hdrp
+ return (rval);
+}
+
+
+/*
+ * Toggle (on/off) target mode for bus/target/lun
+ *
+ * The caller has checked for overlap and legality.
+ *
+ * Note that not all of bus, target or lun can be paid attention to.
+ * Note also that this action will not be complete until the f/w writes
+ * response entry. The caller is responsible for synchronizing this.
+ */
+int
+isp_lun_cmd(isp, cmd, bus, tgt, lun, opaque)
+ struct ispsoftc *isp;
+ int cmd;
+ int bus;
+ int tgt;
+ int lun;
+ u_int32_t opaque;
+{
+ lun_entry_t el;
+ u_int16_t iptr, optr;
+ void *outp;
+
+
+ MEMZERO(&el, sizeof (el));
+ if (IS_DUALBUS(isp)) {
+ el.le_rsvd = (bus & 0x1) << 7;
+ }
+ el.le_cmd_count = DFLT_CMD_CNT;
+ el.le_in_count = DFLT_INOTIFY;
+ if (cmd == RQSTYPE_ENABLE_LUN) {
+ if (IS_SCSI(isp)) {
+ el.le_flags = LUN_TQAE;
+ el.le_cdb6len = 12;
+ el.le_cdb7len = 12;
+ }
+ } else if (cmd == -RQSTYPE_ENABLE_LUN) {
+ cmd = RQSTYPE_ENABLE_LUN;
+ el.le_cmd_count = 0;
+ el.le_in_count = 0;
+ } else if (cmd == -RQSTYPE_MODIFY_LUN) {
+ cmd = RQSTYPE_MODIFY_LUN;
+ el.le_ops = LUN_CCDECR | LUN_INDECR;
+ } else {
+ el.le_ops = LUN_CCINCR | LUN_ININCR;
+ }
+ el.le_header.rqs_entry_type = cmd;
+ el.le_header.rqs_entry_count = 1;
+ el.le_reserved = opaque;
+ if (IS_SCSI(isp)) {
+ el.le_tgt = tgt;
+ el.le_lun = lun;
+#ifndef ISP2100_SCCLUN
+ } else {
+ el.le_lun = lun;
+#endif
+ }
+
+ if (isp_getrqentry(isp, &iptr, &optr, &outp)) {
+ PRINTF("%s: Request Queue Overflow in isp_lun_cmd\n",
+ isp->isp_name);
+ return (-1);
+ }
+ ISP_SWIZ_ENABLE_LUN(isp, outp, &el);
+ ISP_TDQE(isp, "isp_lun_cmd", (int) optr, &el);
+ ISP_ADD_REQUEST(isp, iptr);
+ return (0);
+}
+
+
+int
+isp_target_put_entry(isp, ap)
+ struct ispsoftc *isp;
+ void *ap;
+{
+ void *outp;
+ u_int16_t iptr, optr;
+ u_int8_t etype = ((isphdr_t *) ap)->rqs_entry_type;
+
+ if (isp_getrqentry(isp, &iptr, &optr, &outp)) {
+ PRINTF("%s: Request Queue Overflow in isp_target_put_entry "
+ "for type 0x%x\n", isp->isp_name, etype);
+ return (-1);
+ }
+ switch (etype) {
+ case RQSTYPE_ATIO:
+ ISP_SWIZ_ATIO(isp, outp, ap);
+ break;
+ case RQSTYPE_ATIO2:
+ ISP_SWIZ_ATIO2(isp, outp, ap);
+ break;
+ case RQSTYPE_CTIO:
+ ISP_SWIZ_CTIO(isp, outp, ap);
+ break;
+ case RQSTYPE_CTIO2:
+ ISP_SWIZ_CTIO2(isp, outp, ap);
+ break;
+ default:
+ PRINTF("%s: Unknown type 0x%x in isp_put_entry\n",
+ isp->isp_name, etype);
+ return (-1);
+ }
+
+ ISP_TDQE(isp, "isp_target_put_entry", (int) optr, ap);;
+
+ ISP_ADD_REQUEST(isp, iptr);
+ return (0);
+}
+
+int
+isp_target_put_atio(isp, iid, tgt, lun, ttype, tval)
+ struct ispsoftc *isp;
+ int iid;
+ int tgt;
+ int lun;
+ int ttype;
+ int tval;
+{
+ union {
+ at_entry_t _atio;
+ at2_entry_t _atio2;
+ } atun;
+
+ MEMZERO(&atun, sizeof atun);
+ if (IS_FC(isp)) {
+ atun._atio2.at_header.rqs_entry_type = RQSTYPE_ATIO2;
+ atun._atio2.at_header.rqs_entry_count = 1;
+#ifdef ISP2100_SCCLUN
+ atun._atio2.at_scclun = (uint16_t) lun;
+#else
+ atun._atio2.at_lun = (uint8_t) lun;
+#endif
+ atun._atio2.at_status = CT_OK;
+ } else {
+ atun._atio.at_header.rqs_entry_type = RQSTYPE_ATIO;
+ atun._atio.at_header.rqs_entry_count = 1;
+ atun._atio.at_iid = iid;
+ atun._atio.at_tgt = tgt;
+ atun._atio.at_lun = lun;
+ atun._atio.at_tag_type = ttype;
+ atun._atio.at_tag_val = tval;
+ atun._atio.at_status = CT_OK;
+ }
+ return (isp_target_put_entry(isp, &atun));
+}
+
+/*
+ * Command completion- both for handling cases of no resources or
+ * no blackhole driver, or other cases where we have to, inline,
+ * finish the command sanely, or for normal command completion.
+ *
+ * The 'completion' code value has the scsi status byte in the low 8 bits.
+ * If status is a CHECK CONDITION and bit 8 is nonzero, then bits 12..15 have
+ * the sense key and bits 16..23 have the ASCQ and bits 24..31 have the ASC
+ * values.
+ *
+ * NB: the key, asc, ascq, cannot be used for parallel SCSI as it doesn't
+ * NB: inline SCSI sense reporting.
+ *
+ * For both parallel && fibre channel, we use the feature that does
+ * an automatic resource autoreplenish so we don't have then later do
+ * put of an atio to replenish the f/w's resource count.
+ */
+
+int
+isp_endcmd(struct ispsoftc *isp, void *arg, u_int32_t code, u_int32_t hdl)
+{
+ int sts;
+ union {
+ ct_entry_t _ctio;
+ ct2_entry_t _ctio2;
+ } un;
+
+ MEMZERO(&un, sizeof un);
+ sts = code & 0xff;
+
+ if (IS_FC(isp)) {
+ at2_entry_t *aep = arg;
+ ct2_entry_t *cto = &un._ctio2;
+
+ cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
+ cto->ct_header.rqs_entry_count = 1;
+ cto->ct_iid = aep->at_iid;
+#ifndef ISP2100_SCCLUN
+ cto->ct_lun = aep->at_lun;
+#endif
+ cto->ct_rxid = aep->at_rxid;
+ cto->rsp.m1.ct_scsi_status = sts & 0xff;
+ cto->ct_flags = CT2_SENDSTATUS | CT2_NO_DATA | CT2_FLAG_MODE1;
+ if (hdl == 0) {
+ cto->ct_flags |= CT2_CCINCR;
+ }
+ if (aep->at_datalen) {
+ cto->ct_resid = aep->at_datalen;
+ cto->ct_flags |= CT2_DATA_UNDER;
+ }
+ if ((sts & 0xff) == SCSI_CHECK && (sts & ECMD_SVALID)) {
+ cto->rsp.m1.ct_resp[0] = 0xf0;
+ cto->rsp.m1.ct_resp[2] = (code >> 12) & 0xf;
+ cto->rsp.m1.ct_resp[7] = 8;
+ cto->rsp.m1.ct_resp[12] = (code >> 24) & 0xff;
+ cto->rsp.m1.ct_resp[13] = (code >> 16) & 0xff;
+ cto->rsp.m1.ct_senselen = 16;
+ cto->ct_flags |= CT2_SNSLEN_VALID;
+ }
+ cto->ct_reserved = hdl;
+ } else {
+ at_entry_t *aep = arg;
+ ct_entry_t *cto = &un._ctio;
+
+ cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
+ cto->ct_header.rqs_entry_count = 1;
+ cto->ct_iid = aep->at_iid;
+ cto->ct_tgt = aep->at_tgt;
+ cto->ct_lun = aep->at_lun;
+ cto->ct_tag_type = aep->at_tag_type;
+ cto->ct_tag_val = aep->at_tag_val;
+ cto->ct_flags = CT_SENDSTATUS | CT_NO_DATA;
+ if (hdl == 0) {
+ cto->ct_flags |= CT_CCINCR;
+ }
+ cto->ct_scsi_status = sts;
+ cto->ct_reserved = hdl;
+ }
+ return (isp_target_put_entry(isp, &un));
+}
+
+void
+isp_target_async(isp, bus, event)
+ struct ispsoftc *isp;
+ int bus;
+ int event;
+{
+ tmd_event_t evt;
+ tmd_msg_t msg;
+
+ switch (event) {
+ /*
+ * These three we handle here to propagate an effective bus reset
+ * upstream, but these do not require any immediate notify actions
+ * so we return when done.
+ */
+ case ASYNC_LIP_OCCURRED:
+ case ASYNC_LOOP_UP:
+ case ASYNC_LOOP_DOWN:
+ evt.ev_bus = bus;
+ evt.ev_event = event;
+ (void) isp_async(isp, ISPASYNC_TARGET_EVENT, &evt);
+ return;
+
+ case ASYNC_LOOP_RESET:
+ case ASYNC_BUS_RESET:
+ case ASYNC_TIMEOUT_RESET:
+ if (IS_FC(isp)) {
+ return; /* we'll be getting an inotify instead */
+ }
+ evt.ev_bus = bus;
+ evt.ev_event = event;
+ (void) isp_async(isp, ISPASYNC_TARGET_EVENT, &evt);
+ break;
+ case ASYNC_DEVICE_RESET:
+ /*
+ * Bus Device Reset resets a specific target, so
+ * we pass this as a synthesized message.
+ */
+ MEMZERO(&msg, sizeof msg);
+ if (IS_FC(isp)) {
+ msg.nt_iid =
+ ((fcparam *)isp->isp_param)->isp_loopid;
+ } else {
+ msg.nt_iid =
+ ((sdparam *)isp->isp_param)->isp_initiator_id;
+ }
+ msg.nt_bus = bus;
+ msg.nt_msg[0] = MSG_BUS_DEV_RESET;
+ (void) isp_async(isp, ISPASYNC_TARGET_MESSAGE, &msg);
+ break;
+ default:
+ PRINTF("%s: isp_target_async: unknown event 0x%x\n",
+ isp->isp_name, event);
+ break;
+ }
+ isp_notify_ack(isp, NULL);
+}
+
+
+/*
+ * Process a received message.
+ * The ISP firmware can handle most messages, there are only
+ * a few that we need to deal with:
+ * - abort: clean up the current command
+ * - abort tag and clear queue
+ */
+
+static void
+isp_got_msg(isp, bus, inp)
+ struct ispsoftc *isp;
+ int bus;
+ in_entry_t *inp;
+{
+ u_int8_t status = inp->in_status & ~QLTM_SVALID;
+
+ if (status == IN_IDE_RECEIVED || status == IN_MSG_RECEIVED) {
+ tmd_msg_t msg;
+
+ MEMZERO(&msg, sizeof (msg));
+ msg.nt_bus = bus;
+ msg.nt_iid = inp->in_iid;
+ msg.nt_tgt = inp->in_tgt;
+ msg.nt_lun = inp->in_lun;
+ msg.nt_tagtype = inp->in_tag_type;
+ msg.nt_tagval = inp->in_tag_val;
+ MEMCPY(msg.nt_msg, inp->in_msg, IN_MSGLEN);
+ (void) isp_async(isp, ISPASYNC_TARGET_MESSAGE, &msg);
+ } else {
+ PRINTF("%s: unknown immediate notify status 0x%x\n",
+ isp->isp_name, inp->in_status);
+ }
+}
+
+/*
+ * Synthesize a message from the task management flags in a FCP_CMND_IU.
+ */
+static void
+isp_got_msg_fc(isp, bus, inp)
+ struct ispsoftc *isp;
+ int bus;
+ in_fcentry_t *inp;
+{
+ static char *f1 = "%s: %s from iid %d lun %d seq 0x%x\n";
+ static char *f2 =
+ "%s: unknown %s 0x%x lun %d iid %d task flags 0x%x seq 0x%x\n";
+
+ if (inp->in_status != IN_MSG_RECEIVED) {
+ PRINTF(f2, isp->isp_name, "immediate notify status",
+ inp->in_status, inp->in_lun, inp->in_iid,
+ inp->in_task_flags, inp->in_seqid);
+ } else {
+ tmd_msg_t msg;
+
+ MEMZERO(&msg, sizeof (msg));
+ msg.nt_bus = bus;
+ msg.nt_iid = inp->in_iid;
+#ifdef ISP2100_SCCLUN
+ msg.nt_lun = inp->in_scclun;
+#else
+ msg.nt_lun = inp->in_lun;
+#endif
+ msg.nt_tagval = inp->in_seqid;
+
+ if (inp->in_task_flags & TASK_FLAGS_ABORT_TASK) {
+ PRINTF(f1, isp->isp_name, "ABORT TASK",
+ inp->in_iid, inp->in_lun, inp->in_seqid);
+ msg.nt_msg[0] = MSG_ABORT_TAG;
+ } else if (inp->in_task_flags & TASK_FLAGS_CLEAR_TASK_SET) {
+ PRINTF(f1, isp->isp_name, "CLEAR TASK SET",
+ inp->in_iid, inp->in_lun, inp->in_seqid);
+ msg.nt_msg[0] = MSG_CLEAR_QUEUE;
+ } else if (inp->in_task_flags & TASK_FLAGS_TARGET_RESET) {
+ PRINTF(f1, isp->isp_name, "TARGET RESET",
+ inp->in_iid, inp->in_lun, inp->in_seqid);
+ msg.nt_msg[0] = MSG_BUS_DEV_RESET;
+ } else if (inp->in_task_flags & TASK_FLAGS_CLEAR_ACA) {
+ PRINTF(f1, isp->isp_name, "CLEAR ACA",
+ inp->in_iid, inp->in_lun, inp->in_seqid);
+ /* ???? */
+ msg.nt_msg[0] = MSG_REL_RECOVERY;
+ } else if (inp->in_task_flags & TASK_FLAGS_TERMINATE_TASK) {
+ PRINTF(f1, isp->isp_name, "TERMINATE TASK",
+ inp->in_iid, inp->in_lun, inp->in_seqid);
+ msg.nt_msg[0] = MSG_TERM_IO_PROC;
+ } else {
+ PRINTF(f2, isp->isp_name, "task flag",
+ inp->in_status, inp->in_lun, inp->in_iid,
+ inp->in_task_flags, inp->in_seqid);
+ }
+ if (msg.nt_msg[0]) {
+ (void) isp_async(isp, ISPASYNC_TARGET_MESSAGE, &msg);
+ }
+ }
+}
+
+static void
+isp_notify_ack(isp, arg)
+ struct ispsoftc *isp;
+ void *arg;
+{
+ char storage[QENTRY_LEN];
+ u_int16_t iptr, optr;
+ void *outp;
+
+ if (isp_getrqentry(isp, &iptr, &optr, &outp)) {
+ PRINTF("%s: Request Queue Overflow For isp_notify_ack\n",
+ isp->isp_name);
+ return;
+ }
+
+ MEMZERO(storage, QENTRY_LEN);
+
+ if (IS_FC(isp)) {
+ na_fcentry_t *na = (na_fcentry_t *) storage;
+ if (arg) {
+ in_fcentry_t *inp = arg;
+ MEMCPY(storage, arg, sizeof (isphdr_t));
+ na->na_iid = inp->in_iid;
+#ifdef ISP2100_SCCLUN
+ na->na_lun = inp->in_scclun;
+#else
+ na->na_lun = inp->in_lun;
+#endif
+ na->na_task_flags = inp->in_task_flags;
+ na->na_seqid = inp->in_seqid;
+ na->na_flags = NAFC_RCOUNT;
+ if (inp->in_status == IN_RESET) {
+ na->na_flags |= NAFC_RST_CLRD;
+ }
+ } else {
+ na->na_flags = NAFC_RST_CLRD;
+ }
+ ISP_SWIZ_NOT_ACK_FC(isp, outp, na);
+ } else {
+ na_entry_t *na = (na_entry_t *) storage;
+ if (arg) {
+ in_entry_t *inp = arg;
+ MEMCPY(storage, arg, sizeof (isphdr_t));
+ na->na_iid = inp->in_iid;
+ na->na_lun = inp->in_lun;
+ na->na_tgt = inp->in_tgt;
+ na->na_seqid = inp->in_seqid;
+ if (inp->in_status == IN_RESET) {
+ na->na_flags = NA_RST_CLRD;
+ }
+ } else {
+ na->na_flags = NA_RST_CLRD;
+ }
+ ISP_SWIZ_NOT_ACK(isp, outp, na);
+ }
+ ISP_TDQE(isp, "isp_notify_ack", (int) optr, storage);
+ ISP_ADD_REQUEST(isp, iptr);
+}
+
+static void
+isp_handle_atio(isp, aep)
+ struct ispsoftc *isp;
+ at_entry_t *aep;
+{
+ int lun;
+ lun = aep->at_lun;
+ /*
+ * The firmware status (except for the QLTM_SVALID bit) indicates
+ * why this ATIO was sent to us.
+ *
+ * If QLTM_SVALID 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(aep->at_status & ~QLTM_SVALID) {
+ case AT_PATH_INVALID:
+ /*
+ * ATIO rejected by the firmware due to disabled lun.
+ */
+ PRINTF("%s: rejected ATIO for disabled lun %d\n",
+ isp->isp_name, lun);
+ break;
+ case AT_NOCAP:
+ /*
+ * Requested Capability not available
+ * We sent an ATIO that overflowed the firmware's
+ * command resource count.
+ */
+ PRINTF("%s: rejected ATIO for lun %d because of command count"
+ " overflow\n", isp->isp_name, lun);
+ 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. We set the command
+ * resource count in the Enable Lun entry and no
+ * not increment it. Therefore we should never get
+ * this status here.
+ */
+ PRINTF("%s: ATIO returned for lun %d because it was in the "
+ " middle of coping with a Bus Device Reset\n",
+ isp->isp_name, lun);
+ break;
+
+ case AT_CDB: /* Got a CDB */
+ case AT_PHASE_ERROR: /* Bus Phase Sequence Error */
+ /*
+ * Punt to platform specific layer.
+ */
+ (void) isp_async(isp, ISPASYNC_TARGET_ACTION, aep);
+ break;
+
+ case AT_RESET:
+ /*
+ * A bus reset came along an blew away this command. Why
+ * they do this in addition the async event code stuff,
+ * I dunno.
+ *
+ * Ignore it because the async event will clear things
+ * up for us.
+ */
+ PRINTF("%s: ATIO returned for lun %d from initiator %d because"
+ " a Bus Reset occurred\n", isp->isp_name, lun,
+ aep->at_iid);
+ break;
+
+
+ default:
+ PRINTF("%s: Unknown ATIO status 0x%x from initiator %d for lun"
+ " %d\n", isp->isp_name, aep->at_status, aep->at_iid, lun);
+ (void) isp_target_put_atio(isp, aep->at_iid, aep->at_tgt,
+ lun, aep->at_tag_type, aep->at_tag_val);
+ break;
+ }
+}
+
+static void
+isp_handle_atio2(isp, aep)
+ struct ispsoftc *isp;
+ at2_entry_t *aep;
+{
+ int lun;
+#ifdef ISP2100_SCCLUN
+ lun = aep->at_scclun;
+#else
+ lun = aep->at_lun;
+#endif
+ /*
+ * The firmware status (except for the QLTM_SVALID bit) indicates
+ * why this ATIO was sent to us.
+ *
+ * If QLTM_SVALID 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(aep->at_status & ~QLTM_SVALID) {
+ case AT_PATH_INVALID:
+ /*
+ * ATIO rejected by the firmware due to disabled lun.
+ */
+ PRINTF("%s: rejected ATIO2 for disabled lun %d\n",
+ isp->isp_name, lun);
+ break;
+ case AT_NOCAP:
+ /*
+ * Requested Capability not available
+ * We sent an ATIO that overflowed the firmware's
+ * command resource count.
+ */
+ PRINTF("%s: rejected ATIO2 for lun %d because of command count"
+ " overflow\n", isp->isp_name, lun);
+ 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. We set the command
+ * resource count in the Enable Lun entry and no
+ * not increment it. Therefore we should never get
+ * this status here.
+ */
+ PRINTF("%s: ATIO2 returned for lun %d because it was in the "
+ " middle of coping with a Bus Device Reset\n",
+ isp->isp_name, lun);
+ break;
+
+ case AT_CDB: /* Got a CDB */
+ /*
+ * Punt to platform specific layer.
+ */
+ (void) isp_async(isp, ISPASYNC_TARGET_ACTION, aep);
+ break;
+
+ case AT_RESET:
+ /*
+ * A bus reset came along an blew away this command. Why
+ * they do this in addition the async event code stuff,
+ * I dunno.
+ *
+ * Ignore it because the async event will clear things
+ * up for us.
+ */
+ PRINTF("%s: ATIO2 returned for lun %d from initiator %d because"
+ " a Bus Reset occurred\n", isp->isp_name, lun,
+ aep->at_iid);
+ break;
+
+
+ default:
+ PRINTF("%s: Unknown ATIO2 status 0x%x from initiator %d for lun"
+ " %d\n", isp->isp_name, aep->at_status, aep->at_iid, lun);
+ (void) isp_target_put_atio(isp, aep->at_iid, 0, lun, 0, 0);
+ break;
+ }
+}
+
+static void
+isp_handle_ctio(isp, ct)
+ struct ispsoftc *isp;
+ ct_entry_t *ct;
+{
+ ISP_SCSI_XFER_T *xs;
+ int pl = 0;
+ char *fmsg = NULL;
+
+ if (ct->ct_reserved) {
+ xs = isp_find_xs(isp, ct->ct_reserved);
+ if (xs == NULL)
+ pl = 0;
+ } else {
+ pl = 2;
+ xs = NULL;
+ }
+
+ switch(ct->ct_status & ~QLTM_SVALID) {
+ case CT_OK:
+ /*
+ * There are generally 3 possibilities as to why we'd get
+ * this condition:
+ * We disconnected after receiving a CDB.
+ * We sent or received data.
+ * We sent status & command complete.
+ */
+
+ if ((ct->ct_flags & CT_DATAMASK) == CT_NO_DATA) {
+ /*
+ * Nothing to do in this case.
+ */
+ IDPRINTF(pl, ("%s: CTIO- initiator disconnected OK\n",
+ isp->isp_name));
+ return;
+ }
+ break;
+
+ case CT_BDR_MSG:
+ /*
+ * Bus Device Reset message received or the SCSI Bus has
+ * been Reset; the firmware has gone to Bus Free.
+ *
+ * The firmware generates an async mailbox interupt to
+ * notify us of this and returns outstanding CTIOs with this
+ * status. These CTIOs are handled in that same way as
+ * CT_ABORTED ones, so just fall through here.
+ */
+ fmsg = "Bus Device Reset";
+ /*FALLTHROUGH*/
+ case CT_RESET:
+ if (fmsg == NULL)
+ fmsg = "Bus Reset";
+ /*FALLTHROUGH*/
+ case CT_ABORTED:
+ /*
+ * When an Abort message is received the firmware goes to
+ * Bus Free and returns all outstanding CTIOs with the status
+ * set, then sends us an Immediate Notify entry.
+ */
+ if (fmsg == NULL)
+ fmsg = "ABORT TASK sent by Initiator";
+
+ PRINTF("%s: CTIO destroyed by %s\n", isp->isp_name, fmsg);
+ break;
+
+ case CT_INVAL:
+ /*
+ * CTIO rejected by the firmware due to disabled lun.
+ * "Cannot Happen".
+ */
+ PRINTF("%s: Firmware rejected CTIO for disabled lun %d\n",
+ isp->isp_name, ct->ct_lun);
+ break;
+
+ case CT_NOPATH:
+ /*
+ * CTIO rejected by the firmware due "no path for the
+ * nondisconnecting nexus specified". This means that
+ * we tried to access the bus while a non-disconnecting
+ * command is in process.
+ */
+ PRINTF("%s: Firmware rejected CTIO for bad nexus %d/%d/%d\n",
+ isp->isp_name, ct->ct_iid, ct->ct_tgt, ct->ct_lun);
+ break;
+
+ case CT_RSELTMO:
+ fmsg = "Reselection";
+ /*FALLTHROUGH*/
+ case CT_TIMEOUT:
+ if (fmsg == NULL)
+ fmsg = "Command";
+ PRINTF("%s: Firmware timed out on %s\n", isp->isp_name, fmsg);
+ break;
+
+ case CT_ERR:
+ fmsg = "Completed with Error";
+ /*FALLTHROUGH*/
+ case CT_PHASE_ERROR:
+ if (fmsg == NULL)
+ fmsg = "Phase Sequence Error";
+ /*FALLTHROUGH*/
+ case CT_TERMINATED:
+ if (fmsg == NULL)
+ fmsg = "terminated by TERMINATE TRANSFER";
+ /*FALLTHROUGH*/
+ case CT_NOACK:
+ if (fmsg == NULL)
+ fmsg = "unacknowledged Immediate Notify pending";
+
+ PRINTF("%s: CTIO returned by f/w- %s\n", isp->isp_name, fmsg);
+#if 0
+ if (status & SENSEVALID) {
+ bcopy((caddr_t) (cep + CTIO_SENSE_OFFSET),
+ (caddr_t) &cdp->cd_sensedata,
+ sizeof(scsi_sense_t));
+ cdp->cd_flags |= CDF_SENSEVALID;
+ }
+#endif
+ break;
+ default:
+ PRINTF("%s: Unknown CTIO status 0x%x\n", isp->isp_name,
+ ct->ct_status & ~QLTM_SVALID);
+ break;
+ }
+
+ if (xs == NULL) {
+ /*
+ * There may be more than one CTIO for a data transfer,
+ * or this may be a status CTIO we're not monitoring.
+ *
+ * The assumption is that they'll all be returned in the
+ * order we got them.
+ */
+ if (ct->ct_reserved == 0) {
+ if ((ct->ct_flags & CT_SENDSTATUS) == 0) {
+ IDPRINTF(pl,
+ ("%s: intermediate CTIO completed ok\n",
+ isp->isp_name));
+ } else {
+ IDPRINTF(pl,
+ ("%s: unmonitored CTIO completed ok\n",
+ isp->isp_name));
+ }
+ } else {
+ IDPRINTF(pl,
+ ("%s: NO xs for CTIO (handle 0x%x) status 0x%x\n",
+ isp->isp_name, ct->ct_reserved,
+ ct->ct_status & ~QLTM_SVALID));
+ }
+ } else {
+ if (ct->ct_flags & CT_SENDSTATUS) {
+ /*
+ * Sent status and command complete.
+ *
+ * We're now really done with this command, so we
+ * punt to the platform dependent layers because
+ * only there can we do the appropriate command
+ * complete thread synchronization.
+ */
+ IDPRINTF(pl,
+ ("%s: status CTIO complete\n", isp->isp_name));
+ } else {
+ /*
+ * Final CTIO completed. Release DMA resources and
+ * notify platform dependent layers.
+ */
+ IDPRINTF(pl,
+ ("%s: data CTIO complete\n", isp->isp_name));
+ ISP_DMAFREE(isp, xs, ct->ct_reserved);
+ }
+ (void) isp_async(isp, ISPASYNC_TARGET_ACTION, ct);
+ /*
+ * The platform layer will destroy the handle if appropriate.
+ */
+ }
+}
+
+static void
+isp_handle_ctio2(isp, ct)
+ struct ispsoftc *isp;
+ ct2_entry_t *ct;
+{
+ ISP_SCSI_XFER_T *xs;
+ int pl = 3;
+ char *fmsg = NULL;
+
+ if (ct->ct_reserved) {
+ xs = isp_find_xs(isp, ct->ct_reserved);
+ if (xs == NULL)
+ pl = 0;
+ } else {
+ pl = 2;
+ xs = NULL;
+ }
+
+ switch(ct->ct_status & ~QLTM_SVALID) {
+ case CT_OK:
+ /*
+ * There are generally 2 possibilities as to why we'd get
+ * this condition:
+ * We sent or received data.
+ * We sent status & command complete.
+ */
+
+ break;
+
+ case CT_BDR_MSG:
+ /*
+ * Bus Device Reset message received or the SCSI Bus has
+ * been Reset; the firmware has gone to Bus Free.
+ *
+ * The firmware generates an async mailbox interupt to
+ * notify us of this and returns outstanding CTIOs with this
+ * status. These CTIOs are handled in that same way as
+ * CT_ABORTED ones, so just fall through here.
+ */
+ fmsg = "Bus Device Reset";
+ /*FALLTHROUGH*/
+ case CT_RESET:
+ if (fmsg == NULL)
+ fmsg = "Bus Reset";
+ /*FALLTHROUGH*/
+ case CT_ABORTED:
+ /*
+ * When an Abort message is received the firmware goes to
+ * Bus Free and returns all outstanding CTIOs with the status
+ * set, then sends us an Immediate Notify entry.
+ */
+ if (fmsg == NULL)
+ fmsg = "ABORT TASK sent by Initiator";
+
+ PRINTF("%s: CTIO2 destroyed by %s\n", isp->isp_name, fmsg);
+ break;
+
+ case CT_INVAL:
+ /*
+ * CTIO rejected by the firmware - invalid data direction.
+ */
+ PRINTF("%s: CTIO2 had wrong data directiond\n", isp->isp_name);
+ break;
+
+ case CT_NOPATH:
+ /*
+ * CTIO rejected by the firmware due "no path for the
+ * nondisconnecting nexus specified". This means that
+ * we tried to access the bus while a non-disconnecting
+ * command is in process.
+ */
+ PRINTF("%s: Firmware rejected CTIO2 for bad nexus %d->%d\n",
+ isp->isp_name, ct->ct_iid, ct->ct_lun);
+ break;
+
+ case CT_RSELTMO:
+ fmsg = "Reselection";
+ /*FALLTHROUGH*/
+ case CT_TIMEOUT:
+ if (fmsg == NULL)
+ fmsg = "Command";
+ PRINTF("%s: Firmware timed out on %s\n", isp->isp_name, fmsg);
+ break;
+
+ case CT_ERR:
+ fmsg = "Completed with Error";
+ /*FALLTHROUGH*/
+ case CT_PHASE_ERROR: /* Bus phase sequence error */
+ if (fmsg == NULL)
+ fmsg = "Phase Sequence Error";
+ /*FALLTHROUGH*/
+ case CT_TERMINATED:
+ if (fmsg == NULL)
+ fmsg = "terminated by TERMINATE TRANSFER";
+ /*FALLTHROUGH*/
+ case CT_LOGOUT:
+ if (fmsg == NULL)
+ fmsg = "Port Logout";
+ /*FALLTHROUGH*/
+ case CT_PORTNOTAVAIL:
+ if (fmsg == NULL)
+ fmsg = "Port not available";
+ case CT_NOACK:
+ if (fmsg == NULL)
+ fmsg = "unacknowledged Immediate Notify pending";
+
+ PRINTF("%s: CTIO returned by f/w- %s\n", isp->isp_name, fmsg);
+#if 0
+ if (status & SENSEVALID) {
+ bcopy((caddr_t) (cep + CTIO_SENSE_OFFSET),
+ (caddr_t) &cdp->cd_sensedata,
+ sizeof(scsi_sense_t));
+ cdp->cd_flags |= CDF_SENSEVALID;
+ }
+#endif
+ break;
+
+ case CT_INVRXID:
+ /*
+ * CTIO rejected by the firmware because an invalid RX_ID.
+ * Just print a message.
+ */
+ PRINTF("%s: CTIO2 completed with Invalid RX_ID 0x%x\n",
+ isp->isp_name, ct->ct_rxid);
+ break;
+
+ default:
+ IDPRINTF(pl, ("%s: Unknown CTIO status 0x%x\n", isp->isp_name,
+ ct->ct_status & ~QLTM_SVALID));
+ break;
+ }
+
+ if (xs == NULL) {
+ /*
+ * There may be more than one CTIO for a data transfer,
+ * or this may be a status CTIO we're not monitoring.
+ *
+ * The assumption is that they'll all be returned in the
+ * order we got them.
+ */
+ if (ct->ct_reserved == 0) {
+ if ((ct->ct_flags & CT_SENDSTATUS) == 0) {
+ IDPRINTF(pl,
+ ("%s: intermediate CTIO completed ok\n",
+ isp->isp_name));
+ } else {
+ IDPRINTF(pl,
+ ("%s: unmonitored CTIO completed ok\n",
+ isp->isp_name));
+ }
+ } else {
+ IDPRINTF(pl,
+ ("%s: NO xs for CTIO (handle 0x%x) status 0x%x\n",
+ isp->isp_name, ct->ct_reserved,
+ ct->ct_status & ~QLTM_SVALID));
+ }
+ } else {
+ if (ct->ct_flags & CT_SENDSTATUS) {
+ /*
+ * Sent status and command complete.
+ *
+ * We're now really done with this command, so we
+ * punt to the platform dependent layers because
+ * only there can we do the appropriate command
+ * complete thread synchronization.
+ */
+ IDPRINTF(pl,
+ ("%s: status CTIO complete\n", isp->isp_name));
+ } else {
+ /*
+ * Final CTIO completed. Release DMA resources and
+ * notify platform dependent layers.
+ */
+ IDPRINTF(pl,
+ ("%s: data CTIO complete\n", isp->isp_name));
+ ISP_DMAFREE(isp, xs, ct->ct_reserved);
+ }
+ (void) isp_async(isp, ISPASYNC_TARGET_ACTION, ct);
+ /*
+ * The platform layer will destroy the handle if appropriate.
+ */
+ }
+}
+#endif
diff --git a/sys/dev/ic/isp_target.h b/sys/dev/ic/isp_target.h
new file mode 100644
index 00000000000..7b86aa1de94
--- /dev/null
+++ b/sys/dev/ic/isp_target.h
@@ -0,0 +1,654 @@
+/* $OpenBSD: isp_target.h,v 1.1 2000/02/20 21:22:40 mjacob Exp $ */
+/*
+ * Qlogic Target Mode Structure and Flag Definitions
+ *
+ * Copyright (c) 1997, 1998
+ * Patrick Stirling
+ * pms@psconsult.com
+ * All rights reserved.
+ *
+ * Additional Copyright (c) 1999
+ * Matthew Jacob
+ * mjacob@feral.com
+ * 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
+ * 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 _ISPTARGET_H
+#define _ISPTARGET_H
+
+/*
+ * Defines for all entry types
+ */
+#define QLTM_SVALID 0x80
+#define QLTM_SENSELEN 18
+
+/*
+ * Structure for Enable Lun and Modify Lun queue entries
+ */
+typedef struct {
+ isphdr_t le_header;
+ u_int32_t le_reserved;
+ 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 */
+ u_int32_t le_flags; /* Not for FC */
+ u_int8_t le_status;
+ u_int8_t le_reserved2;
+ 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 */
+ u_int16_t le_timeout;
+ u_int16_t le_reserved3[20];
+} lun_entry_t;
+
+/*
+ * le_flags values
+ */
+#define LUN_TQAE 0x00000001 /* bit1 Tagged Queue Action Enable */
+#define LUN_DSSM 0x01000000 /* bit24 Disable Sending SDP Message */
+#define LUN_DM 0x40000000 /* bit30 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_OK 0x01 /* we be rockin' */
+#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_reserved;
+ u_int8_t in_lun; /* lun */
+ u_int8_t in_iid; /* initiator */
+ u_int8_t in_reserved2;
+ u_int8_t in_tgt; /* target */
+ u_int32_t in_flags;
+ 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 */
+ u_int16_t in_seqid; /* sequence id */
+ u_int8_t in_msg[IN_MSGLEN]; /* SCSI message bytes */
+ u_int16_t in_reserved3[IN_RSVDLEN];
+ u_int8_t in_sense[QLTM_SENSELEN];/* suggested sense data */
+} in_entry_t;
+
+typedef struct {
+ isphdr_t in_header;
+ u_int32_t in_reserved;
+ u_int8_t in_lun; /* lun */
+ u_int8_t in_iid; /* initiator */
+ u_int16_t in_scclun;
+ u_int32_t in_reserved2;
+ 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_RESET 0x0E /* Bus Reset occurred */
+#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_ABORT_TASK 0x20 /* task named in RX_ID is being aborted (FC) */
+#define IN_PORT_LOGOUT 0x29 /* port has logged out (FC) */
+#define IN_PORT_CHANGED 0x2A /* port changed */
+#define IN_GLOBAL_LOGO 0x2E /* all ports logged out */
+
+/*
+ * Values for the in_task_flags field- should only get one at a time!
+ */
+#define TASK_FLAGS_ABORT_TASK (1<<9)
+#define TASK_FLAGS_CLEAR_TASK_SET (1<<10)
+#define TASK_FLAGS_TARGET_RESET (1<<13)
+#define TASK_FLAGS_CLEAR_ACA (1<<14)
+#define TASK_FLAGS_TERMINATE_TASK (1<<15)
+
+#ifndef MSG_ABORT_TAG
+#define MSG_ABORT_TAG 0x06
+#endif
+#ifndef MSG_CLEAR_QUEUE
+#define MSG_CLEAR_QUEUE 0x0e
+#endif
+#ifndef MSG_BUS_DEV_RESET
+#define MSG_BUS_DEV_RESET 0x0b
+#endif
+#ifndef MSG_REL_RECOVERY
+#define MSG_REL_RECOVERY 0x10
+#endif
+#ifndef MSG_TERM_IO_PROC
+#define MSG_TERM_IO_PROC 0x11
+#endif
+
+
+/*
+ * Notify Acknowledge Entry structure
+ */
+#define NA_RSVDLEN 22
+typedef struct {
+ isphdr_t na_header;
+ u_int32_t na_reserved;
+ u_int8_t na_lun; /* lun */
+ u_int8_t na_iid; /* initiator */
+ u_int8_t na_reserved2;
+ u_int8_t na_tgt; /* target */
+ u_int32_t na_flags;
+ u_int8_t na_status;
+ u_int8_t na_event;
+ u_int16_t na_seqid; /* sequence id */
+ u_int16_t na_reserved3[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_reserved;
+ u_int8_t na_lun; /* lun */
+ u_int8_t na_iid; /* initiator */
+ u_int16_t na_scclun;
+ u_int16_t na_flags;
+ u_int16_t na_reserved2;
+ u_int16_t na_status;
+ u_int16_t na_task_flags;
+ u_int16_t na_seqid; /* sequence id */
+ u_int16_t na_reserved3[NA2_RSVDLEN];
+} na_fcentry_t;
+#define NAFC_RCOUNT 0x80 /* increment resource count */
+#define NAFC_RST_CLRD 0x20 /* Clear LIP Reset */
+/*
+ * Accept Target I/O Entry structure
+ */
+#define ATIO_CDBLEN 26
+
+typedef struct {
+ isphdr_t at_header;
+ u_int32_t at_reserved;
+ 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 */
+ u_int32_t at_flags;
+ 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 */
+ u_int8_t at_cdb[ATIO_CDBLEN]; /* received CDB */
+ u_int8_t at_sense[QLTM_SENSELEN];/* 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_RESET 0x0E /* SCSI Bus Reset Occurred */
+#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_reserved;
+ u_int8_t at_lun; /* lun or reserved */
+ u_int8_t at_iid; /* initiator */
+ u_int16_t at_rxid; /* response ID */
+ u_int16_t at_flags;
+ u_int16_t at_status; /* firmware status */
+ u_int8_t at_reserved1;
+ u_int8_t at_taskcodes;
+ u_int8_t at_taskflags;
+ u_int8_t at_execodes;
+ u_int8_t at_cdb[ATIO2_CDBLEN]; /* received CDB */
+ u_int32_t at_datalen; /* allocated data len */
+ u_int16_t at_scclun; /* SCC Lun or reserved */
+ u_int16_t at_reserved2;
+ u_int16_t at_scsi_status;
+ u_int8_t at_sense[QLTM_SENSELEN];
+} 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
+
+/*
+ * 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;
+ u_int8_t ct_lun; /* lun */
+ u_int8_t ct_iid; /* initiator id */
+ u_int8_t ct_reserved2;
+ u_int8_t ct_tgt; /* our target id */
+ u_int32_t ct_flags;
+ 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 */
+ 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;
+
+/*
+ * For some of the dual port SCSI adapters, port (bus #) is reported
+ * in the MSbit of ct_iid. Bit fields are a bit too awkward here.
+ *
+ * Note that this does not apply to FC adapters at all which can and
+ * do report IIDs between 129 && 255 (these represent devices that have
+ * logged in across a SCSI fabric).
+ */
+#define GET_IID_VAL(x) (x & 0x3f)
+#define GET_BUS_VAL(x) ((x >> 7) & 0x1)
+#define SET_IID_VAL(y, x) (y | (x & 0x3f))
+#define SET_BUS_VAL(y, x) (y | ((x & 0x1) << 7))
+
+/*
+ * ct_flags values
+ */
+#define CT_TQAE 0x00000001 /* bit 1, Tagged Queue Action enable */
+#define CT_DATA_IN 0x00000040 /* bits 6&7, Data direction */
+#define CT_DATA_OUT 0x00000080 /* bits 6&7, Data direction */
+#define CT_NO_DATA 0x000000C0 /* bits 6&7, Data direction */
+#define CT_CCINCR 0x00000100 /* bit 8, autoincrement atio count */
+#define CT_DATAMASK 0x000000C0 /* bits 6&7, Data direction */
+#define CT_NODISC 0x00008000 /* bit 15, Disconnects disabled */
+#define CT_DSDP 0x01000000 /* bit 24, Disable Save Data Pointers */
+#define CT_SENDRDP 0x04000000 /* bit 26, Send Restore Pointers msg */
+#define CT_SENDSTATUS 0x80000000 /* bit 31, 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_PORTNOTAVAIL 0x28 /* port not available */
+#define CT_LOGOUT 0x29 /* port logout */
+#define CT_PORTCHANGED 0x2A /* port changed */
+#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;
+ u_int8_t ct_lun; /* lun */
+ u_int8_t ct_iid; /* initiator id */
+ 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 */
+ 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[QLTM_SENSELEN];
+ } 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_DATAMASK
+#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
+
+/*
+ * Macros for packing/unpacking the above structures
+ */
+
+#ifdef __sparc__
+#define ISP_SBUS_SWOZZLE(isp, src, dest, taga, tagb) \
+ if (isp->isp_bus == ISP_SBUS) { \
+ source -> taga = dest -> tagb; \
+ source -> tagb = dest -> taga; \
+ } else { \
+ source -> taga = dest -> taga; \
+ source -> tagb = dest -> taga; \
+ }
+#else
+#define ISP_SBUS_SWOZZLE(isp, src, dest, taga, tagb) \
+ source -> taga = dest -> taga; \
+ source -> tagb = dest -> taga;
+#endif
+
+#define MCIDF(d, s) if ((void *) d != (void *)s) MEMCPY(d, s, QENTRY_LEN)
+
+/* This is really only for SBus cards on a sparc */
+#ifdef __sparc__
+#define ISP_SWIZ_ATIO(isp, dest, vsrc) \
+{ \
+ at_entry_t *source = (at_entry_t *) vsrc; \
+ at_entry_t local, *vdst; \
+ if ((void *)dest == (void *)vsrc) { \
+ MEMCPY(vsrc, &local, sizeof (at_entry_t)); \
+ vdst = &local; \
+ } else { \
+ vdst = dest; \
+ } \
+ vdst->at_header = source->at_header; \
+ vdst->at_reserved2 = source->at_reserved2; \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, at_lun, at_iid); \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, at_cdblen, at_tgt); \
+ vdst->at_flags = source->at_flags; \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, at_status, at_scsi_status); \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, at_tag_val, at_tag_type); \
+ MEMCPY(vdst->at_cdb, source->at_cdb, ATIO_CDBLEN); \
+ MEMCPY(vdst->at_sense, source->at_sense, QLTM_SENSELEN); \
+}
+
+#define ISP_SWIZ_CTIO(isp, dest, vsrc) \
+{ \
+ ct_entry_t *source = (ct_entry-t *) vsrc; \
+ ct_entry_t *local, *vdst; \
+ if ((void *)dest == (void *)vsrc) { \
+ MEMCPY(vsrc, &local, sizeof (ct_entry_t)); \
+ vdst = &local; \
+ } else { \
+ vdst = dest; \
+ } \
+ vdst->ct_header = source->ct_header; \
+ vdst->ct_reserved = source->ct_reserved; \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, ct_lun, ct_iid); \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, ct_rsvd, ct_tgt); \
+ vdst->ct_flags = source->ct_flags; \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, ct_status, ct_scsi_status); \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, ct_tag_val, ct_tag_type); \
+ vdst->ct_xfrlen = source->ct_xfrlen; \
+ vdst->ct_resid = source->ct_resid; \
+ vdst->ct_timeout = source->ct_timeout; \
+ vdst->ct_seg_count = source->ct_seg_count; \
+ MEMCPY(vdst->ct_cdb, source->ct_cdb, ATIO_CDBLEN); \
+ MEMCPY(vdst->ct_sense, source->ct_sense, QLTM_SENSELEN); \
+ vdst->ct_dataseg = source->ct_dataseg; \
+}
+#define ISP_SWIZ_ENABLE_LUN(isp, dest, vsrc) \
+{ \
+ lun_entry_t *source = (lun_entry_t *)vsrc; \
+ lun_entry_t *local, *vdst; \
+ if ((void *)dest == (void *)vsrc) { \
+ MEMCPY(vsrc, &local, sizeof (lun_entry_t)); \
+ vdst = &local; \
+ } else { \
+ vdst = dest; \
+ } \
+ vdst->le_header = source->le_header; \
+ vdst->le_reserved2 = source->le_reserved2; \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, le_lun, le_rsvd); \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, le_ops, le_tgt); \
+ vdst->le_flags = source->le_flags; \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, le_status, le_rsvd2); \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, le_cmd_count, le_in_count); \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, le_cdb6len, le_cdb7len); \
+ vdst->le_timeout = source->le_timeout; \
+ vdst->le_reserved = source->le_reserved; \
+}
+#define ISP_SWIZ_NOTIFY(isp, dest, vsrc) \
+{ \
+ in_entry_type *source = (in_entry_t *)vsrc; \
+ in_entry_t *local, *vdst; \
+ if ((void *)dest == (void *)vsrc) { \
+ MEMCPY(vsrc, &local, sizeof (in_entry_t)); \
+ vdst = &local; \
+ } else { \
+ vdst = dest; \
+ } \
+ vdst->in_header = source->in_header; \
+ vdst->in_reserved2 = source->in_reserved2; \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, in_lun, in_iid); \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, in_rsvd, in_tgt); \
+ vdst->in_flags = source->in_flags; \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, in_status, in_rsvd2); \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, in_tag_val, in_tag_type); \
+ vdst->in_seqid = source->in_seqid; \
+ MEMCPY(vdst->in_msg, source->in_msg, IN_MSGLEN); \
+ MEMCPY(vdst->in_reserved, source->in_reserved, IN_RESERVED); \
+ MEMCPY(vdst->in_sense, source->in_sense, QLTM_SENSELEN); \
+}
+#define ISP_SWIZ_NOT_ACK(isp, dest) \
+{ \
+ na_entry_t *source = (na_entry_t *)vsrc; \
+ na_entry_t *local, *vdst; \
+ if ((void *)dest == (void *)vsrc) { \
+ MEMCPY(vsrc, &local, sizeof (na_entry_t)); \
+ vdst = &local; \
+ } else { \
+ vdst = dest; \
+ } \
+ vdst->na_header = source->na_header; \
+ vdst->na_reserved2 = source->na_reserved2; \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, na_lun, na_iid); \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, na_rsvd, na_tgt); \
+ vdst->na_flags = source->na_flags; \
+ ISP_SBUS_SWOZZLE(isp, source, vdst, na_status, na_event); \
+ vdst->na_seqid = source->na_seqid; \
+ MEMCPY(vdst->na_reserved, source->na_reserved, NA_RSVDLEN); \
+}
+#define ISP_SWIZ_NOT_ACK_FC(isp, d, s) MCIDF(d, s)
+#define ISP_SWIZ_ATIO2(isp, d, s) MCIDF(d, s)
+#define ISP_SWIZ_CTIO2(isp, d, s) MCIDF(d, s)
+#else
+#define ISP_SWIZ_ATIO(isp, d, s) MCIDF(d, s)
+#define ISP_SWIZ_CTIO(isp, d, s) MCIDF(d, s)
+#define ISP_SWIZ_ENABLE_LUN(isp, d, s) MCIDF(d, s)
+#define ISP_SWIZ_NOTIFY(isp, d, s) MCIDF(d, s)
+#define ISP_SWIZ_NOT_ACK(isp, d, s) MCIDF(d, s)
+#define ISP_SWIZ_NOT_ACK_FC(isp, d, s) MCIDF(d, s)
+#define ISP_SWIZ_ATIO2(isp, d, s) MCIDF(d, s)
+#define ISP_SWIZ_CTIO2(isp, d, s) MCIDF(d, s)
+#endif
+
+/*
+ * Debug macros
+ */
+
+extern int isp_tdebug;
+#define ISP_TDQE(isp, msg, idx, arg) \
+ if (isp_tdebug > 3) isp_print_qentry(isp, msg, idx, arg)
+
+#define ITDEBUG(level, msg) if (isp_tdebug >= level) PRINTF msg
+
+/*
+ * The functions below are target mode functions that
+ * are generally internal to the Qlogic driver.
+ */
+
+/*
+ * This function handles new response queue entry appropriate for target mode.
+ */
+int isp_target_notify __P((struct ispsoftc *, void *, u_int16_t *));
+
+/*
+ * Enable/Disable/Modify a logical unit.
+ */
+#define DFLT_CMD_CNT (RESULT_QUEUE_LEN >> 1)
+#define DFLT_INOTIFY (4)
+int isp_lun_cmd __P((struct ispsoftc *isp, int, int, int, int, u_int32_t));
+
+/*
+ * General request queue 'put' routine for target mode entries.
+ */
+int isp_target_put_entry __P((struct ispsoftc *isp, void *));
+
+/*
+ * General routine to put back an ATIO entry-
+ * used for replenishing f/w resource counts.
+ */
+int
+isp_target_put_atio __P((struct ispsoftc *isp, int, int, int, int, int));
+
+/*
+ * General routine to send a final CTIO for a command- used mostly for
+ * local responses.
+ */
+int
+isp_endcmd __P((struct ispsoftc *isp, void *, u_int32_t, u_int32_t));
+#define ECMD_SVALID 0x100
+
+/*
+ * Handle an asynchronous event
+ */
+
+void isp_target_async __P((struct ispsoftc *, int, int));
+
+#endif /* _ISPTARGET_H */
diff --git a/sys/dev/ic/isp_tpublic.h b/sys/dev/ic/isp_tpublic.h
new file mode 100644
index 00000000000..a9ebe9589a8
--- /dev/null
+++ b/sys/dev/ic/isp_tpublic.h
@@ -0,0 +1,301 @@
+/* $OpenBSD: isp_tpublic.h,v 1.1 2000/02/20 21:22:40 mjacob Exp $ */
+/*
+ * Qlogic ISP Host Adapter Public Target Interface Structures && Routines
+ *---------------------------------------
+ * Copyright (c) 2000 by Matthew Jacob
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Matthew Jacob
+ * Feral Software
+ * mjacob@feral.com
+ */
+
+/*
+ * Required software target mode message and event handling structures.
+ *
+ * The message and event structures are used by the MI layer
+ * to propagate messages and events upstream.
+ */
+
+#ifndef IN_MSGLEN
+#define IN_MSGLEN 8
+#endif
+typedef struct {
+ void * nt_hba; /* HBA tag */
+ u_int64_t nt_iid; /* inititator id */
+ u_int64_t nt_tgt; /* target id */
+ u_int64_t nt_lun; /* logical unit */
+ u_int8_t nt_bus; /* bus */
+ u_int8_t nt_tagtype; /* tag type */
+ u_int16_t nt_tagval; /* tag value */
+ u_int8_t nt_msg[IN_MSGLEN]; /* message content */
+} tmd_msg_t;
+
+typedef struct {
+ void * ev_hba; /* HBA tag */
+ u_int16_t ev_bus; /* bus */
+ u_int16_t ev_event; /* type of async event */
+} tmd_event_t;
+
+/*
+ * Suggested software target mode command handling structure.
+ *
+ * The command structure is one suggested possible MD command structure,
+ * but since the handling of thbis is entirely in the MD layer, there
+ * is no requirement that it be used.
+ *
+ * The cd_private tag should be used by the MD layer to keep a free list
+ * of these structures. Code outside of this driver can then use this
+ * as an to identify it's own unit structures. That is, when not on the MD
+ * layer's freelist, the MD layer should shove into it the identifier
+ * that the outer layer has for it- passed in on an initial QIN_HBA_REG
+ * call (see below).
+ *
+ * The cd_hba tag is a tag that uniquely identifies the HBA this target
+ * mode command is coming from. The outer layer has to pass this back
+ * unchanged to avoid chaos.
+ *
+ * The cd_iid, cd_tgt, cd_lun and cd_bus tags are used to identify the
+ * id of the initiator who sent us a command, the target claim to be, the
+ * lun on the target we claim to be, and the bus instance (for multiple
+ * bus host adapters) that this applies to (consider it an extra Port
+ * parameter). The iid, tgt and lun values are deliberately chosen to be
+ * fat so that, for example, World Wide Names can be used instead of
+ * the units that the Qlogic firmware uses (in the case where the MD
+ * layer maintains a port database, for example).
+ *
+ * The cd_tagtype field specifies what kind of command tag has been
+ * sent with the command. The cd_tagval is the tag's value.
+ *
+ * N.B.: when the MD layer sends this command to outside software
+ * the outside software likely *MUST* return the same cd_tagval that
+ * was in place because this value is likely what the Qlogic f/w uses
+ * to identify a command.
+ *
+ * The cd_cdb contains storage for the passed in command descriptor block.
+ * This is the maximum size we can get out of the Qlogic f/w. There's no
+ * passed in length because whoever decodes the command to act upon it
+ * will know what the appropriate length is.
+ *
+ * The tag cd_lflags are the flags set by the MD driver when it gets
+ * command incoming or when it needs to inform any outside entities
+ * that the last requested action failed.
+ *
+ * The tag cd_hflags should be set by any outside software to indicate
+ * the validity of sense and status fields (defined below) and to indicate
+ * the direction data is expected to move. It is an error to have both
+ * CDFH_DATA_IN and CDFH_DATA_OUT set.
+ *
+ * If the CDFH_STSVALID flag is set, the command should be completed (after
+ * sending any data and/or status). If CDFH_SNSVALID is set and the MD layer
+ * can also handle sending the associated sense data (either back with an
+ * FCP RESPONSE IU for Fibre Channel or otherwise automatically handling a
+ * REQUEST SENSE from the initator for this target/lun), the MD layer will
+ * set the CDFL_SENTSENSE flag on successful transmission of the sense data.
+ * It is an error for the CDFH_SNSVALID bit to be set and CDFH_STSVALID not
+ * to be set. It is an error for the CDFH_SNSVALID be set and the associated
+ * SCSI status (cd_scsi_status) not be set to CHECK CONDITON.
+ *
+ * The tag cd_data points to a data segment to either be filled or
+ * read from depending on the direction of data movement. The tag
+ * is undefined if no data direction is set. The MD layer and outer
+ * layers must agree on the meaning of cd_data.
+ *
+ * The tag cd_totlen is the total data amount expected to be moved
+ * over the life of the command. It may be set by the MD layer,
+ * for example, from the datalen field of an FCP CMND IU unit. If
+ * it shows up in the outer layers set to zero and the CDB indicates
+ * data should be moved, the outer layer should set it to the amount
+ * expected to be moved.
+ *
+ * The tag cd_resid should be the total residual of data not transferred.
+ * The outer layers need to set this at the begining of command processing
+ * to equal cd_totlen. As data is successfully moved, this value is decreased.
+ * At the end of a command, any nonzero residual indicates the number of bytes
+ * requested but not moved.
+ *
+ * The tag cd_xfrlen is the length of the currently active data transfer.
+ * This allows several interations between any outside software and the
+ * MD layer to move data.
+ *
+ * The reason that total length and total residual have to be tracked
+ * is that fibre channel FCP DATA IU units have to have a relative
+ * offset field.
+ *
+ * N.B.: there is no necessary 1-to-1 correspondence between any one
+ * data transfer segment and the number of CTIOs that will be generated
+ * satisfy the current data transfer segment. It's not also possible to
+ * predict how big a transfer can be before it will be 'too big'. Be
+ * reasonable- a 64KB transfer is 'reasonable'. A 1MB transfer may not
+ * be. A 32MB transfer is unreasonable. The problem here has to do with
+ * how CTIOs can be used to map passed data pointers. In systems which
+ * have page based scatter-gather requirements, each PAGESIZEd chunk will
+ * consume one data segment descriptor- you get 3 or 4 of them per CTIO.
+ * The size of the REQUEST QUEUE you drop a CTIO onto is finite (typically
+ * it's 256, but on some systems it's even smaller, and note you have to
+ * sure this queue with the initiator side of this driver).
+ *
+ * The tags cd_sense and cd_scsi_status are pretty obvious.
+ *
+ * The tag cd_error is to communicate between the MD layer and outer software
+ * the current error conditions.
+ *
+ * The tag cd_reserved pads out the structure to 128 bytes.
+ */
+
+#ifndef _LP64
+#if defined(__alpha__) || defined(__sparcv9cpu) || defined(__sparc_v9__)
+#define _LP64
+#endif
+#endif
+
+#ifndef _TMD_PAD_LEN
+#ifdef _LP64
+#define _TMD_PAD_LEN 12
+#else
+#define _TMD_PAD_LEN 24
+#endif
+#endif
+#ifndef ATIO_CDBLEN
+#define ATIO_CDBLEN 26
+#endif
+#ifndef QLTM_SENSELEN
+#define QLTM_SENSELEN 18
+#endif
+typedef struct tmd_cmd {
+ void * cd_private; /* layer private data */
+ void * cd_hba; /* HBA tag */
+ void * cd_data; /* 'pointer' to data */
+ u_int64_t cd_iid; /* initiator ID */
+ u_int64_t cd_tgt; /* target id */
+ u_int64_t cd_lun; /* logical unit */
+ u_int8_t cd_bus; /* bus */
+ u_int8_t cd_tagtype; /* tag type */
+ u_int16_t cd_tagval; /* tag value */
+ u_int8_t cd_cdb[ATIO_CDBLEN]; /* Command */
+ u_int8_t cd_lflags; /* flags lower level sets */
+ u_int8_t cd_hflags; /* flags higher level sets */
+ u_int32_t cd_totlen; /* total data requirement */
+ u_int32_t cd_resid; /* total data residual */
+ u_int32_t cd_xfrlen; /* current data requirement */
+ int32_t cd_error; /* current error */
+ u_int8_t cd_sense[QLTM_SENSELEN];
+ u_int16_t cd_scsi_status; /* closing SCSI status */
+ u_int8_t cd_reserved[_TMD_PAD_LEN];
+} tmd_cmd_t;
+
+#define CDFL_BUSY 0x01 /* this command is not on a free list */
+#define CDFL_NODISC 0x02 /* disconnect not allowed */
+#define CDFL_SENTSENSE 0x04 /* last action sent sense data */
+#define CDFL_ERROR 0x08 /* last action ended in error */
+#define CDFL_PRIVATE_0 0x80 /* private layer flags */
+
+#define CDFH_SNSVALID 0x01 /* sense data valid */
+#define CDFH_STSVALID 0x02 /* status valid */
+#define CDFH_NODATA 0x00 /* no data transfer expected */
+#define CDFH_DATA_IN 0x04 /* target (us) -> initiator (them) */
+#define CDFH_DATA_OUT 0x08 /* initiator (them) -> target (us) */
+#define CDFH_DATA_MASK 0x0C /* mask to cover data direction */
+#define CDFH_PRIVATE_0 0x80 /* private layer flags */
+
+/*
+ * Action codes set by the Qlogic MD target driver for
+ * the external layer to figure out what to do with.
+ */
+typedef enum {
+ QOUT_HBA_REG=0, /* the argument is a pointer to a hba_register_t */
+ QOUT_TMD_START, /* the argument is a pointer to a tmd_cmd_t */
+ QOUT_TMD_DONE, /* the argument is a pointer to a tmd_cmd_t */
+ QOUT_TEVENT, /* the argument is a pointer to a tmd_event_t */
+ QOUT_TMSG, /* the argument is a pointer to a tmd_msg_t */
+ QOUT_HBA_UNREG /* the argument is a pointer to a hba_register_t */
+} tact_e;
+
+/*
+ * Action codes set by the external layer for the
+ * MD Qlogic driver to figure out what to do with.
+ */
+typedef enum {
+ QIN_HBA_REG=6, /* the argument is a pointer to a hba_register_t */
+ QIN_TMD_CONT, /* the argument is a pointer to a tmd_cmd_t */
+ QIN_TMD_FIN, /* the argument is a pointer to a done tmd_cmd_t */
+ QIN_HBA_UNREG /* the argument is a pointer to a hba_register_t */
+} qact_e;
+
+/*
+ * A word about the START/CONT/DONE/FIN dance:
+ *
+ * When the HBA is enabled for receiving commands, one may show up
+ * without notice. When that happens, the Qlogic target mode driver
+ * gets a tmd_cmd_t, fills it with the info that just arrived, and
+ * calls the outer layer with a QIN_TMD_START code and pointer to
+ * the tmd_cmd_t.
+ *
+ * The outer layer decodes the command, fetches data, prepares stuff,
+ * whatever, and starts by passing back the pointer with a QIN_TMD_CONT
+ * code which causes the Qlogic target mode driver to generate CTIOs to
+ * satisfy whatever action needs to be taken. When those CTIOs complete,
+ * the Qlogic target driver sends the pointer to the cmd_tmd_t back with
+ * a QOUT_TMD_DONE code. This repeats for as long as necessary.
+ *
+ * The outer layer signals it wants to end the command by settings within
+ * the tmd_cmd_t itself. When the final QIN_TMD_CONT is reported completed,
+ * the outer layer frees the tmd_cmd_t by sending the pointer to it
+ * back with a QIN_TMD_FIN code.
+ *
+ * The graph looks like:
+ *
+ * QOUT_TMD_START -> [ QIN_TMD_CONT -> QOUT_TMD_DONE ] * -> QIN_TMD_FIN.
+ */
+
+/*
+ * Target handler functions.
+ * The MD target handler function (the outer layer calls this)
+ * should be be prototyped like:
+ *
+ * void target_action(qact_e, void *arg)
+ *
+ * The outer layer target handler function (the MD layer calls this)
+ * should be be prototyped like:
+ *
+ * void system_action(tact_e, void *arg)
+ */
+
+/*
+ * This structure is used to register to other software modules the
+ * binding of an HBA identifier, driver name and instance and the
+ * lun width capapbilities of this target driver. It's up to each
+ * platform to figure out how it wants to do this, but a typical
+ * sequence would be for the MD layer to find some external module's
+ * entry point and start by sending a QOUT_HBA_REG with info filled
+ * in, and the external module to call back with a QIN_HBA_REG that
+ * passes back the corresponding information.
+ */
+typedef struct {
+ void * r_identity;
+ char r_name[8];
+ int r_inst;
+ int r_lunwidth;
+ void (*r_action) __P((int, void *));
+} hba_register_t;
diff --git a/sys/dev/ic/ispmbox.h b/sys/dev/ic/ispmbox.h
index 3c9daa00bc2..51cc085b2b9 100644
--- a/sys/dev/ic/ispmbox.h
+++ b/sys/dev/ic/ispmbox.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ispmbox.h,v 1.7 1999/11/22 12:50:53 mjacob Exp $ */
+/* $OpenBSD: ispmbox.h,v 1.8 2000/02/20 21:22:41 mjacob Exp $ */
/*
* Mailbox and Queue Entry Definitions for for Qlogic ISP SCSI adapters.
*
@@ -113,6 +113,9 @@
#define FW_FEATURE_LVD_NOTIFY 0x2
#define FW_FEATURE_FAST_POST 0x1
+#define MBOX_ENABLE_TARGET_MODE 0x55
+#define ENABLE_TARGET_FLAG 0x8000
+
/* These are for the ISP2100 FC cards */
#define MBOX_GET_LOOP_ID 0x20
#define MBOX_EXEC_COMMAND_IOCB_A64 0x54
@@ -152,6 +155,10 @@ typedef struct {
#define MBOX_TEST_FAILED 0x4003
#define MBOX_COMMAND_ERROR 0x4005
#define MBOX_COMMAND_PARAM_ERROR 0x4006
+#define MBOX_PORT_ID_USED 0x4007
+#define MBOX_LOOP_ID_USED 0x4008
+#define MBOX_ALL_IDS_USED 0x4009
+#define MBOX_NOT_LOGGED_IN 0x400A
/*
* Asynchronous event status codes
@@ -179,6 +186,15 @@ typedef struct {
#define ASYNC_PDB_CHANGED 0x8014
#define ASYNC_CHANGE_NOTIFY 0x8015
+/* for ISP2200 only */
+#define ASYNC_PTPMODE 0x8030
+#define ASYNC_CONNMODE 0x8036
+#define ISP_CONN_LOOP 1
+#define ISP_CONN_PTP 2
+#define ISP_CONN_BADLIP 3
+#define ISP_CONN_FATAL 4
+#define ISP_CONN_LOOPBACK 5
+
/*
* Command Structure Definitions
*/
@@ -230,7 +246,7 @@ typedef struct {
#define RQSTYPE_MARKER 0x04
#define RQSTYPE_CMDONLY 0x05
#define RQSTYPE_ATIO 0x06 /* Target Mode */
-#define RQSTYPE_CTIO0 0x07 /* Target Mode */
+#define RQSTYPE_CTIO 0x07 /* Target Mode */
#define RQSTYPE_SCAM 0x08
#define RQSTYPE_A64 0x09
#define RQSTYPE_A64_CONT 0x0a
@@ -351,6 +367,7 @@ typedef struct {
u_int16_t req_state_flags;
u_int16_t req_status_flags;
u_int16_t req_time;
+#define req_response_len req_time /* FC only */
u_int16_t req_sense_len;
u_int32_t req_resid;
u_int8_t _res1[8];
@@ -490,6 +507,20 @@ typedef struct isp_icb {
#define ICBOPT_USE_PORTNAME 0x4000
#define ICBOPT_EXTENDED 0x8000
+#define ICBXOPT_CLASS2_ACK0 0x0200
+#define ICBXOPT_CLASS2 0x0100
+#define ICBXOPT_LOOP_ONLY (0 << 4)
+#define ICBXOPT_PTP_ONLY (1 << 4)
+#define ICBXOPT_LOOP_2_PTP (2 << 4)
+#define ICBXOPT_PTP_2_LOOP (3 << 4)
+
+#define ICBXOPT_RIO_OFF 0
+#define ICBXOPT_RIO_16BIT 1
+#define ICBXOPT_RIO_32BIT 2
+#define ICBXOPT_RIO_16BIT_DELAY 3
+#define ICBXOPT_RIO_32BIT_DELAY 4
+
+
#define ICB_MIN_FRMLEN 256
#define ICB_MAX_FRMLEN 2112
@@ -617,4 +648,23 @@ typedef struct {
#define SNS_GAN_RESP_SIZE 608 /* Maximum response size (bytes) */
#define SNS_GP3_RESP_SIZE 532 /* XXX: For 128 ports */
+typedef struct {
+ u_int8_t snscb_cthdr[16];
+ u_int8_t snscb_port_type;
+ u_int8_t snscb_port_id[3];
+ u_int8_t snscb_portname[8];
+ u_int8_t snscb_pnlen; /* symbolic port name length */
+ u_int8_t snscb_pname[255]; /* symbolic port name */
+ u_int8_t snscb_nodename[8];
+ u_int8_t snscb_nnlen; /* symbolic node name length */
+ u_int8_t snscb_nname[255]; /* symbolic node name */
+ u_int8_t snscb_ipassoc[8];
+ u_int8_t snscb_ipaddr[16];
+ u_int8_t snscb_svc_class[4];
+ u_int8_t snscb_fc4_types[32];
+ u_int8_t snscb_fpname[8];
+ u_int8_t snscb_reserved;
+ u_int8_t snscb_hardaddr[3];
+} sns_ganrsp_t; /* Subcommand Response Structure */
+
#endif /* _ISPMBOX_H */
diff --git a/sys/dev/ic/ispreg.h b/sys/dev/ic/ispreg.h
index 36f780aa35d..0a7a1ae7ac2 100644
--- a/sys/dev/ic/ispreg.h
+++ b/sys/dev/ic/ispreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ispreg.h,v 1.6 1999/12/16 05:22:18 mjacob Exp $ */
+/* $OpenBSD: ispreg.h,v 1.7 2000/02/20 21:22:41 mjacob Exp $ */
/*
* Machine Independent (well, as best as possible) register
* definitions for Qlogic ISP SCSI adapters.
@@ -733,8 +733,8 @@
#define ISP1080_ISP_PARAMETER(c) \
(((c)[18]) | ((c)[19] << 8))
-#define ISP1080_FAST_POST ISPBSMX(c, 20, 0, 0x01)
-#define ISP1080_REPORT_LVD_TRANSITION ISPBSMX(c, 20, 1, 0x01)
+#define ISP1080_FAST_POST(c) ISPBSMX(c, 20, 0, 0x01)
+#define ISP1080_REPORT_LVD_TRANSITION(c) ISPBSMX(c, 20, 1, 0x01)
#define ISP1080_BUS1_OFF 112
@@ -793,6 +793,80 @@
#define ISP1080_NVRAM_TGT_LUN_DISABLE(c, t, b) \
ISPBSMX(c, _IxT8(t, 3, (b)), 5, 0x01)
+#define ISP12160_NVRAM_HBA_ENABLE ISP1080_NVRAM_HBA_ENABLE
+#define ISP12160_NVRAM_BURST_ENABLE ISP1080_NVRAM_BURST_ENABLE
+#define ISP12160_NVRAM_FIFO_THRESHOLD ISP1080_NVRAM_FIFO_THRESHOLD
+#define ISP12160_NVRAM_AUTO_TERM_SUPPORT ISP1080_NVRAM_AUTO_TERM_SUPPORT
+#define ISP12160_NVRAM_BUS0_TERM_MODE ISP1080_NVRAM_BUS0_TERM_MODE
+#define ISP12160_NVRAM_BUS1_TERM_MODE ISP1080_NVRAM_BUS1_TERM_MODE
+#define ISP12160_ISP_PARAMETER ISP12160_ISP_PARAMETER
+#define ISP12160_FAST_POST ISP1080_FAST_POST
+#define ISP12160_REPORT_LVD_TRANSITION ISP1080_REPORT_LVD_TRANSTION
+
+#define ISP12160_NVRAM_INITIATOR_ID \
+ ISP1080_NVRAM_INITIATOR_ID
+#define ISP12160_NVRAM_BUS_RESET_DELAY \
+ ISP1080_NVRAM_BUS_RESET_DELAY
+#define ISP12160_NVRAM_BUS_RETRY_COUNT \
+ ISP1080_NVRAM_BUS_RETRY_COUNT
+#define ISP12160_NVRAM_BUS_RETRY_DELAY \
+ ISP1080_NVRAM_BUS_RETRY_DELAY
+#define ISP12160_NVRAM_ASYNC_DATA_SETUP_TIME \
+ ISP1080_NVRAM_ASYNC_DATA_SETUP_TIME
+#define ISP12160_NVRAM_REQ_ACK_ACTIVE_NEGATION \
+ ISP1080_NVRAM_REQ_ACK_ACTIVE_NEGATION
+#define ISP12160_NVRAM_DATA_LINE_ACTIVE_NEGATION \
+ ISP1080_NVRAM_DATA_LINE_ACTIVE_NEGATION
+#define ISP12160_NVRAM_SELECTION_TIMEOUT \
+ ISP1080_NVRAM_SELECTION_TIMEOUT
+#define ISP12160_NVRAM_MAX_QUEUE_DEPTH \
+ ISP1080_NVRAM_MAX_QUEUE_DEPTH
+
+
+#define ISP12160_BUS0_OFF 24
+#define ISP12160_BUS1_OFF 136
+
+#define ISP12160_NVRAM_TARGOFF(b) \
+ (((b == 0)? ISP12160_BUS0_OFF : ISP12160_BUS1_OFF) + 16)
+
+#define ISP12160_NVRAM_TARGSIZE 6
+#define _IxT16(tgt, tidx, b) \
+ (ISP12160_NVRAM_TARGOFF((b))+(ISP12160_NVRAM_TARGSIZE * (tgt))+(tidx))
+
+#define ISP12160_NVRAM_TGT_RENEG(c, t, b) \
+ ISPBSMX(c, _IxT16(t, 0, (b)), 0, 0x01)
+#define ISP12160_NVRAM_TGT_QFRZ(c, t, b) \
+ ISPBSMX(c, _IxT16(t, 0, (b)), 1, 0x01)
+#define ISP12160_NVRAM_TGT_ARQ(c, t, b) \
+ ISPBSMX(c, _IxT16(t, 0, (b)), 2, 0x01)
+#define ISP12160_NVRAM_TGT_TQING(c, t, b) \
+ ISPBSMX(c, _IxT16(t, 0, (b)), 3, 0x01)
+#define ISP12160_NVRAM_TGT_SYNC(c, t, b) \
+ ISPBSMX(c, _IxT16(t, 0, (b)), 4, 0x01)
+#define ISP12160_NVRAM_TGT_WIDE(c, t, b) \
+ ISPBSMX(c, _IxT16(t, 0, (b)), 5, 0x01)
+#define ISP12160_NVRAM_TGT_PARITY(c, t, b) \
+ ISPBSMX(c, _IxT16(t, 0, (b)), 6, 0x01)
+#define ISP12160_NVRAM_TGT_DISC(c, t, b) \
+ ISPBSMX(c, _IxT16(t, 0, (b)), 7, 0x01)
+
+#define ISP12160_NVRAM_TGT_EXEC_THROTTLE(c, t, b) \
+ ISPBSMX(c, _IxT16(t, 1, (b)), 0, 0xff)
+#define ISP12160_NVRAM_TGT_SYNC_PERIOD(c, t, b) \
+ ISPBSMX(c, _IxT16(t, 2, (b)), 0, 0xff)
+
+#define ISP12160_NVRAM_TGT_SYNC_OFFSET(c, t, b) \
+ ISPBSMX(c, _IxT16(t, 3, (b)), 0, 0x1f)
+#define ISP12160_NVRAM_TGT_DEVICE_ENABLE(c, t, b) \
+ ISPBSMX(c, _IxT16(t, 3, (b)), 5, 0x01)
+
+#define ISP12160_NVRAM_PPR_OPTIONS(c, t, b) \
+ ISPBSMX(c, _IxT16(t, 4, (b)), 0, 0x0f)
+#define ISP12160_NVRAM_PPR_WIDTH(c, t, b) \
+ ISPBSMX(c, _IxT16(t, 4, (b)), 4, 0x03)
+#define ISP12160_NVRAM_PPR_ENABLE(c, t, b) \
+ ISPBSMX(c, _IxT16(t, 4, (b)), 7, 0x01)
+
/*
* Qlogic 2XXX NVRAM is an array of 256 bytes.
*
diff --git a/sys/dev/ic/ispvar.h b/sys/dev/ic/ispvar.h
index 5dd0f3cc0ae..c8b087b1690 100644
--- a/sys/dev/ic/ispvar.h
+++ b/sys/dev/ic/ispvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ispvar.h,v 1.8 1999/12/16 05:20:53 mjacob Exp $ */
+/* $OpenBSD: ispvar.h,v 1.9 2000/02/20 21:22:41 mjacob Exp $ */
/*
* Soft Definitions for for Qlogic ISP SCSI adapters.
*
@@ -40,23 +40,26 @@
#include <dev/ic/ispmbox.h>
#ifdef ISP_TARGET_MODE
#include <dev/ic/isp_target.h>
+#include <dev/ic/isp_tpublic.h>
#endif
#endif
#ifdef __FreeBSD__
#include <dev/isp/ispmbox.h>
#ifdef ISP_TARGET_MODE
#include <dev/isp/isp_target.h>
+#include <dev/isp/isp_tpublic.h>
#endif
#endif
#ifdef __linux__
#include "ispmbox.h"
#ifdef ISP_TARGET_MODE
#include "isp_target.h"
+#include "isp_tpublic.h"
#endif
#endif
#define ISP_CORE_VERSION_MAJOR 1
-#define ISP_CORE_VERSION_MINOR 11
+#define ISP_CORE_VERSION_MINOR 12
/*
* Vector for bus specific code to provide specific services.
@@ -370,6 +373,7 @@ struct ispsoftc {
#define ISP_CFG_NONVRAM 0x40 /* ignore NVRAM */
#define ISP_CFG_FULL_DUPLEX 0x01 /* Full Duplex (Fibre Channel only) */
#define ISP_CFG_OWNWWN 0x02 /* override NVRAM wwn */
+#define ISP_CFG_NPORT 0x04 /* try to force N- instead of L-Port */
#define ISP_FW_REV(maj, min, mic) ((maj << 24) | (min << 16) | mic)
#define ISP_FW_REVX(xp) ((xp[0]<<24) | (xp[1] << 16) | xp[2])
@@ -394,6 +398,7 @@ struct ispsoftc {
#define ISP_HA_SCSI_1240 0x8
#define ISP_HA_SCSI_1080 0x9
#define ISP_HA_SCSI_1280 0xa
+#define ISP_HA_SCSI_12160 0xb
#define ISP_HA_FC 0xf0
#define ISP_HA_FC_2100 0x10
#define ISP_HA_FC_2200 0x20
@@ -402,12 +407,17 @@ struct ispsoftc {
#define IS_1240(isp) (isp->isp_type == ISP_HA_SCSI_1240)
#define IS_1080(isp) (isp->isp_type == ISP_HA_SCSI_1080)
#define IS_1280(isp) (isp->isp_type == ISP_HA_SCSI_1280)
-#define IS_12X0(isp) \
- (isp->isp_type == ISP_HA_SCSI_1240 || isp->isp_type == ISP_HA_SCSI_1280)
-#define IS_DUALBUS(isp) IS_12X0(isp)
-#define IS_ULTRA2(isp) \
- (isp->isp_type == ISP_HA_SCSI_1080 || isp->isp_type == ISP_HA_SCSI_1280)
+#define IS_12160(isp) (isp->isp_type == ISP_HA_SCSI_12160)
+
+#define IS_12X0(isp) (IS_1240(isp) || IS_1280(isp))
+#define IS_DUALBUS(isp) (IS_12X0(isp) || IS_12160(isp))
+#define IS_ULTRA2(isp) (IS_1080(isp) || IS_1280(isp) || IS_12160(isp))
+#define IS_ULTRA3(isp) (IS_12160(isp))
+
#define IS_FC(isp) (isp->isp_type & ISP_HA_FC)
+#define IS_2100(isp) (isp->isp_type == ISP_HA_FC_2100)
+#define IS_2200(isp) (isp->isp_type == ISP_HA_FC_2200)
+
/*
* Function Prototypes
@@ -450,11 +460,9 @@ typedef enum {
ISPCTL_RESET_DEV, /* Reset Device */
ISPCTL_ABORT_CMD, /* Abort Command */
ISPCTL_UPDATE_PARAMS, /* Update Operating Parameters */
-#ifdef ISP_TARGET_MODE
- ISPCTL_ENABLE_LUN, /* enable a LUN */
- ISPCTL_MODIFY_LUN, /* enable a LUN */
-#endif
- ISPCTL_FCLINK_TEST /* Test FC Link Status */
+ ISPCTL_FCLINK_TEST, /* Test FC Link Status */
+ ISPCTL_PDB_SYNC, /* Synchronize Port Database */
+ ISPCTL_TOGGLE_TMODE /* toggle target mode */
} ispctl_t;
int isp_control __P((struct ispsoftc *, ispctl_t, void *));
@@ -475,8 +483,9 @@ typedef enum {
ISPASYNC_PDB_CHANGED, /* FC Port Data Base Changed */
ISPASYNC_CHANGE_NOTIFY, /* FC SNS Change Notification */
ISPASYNC_FABRIC_DEV, /* FC New Fabric Device */
- ISPASYNC_TARGET_CMD, /* New target command */
- ISPASYNC_TARGET_EVENT /* New target event */
+ ISPASYNC_TARGET_MESSAGE, /* target message */
+ ISPASYNC_TARGET_EVENT, /* target asynchronous event */
+ ISPASYNC_TARGET_ACTION /* other target command action */
} ispasync_t;
int isp_async __P((struct ispsoftc *, ispasync_t, void *));