[SCSI] use scatter lists for all block pc requests and simplify hw handlers

2005-09-07 Thread Linux Kernel Mailing List
tree 5c3a30bec263cb62538f08834db5e1cfec64c265
parent 31151ba2cef171344beac254e65bd7e00138bb0d
author James Bottomley [EMAIL PROTECTED] Sun, 05 Jun 2005 12:07:14 -0500
committer James Bottomley [EMAIL PROTECTED](none) Sun, 28 Aug 2005 20:45:34 
-0500

[SCSI] use scatter lists for all block pc requests and simplify hw handlers

Here's the proof of concept for this one.  It converts scsi_wait_req to
do correct REQ_BLOCK_PC submission (and works nicely in my setup).

The final goal should be to eliminate struct scsi_request, but that
can't be done until the character submission paths of sg and st are also
modified.

There's some loss of functionality to this: retries are no longer
controllable (except by setting REQ_FASTFAIL) and the wait_req API needs
to be altered, but it looks very nice.

Signed-off-by: James Bottomley [EMAIL PROTECTED]

 drivers/scsi/scsi_lib.c |   96 +---
 1 files changed, 59 insertions(+), 37 deletions(-)

diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -232,23 +232,6 @@ void scsi_do_req(struct scsi_request *sr
 }
 EXPORT_SYMBOL(scsi_do_req);
 
-static void scsi_wait_done(struct scsi_cmnd *cmd)
-{
-   struct request *req = cmd-request;
-   struct request_queue *q = cmd-device-request_queue;
-   unsigned long flags;
-
-   req-rq_status = RQ_SCSI_DONE;  /* Busy, but indicate request done */
-
-   spin_lock_irqsave(q-queue_lock, flags);
-   if (blk_rq_tagged(req))
-   blk_queue_end_tag(q, req);
-   spin_unlock_irqrestore(q-queue_lock, flags);
-
-   if (req-waiting)
-   complete(req-waiting);
-}
-
 /* This is the end routine we get to if a command was never attached
  * to the request.  Simply complete the request without changing
  * rq_status; this will cause a DRIVER_ERROR. */
@@ -263,19 +246,36 @@ void scsi_wait_req(struct scsi_request *
   unsigned bufflen, int timeout, int retries)
 {
DECLARE_COMPLETION(wait);
-   
-   sreq-sr_request-waiting = wait;
-   sreq-sr_request-rq_status = RQ_SCSI_BUSY;
-   sreq-sr_request-end_io = scsi_wait_req_end_io;
-   scsi_do_req(sreq, cmnd, buffer, bufflen, scsi_wait_done,
-   timeout, retries);
+   struct request *req;
+
+   if (bufflen)
+   req = blk_rq_map_kern(sreq-sr_device-request_queue,
+ sreq-sr_data_direction == DMA_TO_DEVICE,
+ buffer, bufflen, __GFP_WAIT);
+   else
+   req = blk_get_request(sreq-sr_device-request_queue, READ,
+ __GFP_WAIT);
+   req-flags |= REQ_NOMERGE;
+   req-waiting = wait;
+   req-end_io = scsi_wait_req_end_io;
+   req-cmd_len = COMMAND_SIZE(((u8 *)cmnd)[0]);
+   req-sense = sreq-sr_sense_buffer;
+   req-sense_len = 0;
+   memcpy(req-cmd, cmnd, req-cmd_len);
+   req-timeout = timeout;
+   req-flags |= REQ_BLOCK_PC;
+   req-rq_disk = NULL;
+   blk_insert_request(sreq-sr_device-request_queue, req,
+  sreq-sr_data_direction == DMA_TO_DEVICE, NULL);
wait_for_completion(wait);
sreq-sr_request-waiting = NULL;
-   if (sreq-sr_request-rq_status != RQ_SCSI_DONE)
+   sreq-sr_result = req-errors;
+   if (req-errors)
sreq-sr_result |= (DRIVER_ERROR  24);
 
-   __scsi_release_request(sreq);
+   blk_put_request(req);
 }
