Commit 176aa9d6 authored by Christoph Hellwig's avatar Christoph Hellwig

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: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
parent 1ee8e889
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <scsi/scsi_transport.h> #include <scsi/scsi_transport.h>
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h> #include <scsi/scsi_ioctl.h>
#include <scsi/sg.h>
#include "scsi_priv.h" #include "scsi_priv.h"
#include "scsi_logging.h" #include "scsi_logging.h"
...@@ -2311,39 +2312,36 @@ scsi_reset_provider_done_command(struct scsi_cmnd *scmd) ...@@ -2311,39 +2312,36 @@ scsi_reset_provider_done_command(struct scsi_cmnd *scmd)
{ {
} }
/* /**
* Function: scsi_reset_provider * scsi_ioctl_reset: explicitly reset a host/bus/target/device
* * @dev: scsi_device to operate on
* Purpose: Send requested reset to a bus or device at any phase. * @arg: reset type (see sg.h)
*
* 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.
*/ */
int 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_cmnd *scmd;
struct Scsi_Host *shost = dev->host; struct Scsi_Host *shost = dev->host;
struct request req; struct request req;
unsigned long flags; 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) if (scsi_autopm_get_host(shost) < 0)
return FAILED; return -EIO;
if (!get_device(&dev->sdev_gendev)) { error = -EIO;
rtn = FAILED; if (!get_device(&dev->sdev_gendev))
goto out_put_autopm_host; goto out_put_autopm_host;
}
scmd = scsi_get_command(dev, GFP_KERNEL); scmd = scsi_get_command(dev, GFP_KERNEL);
if (!scmd) { if (!scmd) {
rtn = FAILED;
put_device(&dev->sdev_gendev); put_device(&dev->sdev_gendev);
goto out_put_autopm_host; goto out_put_autopm_host;
} }
...@@ -2364,39 +2362,37 @@ scsi_reset_provider(struct scsi_device *dev, int flag) ...@@ -2364,39 +2362,37 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
shost->tmf_in_progress = 1; shost->tmf_in_progress = 1;
spin_unlock_irqrestore(shost->host_lock, flags); spin_unlock_irqrestore(shost->host_lock, flags);
switch (flag) { switch (val & ~SG_SCSI_RESET_NO_ESCALATE) {
case SCSI_TRY_RESET_DEVICE: case SG_SCSI_RESET_NOTHING:
rtn = SUCCESS;
break;
case SG_SCSI_RESET_DEVICE:
rtn = scsi_try_bus_device_reset(scmd); rtn = scsi_try_bus_device_reset(scmd);
if (rtn == SUCCESS) if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE))
break; break;
/* FALLTHROUGH */ /* FALLTHROUGH */
case SCSI_TRY_RESET_TARGET: case SG_SCSI_RESET_TARGET:
rtn = scsi_try_target_reset(scmd); rtn = scsi_try_target_reset(scmd);
if (rtn == SUCCESS) if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE))
break; break;
/* FALLTHROUGH */ /* FALLTHROUGH */
case SCSI_TRY_RESET_BUS: case SG_SCSI_RESET_BUS:
rtn = scsi_try_bus_reset(scmd); rtn = scsi_try_bus_reset(scmd);
if (rtn == SUCCESS) if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE))
break; break;
/* FALLTHROUGH */ /* FALLTHROUGH */
case SCSI_TRY_RESET_HOST: case SG_SCSI_RESET_HOST:
case SCSI_TRY_RESET_HOST | SCSI_TRY_RESET_NO_ESCALATE:
rtn = scsi_try_host_reset(scmd); rtn = scsi_try_host_reset(scmd);
break; if (rtn == SUCCESS)
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; break;
default: default:
/* FALLTHROUGH */
rtn = FAILED; rtn = FAILED;
break;
} }
error = (rtn == SUCCESS) ? 0 : -EIO;
spin_lock_irqsave(shost->host_lock, flags); spin_lock_irqsave(shost->host_lock, flags);
shost->tmf_in_progress = 0; shost->tmf_in_progress = 0;
spin_unlock_irqrestore(shost->host_lock, flags); spin_unlock_irqrestore(shost->host_lock, flags);
...@@ -2416,9 +2412,9 @@ scsi_reset_provider(struct scsi_device *dev, int flag) ...@@ -2416,9 +2412,9 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
scsi_next_command(scmd); scsi_next_command(scmd);
out_put_autopm_host: out_put_autopm_host:
scsi_autopm_put_host(shost); 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 * scsi_normalize_sense - normalize main elements from either fixed or
......
...@@ -292,8 +292,6 @@ EXPORT_SYMBOL(scsi_ioctl); ...@@ -292,8 +292,6 @@ EXPORT_SYMBOL(scsi_ioctl);
int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
void __user *arg, int ndelay) void __user *arg, int ndelay)
{ {
int val, val2, result;
/* The first set of iocts may be executed even if we're doing /* The first set of iocts may be executed even if we're doing
* error processing, as long as the device was opened * error processing, as long as the device was opened
* non-blocking */ * non-blocking */
...@@ -305,36 +303,7 @@ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, ...@@ -305,36 +303,7 @@ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
switch (cmd) { switch (cmd) {
case SG_SCSI_RESET: case SG_SCSI_RESET:
result = get_user(val, (int __user *)arg); return scsi_ioctl_reset(sdev, 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 -ENODEV; return -ENODEV;
} }
......
...@@ -847,7 +847,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) ...@@ -847,7 +847,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
{ {
void __user *p = (void __user *)arg; void __user *p = (void __user *)arg;
int __user *ip = p; int __user *ip = p;
int result, val, val2, read_only; int result, val, read_only;
Sg_device *sdp; Sg_device *sdp;
Sg_fd *sfp; Sg_fd *sfp;
Sg_request *srp; Sg_request *srp;
...@@ -1079,36 +1079,8 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) ...@@ -1079,36 +1079,8 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
return -EBUSY; return -EBUSY;
} else if (!scsi_block_when_processing_errors(sdp->device)) } else if (!scsi_block_when_processing_errors(sdp->device))
return -EBUSY; return -EBUSY;
result = get_user(val, ip);
if (result) return scsi_ioctl_reset(sdp->device, ip);
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;
case SCSI_IOCTL_SEND_COMMAND: case SCSI_IOCTL_SEND_COMMAND:
if (atomic_read(&sdp->detaching)) if (atomic_read(&sdp->detaching))
return -ENODEV; return -ENODEV;
......
...@@ -60,20 +60,7 @@ extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len, ...@@ -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); extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq);
/* extern int scsi_ioctl_reset(struct scsi_device *, int __user *);
* 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);
struct scsi_eh_save { struct scsi_eh_save {
/* saved state */ /* saved state */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment