diff options
-rw-r--r-- | block/scsi_ioctl.c | 101 | ||||
-rw-r--r-- | drivers/scsi/scsi_ioctl.c | 176 | ||||
-rw-r--r-- | drivers/scsi/sg.c | 2 | ||||
-rw-r--r-- | include/linux/blkdev.h | 4 | ||||
-rw-r--r-- | include/scsi/scsi_ioctl.h | 2 |
5 files changed, 78 insertions, 207 deletions
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 24f7af9d0abc..b33eda26e205 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c | |||
@@ -350,16 +350,51 @@ out: | |||
350 | return ret; | 350 | return ret; |
351 | } | 351 | } |
352 | 352 | ||
353 | /** | ||
354 | * sg_scsi_ioctl -- handle deprecated SCSI_IOCTL_SEND_COMMAND ioctl | ||
355 | * @file: file this ioctl operates on (optional) | ||
356 | * @q: request queue to send scsi commands down | ||
357 | * @disk: gendisk to operate on (option) | ||
358 | * @sic: userspace structure describing the command to perform | ||
359 | * | ||
360 | * Send down the scsi command described by @sic to the device below | ||
361 | * the request queue @q. If @file is non-NULL it's used to perform | ||
362 | * fine-grained permission checks that allow users to send down | ||
363 | * non-destructive SCSI commands. If the caller has a struct gendisk | ||
364 | * available it should be passed in as @disk to allow the low level | ||
365 | * driver to use the information contained in it. A non-NULL @disk | ||
366 | * is only allowed if the caller knows that the low level driver doesn't | ||
367 | * need it (e.g. in the scsi subsystem). | ||
368 | * | ||
369 | * Notes: | ||
370 | * - This interface is deprecated - users should use the SG_IO | ||
371 | * interface instead, as this is a more flexible approach to | ||
372 | * performing SCSI commands on a device. | ||
373 | * - The SCSI command length is determined by examining the 1st byte | ||
374 | * of the given command. There is no way to override this. | ||
375 | * - Data transfers are limited to PAGE_SIZE | ||
376 | * - The length (x + y) must be at least OMAX_SB_LEN bytes long to | ||
377 | * accommodate the sense buffer when an error occurs. | ||
378 | * The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that | ||
379 | * old code will not be surprised. | ||
380 | * - If a Unix error occurs (e.g. ENOMEM) then the user will receive | ||
381 | * a negative return and the Unix error code in 'errno'. | ||
382 | * If the SCSI command succeeds then 0 is returned. | ||
383 | * Positive numbers returned are the compacted SCSI error codes (4 | ||
384 | * bytes in one int) where the lowest byte is the SCSI status. | ||
385 | */ | ||
353 | #define OMAX_SB_LEN 16 /* For backward compatibility */ | 386 | #define OMAX_SB_LEN 16 /* For backward compatibility */ |
354 | 387 | int sg_scsi_ioctl(struct file *file, struct request_queue *q, | |
355 | static int sg_scsi_ioctl(struct file *file, request_queue_t *q, | 388 | struct gendisk *disk, struct scsi_ioctl_command __user *sic) |
356 | struct gendisk *bd_disk, Scsi_Ioctl_Command __user *sic) | ||
357 | { | 389 | { |
358 | struct request *rq; | 390 | struct request *rq; |
359 | int err; | 391 | int err; |
360 | unsigned int in_len, out_len, bytes, opcode, cmdlen; | 392 | unsigned int in_len, out_len, bytes, opcode, cmdlen; |
361 | char *buffer = NULL, sense[SCSI_SENSE_BUFFERSIZE]; | 393 | char *buffer = NULL, sense[SCSI_SENSE_BUFFERSIZE]; |
362 | 394 | ||
395 | if (!sic) | ||
396 | return -EINVAL; | ||
397 | |||
363 | /* | 398 | /* |
364 | * get in an out lengths, verify they don't exceed a page worth of data | 399 | * get in an out lengths, verify they don't exceed a page worth of data |
365 | */ | 400 | */ |
@@ -393,45 +428,53 @@ static int sg_scsi_ioctl(struct file *file, request_queue_t *q, | |||
393 | if (copy_from_user(rq->cmd, sic->data, cmdlen)) | 428 | if (copy_from_user(rq->cmd, sic->data, cmdlen)) |
394 | goto error; | 429 | goto error; |
395 | 430 | ||
396 | if (copy_from_user(buffer, sic->data + cmdlen, in_len)) | 431 | if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len)) |
397 | goto error; | 432 | goto error; |
398 | 433 | ||
399 | err = verify_command(file, rq->cmd); | 434 | err = verify_command(file, rq->cmd); |
400 | if (err) | 435 | if (err) |
401 | goto error; | 436 | goto error; |
402 | 437 | ||
438 | /* default. possible overriden later */ | ||
439 | rq->retries = 5; | ||
440 | |||
403 | switch (opcode) { | 441 | switch (opcode) { |
404 | case SEND_DIAGNOSTIC: | 442 | case SEND_DIAGNOSTIC: |
405 | case FORMAT_UNIT: | 443 | case FORMAT_UNIT: |
406 | rq->timeout = FORMAT_UNIT_TIMEOUT; | 444 | rq->timeout = FORMAT_UNIT_TIMEOUT; |
407 | break; | 445 | rq->retries = 1; |
408 | case START_STOP: | 446 | break; |
409 | rq->timeout = START_STOP_TIMEOUT; | 447 | case START_STOP: |
410 | break; | 448 | rq->timeout = START_STOP_TIMEOUT; |
411 | case MOVE_MEDIUM: | 449 | break; |
412 | rq->timeout = MOVE_MEDIUM_TIMEOUT; | 450 | case MOVE_MEDIUM: |
413 | break; | 451 | rq->timeout = MOVE_MEDIUM_TIMEOUT; |
414 | case READ_ELEMENT_STATUS: | 452 | break; |
415 | rq->timeout = READ_ELEMENT_STATUS_TIMEOUT; | 453 | case READ_ELEMENT_STATUS: |
416 | break; | 454 | rq->timeout = READ_ELEMENT_STATUS_TIMEOUT; |
417 | case READ_DEFECT_DATA: | 455 | break; |
418 | rq->timeout = READ_DEFECT_DATA_TIMEOUT; | 456 | case READ_DEFECT_DATA: |
419 | break; | 457 | rq->timeout = READ_DEFECT_DATA_TIMEOUT; |
420 | default: | 458 | rq->retries = 1; |
421 | rq->timeout = BLK_DEFAULT_TIMEOUT; | 459 | break; |
422 | break; | 460 | default: |
461 | rq->timeout = BLK_DEFAULT_TIMEOUT; | ||
462 | break; | ||
463 | } | ||
464 | |||
465 | if (bytes && blk_rq_map_kern(q, rq, buffer, bytes, __GFP_WAIT)) { | ||
466 | err = DRIVER_ERROR << 24; | ||
467 | goto out; | ||
423 | } | 468 | } |
424 | 469 | ||
425 | memset(sense, 0, sizeof(sense)); | 470 | memset(sense, 0, sizeof(sense)); |
426 | rq->sense = sense; | 471 | rq->sense = sense; |
427 | rq->sense_len = 0; | 472 | rq->sense_len = 0; |
428 | |||
429 | rq->data = buffer; | ||
430 | rq->data_len = bytes; | ||
431 | rq->flags |= REQ_BLOCK_PC; | 473 | rq->flags |= REQ_BLOCK_PC; |
432 | rq->retries = 0; | ||
433 | 474 | ||
434 | blk_execute_rq(q, bd_disk, rq, 0); | 475 | blk_execute_rq(q, disk, rq, 0); |
476 | |||
477 | out: | ||
435 | err = rq->errors & 0xff; /* only 8 bit SCSI status */ | 478 | err = rq->errors & 0xff; /* only 8 bit SCSI status */ |
436 | if (err) { | 479 | if (err) { |
437 | if (rq->sense_len && rq->sense) { | 480 | if (rq->sense_len && rq->sense) { |
@@ -450,7 +493,7 @@ error: | |||
450 | blk_put_request(rq); | 493 | blk_put_request(rq); |
451 | return err; | 494 | return err; |
452 | } | 495 | } |
453 | 496 | EXPORT_SYMBOL_GPL(sg_scsi_ioctl); | |
454 | 497 | ||
455 | /* Send basic block requests */ | 498 | /* Send basic block requests */ |
456 | static int __blk_send_generic(request_queue_t *q, struct gendisk *bd_disk, int cmd, int data) | 499 | static int __blk_send_generic(request_queue_t *q, struct gendisk *bd_disk, int cmd, int data) |
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 36e930066649..a89aff61d3d8 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c | |||
@@ -158,180 +158,6 @@ int scsi_set_medium_removal(struct scsi_device *sdev, char state) | |||
158 | EXPORT_SYMBOL(scsi_set_medium_removal); | 158 | EXPORT_SYMBOL(scsi_set_medium_removal); |
159 | 159 | ||
160 | /* | 160 | /* |
161 | * This interface is deprecated - users should use the scsi generic (sg) | ||
162 | * interface instead, as this is a more flexible approach to performing | ||
163 | * generic SCSI commands on a device. | ||
164 | * | ||
165 | * The structure that we are passed should look like: | ||
166 | * | ||
167 | * struct sdata { | ||
168 | * unsigned int inlen; [i] Length of data to be written to device | ||
169 | * unsigned int outlen; [i] Length of data to be read from device | ||
170 | * unsigned char cmd[x]; [i] SCSI command (6 <= x <= 12). | ||
171 | * [o] Data read from device starts here. | ||
172 | * [o] On error, sense buffer starts here. | ||
173 | * unsigned char wdata[y]; [i] Data written to device starts here. | ||
174 | * }; | ||
175 | * Notes: | ||
176 | * - The SCSI command length is determined by examining the 1st byte | ||
177 | * of the given command. There is no way to override this. | ||
178 | * - Data transfers are limited to PAGE_SIZE (4K on i386, 8K on alpha). | ||
179 | * - The length (x + y) must be at least OMAX_SB_LEN bytes long to | ||
180 | * accommodate the sense buffer when an error occurs. | ||
181 | * The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that | ||
182 | * old code will not be surprised. | ||
183 | * - If a Unix error occurs (e.g. ENOMEM) then the user will receive | ||
184 | * a negative return and the Unix error code in 'errno'. | ||
185 | * If the SCSI command succeeds then 0 is returned. | ||
186 | * Positive numbers returned are the compacted SCSI error codes (4 | ||
187 | * bytes in one int) where the lowest byte is the SCSI status. | ||
188 | * See the drivers/scsi/scsi.h file for more information on this. | ||
189 | * | ||
190 | */ | ||
191 | #define OMAX_SB_LEN 16 /* Old sense buffer length */ | ||
192 | |||
193 | int scsi_ioctl_send_command(struct scsi_device *sdev, | ||
194 | struct scsi_ioctl_command __user *sic) | ||
195 | { | ||
196 | char *buf; | ||
197 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
198 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | ||
199 | char __user *cmd_in; | ||
200 | unsigned char opcode; | ||
201 | unsigned int inlen, outlen, cmdlen; | ||
202 | unsigned int needed, buf_needed; | ||
203 | int timeout, retries, result; | ||
204 | int data_direction; | ||
205 | gfp_t gfp_mask = GFP_KERNEL; | ||
206 | |||
207 | if (!sic) | ||
208 | return -EINVAL; | ||
209 | |||
210 | if (sdev->host->unchecked_isa_dma) | ||
211 | gfp_mask |= GFP_DMA; | ||
212 | |||
213 | /* | ||
214 | * Verify that we can read at least this much. | ||
215 | */ | ||
216 | if (!access_ok(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command))) | ||
217 | return -EFAULT; | ||
218 | |||
219 | if(__get_user(inlen, &sic->inlen)) | ||
220 | return -EFAULT; | ||
221 | |||
222 | if(__get_user(outlen, &sic->outlen)) | ||
223 | return -EFAULT; | ||
224 | |||
225 | /* | ||
226 | * We do not transfer more than MAX_BUF with this interface. | ||
227 | * If the user needs to transfer more data than this, they | ||
228 | * should use scsi_generics (sg) instead. | ||
229 | */ | ||
230 | if (inlen > MAX_BUF) | ||
231 | return -EINVAL; | ||
232 | if (outlen > MAX_BUF) | ||
233 | return -EINVAL; | ||
234 | |||
235 | cmd_in = sic->data; | ||
236 | if(get_user(opcode, cmd_in)) | ||
237 | return -EFAULT; | ||
238 | |||
239 | needed = buf_needed = (inlen > outlen ? inlen : outlen); | ||
240 | if (buf_needed) { | ||
241 | buf_needed = (buf_needed + 511) & ~511; | ||
242 | if (buf_needed > MAX_BUF) | ||
243 | buf_needed = MAX_BUF; | ||
244 | buf = kzalloc(buf_needed, gfp_mask); | ||
245 | if (!buf) | ||
246 | return -ENOMEM; | ||
247 | if (inlen == 0) { | ||
248 | data_direction = DMA_FROM_DEVICE; | ||
249 | } else if (outlen == 0 ) { | ||
250 | data_direction = DMA_TO_DEVICE; | ||
251 | } else { | ||
252 | /* | ||
253 | * Can this ever happen? | ||
254 | */ | ||
255 | data_direction = DMA_BIDIRECTIONAL; | ||
256 | } | ||
257 | |||
258 | } else { | ||
259 | buf = NULL; | ||
260 | data_direction = DMA_NONE; | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * Obtain the command from the user's address space. | ||
265 | */ | ||
266 | cmdlen = COMMAND_SIZE(opcode); | ||
267 | |||
268 | result = -EFAULT; | ||
269 | |||
270 | if (!access_ok(VERIFY_READ, cmd_in, cmdlen + inlen)) | ||
271 | goto error; | ||
272 | |||
273 | if(__copy_from_user(cmd, cmd_in, cmdlen)) | ||
274 | goto error; | ||
275 | |||
276 | /* | ||
277 | * Obtain the data to be sent to the device (if any). | ||
278 | */ | ||
279 | |||
280 | if(inlen && copy_from_user(buf, cmd_in + cmdlen, inlen)) | ||
281 | goto error; | ||
282 | |||
283 | switch (opcode) { | ||
284 | case SEND_DIAGNOSTIC: | ||
285 | case FORMAT_UNIT: | ||
286 | timeout = FORMAT_UNIT_TIMEOUT; | ||
287 | retries = 1; | ||
288 | break; | ||
289 | case START_STOP: | ||
290 | timeout = START_STOP_TIMEOUT; | ||
291 | retries = NORMAL_RETRIES; | ||
292 | break; | ||
293 | case MOVE_MEDIUM: | ||
294 | timeout = MOVE_MEDIUM_TIMEOUT; | ||
295 | retries = NORMAL_RETRIES; | ||
296 | break; | ||
297 | case READ_ELEMENT_STATUS: | ||
298 | timeout = READ_ELEMENT_STATUS_TIMEOUT; | ||
299 | retries = NORMAL_RETRIES; | ||
300 | break; | ||
301 | case READ_DEFECT_DATA: | ||
302 | timeout = READ_DEFECT_DATA_TIMEOUT; | ||
303 | retries = 1; | ||
304 | break; | ||
305 | default: | ||
306 | timeout = IOCTL_NORMAL_TIMEOUT; | ||
307 | retries = NORMAL_RETRIES; | ||
308 | break; | ||
309 | } | ||
310 | |||
311 | result = scsi_execute(sdev, cmd, data_direction, buf, needed, | ||
312 | sense, timeout, retries, 0); | ||
313 | |||
314 | /* | ||
315 | * If there was an error condition, pass the info back to the user. | ||
316 | */ | ||
317 | if (result) { | ||
318 | int sb_len = sizeof(*sense); | ||
319 | |||
320 | sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len; | ||
321 | if (copy_to_user(cmd_in, sense, sb_len)) | ||
322 | result = -EFAULT; | ||
323 | } else { | ||
324 | if (outlen && copy_to_user(cmd_in, buf, outlen)) | ||
325 | result = -EFAULT; | ||
326 | } | ||
327 | |||
328 | error: | ||
329 | kfree(buf); | ||
330 | return result; | ||
331 | } | ||
332 | EXPORT_SYMBOL(scsi_ioctl_send_command); | ||
333 | |||
334 | /* | ||
335 | * The scsi_ioctl_get_pci() function places into arg the value | 161 | * The scsi_ioctl_get_pci() function places into arg the value |
336 | * pci_dev::slot_name (8 characters) for the PCI device (if any). | 162 | * pci_dev::slot_name (8 characters) for the PCI device (if any). |
337 | * Returns: 0 on success | 163 | * Returns: 0 on success |
@@ -409,7 +235,7 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) | |||
409 | case SCSI_IOCTL_SEND_COMMAND: | 235 | case SCSI_IOCTL_SEND_COMMAND: |
410 | if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) | 236 | if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) |
411 | return -EACCES; | 237 | return -EACCES; |
412 | return scsi_ioctl_send_command(sdev, arg); | 238 | return sg_scsi_ioctl(NULL, sdev->request_queue, NULL, arg); |
413 | case SCSI_IOCTL_DOORLOCK: | 239 | case SCSI_IOCTL_DOORLOCK: |
414 | return scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); | 240 | return scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); |
415 | case SCSI_IOCTL_DOORUNLOCK: | 241 | case SCSI_IOCTL_DOORUNLOCK: |
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 7405d0df95db..fcf9243dfa7d 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c | |||
@@ -1044,7 +1044,7 @@ sg_ioctl(struct inode *inode, struct file *filp, | |||
1044 | if (!sg_allow_access(opcode, sdp->device->type)) | 1044 | if (!sg_allow_access(opcode, sdp->device->type)) |
1045 | return -EPERM; | 1045 | return -EPERM; |
1046 | } | 1046 | } |
1047 | return scsi_ioctl_send_command(sdp->device, p); | 1047 | return sg_scsi_ioctl(filp, sdp->device->request_queue, NULL, p); |
1048 | case SG_SET_DEBUG: | 1048 | case SG_SET_DEBUG: |
1049 | result = get_user(val, ip); | 1049 | result = get_user(val, ip); |
1050 | if (result) | 1050 | if (result) |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index d0cac8b58de7..59e1259b1c40 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
@@ -17,6 +17,8 @@ | |||
17 | 17 | ||
18 | #include <asm/scatterlist.h> | 18 | #include <asm/scatterlist.h> |
19 | 19 | ||
20 | struct scsi_ioctl_command; | ||
21 | |||
20 | struct request_queue; | 22 | struct request_queue; |
21 | typedef struct request_queue request_queue_t; | 23 | typedef struct request_queue request_queue_t; |
22 | struct elevator_queue; | 24 | struct elevator_queue; |
@@ -611,6 +613,8 @@ extern void blk_plug_device(request_queue_t *); | |||
611 | extern int blk_remove_plug(request_queue_t *); | 613 | extern int blk_remove_plug(request_queue_t *); |
612 | extern void blk_recount_segments(request_queue_t *, struct bio *); | 614 | extern void blk_recount_segments(request_queue_t *, struct bio *); |
613 | extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __user *); | 615 | extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __user *); |
616 | extern int sg_scsi_ioctl(struct file *, struct request_queue *, | ||
617 | struct gendisk *, struct scsi_ioctl_command __user *); | ||
614 | extern void blk_start_queue(request_queue_t *q); | 618 | extern void blk_start_queue(request_queue_t *q); |
615 | extern void blk_stop_queue(request_queue_t *q); | 619 | extern void blk_stop_queue(request_queue_t *q); |
616 | extern void blk_sync_queue(struct request_queue *q); | 620 | extern void blk_sync_queue(struct request_queue *q); |
diff --git a/include/scsi/scsi_ioctl.h b/include/scsi/scsi_ioctl.h index d4be4d92d586..edb9525386da 100644 --- a/include/scsi/scsi_ioctl.h +++ b/include/scsi/scsi_ioctl.h | |||
@@ -41,8 +41,6 @@ typedef struct scsi_fctargaddress { | |||
41 | } Scsi_FCTargAddress; | 41 | } Scsi_FCTargAddress; |
42 | 42 | ||
43 | extern int scsi_ioctl(struct scsi_device *, int, void __user *); | 43 | extern int scsi_ioctl(struct scsi_device *, int, void __user *); |
44 | extern int scsi_ioctl_send_command(struct scsi_device *, | ||
45 | struct scsi_ioctl_command __user *); | ||
46 | extern int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, | 44 | extern int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, |
47 | void __user *arg, struct file *filp); | 45 | void __user *arg, struct file *filp); |
48 | 46 | ||