diff options
author | Martin K. Petersen <martin.petersen@oracle.com> | 2012-09-18 12:19:31 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-11-14 00:23:53 -0500 |
commit | 26e85fcd15f68b57d9ba645cd3591117a8ac0e05 (patch) | |
tree | 5dcb12ddd18e8ced5707239cdb0da6feaf3c9c80 /drivers/scsi/sd.c | |
parent | 3c6bdaeab4fda6c9fdd5f3f5c610dea97bddf7d6 (diff) |
[SCSI] sd: Permit merged discard requests
Support requests with more than one bio payload for discards. The total
number of bytes to be discarded is stored in req->__data_len and used in
sd_done() to complete the I/O.
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r-- | drivers/scsi/sd.c | 32 |
1 files changed, 19 insertions, 13 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 12f6fdfc1147..c6af4c1a9ca3 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
@@ -583,29 +583,26 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) | |||
583 | } | 583 | } |
584 | 584 | ||
585 | /** | 585 | /** |
586 | * scsi_setup_discard_cmnd - unmap blocks on thinly provisioned device | 586 | * sd_setup_discard_cmnd - unmap blocks on thinly provisioned device |
587 | * @sdp: scsi device to operate one | 587 | * @sdp: scsi device to operate one |
588 | * @rq: Request to prepare | 588 | * @rq: Request to prepare |
589 | * | 589 | * |
590 | * Will issue either UNMAP or WRITE SAME(16) depending on preference | 590 | * Will issue either UNMAP or WRITE SAME(16) depending on preference |
591 | * indicated by target device. | 591 | * indicated by target device. |
592 | **/ | 592 | **/ |
593 | static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) | 593 | static int sd_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) |
594 | { | 594 | { |
595 | struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); | 595 | struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); |
596 | struct bio *bio = rq->bio; | 596 | sector_t sector = blk_rq_pos(rq); |
597 | sector_t sector = bio->bi_sector; | 597 | unsigned int nr_sectors = blk_rq_sectors(rq); |
598 | unsigned int nr_sectors = bio_sectors(bio); | 598 | unsigned int nr_bytes = blk_rq_bytes(rq); |
599 | unsigned int len; | 599 | unsigned int len; |
600 | int ret; | 600 | int ret; |
601 | char *buf; | 601 | char *buf; |
602 | struct page *page; | 602 | struct page *page; |
603 | 603 | ||
604 | if (sdkp->device->sector_size == 4096) { | 604 | sector >>= ilog2(sdp->sector_size) - 9; |
605 | sector >>= 3; | 605 | nr_sectors >>= ilog2(sdp->sector_size) - 9; |
606 | nr_sectors >>= 3; | ||
607 | } | ||
608 | |||
609 | rq->timeout = SD_TIMEOUT; | 606 | rq->timeout = SD_TIMEOUT; |
610 | 607 | ||
611 | memset(rq->cmd, 0, rq->cmd_len); | 608 | memset(rq->cmd, 0, rq->cmd_len); |
@@ -660,6 +657,7 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) | |||
660 | blk_add_request_payload(rq, page, len); | 657 | blk_add_request_payload(rq, page, len); |
661 | ret = scsi_setup_blk_pc_cmnd(sdp, rq); | 658 | ret = scsi_setup_blk_pc_cmnd(sdp, rq); |
662 | rq->buffer = page_address(page); | 659 | rq->buffer = page_address(page); |
660 | rq->__data_len = nr_bytes; | ||
663 | 661 | ||
664 | out: | 662 | out: |
665 | if (ret != BLKPREP_OK) { | 663 | if (ret != BLKPREP_OK) { |
@@ -712,7 +710,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
712 | * block PC requests to make life easier. | 710 | * block PC requests to make life easier. |
713 | */ | 711 | */ |
714 | if (rq->cmd_flags & REQ_DISCARD) { | 712 | if (rq->cmd_flags & REQ_DISCARD) { |
715 | ret = scsi_setup_discard_cmnd(sdp, rq); | 713 | ret = sd_setup_discard_cmnd(sdp, rq); |
716 | goto out; | 714 | goto out; |
717 | } else if (rq->cmd_flags & REQ_FLUSH) { | 715 | } else if (rq->cmd_flags & REQ_FLUSH) { |
718 | ret = scsi_setup_flush_cmnd(sdp, rq); | 716 | ret = scsi_setup_flush_cmnd(sdp, rq); |
@@ -1482,12 +1480,20 @@ static int sd_done(struct scsi_cmnd *SCpnt) | |||
1482 | unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt); | 1480 | unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt); |
1483 | struct scsi_sense_hdr sshdr; | 1481 | struct scsi_sense_hdr sshdr; |
1484 | struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk); | 1482 | struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk); |
1483 | struct request *req = SCpnt->request; | ||
1485 | int sense_valid = 0; | 1484 | int sense_valid = 0; |
1486 | int sense_deferred = 0; | 1485 | int sense_deferred = 0; |
1487 | unsigned char op = SCpnt->cmnd[0]; | 1486 | unsigned char op = SCpnt->cmnd[0]; |
1488 | 1487 | ||
1489 | if ((SCpnt->request->cmd_flags & REQ_DISCARD) && !result) | 1488 | if (req->cmd_flags & REQ_DISCARD) { |
1490 | scsi_set_resid(SCpnt, 0); | 1489 | if (!result) { |
1490 | good_bytes = blk_rq_bytes(req); | ||
1491 | scsi_set_resid(SCpnt, 0); | ||
1492 | } else { | ||
1493 | good_bytes = 0; | ||
1494 | scsi_set_resid(SCpnt, blk_rq_bytes(req)); | ||
1495 | } | ||
1496 | } | ||
1491 | 1497 | ||
1492 | if (result) { | 1498 | if (result) { |
1493 | sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr); | 1499 | sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr); |