From ed4246d37f3b94e429d020cac692434a00bae4cc Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Sun, 4 Jul 2021 09:54:02 +0200 Subject: scsi: sd: REQUEST SENSE for BLIST_IGN_MEDIA_CHANGE devices in runtime_resume() For SD card reader devices that have the BLIST_IGN_MEDIA_CHANGE flag set, a MEDIUM MAY HAVE CHANGED unit attention is established after resuming from runtime suspend. Send a REQUEST SENSE to consume the UA. The "downside" is that for these devices we now rely on users to not change the medium (SD card) *during* a runtime suspend/resume cycle, i.e. when not unmounting. To enable runtime PM for an SD cardreader (device number 0:0:0:0), do: echo 0 > /sys/module/block/parameters/events_dfl_poll_msecs echo 1000 > /sys/bus/scsi/devices/0:0:0:0/power/autosuspend_delay_ms echo auto > /sys/bus/scsi/devices/0:0:0:0/power/control [mkp: use scsi_device flag instead of poking at BLIST] Link: https://lore.kernel.org/r/20210704075403.147114-3-martin.kepplinger@puri.sm Reviewed-by: Bart Van Assche Signed-off-by: Martin Kepplinger Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index b8d55af763f9..e7ef4728d5eb 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -110,6 +110,7 @@ static void sd_shutdown(struct device *); static int sd_suspend_system(struct device *); static int sd_suspend_runtime(struct device *); static int sd_resume(struct device *); +static int sd_resume_runtime(struct device *); static void sd_rescan(struct device *); static blk_status_t sd_init_command(struct scsi_cmnd *SCpnt); static void sd_uninit_command(struct scsi_cmnd *SCpnt); @@ -604,7 +605,7 @@ static const struct dev_pm_ops sd_pm_ops = { .poweroff = sd_suspend_system, .restore = sd_resume, .runtime_suspend = sd_suspend_runtime, - .runtime_resume = sd_resume, + .runtime_resume = sd_resume_runtime, }; static struct scsi_driver sd_template = { @@ -3716,6 +3717,25 @@ static int sd_resume(struct device *dev) return ret; } +static int sd_resume_runtime(struct device *dev) +{ + struct scsi_disk *sdkp = dev_get_drvdata(dev); + struct scsi_device *sdp = sdkp->device; + + if (sdp->ignore_media_change) { + /* clear the device's sense data */ + static const u8 cmd[10] = { REQUEST_SENSE }; + + if (scsi_execute(sdp, cmd, DMA_NONE, NULL, 0, NULL, + NULL, sdp->request_queue->rq_timeout, 1, 0, + RQF_PM, NULL)) + sd_printk(KERN_NOTICE, sdkp, + "Failed to clear sense data\n"); + } + + return sd_resume(dev); +} + /** * init_sd - entry point for this driver (both when built in or when * a module). -- cgit v1.2.3 From 443283109f5c9dbcd878f4572a1b8876eae3b6c0 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 24 Jul 2021 09:20:12 +0200 Subject: scsi: sd: Consolidate compat ioctl handling Merge the native and compat ioctl handlers into a single one using in_compat_syscall(), and also simplify the calling conventions by merging sd_ioctl_common() into sd_ioctl(). Link: https://lore.kernel.org/r/20210724072033.1284840-4-hch@lst.de Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 63 ++++++++++++++++--------------------------------------- 1 file changed, 18 insertions(+), 45 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e7ef4728d5eb..12faebc163ab 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1530,11 +1530,11 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo) } /** - * sd_ioctl_common - process an ioctl + * sd_ioctl - process an ioctl * @bdev: target block device * @mode: FMODE_* mask * @cmd: ioctl command number - * @p: this is third argument given to ioctl(2) system call. + * @arg: this is third argument given to ioctl(2) system call. * Often contains a pointer. * * Returns 0 if successful (some ioctls return positive numbers on @@ -1543,12 +1543,13 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo) * Note: most ioctls are forward onto the block subsystem or further * down in the scsi subsystem. **/ -static int sd_ioctl_common(struct block_device *bdev, fmode_t mode, - unsigned int cmd, void __user *p) +static int sd_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) { struct gendisk *disk = bdev->bd_disk; struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; + void __user *p = (void __user *)arg; int error; SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, " @@ -1567,7 +1568,7 @@ static int sd_ioctl_common(struct block_device *bdev, fmode_t mode, error = scsi_ioctl_block_when_processing_errors(sdp, cmd, (mode & FMODE_NDELAY) != 0); if (error) - goto out; + return error; if (is_sed_ioctl(cmd)) return sed_ioctl(sdkp->opal_dev, cmd, p); @@ -1578,16 +1579,18 @@ static int sd_ioctl_common(struct block_device *bdev, fmode_t mode, * resolved. */ switch (cmd) { - case SCSI_IOCTL_GET_IDLUN: - case SCSI_IOCTL_GET_BUS_NUMBER: - error = scsi_ioctl(sdp, cmd, p); - break; - default: - error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p); - break; + case SCSI_IOCTL_GET_IDLUN: + case SCSI_IOCTL_GET_BUS_NUMBER: + break; + default: + error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p); + if (error != -ENOTTY) + return error; } -out: - return error; + + if (in_compat_syscall()) + return scsi_compat_ioctl(sdp, cmd, p); + return scsi_ioctl(sdp, cmd, p); } static void set_media_not_present(struct scsi_disk *sdkp) @@ -1770,34 +1773,6 @@ static void sd_rescan(struct device *dev) sd_revalidate_disk(sdkp->disk); } -static int sd_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - void __user *p = (void __user *)arg; - int ret; - - ret = sd_ioctl_common(bdev, mode, cmd, p); - if (ret != -ENOTTY) - return ret; - - return scsi_ioctl(scsi_disk(bdev->bd_disk)->device, cmd, p); -} - -#ifdef CONFIG_COMPAT -static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - void __user *p = compat_ptr(arg); - int ret; - - ret = sd_ioctl_common(bdev, mode, cmd, p); - if (ret != -ENOTTY) - return ret; - - return scsi_compat_ioctl(scsi_disk(bdev->bd_disk)->device, cmd, p); -} -#endif - static char sd_pr_type(enum pr_type type) { switch (type) { @@ -1898,9 +1873,7 @@ static const struct block_device_operations sd_fops = { .release = sd_release, .ioctl = sd_ioctl, .getgeo = sd_getgeo, -#ifdef CONFIG_COMPAT - .compat_ioctl = sd_compat_ioctl, -#endif + .compat_ioctl = blkdev_compat_ptr_ioctl, .check_events = sd_check_events, .unlock_native_capacity = sd_unlock_native_capacity, .report_zones = sd_zbc_report_zones, -- cgit v1.2.3 From 6fade4505af898c849ebe80f54313aa9c387e6da Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 24 Jul 2021 09:20:15 +0200 Subject: scsi: core: Remove scsi_compat_ioctl() Just handle the compat case in scsi_ioctl() using in_compat_syscall(). Link: https://lore.kernel.org/r/20210724072033.1284840-7-hch@lst.de Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/ch.c | 2 -- drivers/scsi/scsi_ioctl.c | 60 ++++++++++++++++------------------------------- drivers/scsi/sd.c | 2 -- drivers/scsi/sg.c | 3 --- drivers/scsi/sr.c | 5 +--- drivers/scsi/st.c | 2 +- include/scsi/scsi_ioctl.h | 1 - 7 files changed, 22 insertions(+), 53 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index cf517381cbcc..e354a95c56af 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -877,8 +877,6 @@ static long ch_ioctl(struct file *file, } default: - if (in_compat_syscall()) - return scsi_compat_ioctl(ch->device, cmd, argp); return scsi_ioctl(ch->device, cmd, argp); } diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 0d13610cd6bf..7b2e3cc85e66 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -189,8 +189,17 @@ static int scsi_ioctl_get_pci(struct scsi_device *sdev, void __user *arg) ? -EFAULT: 0; } - -static int scsi_ioctl_common(struct scsi_device *sdev, int cmd, void __user *arg) +/** + * scsi_ioctl - Dispatch ioctl to scsi device + * @sdev: scsi device receiving ioctl + * @cmd: which ioctl is it + * @arg: data associated with ioctl + * + * Description: The scsi_ioctl() function differs from most ioctls in that it + * does not take a major/minor number as the dev field. Rather, it takes + * a pointer to a &struct scsi_device. + */ +int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) { char scsi_cmd[MAX_COMMAND_SIZE]; struct scsi_sense_hdr sense_hdr; @@ -258,48 +267,19 @@ static int scsi_ioctl_common(struct scsi_device *sdev, int cmd, void __user *arg case SG_SCSI_RESET: return scsi_ioctl_reset(sdev, arg); } - return -ENOIOCTLCMD; -} - -/** - * scsi_ioctl - Dispatch ioctl to scsi device - * @sdev: scsi device receiving ioctl - * @cmd: which ioctl is it - * @arg: data associated with ioctl - * - * Description: The scsi_ioctl() function differs from most ioctls in that it - * does not take a major/minor number as the dev field. Rather, it takes - * a pointer to a &struct scsi_device. - */ -int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) -{ - int ret = scsi_ioctl_common(sdev, cmd, arg); - - if (ret != -ENOIOCTLCMD) - return ret; - - if (sdev->host->hostt->ioctl) - return sdev->host->hostt->ioctl(sdev, cmd, arg); - - return -EINVAL; -} -EXPORT_SYMBOL(scsi_ioctl); #ifdef CONFIG_COMPAT -int scsi_compat_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) -{ - int ret = scsi_ioctl_common(sdev, cmd, arg); - - if (ret != -ENOIOCTLCMD) - return ret; - - if (sdev->host->hostt->compat_ioctl) + if (in_compat_syscall()) { + if (!sdev->host->hostt->compat_ioctl) + return -EINVAL; return sdev->host->hostt->compat_ioctl(sdev, cmd, arg); - - return ret; -} -EXPORT_SYMBOL(scsi_compat_ioctl); + } #endif + if (!sdev->host->hostt->ioctl) + return -EINVAL; + return sdev->host->hostt->ioctl(sdev, cmd, arg); +} +EXPORT_SYMBOL(scsi_ioctl); /* * We can process a reset even when a device isn't fully operable. diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 12faebc163ab..0b87ca01efff 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1588,8 +1588,6 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, return error; } - if (in_compat_syscall()) - return scsi_compat_ioctl(sdp, cmd, p); return scsi_ioctl(sdp, cmd, p); } diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 0a6655bad5a4..c3562c2d0dca 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1165,9 +1165,6 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) ret = sg_ioctl_common(filp, sdp, sfp, cmd_in, p); if (ret != -ENOIOCTLCMD) return ret; - - if (in_compat_syscall()) - return scsi_compat_ioctl(sdp->device, cmd_in, p); return scsi_ioctl(sdp->device, cmd_in, p); } diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index b34f06924659..c5e163a659d2 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -584,10 +584,7 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, goto put; } - if (in_compat_syscall()) - ret = scsi_compat_ioctl(sdev, cmd, argp); - else - ret = scsi_ioctl(sdev, cmd, argp); + ret = scsi_ioctl(sdev, cmd, argp); put: scsi_autopm_put_device(sdev); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index c6f14540ae03..c3fee73e018e 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -3886,7 +3886,7 @@ static long st_compat_ioctl(struct file *file, unsigned int cmd_in, unsigned lon if (ret != -ENOTTY) return ret; - return scsi_compat_ioctl(STp->device, cmd_in, p); + return scsi_ioctl(STp->device, cmd_in, p); } #endif diff --git a/include/scsi/scsi_ioctl.h b/include/scsi/scsi_ioctl.h index b465799f4d2d..cdb3ba3451e7 100644 --- a/include/scsi/scsi_ioctl.h +++ b/include/scsi/scsi_ioctl.h @@ -44,7 +44,6 @@ typedef struct scsi_fctargaddress { int scsi_ioctl_block_when_processing_errors(struct scsi_device *sdev, int cmd, bool ndelay); extern int scsi_ioctl(struct scsi_device *, int, void __user *); -extern int scsi_compat_ioctl(struct scsi_device *sdev, int cmd, void __user *arg); #endif /* __KERNEL__ */ #endif /* _SCSI_IOCTL_H */ -- cgit v1.2.3 From fb1ba406c451045f1063ace70086b4645d4e9d54 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 24 Jul 2021 09:20:18 +0200 Subject: scsi: scsi_ioctl: Remove scsi_cmd_blk_ioctl() Open code scsi_cmd_blk_ioctl() in its two callers. Link: https://lore.kernel.org/r/20210724072033.1284840-10-hch@lst.de Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- block/scsi_ioctl.c | 13 ------------- drivers/scsi/sd.c | 5 ++++- drivers/scsi/sr.c | 8 ++++++-- include/linux/blkdev.h | 2 -- 4 files changed, 10 insertions(+), 18 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index d247431a6853..f8138438c56f 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -854,19 +854,6 @@ int scsi_verify_blk_ioctl(struct block_device *bd, unsigned int cmd) } EXPORT_SYMBOL(scsi_verify_blk_ioctl); -int scsi_cmd_blk_ioctl(struct block_device *bd, fmode_t mode, - unsigned int cmd, void __user *arg) -{ - int ret; - - ret = scsi_verify_blk_ioctl(bd, cmd); - if (ret < 0) - return ret; - - return scsi_cmd_ioctl(bd->bd_disk->queue, bd->bd_disk, mode, cmd, arg); -} -EXPORT_SYMBOL(scsi_cmd_blk_ioctl); - /** * scsi_req_init - initialize certain fields of a scsi_request structure * @req: Pointer to a scsi_request structure. diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 0b87ca01efff..d65bfe505e08 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1583,7 +1583,10 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, case SCSI_IOCTL_GET_BUS_NUMBER: break; default: - error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p); + error = scsi_verify_blk_ioctl(bdev, cmd); + if (error < 0) + return error; + error = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, p); if (error != -ENOTTY) return error; } diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 7948416f40d5..b903e54c57fd 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -556,7 +556,8 @@ static void sr_block_release(struct gendisk *disk, fmode_t mode) static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, unsigned long arg) { - struct scsi_cd *cd = scsi_cd(bdev->bd_disk); + struct gendisk *disk = bdev->bd_disk; + struct scsi_cd *cd = scsi_cd(disk); struct scsi_device *sdev = cd->device; void __user *argp = (void __user *)arg; int ret; @@ -579,7 +580,10 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, case SCSI_IOCTL_GET_BUS_NUMBER: break; default: - ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); + ret = scsi_verify_blk_ioctl(bdev, cmd); + if (ret < 0) + goto put; + ret = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp); if (ret != -ENOTTY) goto put; ret = cdrom_ioctl(&cd->cdi, bdev, mode, cmd, arg); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 3177181c4326..19aa3d5429c0 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -889,8 +889,6 @@ extern blk_status_t blk_insert_cloned_request(struct request_queue *q, int blk_rq_append_bio(struct request *rq, struct bio *bio); extern void blk_queue_split(struct bio **); extern int scsi_verify_blk_ioctl(struct block_device *, unsigned int); -extern int scsi_cmd_blk_ioctl(struct block_device *, fmode_t, - unsigned int, void __user *); extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t, unsigned int, void __user *); extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t, -- cgit v1.2.3 From 4f07bfc56157ebc689ef54879e90c48a47294083 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 24 Jul 2021 09:20:19 +0200 Subject: scsi: scsi_ioctl: Remove scsi_verify_blk_ioctl() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Manually verify that the device is not a partition and the caller has admin privŃ–leges at the beginning of the sr ioctl method and open code the trivial check for sd as well. Link: https://lore.kernel.org/r/20210724072033.1284840-11-hch@lst.de Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- block/scsi_ioctl.c | 12 ------------ drivers/scsi/sd.c | 8 ++------ drivers/scsi/sr.c | 6 +++--- include/linux/blkdev.h | 1 - 4 files changed, 5 insertions(+), 22 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index f8138438c56f..ca7b84452d9d 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -842,18 +842,6 @@ int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mod } EXPORT_SYMBOL(scsi_cmd_ioctl); -int scsi_verify_blk_ioctl(struct block_device *bd, unsigned int cmd) -{ - if (bd && !bdev_is_partition(bd)) - return 0; - - if (capable(CAP_SYS_RAWIO)) - return 0; - - return -ENOIOCTLCMD; -} -EXPORT_SYMBOL(scsi_verify_blk_ioctl); - /** * scsi_req_init - initialize certain fields of a scsi_request structure * @req: Pointer to a scsi_request structure. diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index d65bfe505e08..bcc4b1339e21 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1555,9 +1555,8 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, " "cmd=0x%x\n", disk->disk_name, cmd)); - error = scsi_verify_blk_ioctl(bdev, cmd); - if (error < 0) - return error; + if (bdev_is_partition(bdev) && !capable(CAP_SYS_RAWIO)) + return -ENOIOCTLCMD; /* * If we are in the middle of error recovery, don't let anyone @@ -1583,9 +1582,6 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, case SCSI_IOCTL_GET_BUS_NUMBER: break; default: - error = scsi_verify_blk_ioctl(bdev, cmd); - if (error < 0) - return error; error = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, p); if (error != -ENOTTY) return error; diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index b903e54c57fd..e6eadba4d638 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -562,6 +562,9 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, void __user *argp = (void __user *)arg; int ret; + if (bdev_is_partition(bdev) && !capable(CAP_SYS_RAWIO)) + return -ENOIOCTLCMD; + mutex_lock(&cd->lock); ret = scsi_ioctl_block_when_processing_errors(sdev, cmd, @@ -580,9 +583,6 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, case SCSI_IOCTL_GET_BUS_NUMBER: break; default: - ret = scsi_verify_blk_ioctl(bdev, cmd); - if (ret < 0) - goto put; ret = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp); if (ret != -ENOTTY) goto put; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 19aa3d5429c0..e2b972a85012 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -888,7 +888,6 @@ extern blk_status_t blk_insert_cloned_request(struct request_queue *q, struct request *rq); int blk_rq_append_bio(struct request *rq, struct bio *bio); extern void blk_queue_split(struct bio **); -extern int scsi_verify_blk_ioctl(struct block_device *, unsigned int); extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t, unsigned int, void __user *); extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t, -- cgit v1.2.3 From 2e27f576abc6f056e63ef207b9911b1a04d07020 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 24 Jul 2021 09:20:20 +0200 Subject: scsi: scsi_ioctl: Call scsi_cmd_ioctl() from scsi_ioctl() Ensure SCSI ULD only has to call a single ioctl helper. This also adds a bunch of missing ioctls to the ch driver, and removes the need for a duplicate implementation of SCSI_IOCTL_SEND_COMMAND command. Link: https://lore.kernel.org/r/20210724072033.1284840-12-hch@lst.de Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/ch.c | 2 +- drivers/scsi/scsi_ioctl.c | 17 ++++++++++++----- drivers/scsi/sd.c | 18 +----------------- drivers/scsi/sg.c | 2 +- drivers/scsi/sr.c | 16 ++-------------- drivers/scsi/st.c | 10 +--------- include/scsi/scsi_ioctl.h | 4 +++- 7 files changed, 21 insertions(+), 48 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index e354a95c56af..27012908b586 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -877,7 +877,7 @@ static long ch_ioctl(struct file *file, } default: - return scsi_ioctl(ch->device, cmd, argp); + return scsi_ioctl(ch->device, NULL, file->f_mode, cmd, argp); } } diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 7b2e3cc85e66..7739575b5229 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -192,6 +192,8 @@ static int scsi_ioctl_get_pci(struct scsi_device *sdev, void __user *arg) /** * scsi_ioctl - Dispatch ioctl to scsi device * @sdev: scsi device receiving ioctl + * @disk: disk receiving the ioctl + * @mode: mode the block/char device is opened with * @cmd: which ioctl is it * @arg: data associated with ioctl * @@ -199,10 +201,13 @@ static int scsi_ioctl_get_pci(struct scsi_device *sdev, void __user *arg) * does not take a major/minor number as the dev field. Rather, it takes * a pointer to a &struct scsi_device. */ -int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) +int scsi_ioctl(struct scsi_device *sdev, struct gendisk *disk, fmode_t mode, + int cmd, void __user *arg) { + struct request_queue *q = sdev->request_queue; char scsi_cmd[MAX_COMMAND_SIZE]; struct scsi_sense_hdr sense_hdr; + int error; /* Check for deprecated ioctls ... all the ioctls which don't * follow the new unique numbering scheme are deprecated */ @@ -220,6 +225,12 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) break; } + if (cmd != SCSI_IOCTL_GET_IDLUN && cmd != SCSI_IOCTL_GET_BUS_NUMBER) { + error = scsi_cmd_ioctl(q, disk, mode, cmd, arg); + if (error != -ENOTTY) + return error; + } + switch (cmd) { case SCSI_IOCTL_GET_IDLUN: { struct scsi_idlun v = { @@ -237,10 +248,6 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) return put_user(sdev->host->host_no, (int __user *)arg); case SCSI_IOCTL_PROBE_HOST: return ioctl_probe(sdev->host, arg); - case SCSI_IOCTL_SEND_COMMAND: - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) - return -EACCES; - return sg_scsi_ioctl(sdev->request_queue, NULL, 0, arg); case SCSI_IOCTL_DOORLOCK: return scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); case SCSI_IOCTL_DOORUNLOCK: diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index bcc4b1339e21..c1b75f159e0c 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1571,23 +1571,7 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, if (is_sed_ioctl(cmd)) return sed_ioctl(sdkp->opal_dev, cmd, p); - - /* - * Send SCSI addressing ioctls directly to mid level, send other - * ioctls to block level and then onto mid level if they can't be - * resolved. - */ - switch (cmd) { - case SCSI_IOCTL_GET_IDLUN: - case SCSI_IOCTL_GET_BUS_NUMBER: - break; - default: - error = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, p); - if (error != -ENOTTY) - return error; - } - - return scsi_ioctl(sdp, cmd, p); + return scsi_ioctl(sdp, disk, mode, cmd, p); } static void set_media_not_present(struct scsi_disk *sdkp) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index c3562c2d0dca..6cb1e4b6eac2 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1165,7 +1165,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) ret = sg_ioctl_common(filp, sdp, sfp, cmd_in, p); if (ret != -ENOIOCTLCMD) return ret; - return scsi_ioctl(sdp->device, cmd_in, p); + return scsi_ioctl(sdp->device, NULL, filp->f_mode, cmd_in, p); } static __poll_t diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index e6eadba4d638..b98e77fe700b 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -574,24 +574,12 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, scsi_autopm_get_device(sdev); - /* - * Send SCSI addressing ioctls directly to mid level, send other - * ioctls to cdrom/block level. - */ - switch (cmd) { - case SCSI_IOCTL_GET_IDLUN: - case SCSI_IOCTL_GET_BUS_NUMBER: - break; - default: - ret = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp); - if (ret != -ENOTTY) - goto put; + if (ret != CDROMCLOSETRAY && ret != CDROMEJECT) { ret = cdrom_ioctl(&cd->cdi, bdev, mode, cmd, arg); if (ret != -ENOSYS) goto put; } - - ret = scsi_ioctl(sdev, cmd, argp); + ret = scsi_ioctl(sdev, disk, mode, cmd, argp); put: scsi_autopm_put_device(sdev); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 9274f665bc0f..2d1b0594af69 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -3823,24 +3823,16 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) mutex_unlock(&STp->lock); switch (cmd_in) { - case SCSI_IOCTL_GET_IDLUN: - case SCSI_IOCTL_GET_BUS_NUMBER: - break; case SG_IO: case SCSI_IOCTL_SEND_COMMAND: case CDROM_SEND_PACKET: if (!capable(CAP_SYS_RAWIO)) return -EPERM; - fallthrough; default: - retval = scsi_cmd_ioctl(STp->disk->queue, STp->disk, - file->f_mode, cmd_in, p); - if (retval != -ENOTTY) - return retval; break; } - retval = scsi_ioctl(STp->device, cmd_in, p); + retval = scsi_ioctl(STp->device, STp->disk, file->f_mode, cmd_in, p); if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) { /* unload */ STp->rew_at_close = 0; diff --git a/include/scsi/scsi_ioctl.h b/include/scsi/scsi_ioctl.h index cdb3ba3451e7..defbe8084eb8 100644 --- a/include/scsi/scsi_ioctl.h +++ b/include/scsi/scsi_ioctl.h @@ -18,6 +18,7 @@ #ifdef __KERNEL__ +struct gendisk; struct scsi_device; /* @@ -43,7 +44,8 @@ typedef struct scsi_fctargaddress { int scsi_ioctl_block_when_processing_errors(struct scsi_device *sdev, int cmd, bool ndelay); -extern int scsi_ioctl(struct scsi_device *, int, void __user *); +int scsi_ioctl(struct scsi_device *sdev, struct gendisk *disk, fmode_t mode, + int cmd, void __user *arg); #endif /* __KERNEL__ */ #endif /* _SCSI_IOCTL_H */ -- cgit v1.2.3 From 5999ccff0fd664e0dac0fe0093b9a5962161d636 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 9 Aug 2021 16:03:06 -0700 Subject: scsi: sd: Use scsi_cmd_to_rq() instead of scsi_cmnd.request Prepare for removal of the request pointer by using scsi_cmd_to_rq() instead. This patch does not change any functionality. Link: https://lore.kernel.org/r/20210809230355.8186-4-bvanassche@acm.org Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Ming Lei Reviewed-by: Hannes Reinecke Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 33 +++++++++++++++++---------------- drivers/scsi/sd_zbc.c | 10 +++++----- 2 files changed, 22 insertions(+), 21 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index c1b75f159e0c..ac431b0477da 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -776,8 +776,9 @@ static unsigned int sd_prot_flag_mask(unsigned int prot_op) static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd, unsigned int dix, unsigned int dif) { - struct bio *bio = scmd->request->bio; - unsigned int prot_op = sd_prot_op(rq_data_dir(scmd->request), dix, dif); + struct request *rq = scsi_cmd_to_rq(scmd); + struct bio *bio = rq->bio; + unsigned int prot_op = sd_prot_op(rq_data_dir(rq), dix, dif); unsigned int protect = 0; if (dix) { /* DIX Type 0, 1, 2, 3 */ @@ -868,7 +869,7 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) static blk_status_t sd_setup_unmap_cmnd(struct scsi_cmnd *cmd) { struct scsi_device *sdp = cmd->device; - struct request *rq = cmd->request; + struct request *rq = scsi_cmd_to_rq(cmd); struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); u64 lba = sectors_to_logical(sdp, blk_rq_pos(rq)); u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq)); @@ -904,7 +905,7 @@ static blk_status_t sd_setup_write_same16_cmnd(struct scsi_cmnd *cmd, bool unmap) { struct scsi_device *sdp = cmd->device; - struct request *rq = cmd->request; + struct request *rq = scsi_cmd_to_rq(cmd); struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); u64 lba = sectors_to_logical(sdp, blk_rq_pos(rq)); u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq)); @@ -936,7 +937,7 @@ static blk_status_t sd_setup_write_same10_cmnd(struct scsi_cmnd *cmd, bool unmap) { struct scsi_device *sdp = cmd->device; - struct request *rq = cmd->request; + struct request *rq = scsi_cmd_to_rq(cmd); struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); u64 lba = sectors_to_logical(sdp, blk_rq_pos(rq)); u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq)); @@ -966,7 +967,7 @@ static blk_status_t sd_setup_write_same10_cmnd(struct scsi_cmnd *cmd, static blk_status_t sd_setup_write_zeroes_cmnd(struct scsi_cmnd *cmd) { - struct request *rq = cmd->request; + struct request *rq = scsi_cmd_to_rq(cmd); struct scsi_device *sdp = cmd->device; struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); u64 lba = sectors_to_logical(sdp, blk_rq_pos(rq)); @@ -1063,7 +1064,7 @@ out: **/ static blk_status_t sd_setup_write_same_cmnd(struct scsi_cmnd *cmd) { - struct request *rq = cmd->request; + struct request *rq = scsi_cmd_to_rq(cmd); struct scsi_device *sdp = cmd->device; struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); struct bio *bio = rq->bio; @@ -1112,7 +1113,7 @@ static blk_status_t sd_setup_write_same_cmnd(struct scsi_cmnd *cmd) static blk_status_t sd_setup_flush_cmnd(struct scsi_cmnd *cmd) { - struct request *rq = cmd->request; + struct request *rq = scsi_cmd_to_rq(cmd); struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); /* flush requests don't perform I/O, zero the S/G table */ @@ -1210,7 +1211,7 @@ static blk_status_t sd_setup_rw6_cmnd(struct scsi_cmnd *cmd, bool write, static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd) { - struct request *rq = cmd->request; + struct request *rq = scsi_cmd_to_rq(cmd); struct scsi_device *sdp = cmd->device; struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); sector_t lba = sectors_to_logical(sdp, blk_rq_pos(rq)); @@ -1324,7 +1325,7 @@ fail: static blk_status_t sd_init_command(struct scsi_cmnd *cmd) { - struct request *rq = cmd->request; + struct request *rq = scsi_cmd_to_rq(cmd); switch (req_op(rq)) { case REQ_OP_DISCARD: @@ -1370,7 +1371,7 @@ static blk_status_t sd_init_command(struct scsi_cmnd *cmd) static void sd_uninit_command(struct scsi_cmnd *SCpnt) { - struct request *rq = SCpnt->request; + struct request *rq = scsi_cmd_to_rq(SCpnt); u8 *cmnd; if (rq->rq_flags & RQF_SPECIAL_PAYLOAD) @@ -1875,7 +1876,7 @@ static const struct block_device_operations sd_fops = { **/ static void sd_eh_reset(struct scsi_cmnd *scmd) { - struct scsi_disk *sdkp = scsi_disk(scmd->request->rq_disk); + struct scsi_disk *sdkp = scsi_disk(scsi_cmd_to_rq(scmd)->rq_disk); /* New SCSI EH run, reset gate variable */ sdkp->ignore_medium_access_errors = false; @@ -1895,7 +1896,7 @@ static void sd_eh_reset(struct scsi_cmnd *scmd) **/ static int sd_eh_action(struct scsi_cmnd *scmd, int eh_disp) { - struct scsi_disk *sdkp = scsi_disk(scmd->request->rq_disk); + struct scsi_disk *sdkp = scsi_disk(scsi_cmd_to_rq(scmd)->rq_disk); struct scsi_device *sdev = scmd->device; if (!scsi_device_online(sdev) || @@ -1936,7 +1937,7 @@ static int sd_eh_action(struct scsi_cmnd *scmd, int eh_disp) static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd) { - struct request *req = scmd->request; + struct request *req = scsi_cmd_to_rq(scmd); struct scsi_device *sdev = scmd->device; unsigned int transferred, good_bytes; u64 start_lba, end_lba, bad_lba; @@ -1991,8 +1992,8 @@ static int sd_done(struct scsi_cmnd *SCpnt) unsigned int sector_size = SCpnt->device->sector_size; unsigned int resid; struct scsi_sense_hdr sshdr; - struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk); - struct request *req = SCpnt->request; + struct request *req = scsi_cmd_to_rq(SCpnt); + struct scsi_disk *sdkp = scsi_disk(req->rq_disk); int sense_valid = 0; int sense_deferred = 0; diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 186b5ff52c3a..b9757f24b0d6 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -243,7 +243,7 @@ out: static blk_status_t sd_zbc_cmnd_checks(struct scsi_cmnd *cmd) { - struct request *rq = cmd->request; + struct request *rq = scsi_cmd_to_rq(cmd); struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); sector_t sector = blk_rq_pos(rq); @@ -321,7 +321,7 @@ static void sd_zbc_update_wp_offset_workfn(struct work_struct *work) blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd, sector_t *lba, unsigned int nr_blocks) { - struct request *rq = cmd->request; + struct request *rq = scsi_cmd_to_rq(cmd); struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); unsigned int wp_offset, zno = blk_rq_zone_no(rq); unsigned long flags; @@ -386,7 +386,7 @@ blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd, sector_t *lba, blk_status_t sd_zbc_setup_zone_mgmt_cmnd(struct scsi_cmnd *cmd, unsigned char op, bool all) { - struct request *rq = cmd->request; + struct request *rq = scsi_cmd_to_rq(cmd); sector_t sector = blk_rq_pos(rq); struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); sector_t block = sectors_to_logical(sdkp->device, sector); @@ -442,7 +442,7 @@ static unsigned int sd_zbc_zone_wp_update(struct scsi_cmnd *cmd, unsigned int good_bytes) { int result = cmd->result; - struct request *rq = cmd->request; + struct request *rq = scsi_cmd_to_rq(cmd); struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); unsigned int zno = blk_rq_zone_no(rq); enum req_opf op = req_op(rq); @@ -516,7 +516,7 @@ unsigned int sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes, struct scsi_sense_hdr *sshdr) { int result = cmd->result; - struct request *rq = cmd->request; + struct request *rq = scsi_cmd_to_rq(cmd); if (op_is_zone_mgmt(req_op(rq)) && result && -- cgit v1.2.3 From 848ade90ba9c1e2bc2f7869fbe5d08bb32f3db09 Mon Sep 17 00:00:00 2001 From: Christian Loehle Date: Mon, 16 Aug 2021 09:37:51 +0000 Subject: scsi: sd: Do not exit sd_spinup_disk() quietly The sd_spinup_disk() function logs what is happening. Unfortunately this output stops if the media was marked as removed in the meantime. Add a print for this case too. Link: https://lore.kernel.org/r/CWXP265MB26803209FD08A64222EEEA02C4FD9@CWXP265MB2680.GBRP265.PROD.OUTLOOK.COM Reviewed-by: Bart Van Assche Signed-off-by: Christian Loehle Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index ac431b0477da..920df3a04a7b 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2136,8 +2136,10 @@ sd_spinup_disk(struct scsi_disk *sdkp) * doesn't have any media in it, don't bother * with any more polling. */ - if (media_not_present(sdkp, &sshdr)) + if (media_not_present(sdkp, &sshdr)) { + sd_printk(KERN_NOTICE, sdkp, "Media removed, stopped polling\n"); return; + } if (the_result) sense_valid = scsi_sense_valid(&sshdr); -- cgit v1.2.3