diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/scsi/scsi_ioctl.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/scsi/scsi_ioctl.c')
-rw-r--r-- | drivers/scsi/scsi_ioctl.c | 516 |
1 files changed, 516 insertions, 0 deletions
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c new file mode 100644 index 000000000000..68c9728dfbbb --- /dev/null +++ b/drivers/scsi/scsi_ioctl.c | |||
@@ -0,0 +1,516 @@ | |||
1 | /* | ||
2 | * Changes: | ||
3 | * Arnaldo Carvalho de Melo <acme@conectiva.com.br> 08/23/2000 | ||
4 | * - get rid of some verify_areas and use __copy*user and __get/put_user | ||
5 | * for the ones that remain | ||
6 | */ | ||
7 | #include <linux/module.h> | ||
8 | #include <linux/blkdev.h> | ||
9 | #include <linux/interrupt.h> | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include <linux/mm.h> | ||
14 | #include <linux/string.h> | ||
15 | #include <asm/uaccess.h> | ||
16 | |||
17 | #include <scsi/scsi.h> | ||
18 | #include <scsi/scsi_device.h> | ||
19 | #include <scsi/scsi_eh.h> | ||
20 | #include <scsi/scsi_host.h> | ||
21 | #include <scsi/scsi_ioctl.h> | ||
22 | #include <scsi/scsi_request.h> | ||
23 | #include <scsi/sg.h> | ||
24 | #include <scsi/scsi_dbg.h> | ||
25 | |||
26 | #include "scsi_logging.h" | ||
27 | |||
28 | #define NORMAL_RETRIES 5 | ||
29 | #define IOCTL_NORMAL_TIMEOUT (10 * HZ) | ||
30 | #define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ) | ||
31 | #define START_STOP_TIMEOUT (60 * HZ) | ||
32 | #define MOVE_MEDIUM_TIMEOUT (5 * 60 * HZ) | ||
33 | #define READ_ELEMENT_STATUS_TIMEOUT (5 * 60 * HZ) | ||
34 | #define READ_DEFECT_DATA_TIMEOUT (60 * HZ ) /* ZIP-250 on parallel port takes as long! */ | ||
35 | |||
36 | #define MAX_BUF PAGE_SIZE | ||
37 | |||
38 | /* | ||
39 | * If we are told to probe a host, we will return 0 if the host is not | ||
40 | * present, 1 if the host is present, and will return an identifying | ||
41 | * string at *arg, if arg is non null, filling to the length stored at | ||
42 | * (int *) arg | ||
43 | */ | ||
44 | |||
45 | static int ioctl_probe(struct Scsi_Host *host, void __user *buffer) | ||
46 | { | ||
47 | unsigned int len, slen; | ||
48 | const char *string; | ||
49 | int temp = host->hostt->present; | ||
50 | |||
51 | if (temp && buffer) { | ||
52 | if (get_user(len, (unsigned int __user *) buffer)) | ||
53 | return -EFAULT; | ||
54 | |||
55 | if (host->hostt->info) | ||
56 | string = host->hostt->info(host); | ||
57 | else | ||
58 | string = host->hostt->name; | ||
59 | if (string) { | ||
60 | slen = strlen(string); | ||
61 | if (len > slen) | ||
62 | len = slen + 1; | ||
63 | if (copy_to_user(buffer, string, len)) | ||
64 | return -EFAULT; | ||
65 | } | ||
66 | } | ||
67 | return temp; | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | |||
72 | * The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host. | ||
73 | * The IOCTL_NORMAL_TIMEOUT and NORMAL_RETRIES variables are used. | ||
74 | * | ||
75 | * dev is the SCSI device struct ptr, *(int *) arg is the length of the | ||
76 | * input data, if any, not including the command string & counts, | ||
77 | * *((int *)arg + 1) is the output buffer size in bytes. | ||
78 | * | ||
79 | * *(char *) ((int *) arg)[2] the actual command byte. | ||
80 | * | ||
81 | * Note that if more than MAX_BUF bytes are requested to be transferred, | ||
82 | * the ioctl will fail with error EINVAL. | ||
83 | * | ||
84 | * This size *does not* include the initial lengths that were passed. | ||
85 | * | ||
86 | * The SCSI command is read from the memory location immediately after the | ||
87 | * length words, and the input data is right after the command. The SCSI | ||
88 | * routines know the command size based on the opcode decode. | ||
89 | * | ||
90 | * The output area is then filled in starting from the command byte. | ||
91 | */ | ||
92 | |||
93 | static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, | ||
94 | int timeout, int retries) | ||
95 | { | ||
96 | struct scsi_request *sreq; | ||
97 | int result; | ||
98 | struct scsi_sense_hdr sshdr; | ||
99 | |||
100 | SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd)); | ||
101 | |||
102 | sreq = scsi_allocate_request(sdev, GFP_KERNEL); | ||
103 | if (!sreq) { | ||
104 | printk(KERN_WARNING "SCSI internal ioctl failed, no memory\n"); | ||
105 | return -ENOMEM; | ||
106 | } | ||
107 | |||
108 | sreq->sr_data_direction = DMA_NONE; | ||
109 | scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries); | ||
110 | |||
111 | SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", sreq->sr_result)); | ||
112 | |||
113 | if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && | ||
114 | (scsi_request_normalize_sense(sreq, &sshdr))) { | ||
115 | switch (sshdr.sense_key) { | ||
116 | case ILLEGAL_REQUEST: | ||
117 | if (cmd[0] == ALLOW_MEDIUM_REMOVAL) | ||
118 | sdev->lockable = 0; | ||
119 | else | ||
120 | printk(KERN_INFO "ioctl_internal_command: " | ||
121 | "ILLEGAL REQUEST asc=0x%x ascq=0x%x\n", | ||
122 | sshdr.asc, sshdr.ascq); | ||
123 | break; | ||
124 | case NOT_READY: /* This happens if there is no disc in drive */ | ||
125 | if (sdev->removable && (cmd[0] != TEST_UNIT_READY)) { | ||
126 | printk(KERN_INFO "Device not ready. Make sure" | ||
127 | " there is a disc in the drive.\n"); | ||
128 | break; | ||
129 | } | ||
130 | case UNIT_ATTENTION: | ||
131 | if (sdev->removable) { | ||
132 | sdev->changed = 1; | ||
133 | sreq->sr_result = 0; /* This is no longer considered an error */ | ||
134 | break; | ||
135 | } | ||
136 | default: /* Fall through for non-removable media */ | ||
137 | printk(KERN_INFO "ioctl_internal_command: <%d %d %d " | ||
138 | "%d> return code = %x\n", | ||
139 | sdev->host->host_no, | ||
140 | sdev->channel, | ||
141 | sdev->id, | ||
142 | sdev->lun, | ||
143 | sreq->sr_result); | ||
144 | scsi_print_req_sense(" ", sreq); | ||
145 | break; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | result = sreq->sr_result; | ||
150 | SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n")); | ||
151 | scsi_release_request(sreq); | ||
152 | return result; | ||
153 | } | ||
154 | |||
155 | int scsi_set_medium_removal(struct scsi_device *sdev, char state) | ||
156 | { | ||
157 | char scsi_cmd[MAX_COMMAND_SIZE]; | ||
158 | int ret; | ||
159 | |||
160 | if (!sdev->removable || !sdev->lockable) | ||
161 | return 0; | ||
162 | |||
163 | scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; | ||
164 | scsi_cmd[1] = 0; | ||
165 | scsi_cmd[2] = 0; | ||
166 | scsi_cmd[3] = 0; | ||
167 | scsi_cmd[4] = state; | ||
168 | scsi_cmd[5] = 0; | ||
169 | |||
170 | ret = ioctl_internal_command(sdev, scsi_cmd, | ||
171 | IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); | ||
172 | if (ret == 0) | ||
173 | sdev->locked = (state == SCSI_REMOVAL_PREVENT); | ||
174 | return ret; | ||
175 | } | ||
176 | EXPORT_SYMBOL(scsi_set_medium_removal); | ||
177 | |||
178 | /* | ||
179 | * This interface is deprecated - users should use the scsi generic (sg) | ||
180 | * interface instead, as this is a more flexible approach to performing | ||
181 | * generic SCSI commands on a device. | ||
182 | * | ||
183 | * The structure that we are passed should look like: | ||
184 | * | ||
185 | * struct sdata { | ||
186 | * unsigned int inlen; [i] Length of data to be written to device | ||
187 | * unsigned int outlen; [i] Length of data to be read from device | ||
188 | * unsigned char cmd[x]; [i] SCSI command (6 <= x <= 12). | ||
189 | * [o] Data read from device starts here. | ||
190 | * [o] On error, sense buffer starts here. | ||
191 | * unsigned char wdata[y]; [i] Data written to device starts here. | ||
192 | * }; | ||
193 | * Notes: | ||
194 | * - The SCSI command length is determined by examining the 1st byte | ||
195 | * of the given command. There is no way to override this. | ||
196 | * - Data transfers are limited to PAGE_SIZE (4K on i386, 8K on alpha). | ||
197 | * - The length (x + y) must be at least OMAX_SB_LEN bytes long to | ||
198 | * accommodate the sense buffer when an error occurs. | ||
199 | * The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that | ||
200 | * old code will not be surprised. | ||
201 | * - If a Unix error occurs (e.g. ENOMEM) then the user will receive | ||
202 | * a negative return and the Unix error code in 'errno'. | ||
203 | * If the SCSI command succeeds then 0 is returned. | ||
204 | * Positive numbers returned are the compacted SCSI error codes (4 | ||
205 | * bytes in one int) where the lowest byte is the SCSI status. | ||
206 | * See the drivers/scsi/scsi.h file for more information on this. | ||
207 | * | ||
208 | */ | ||
209 | #define OMAX_SB_LEN 16 /* Old sense buffer length */ | ||
210 | |||
211 | int scsi_ioctl_send_command(struct scsi_device *sdev, | ||
212 | struct scsi_ioctl_command __user *sic) | ||
213 | { | ||
214 | char *buf; | ||
215 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
216 | char __user *cmd_in; | ||
217 | struct scsi_request *sreq; | ||
218 | unsigned char opcode; | ||
219 | unsigned int inlen, outlen, cmdlen; | ||
220 | unsigned int needed, buf_needed; | ||
221 | int timeout, retries, result; | ||
222 | int data_direction, gfp_mask = GFP_KERNEL; | ||
223 | |||
224 | if (!sic) | ||
225 | return -EINVAL; | ||
226 | |||
227 | if (sdev->host->unchecked_isa_dma) | ||
228 | gfp_mask |= GFP_DMA; | ||
229 | |||
230 | /* | ||
231 | * Verify that we can read at least this much. | ||
232 | */ | ||
233 | if (!access_ok(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command))) | ||
234 | return -EFAULT; | ||
235 | |||
236 | if(__get_user(inlen, &sic->inlen)) | ||
237 | return -EFAULT; | ||
238 | |||
239 | if(__get_user(outlen, &sic->outlen)) | ||
240 | return -EFAULT; | ||
241 | |||
242 | /* | ||
243 | * We do not transfer more than MAX_BUF with this interface. | ||
244 | * If the user needs to transfer more data than this, they | ||
245 | * should use scsi_generics (sg) instead. | ||
246 | */ | ||
247 | if (inlen > MAX_BUF) | ||
248 | return -EINVAL; | ||
249 | if (outlen > MAX_BUF) | ||
250 | return -EINVAL; | ||
251 | |||
252 | cmd_in = sic->data; | ||
253 | if(get_user(opcode, cmd_in)) | ||
254 | return -EFAULT; | ||
255 | |||
256 | needed = buf_needed = (inlen > outlen ? inlen : outlen); | ||
257 | if (buf_needed) { | ||
258 | buf_needed = (buf_needed + 511) & ~511; | ||
259 | if (buf_needed > MAX_BUF) | ||
260 | buf_needed = MAX_BUF; | ||
261 | buf = kmalloc(buf_needed, gfp_mask); | ||
262 | if (!buf) | ||
263 | return -ENOMEM; | ||
264 | memset(buf, 0, buf_needed); | ||
265 | if (inlen == 0) { | ||
266 | data_direction = DMA_FROM_DEVICE; | ||
267 | } else if (outlen == 0 ) { | ||
268 | data_direction = DMA_TO_DEVICE; | ||
269 | } else { | ||
270 | /* | ||
271 | * Can this ever happen? | ||
272 | */ | ||
273 | data_direction = DMA_BIDIRECTIONAL; | ||
274 | } | ||
275 | |||
276 | } else { | ||
277 | buf = NULL; | ||
278 | data_direction = DMA_NONE; | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * Obtain the command from the user's address space. | ||
283 | */ | ||
284 | cmdlen = COMMAND_SIZE(opcode); | ||
285 | |||
286 | result = -EFAULT; | ||
287 | |||
288 | if (!access_ok(VERIFY_READ, cmd_in, cmdlen + inlen)) | ||
289 | goto error; | ||
290 | |||
291 | if(__copy_from_user(cmd, cmd_in, cmdlen)) | ||
292 | goto error; | ||
293 | |||
294 | /* | ||
295 | * Obtain the data to be sent to the device (if any). | ||
296 | */ | ||
297 | |||
298 | if(copy_from_user(buf, cmd_in + cmdlen, inlen)) | ||
299 | goto error; | ||
300 | |||
301 | switch (opcode) { | ||
302 | case SEND_DIAGNOSTIC: | ||
303 | case FORMAT_UNIT: | ||
304 | timeout = FORMAT_UNIT_TIMEOUT; | ||
305 | retries = 1; | ||
306 | break; | ||
307 | case START_STOP: | ||
308 | timeout = START_STOP_TIMEOUT; | ||
309 | retries = NORMAL_RETRIES; | ||
310 | break; | ||
311 | case MOVE_MEDIUM: | ||
312 | timeout = MOVE_MEDIUM_TIMEOUT; | ||
313 | retries = NORMAL_RETRIES; | ||
314 | break; | ||
315 | case READ_ELEMENT_STATUS: | ||
316 | timeout = READ_ELEMENT_STATUS_TIMEOUT; | ||
317 | retries = NORMAL_RETRIES; | ||
318 | break; | ||
319 | case READ_DEFECT_DATA: | ||
320 | timeout = READ_DEFECT_DATA_TIMEOUT; | ||
321 | retries = 1; | ||
322 | break; | ||
323 | default: | ||
324 | timeout = IOCTL_NORMAL_TIMEOUT; | ||
325 | retries = NORMAL_RETRIES; | ||
326 | break; | ||
327 | } | ||
328 | |||
329 | sreq = scsi_allocate_request(sdev, GFP_KERNEL); | ||
330 | if (!sreq) { | ||
331 | result = -EINTR; | ||
332 | goto error; | ||
333 | } | ||
334 | |||
335 | sreq->sr_data_direction = data_direction; | ||
336 | scsi_wait_req(sreq, cmd, buf, needed, timeout, retries); | ||
337 | |||
338 | /* | ||
339 | * If there was an error condition, pass the info back to the user. | ||
340 | */ | ||
341 | result = sreq->sr_result; | ||
342 | if (result) { | ||
343 | int sb_len = sizeof(sreq->sr_sense_buffer); | ||
344 | |||
345 | sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len; | ||
346 | if (copy_to_user(cmd_in, sreq->sr_sense_buffer, sb_len)) | ||
347 | result = -EFAULT; | ||
348 | } else { | ||
349 | if (copy_to_user(cmd_in, buf, outlen)) | ||
350 | result = -EFAULT; | ||
351 | } | ||
352 | |||
353 | scsi_release_request(sreq); | ||
354 | error: | ||
355 | kfree(buf); | ||
356 | return result; | ||
357 | } | ||
358 | EXPORT_SYMBOL(scsi_ioctl_send_command); | ||
359 | |||
360 | /* | ||
361 | * The scsi_ioctl_get_pci() function places into arg the value | ||
362 | * pci_dev::slot_name (8 characters) for the PCI device (if any). | ||
363 | * Returns: 0 on success | ||
364 | * -ENXIO if there isn't a PCI device pointer | ||
365 | * (could be because the SCSI driver hasn't been | ||
366 | * updated yet, or because it isn't a SCSI | ||
367 | * device) | ||
368 | * any copy_to_user() error on failure there | ||
369 | */ | ||
370 | static int scsi_ioctl_get_pci(struct scsi_device *sdev, void __user *arg) | ||
371 | { | ||
372 | struct device *dev = scsi_get_device(sdev->host); | ||
373 | |||
374 | if (!dev) | ||
375 | return -ENXIO; | ||
376 | return copy_to_user(arg, dev->bus_id, sizeof(dev->bus_id))? -EFAULT: 0; | ||
377 | } | ||
378 | |||
379 | |||
380 | /* | ||
381 | * the scsi_ioctl() function differs from most ioctls in that it does | ||
382 | * not take a major/minor number as the dev field. Rather, it takes | ||
383 | * a pointer to a scsi_devices[] element, a structure. | ||
384 | */ | ||
385 | int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) | ||
386 | { | ||
387 | char scsi_cmd[MAX_COMMAND_SIZE]; | ||
388 | |||
389 | /* No idea how this happens.... */ | ||
390 | if (!sdev) | ||
391 | return -ENXIO; | ||
392 | |||
393 | /* | ||
394 | * If we are in the middle of error recovery, don't let anyone | ||
395 | * else try and use this device. Also, if error recovery fails, it | ||
396 | * may try and take the device offline, in which case all further | ||
397 | * access to the device is prohibited. | ||
398 | */ | ||
399 | if (!scsi_block_when_processing_errors(sdev)) | ||
400 | return -ENODEV; | ||
401 | |||
402 | /* Check for deprecated ioctls ... all the ioctls which don't | ||
403 | * follow the new unique numbering scheme are deprecated */ | ||
404 | switch (cmd) { | ||
405 | case SCSI_IOCTL_SEND_COMMAND: | ||
406 | case SCSI_IOCTL_TEST_UNIT_READY: | ||
407 | case SCSI_IOCTL_BENCHMARK_COMMAND: | ||
408 | case SCSI_IOCTL_SYNC: | ||
409 | case SCSI_IOCTL_START_UNIT: | ||
410 | case SCSI_IOCTL_STOP_UNIT: | ||
411 | printk(KERN_WARNING "program %s is using a deprecated SCSI " | ||
412 | "ioctl, please convert it to SG_IO\n", current->comm); | ||
413 | break; | ||
414 | default: | ||
415 | break; | ||
416 | } | ||
417 | |||
418 | switch (cmd) { | ||
419 | case SCSI_IOCTL_GET_IDLUN: | ||
420 | if (!access_ok(VERIFY_WRITE, arg, sizeof(struct scsi_idlun))) | ||
421 | return -EFAULT; | ||
422 | |||
423 | __put_user((sdev->id & 0xff) | ||
424 | + ((sdev->lun & 0xff) << 8) | ||
425 | + ((sdev->channel & 0xff) << 16) | ||
426 | + ((sdev->host->host_no & 0xff) << 24), | ||
427 | &((struct scsi_idlun __user *)arg)->dev_id); | ||
428 | __put_user(sdev->host->unique_id, | ||
429 | &((struct scsi_idlun __user *)arg)->host_unique_id); | ||
430 | return 0; | ||
431 | case SCSI_IOCTL_GET_BUS_NUMBER: | ||
432 | return put_user(sdev->host->host_no, (int __user *)arg); | ||
433 | case SCSI_IOCTL_PROBE_HOST: | ||
434 | return ioctl_probe(sdev->host, arg); | ||
435 | case SCSI_IOCTL_SEND_COMMAND: | ||
436 | if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) | ||
437 | return -EACCES; | ||
438 | return scsi_ioctl_send_command(sdev, arg); | ||
439 | case SCSI_IOCTL_DOORLOCK: | ||
440 | return scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); | ||
441 | case SCSI_IOCTL_DOORUNLOCK: | ||
442 | return scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW); | ||
443 | case SCSI_IOCTL_TEST_UNIT_READY: | ||
444 | return scsi_test_unit_ready(sdev, IOCTL_NORMAL_TIMEOUT, | ||
445 | NORMAL_RETRIES); | ||
446 | case SCSI_IOCTL_START_UNIT: | ||
447 | scsi_cmd[0] = START_STOP; | ||
448 | scsi_cmd[1] = 0; | ||
449 | scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; | ||
450 | scsi_cmd[4] = 1; | ||
451 | return ioctl_internal_command(sdev, scsi_cmd, | ||
452 | START_STOP_TIMEOUT, NORMAL_RETRIES); | ||
453 | case SCSI_IOCTL_STOP_UNIT: | ||
454 | scsi_cmd[0] = START_STOP; | ||
455 | scsi_cmd[1] = 0; | ||
456 | scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; | ||
457 | scsi_cmd[4] = 0; | ||
458 | return ioctl_internal_command(sdev, scsi_cmd, | ||
459 | START_STOP_TIMEOUT, NORMAL_RETRIES); | ||
460 | case SCSI_IOCTL_GET_PCI: | ||
461 | return scsi_ioctl_get_pci(sdev, arg); | ||
462 | default: | ||
463 | if (sdev->host->hostt->ioctl) | ||
464 | return sdev->host->hostt->ioctl(sdev, cmd, arg); | ||
465 | } | ||
466 | return -EINVAL; | ||
467 | } | ||
468 | EXPORT_SYMBOL(scsi_ioctl); | ||
469 | |||
470 | /* | ||
471 | * the scsi_nonblock_ioctl() function is designed for ioctls which may | ||
472 | * be executed even if the device is in recovery. | ||
473 | */ | ||
474 | int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, | ||
475 | void __user *arg, struct file *filp) | ||
476 | { | ||
477 | int val, result; | ||
478 | |||
479 | /* The first set of iocts may be executed even if we're doing | ||
480 | * error processing, as long as the device was opened | ||
481 | * non-blocking */ | ||
482 | if (filp && filp->f_flags & O_NONBLOCK) { | ||
483 | if (test_bit(SHOST_RECOVERY, | ||
484 | &sdev->host->shost_state)) | ||
485 | return -ENODEV; | ||
486 | } else if (!scsi_block_when_processing_errors(sdev)) | ||
487 | return -ENODEV; | ||
488 | |||
489 | switch (cmd) { | ||
490 | case SG_SCSI_RESET: | ||
491 | result = get_user(val, (int __user *)arg); | ||
492 | if (result) | ||
493 | return result; | ||
494 | if (val == SG_SCSI_RESET_NOTHING) | ||
495 | return 0; | ||
496 | switch (val) { | ||
497 | case SG_SCSI_RESET_DEVICE: | ||
498 | val = SCSI_TRY_RESET_DEVICE; | ||
499 | break; | ||
500 | case SG_SCSI_RESET_BUS: | ||
501 | val = SCSI_TRY_RESET_BUS; | ||
502 | break; | ||
503 | case SG_SCSI_RESET_HOST: | ||
504 | val = SCSI_TRY_RESET_HOST; | ||
505 | break; | ||
506 | default: | ||
507 | return -EINVAL; | ||
508 | } | ||
509 | if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) | ||
510 | return -EACCES; | ||
511 | return (scsi_reset_provider(sdev, val) == | ||
512 | SUCCESS) ? 0 : -EIO; | ||
513 | } | ||
514 | return -ENODEV; | ||
515 | } | ||
516 | EXPORT_SYMBOL(scsi_nonblockable_ioctl); | ||