Commit 0ed32242 authored by James Bottomley's avatar James Bottomley Committed by James Bottomley

scsi: Add reset ioctl capability to ULDs

Currently, the only way to issue a SCSI reset of any
type is to use the sg device.  By adding extra ioctls
to scsi_ioctl.c we enable this for all ULDs.

The slight complication is that scsi_ioctl() is usually
only called when the device has been checked not to be
undergoing eh recovery.  Resets may be issued in
this scenario if the user opens the device O_NONBLOCK.
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 89f88233
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h> #include <scsi/scsi_ioctl.h>
#include <scsi/scsi_request.h> #include <scsi/scsi_request.h>
#include <scsi/sg.h>
#include "scsi_logging.h" #include "scsi_logging.h"
...@@ -456,3 +457,51 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) ...@@ -456,3 +457,51 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
} }
return -EINVAL; return -EINVAL;
} }
/*
* the scsi_nonblock_ioctl() function is designed for ioctls which may
* be executed even if the device is in recovery.
*/
int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
void __user *arg, struct file *filp)
{
int val, 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 */
if (filp && filp->f_flags & O_NONBLOCK) {
if (test_bit(SHOST_RECOVERY,
&sdev->host->shost_state))
return -ENODEV;
} else if (!scsi_block_when_processing_errors(sdev))
return -ENODEV;
switch (cmd) {
case SG_SCSI_RESET:
result = get_user(val, (int __user *)arg);
if (result)
return result;
if (val == SG_SCSI_RESET_NOTHING)
return 0;
switch (val) {
case SG_SCSI_RESET_DEVICE:
val = SCSI_TRY_RESET_DEVICE;
break;
case SG_SCSI_RESET_BUS:
val = SCSI_TRY_RESET_BUS;
break;
case SG_SCSI_RESET_HOST:
val = SCSI_TRY_RESET_HOST;
break;
default:
return -EINVAL;
}
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
return -EACCES;
return (scsi_reset_provider(sdev, val) ==
SUCCESS) ? 0 : -EIO;
}
return -ENODEV;
}
EXPORT_SYMBOL(scsi_nonblockable_ioctl);
...@@ -574,8 +574,9 @@ static int sd_ioctl(struct inode * inode, struct file * filp, ...@@ -574,8 +574,9 @@ static int sd_ioctl(struct inode * inode, struct file * filp,
* may try and take the device offline, in which case all further * may try and take the device offline, in which case all further
* access to the device is prohibited. * access to the device is prohibited.
*/ */
if (!scsi_block_when_processing_errors(sdp)) error = scsi_nonblockable_ioctl(sdp, cmd, p, filp);
return -ENODEV; if (!scsi_block_when_processing_errors(sdp) || !error)
return error;
if (cmd == HDIO_GETGEO) { if (cmd == HDIO_GETGEO) {
if (!arg) if (!arg)
......
...@@ -549,5 +549,17 @@ int sr_dev_ioctl(struct cdrom_device_info *cdi, ...@@ -549,5 +549,17 @@ int sr_dev_ioctl(struct cdrom_device_info *cdi,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
Scsi_CD *cd = cdi->handle; Scsi_CD *cd = cdi->handle;
int ret;
ret = scsi_nonblockable_ioctl(cd->device, cmd,
(void __user *)arg, NULL);
/*
* ENODEV means that we didn't recognise the ioctl, or that we
* cannot execute it in the current device state. In either
* case fall through to scsi_ioctl, which will return ENDOEV again
* if it doesn't recognise the ioctl
*/
if (ret != -ENODEV)
return ret;
return scsi_ioctl(cd->device, cmd, (void __user *)arg); return scsi_ioctl(cd->device, cmd, (void __user *)arg);
} }
...@@ -3128,10 +3128,10 @@ static int st_ioctl(struct inode *inode, struct file *file, ...@@ -3128,10 +3128,10 @@ static int st_ioctl(struct inode *inode, struct file *file,
* may try and take the device offline, in which case all further * may try and take the device offline, in which case all further
* access to the device is prohibited. * access to the device is prohibited.
*/ */
if (!scsi_block_when_processing_errors(STp->device)) { retval = scsi_nonblockable_ioctl(STp->device, cmd_in, p, file);
retval = (-ENXIO); if (!scsi_block_when_processing_errors(STp->device) || !retval)
goto out; goto out;
}
cmd_type = _IOC_TYPE(cmd_in); cmd_type = _IOC_TYPE(cmd_in);
cmd_nr = _IOC_NR(cmd_in); cmd_nr = _IOC_NR(cmd_in);
......
...@@ -43,6 +43,8 @@ typedef struct scsi_fctargaddress { ...@@ -43,6 +43,8 @@ typedef struct scsi_fctargaddress {
extern int scsi_ioctl(struct scsi_device *, int, void __user *); extern int scsi_ioctl(struct scsi_device *, int, void __user *);
extern int scsi_ioctl_send_command(struct scsi_device *, extern int scsi_ioctl_send_command(struct scsi_device *,
struct scsi_ioctl_command __user *); struct scsi_ioctl_command __user *);
extern int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
void __user *arg, struct file *filp);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _SCSI_IOCTL_H */ #endif /* _SCSI_IOCTL_H */
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