summaryrefslogtreecommitdiff
path: root/sys/dev/isp/isp_freebsd.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/isp/isp_freebsd.c')
-rw-r--r--sys/dev/isp/isp_freebsd.c251
1 files changed, 211 insertions, 40 deletions
diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c
index ee56cf6298fbb..dcbf7528fd7ae 100644
--- a/sys/dev/isp/isp_freebsd.c
+++ b/sys/dev/isp/isp_freebsd.c
@@ -1,5 +1,5 @@
-/* $Id: isp_freebsd.c,v 1.11 1999/01/30 07:29:00 mjacob Exp $ */
-/* release_02_05_99 */
+/* $Id: isp_freebsd.c,v 1.12 1999/02/09 01:08:38 mjacob Exp $ */
+/* release_03_16_99 */
/*
* Platform (FreeBSD) dependent common attachment code for Qlogic adapters.
*
@@ -92,7 +92,8 @@ isp_attach(struct ispsoftc *isp)
if (isp->isp_type & ISP_HA_FC) {
isp->isp_sim->base_transfer_speed = 100000;
}
- isp->isp_state = ISP_RUNSTATE;
+ if (isp->isp_state == ISP_INITSTATE)
+ isp->isp_state = ISP_RUNSTATE;
}
static void
@@ -148,6 +149,30 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
isp = (struct ispsoftc *)cam_sim_softc(sim);
ccb->ccb_h.sim_priv.entries[0].field = 0;
ccb->ccb_h.sim_priv.entries[1].ptr = isp;
+ /*
+ * This should only happen for Fibre Channel adapters.
+ * We want to pass through all but XPT_SCSI_IO (e.g.,
+ * path inquiry) but fail if we can't get good Fibre
+ * Channel link status.
+ */
+ if (ccb->ccb_h.func_code == XPT_SCSI_IO &&
+ isp->isp_state != ISP_RUNSTATE) {
+ s = splcam();
+ DISABLE_INTS(isp);
+ isp_init(isp);
+ if (isp->isp_state != ISP_INITSTATE) {
+ (void) splx(s);
+ /*
+ * Lie. Say it was a selection timeout.
+ */
+ ccb->ccb_h.status = CAM_SEL_TIMEOUT;
+ xpt_done(ccb);
+ return;
+ }
+ isp->isp_state = ISP_RUNSTATE;
+ ENABLE_INTS(isp);
+ (void) splx(s);
+ }
IDPRINTF(4, ("%s: isp_action code %x\n", isp->isp_name,
ccb->ccb_h.func_code));
@@ -218,9 +243,9 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
ccb->ccb_h.status |= CAM_SIM_QUEUED;
break;
case CMD_EAGAIN:
- if (isp->isp_osinfo.simqfrozen == 0) {
+ if (!(isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE)) {
xpt_freeze_simq(sim, 1);
- isp->isp_osinfo.simqfrozen = 1;
+ isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE;
}
ccb->ccb_h.status &= ~CAM_STATUS_MASK;
ccb->ccb_h.status |= CAM_REQUEUE_REQ;
@@ -547,13 +572,10 @@ isp_done(struct ccb_scsiio *sccb)
sccb->ccb_h.status |= CAM_DEV_QFRZN;
}
}
- if (isp->isp_osinfo.simqfrozen) {
-
- xpt_print_path(sccb->ccb_h.path);
- printf("isp_done releasing SIMQ\n");
-
+ if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) {
+ isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE;
sccb->ccb_h.status |= CAM_RELEASE_SIMQ;
- isp->isp_osinfo.simqfrozen = 0;
+ xpt_release_simq(isp->isp_sim, 1);
}
sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
if (CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB) &&
@@ -572,29 +594,6 @@ isp_async(isp, cmd, arg)
{
int rv = 0;
switch (cmd) {
- case ISPASYNC_LOOP_DOWN:
- if (isp->isp_path) {
- /*
- * We can get multiple LOOP downs, so only count one.
- */
- if (isp->isp_osinfo.simqfrozen == 0) {
- xpt_freeze_simq(isp->isp_sim, 1);
- isp->isp_osinfo.simqfrozen = 1;
- xpt_print_path(isp->isp_path);
- printf("freezing SIMQ until loop comes up\n");
- }
- }
- break;
- case ISPASYNC_LOOP_UP:
- if (isp->isp_path) {
- xpt_print_path(isp->isp_path);
- if (isp->isp_osinfo.simqfrozen) {
- isp->isp_osinfo.simqfrozen = 0;
- printf("releasing frozen SIMQ\n");
- xpt_release_simq(isp->isp_sim, 1);
- }
- }
- break;
case ISPASYNC_NEW_TGT_PARAMS:
if (isp->isp_type & ISP_HA_SCSI) {
int flags, tgt;
@@ -638,6 +637,100 @@ isp_async(isp, cmd, arg)
xpt_free_path(tmppath);
}
break;
+ case ISPASYNC_BUS_RESET:
+ printf("%s: SCSI bus reset detected\n", isp->isp_name);
+ if (isp->isp_path) {
+ xpt_async(AC_BUS_RESET, isp->isp_path, NULL);
+ }
+ break;
+ case ISPASYNC_LOOP_DOWN:
+ if (isp->isp_path) {
+ /*
+ * We can get multiple LOOP downs, so only count one.
+ */
+ if (!(isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN)) {
+ xpt_freeze_simq(isp->isp_sim, 1);
+ isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN;
+ printf("%s: Loop DOWN- freezing SIMQ until Loop"
+ " comes up\n", isp->isp_name);
+ }
+ } else {
+ printf("%s: Loop DOWN\n", isp->isp_name);
+ }
+ break;
+ case ISPASYNC_LOOP_UP:
+ if (isp->isp_path) {
+ if (isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN) {
+ xpt_release_simq(isp->isp_sim, 1);
+ isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN;
+ if (isp->isp_osinfo.simqfrozen) {
+ printf("%s: Loop UP- SIMQ still "
+ "frozen\n", isp->isp_name);
+ } else {
+ printf("%s: Loop UP-releasing frozen "
+ "SIMQ\n", isp->isp_name);
+ }
+ }
+ } else {
+ printf("%s: Loop UP\n", isp->isp_name);
+ }
+ break;
+ case ISPASYNC_PDB_CHANGE_COMPLETE:
+ if (isp->isp_type & ISP_HA_FC) {
+ int i;
+ static char *roles[4] = {
+ "No", "Target", "Initiator", "Target/Initiator"
+ };
+ for (i = 0; i < MAX_FC_TARG; i++) {
+ isp_pdb_t *pdbp =
+ &((fcparam *)isp->isp_param)->isp_pdb[i];
+ if (pdbp->pdb_options == INVALID_PDB_OPTIONS)
+ continue;
+ printf("%s: Loop ID %d, %s role\n",
+ isp->isp_name, pdbp->pdb_loopid,
+ roles[(pdbp->pdb_prli_svc3 >> 4) & 0x3]);
+ printf(" Node Address 0x%x WWN 0x"
+ "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ BITS2WORD(pdbp->pdb_portid_bits),
+ pdbp->pdb_portname[0], pdbp->pdb_portname[1],
+ pdbp->pdb_portname[2], pdbp->pdb_portname[3],
+ pdbp->pdb_portname[4], pdbp->pdb_portname[5],
+ pdbp->pdb_portname[6], pdbp->pdb_portname[7]);
+ if (pdbp->pdb_options & PDB_OPTIONS_ADISC)
+ printf(" Hard Address 0x%x WWN 0x"
+ "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ BITS2WORD(pdbp->pdb_hardaddr_bits),
+ pdbp->pdb_nodename[0],
+ pdbp->pdb_nodename[1],
+ pdbp->pdb_nodename[2],
+ pdbp->pdb_nodename[3],
+ pdbp->pdb_nodename[4],
+ pdbp->pdb_nodename[5],
+ pdbp->pdb_nodename[6],
+ pdbp->pdb_nodename[7]);
+ switch (pdbp->pdb_prli_svc3 & SVC3_ROLE_MASK) {
+ case SVC3_TGT_ROLE|SVC3_INI_ROLE:
+ printf(" Master State=%s, Slave State=%s\n",
+ isp2100_pdb_statename(pdbp->pdb_mstate),
+ isp2100_pdb_statename(pdbp->pdb_sstate));
+ break;
+ case SVC3_TGT_ROLE:
+ printf(" Master State=%s\n",
+ isp2100_pdb_statename(pdbp->pdb_mstate));
+ break;
+ case SVC3_INI_ROLE:
+ printf(" Slave State=%s\n",
+ isp2100_pdb_statename(pdbp->pdb_sstate));
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ case ISPASYNC_CHANGE_NOTIFY:
+ printf("%s: Name Server Database Changed\n", isp->isp_name);
+ break;
default:
break;
}
@@ -672,7 +765,9 @@ isp_attach(struct ispsoftc *isp)
if(!scbus) {
return;
}
- isp->isp_state = ISP_RUNSTATE;
+ if (isp->isp_state == ISP_INITSTATE)
+ isp->isp_state = ISP_RUNSTATE;
+
START_WATCHDOG(isp);
isp->isp_osinfo._link.adapter_unit = isp->isp_osinfo.unit;
@@ -736,14 +831,25 @@ static int
ispcmd(ISP_SCSI_XFER_T *xs)
{
struct ispsoftc *isp;
- int r;
- ISP_LOCKVAL_DECL;
+ int r, s;
isp = XS_ISP(xs);
- ISP_LOCK;
+ s = splbio();
+ DISABLE_INTS(isp);
+ if (isp->isp_state != ISP_RUNSTATE) {
+ isp_init(isp);
+ if (isp->isp_state != ISP_INITSTATE) {
+ ENABLE_INTS(isp);
+ (void) splx(s);
+ XS_SETERR(xs, HBA_BOTCH);
+ return (CMD_COMPLETE);
+ }
+ isp_state = ISP_RUNSTATE;
+ }
r = ispscsicmd(xs);
+ ENABLE_INTS(isp);
if (r != CMD_QUEUED || (xs->flags & SCSI_NOMASK) == 0) {
- ISP_UNLOCK;
+ (void) splx(s);
return (r);
}
@@ -765,7 +871,7 @@ ispcmd(ISP_SCSI_XFER_T *xs)
}
}
}
- ISP_UNLOCK;
+ (void) splx(s);
return (CMD_COMPLETE);
}
@@ -873,6 +979,71 @@ isp_async(isp, cmd, arg)
}
}
break;
+ case ISPASYNC_BUS_RESET:
+ printf("%s: SCSI bus reset detected\n", isp->isp_name);
+ break;
+ case ISPASYNC_LOOP_DOWN:
+ printf("%s: Loop DOWN\n", isp->isp_name);
+ break;
+ case ISPASYNC_LOOP_UP:
+ printf("%s: Loop UP\n", isp->isp_name);
+ break;
+ case ISPASYNC_PDB_CHANGE_COMPLETE:
+ if (isp->isp_type & ISP_HA_FC) {
+ int i;
+ static char *roles[4] = {
+ "No", "Target", "Initiator", "Target/Initiator"
+ };
+ for (i = 0 i < MAX_FC_TARG; i++) {
+ isp_pdb_t *pdbp =
+ &((fcparam *)isp->isp_param)->isp_pdb[i];
+ if (pdbp->pdb_options == INVALID_PDB_OPTIONS)
+ continue;
+ printf("%s: Loop ID %d, %s role\n",
+ isp->isp_name, pdbp->pdb_loopid,
+ roles[(pdbp->pdb_prli_svc3 >> 4) & 0x3]);
+ printf(" Node Address 0x%x WWN 0x"
+ "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ BITS2WORD(pdbp->pdb_portid_bits),
+ pdbp->pdb_portname[0], pdbp->pdb_portname[1],
+ pdbp->pdb_portname[2], pdbp->pdb_portname[3],
+ pdbp->pdb_portname[4], pdbp->pdb_portname[5],
+ pdbp->pdb_portname[6], pdbp->pdb_portname[7]);
+ if (pdbp->pdb_options & PDB_OPTIONS_ADISC)
+ printf(" Hard Address 0x%x WWN 0x"
+ "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ BITS2WORD(pdbp->pdb_hardaddr_bits),
+ pdbp->pdb_nodename[0],
+ pdbp->pdb_nodename[1],
+ pdbp->pdb_nodename[2],
+ pdbp->pdb_nodename[3],
+ pdbp->pdb_nodename[4],
+ pdbp->pdb_nodename[5],
+ pdbp->pdb_nodename[6],
+ pdbp->pdb_nodename[7]);
+ switch (pdbp->pdb_prli_svc3 & SVC3_ROLE_MASK) {
+ case SVC3_TGT_ROLE|SVC3_INI_ROLE:
+ printf(" Master State=%s, Slave State=%s\n",
+ isp2100_pdb_statename(pdbp->pdb_mstate),
+ isp2100_pdb_statename(pdbp->pdb_sstate));
+ break;
+ case SVC3_TGT_ROLE:
+ printf(" Master State=%s\n",
+ isp2100_pdb_statename(pdbp->pdb_mstate));
+ break;
+ case SVC3_INI_ROLE:
+ printf(" Slave State=%s\n",
+ isp2100_pdb_statename(pdbp->pdb_sstate));
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ case ISPASYNC_CHANGE_NOTIFY:
+ printf("%s: Name Server Database Changed\n", isp->isp_name);
+ break;
default:
break;
}