From 176aa9d6ee2db582e7e856dbe1983004a82869b4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 11 Oct 2014 12:06:47 +0200 Subject: [PATCH] scsi: refactor scsi_reset_provider handling Pull the common code from the two callers into the function, and rename it to scsi_ioctl_reset. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke --- drivers/scsi/scsi_error.c | 76 +++++++++++++++++++-------------------- drivers/scsi/scsi_ioctl.c | 33 +---------------- drivers/scsi/sg.c | 34 ++---------------- include/scsi/scsi_eh.h | 15 +------- 4 files changed, 41 insertions(+), 117 deletions(-) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 95c9abb64183..a6f6b9222b51 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "scsi_priv.h" #include "scsi_logging.h" @@ -2311,39 +2312,36 @@ scsi_reset_provider_done_command(struct scsi_cmnd *scmd) { } -/* - * Function: scsi_reset_provider - * - * Purpose: Send requested reset to a bus or device at any phase. - * - * Arguments: device - device to send reset to - * flag - reset type (see scsi.h) - * - * Returns: SUCCESS/FAILURE. - * - * Notes: This is used by the SCSI Generic driver to provide - * Bus/Device reset capability. +/** + * scsi_ioctl_reset: explicitly reset a host/bus/target/device + * @dev: scsi_device to operate on + * @arg: reset type (see sg.h) */ int -scsi_reset_provider(struct scsi_device *dev, int flag) +scsi_ioctl_reset(struct scsi_device *dev, int __user *arg) { struct scsi_cmnd *scmd; struct Scsi_Host *shost = dev->host; struct request req; unsigned long flags; - int rtn; + int error = 0, rtn, val; + + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + + error = get_user(val, arg); + if (error) + return error; if (scsi_autopm_get_host(shost) < 0) - return FAILED; + return -EIO; - if (!get_device(&dev->sdev_gendev)) { - rtn = FAILED; + error = -EIO; + if (!get_device(&dev->sdev_gendev)) goto out_put_autopm_host; - } scmd = scsi_get_command(dev, GFP_KERNEL); if (!scmd) { - rtn = FAILED; put_device(&dev->sdev_gendev); goto out_put_autopm_host; } @@ -2364,39 +2362,37 @@ scsi_reset_provider(struct scsi_device *dev, int flag) shost->tmf_in_progress = 1; spin_unlock_irqrestore(shost->host_lock, flags); - switch (flag) { - case SCSI_TRY_RESET_DEVICE: + switch (val & ~SG_SCSI_RESET_NO_ESCALATE) { + case SG_SCSI_RESET_NOTHING: + rtn = SUCCESS; + break; + case SG_SCSI_RESET_DEVICE: rtn = scsi_try_bus_device_reset(scmd); - if (rtn == SUCCESS) + if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE)) break; /* FALLTHROUGH */ - case SCSI_TRY_RESET_TARGET: + case SG_SCSI_RESET_TARGET: rtn = scsi_try_target_reset(scmd); - if (rtn == SUCCESS) + if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE)) break; /* FALLTHROUGH */ - case SCSI_TRY_RESET_BUS: + case SG_SCSI_RESET_BUS: rtn = scsi_try_bus_reset(scmd); - if (rtn == SUCCESS) + if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE)) break; /* FALLTHROUGH */ - case SCSI_TRY_RESET_HOST: - case SCSI_TRY_RESET_HOST | SCSI_TRY_RESET_NO_ESCALATE: + case SG_SCSI_RESET_HOST: rtn = scsi_try_host_reset(scmd); - break; - case SCSI_TRY_RESET_DEVICE | SCSI_TRY_RESET_NO_ESCALATE: - rtn = scsi_try_bus_device_reset(scmd); - break; - case SCSI_TRY_RESET_TARGET | SCSI_TRY_RESET_NO_ESCALATE: - rtn = scsi_try_target_reset(scmd); - break; - case SCSI_TRY_RESET_BUS | SCSI_TRY_RESET_NO_ESCALATE: - rtn = scsi_try_bus_reset(scmd); - break; + if (rtn == SUCCESS) + break; default: + /* FALLTHROUGH */ rtn = FAILED; + break; } + error = (rtn == SUCCESS) ? 0 : -EIO; + spin_lock_irqsave(shost->host_lock, flags); shost->tmf_in_progress = 0; spin_unlock_irqrestore(shost->host_lock, flags); @@ -2416,9 +2412,9 @@ scsi_reset_provider(struct scsi_device *dev, int flag) scsi_next_command(scmd); out_put_autopm_host: scsi_autopm_put_host(shost); - return rtn; + return error; } -EXPORT_SYMBOL(scsi_reset_provider); +EXPORT_SYMBOL(scsi_ioctl_reset); /** * scsi_normalize_sense - normalize main elements from either fixed or diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 5207274574f5..5ddc08f39987 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -292,8 +292,6 @@ EXPORT_SYMBOL(scsi_ioctl); int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, void __user *arg, int ndelay) { - int val, val2, result; - /* The first set of iocts may be executed even if we're doing * error processing, as long as the device was opened * non-blocking */ @@ -305,36 +303,7 @@ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, switch (cmd) { case SG_SCSI_RESET: - result = get_user(val, (int __user *)arg); - if (result) - return result; - if (val & SG_SCSI_RESET_NO_ESCALATE) { - val &= ~SG_SCSI_RESET_NO_ESCALATE; - val2 = SCSI_TRY_RESET_NO_ESCALATE; - } else - val2 = 0; - if (val == SG_SCSI_RESET_NOTHING) - return 0; - switch (val) { - case SG_SCSI_RESET_DEVICE: - val2 |= SCSI_TRY_RESET_DEVICE; - break; - case SG_SCSI_RESET_TARGET: - val2 |= SCSI_TRY_RESET_TARGET; - break; - case SG_SCSI_RESET_BUS: - val2 |= SCSI_TRY_RESET_BUS; - break; - case SG_SCSI_RESET_HOST: - val2 |= SCSI_TRY_RESET_HOST; - break; - default: - return -EINVAL; - } - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) - return -EACCES; - return (scsi_reset_provider(sdev, val2) == - SUCCESS) ? 0 : -EIO; + return scsi_ioctl_reset(sdev, arg); } return -ENODEV; } diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 2fe2701d86db..7c55cacceb7c 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -847,7 +847,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) { void __user *p = (void __user *)arg; int __user *ip = p; - int result, val, val2, read_only; + int result, val, read_only; Sg_device *sdp; Sg_fd *sfp; Sg_request *srp; @@ -1079,36 +1079,8 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) return -EBUSY; } else if (!scsi_block_when_processing_errors(sdp->device)) return -EBUSY; - result = get_user(val, ip); - if (result) - return result; - if (val & SG_SCSI_RESET_NO_ESCALATE) { - val &= ~SG_SCSI_RESET_NO_ESCALATE; - val2 = SCSI_TRY_RESET_NO_ESCALATE; - } else - val2 = 0; - if (SG_SCSI_RESET_NOTHING == val) - return 0; - switch (val) { - case SG_SCSI_RESET_DEVICE: - val2 |= SCSI_TRY_RESET_DEVICE; - break; - case SG_SCSI_RESET_TARGET: - val2 |= SCSI_TRY_RESET_TARGET; - break; - case SG_SCSI_RESET_BUS: - val2 |= SCSI_TRY_RESET_BUS; - break; - case SG_SCSI_RESET_HOST: - val2 |= SCSI_TRY_RESET_HOST; - break; - default: - return -EINVAL; - } - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) - return -EACCES; - return (scsi_reset_provider(sdp->device, val2) == - SUCCESS) ? 0 : -EIO; + + return scsi_ioctl_reset(sdp->device, ip); case SCSI_IOCTL_SEND_COMMAND: if (atomic_read(&sdp->detaching)) return -ENODEV; diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h index 256248141322..1e1421b06565 100644 --- a/include/scsi/scsi_eh.h +++ b/include/scsi/scsi_eh.h @@ -60,20 +60,7 @@ extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len, extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq); -/* - * Reset request from external source - * Note: if SCSI_TRY_RESET_DEVICE fails then it will escalate to - * SCSI_TRY_RESET_TARGET which if it fails will escalate to - * SCSI_TRY_RESET_BUS which if it fails will escalate to SCSI_TRY_RESET_HOST. - * To prevent escalation OR with SCSI_TRY_RESET_NO_ESCALATE. - */ -#define SCSI_TRY_RESET_DEVICE 1 -#define SCSI_TRY_RESET_BUS 2 -#define SCSI_TRY_RESET_HOST 3 -#define SCSI_TRY_RESET_TARGET 4 -#define SCSI_TRY_RESET_NO_ESCALATE 0x100 /* OR-ed to prior defines */ - -extern int scsi_reset_provider(struct scsi_device *, int); +extern int scsi_ioctl_reset(struct scsi_device *, int __user *); struct scsi_eh_save { /* saved state */