patch-2.3.38 linux/drivers/scsi/scsi_lib.c
Next file: linux/drivers/scsi/scsi_merge.c
Previous file: linux/drivers/scsi/scsi_ioctl.c
Back to the patch index
Back to the overall index
- Lines: 260
- Date:
Fri Jan 7 11:55:28 2000
- Orig file:
v2.3.37/linux/drivers/scsi/scsi_lib.c
- Orig date:
Wed Dec 29 13:13:19 1999
diff -u --recursive --new-file v2.3.37/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c
@@ -294,11 +294,12 @@
* Function: scsi_end_request()
*
* Purpose: Post-processing of completed commands called from interrupt
- * handler.
+ * handler or a bottom-half handler.
*
* Arguments: SCpnt - command that is complete.
* uptodate - 1 if I/O indicates success, 0 for I/O error.
* sectors - number of sectors we want to mark.
+ * requeue - indicates whether we should requeue leftovers.
*
* Lock status: Assumed that lock is not held upon entry.
*
@@ -310,7 +311,10 @@
* We are guaranteeing that the request queue will be goosed
* at some point during this call.
*/
-Scsi_Cmnd *scsi_end_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors)
+static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt,
+ int uptodate,
+ int sectors,
+ int requeue)
{
struct request *req;
struct buffer_head *bh;
@@ -348,6 +352,11 @@
if (req->bh) {
request_queue_t *q;
+ if( !requeue )
+ {
+ return SCpnt;
+ }
+
q = &SCpnt->device->request_queue;
req->buffer = bh->b_data;
@@ -377,6 +386,83 @@
}
/*
+ * Function: scsi_end_request()
+ *
+ * Purpose: Post-processing of completed commands called from interrupt
+ * handler or a bottom-half handler.
+ *
+ * Arguments: SCpnt - command that is complete.
+ * uptodate - 1 if I/O indicates success, 0 for I/O error.
+ * sectors - number of sectors we want to mark.
+ *
+ * Lock status: Assumed that lock is not held upon entry.
+ *
+ * Returns: Nothing
+ *
+ * Notes: This is called for block device requests in order to
+ * mark some number of sectors as complete.
+ *
+ * We are guaranteeing that the request queue will be goosed
+ * at some point during this call.
+ */
+Scsi_Cmnd *scsi_end_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors)
+{
+ return __scsi_end_request(SCpnt, uptodate, sectors, 1);
+}
+
+/*
+ * Function: scsi_release_buffers()
+ *
+ * Purpose: Completion processing for block device I/O requests.
+ *
+ * Arguments: SCpnt - command that we are bailing.
+ *
+ * Lock status: Assumed that no lock is held upon entry.
+ *
+ * Returns: Nothing
+ *
+ * Notes: In the event that an upper level driver rejects a
+ * command, we must release resources allocated during
+ * the __init_io() function. Primarily this would involve
+ * the scatter-gather table, and potentially any bounce
+ * buffers.
+ */
+static void scsi_release_buffers(Scsi_Cmnd * SCpnt)
+{
+ ASSERT_LOCK(&io_request_lock, 0);
+
+ /*
+ * Free up any indirection buffers we allocated for DMA purposes.
+ */
+ if (SCpnt->use_sg) {
+ struct scatterlist *sgpnt;
+ int i;
+
+ sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+
+ for (i = 0; i < SCpnt->use_sg; i++) {
+ if (sgpnt[i].alt_address) {
+ scsi_free(sgpnt[i].address, sgpnt[i].length);
+ }
+ }
+ scsi_free(SCpnt->request_buffer, SCpnt->sglist_len);
+ } else {
+ if (SCpnt->request_buffer != SCpnt->request.buffer) {
+ scsi_free(SCpnt->request_buffer, SCpnt->request_bufflen);
+ }
+ }
+
+ /*
+ * Zero these out. They now point to freed memory, and it is
+ * dangerous to hang onto the pointers.
+ */
+ SCpnt->buffer = NULL;
+ SCpnt->bufflen = 0;
+ SCpnt->request_buffer = NULL;
+ SCpnt->request_bufflen = 0;
+}
+
+/*
* Function: scsi_io_completion()
*
* Purpose: Completion processing for block device I/O requests.
@@ -471,14 +557,23 @@
* If multiple sectors are requested in one buffer, then
* they will have been finished off by the first command.
* If not, then we have a multi-buffer command.
- */
- SCpnt = scsi_end_request(SCpnt, 1, good_sectors);
+ *
+ * If block_sectors != 0, it means we had a medium error
+ * of some sort, and that we want to mark some number of
+ * sectors as not uptodate. Thus we want to inhibit
+ * requeueing right here - we will requeue down below
+ * when we handle the bad sectors.
+ */
+ SCpnt = __scsi_end_request(SCpnt,
+ 1,
+ good_sectors,
+ result == 0);
/*
* If the command completed without error, then either finish off the
* rest of the command, or start a new one.
*/
- if (result == 0) {
+ if (result == 0 || SCpnt == NULL ) {
return;
}
}
@@ -561,7 +656,11 @@
}
} /* driver byte != 0 */
if (result) {
- printk("SCSI disk error : host %d channel %d id %d lun %d return code = %x\n",
+ struct Scsi_Device_Template *STpnt;
+
+ STpnt = scsi_get_request_dev(&SCpnt->request);
+ printk("SCSI %s error : host %d channel %d id %d lun %d return code = %x\n",
+ (STpnt ? STpnt->name : "device"),
SCpnt->device->host->host_no,
SCpnt->device->channel,
SCpnt->device->id,
@@ -569,6 +668,11 @@
if (driver_byte(result) & DRIVER_SENSE)
print_sense("sd", SCpnt);
+ /*
+ * Mark a single buffer as not uptodate. Queue the remainder.
+ * We sometimes get this cruft in the event that a medium error
+ * isn't properly reported.
+ */
SCpnt = scsi_end_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
return;
}
@@ -702,6 +806,31 @@
} else {
SDpnt->starved = 0;
}
+
+ /*
+ * FIXME(eric)
+ * I am not sure where the best place to do this is. We need
+ * to hook in a place where we are likely to come if in user
+ * space. Technically the error handling thread should be
+ * doing this crap, but the error handler isn't used by
+ * most hosts.
+ */
+ if (SDpnt->was_reset) {
+ /*
+ * We need to relock the door, but we might
+ * be in an interrupt handler. Only do this
+ * from user space, since we do not want to
+ * sleep from an interrupt.
+ */
+ SDpnt->was_reset = 0;
+ if (SDpnt->removable && !in_interrupt()) {
+ spin_unlock_irq(&io_request_lock);
+ scsi_ioctl(SDpnt, SCSI_IOCTL_DOORLOCK, 0);
+ spin_lock_irq(&io_request_lock);
+ continue;
+ }
+ }
+
/*
* Loop through all of the requests in this queue, and find
* one that is queueable.
@@ -768,30 +897,6 @@
SDpnt->device_busy++;
/*
- * FIXME(eric)
- * I am not sure where the best place to do this is. We need
- * to hook in a place where we are likely to come if in user
- * space. Technically the error handling thread should be
- * doing this crap, but the error handler isn't used by
- * most hosts.
- */
- if (SDpnt->was_reset) {
- /*
- * We need to relock the door, but we might
- * be in an interrupt handler. Only do this
- * from user space, since we do not want to
- * sleep from an interrupt.
- */
- if (SDpnt->removable && !in_interrupt()) {
- spin_unlock_irq(&io_request_lock);
- scsi_ioctl(SDpnt, SCSI_IOCTL_DOORLOCK, 0);
- SDpnt->was_reset = 0;
- spin_lock_irq(&io_request_lock);
- continue;
- }
- SDpnt->was_reset = 0;
- }
- /*
* Finally, before we release the lock, we copy the
* request to the command block, and remove the
* request from the request list. Note that we always
@@ -842,6 +947,10 @@
* get those allocated here.
*/
if (!SDpnt->scsi_init_io_fn(SCpnt)) {
+ SHpnt->host_busy--;
+ SDpnt->device_busy--;
+ scsi_end_request(SCpnt, 0,
+ SCpnt->request.nr_sectors);
spin_lock_irq(&io_request_lock);
continue;
}
@@ -849,6 +958,11 @@
* Initialize the actual SCSI command for this request.
*/
if (!STpnt->init_command(SCpnt)) {
+ SHpnt->host_busy--;
+ SDpnt->device_busy--;
+ scsi_release_buffers(SCpnt);
+ scsi_end_request(SCpnt, 0,
+ SCpnt->request.nr_sectors);
spin_lock_irq(&io_request_lock);
continue;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)