aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2014-10-18 16:11:21 -0400
committerChristoph Hellwig <hch@lst.de>2014-11-12 05:15:54 -0500
commit26cf591e6dfc0d07495b7bcf20a557b316811f00 (patch)
treeaaebbfe8c9764f981f2fa540b6ae20c79dce55af
parent678e27573237a0b065defdf99e5070c9b0c403c3 (diff)
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>
-rw-r--r--drivers/scsi/scsi_error.c10
-rw-r--r--drivers/scsi/scsi_ioctl.c20
-rw-r--r--drivers/scsi/sg.c17
-rw-r--r--include/scsi/scsi_eh.h5
-rw-r--r--include/scsi/sg.h5
5 files changed, 43 insertions, 14 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index bc5ff6ff9c79..0ed666112b4f 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -2366,8 +2366,18 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
2366 break; 2366 break;
2367 /* FALLTHROUGH */ 2367 /* FALLTHROUGH */
2368 case SCSI_TRY_RESET_HOST: 2368 case SCSI_TRY_RESET_HOST:
2369 case SCSI_TRY_RESET_HOST | SCSI_TRY_RESET_NO_ESCALATE:
2369 rtn = scsi_try_host_reset(scmd); 2370 rtn = scsi_try_host_reset(scmd);
2370 break; 2371 break;
2372 case SCSI_TRY_RESET_DEVICE | SCSI_TRY_RESET_NO_ESCALATE:
2373 rtn = scsi_try_bus_device_reset(scmd);
2374 break;
2375 case SCSI_TRY_RESET_TARGET | SCSI_TRY_RESET_NO_ESCALATE:
2376 rtn = scsi_try_target_reset(scmd);
2377 break;
2378 case SCSI_TRY_RESET_BUS | SCSI_TRY_RESET_NO_ESCALATE:
2379 rtn = scsi_try_bus_reset(scmd);
2380 break;
2371 default: 2381 default:
2372 rtn = FAILED; 2382 rtn = FAILED;
2373 } 2383 }
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 1aaaf43c6803..12fe676d1343 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -285,13 +285,14 @@ EXPORT_SYMBOL(scsi_ioctl);
285 * scsi_nonblockable_ioctl() - Handle SG_SCSI_RESET 285 * scsi_nonblockable_ioctl() - Handle SG_SCSI_RESET
286 * @sdev: scsi device receiving ioctl 286 * @sdev: scsi device receiving ioctl
287 * @cmd: Must be SC_SCSI_RESET 287 * @cmd: Must be SC_SCSI_RESET
288 * @arg: pointer to int containing SG_SCSI_RESET_{DEVICE,BUS,HOST} 288 * @arg: pointer to int containing SG_SCSI_RESET_{DEVICE,TARGET,BUS,HOST}
289 * possibly OR-ed with SG_SCSI_RESET_NO_ESCALATE
289 * @ndelay: file mode O_NDELAY flag 290 * @ndelay: file mode O_NDELAY flag
290 */ 291 */
291int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, 292int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
292 void __user *arg, int ndelay) 293 void __user *arg, int ndelay)
293{ 294{
294 int val, result; 295 int val, val2, result;
295 296
296 /* The first set of iocts may be executed even if we're doing 297 /* The first set of iocts may be executed even if we're doing
297 * error processing, as long as the device was opened 298 * error processing, as long as the device was opened
@@ -307,27 +308,32 @@ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
307 result = get_user(val, (int __user *)arg); 308 result = get_user(val, (int __user *)arg);
308 if (result) 309 if (result)
309 return result; 310 return result;
311 if (val & SG_SCSI_RESET_NO_ESCALATE) {
312 val &= ~SG_SCSI_RESET_NO_ESCALATE;
313 val2 = SCSI_TRY_RESET_NO_ESCALATE;
314 } else
315 val2 = 0;
310 if (val == SG_SCSI_RESET_NOTHING) 316 if (val == SG_SCSI_RESET_NOTHING)
311 return 0; 317 return 0;
312 switch (val) { 318 switch (val) {
313 case SG_SCSI_RESET_DEVICE: 319 case SG_SCSI_RESET_DEVICE:
314 val = SCSI_TRY_RESET_DEVICE; 320 val2 |= SCSI_TRY_RESET_DEVICE;
315 break; 321 break;
316 case SG_SCSI_RESET_TARGET: 322 case SG_SCSI_RESET_TARGET:
317 val = SCSI_TRY_RESET_TARGET; 323 val2 |= SCSI_TRY_RESET_TARGET;
318 break; 324 break;
319 case SG_SCSI_RESET_BUS: 325 case SG_SCSI_RESET_BUS:
320 val = SCSI_TRY_RESET_BUS; 326 val2 |= SCSI_TRY_RESET_BUS;
321 break; 327 break;
322 case SG_SCSI_RESET_HOST: 328 case SG_SCSI_RESET_HOST:
323 val = SCSI_TRY_RESET_HOST; 329 val2 |= SCSI_TRY_RESET_HOST;
324 break; 330 break;
325 default: 331 default:
326 return -EINVAL; 332 return -EINVAL;
327 } 333 }
328 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 334 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
329 return -EACCES; 335 return -EACCES;
330 return (scsi_reset_provider(sdev, val) == 336 return (scsi_reset_provider(sdev, val2) ==
331 SUCCESS) ? 0 : -EIO; 337 SUCCESS) ? 0 : -EIO;
332 } 338 }
333 return -ENODEV; 339 return -ENODEV;
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 60354449d9ed..fe44c14f551e 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)
847{ 847{
848 void __user *p = (void __user *)arg; 848 void __user *p = (void __user *)arg;
849 int __user *ip = p; 849 int __user *ip = p;
850 int result, val, read_only; 850 int result, val, val2, read_only;
851 Sg_device *sdp; 851 Sg_device *sdp;
852 Sg_fd *sfp; 852 Sg_fd *sfp;
853 Sg_request *srp; 853 Sg_request *srp;
@@ -1082,27 +1082,32 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
1082 result = get_user(val, ip); 1082 result = get_user(val, ip);
1083 if (result) 1083 if (result)
1084 return result; 1084 return result;
1085 if (val & SG_SCSI_RESET_NO_ESCALATE) {
1086 val &= ~SG_SCSI_RESET_NO_ESCALATE;
1087 val2 = SCSI_TRY_RESET_NO_ESCALATE;
1088 } else
1089 val2 = 0;
1085 if (SG_SCSI_RESET_NOTHING == val) 1090 if (SG_SCSI_RESET_NOTHING == val)
1086 return 0; 1091 return 0;
1087 switch (val) { 1092 switch (val) {
1088 case SG_SCSI_RESET_DEVICE: 1093 case SG_SCSI_RESET_DEVICE:
1089 val = SCSI_TRY_RESET_DEVICE; 1094 val2 |= SCSI_TRY_RESET_DEVICE;
1090 break; 1095 break;
1091 case SG_SCSI_RESET_TARGET: 1096 case SG_SCSI_RESET_TARGET:
1092 val = SCSI_TRY_RESET_TARGET; 1097 val2 |= SCSI_TRY_RESET_TARGET;
1093 break; 1098 break;
1094 case SG_SCSI_RESET_BUS: 1099 case SG_SCSI_RESET_BUS:
1095 val = SCSI_TRY_RESET_BUS; 1100 val2 |= SCSI_TRY_RESET_BUS;
1096 break; 1101 break;
1097 case SG_SCSI_RESET_HOST: 1102 case SG_SCSI_RESET_HOST:
1098 val = SCSI_TRY_RESET_HOST; 1103 val2 |= SCSI_TRY_RESET_HOST;
1099 break; 1104 break;
1100 default: 1105 default:
1101 return -EINVAL; 1106 return -EINVAL;
1102 } 1107 }
1103 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 1108 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
1104 return -EACCES; 1109 return -EACCES;
1105 return (scsi_reset_provider(sdp->device, val) == 1110 return (scsi_reset_provider(sdp->device, val2) ==
1106 SUCCESS) ? 0 : -EIO; 1111 SUCCESS) ? 0 : -EIO;
1107 case SCSI_IOCTL_SEND_COMMAND: 1112 case SCSI_IOCTL_SEND_COMMAND:
1108 if (atomic_read(&sdp->detaching)) 1113 if (atomic_read(&sdp->detaching))
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h
index 06a8790893ef..49af14ad5288 100644
--- a/include/scsi/scsi_eh.h
+++ b/include/scsi/scsi_eh.h
@@ -62,11 +62,16 @@ extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq);
62 62
63/* 63/*
64 * Reset request from external source 64 * Reset request from external source
65 * Note: if SCSI_TRY_RESET_DEVICE fails then it will escalate to
66 * SCSI_TRY_RESET_TARGET which if it fails will escalate to
67 * SCSI_TRY_RESET_BUS which if it fails will escalate to SCSI_TRY_RESET_HOST.
68 * To prevent escalation OR with SCSI_TRY_RESET_NO_ESCALATE.
65 */ 69 */
66#define SCSI_TRY_RESET_DEVICE 1 70#define SCSI_TRY_RESET_DEVICE 1
67#define SCSI_TRY_RESET_BUS 2 71#define SCSI_TRY_RESET_BUS 2
68#define SCSI_TRY_RESET_HOST 3 72#define SCSI_TRY_RESET_HOST 3
69#define SCSI_TRY_RESET_TARGET 4 73#define SCSI_TRY_RESET_TARGET 4
74#define SCSI_TRY_RESET_NO_ESCALATE 0x100 /* OR-ed to prior defines */
70 75
71extern int scsi_reset_provider(struct scsi_device *, int); 76extern int scsi_reset_provider(struct scsi_device *, int);
72 77
diff --git a/include/scsi/sg.h b/include/scsi/sg.h
index 750e5db7c6bf..3afec7032448 100644
--- a/include/scsi/sg.h
+++ b/include/scsi/sg.h
@@ -164,12 +164,15 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
164 164
165/* Returns -EBUSY if occupied. 3rd argument pointer to int (see next) */ 165/* Returns -EBUSY if occupied. 3rd argument pointer to int (see next) */
166#define SG_SCSI_RESET 0x2284 166#define SG_SCSI_RESET 0x2284
167/* Associated values that can be given to SG_SCSI_RESET follow */ 167/* Associated values that can be given to SG_SCSI_RESET follow.
168 * SG_SCSI_RESET_NO_ESCALATE may be OR-ed to the _DEVICE, _TARGET, _BUS
169 * or _HOST reset value so only that action is attempted. */
168#define SG_SCSI_RESET_NOTHING 0 170#define SG_SCSI_RESET_NOTHING 0
169#define SG_SCSI_RESET_DEVICE 1 171#define SG_SCSI_RESET_DEVICE 1
170#define SG_SCSI_RESET_BUS 2 172#define SG_SCSI_RESET_BUS 2
171#define SG_SCSI_RESET_HOST 3 173#define SG_SCSI_RESET_HOST 3
172#define SG_SCSI_RESET_TARGET 4 174#define SG_SCSI_RESET_TARGET 4
175#define SG_SCSI_RESET_NO_ESCALATE 0x100
173 176
174/* synchronous SCSI command ioctl, (only in version 3 interface) */ 177/* synchronous SCSI command ioctl, (only in version 3 interface) */
175#define SG_IO 0x2285 /* similar effect as write() followed by read() */ 178#define SG_IO 0x2285 /* similar effect as write() followed by read() */