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 <hch@lst.de> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> Reviewed-by: Hannes Reinecke <hare@suse.de>
This commit is contained in:
Родитель
1ee8e889d9
Коммит
176aa9d6ee
|
@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* 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)
|
||||||
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:
|
break;
|
||||||
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;
|
|
||||||
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)
|
||||||
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);
|
||||||
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,
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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,
|
||||||
|
|
||||||
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 */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче