diff options
-rw-r--r-- | drivers/scsi/scsi_tgt_lib.c | 133 | ||||
-rw-r--r-- | include/scsi/scsi_cmnd.h | 3 |
2 files changed, 34 insertions, 102 deletions
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c index d402aff5f314..47c29a98c922 100644 --- a/drivers/scsi/scsi_tgt_lib.c +++ b/drivers/scsi/scsi_tgt_lib.c | |||
@@ -28,7 +28,6 @@ | |||
28 | #include <scsi/scsi_device.h> | 28 | #include <scsi/scsi_device.h> |
29 | #include <scsi/scsi_host.h> | 29 | #include <scsi/scsi_host.h> |
30 | #include <scsi/scsi_tgt.h> | 30 | #include <scsi/scsi_tgt.h> |
31 | #include <../drivers/md/dm-bio-list.h> | ||
32 | 31 | ||
33 | #include "scsi_tgt_priv.h" | 32 | #include "scsi_tgt_priv.h" |
34 | 33 | ||
@@ -42,9 +41,8 @@ static struct kmem_cache *scsi_tgt_cmd_cache; | |||
42 | struct scsi_tgt_cmd { | 41 | struct scsi_tgt_cmd { |
43 | /* TODO replace work with James b's code */ | 42 | /* TODO replace work with James b's code */ |
44 | struct work_struct work; | 43 | struct work_struct work; |
45 | /* TODO replace the lists with a large bio */ | 44 | /* TODO fix limits of some drivers */ |
46 | struct bio_list xfer_done_list; | 45 | struct bio *bio; |
47 | struct bio_list xfer_list; | ||
48 | 46 | ||
49 | struct list_head hash_list; | 47 | struct list_head hash_list; |
50 | struct request *rq; | 48 | struct request *rq; |
@@ -93,7 +91,12 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost, | |||
93 | if (!tcmd) | 91 | if (!tcmd) |
94 | goto put_dev; | 92 | goto put_dev; |
95 | 93 | ||
96 | rq = blk_get_request(shost->uspace_req_q, write, gfp_mask); | 94 | /* |
95 | * The blk helpers are used to the READ/WRITE requests | ||
96 | * transfering data from a initiator point of view. Since | ||
97 | * we are in target mode we want the opposite. | ||
98 | */ | ||
99 | rq = blk_get_request(shost->uspace_req_q, !write, gfp_mask); | ||
97 | if (!rq) | 100 | if (!rq) |
98 | goto free_tcmd; | 101 | goto free_tcmd; |
99 | 102 | ||
@@ -111,8 +114,6 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost, | |||
111 | rq->cmd_flags |= REQ_TYPE_BLOCK_PC; | 114 | rq->cmd_flags |= REQ_TYPE_BLOCK_PC; |
112 | rq->end_io_data = tcmd; | 115 | rq->end_io_data = tcmd; |
113 | 116 | ||
114 | bio_list_init(&tcmd->xfer_list); | ||
115 | bio_list_init(&tcmd->xfer_done_list); | ||
116 | tcmd->rq = rq; | 117 | tcmd->rq = rq; |
117 | 118 | ||
118 | return cmd; | 119 | return cmd; |
@@ -157,22 +158,6 @@ void scsi_host_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd) | |||
157 | } | 158 | } |
158 | EXPORT_SYMBOL_GPL(scsi_host_put_command); | 159 | EXPORT_SYMBOL_GPL(scsi_host_put_command); |
159 | 160 | ||
160 | static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd) | ||
161 | { | ||
162 | struct bio *bio; | ||
163 | |||
164 | /* must call bio_endio in case bio was bounced */ | ||
165 | while ((bio = bio_list_pop(&tcmd->xfer_done_list))) { | ||
166 | bio_endio(bio, bio->bi_size, 0); | ||
167 | bio_unmap_user(bio); | ||
168 | } | ||
169 | |||
170 | while ((bio = bio_list_pop(&tcmd->xfer_list))) { | ||
171 | bio_endio(bio, bio->bi_size, 0); | ||
172 | bio_unmap_user(bio); | ||
173 | } | ||
174 | } | ||
175 | |||
176 | static void cmd_hashlist_del(struct scsi_cmnd *cmd) | 161 | static void cmd_hashlist_del(struct scsi_cmnd *cmd) |
177 | { | 162 | { |
178 | struct request_queue *q = cmd->request->q; | 163 | struct request_queue *q = cmd->request->q; |
@@ -185,6 +170,11 @@ static void cmd_hashlist_del(struct scsi_cmnd *cmd) | |||
185 | spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); | 170 | spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); |
186 | } | 171 | } |
187 | 172 | ||
173 | static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd) | ||
174 | { | ||
175 | blk_rq_unmap_user(tcmd->bio); | ||
176 | } | ||
177 | |||
188 | static void scsi_tgt_cmd_destroy(struct work_struct *work) | 178 | static void scsi_tgt_cmd_destroy(struct work_struct *work) |
189 | { | 179 | { |
190 | struct scsi_tgt_cmd *tcmd = | 180 | struct scsi_tgt_cmd *tcmd = |
@@ -193,16 +183,6 @@ static void scsi_tgt_cmd_destroy(struct work_struct *work) | |||
193 | 183 | ||
194 | dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction, | 184 | dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction, |
195 | rq_data_dir(cmd->request)); | 185 | rq_data_dir(cmd->request)); |
196 | /* | ||
197 | * We fix rq->cmd_flags here since when we told bio_map_user | ||
198 | * to write vm for WRITE commands, blk_rq_bio_prep set | ||
199 | * rq_data_dir the flags to READ. | ||
200 | */ | ||
201 | if (cmd->sc_data_direction == DMA_TO_DEVICE) | ||
202 | cmd->request->cmd_flags |= REQ_RW; | ||
203 | else | ||
204 | cmd->request->cmd_flags &= ~REQ_RW; | ||
205 | |||
206 | scsi_unmap_user_pages(tcmd); | 186 | scsi_unmap_user_pages(tcmd); |
207 | scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd); | 187 | scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd); |
208 | } | 188 | } |
@@ -215,6 +195,7 @@ static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd, | |||
215 | struct list_head *head; | 195 | struct list_head *head; |
216 | 196 | ||
217 | tcmd->tag = tag; | 197 | tcmd->tag = tag; |
198 | tcmd->bio = NULL; | ||
218 | INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy); | 199 | INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy); |
219 | spin_lock_irqsave(&qdata->cmd_hash_lock, flags); | 200 | spin_lock_irqsave(&qdata->cmd_hash_lock, flags); |
220 | head = &qdata->cmd_hash[cmd_hashfn(tag)]; | 201 | head = &qdata->cmd_hash[cmd_hashfn(tag)]; |
@@ -419,52 +400,33 @@ static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd, | |||
419 | struct request *rq = cmd->request; | 400 | struct request *rq = cmd->request; |
420 | void *uaddr = tcmd->buffer; | 401 | void *uaddr = tcmd->buffer; |
421 | unsigned int len = tcmd->bufflen; | 402 | unsigned int len = tcmd->bufflen; |
422 | struct bio *bio; | ||
423 | int err; | 403 | int err; |
424 | 404 | ||
425 | while (len > 0) { | 405 | dprintk("%lx %u\n", (unsigned long) uaddr, len); |
426 | dprintk("%lx %u\n", (unsigned long) uaddr, len); | 406 | err = blk_rq_map_user(q, rq, uaddr, len); |
427 | bio = bio_map_user(q, NULL, (unsigned long) uaddr, len, rw); | 407 | if (err) { |
428 | if (IS_ERR(bio)) { | ||
429 | err = PTR_ERR(bio); | ||
430 | dprintk("fail to map %lx %u %d %x\n", | ||
431 | (unsigned long) uaddr, len, err, cmd->cmnd[0]); | ||
432 | goto unmap_bios; | ||
433 | } | ||
434 | |||
435 | uaddr += bio->bi_size; | ||
436 | len -= bio->bi_size; | ||
437 | |||
438 | /* | 408 | /* |
439 | * The first bio is added and merged. We could probably | 409 | * TODO: need to fixup sg_tablesize, max_segment_size, |
440 | * try to add others using scsi_merge_bio() but for now | 410 | * max_sectors, etc for modern HW and software drivers |
441 | * we keep it simple. The first bio should be pretty large | 411 | * where this value is bogus. |
442 | * (either hitting the 1 MB bio pages limit or a queue limit) | 412 | * |
443 | * already but for really large IO we may want to try and | 413 | * TODO2: we can alloc a reserve buffer of max size |
444 | * merge these. | 414 | * we can handle and do the slow copy path for really large |
415 | * IO. | ||
445 | */ | 416 | */ |
446 | if (!rq->bio) { | 417 | eprintk("Could not handle request of size %u.\n", len); |
447 | blk_rq_bio_prep(q, rq, bio); | 418 | return err; |
448 | rq->data_len = bio->bi_size; | ||
449 | } else | ||
450 | /* put list of bios to transfer in next go around */ | ||
451 | bio_list_add(&tcmd->xfer_list, bio); | ||
452 | } | 419 | } |
453 | 420 | ||
454 | cmd->offset = 0; | 421 | tcmd->bio = rq->bio; |
455 | err = scsi_tgt_init_cmd(cmd, GFP_KERNEL); | 422 | err = scsi_tgt_init_cmd(cmd, GFP_KERNEL); |
456 | if (err) | 423 | if (err) |
457 | goto unmap_bios; | 424 | goto unmap_rq; |
458 | 425 | ||
459 | return 0; | 426 | return 0; |
460 | 427 | ||
461 | unmap_bios: | 428 | unmap_rq: |
462 | if (rq->bio) { | 429 | scsi_unmap_user_pages(tcmd); |
463 | bio_unmap_user(rq->bio); | ||
464 | while ((bio = bio_list_pop(&tcmd->xfer_list))) | ||
465 | bio_unmap_user(bio); | ||
466 | } | ||
467 | |||
468 | return err; | 430 | return err; |
469 | } | 431 | } |
470 | 432 | ||
@@ -473,12 +435,10 @@ static int scsi_tgt_transfer_data(struct scsi_cmnd *); | |||
473 | static void scsi_tgt_data_transfer_done(struct scsi_cmnd *cmd) | 435 | static void scsi_tgt_data_transfer_done(struct scsi_cmnd *cmd) |
474 | { | 436 | { |
475 | struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; | 437 | struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; |
476 | struct bio *bio; | ||
477 | int err; | 438 | int err; |
478 | 439 | ||
479 | /* should we free resources here on error ? */ | 440 | /* should we free resources here on error ? */ |
480 | if (cmd->result) { | 441 | if (cmd->result) { |
481 | send_uspace_err: | ||
482 | err = scsi_tgt_uspace_send_status(cmd, tcmd->tag); | 442 | err = scsi_tgt_uspace_send_status(cmd, tcmd->tag); |
483 | if (err <= 0) | 443 | if (err <= 0) |
484 | /* the tgt uspace eh will have to pick this up */ | 444 | /* the tgt uspace eh will have to pick this up */ |
@@ -490,34 +450,8 @@ send_uspace_err: | |||
490 | cmd, cmd->request_bufflen, tcmd->bufflen); | 450 | cmd, cmd->request_bufflen, tcmd->bufflen); |
491 | 451 | ||
492 | scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); | 452 | scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); |
493 | bio_list_add(&tcmd->xfer_done_list, cmd->request->bio); | ||
494 | |||
495 | tcmd->buffer += cmd->request_bufflen; | 453 | tcmd->buffer += cmd->request_bufflen; |
496 | cmd->offset += cmd->request_bufflen; | 454 | scsi_tgt_transfer_response(cmd); |
497 | |||
498 | if (!tcmd->xfer_list.head) { | ||
499 | scsi_tgt_transfer_response(cmd); | ||
500 | return; | ||
501 | } | ||
502 | |||
503 | dprintk("cmd2 %p request_bufflen %u bufflen %u\n", | ||
504 | cmd, cmd->request_bufflen, tcmd->bufflen); | ||
505 | |||
506 | bio = bio_list_pop(&tcmd->xfer_list); | ||
507 | BUG_ON(!bio); | ||
508 | |||
509 | blk_rq_bio_prep(cmd->request->q, cmd->request, bio); | ||
510 | cmd->request->data_len = bio->bi_size; | ||
511 | err = scsi_tgt_init_cmd(cmd, GFP_ATOMIC); | ||
512 | if (err) { | ||
513 | cmd->result = DID_ERROR << 16; | ||
514 | goto send_uspace_err; | ||
515 | } | ||
516 | |||
517 | if (scsi_tgt_transfer_data(cmd)) { | ||
518 | cmd->result = DID_NO_CONNECT << 16; | ||
519 | goto send_uspace_err; | ||
520 | } | ||
521 | } | 455 | } |
522 | 456 | ||
523 | static int scsi_tgt_transfer_data(struct scsi_cmnd *cmd) | 457 | static int scsi_tgt_transfer_data(struct scsi_cmnd *cmd) |
@@ -617,8 +551,9 @@ int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len, | |||
617 | } | 551 | } |
618 | cmd = rq->special; | 552 | cmd = rq->special; |
619 | 553 | ||
620 | dprintk("cmd %p result %d len %d bufflen %u %lu %x\n", cmd, | 554 | dprintk("cmd %p scb %x result %d len %d bufflen %u %lu %x\n", |
621 | result, len, cmd->request_bufflen, rq_data_dir(rq), cmd->cmnd[0]); | 555 | cmd, cmd->cmnd[0], result, len, cmd->request_bufflen, |
556 | rq_data_dir(rq), cmd->cmnd[0]); | ||
622 | 557 | ||
623 | if (result == TASK_ABORTED) { | 558 | if (result == TASK_ABORTED) { |
624 | scsi_tgt_abort_cmd(shost, cmd); | 559 | scsi_tgt_abort_cmd(shost, cmd); |
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index d6948d0e8cdb..a2e0c1032491 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h | |||
@@ -73,9 +73,6 @@ struct scsi_cmnd { | |||
73 | unsigned short use_sg; /* Number of pieces of scatter-gather */ | 73 | unsigned short use_sg; /* Number of pieces of scatter-gather */ |
74 | unsigned short sglist_len; /* size of malloc'd scatter-gather list */ | 74 | unsigned short sglist_len; /* size of malloc'd scatter-gather list */ |
75 | 75 | ||
76 | /* offset in cmd we are at (for multi-transfer tgt cmds) */ | ||
77 | unsigned offset; | ||
78 | |||
79 | unsigned underflow; /* Return error if less than | 76 | unsigned underflow; /* Return error if less than |
80 | this amount is transferred */ | 77 | this amount is transferred */ |
81 | 78 | ||