summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authormjacob <mjacob@FreeBSD.org>2001-07-30 00:19:50 +0000
committermjacob <mjacob@FreeBSD.org>2001-07-30 00:19:50 +0000
commite082eeba8dbddaecba7fb025c178f9b45da9bedd (patch)
tree363a5b7f56d81b7c78834950427f816edb3ab0c6 /sys
parent45d74ded45f372ec65026357850606d9048d7abc (diff)
downloadFreeBSD-src-e082eeba8dbddaecba7fb025c178f9b45da9bedd.zip
FreeBSD-src-e082eeba8dbddaecba7fb025c178f9b45da9bedd.tar.gz
Propagate CAM_DIS_DISCONNECT on through:
1. If we get frozen, unfreeze for disable disconnects. 2. Put CAM_DIS_DISCONNECT commands at the head of the work queue (we have a target still connected and we can't run anything else until this command completes). If we had an error sending the last CTIO, unfreeze the queue anyway.
Diffstat (limited to 'sys')
-rw-r--r--sys/cam/scsi/scsi_targ_bh.c59
1 files changed, 54 insertions, 5 deletions
diff --git a/sys/cam/scsi/scsi_targ_bh.c b/sys/cam/scsi/scsi_targ_bh.c
index 95f2631..f18dee3 100644
--- a/sys/cam/scsi/scsi_targ_bh.c
+++ b/sys/cam/scsi/scsi_targ_bh.c
@@ -487,7 +487,8 @@ targbhstart(struct cam_periph *periph, union ccb *start_ccb)
desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
/* Is this a tagged request? */
- flags = atio->ccb_h.flags & (CAM_TAG_ACTION_VALID|CAM_DIR_MASK);
+ flags = atio->ccb_h.flags &
+ (CAM_DIS_DISCONNECT|CAM_TAG_ACTION_VALID|CAM_DIR_MASK);
csio = &start_ccb->csio;
/*
@@ -529,6 +530,19 @@ targbhstart(struct cam_periph *periph, union ccb *start_ccb)
CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
("Sending a CTIO\n"));
xpt_action(start_ccb);
+ /*
+ * If the queue was frozen waiting for the response
+ * to this ATIO (for instance disconnection was disallowed),
+ * then release it now that our response has been queued.
+ */
+ if ((atio->ccb_h.status & CAM_DEV_QFRZN) != 0) {
+ cam_release_devq(periph->path,
+ /*relsim_flags*/0,
+ /*reduction*/0,
+ /*timeout*/0,
+ /*getcount_only*/0);
+ atio->ccb_h.status &= ~CAM_DEV_QFRZN;
+ }
s = splbio();
ccbh = TAILQ_FIRST(&softc->work_queue);
splx(s);
@@ -556,6 +570,7 @@ targbhdone(struct cam_periph *periph, union ccb *done_ccb)
struct ccb_accept_tio *atio;
struct targbh_cmd_desc *descr;
u_int8_t *cdb;
+ int priority;
atio = &done_ccb->atio;
descr = (struct targbh_cmd_desc*)atio->ccb_h.ccb_descr;
@@ -645,9 +660,16 @@ targbhdone(struct cam_periph *periph, union ccb *done_ccb)
}
/* Queue us up to receive a Continue Target I/O ccb. */
- TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h,
- periph_links.tqe);
- xpt_schedule(periph, /*priority*/1);
+ if ((atio->ccb_h.flags & CAM_DIS_DISCONNECT) != 0) {
+ TAILQ_INSERT_HEAD(&softc->work_queue, &atio->ccb_h,
+ periph_links.tqe);
+ priority = 0;
+ } else {
+ TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h,
+ periph_links.tqe);
+ priority = 1;
+ }
+ xpt_schedule(periph, priority);
break;
}
case XPT_CONT_TARGET_IO:
@@ -672,7 +694,22 @@ targbhdone(struct cam_periph *periph, union ccb *done_ccb)
done_ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
done_ccb->ccb_h.status &= ~CAM_SENT_SENSE;
- /* XXX Check for errors */
+ /*
+ * Any errors will not change the data we return,
+ * so make sure the queue is not left frozen.
+ * XXX - At some point there may be errors that
+ * leave us in a connected state with the
+ * initiator...
+ */
+ if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
+ printf("Releasing Queue\n");
+ cam_release_devq(done_ccb->ccb_h.path,
+ /*relsim_flags*/0,
+ /*reduction*/0,
+ /*timeout*/0,
+ /*getcount_only*/0);
+ done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
+ }
desc->data_resid -= desc->data_increment;
xpt_release_ccb(done_ccb);
if (softc->state != TARGBH_STATE_TEARDOWN) {
@@ -696,11 +733,23 @@ targbhdone(struct cam_periph *periph, union ccb *done_ccb)
}
case XPT_IMMED_NOTIFY:
{
+ int frozen;
+
+ frozen = (done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0;
if (softc->state == TARGBH_STATE_TEARDOWN
|| done_ccb->ccb_h.status == CAM_REQ_ABORTED) {
printf("Freed an immediate notify\n");
free(done_ccb, M_DEVBUF);
+ } else {
+ /* Requeue for another immediate event */
+ xpt_action(done_ccb);
}
+ if (frozen != 0)
+ cam_release_devq(periph->path,
+ /*relsim_flags*/0,
+ /*opening reduction*/0,
+ /*timeout*/0,
+ /*getcount_only*/0);
break;
}
default:
OpenPOWER on IntegriCloud