aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2007-03-02 19:55:54 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-03-11 12:39:27 -0400
commitbc7e380a6a4c94f79a49c36bdb28062a750b3c2b (patch)
treec5ae13015fd0f7f15e9dbf16f865a11d0c495f3b
parent181011e04a2a32f8d5df212254239ac9a3c8ab5e (diff)
[SCSI] tgt: fix sesnse buffer problems
This patch simplify the way to notify LLDs of the command completion and addresses the following sense buffer problems: - can't handle both data and sense. - forces user-space to use aligned sense buffer tgt copies sense_data from userspace to cmnd->sense_buffer (if necessary), maps user-space pages (if necessary) and then calls host->transfer_response (host->transfer_data is removed). Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/scsi/ibmvscsi/ibmvstgt.c21
-rw-r--r--drivers/scsi/scsi_tgt_if.c6
-rw-r--r--drivers/scsi/scsi_tgt_lib.c120
-rw-r--r--drivers/scsi/scsi_tgt_priv.h5
-rw-r--r--include/scsi/scsi_host.h19
-rw-r--r--include/scsi/scsi_tgt_if.h6
6 files changed, 44 insertions, 133 deletions
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
index 4368ca0e8270..a7fbd10817a0 100644
--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -273,23 +273,9 @@ static int ibmvstgt_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
273 rest -= mlen; 273 rest -= mlen;
274 } 274 }
275out: 275out:
276
277 return 0; 276 return 0;
278} 277}
279 278
280static int ibmvstgt_transfer_data(struct scsi_cmnd *sc,
281 void (*done)(struct scsi_cmnd *))
282{
283 struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
284 int err;
285
286 err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
287
288 done(sc);
289
290 return err;
291}
292
293static int ibmvstgt_cmd_done(struct scsi_cmnd *sc, 279static int ibmvstgt_cmd_done(struct scsi_cmnd *sc,
294 void (*done)(struct scsi_cmnd *)) 280 void (*done)(struct scsi_cmnd *))
295{ 281{
@@ -297,7 +283,11 @@ static int ibmvstgt_cmd_done(struct scsi_cmnd *sc,
297 struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr; 283 struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
298 struct srp_target *target = iue->target; 284 struct srp_target *target = iue->target;
299 285
300 dprintk("%p %p %x\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0]); 286 dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0],
287 cmd->usg_sg);
288
289 if (sc->use_sg)
290 srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
301 291
302 spin_lock_irqsave(&target->lock, flags); 292 spin_lock_irqsave(&target->lock, flags);
303 list_del(&iue->ilist); 293 list_del(&iue->ilist);
@@ -794,7 +784,6 @@ static struct scsi_host_template ibmvstgt_sht = {
794 .use_clustering = DISABLE_CLUSTERING, 784 .use_clustering = DISABLE_CLUSTERING,
795 .max_sectors = DEFAULT_MAX_SECTORS, 785 .max_sectors = DEFAULT_MAX_SECTORS,
796 .transfer_response = ibmvstgt_cmd_done, 786 .transfer_response = ibmvstgt_cmd_done,
797 .transfer_data = ibmvstgt_transfer_data,
798 .eh_abort_handler = ibmvstgt_eh_abort_handler, 787 .eh_abort_handler = ibmvstgt_eh_abort_handler,
799 .tsk_mgmt_response = ibmvstgt_tsk_mgmt_response, 788 .tsk_mgmt_response = ibmvstgt_tsk_mgmt_response,
800 .shost_attrs = ibmvstgt_attrs, 789 .shost_attrs = ibmvstgt_attrs,
diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c
index 0e08817fdecf..ca22ddf81746 100644
--- a/drivers/scsi/scsi_tgt_if.c
+++ b/drivers/scsi/scsi_tgt_if.c
@@ -179,10 +179,12 @@ static int event_recv_msg(struct tgt_event *ev)
179 switch (ev->hdr.type) { 179 switch (ev->hdr.type) {
180 case TGT_UEVENT_CMD_RSP: 180 case TGT_UEVENT_CMD_RSP:
181 err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no, 181 err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no,
182 ev->p.cmd_rsp.tag,
183 ev->p.cmd_rsp.result, 182 ev->p.cmd_rsp.result,
184 ev->p.cmd_rsp.len, 183 ev->p.cmd_rsp.tag,
185 ev->p.cmd_rsp.uaddr, 184 ev->p.cmd_rsp.uaddr,
185 ev->p.cmd_rsp.len,
186 ev->p.cmd_rsp.sense_uaddr,
187 ev->p.cmd_rsp.sense_len,
186 ev->p.cmd_rsp.rw); 188 ev->p.cmd_rsp.rw);
187 break; 189 break;
188 case TGT_UEVENT_TSK_MGMT_RSP: 190 case TGT_UEVENT_TSK_MGMT_RSP:
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 47c29a98c922..dc8781a68d7c 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -47,9 +47,6 @@ struct scsi_tgt_cmd {
47 struct list_head hash_list; 47 struct list_head hash_list;
48 struct request *rq; 48 struct request *rq;
49 u64 tag; 49 u64 tag;
50
51 void *buffer;
52 unsigned bufflen;
53}; 50};
54 51
55#define TGT_HASH_ORDER 4 52#define TGT_HASH_ORDER 4
@@ -330,10 +327,14 @@ static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd)
330 dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request)); 327 dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
331 328
332 scsi_tgt_uspace_send_status(cmd, tcmd->tag); 329 scsi_tgt_uspace_send_status(cmd, tcmd->tag);
330
331 if (cmd->request_buffer)
332 scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
333
333 queue_work(scsi_tgtd, &tcmd->work); 334 queue_work(scsi_tgtd, &tcmd->work);
334} 335}
335 336
336static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd) 337static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
337{ 338{
338 struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); 339 struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
339 int err; 340 int err;
@@ -346,30 +347,12 @@ static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
346 case SCSI_MLQUEUE_DEVICE_BUSY: 347 case SCSI_MLQUEUE_DEVICE_BUSY:
347 return -EAGAIN; 348 return -EAGAIN;
348 } 349 }
349
350 return 0; 350 return 0;
351} 351}
352 352
353static void scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
354{
355 struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
356 int err;
357
358 err = __scsi_tgt_transfer_response(cmd);
359 if (!err)
360 return;
361
362 cmd->result = DID_BUS_BUSY << 16;
363 err = scsi_tgt_uspace_send_status(cmd, tcmd->tag);
364 if (err <= 0)
365 /* the eh will have to pick this up */
366 printk(KERN_ERR "Could not send cmd %p status\n", cmd);
367}
368
369static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask) 353static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask)
370{ 354{
371 struct request *rq = cmd->request; 355 struct request *rq = cmd->request;
372 struct scsi_tgt_cmd *tcmd = rq->end_io_data;
373 int count; 356 int count;
374 357
375 cmd->use_sg = rq->nr_phys_segments; 358 cmd->use_sg = rq->nr_phys_segments;
@@ -379,31 +362,28 @@ static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask)
379 362
380 cmd->request_bufflen = rq->data_len; 363 cmd->request_bufflen = rq->data_len;
381 364
382 dprintk("cmd %p addr %p cnt %d %lu\n", cmd, tcmd->buffer, cmd->use_sg, 365 dprintk("cmd %p cnt %d %lu\n", cmd, cmd->use_sg, rq_data_dir(rq));
383 rq_data_dir(rq));
384 count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer); 366 count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer);
385 if (likely(count <= cmd->use_sg)) { 367 if (likely(count <= cmd->use_sg)) {
386 cmd->use_sg = count; 368 cmd->use_sg = count;
387 return 0; 369 return 0;
388 } 370 }
389 371
390 eprintk("cmd %p addr %p cnt %d\n", cmd, tcmd->buffer, cmd->use_sg); 372 eprintk("cmd %p cnt %d\n", cmd, cmd->use_sg);
391 scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); 373 scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
392 return -EINVAL; 374 return -EINVAL;
393} 375}
394 376
395/* TODO: test this crap and replace bio_map_user with new interface maybe */ 377/* TODO: test this crap and replace bio_map_user with new interface maybe */
396static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd, 378static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd,
397 int rw) 379 unsigned long uaddr, unsigned int len, int rw)
398{ 380{
399 struct request_queue *q = cmd->request->q; 381 struct request_queue *q = cmd->request->q;
400 struct request *rq = cmd->request; 382 struct request *rq = cmd->request;
401 void *uaddr = tcmd->buffer;
402 unsigned int len = tcmd->bufflen;
403 int err; 383 int err;
404 384
405 dprintk("%lx %u\n", (unsigned long) uaddr, len); 385 dprintk("%lx %u\n", uaddr, len);
406 err = blk_rq_map_user(q, rq, uaddr, len); 386 err = blk_rq_map_user(q, rq, (void *)uaddr, len);
407 if (err) { 387 if (err) {
408 /* 388 /*
409 * TODO: need to fixup sg_tablesize, max_segment_size, 389 * TODO: need to fixup sg_tablesize, max_segment_size,
@@ -430,45 +410,6 @@ unmap_rq:
430 return err; 410 return err;
431} 411}
432 412
433static int scsi_tgt_transfer_data(struct scsi_cmnd *);
434
435static void scsi_tgt_data_transfer_done(struct scsi_cmnd *cmd)
436{
437 struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
438 int err;
439
440 /* should we free resources here on error ? */
441 if (cmd->result) {
442 err = scsi_tgt_uspace_send_status(cmd, tcmd->tag);
443 if (err <= 0)
444 /* the tgt uspace eh will have to pick this up */
445 printk(KERN_ERR "Could not send cmd %p status\n", cmd);
446 return;
447 }
448
449 dprintk("cmd %p request_bufflen %u bufflen %u\n",
450 cmd, cmd->request_bufflen, tcmd->bufflen);
451
452 scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
453 tcmd->buffer += cmd->request_bufflen;
454 scsi_tgt_transfer_response(cmd);
455}
456
457static int scsi_tgt_transfer_data(struct scsi_cmnd *cmd)
458{
459 int err;
460 struct Scsi_Host *host = scsi_tgt_cmd_to_host(cmd);
461
462 err = host->hostt->transfer_data(cmd, scsi_tgt_data_transfer_done);
463 switch (err) {
464 case SCSI_MLQUEUE_HOST_BUSY:
465 case SCSI_MLQUEUE_DEVICE_BUSY:
466 return -EAGAIN;
467 default:
468 return 0;
469 }
470}
471
472static int scsi_tgt_copy_sense(struct scsi_cmnd *cmd, unsigned long uaddr, 413static int scsi_tgt_copy_sense(struct scsi_cmnd *cmd, unsigned long uaddr,
473 unsigned len) 414 unsigned len)
474{ 415{
@@ -518,8 +459,9 @@ static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u64 tag)
518 return rq; 459 return rq;
519} 460}
520 461
521int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len, 462int scsi_tgt_kspace_exec(int host_no, int result, u64 tag,
522 unsigned long uaddr, u8 rw) 463 unsigned long uaddr, u32 len, unsigned long sense_uaddr,
464 u32 sense_len, u8 rw)
523{ 465{
524 struct Scsi_Host *shost; 466 struct Scsi_Host *shost;
525 struct scsi_cmnd *cmd; 467 struct scsi_cmnd *cmd;
@@ -564,36 +506,20 @@ int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len,
564 * in the request_* values 506 * in the request_* values
565 */ 507 */
566 tcmd = cmd->request->end_io_data; 508 tcmd = cmd->request->end_io_data;
567 tcmd->buffer = (void *)uaddr;
568 tcmd->bufflen = len;
569 cmd->result = result; 509 cmd->result = result;
570 510
571 if (!tcmd->bufflen || cmd->request_buffer) { 511 if (cmd->result == SAM_STAT_CHECK_CONDITION)
572 err = __scsi_tgt_transfer_response(cmd); 512 scsi_tgt_copy_sense(cmd, sense_uaddr, sense_len);
573 goto done;
574 }
575
576 /*
577 * TODO: Do we need to handle case where request does not
578 * align with LLD.
579 */
580 err = scsi_map_user_pages(rq->end_io_data, cmd, rw);
581 if (err) {
582 eprintk("%p %d\n", cmd, err);
583 err = -EAGAIN;
584 goto done;
585 }
586 513
587 /* userspace failure */ 514 if (len) {
588 if (cmd->result) { 515 err = scsi_map_user_pages(rq->end_io_data, cmd, uaddr, len, rw);
589 if (status_byte(cmd->result) == CHECK_CONDITION) 516 if (err) {
590 scsi_tgt_copy_sense(cmd, uaddr, len); 517 eprintk("%p %d\n", cmd, err);
591 err = __scsi_tgt_transfer_response(cmd); 518 err = -EAGAIN;
592 goto done; 519 goto done;
520 }
593 } 521 }
594 /* ask the target LLD to transfer the data to the buffer */ 522 err = scsi_tgt_transfer_response(cmd);
595 err = scsi_tgt_transfer_data(cmd);
596
597done: 523done:
598 scsi_host_put(shost); 524 scsi_host_put(shost);
599 return err; 525 return err;
diff --git a/drivers/scsi/scsi_tgt_priv.h b/drivers/scsi/scsi_tgt_priv.h
index 84488c51ff62..e9e6db1c417f 100644
--- a/drivers/scsi/scsi_tgt_priv.h
+++ b/drivers/scsi/scsi_tgt_priv.h
@@ -18,8 +18,9 @@ extern int scsi_tgt_if_init(void);
18extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, 18extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun,
19 u64 tag); 19 u64 tag);
20extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag); 20extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag);
21extern int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len, 21extern int scsi_tgt_kspace_exec(int host_no, int result, u64 tag,
22 unsigned long uaddr, u8 rw); 22 unsigned long uaddr, u32 len, unsigned long sense_uaddr,
23 u32 sense_len, u8 rw);
23extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag, 24extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
24 struct scsi_lun *scsilun, void *data); 25 struct scsi_lun *scsilun, void *data);
25extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result); 26extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result);
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 7f1f411d07af..965b6b8ffec5 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -129,6 +129,11 @@ struct scsi_host_template {
129 * the LLD. When the driver is finished processing the command 129 * the LLD. When the driver is finished processing the command
130 * the done callback is invoked. 130 * the done callback is invoked.
131 * 131 *
132 * This is called to inform the LLD to transfer
133 * cmd->request_bufflen bytes. The cmd->use_sg speciefies the
134 * number of scatterlist entried in the command and
135 * cmd->request_buffer contains the scatterlist.
136 *
132 * return values: see queuecommand 137 * return values: see queuecommand
133 * 138 *
134 * If the LLD accepts the cmd, it should set the result to an 139 * If the LLD accepts the cmd, it should set the result to an
@@ -139,20 +144,6 @@ struct scsi_host_template {
139 /* TODO: rename */ 144 /* TODO: rename */
140 int (* transfer_response)(struct scsi_cmnd *, 145 int (* transfer_response)(struct scsi_cmnd *,
141 void (*done)(struct scsi_cmnd *)); 146 void (*done)(struct scsi_cmnd *));
142 /*
143 * This is called to inform the LLD to transfer cmd->request_bufflen
144 * bytes of the cmd at cmd->offset in the cmd. The cmd->use_sg
145 * speciefies the number of scatterlist entried in the command
146 * and cmd->request_buffer contains the scatterlist.
147 *
148 * If the command cannot be processed in one transfer_data call
149 * becuase a scatterlist within the LLD's limits cannot be
150 * created then transfer_data will be called multiple times.
151 * It is initially called from process context, and later
152 * calls are from the interrup context.
153 */
154 int (* transfer_data)(struct scsi_cmnd *,
155 void (*done)(struct scsi_cmnd *));
156 147
157 /* Used as callback for the completion of task management request. */ 148 /* Used as callback for the completion of task management request. */
158 int (* tsk_mgmt_response)(u64 mid, int result); 149 int (* tsk_mgmt_response)(u64 mid, int result);
diff --git a/include/scsi/scsi_tgt_if.h b/include/scsi/scsi_tgt_if.h
index 07d6e77ae895..4cf9dff29a2f 100644
--- a/include/scsi/scsi_tgt_if.h
+++ b/include/scsi/scsi_tgt_if.h
@@ -45,11 +45,13 @@ struct tgt_event {
45 /* user-> kernel */ 45 /* user-> kernel */
46 struct { 46 struct {
47 int host_no; 47 int host_no;
48 uint32_t len;
49 int result; 48 int result;
49 aligned_u64 tag;
50 aligned_u64 uaddr; 50 aligned_u64 uaddr;
51 aligned_u64 sense_uaddr;
52 uint32_t len;
53 uint32_t sense_len;
51 uint8_t rw; 54 uint8_t rw;
52 aligned_u64 tag;
53 } cmd_rsp; 55 } cmd_rsp;
54 struct { 56 struct {
55 int host_no; 57 int host_no;