diff options
author | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2007-03-02 19:55:54 -0500 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-03-11 12:39:27 -0400 |
commit | bc7e380a6a4c94f79a49c36bdb28062a750b3c2b (patch) | |
tree | c5ae13015fd0f7f15e9dbf16f865a11d0c495f3b /drivers/scsi/scsi_tgt_lib.c | |
parent | 181011e04a2a32f8d5df212254239ac9a3c8ab5e (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>
Diffstat (limited to 'drivers/scsi/scsi_tgt_lib.c')
-rw-r--r-- | drivers/scsi/scsi_tgt_lib.c | 120 |
1 files changed, 23 insertions, 97 deletions
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 | ||
336 | static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd) | 337 | static 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 | ||
353 | static 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 | |||
369 | static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask) | 353 | static 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 */ |
396 | static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd, | 378 | static 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 | ||
433 | static int scsi_tgt_transfer_data(struct scsi_cmnd *); | ||
434 | |||
435 | static 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 | |||
457 | static 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 | |||
472 | static int scsi_tgt_copy_sense(struct scsi_cmnd *cmd, unsigned long uaddr, | 413 | static 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 | ||
521 | int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len, | 462 | int 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 | |||
597 | done: | 523 | done: |
598 | scsi_host_put(shost); | 524 | scsi_host_put(shost); |
599 | return err; | 525 | return err; |