diff options
author | mjacob <mjacob@cvs.openbsd.org> | 2000-02-20 21:22:42 +0000 |
---|---|---|
committer | mjacob <mjacob@cvs.openbsd.org> | 2000-02-20 21:22:42 +0000 |
commit | 843be39a687253a9894847550ed56ea58510c179 (patch) | |
tree | 5ba8385712451adffcce024f1c84487e320e5d2d /sys | |
parent | 507037610dbda92ebe936b00eda0be017503a7d8 (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.c | 1184 | ||||
-rw-r--r-- | sys/dev/ic/isp_inline.h | 23 | ||||
-rw-r--r-- | sys/dev/ic/isp_openbsd.c | 76 | ||||
-rw-r--r-- | sys/dev/ic/isp_openbsd.h | 8 | ||||
-rw-r--r-- | sys/dev/ic/isp_target.c | 1228 | ||||
-rw-r--r-- | sys/dev/ic/isp_target.h | 654 | ||||
-rw-r--r-- | sys/dev/ic/isp_tpublic.h | 301 | ||||
-rw-r--r-- | sys/dev/ic/ispmbox.h | 54 | ||||
-rw-r--r-- | sys/dev/ic/ispreg.h | 80 | ||||
-rw-r--r-- | sys/dev/ic/ispvar.h | 37 |
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 *)); |