break;
/* FALLTHROUGH */
case SCSI_TRY_RESET_HOST:
+ case SCSI_TRY_RESET_HOST | SCSI_TRY_RESET_NO_ESCALATE:
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;
default:
rtn = FAILED;
}
* scsi_nonblockable_ioctl() - Handle SG_SCSI_RESET
* @sdev: scsi device receiving ioctl
* @cmd: Must be SC_SCSI_RESET
- * @arg: pointer to int containing SG_SCSI_RESET_{DEVICE,BUS,HOST}
+ * @arg: pointer to int containing SG_SCSI_RESET_{DEVICE,TARGET,BUS,HOST}
+ * possibly OR-ed with SG_SCSI_RESET_NO_ESCALATE
* @ndelay: file mode O_NDELAY flag
*/
int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
void __user *arg, int ndelay)
{
- int val, result;
+ 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
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:
- val = SCSI_TRY_RESET_DEVICE;
+ val2 |= SCSI_TRY_RESET_DEVICE;
break;
case SG_SCSI_RESET_TARGET:
- val = SCSI_TRY_RESET_TARGET;
+ val2 |= SCSI_TRY_RESET_TARGET;
break;
case SG_SCSI_RESET_BUS:
- val = SCSI_TRY_RESET_BUS;
+ val2 |= SCSI_TRY_RESET_BUS;
break;
case SG_SCSI_RESET_HOST:
- val = SCSI_TRY_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, val) ==
+ return (scsi_reset_provider(sdev, val2) ==
SUCCESS) ? 0 : -EIO;
}
return -ENODEV;
{
void __user *p = (void __user *)arg;
int __user *ip = p;
- int result, val, read_only;
+ int result, val, val2, read_only;
Sg_device *sdp;
Sg_fd *sfp;
Sg_request *srp;
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:
- val = SCSI_TRY_RESET_DEVICE;
+ val2 |= SCSI_TRY_RESET_DEVICE;
break;
case SG_SCSI_RESET_TARGET:
- val = SCSI_TRY_RESET_TARGET;
+ val2 |= SCSI_TRY_RESET_TARGET;
break;
case SG_SCSI_RESET_BUS:
- val = SCSI_TRY_RESET_BUS;
+ val2 |= SCSI_TRY_RESET_BUS;
break;
case SG_SCSI_RESET_HOST:
- val = SCSI_TRY_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, val) ==
+ return (scsi_reset_provider(sdp->device, val2) ==
SUCCESS) ? 0 : -EIO;
case SCSI_IOCTL_SEND_COMMAND:
if (atomic_read(&sdp->detaching))
/*
* 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);
/* Returns -EBUSY if occupied. 3rd argument pointer to int (see next) */
#define SG_SCSI_RESET 0x2284
-/* Associated values that can be given to SG_SCSI_RESET follow */
+/* Associated values that can be given to SG_SCSI_RESET follow.
+ * SG_SCSI_RESET_NO_ESCALATE may be OR-ed to the _DEVICE, _TARGET, _BUS
+ * or _HOST reset value so only that action is attempted. */
#define SG_SCSI_RESET_NOTHING 0
#define SG_SCSI_RESET_DEVICE 1
#define SG_SCSI_RESET_BUS 2
#define SG_SCSI_RESET_HOST 3
#define SG_SCSI_RESET_TARGET 4
+#define SG_SCSI_RESET_NO_ESCALATE 0x100
/* synchronous SCSI command ioctl, (only in version 3 interface) */
#define SG_IO 0x2285 /* similar effect as write() followed by read() */