+
 EXPORT_SYMBOL(scsi_wait_req);
 
 /*
@@ -878,11 +878,12 @@ void scsi_io_completion(struct scsi_cmnd
return;
}
if (result) {
-   printk(KERN_INFO SCSI error : %d %d %d %d return code 
-  = 0x%x\n, cmd-device-host-host_no,
-  cmd-device-channel,
-  cmd-device-id,
-  cmd-device-lun, result);
+   if (!(req-flags  REQ_SPECIAL))
+   printk(KERN_INFO SCSI error : %d %d %d %d return 
code 
+  = 0x%x\n, cmd-device-host-host_no,
+  cmd-device-channel,
+  cmd-device-id,
+  cmd-device-lun, result);
 
if (driver_byte(result)  DRIVER_SENSE)
scsi_print_sense(, cmd);
@@ -1020,6 +1021,12 @@ static int scsi_issue_flush_fn(request_q
return -EOPNOTSUPP;
 }
 
+static void scsi_generic_done(struct scsi_cmnd *cmd)
+{
+   BUG_ON(!blk_pc_request(cmd-request));
+   scsi_io_completion(cmd, cmd-result == 0 ? cmd-bufflen : 0, 0);
+}
+
 static int scsi_prep_fn(struct request_queue *q, struct request *req)
 {
struct scsi_device *sdev = q-queuedata;
@@ -1061,7 +1068,7 @@ static int scsi_prep_fn(struct request_q
 * these two cases differently.  We differentiate by looking
 * at request-cmd, as this tells us

[SCSI] use scatter lists for all block pc requests and simplify hw handlers

2005-09-07 Thread Linux Kernel Mailing List
tree ce664010089283f464d88cd89c11a60d35923851
parent 8e6401187ef7fb1edc2740832b48bf47ed2c90f2
author James Bottomley [EMAIL PROTECTED](none) Thu, 16 Jun 2005 04:48:29 -0500
committer James Bottomley [EMAIL PROTECTED](none) Sun, 28 Aug 2005 20:46:40 
-0500

[SCSI] use scatter lists for all block pc requests and simplify hw handlers

Original From: Mike Christie [EMAIL PROTECTED]

Add scsi_execute_req() as a replacement for scsi_wait_req()

Fixed up various pieces (added REQ_SPECIAL and caught req use after
free)

Signed-off-by: James Bottomley [EMAIL PROTECTED]
 drivers/scsi/scsi_lib.c |   51 +++-
 drivers/scsi/scsi_scan.c|  112 +++-
 include/scsi/scsi_request.h |3 +
 3 files changed, 102 insertions(+), 64 deletions(-)

diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -246,7 +246,7 @@ void scsi_wait_req(struct scsi_request *
   unsigned bufflen, int timeout, int retries)
 {
DECLARE_COMPLETION(wait);
-   int write = sreq-sr_data_direction == DMA_TO_DEVICE;
+   int write = (sreq-sr_data_direction == DMA_TO_DEVICE);
struct request *req;
 
req = blk_get_request(sreq-sr_device-request_queue, write,
@@ -281,6 +281,55 @@ void scsi_wait_req(struct scsi_request *
 
 EXPORT_SYMBOL(scsi_wait_req);
 
+/**
+ * scsi_execute_req - insert request and wait for the result
+ * @sdev:  scsi device
+ * @cmd:   scsi command
+ * @data_direction: data direction
+ * @buffer:data buffer
+ * @bufflen:   len of buffer
+ * @sense: optional sense buffer
+ * @timeout:   request timeout in seconds
+ * @retries:   number of times to retry request
+ *
+ * scsi_execute_req returns the req-errors value which is the
+ * the scsi_cmnd result field.
+ **/
+int scsi_execute_req(struct scsi_device *sdev, unsigned char *cmd,
+int data_direction, void *buffer, unsigned bufflen,
+unsigned char *sense, int timeout, int retries)
+{
+   struct request *req;
+   int write = (data_direction == DMA_TO_DEVICE);
+   int ret = DRIVER_ERROR  24;
+
+   req = blk_get_request(sdev-request_queue, write, __GFP_WAIT);
+
+   if (bufflen   blk_rq_map_kern(sdev-request_queue, req,
+   buffer, bufflen, __GFP_WAIT))
+   goto out;
+
+   req-cmd_len = COMMAND_SIZE(cmd[0]);
+   memcpy(req-cmd, cmd, req-cmd_len);
+   req-sense = sense;
+   req-sense_len = 0;
+   req-timeout = timeout;
+   req-flags |= REQ_BLOCK_PC | REQ_SPECIAL;
+
+   /*
+* head injection *required* here otherwise quiesce won't work
+*/
+   blk_execute_rq(req-q, NULL, req, 1);
+
+   ret = req-errors;
+ out:
+   blk_put_request(req);
+
+   return ret;
+}
+
+EXPORT_SYMBOL(scsi_execute_req);
+
 /*
  * Function:scsi_init_cmd_errh()
  *
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -111,15 +111,14 @@ MODULE_PARM_DESC(inq_timeout, 
 
 /**
  * scsi_unlock_floptical - unlock device via a special MODE SENSE command
- * @sreq:  used to send the command
+ * @sdev:  scsi device to send command to
  * @result:area to store the result of the MODE SENSE
  *
  * Description:
- * Send a vendor specific MODE SENSE (not a MODE SELECT) command using
- * @sreq to unlock a device, storing the (unused) results into result.
+ * Send a vendor specific MODE SENSE (not a MODE SELECT) command.
  * Called for BLIST_KEY devices.
  **/
-static void scsi_unlock_floptical(struct scsi_request *sreq,
+static void scsi_unlock_floptical(struct scsi_device *sdev,
  unsigned char *result)
 {
unsigned char scsi_cmd[MAX_COMMAND_SIZE];
@@ -129,11 +128,10 @@ static void scsi_unlock_floptical(struct
scsi_cmd[1] = 0;
scsi_cmd[2] = 0x2e;
scsi_cmd[3] = 0;
-   scsi_cmd[4] = 0x2a; /* size */
+   scsi_cmd[4] = 0x2a; /* size */
scsi_cmd[5] = 0;
-   sreq-sr_cmd_len = 0;
-   sreq-sr_data_direction = DMA_FROM_DEVICE;
-   scsi_wait_req(sreq, scsi_cmd, result, 0x2a /* size */, SCSI_TIMEOUT, 3);
+   scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, result, 0x2a, NULL,
+SCSI_TIMEOUT, 3);
 }
 
 /**
@@ -433,26 +431,26 @@ void scsi_target_reap(struct scsi_target
 
 /**
  * scsi_probe_lun - probe a single LUN using a SCSI INQUIRY
- * @sreq:  used to send the INQUIRY
+ * @sdev:  scsi_device to probe
  * @inq_result:area to store the INQUIRY result
+ * @result_len: len of inq_result
  * @bflags:store any bflags found here
  *
  * Description:
- * Probe the lun associated with @sreq using a standard SCSI INQUIRY;
+ * Probe the lun associated with @req using a standard SCSI INQUIRY;
  *
- * If the INQUIRY is successful, sreq