Add in the enabling of interrupts (to isp_attach). Clean up a busted

comment. Check against firmware state- not loop state when enabling
target mode. Other changes have to do with no longer enabling/disabling
interrupts at will.

Rearchitect command watchdog timeouts-

First of all, set the timeout period for a command that has a
timeout (in isp_action) to the period of time requested *plus* two
seconds. We don't want the Qlogic firmware and the host system to
race each other to report a dead command (the watchdog is there to
catch dead and/or broken firmware).

Next, make sure that the command being watched isn't done yet. If
it's not done yet, check for INT_PENDING and call isp_intr- if that
said it serviced an interrupt, check to see whether the command is
now done (this is what the "IN WATCHDOG" private flag is for- if
isp_intr completes the command, it won't call xpt_done on it because
isp_watchdog is still looking at the command).

If no interrupt was pending, or the command wasn't completed, check
to see if we've set the private 'grace period' flag. If so, the
command really *is* dead, so report it as dead and complete it with
a CAM_CMD_TIMEOUT value.

If the grace period flag wasn't set, set it and issue a SYNCHRONIZE_ALL
Marker Request Queue entry and re-set the timeout for one second
from now (see Revision 1.45 isp.c notes for more on this) to give
the firmware a final chance to complete this command.
This commit is contained in:
Matt Jacob 2000-06-27 19:31:02 +00:00
parent cc28790740
commit b85389e117

View File

@ -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