scsi: add SG_SCSI_RESET_NO_ESCALATE flag to SG_SCSI_RESET ioctl

Further to a January 2013 thread titled: "[PATCH] SG_SCSI_RESET ioctl
should only perform requested operation" by Jeremy Linton a patch (v3)
is presented that expands the existing ioctl to include "no_escalate"
versions to the existing resets. This requires no changes to SCSI low
level drivers (LLDs); it adds several more finely tuned reset options
to the user space. For example:

   /* This call remains the same, with the same escalating semantics
    * if the device (LU) reset fail. That is: on failure to try a
    * target reset and if that fails, try a bus reset, and if that fails
    * try a host (i.e. LLD) reset. */
   val = SG_SCSI_RESET_DEVICE;
   res = ioctl(<sg_or_block_fd>, SG_SCSI_RESET, &val);

   /* What follows is a new option introduced by this patch series. Only
    * a device reset is attempted. If that fails then an appropriate
    * error code is provided. N.B. There is no reset escalation. */
   val = SG_SCSI_RESET_DEVICE | SG_SCSI_RESET_NO_ESCALATE;
   res = ioctl(<sg_or_block_fd>, SG_SCSI_RESET, &val);

Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
Reviewed-by: Jeremy Linton <jlinton@tributary.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Цей коміт міститься в:
Douglas Gilbert
2014-10-18 22:11:21 +02:00
зафіксовано Christoph Hellwig
джерело 678e275732
коміт 26cf591e6d
5 змінених файлів з 43 додано та 14 видалено

Переглянути файл

@@ -285,13 +285,14 @@ EXPORT_SYMBOL(scsi_ioctl);
* 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
@@ -307,27 +308,32 @@ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
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;