diff options
author | James Bottomley <James.Bottomley@steeleye.com> | 2005-06-05 03:07:14 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2005-08-28 11:45:34 -0400 |
commit | e537a36d528053f6b9dbe6c88e763e835c0d3517 (patch) | |
tree | 5c3a30bec263cb62538f08834db5e1cfec64c265 /drivers/scsi/scsi_lib.c | |
parent | 31151ba2cef171344beac254e65bd7e00138bb0d (diff) |
[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 <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
-rw-r--r-- | 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 index 7a91ca3d32a6..253c1a98d159 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
@@ -232,23 +232,6 @@ void scsi_do_req(struct scsi_request *sreq, const void *cmnd, | |||
232 | } | 232 | } |
233 | EXPORT_SYMBOL(scsi_do_req); | 233 | EXPORT_SYMBOL(scsi_do_req); |
234 | 234 | ||
235 | static void scsi_wait_done(struct scsi_cmnd *cmd) | ||
236 | { | ||
237 | struct request *req = cmd->request; | ||
238 | struct request_queue *q = cmd->device->request_queue; | ||
239 | unsigned long flags; | ||
240 | |||
241 | req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ | ||
242 | |||
243 | spin_lock_irqsave(q->queue_lock, flags); | ||
244 | if (blk_rq_tagged(req)) | ||
245 | blk_queue_end_tag(q, req); | ||
246 | spin_unlock_irqrestore(q->queue_lock, flags); | ||
247 | |||
248 | if (req->waiting) | ||
249 | complete(req->waiting); | ||
250 | } | ||
251 | |||
252 | /* This is the end routine we get to if a command was never attached | 235 | /* This is the end routine we get to if a command was never attached |
253 | * to the request. Simply complete the request without changing | 236 | * to the request. Simply complete the request without changing |
254 | * rq_status; this will cause a DRIVER_ERROR. */ | 237 | * rq_status; this will cause a DRIVER_ERROR. */ |
@@ -263,19 +246,36 @@ void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer, | |||
263 | unsigned bufflen, int timeout, int retries) | 246 | unsigned bufflen, int timeout, int retries) |
264 | { | 247 | { |
265 | DECLARE_COMPLETION(wait); | 248 | DECLARE_COMPLETION(wait); |
266 | 249 | struct request *req; | |
267 | sreq->sr_request->waiting = &wait; | 250 | |
268 | sreq->sr_request->rq_status = RQ_SCSI_BUSY; | 251 | if (bufflen) |
269 | sreq->sr_request->end_io = scsi_wait_req_end_io; | 252 | req = blk_rq_map_kern(sreq->sr_device->request_queue, |
270 | scsi_do_req(sreq, cmnd, buffer, bufflen, scsi_wait_done, | 253 | sreq->sr_data_direction == DMA_TO_DEVICE, |
271 | timeout, retries); | 254 | buffer, bufflen, __GFP_WAIT); |
255 | else | ||
256 | req = blk_get_request(sreq->sr_device->request_queue, READ, | ||
257 | __GFP_WAIT); | ||
258 | req->flags |= REQ_NOMERGE; | ||
259 | req->waiting = &wait; | ||
260 | req->end_io = scsi_wait_req_end_io; | ||
261 | req->cmd_len = COMMAND_SIZE(((u8 *)cmnd)[0]); | ||
262 | req->sense = sreq->sr_sense_buffer; | ||
263 | req->sense_len = 0; | ||
264 | memcpy(req->cmd, cmnd, req->cmd_len); | ||
265 | req->timeout = timeout; | ||
266 | req->flags |= REQ_BLOCK_PC; | ||
267 | req->rq_disk = NULL; | ||
268 | blk_insert_request(sreq->sr_device->request_queue, req, | ||
269 | sreq->sr_data_direction == DMA_TO_DEVICE, NULL); | ||
272 | wait_for_completion(&wait); | 270 | wait_for_completion(&wait); |
273 | sreq->sr_request->waiting = NULL; | 271 | sreq->sr_request->waiting = NULL; |
274 | if (sreq->sr_request->rq_status != RQ_SCSI_DONE) | 272 | sreq->sr_result = req->errors; |
273 | if (req->errors) | ||
275 | sreq->sr_result |= (DRIVER_ERROR << 24); | 274 | sreq->sr_result |= (DRIVER_ERROR << 24); |
276 | 275 | ||
277 | __scsi_release_request(sreq); | 276 | blk_put_request(req); |
278 | } | 277 | } |
278 | |||
279 | EXPORT_SYMBOL(scsi_wait_req); | 279 | EXPORT_SYMBOL(scsi_wait_req); |
280 | 280 | ||
281 | /* | 281 | /* |
@@ -878,11 +878,12 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, | |||
878 | return; | 878 | return; |
879 | } | 879 | } |
880 | if (result) { | 880 | if (result) { |
881 | printk(KERN_INFO "SCSI error : <%d %d %d %d> return code " | 881 | if (!(req->flags & REQ_SPECIAL)) |
882 | "= 0x%x\n", cmd->device->host->host_no, | 882 | printk(KERN_INFO "SCSI error : <%d %d %d %d> return code " |
883 | cmd->device->channel, | 883 | "= 0x%x\n", cmd->device->host->host_no, |
884 | cmd->device->id, | 884 | cmd->device->channel, |
885 | cmd->device->lun, result); | 885 | cmd->device->id, |
886 | cmd->device->lun, result); | ||
886 | 887 | ||
887 | if (driver_byte(result) & DRIVER_SENSE) | 888 | if (driver_byte(result) & DRIVER_SENSE) |
888 | scsi_print_sense("", cmd); | 889 | scsi_print_sense("", cmd); |
@@ -1020,6 +1021,12 @@ static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk, | |||
1020 | return -EOPNOTSUPP; | 1021 | return -EOPNOTSUPP; |
1021 | } | 1022 | } |
1022 | 1023 | ||
1024 | static void scsi_generic_done(struct scsi_cmnd *cmd) | ||
1025 | { | ||
1026 | BUG_ON(!blk_pc_request(cmd->request)); | ||
1027 | scsi_io_completion(cmd, cmd->result == 0 ? cmd->bufflen : 0, 0); | ||
1028 | } | ||
1029 | |||
1023 | static int scsi_prep_fn(struct request_queue *q, struct request *req) | 1030 | static int scsi_prep_fn(struct request_queue *q, struct request *req) |
1024 | { | 1031 | { |
1025 | struct scsi_device *sdev = q->queuedata; | 1032 | struct scsi_device *sdev = q->queuedata; |
@@ -1061,7 +1068,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) | |||
1061 | * these two cases differently. We differentiate by looking | 1068 | * these two cases differently. We differentiate by looking |
1062 | * at request->cmd, as this tells us the real story. | 1069 | * at request->cmd, as this tells us the real story. |
1063 | */ | 1070 | */ |
1064 | if (req->flags & REQ_SPECIAL) { | 1071 | if (req->flags & REQ_SPECIAL && req->special) { |
1065 | struct scsi_request *sreq = req->special; | 1072 | struct scsi_request *sreq = req->special; |
1066 | 1073 | ||
1067 | if (sreq->sr_magic == SCSI_REQ_MAGIC) { | 1074 | if (sreq->sr_magic == SCSI_REQ_MAGIC) { |
@@ -1073,7 +1080,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) | |||
1073 | cmd = req->special; | 1080 | cmd = req->special; |
1074 | } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { | 1081 | } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { |
1075 | 1082 | ||
1076 | if(unlikely(specials_only)) { | 1083 | if(unlikely(specials_only) && !(req->flags & REQ_SPECIAL)) { |
1077 | if(specials_only == SDEV_QUIESCE || | 1084 | if(specials_only == SDEV_QUIESCE || |
1078 | specials_only == SDEV_BLOCK) | 1085 | specials_only == SDEV_BLOCK) |
1079 | return BLKPREP_DEFER; | 1086 | return BLKPREP_DEFER; |
@@ -1142,11 +1149,26 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) | |||
1142 | /* | 1149 | /* |
1143 | * Initialize the actual SCSI command for this request. | 1150 | * Initialize the actual SCSI command for this request. |
1144 | */ | 1151 | */ |
1145 | drv = *(struct scsi_driver **)req->rq_disk->private_data; | 1152 | if (req->rq_disk) { |
1146 | if (unlikely(!drv->init_command(cmd))) { | 1153 | drv = *(struct scsi_driver **)req->rq_disk->private_data; |
1147 | scsi_release_buffers(cmd); | 1154 | if (unlikely(!drv->init_command(cmd))) { |
1148 | scsi_put_command(cmd); | 1155 | scsi_release_buffers(cmd); |
1149 | return BLKPREP_KILL; | 1156 | scsi_put_command(cmd); |
1157 | return BLKPREP_KILL; | ||
1158 | } | ||
1159 | } else { | ||
1160 | memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd)); | ||
1161 | if (rq_data_dir(req) == WRITE) | ||
1162 | cmd->sc_data_direction = DMA_TO_DEVICE; | ||
1163 | else if (req->data_len) | ||
1164 | cmd->sc_data_direction = DMA_FROM_DEVICE; | ||
1165 | else | ||
1166 | cmd->sc_data_direction = DMA_NONE; | ||
1167 | |||
1168 | cmd->transfersize = req->data_len; | ||
1169 | cmd->allowed = 3; | ||
1170 | cmd->timeout_per_command = req->timeout; | ||
1171 | cmd->done = scsi_generic_done; | ||
1150 | } | 1172 | } |
1151 | } | 1173 | } |
1152 | 1174 | ||