summaryrefslogtreecommitdiffstats
path: root/sys/dev/ic/isp_openbsd.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ic/isp_openbsd.c')
-rw-r--r--sys/dev/ic/isp_openbsd.c586
1 files changed, 420 insertions, 166 deletions
diff --git a/sys/dev/ic/isp_openbsd.c b/sys/dev/ic/isp_openbsd.c
index 7cbeaef9749..71b8f526dbe 100644
--- a/sys/dev/ic/isp_openbsd.c
+++ b/sys/dev/ic/isp_openbsd.c
@@ -1,5 +1,4 @@
-/* $OpenBSD: isp_openbsd.c,v 1.3 1999/03/25 22:58:38 mjacob Exp $ */
-/* release_03_25_99 */
+/* $OpenBSD: isp_openbsd.c,v 1.4 1999/11/22 12:50:53 mjacob Exp $ */
/*
* Platform (OpenBSD) dependent common attachment code for Qlogic adapters.
*
@@ -42,29 +41,28 @@
*
* Matthew Jacob
* Feral Software
- * 2339 3rd Street
- * Suite 24
- * San Francisco, CA, 94107
+ * PMB#825
+ * 5214-F Diamond Heights Blvd.
+ * San Francisco, CA, 94131
*/
#include <dev/ic/isp_openbsd.h>
static void ispminphys __P((struct buf *));
+static int32_t ispcmd_slow __P((ISP_SCSI_XFER_T *));
static int32_t ispcmd __P((ISP_SCSI_XFER_T *));
static struct scsi_device isp_dev = { NULL, NULL, NULL, NULL };
static int isp_poll __P((struct ispsoftc *, ISP_SCSI_XFER_T *, int));
static void isp_watch __P((void *));
+static void isp_command_requeue(void *);
+static void isp_internal_restart(void *);
struct cfdriver isp_cd = {
NULL, "isp", DV_DULL
};
-#define FC_OPENINGS RQUEST_QUEUE_LEN / (MAX_FC_TARG-1)
-#define PI_OPENINGS RQUEST_QUEUE_LEN / (MAX_TARGETS-1)
-#define DTHR 1
-
/*
* Complete attachment of hardware, include subdevices.
*/
@@ -72,7 +70,6 @@ void
isp_attach(isp)
struct ispsoftc *isp;
{
- isp->isp_osinfo._adapter.scsi_cmd = ispcmd;
isp->isp_osinfo._adapter.scsi_minphys = ispminphys;
isp->isp_state = ISP_RUNSTATE;
@@ -86,23 +83,23 @@ isp_attach(isp)
isp->isp_osinfo._link.adapter_softc = isp;
isp->isp_osinfo._link.device = &isp_dev;
isp->isp_osinfo._link.adapter = &isp->isp_osinfo._adapter;
+ isp->isp_osinfo._link.openings = isp->isp_maxcmds;
+ isp->isp_osinfo.wqf = isp->isp_osinfo.wqt = NULL; /* XXX 2nd Bus? */
- if (isp->isp_type & ISP_HA_FC) {
- isp->isp_osinfo._link.openings = FC_OPENINGS;
+ if (IS_FC(isp)) {
+ isp->isp_osinfo._adapter.scsi_cmd = ispcmd;
isp->isp_osinfo._link.adapter_buswidth = MAX_FC_TARG;
/* We can set max lun width here */
- isp->isp_osinfo._link.adapter_target =
- ((fcparam *)isp->isp_param)->isp_loopid;
+ /* loopid set below */
} else {
- isp->isp_osinfo.delay_throttle_count = DTHR;
- isp->isp_osinfo._link.openings = PI_OPENINGS;
+ sdparam *sdp = isp->isp_param;
+ isp->isp_osinfo._adapter.scsi_cmd = ispcmd_slow;
isp->isp_osinfo._link.adapter_buswidth = MAX_TARGETS;
/* We can set max lun width here */
isp->isp_osinfo._link.adapter_target =
- ((sdparam *)isp->isp_param)->isp_initiator_id;
+ sdp->isp_initiator_id;
+ isp->isp_osinfo.discovered[0] = 1 << sdp->isp_initiator_id;
}
- if (isp->isp_osinfo._link.openings < 2)
- isp->isp_osinfo._link.openings = 2;
/*
* Send a SCSI Bus Reset (used to be done as part of attach,
@@ -114,17 +111,57 @@ isp_attach(isp)
* XXX: that async events happen.
*/
if (IS_SCSI(isp)) {
- (void) isp_control(isp, ISPCTL_RESET_BUS, NULL);
+ int bus = 0;
+ (void) isp_control(isp, ISPCTL_RESET_BUS, &bus);
+ if (IS_12X0(isp)) {
+ bus++;
+ (void) isp_control(isp, ISPCTL_RESET_BUS, &bus);
+ }
/*
- * Wait for it to settle.
+ * wait for the bus to settle.
*/
+ printf("%s: waiting 2 seconds for bus reset settling\n",
+ isp->isp_name);
delay(2 * 1000000);
+ } else {
+ int i, j;
+ fcparam *fcp = isp->isp_param;
+ /*
+ * wait for the loop to settle.
+ */
+ printf("%s: waiting 2 seconds for loop reset settling\n",
+ isp->isp_name);
+ delay(2 * 1000000);
+ for (j = 0; j < 5; j++) {
+ for (i = 0; i < 5; i++) {
+ if (isp_control(isp, ISPCTL_FCLINK_TEST, NULL))
+ continue;
+#ifdef ISP2100_FABRIC
+ /*
+ * Wait extra time to see if the f/w
+ * eventually completed an FLOGI that
+ * will allow us to know we're on a
+ * fabric.
+ */
+ if (fcp->isp_onfabric == 0) {
+ delay(1 * 1000000);
+ continue;
+ }
+#endif
+ break;
+ }
+ if (fcp->isp_fwstate == FW_READY &&
+ fcp->isp_loopstate >= LOOP_PDB_RCVD) {
+ break;
+ }
+ }
+ isp->isp_osinfo._link.adapter_target = fcp->isp_loopid;
}
/*
* Start the watchdog.
*
- * The wathdog will, ridiculously enough, also enable Sync negotiation.
+ * The watchdog will, ridiculously enough, also enable Sync negotiation.
*/
isp->isp_dogactive = 1;
timeout(isp_watch, isp, WATCH_INTERVAL * hz);
@@ -156,7 +193,87 @@ ispminphys(bp)
minphys(bp);
}
-static int
+static int32_t
+ispcmd_slow(xs)
+ ISP_SCSI_XFER_T *xs;
+{
+ sdparam *sdp;
+ int tgt, chan;
+ u_int16_t f;
+ struct ispsoftc *isp = XS_ISP(xs);
+
+ /*
+ * Have we completed discovery for this target on this adapter?
+ */
+ sdp = isp->isp_param;
+ sdp += chan;
+ tgt = XS_TGT(xs);
+ chan = XS_CHANNEL(xs);
+ if ((xs->flags & SCSI_POLL) != 0 ||
+ (isp->isp_osinfo.discovered[chan] & (1 << tgt)) != 0) {
+ return (ispcmd(xs));
+ }
+
+ f = DPARM_DEFAULT;
+ if (xs->sc_link->quirks & SDEV_NOSYNCWIDE) {
+ f ^= DPARM_SYNC;
+ f ^= DPARM_WIDE;
+#ifdef DEBUG
+ } else {
+ printf("%s: channel %d target %d can do SYNC xfers\n",
+ isp->isp_name, chan, tgt);
+ printf("%s: channel %d target %d can do WIDE xfers\n",
+ isp->isp_name, chan, tgt);
+#endif
+ }
+ if (xs->sc_link->quirks & SDEV_NOTAGS) {
+ f ^= DPARM_TQING;
+#ifdef DEBUG
+ } else {
+ printf("%s: channel %d target %d can do TAGGED xfers\n",
+ isp->isp_name, chan, tgt);
+#endif
+ }
+
+ /*
+ * Okay, we know about this device now,
+ * so mark parameters to be updated for it.
+ */
+ sdp->isp_devparam[tgt].dev_flags = f;
+ sdp->isp_devparam[tgt].dev_update = 1;
+ isp->isp_update |= 1 << chan;
+
+ /*
+ * Now check to see whether we can get out of this checking mode now.
+ * XXX: WE CANNOT AS YET BECAUSE THERE IS NO MECHANISM TO TELL US
+ * XXX: WHEN WE'RE DONE DISCOVERY BECAUSE WE NEED ONE COMMAND AFTER
+ * XXX: DISCOVERY IS DONE FOR EACH TARGET TO TELL US THAT WE'RE DONE
+ * XXX: AND THAT DOESN'T HAPPEN HERE. AT BEST WE CAN MARK OURSELVES
+ * XXX: DONE WITH DISCOVERY FOR THIS TARGET AND SO SAVE MAYBE 20
+ * XXX: LINES OF C CODE.
+ */
+ isp->isp_osinfo.discovered[chan] |= (1 << tgt);
+ /* do not bother with these lines- they'll never execute correctly */
+#if 0
+ sdp = isp->isp_param;
+ for (chan = 0; chan < (IS_12X0(isp)? 2 : 1); chan++, sdp++) {
+ f = 0xffff & ~(1 << sdp->isp_initiator_id);
+ if (isp->isp_osinfo.discovered[chan] != f) {
+ break;
+ }
+ }
+ if (chan == (IS_12X0(isp)? 2 : 1)) {
+ CFGPRINTF("%s: allowing sync/wide negotiation and "
+ "tag usage\n", isp->isp_name);
+ isp->isp_osinfo._adapter.scsipi_cmd = ispcmd;
+ if (IS_12X0(isp))
+ isp->isp_update |= 2;
+ }
+#endif
+ return (ispcmd(xs));
+}
+
+static int32_t
ispcmd(xs)
ISP_SCSI_XFER_T *xs;
{
@@ -179,34 +296,89 @@ ispcmd(xs)
isp->isp_state = ISP_RUNSTATE;
ENABLE_INTS(isp);
}
+
+ /*
+ * Check for queue blockage...
+ */
+ if (isp->isp_osinfo.blocked) {
+ if (xs->flags & SCSI_POLL) {
+ xs->error = XS_DRIVER_STUFFUP;
+ splx(s);
+ return (TRY_AGAIN_LATER);
+ }
+ if (isp->isp_osinfo.wqf != NULL) {
+ isp->isp_osinfo.wqt->free_list.le_next = xs;
+ } else {
+ isp->isp_osinfo.wqf = xs;
+ }
+ isp->isp_osinfo.wqt = xs;
+ xs->free_list.le_next = NULL;
+ splx(s);
+ return (SUCCESSFULLY_QUEUED);
+ }
DISABLE_INTS(isp);
result = ispscsicmd(xs);
ENABLE_INTS(isp);
- if (result != CMD_QUEUED || (xs->flags & SCSI_POLL) == 0) {
+
+ if ((xs->flags & SCSI_POLL) == 0) {
+ switch (result) {
+ case CMD_QUEUED:
+ result = SUCCESSFULLY_QUEUED;
+ break;
+ case CMD_EAGAIN:
+ result = TRY_AGAIN_LATER;
+ break;
+ case CMD_RQLATER:
+ result = SUCCESSFULLY_QUEUED;
+ timeout(isp_command_requeue, xs, hz);
+ break;
+ case CMD_COMPLETE:
+ result = COMPLETE;
+ break;
+ }
(void) splx(s);
return (result);
}
+ switch (result) {
+ case CMD_QUEUED:
+ result = SUCCESSFULLY_QUEUED;
+ break;
+ case CMD_RQLATER:
+ case CMD_EAGAIN:
+ if (XS_NOERR(xs)) {
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ result = TRY_AGAIN_LATER;
+ break;
+ case CMD_COMPLETE:
+ result = COMPLETE;
+ break;
+
+ }
+
/*
- * If we can't use interrupts, poll on completion.
+ * We can't use interrupts so poll on completion.
*/
- if (isp_poll(isp, xs, xs->timeout)) {
- /*
- * If no other error occurred but we didn't finish,
- * something bad happened.
- */
- if ((xs->flags & ITSDONE) == 0) {
- isp->isp_nactive--;
- if (isp->isp_nactive < 0)
- isp->isp_nactive = 0;
- if (xs->error == XS_NOERROR) {
- isp_lostcmd(isp, xs);
- xs->error = XS_DRIVER_STUFFUP;
+ if (result == SUCCESSFULLY_QUEUED) {
+ if (isp_poll(isp, xs, xs->timeout)) {
+ /*
+ * If no other error occurred but we didn't finish,
+ * something bad happened.
+ */
+ if (XS_IS_CMD_DONE(xs) == 0) {
+ if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) {
+ isp_restart(isp);
+ }
+ if (XS_NOERR(xs)) {
+ XS_SETERR(xs, HBA_BOTCH);
+ }
}
}
+ result = COMPLETE;
}
(void) splx(s);
- return (COMPLETE);
+ return (result);
}
static int
@@ -237,20 +409,22 @@ isp_watch(arg)
{
int i;
struct ispsoftc *isp = arg;
- ISP_SCSI_XFER_T *xs;
- int s = splbio();
+ struct scsi_xfer *xs;
+ int s;
/*
- * Look for completely dead commands.
+ * Look for completely dead commands (but not polled ones).
*/
- for (i = 0; i < RQUEST_QUEUE_LEN; i++) {
- if ((xs = (ISP_SCSI_XFER_T *) isp->isp_xflist[i]) == NULL) {
+ s = splbio();
+ for (i = 0; i < isp->isp_maxcmds; i++) {
+ if ((xs = (struct scsi_xfer *) isp->isp_xflist[i]) == NULL) {
continue;
}
- if (XS_TIME(xs) == 0) {
+ if (xs->timeout == 0 || (xs->flags & SCSI_POLL)) {
continue;
}
- XS_TIME(xs) -= (WATCH_INTERVAL * 1000);
+ xs->timeout -= (WATCH_INTERVAL * 1000);
+
/*
* Avoid later thinking that this
* transaction is not being timed.
@@ -262,9 +436,6 @@ isp_watch(arg)
} else if (xs->timeout > -(2 * WATCH_INTERVAL * 1000)) {
continue;
}
- if (IS_SCSI(isp)) {
- isp->isp_osinfo.delay_throttle_count = DTHR;
- }
if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) {
printf("%s: isp_watch failed to abort command\n",
isp->isp_name);
@@ -272,21 +443,9 @@ isp_watch(arg)
break;
}
}
-
- if (isp->isp_osinfo.delay_throttle_count) {
- if (--isp->isp_osinfo.delay_throttle_count == 0) {
- sdparam *sdp = isp->isp_param;
- for (i = 0; i < MAX_TARGETS; i++) {
- sdp->isp_devparam[i].dev_flags |=
- DPARM_WIDE|DPARM_SYNC|DPARM_TQING;
- sdp->isp_devparam[i].dev_update = 1;
- }
- isp->isp_update = 1;
- }
- }
- timeout(isp_watch, isp, WATCH_INTERVAL * hz);
+ timeout(isp_watch, isp, WATCH_INTERVAL * hz);
isp->isp_dogactive = 1;
- (void) splx(s);
+ splx(s);
}
/*
@@ -317,140 +476,235 @@ isp_uninit(isp)
splx(s);
}
+/*
+ * Restart function for a command to be requeued later.
+ */
+static void
+isp_command_requeue(void *arg)
+{
+ struct scsi_xfer *xs = arg;
+ struct ispsoftc *isp = XS_ISP(xs);
+ int s = splbio();
+ switch (ispcmd_slow(xs)) {
+ case SUCCESSFULLY_QUEUED:
+ printf("%s: isp_command_reque: queued %d.%d\n",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ break;
+ case TRY_AGAIN_LATER:
+ printf("%s: EAGAIN for %d.%d\n",
+ isp->isp_name, XS_TGT(xs), XS_LUN(xs));
+ /* FALLTHROUGH */
+ case COMPLETE:
+ /* can only be an error */
+ if (XS_NOERR(xs))
+ XS_SETERR(xs, XS_DRIVER_STUFFUP);
+ XS_CMD_DONE(xs);
+ break;
+ }
+ (void) splx(s);
+}
+
+/*
+ * Restart function after a LOOP UP event (e.g.),
+ * done as a timeout for some hysteresis.
+ */
+static void
+isp_internal_restart(void *arg)
+{
+ struct ispsoftc *isp = arg;
+ int result, nrestarted = 0, s;
+
+ s = splbio();
+ if (isp->isp_osinfo.blocked == 0) {
+ struct scsi_xfer *xs;
+ while ((xs = isp->isp_osinfo.wqf) != NULL) {
+ isp->isp_osinfo.wqf = xs->free_list.le_next;
+ xs->free_list.le_next = NULL;
+ DISABLE_INTS(isp);
+ result = ispscsicmd(xs);
+ ENABLE_INTS(isp);
+ if (result != CMD_QUEUED) {
+ printf("%s: botched command restart (0x%x)\n",
+ isp->isp_name, result);
+ if (XS_NOERR(xs))
+ XS_SETERR(xs, XS_DRIVER_STUFFUP);
+ XS_CMD_DONE(xs);
+ }
+ nrestarted++;
+ }
+ printf("%s: requeued %d commands\n", isp->isp_name, nrestarted);
+ }
+ (void) splx(s);
+}
+
int
isp_async(isp, cmd, arg)
struct ispsoftc *isp;
ispasync_t cmd;
void *arg;
{
+ int bus, tgt;
int s = splbio();
switch (cmd) {
case ISPASYNC_NEW_TGT_PARAMS:
- if (IS_SCSI(isp)) {
- sdparam *sdp = isp->isp_param;
- char *wt;
- int mhz, flags, tgt, period;
-
- tgt = *((int *) arg);
-
- flags = sdp->isp_devparam[tgt].cur_dflags;
- period = sdp->isp_devparam[tgt].cur_period;
- if ((flags & DPARM_SYNC) && period &&
- (sdp->isp_devparam[tgt].cur_offset) != 0) {
- if (sdp->isp_lvdmode) {
- switch (period) {
- case 0xa:
- mhz = 40;
- break;
- case 0xb:
- mhz = 33;
- break;
- case 0xc:
- mhz = 25;
- break;
- default:
- mhz = 1000 / (period * 4);
- break;
- }
- } else {
+ if (IS_SCSI(isp) && isp->isp_dblev) {
+ sdparam *sdp = isp->isp_param;
+ char *wt;
+ int mhz, flags, period;
+
+ tgt = *((int *) arg);
+ bus = (tgt >> 16) & 0xffff;
+ tgt &= 0xffff;
+
+ flags = sdp->isp_devparam[tgt].cur_dflags;
+ period = sdp->isp_devparam[tgt].cur_period;
+ if ((flags & DPARM_SYNC) && period &&
+ (sdp->isp_devparam[tgt].cur_offset) != 0) {
+ if (sdp->isp_lvdmode) {
+ switch (period) {
+ case 0xa:
+ mhz = 40;
+ break;
+ case 0xb:
+ mhz = 33;
+ break;
+ case 0xc:
+ mhz = 25;
+ break;
+ default:
mhz = 1000 / (period * 4);
+ break;
}
} else {
- mhz = 0;
- }
- switch (flags & (DPARM_WIDE|DPARM_TQING)) {
- case DPARM_WIDE:
- wt = ", 16 bit wide\n";
- break;
- case DPARM_TQING:
- wt = ", Tagged Queueing Enabled\n";
- break;
- case DPARM_WIDE|DPARM_TQING:
- wt = ", 16 bit wide, Tagged Queueing Enabled\n";
- break;
- default:
- wt = "\n";
- break;
- }
- if (mhz) {
- printf("%s: Target %d at %dMHz Max Offset %d%s",
- isp->isp_name, tgt, mhz,
- sdp->isp_devparam[tgt].cur_offset, wt);
- } else {
- printf("%s: Target %d Async Mode%s",
- isp->isp_name, tgt, wt);
+ mhz = 1000 / (period * 4);
}
+ } else {
+ mhz = 0;
+ }
+ switch (flags & (DPARM_WIDE|DPARM_TQING)) {
+ case DPARM_WIDE:
+ wt = ", 16 bit wide\n";
+ break;
+ case DPARM_TQING:
+ wt = ", Tagged Queueing Enabled\n";
+ break;
+ case DPARM_WIDE|DPARM_TQING:
+ wt = ", 16 bit wide, Tagged Queueing Enabled\n";
+ break;
+ default:
+ wt = "\n";
+ break;
+ }
+ if (mhz) {
+ CFGPRINTF("%s: Bus %d Target %d at %dMHz Max "
+ "Offset %d%s", isp->isp_name, bus, tgt, mhz,
+ sdp->isp_devparam[tgt].cur_offset, wt);
+ } else {
+ CFGPRINTF("%s: Bus %d Target %d Async Mode%s",
+ isp->isp_name, bus, tgt, wt);
}
break;
+ }
case ISPASYNC_BUS_RESET:
- printf("%s: SCSI bus reset detected\n", isp->isp_name);
+ if (arg)
+ bus = *((int *) arg);
+ else
+ bus = 0;
+ printf("%s: SCSI bus %d reset detected\n", isp->isp_name, bus);
break;
case ISPASYNC_LOOP_DOWN:
+ /*
+ * Hopefully we get here in time to minimize the number
+ * of commands we are firing off that are sure to die.
+ */
+ isp->isp_osinfo.blocked = 1;
printf("%s: Loop DOWN\n", isp->isp_name);
break;
- case ISPASYNC_LOOP_UP:
+ case ISPASYNC_LOOP_UP:
+ isp->isp_osinfo.blocked = 0;
+ timeout(isp_internal_restart, isp, 1);
printf("%s: Loop UP\n", isp->isp_name);
break;
- case ISPASYNC_PDB_CHANGE_COMPLETE:
-#if 0
- if (isp->isp_type & ISP_HA_FC) {
- int i;
- static char *roles[4] = {
+ case ISPASYNC_PDB_CHANGED:
+ if (IS_FC(isp) && isp->isp_dblev) {
+ const char *fmt = "%s: Target %d (Loop 0x%x) Port ID 0x%x "
+ "role %s %s\n Port WWN 0x%08x%08x\n Node WWN 0x%08x%08x\n";
+ const static char *roles[4] = {
"No", "Target", "Initiator", "Target/Initiator"
};
- for (i = 0; i < MAX_FC_TARG; i++) {
- isp_pdb_t *pdbp =
- &((fcparam *)isp->isp_param)->isp_pdb[i];
- if (pdbp->pdb_options == INVALID_PDB_OPTIONS)
- continue;
- printf("%s: Loop ID %d, %s role\n",
- isp->isp_name, pdbp->pdb_loopid,
- roles[(pdbp->pdb_prli_svc3 >> 4) & 0x3]);
- printf(" Node Address 0x%x WWN 0x"
- "%02x%02x%02x%02x%02x%02x%02x%02x\n",
- BITS2WORD(pdbp->pdb_portid_bits),
- pdbp->pdb_portname[0], pdbp->pdb_portname[1],
- pdbp->pdb_portname[2], pdbp->pdb_portname[3],
- pdbp->pdb_portname[4], pdbp->pdb_portname[5],
- pdbp->pdb_portname[6], pdbp->pdb_portname[7]);
- if (pdbp->pdb_options & PDB_OPTIONS_ADISC)
- printf(" Hard Address 0x%x WWN 0x"
- "%02x%02x%02x%02x%02x%02x%02x%02x\n",
- BITS2WORD(pdbp->pdb_hardaddr_bits),
- pdbp->pdb_nodename[0],
- pdbp->pdb_nodename[1],
- pdbp->pdb_nodename[2],
- pdbp->pdb_nodename[3],
- pdbp->pdb_nodename[4],
- pdbp->pdb_nodename[5],
- pdbp->pdb_nodename[6],
- pdbp->pdb_nodename[7]);
- switch (pdbp->pdb_prli_svc3 & SVC3_ROLE_MASK) {
- case SVC3_TGT_ROLE|SVC3_INI_ROLE:
- printf(" Master State=%s, Slave State=%s\n",
- isp2100_pdb_statename(pdbp->pdb_mstate),
- isp2100_pdb_statename(pdbp->pdb_sstate));
- break;
- case SVC3_TGT_ROLE:
- printf(" Master State=%s\n",
- isp2100_pdb_statename(pdbp->pdb_mstate));
- break;
- case SVC3_INI_ROLE:
- printf(" Slave State=%s\n",
- isp2100_pdb_statename(pdbp->pdb_sstate));
- break;
- default:
- break;
- }
+ char *ptr;
+ fcparam *fcp = isp->isp_param;
+ int tgt = *((int *) arg);
+ struct lportdb *lp = &fcp->portdb[tgt];
+
+ if (lp->valid) {
+ ptr = "arrived";
+ } else {
+ ptr = "disappeared";
}
+ printf(fmt, isp->isp_name, tgt, lp->loopid, lp->portid,
+ roles[lp->roles & 0x3], ptr,
+ (u_int32_t) (lp->port_wwn >> 32),
+ (u_int32_t) (lp->port_wwn & 0xffffffffLL),
+ (u_int32_t) (lp->node_wwn >> 32),
+ (u_int32_t) (lp->node_wwn & 0xffffffffLL));
break;
}
-#else
- break;
-#endif
+#ifdef ISP2100_FABRIC
case ISPASYNC_CHANGE_NOTIFY:
printf("%s: Name Server Database Changed\n", isp->isp_name);
break;
+ case ISPASYNC_FABRIC_DEV:
+ {
+ int target;
+ struct lportdb *lp;
+ sns_scrsp_t *resp = (sns_scrsp_t *) arg;
+ u_int32_t portid;
+ u_int64_t wwn;
+ 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 =
+ (((u_int64_t)resp->snscb_portname[0]) << 56) |
+ (((u_int64_t)resp->snscb_portname[1]) << 48) |
+ (((u_int64_t)resp->snscb_portname[2]) << 40) |
+ (((u_int64_t)resp->snscb_portname[3]) << 32) |
+ (((u_int64_t)resp->snscb_portname[4]) << 24) |
+ (((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)
+ break;
+ for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) {
+ lp = &fcp->portdb[target];
+ if (lp->port_wwn == wwn)
+ break;
+ }
+ if (target < MAX_FC_TARG) {
+ break;
+ }
+ for (target = FC_SNS_ID+1; target < MAX_FC_TARG; target++) {
+ lp = &fcp->portdb[target];
+ if (lp->port_wwn == 0)
+ break;
+ }
+ if (target == MAX_FC_TARG) {
+ printf("%s: no more space for fabric devices\n",
+ isp->isp_name);
+ return (-1);
+ }
+ lp->port_wwn = lp->node_wwn = wwn;
+ lp->portid = portid;
+ break;
+ }
+#endif
default:
break;
}