aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/sd.c
diff options
context:
space:
mode:
authorMartin K. Petersen <martin.petersen@oracle.com>2012-09-18 12:19:31 -0400
committerJames Bottomley <JBottomley@Parallels.com>2012-11-14 00:23:53 -0500
commit26e85fcd15f68b57d9ba645cd3591117a8ac0e05 (patch)
tree5dcb12ddd18e8ced5707239cdb0da6feaf3c9c80 /drivers/scsi/sd.c
parent3c6bdaeab4fda6c9fdd5f3f5c610dea97bddf7d6 (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.c32
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 **/
593static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) 593static 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
664out: 662out:
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);