aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@steeleye.com>2005-06-05 03:07:14 -0400
committerJames Bottomley <jejb@mulgrave.(none)>2005-08-28 11:45:34 -0400
commite537a36d528053f6b9dbe6c88e763e835c0d3517 (patch)
tree5c3a30bec263cb62538f08834db5e1cfec64c265
parent31151ba2cef171344beac254e65bd7e00138bb0d (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>
-rw-r--r--drivers/scsi/scsi_lib.c96
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}
233EXPORT_SYMBOL(scsi_do_req); 233EXPORT_SYMBOL(scsi_do_req);
234 234
235static 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
279EXPORT_SYMBOL(scsi_wait_req); 279EXPORT_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
1024static 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
1023static int scsi_prep_fn(struct request_queue *q, struct request *req) 1030static 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