diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2014-10-18 22:11:21 +0200 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2014-11-12 11:15:54 +0100 |
commit | 26cf591e6dfc0d07495b7bcf20a557b316811f00 (patch) | |
tree | aaebbfe8c9764f981f2fa540b6ae20c79dce55af /drivers/scsi/sg.c | |
parent | 678e27573237a0b065defdf99e5070c9b0c403c3 (diff) | |
download | op-kernel-dev-26cf591e6dfc0d07495b7bcf20a557b316811f00.zip op-kernel-dev-26cf591e6dfc0d07495b7bcf20a557b316811f00.tar.gz |
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>
Diffstat (limited to 'drivers/scsi/sg.c')
-rw-r--r-- | drivers/scsi/sg.c | 17 |
1 files changed, 11 insertions, 6 deletions
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 6035444..fe44c14 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -847,7 +847,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) { 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; @@ -1082,27 +1082,32 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) 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)) |