patch-2.3.47 linux/drivers/scsi/scsi_lib.c
Next file: linux/drivers/scsi/scsi_obsolete.c
Previous file: linux/drivers/scsi/scsi_ioctl.c
Back to the patch index
Back to the overall index
- Lines: 236
- Date:
Thu Feb 17 11:39:28 2000
- Orig file:
v2.3.46/linux/drivers/scsi/scsi_lib.c
- Orig date:
Wed Feb 16 17:03:52 2000
diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c
@@ -121,6 +121,74 @@
}
/*
+ * Function: scsi_insert_special_req()
+ *
+ * Purpose: Insert pre-formed request into request queue.
+ *
+ * Arguments: SRpnt - request that is ready to be queued.
+ * at_head - boolean. True if we should insert at head
+ * of queue, false if we should insert at tail.
+ *
+ * Lock status: Assumed that lock is not held upon entry.
+ *
+ * Returns: Nothing
+ *
+ * Notes: This function is called from character device and from
+ * ioctl types of functions where the caller knows exactly
+ * what SCSI command needs to be issued. The idea is that
+ * we merely inject the command into the queue (at the head
+ * for now), and then call the queue request function to actually
+ * process it.
+ */
+int scsi_insert_special_req(Scsi_Request * SRpnt, int at_head)
+{
+ unsigned long flags;
+ request_queue_t *q;
+
+ ASSERT_LOCK(&io_request_lock, 0);
+
+ /*
+ * The SCpnt already contains a request structure - we will doctor the
+ * thing up with the appropriate values and use that in the actual
+ * request queue.
+ */
+ q = &SRpnt->sr_device->request_queue;
+ SRpnt->sr_request.cmd = SPECIAL;
+ SRpnt->sr_request.special = (void *) SRpnt;
+
+ /*
+ * We have the option of inserting the head or the tail of the queue.
+ * Typically we use the tail for new ioctls and so forth. We use the
+ * head of the queue for things like a QUEUE_FULL message from a
+ * device, or a host that is unable to accept a particular command.
+ */
+ spin_lock_irqsave(&io_request_lock, flags);
+
+ if (at_head) {
+ list_add(&SRpnt->sr_request.queue, &q->queue_head);
+ } else {
+ /*
+ * FIXME(eric) - we always insert at the tail of the
+ * list. Otherwise ioctl commands would always take
+ * precedence over normal I/O. An ioctl on a busy
+ * disk might be delayed indefinitely because the
+ * request might not float high enough in the queue
+ * to be scheduled.
+ */
+ list_add_tail(&SRpnt->sr_request.queue, &q->queue_head);
+ }
+
+ /*
+ * Now hit the requeue function for the queue. If the host is
+ * already busy, so be it - we have nothing special to do. If
+ * the host can queue it, then send it off.
+ */
+ q->request_fn(q);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return 0;
+}
+
+/*
* Function: scsi_init_cmd_errh()
*
* Purpose: Initialize SCpnt fields related to error handling.
@@ -160,6 +228,7 @@
*/
SCpnt->old_use_sg = SCpnt->use_sg;
SCpnt->old_cmd_len = SCpnt->cmd_len;
+ SCpnt->sc_old_data_direction = SCpnt->sc_data_direction;
memcpy((void *) SCpnt->data_cmnd,
(const void *) SCpnt->cmnd, sizeof(SCpnt->cmnd));
SCpnt->buffer = SCpnt->request_buffer;
@@ -257,6 +326,7 @@
if (((SHpnt->can_queue > 0)
&& (SHpnt->host_busy >= SHpnt->can_queue))
|| (SHpnt->host_blocked)
+ || (SHpnt->host_self_blocked)
|| (SDpnt->device_blocked)) {
break;
}
@@ -278,7 +348,8 @@
for (SDpnt = SHpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
request_queue_t *q;
if ((SHpnt->can_queue > 0 && (SHpnt->host_busy >= SHpnt->can_queue))
- || (SHpnt->host_blocked)) {
+ || (SHpnt->host_blocked)
+ || (SHpnt->host_self_blocked)) {
break;
}
if (SDpnt->device_blocked || !SDpnt->starved) {
@@ -759,6 +830,7 @@
{
struct request *req;
Scsi_Cmnd *SCpnt;
+ Scsi_Request *SRpnt;
Scsi_Device *SDpnt;
struct Scsi_Host *SHpnt;
struct Scsi_Device_Template *STpnt;
@@ -789,13 +861,24 @@
*/
while (1 == 1) {
/*
+ * Check this again - each time we loop through we will have
+ * released the lock and grabbed it again, so each time
+ * we need to check to see if the queue is plugged or not.
+ */
+ if (SHpnt->in_recovery
+ || q->plugged) {
+ return;
+ }
+
+ /*
* If the device cannot accept another request, then quit.
*/
if (SDpnt->device_blocked) {
break;
}
if ((SHpnt->can_queue > 0 && (SHpnt->host_busy >= SHpnt->can_queue))
- || (SHpnt->host_blocked)) {
+ || (SHpnt->host_blocked)
+ || (SHpnt->host_self_blocked)) {
/*
* If we are unable to process any commands at all for this
* device, then we consider it to be starved. What this means
@@ -862,6 +945,14 @@
if (req->cmd == SPECIAL) {
STpnt = NULL;
SCpnt = (Scsi_Cmnd *) req->special;
+ SRpnt = (Scsi_Request *) req->special;
+
+ if( SRpnt->sr_magic == SCSI_REQ_MAGIC ) {
+ SCpnt = scsi_allocate_device(SRpnt->sr_device,
+ FALSE, FALSE);
+ scsi_init_cmd_from_req(SCpnt, SRpnt);
+ }
+
} else {
STpnt = scsi_get_request_dev(req);
if (!STpnt) {
@@ -986,6 +1077,85 @@
* the request queue and try to find another command.
*/
spin_lock_irq(&io_request_lock);
+ }
+}
+
+/*
+ * Function: scsi_block_requests()
+ *
+ * Purpose: Utility function used by low-level drivers to prevent further
+ * commands from being queued to the device.
+ *
+ * Arguments: SHpnt - Host in question
+ *
+ * Returns: Nothing
+ *
+ * Lock status: No locks are assumed held.
+ *
+ * Notes: There is no timer nor any other means by which the requests
+ * get unblocked other than the low-level driver calling
+ * scsi_unblock_requests().
+ */
+void scsi_block_requests(struct Scsi_Host * SHpnt)
+{
+ SHpnt->host_self_blocked = TRUE;
+}
+
+/*
+ * Function: scsi_unblock_requests()
+ *
+ * Purpose: Utility function used by low-level drivers to allow further
+ * commands from being queued to the device.
+ *
+ * Arguments: SHpnt - Host in question
+ *
+ * Returns: Nothing
+ *
+ * Lock status: No locks are assumed held.
+ *
+ * Notes: There is no timer nor any other means by which the requests
+ * get unblocked other than the low-level driver calling
+ * scsi_unblock_requests().
+ *
+ * This is done as an API function so that changes to the
+ * internals of the scsi mid-layer won't require wholesale
+ * changes to drivers that use this feature.
+ */
+void scsi_unblock_requests(struct Scsi_Host * SHpnt)
+{
+ SHpnt->host_self_blocked = FALSE;
+}
+
+
+/*
+ * Function: scsi_report_bus_reset()
+ *
+ * Purpose: Utility function used by low-level drivers to report that
+ * they have observed a bus reset on the bus being handled.
+ *
+ * Arguments: SHpnt - Host in question
+ * channel - channel on which reset was observed.
+ *
+ * Returns: Nothing
+ *
+ * Lock status: No locks are assumed held.
+ *
+ * Notes: This only needs to be called if the reset is one which
+ * originates from an unknown location. Resets originated
+ * by the mid-level itself don't need to call this, but there
+ * should be no harm.
+ *
+ * The main purpose of this is to make sure that a CHECK_CONDITION
+ * is properly treated.
+ */
+void scsi_report_bus_reset(struct Scsi_Host * SHpnt, int channel)
+{
+ Scsi_Device *SDloop;
+ for (SDloop = SHpnt->host_queue; SDloop; SDloop = SDloop->next) {
+ if (channel == SDloop->channel) {
+ SDloop->was_reset = 1;
+ SDloop->expecting_cc_ua = 1;
+ }
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)