summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/isp/isp_freebsd.c127
1 files changed, 93 insertions, 34 deletions
diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c
index db5e64b71847..e1c19437b9a5 100644
--- a/sys/dev/isp/isp_freebsd.c
+++ b/sys/dev/isp/isp_freebsd.c
@@ -37,7 +37,7 @@
static void isp_cam_async(void *, u_int32_t, struct cam_path *, void *);
static void isp_poll(struct cam_sim *);
static void isp_relsim(void *);
-static timeout_t isp_timeout;
+static timeout_t isp_watchdog;
static void isp_action(struct cam_sim *, union ccb *);
@@ -143,6 +143,7 @@ isp_attach(struct ispsoftc *isp)
isp->isp_path2 = path;
}
isp->isp_state = ISP_RUNSTATE;
+ ENABLE_INTS(isp);
if (isplist == NULL) {
isplist = isp;
} else {
@@ -398,7 +399,7 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
/*
* First, check to see if we're enabling on fibre channel
* and don't yet have a notion of who the heck we are (no
- * loop yet). We do this by
+ * loop yet).
*/
if (IS_FC(isp) && cel->enable &&
(isp->isp_osinfo.tmflags & TM_TMODE_ENABLED) == 0) {
@@ -417,9 +418,9 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
s = splcam();
rv = isp_control(isp, ISPCTL_PDB_SYNC, NULL);
(void) splx(s);
- if (rv || fcp->isp_loopstate != LOOP_READY) {
+ if (rv || fcp->isp_fwstate != FW_READY) {
xpt_print_path(ccb->ccb_h.path);
- printf("could not get a good port database\n");
+ printf("could not get a good port database read\n");
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
return;
}
@@ -806,7 +807,7 @@ isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb)
default:
isp_destroy_handle(isp, save_handle);
- return (ccb->ccb_h.spriv_field0);
+ return (XS_ERR(ccb));
}
}
@@ -1198,23 +1199,74 @@ isp_relsim(void *arg)
}
static void
-isp_timeout(void *arg)
+isp_watchdog(void *arg)
{
ISP_SCSI_XFER_T *xs = arg;
struct ispsoftc *isp = XS_ISP(xs);
u_int32_t handle;
int s = splcam();
+
/*
- * We've decide this command is dead. Make sure we're not trying
- * to kill a command that's already dead by getting it's handle.
+ * We've decided this command is dead. Make sure we're not trying
+ * to kill a command that's already dead by getting it's handle and
+ * and seeing whether it's still alive.
*/
handle = isp_find_handle(isp, xs);
if (handle) {
- isp_destroy_handle(isp, handle);
- xpt_print_path(xs->ccb_h.path);
- printf("watchdog timeout (handle 0x%x)\n", handle);
- XS_SETERR(xs, CAM_CMD_TIMEOUT);
- isp_done(xs);
+ u_int16_t r;
+
+ if (XS_CMD_DONE_P(xs)) {
+ PRINTF("%s: watchdog found done cmd (handle 0x%x)\n",
+ isp->isp_name, handle);
+ (void) splx(s);
+ return;
+ }
+
+ if (XS_CMD_WDOG_P(xs)) {
+ PRINTF("%s: recursive watchdog (handle 0x%x)\n",
+ isp->isp_name, handle);
+ (void) splx(s);
+ return;
+ }
+
+ XS_CMD_S_WDOG(xs);
+
+ r = ISP_READ(isp, BIU_ISR);
+
+ if (INT_PENDING(isp, r) && isp_intr(isp) && XS_CMD_DONE_P(xs)) {
+ IDPRINTF(2, ("%s: watchdog cleanup (%x, %x)\n",
+ isp->isp_name, handle, r));
+ xpt_done((union ccb *) xs);
+ } else if (XS_CMD_GRACE_P(xs)) {
+ isp_destroy_handle(isp, handle);
+ xpt_print_path(xs->ccb_h.path);
+ printf("%s: watchdog timeout (%x, %x)\n",
+ isp->isp_name, handle, r);
+ XS_SETERR(xs, CAM_CMD_TIMEOUT);
+ XS_CMD_C_WDOG(xs);
+ isp_done(xs);
+ } else {
+ u_int16_t iptr, optr;
+ ispreq_t *mp;
+
+ XS_CMD_C_WDOG(xs);
+ xs->ccb_h.timeout_ch = timeout(isp_watchdog, xs, hz);
+ if (isp_getrqentry(isp, &iptr, &optr, (void **) &mp)) {
+ (void) splx(s);
+ return;
+ }
+ XS_CMD_S_GRACE(xs);
+ MEMZERO((void *) mp, sizeof (*mp));
+ mp->req_header.rqs_entry_count = 1;
+ mp->req_header.rqs_entry_type = RQSTYPE_MARKER;
+ mp->req_modifier = SYNC_ALL;
+ mp->req_target = XS_CHANNEL(xs) << 7;
+ ISP_SWIZZLE_REQUEST(isp, mp);
+ MemoryBarrier();
+ ISP_ADD_REQUEST(isp, iptr);
+ }
+ } else {
+ IDPRINTF(2, ("%s: watchdog with no command\n", isp->isp_name));
}
(void) splx(s);
}
@@ -1241,8 +1293,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
/*
* Lie. Say it was a selection timeout.
*/
- ccb->ccb_h.status = CAM_SEL_TIMEOUT;
- ccb->ccb_h.status |= CAM_DEV_QFRZN;
+ ccb->ccb_h.status = CAM_SEL_TIMEOUT | CAM_DEV_QFRZN;
xpt_freeze_devq(ccb->ccb_h.path, 1);
xpt_done(ccb);
return;
@@ -1282,19 +1333,22 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
#endif
((struct ccb_scsiio *) ccb)->scsi_status = SCSI_STATUS_OK;
s = splcam();
- DISABLE_INTS(isp);
error = ispscsicmd((ISP_SCSI_XFER_T *) ccb);
- ENABLE_INTS(isp);
splx(s);
switch (error) {
case CMD_QUEUED:
ccb->ccb_h.status |= CAM_SIM_QUEUED;
if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) {
+ int ticks;
if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT)
- ccb->ccb_h.timeout = 5 * 1000;
+ ticks = 60 * 1000 * hz;
+ else
+ ticks = ccb->ccb_h.timeout * hz;
+ ticks = ((ticks + 999) / 1000) + hz + hz;
ccb->ccb_h.timeout_ch =
- timeout(isp_timeout, (caddr_t)ccb,
- (ccb->ccb_h.timeout * hz) / 1000);
+ timeout(isp_watchdog, (caddr_t)ccb, ticks);
+ } else {
+ callout_handle_init(&ccb->ccb_h.timeout_ch);
}
break;
case CMD_RQLATER:
@@ -1305,8 +1359,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
timeout(isp_relsim, isp, 500);
xpt_freeze_simq(sim, 1);
}
- ccb->ccb_h.status &= ~CAM_STATUS_MASK;
- ccb->ccb_h.status |= CAM_REQUEUE_REQ;
+ XS_SETERR(ccb, CAM_REQUEUE_REQ);
xpt_done(ccb);
break;
case CMD_EAGAIN:
@@ -1316,8 +1369,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
isp->isp_name));
}
isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE;
- ccb->ccb_h.status &= ~CAM_STATUS_MASK;
- ccb->ccb_h.status |= CAM_REQUEUE_REQ;
+ XS_SETERR(ccb, CAM_REQUEUE_REQ);
xpt_done(ccb);
break;
case CMD_COMPLETE:
@@ -1326,8 +1378,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
default:
printf("%s: What's this? 0x%x at %d in file %s\n",
isp->isp_name, error, __LINE__, __FILE__);
- ccb->ccb_h.status &= ~CAM_STATUS_MASK;
- ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
+ XS_SETERR(ccb, CAM_REQ_CMP_ERR);
xpt_done(ccb);
}
break;
@@ -1372,8 +1423,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
printf("XPT_CONT_TARGET_IO freeze simq\n");
}
isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE;
- ccb->ccb_h.status &= ~CAM_STATUS_MASK;
- ccb->ccb_h.status |= CAM_REQUEUE_REQ;
+ XS_SETERR(ccb, CAM_REQUEUE_REQ);
xpt_done(ccb);
} else {
ccb->ccb_h.status |= CAM_SIM_QUEUED;
@@ -1640,7 +1690,6 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
break;
case XPT_TERM_IO: /* Terminate the I/O process */
- /* Does this need to be implemented? */
ccb->ccb_h.status = CAM_REQ_INVALID;
xpt_done(ccb);
break;
@@ -1706,8 +1755,7 @@ isp_done(struct ccb_scsiio *sccb)
if (XS_NOERR(sccb))
XS_SETERR(sccb, CAM_REQ_CMP);
- sccb->ccb_h.status &= ~CAM_STATUS_MASK;
- sccb->ccb_h.status |= sccb->ccb_h.spriv_field0;
+
if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
(sccb->scsi_status != SCSI_STATUS_OK)) {
sccb->ccb_h.status &= ~CAM_STATUS_MASK;
@@ -1718,6 +1766,7 @@ isp_done(struct ccb_scsiio *sccb)
sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
}
}
+
sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
@@ -1730,6 +1779,7 @@ isp_done(struct ccb_scsiio *sccb)
sccb->scsi_status));
}
}
+
/*
* If we were frozen waiting resources, clear that we were frozen
* waiting for resources. If we are no longer frozen, and the devq
@@ -1752,13 +1802,22 @@ isp_done(struct ccb_scsiio *sccb)
isp->isp_name, isp->isp_osinfo.simqfrozen));
}
}
- if (CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB) &&
+ if ((CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB)) &&
(sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
xpt_print_path(sccb->ccb_h.path);
printf("cam completion status 0x%x\n", sccb->ccb_h.status);
}
- untimeout(isp_timeout, (caddr_t)sccb, sccb->ccb_h.timeout_ch);
- xpt_done((union ccb *) sccb);
+
+ XS_CMD_S_DONE(sccb);
+ if (XS_CMD_WDOG_P(sccb) == 0) {
+ untimeout(isp_watchdog, (caddr_t)sccb, sccb->ccb_h.timeout_ch);
+ if (XS_CMD_GRACE_P(sccb)) {
+ IDPRINTF(2, ("%s: finished command on borrowed time\n",
+ isp->isp_name));
+ }
+ XS_CMD_S_CLEAR(sccb);
+ xpt_done((union ccb *) sccb);
+ }
}
int