[SCSI] use scatter lists for all block pc requests and simplify hw handlers
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
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