From e430cbc8bbd779454516467b2947a97b4003c081 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 2 Jun 2014 22:56:47 +0900 Subject: sd: use READ_16 or WRITE_16 when transfer length is greater than 0xffff This change makes the scsi disk driver handle the requests whose transfer length is greater than 0xffff with READ_16 or WRITE_16. However, this is a preparation for extending the data type of max_sectors in struct Scsi_Host and scsi_host_template. So, it is impossible to happen this condition for now, because SCSI low-level drivers can not specify max_sectors greater than 0xffff due to the data type limitation. Signed-off-by: Akinobu Mita Reviewed-by: Martin K. Petersen Signed-off-by: Christoph Hellwig --- drivers/scsi/sd.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 6825eda1114a..14ec8f521ae8 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1042,7 +1042,7 @@ static int sd_init_command(struct scsi_cmnd *SCpnt) SCpnt->cmnd[29] = (unsigned char) (this_count >> 16) & 0xff; SCpnt->cmnd[30] = (unsigned char) (this_count >> 8) & 0xff; SCpnt->cmnd[31] = (unsigned char) this_count & 0xff; - } else if (sdp->use_16_for_rw) { + } else if (sdp->use_16_for_rw || (this_count > 0xffff)) { SCpnt->cmnd[0] += READ_16 - READ_6; SCpnt->cmnd[1] = protect | ((rq->cmd_flags & REQ_FUA) ? 0x8 : 0); SCpnt->cmnd[2] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0; @@ -1061,9 +1061,6 @@ static int sd_init_command(struct scsi_cmnd *SCpnt) } else if ((this_count > 0xff) || (block > 0x1fffff) || scsi_device_protection(SCpnt->device) || SCpnt->device->use_10_for_rw) { - if (this_count > 0xffff) - this_count = 0xffff; - SCpnt->cmnd[0] += READ_10 - READ_6; SCpnt->cmnd[1] = protect | ((rq->cmd_flags & REQ_FUA) ? 0x8 : 0); SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff; -- cgit v1.2.3 From cb2fb68d064c16a559483651132815cc378fd1f9 Mon Sep 17 00:00:00 2001 From: Vaughan Cao Date: Tue, 3 Jun 2014 17:37:30 +0800 Subject: sd: notify block layer when using temporary change to cache_type This is a fix for commit 39c60a0948cc06139e2fbfe084f83cb7e7deae3b "sd: fix array cache flushing bug causing performance problems" We must notify the block layer via q->flush_flags after a temporary change of the cache_type to write through. Without this, a SYNCHRONIZE CACHE command will still be generated. This patch factors out a helper that can be called from sd_revalidate_disk and cache_type_store. Signed-off-by: Vaughan Cao Reviewed-by: Christoph Hellwig Signed-off-by: Christoph Hellwig --- drivers/scsi/sd.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 14ec8f521ae8..4056004102ae 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -134,6 +134,19 @@ static const char *sd_cache_types[] = { "write back, no read (daft)" }; +static void sd_set_flush_flag(struct scsi_disk *sdkp) +{ + unsigned flush = 0; + + if (sdkp->WCE) { + flush |= REQ_FLUSH; + if (sdkp->DPOFUA) + flush |= REQ_FUA; + } + + blk_queue_flush(sdkp->disk->queue, flush); +} + static ssize_t cache_type_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -177,6 +190,7 @@ cache_type_store(struct device *dev, struct device_attribute *attr, if (sdkp->cache_override) { sdkp->WCE = wce; sdkp->RCD = rcd; + sd_set_flush_flag(sdkp); return count; } @@ -2698,7 +2712,6 @@ static int sd_revalidate_disk(struct gendisk *disk) struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; unsigned char *buffer; - unsigned flush = 0; SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_revalidate_disk\n")); @@ -2744,13 +2757,7 @@ static int sd_revalidate_disk(struct gendisk *disk) * We now have all cache related info, determine how we deal * with flush requests. */ - if (sdkp->WCE) { - flush |= REQ_FLUSH; - if (sdkp->DPOFUA) - flush |= REQ_FUA; - } - - blk_queue_flush(sdkp->disk->queue, flush); + sd_set_flush_flag(sdkp); set_capacity(disk, sdkp->capacity); sd_config_write_same(sdkp); -- cgit v1.2.3 From 8d964478b2d124fcfde8017d02d4d70ae20802f2 Mon Sep 17 00:00:00 2001 From: Clément Calmels Date: Tue, 3 Jun 2014 23:34:25 +0200 Subject: sd: bad return code of init_sd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In init_sd function, if kmem_cache_create or mempool_create_slab_pools calls fail, the error will not be correclty reported because class_register previously set the value of err to 0. Signed-off-by: Clément Calmels Reviewed-by: Ewan D. Milne Signed-off-by: Christoph Hellwig --- drivers/scsi/sd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 4056004102ae..5167b9678240 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3212,12 +3212,14 @@ static int __init init_sd(void) 0, 0, NULL); if (!sd_cdb_cache) { printk(KERN_ERR "sd: can't init extended cdb cache\n"); + err = -ENOMEM; goto err_out_class; } sd_cdb_pool = mempool_create_slab_pool(SD_MEMPOOL_SIZE, sd_cdb_cache); if (!sd_cdb_pool) { printk(KERN_ERR "sd: can't init extended cdb pool\n"); + err = -ENOMEM; goto err_out_cache; } -- cgit v1.2.3 From bcdb247c6b6a1f3e72b9b787b73f47dd509d17ec Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Tue, 3 Jun 2014 18:45:51 -0400 Subject: sd: Limit transfer length Until now the per-command transfer length has exclusively been gated by the max_sectors parameter in the scsi_host template. Given that the size of this parameter has been bumped to an unsigned int we have to be careful not to exceed the target device's capabilities. If the if the device specifies a Maximum Transfer Length in the Block Limits VPD we'll use that value. Otherwise we'll use 0xffffffff for devices that have use_16_for_rw set and 0xffff for the rest. We then combine the chosen disk limit with max_sectors in the host template. The smaller of the two will be used to set the max_hw_sectors queue limit. Signed-off-by: Martin K. Petersen Reviewed-by: Ewan D. Milne Signed-off-by: Christoph Hellwig --- drivers/scsi/sd.c | 16 +++++++++++++++- drivers/scsi/sd.h | 3 +++ 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 5167b9678240..87566b51fcf7 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2236,7 +2236,11 @@ got_data: } } - sdp->use_16_for_rw = (sdkp->capacity > 0xffffffff); + if (sdkp->capacity > 0xffffffff) { + sdp->use_16_for_rw = 1; + sdkp->max_xfer_blocks = SD_MAX_XFER_BLOCKS; + } else + sdkp->max_xfer_blocks = SD_DEF_XFER_BLOCKS; /* Rescale capacity to 512-byte units */ if (sector_size == 4096) @@ -2551,6 +2555,7 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) { unsigned int sector_sz = sdkp->device->sector_size; const int vpd_len = 64; + u32 max_xfer_length; unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL); if (!buffer || @@ -2558,6 +2563,10 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) scsi_get_vpd_page(sdkp->device, 0xb0, buffer, vpd_len)) goto out; + max_xfer_length = get_unaligned_be32(&buffer[8]); + if (max_xfer_length) + sdkp->max_xfer_blocks = max_xfer_length; + blk_queue_io_min(sdkp->disk->queue, get_unaligned_be16(&buffer[6]) * sector_sz); blk_queue_io_opt(sdkp->disk->queue, @@ -2712,6 +2721,7 @@ static int sd_revalidate_disk(struct gendisk *disk) struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; unsigned char *buffer; + unsigned int max_xfer; SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_revalidate_disk\n")); @@ -2759,6 +2769,10 @@ static int sd_revalidate_disk(struct gendisk *disk) */ sd_set_flush_flag(sdkp); + max_xfer = min_not_zero(queue_max_hw_sectors(sdkp->disk->queue), + sdkp->max_xfer_blocks); + max_xfer <<= ilog2(sdp->sector_size) - 9; + blk_queue_max_hw_sectors(sdkp->disk->queue, max_xfer); set_capacity(disk, sdkp->capacity); sd_config_write_same(sdkp); kfree(buffer); diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 620871efbf0a..4c3ab8377fd3 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -44,6 +44,8 @@ enum { }; enum { + SD_DEF_XFER_BLOCKS = 0xffff, + SD_MAX_XFER_BLOCKS = 0xffffffff, SD_MAX_WS10_BLOCKS = 0xffff, SD_MAX_WS16_BLOCKS = 0x7fffff, }; @@ -64,6 +66,7 @@ struct scsi_disk { struct gendisk *disk; atomic_t openers; sector_t capacity; /* size in 512-byte sectors */ + u32 max_xfer_blocks; u32 max_ws_blocks; u32 max_unmap_blocks; u32 unmap_granularity; -- cgit v1.2.3 From 3868cf8ea70a57fc3f927872d8296f287ce4b96a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 28 Jun 2014 11:58:42 +0200 Subject: scsi: restructure command initialization for TYPE_FS requests We should call the device handler prep_fn for all TYPE_FS requests, not just simple read/write calls that are handled by the disk driver. Restructure the common I/O code to call the prep_fn handler and zero out the CDB, and just leave the call to scsi_init_io to the ULDs. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke --- drivers/scsi/scsi_lib.c | 22 ++++++++++++---------- drivers/scsi/sd.c | 2 +- drivers/scsi/sr.c | 3 +-- include/scsi/scsi_driver.h | 1 - 4 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 150d7bb675a1..2afb96b801cb 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1082,11 +1082,10 @@ int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) EXPORT_SYMBOL(scsi_setup_blk_pc_cmnd); /* - * Setup a REQ_TYPE_FS command. These are simple read/write request - * from filesystems that still need to be translated to SCSI CDBs from - * the ULD. + * Setup a REQ_TYPE_FS command. These are simple request from filesystems + * that still need to be translated to SCSI CDBs from the ULD. */ -int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req) +static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req) { struct scsi_cmnd *cmd = req->special; @@ -1098,9 +1097,8 @@ int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req) } memset(cmd->cmnd, 0, BLK_MAX_CDB); - return scsi_init_io(cmd, GFP_ATOMIC); + return scsi_cmd_to_driver(cmd)->init_command(cmd); } -EXPORT_SYMBOL(scsi_setup_fs_cmnd); static int scsi_prep_state_check(struct scsi_device *sdev, struct request *req) @@ -1205,12 +1203,16 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) goto out; } - if (req->cmd_type == REQ_TYPE_FS) - ret = scsi_cmd_to_driver(cmd)->init_command(cmd); - else if (req->cmd_type == REQ_TYPE_BLOCK_PC) + switch (req->cmd_type) { + case REQ_TYPE_FS: + ret = scsi_setup_fs_cmnd(sdev, req); + break; + case REQ_TYPE_BLOCK_PC: ret = scsi_setup_blk_pc_cmnd(sdev, req); - else + break; + default: ret = BLKPREP_KILL; + } out: return scsi_prep_return(q, req, ret); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 87566b51fcf7..1b166c7ea891 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -894,7 +894,7 @@ static int sd_init_command(struct scsi_cmnd *SCpnt) ret = scsi_setup_flush_cmnd(sdp, rq); goto out; } - ret = scsi_setup_fs_cmnd(sdp, rq); + ret = scsi_init_io(SCpnt, GFP_ATOMIC); if (ret != BLKPREP_OK) goto out; SCpnt = rq->special; diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index a7ea27c01286..9feeb3766d7d 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -385,10 +385,9 @@ static int sr_init_command(struct scsi_cmnd *SCpnt) int block = 0, this_count, s_size; struct scsi_cd *cd; struct request *rq = SCpnt->request; - struct scsi_device *sdp = SCpnt->device; int ret; - ret = scsi_setup_fs_cmnd(sdp, rq); + ret = scsi_init_io(SCpnt, GFP_ATOMIC); if (ret != BLKPREP_OK) goto out; SCpnt = rq->special; diff --git a/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h index 36c4114ed9bc..009d2ae91a52 100644 --- a/include/scsi/scsi_driver.h +++ b/include/scsi/scsi_driver.h @@ -30,6 +30,5 @@ extern int scsi_register_interface(struct class_interface *); class_interface_unregister(intf) int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req); -int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req); #endif /* _SCSI_SCSI_DRIVER_H */ -- cgit v1.2.3 From 5158a899d8f24f74cad29b6aaad2b0f86499e5d5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 28 Jun 2014 16:41:43 +0200 Subject: scsi: set sc_data_direction in common code The data direction fiel in the SCSI command is derived only from the block request structure. Move setting it up into common code instead of duplicating it in the ULDs. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke --- drivers/scsi/scsi_lib.c | 14 +++++++------- drivers/scsi/sd.c | 2 -- drivers/scsi/sr.c | 2 -- 3 files changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 2afb96b801cb..4e15a3a5ad29 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1068,13 +1068,6 @@ int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) } cmd->cmd_len = req->cmd_len; - if (!blk_rq_bytes(req)) - cmd->sc_data_direction = DMA_NONE; - else if (rq_data_dir(req) == WRITE) - cmd->sc_data_direction = DMA_TO_DEVICE; - else - cmd->sc_data_direction = DMA_FROM_DEVICE; - cmd->transfersize = blk_rq_bytes(req); cmd->allowed = req->retries; return BLKPREP_OK; @@ -1203,6 +1196,13 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) goto out; } + if (!blk_rq_bytes(req)) + cmd->sc_data_direction = DMA_NONE; + else if (rq_data_dir(req) == WRITE) + cmd->sc_data_direction = DMA_TO_DEVICE; + else + cmd->sc_data_direction = DMA_FROM_DEVICE; + switch (req->cmd_type) { case REQ_TYPE_FS: ret = scsi_setup_fs_cmnd(sdev, req); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 1b166c7ea891..e2932ea429e2 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -994,14 +994,12 @@ static int sd_init_command(struct scsi_cmnd *SCpnt) goto out; } SCpnt->cmnd[0] = WRITE_6; - SCpnt->sc_data_direction = DMA_TO_DEVICE; if (blk_integrity_rq(rq)) sd_dif_prepare(rq, block, sdp->sector_size); } else if (rq_data_dir(rq) == READ) { SCpnt->cmnd[0] = READ_6; - SCpnt->sc_data_direction = DMA_FROM_DEVICE; } else { scmd_printk(KERN_ERR, SCpnt, "Unknown command %llx\n", (unsigned long long) rq->cmd_flags); goto out; diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 9feeb3766d7d..cce4771281d9 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -438,11 +438,9 @@ static int sr_init_command(struct scsi_cmnd *SCpnt) if (!cd->device->writeable) goto out; SCpnt->cmnd[0] = WRITE_10; - SCpnt->sc_data_direction = DMA_TO_DEVICE; cd->cdi.media_written = 1; } else if (rq_data_dir(rq) == READ) { SCpnt->cmnd[0] = READ_10; - SCpnt->sc_data_direction = DMA_FROM_DEVICE; } else { blk_dump_rq_flags(rq, "Unknown sr command"); goto out; -- cgit v1.2.3 From a118c6c1d907e52286df25ee1e8b217f25d6f73d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 28 Jun 2014 12:08:05 +0200 Subject: sd: don't use scsi_setup_blk_pc_cmnd for flush requests Simplify handling of flush requests by setting up the command directly instead of initializing request fields and then calling scsi_setup_blk_pc_cmnd to propagate the information into the command. Also rename scsi_setup_flush_cmnd to sd_setup_flush_cmnd for consistency. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke --- drivers/scsi/sd.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e2932ea429e2..18ca21fd7559 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -844,14 +844,20 @@ static int sd_setup_write_same_cmnd(struct scsi_device *sdp, struct request *rq) return ret; } -static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq) +static int sd_setup_flush_cmnd(struct scsi_cmnd *cmd) { - rq->timeout *= SD_FLUSH_TIMEOUT_MULTIPLIER; - rq->retries = SD_MAX_RETRIES; - rq->cmd[0] = SYNCHRONIZE_CACHE; - rq->cmd_len = 10; + struct request *rq = cmd->request; + + /* flush requests don't perform I/O, zero the S/G table */ + memset(&cmd->sdb, 0, sizeof(cmd->sdb)); - return scsi_setup_blk_pc_cmnd(sdp, rq); + cmd->cmnd[0] = SYNCHRONIZE_CACHE; + cmd->cmd_len = 10; + cmd->transfersize = 0; + cmd->allowed = SD_MAX_RETRIES; + + rq->timeout *= SD_FLUSH_TIMEOUT_MULTIPLIER; + return BLKPREP_OK; } static void sd_uninit_command(struct scsi_cmnd *SCpnt) @@ -891,7 +897,7 @@ static int sd_init_command(struct scsi_cmnd *SCpnt) ret = sd_setup_write_same_cmnd(sdp, rq); goto out; } else if (rq->cmd_flags & REQ_FLUSH) { - ret = scsi_setup_flush_cmnd(sdp, rq); + ret = sd_setup_flush_cmnd(SCpnt); goto out; } ret = scsi_init_io(SCpnt, GFP_ATOMIC); -- cgit v1.2.3 From 59b1134c5a2aab2c70725af83d2e2d1c71c509ca Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 28 Jun 2014 12:22:22 +0200 Subject: sd: don't use scsi_setup_blk_pc_cmnd for write same requests Simplify handling of write same requests by setting up the command directly instead of initializing request fields and then calling scsi_setup_blk_pc_cmnd to propagate the information into the command. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Webb Scales --- drivers/scsi/sd.c | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 18ca21fd7559..aefedf4fbb2b 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -799,14 +799,15 @@ out: /** * sd_setup_write_same_cmnd - write the same data to multiple blocks - * @sdp: scsi device to operate one - * @rq: Request to prepare + * @cmd: command to prepare * * Will issue either WRITE SAME(10) or WRITE SAME(16) depending on * preference indicated by target device. **/ -static int sd_setup_write_same_cmnd(struct scsi_device *sdp, struct request *rq) +static int sd_setup_write_same_cmnd(struct scsi_cmnd *cmd) { + struct request *rq = cmd->request; + struct scsi_device *sdp = cmd->device; struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); struct bio *bio = rq->bio; sector_t sector = blk_rq_pos(rq); @@ -822,25 +823,36 @@ static int sd_setup_write_same_cmnd(struct scsi_device *sdp, struct request *rq) sector >>= ilog2(sdp->sector_size) - 9; nr_sectors >>= ilog2(sdp->sector_size) - 9; - rq->__data_len = sdp->sector_size; rq->timeout = SD_WRITE_SAME_TIMEOUT; - memset(rq->cmd, 0, rq->cmd_len); if (sdkp->ws16 || sector > 0xffffffff || nr_sectors > 0xffff) { - rq->cmd_len = 16; - rq->cmd[0] = WRITE_SAME_16; - put_unaligned_be64(sector, &rq->cmd[2]); - put_unaligned_be32(nr_sectors, &rq->cmd[10]); + cmd->cmd_len = 16; + cmd->cmnd[0] = WRITE_SAME_16; + put_unaligned_be64(sector, &cmd->cmnd[2]); + put_unaligned_be32(nr_sectors, &cmd->cmnd[10]); } else { - rq->cmd_len = 10; - rq->cmd[0] = WRITE_SAME; - put_unaligned_be32(sector, &rq->cmd[2]); - put_unaligned_be16(nr_sectors, &rq->cmd[7]); + cmd->cmd_len = 10; + cmd->cmnd[0] = WRITE_SAME; + put_unaligned_be32(sector, &cmd->cmnd[2]); + put_unaligned_be16(nr_sectors, &cmd->cmnd[7]); } - ret = scsi_setup_blk_pc_cmnd(sdp, rq); - rq->__data_len = nr_bytes; + cmd->transfersize = sdp->sector_size; + cmd->allowed = rq->retries; + /* + * For WRITE_SAME the data transferred in the DATA IN buffer is + * different from the amount of data actually written to the target. + * + * We set up __data_len to the amount of data transferred from the + * DATA IN buffer so that blk_rq_map_sg set up the proper S/G list + * to transfer a single sector of data first, but then reset it to + * the amount of data to be written right after so that the I/O path + * knows how much to actually write. + */ + rq->__data_len = sdp->sector_size; + ret = scsi_init_io(cmd, GFP_ATOMIC); + rq->__data_len = nr_bytes; return ret; } @@ -894,7 +906,7 @@ static int sd_init_command(struct scsi_cmnd *SCpnt) ret = sd_setup_discard_cmnd(sdp, rq); goto out; } else if (rq->cmd_flags & REQ_WRITE_SAME) { - ret = sd_setup_write_same_cmnd(sdp, rq); + ret = sd_setup_write_same_cmnd(SCpnt); goto out; } else if (rq->cmd_flags & REQ_FLUSH) { ret = sd_setup_flush_cmnd(SCpnt); -- cgit v1.2.3 From 6a7b43985daa4f42b6d6f0186594c3a68f84a1d8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 28 Jun 2014 12:35:13 +0200 Subject: sd: don't use scsi_setup_blk_pc_cmnd for discard requests Simplify handling of discard requests by setting up the command directly instead of initializing request fields and then calling scsi_setup_blk_pc_cmnd to propagate the information into the command. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke --- drivers/scsi/sd.c | 50 +++++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 19 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index aefedf4fbb2b..03bed86b9fc9 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -691,8 +691,10 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) * Will issue either UNMAP or WRITE SAME(16) depending on preference * indicated by target device. **/ -static int sd_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) +static int sd_setup_discard_cmnd(struct scsi_cmnd *cmd) { + struct request *rq = cmd->request; + struct scsi_device *sdp = cmd->device; struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); sector_t sector = blk_rq_pos(rq); unsigned int nr_sectors = blk_rq_sectors(rq); @@ -704,9 +706,6 @@ static int sd_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) sector >>= ilog2(sdp->sector_size) - 9; nr_sectors >>= ilog2(sdp->sector_size) - 9; - rq->timeout = SD_TIMEOUT; - - memset(rq->cmd, 0, rq->cmd_len); page = alloc_page(GFP_ATOMIC | __GFP_ZERO); if (!page) @@ -716,9 +715,9 @@ static int sd_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) case SD_LBP_UNMAP: buf = page_address(page); - rq->cmd_len = 10; - rq->cmd[0] = UNMAP; - rq->cmd[8] = 24; + cmd->cmd_len = 10; + cmd->cmnd[0] = UNMAP; + cmd->cmnd[8] = 24; put_unaligned_be16(6 + 16, &buf[0]); put_unaligned_be16(16, &buf[2]); @@ -729,23 +728,23 @@ static int sd_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) break; case SD_LBP_WS16: - rq->cmd_len = 16; - rq->cmd[0] = WRITE_SAME_16; - rq->cmd[1] = 0x8; /* UNMAP */ - put_unaligned_be64(sector, &rq->cmd[2]); - put_unaligned_be32(nr_sectors, &rq->cmd[10]); + cmd->cmd_len = 16; + cmd->cmnd[0] = WRITE_SAME_16; + cmd->cmnd[1] = 0x8; /* UNMAP */ + put_unaligned_be64(sector, &cmd->cmnd[2]); + put_unaligned_be32(nr_sectors, &cmd->cmnd[10]); len = sdkp->device->sector_size; break; case SD_LBP_WS10: case SD_LBP_ZERO: - rq->cmd_len = 10; - rq->cmd[0] = WRITE_SAME; + cmd->cmd_len = 10; + cmd->cmnd[0] = WRITE_SAME; if (sdkp->provisioning_mode == SD_LBP_WS10) - rq->cmd[1] = 0x8; /* UNMAP */ - put_unaligned_be32(sector, &rq->cmd[2]); - put_unaligned_be16(nr_sectors, &rq->cmd[7]); + cmd->cmnd[1] = 0x8; /* UNMAP */ + put_unaligned_be32(sector, &cmd->cmnd[2]); + put_unaligned_be16(nr_sectors, &cmd->cmnd[7]); len = sdkp->device->sector_size; break; @@ -756,8 +755,21 @@ static int sd_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) } rq->completion_data = page; + rq->timeout = SD_TIMEOUT; + + cmd->transfersize = len; + cmd->allowed = rq->retries; + + /* + * Initially __data_len is set to the amount of data that needs to be + * transferred to the target. This amount depends on whether WRITE SAME + * or UNMAP is being used. After the scatterlist has been mapped by + * scsi_init_io() we set __data_len to the size of the area to be + * discarded on disk. This allows us to report completion on the full + * amount of blocks described by the request. + */ blk_add_request_payload(rq, page, len); - ret = scsi_setup_blk_pc_cmnd(sdp, rq); + ret = scsi_init_io(cmd, GFP_ATOMIC); rq->__data_len = nr_bytes; out: @@ -903,7 +915,7 @@ static int sd_init_command(struct scsi_cmnd *SCpnt) * block PC requests to make life easier. */ if (rq->cmd_flags & REQ_DISCARD) { - ret = sd_setup_discard_cmnd(sdp, rq); + ret = sd_setup_discard_cmnd(SCpnt); goto out; } else if (rq->cmd_flags & REQ_WRITE_SAME) { ret = sd_setup_write_same_cmnd(SCpnt); -- cgit v1.2.3 From a25ee5485157403612fbb59be6c0435ede2f1da8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 28 Jun 2014 12:29:19 +0200 Subject: sd: retry write same commands Currently cmd->allowed is initialized from rq->retries for write same commands, but retries is always 0 for non-BLOCK_PC requests. Set it to the standard number of retries instead. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke --- drivers/scsi/sd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 03bed86b9fc9..f54a53086c9d 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -850,7 +850,7 @@ static int sd_setup_write_same_cmnd(struct scsi_cmnd *cmd) } cmd->transfersize = sdp->sector_size; - cmd->allowed = rq->retries; + cmd->allowed = SD_MAX_RETRIES; /* * For WRITE_SAME the data transferred in the DATA IN buffer is -- cgit v1.2.3 From e4200f8ee35db820680a3caa25d260ef11fc1462 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 28 Jun 2014 16:18:59 +0200 Subject: sd: retry discard commands Currently cmd->allowed is initialized from rq->retries for discard commands, but retries is always 0 for non-BLOCK_PC requests. Set it to the standard number of retries instead. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke --- drivers/scsi/sd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index f54a53086c9d..fe0b7dff02b4 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -758,7 +758,7 @@ static int sd_setup_discard_cmnd(struct scsi_cmnd *cmd) rq->timeout = SD_TIMEOUT; cmd->transfersize = len; - cmd->allowed = rq->retries; + cmd->allowed = SD_MAX_RETRIES; /* * Initially __data_len is set to the amount of data that needs to be -- cgit v1.2.3 From 87949eee7e15471a42f06ae534847264a41be647 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 28 Jun 2014 12:40:18 +0200 Subject: sd: split sd_init_command Factor out a function to initialize regular read/write commands and leave sd_init_command as a simple dispatcher to the different prepare routines. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke --- drivers/scsi/sd.c | 58 +++++++++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index fe0b7dff02b4..3663e38ba4df 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -884,21 +884,7 @@ static int sd_setup_flush_cmnd(struct scsi_cmnd *cmd) return BLKPREP_OK; } -static void sd_uninit_command(struct scsi_cmnd *SCpnt) -{ - struct request *rq = SCpnt->request; - - if (rq->cmd_flags & REQ_DISCARD) - __free_page(rq->completion_data); - - if (SCpnt->cmnd != rq->cmd) { - mempool_free(SCpnt->cmnd, sd_cdb_pool); - SCpnt->cmnd = NULL; - SCpnt->cmd_len = 0; - } -} - -static int sd_init_command(struct scsi_cmnd *SCpnt) +static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt) { struct request *rq = SCpnt->request; struct scsi_device *sdp = SCpnt->device; @@ -910,20 +896,6 @@ static int sd_init_command(struct scsi_cmnd *SCpnt) int ret, host_dif; unsigned char protect; - /* - * Discard request come in as REQ_TYPE_FS but we turn them into - * block PC requests to make life easier. - */ - if (rq->cmd_flags & REQ_DISCARD) { - ret = sd_setup_discard_cmnd(SCpnt); - goto out; - } else if (rq->cmd_flags & REQ_WRITE_SAME) { - ret = sd_setup_write_same_cmnd(SCpnt); - goto out; - } else if (rq->cmd_flags & REQ_FLUSH) { - ret = sd_setup_flush_cmnd(SCpnt); - goto out; - } ret = scsi_init_io(SCpnt, GFP_ATOMIC); if (ret != BLKPREP_OK) goto out; @@ -1155,6 +1127,34 @@ static int sd_init_command(struct scsi_cmnd *SCpnt) return ret; } +static int sd_init_command(struct scsi_cmnd *cmd) +{ + struct request *rq = cmd->request; + + if (rq->cmd_flags & REQ_DISCARD) + return sd_setup_discard_cmnd(cmd); + else if (rq->cmd_flags & REQ_WRITE_SAME) + return sd_setup_write_same_cmnd(cmd); + else if (rq->cmd_flags & REQ_FLUSH) + return sd_setup_flush_cmnd(cmd); + else + return sd_setup_read_write_cmnd(cmd); +} + +static void sd_uninit_command(struct scsi_cmnd *SCpnt) +{ + struct request *rq = SCpnt->request; + + if (rq->cmd_flags & REQ_DISCARD) + __free_page(rq->completion_data); + + if (SCpnt->cmnd != rq->cmd) { + mempool_free(SCpnt->cmnd, sd_cdb_pool); + SCpnt->cmnd = NULL; + SCpnt->cmd_len = 0; + } +} + /** * sd_open - open a scsi disk device * @inode: only i_rdev member may be used -- cgit v1.2.3 From fd2eb9034e48cdca358dc06a833a736e7c6f68dd Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 18 Jul 2014 16:59:19 +0200 Subject: scsi: move the writeable field from struct scsi_device to struct scsi_cd We currently set the field in common code based on the device type, but then only use it in the cdrom driver which also overrides the value previously set in the generic code. Just leave this entirely to the CDROM driver to make everyones life simpler. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Reviewed-by: Martin K. Petersen --- drivers/scsi/scsi_scan.c | 24 ------------------------ drivers/scsi/sd.c | 3 --- drivers/scsi/sr.c | 4 ++-- drivers/scsi/sr.h | 1 + include/scsi/scsi_device.h | 1 - 5 files changed, 3 insertions(+), 30 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index b91cfaf033aa..a5a0bdeba857 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -807,30 +807,6 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, sdev->removable = (inq_result[1] & 0x80) >> 7; } - switch (sdev->type) { - case TYPE_RBC: - case TYPE_TAPE: - case TYPE_DISK: - case TYPE_PRINTER: - case TYPE_MOD: - case TYPE_PROCESSOR: - case TYPE_SCANNER: - case TYPE_MEDIUM_CHANGER: - case TYPE_ENCLOSURE: - case TYPE_COMM: - case TYPE_RAID: - case TYPE_OSD: - sdev->writeable = 1; - break; - case TYPE_ROM: - case TYPE_WORM: - sdev->writeable = 0; - break; - default: - sdev_printk(KERN_INFO, sdev, "unknown device type %d\n", - sdev->type); - } - if (sdev->type == TYPE_RBC || sdev->type == TYPE_ROM) { /* RBC and MMC devices can return SCSI-3 compliance and yet * still not support REPORT LUNS, so make them act as diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3663e38ba4df..377a5206017e 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -992,9 +992,6 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt) } } if (rq_data_dir(rq) == WRITE) { - if (!sdp->writeable) { - goto out; - } SCpnt->cmnd[0] = WRITE_6; if (blk_integrity_rq(rq)) diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index cce4771281d9..7eeb93627beb 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -435,7 +435,7 @@ static int sr_init_command(struct scsi_cmnd *SCpnt) } if (rq_data_dir(rq) == WRITE) { - if (!cd->device->writeable) + if (!cd->writeable) goto out; SCpnt->cmnd[0] = WRITE_10; cd->cdi.media_written = 1; @@ -927,7 +927,7 @@ static void get_capabilities(struct scsi_cd *cd) */ if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) != (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) { - cd->device->writeable = 1; + cd->writeable = 1; } kfree(buffer); diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h index 5334e988480d..1d1f6f416c59 100644 --- a/drivers/scsi/sr.h +++ b/drivers/scsi/sr.h @@ -36,6 +36,7 @@ typedef struct scsi_cd { struct scsi_device *device; unsigned int vendor; /* vendor code, see sr_vendor.c */ unsigned long ms_offset; /* for reading multisession-CD's */ + unsigned writeable : 1; unsigned use:1; /* is this device still supportable */ unsigned xa_flag:1; /* CD has XA sectors ? */ unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 0f853f2c9dc7..b895784e2313 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -127,7 +127,6 @@ struct scsi_device { * pass settings from slave_alloc to scsi * core. */ unsigned int eh_timeout; /* Error handling timeout */ - unsigned writeable:1; unsigned removable:1; unsigned changed:1; /* Data invalid due to media change */ unsigned busy:1; /* Used to prevent races */ -- cgit v1.2.3 From c1d40a527e885a40bb9ea6c46a1b1145d42b66a0 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Tue, 15 Jul 2014 12:49:17 -0400 Subject: scsi: add a blacklist flag which enables VPD page inquiries Despite supporting modern SCSI features some storage devices continue to claim conformance to an older version of the SPC spec. This is done for compatibility with legacy operating systems. Linux by default will not attempt to read VPD pages on devices that claim SPC-2 or older. Introduce a blacklist flag that can be used to trigger VPD page inquiries on devices that are known to support them. Reported-by: KY Srinivasan Tested-by: KY Srinivasan Reviewed-by: KY Srinivasan Signed-off-by: Martin K. Petersen CC: Signed-off-by: Christoph Hellwig --- drivers/scsi/scsi_scan.c | 4 +++- drivers/scsi/sd.c | 5 +++++ include/scsi/scsi_device.h | 1 + include/scsi/scsi_devinfo.h | 1 + 4 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index a5a0bdeba857..50536cd6b3f2 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -928,7 +928,9 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, sdev->eh_timeout = SCSI_DEFAULT_EH_TIMEOUT; - if (*bflags & BLIST_SKIP_VPD_PAGES) + if (*bflags & BLIST_TRY_VPD_PAGES) + sdev->try_vpd_pages = 1; + else if (*bflags & BLIST_SKIP_VPD_PAGES) sdev->skip_vpd_pages = 1; transport_configure_device(&sdev->sdev_gendev); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 377a5206017e..4d72831eafe5 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2726,6 +2726,11 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) static int sd_try_extended_inquiry(struct scsi_device *sdp) { + /* Attempt VPD inquiry if the device blacklist explicitly calls + * for it. + */ + if (sdp->try_vpd_pages) + return 1; /* * Although VPD inquiries can go to SCSI-2 type devices, * some USB ones crash on receiving them, and the pages diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index b895784e2313..1a0d1842962e 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -154,6 +154,7 @@ struct scsi_device { unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */ unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */ unsigned skip_vpd_pages:1; /* do not read VPD pages */ + unsigned try_vpd_pages:1; /* attempt to read VPD pages */ unsigned use_192_bytes_for_3f:1; /* ask for 192 bytes from page 0x3f */ unsigned no_start_on_add:1; /* do not issue start on add */ unsigned allow_restart:1; /* issue START_UNIT in error handler */ diff --git a/include/scsi/scsi_devinfo.h b/include/scsi/scsi_devinfo.h index 8670c04e199e..1fdd6fc5492b 100644 --- a/include/scsi/scsi_devinfo.h +++ b/include/scsi/scsi_devinfo.h @@ -34,4 +34,5 @@ #define BLIST_SKIP_VPD_PAGES 0x4000000 /* Ignore SBC-3 VPD pages */ #define BLIST_SCSI3LUN 0x8000000 /* Scan more than 256 LUNs for sequential scan */ +#define BLIST_TRY_VPD_PAGES 0x10000000 /* Attempt to read VPD pages */ #endif -- cgit v1.2.3 From 26b9fd8b3452dcf0a8862e307ee23f442f63fb51 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Fri, 18 Jul 2014 17:11:27 +0200 Subject: sd: fix a bug in deriving the FLUSH_TIMEOUT from the basic I/O timeout Commit ID: 7e660100d85af860e7ad763202fff717adcdaacd added code to derive the FLUSH_TIMEOUT from the basic I/O timeout. However, this patch did not use the basic I/O timeout of the device. Fix this bug. Signed-off-by: K. Y. Srinivasan Reviewed-by: James Bottomley Signed-off-by: Christoph Hellwig --- drivers/scsi/sd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 4d72831eafe5..2c2041ca4b70 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -880,7 +880,7 @@ static int sd_setup_flush_cmnd(struct scsi_cmnd *cmd) cmd->transfersize = 0; cmd->allowed = SD_MAX_RETRIES; - rq->timeout *= SD_FLUSH_TIMEOUT_MULTIPLIER; + rq->timeout = rq->q->rq_timeout * SD_FLUSH_TIMEOUT_MULTIPLIER; return BLKPREP_OK; } -- cgit v1.2.3