aboutsummaryrefslogtreecommitdiffstats
path: root/block/scsi_ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/scsi_ioctl.c')
-rw-r--r--block/scsi_ioctl.c163
1 files changed, 95 insertions, 68 deletions
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index e83f1dbf7c29..a26ba07955fe 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -41,8 +41,6 @@ const unsigned char scsi_command_size[8] =
41 41
42EXPORT_SYMBOL(scsi_command_size); 42EXPORT_SYMBOL(scsi_command_size);
43 43
44#define BLK_DEFAULT_TIMEOUT (60 * HZ)
45
46#include <scsi/sg.h> 44#include <scsi/sg.h>
47 45
48static int sg_get_version(int __user *p) 46static int sg_get_version(int __user *p)
@@ -114,7 +112,7 @@ static int sg_emulated_host(request_queue_t *q, int __user *p)
114#define safe_for_read(cmd) [cmd] = CMD_READ_SAFE 112#define safe_for_read(cmd) [cmd] = CMD_READ_SAFE
115#define safe_for_write(cmd) [cmd] = CMD_WRITE_SAFE 113#define safe_for_write(cmd) [cmd] = CMD_WRITE_SAFE
116 114
117static int verify_command(struct file *file, unsigned char *cmd) 115int blk_verify_command(unsigned char *cmd, int has_write_perm)
118{ 116{
119 static unsigned char cmd_type[256] = { 117 static unsigned char cmd_type[256] = {
120 118
@@ -193,18 +191,11 @@ static int verify_command(struct file *file, unsigned char *cmd)
193 safe_for_write(GPCMD_SET_STREAMING), 191 safe_for_write(GPCMD_SET_STREAMING),
194 }; 192 };
195 unsigned char type = cmd_type[cmd[0]]; 193 unsigned char type = cmd_type[cmd[0]];
196 int has_write_perm = 0;
197 194
198 /* Anybody who can open the device can do a read-safe command */ 195 /* Anybody who can open the device can do a read-safe command */
199 if (type & CMD_READ_SAFE) 196 if (type & CMD_READ_SAFE)
200 return 0; 197 return 0;
201 198
202 /*
203 * file can be NULL from ioctl_by_bdev()...
204 */
205 if (file)
206 has_write_perm = file->f_mode & FMODE_WRITE;
207
208 /* Write-safe commands just require a writable open.. */ 199 /* Write-safe commands just require a writable open.. */
209 if ((type & CMD_WRITE_SAFE) && has_write_perm) 200 if ((type & CMD_WRITE_SAFE) && has_write_perm)
210 return 0; 201 return 0;
@@ -221,25 +212,96 @@ static int verify_command(struct file *file, unsigned char *cmd)
221 /* Otherwise fail it with an "Operation not permitted" */ 212 /* Otherwise fail it with an "Operation not permitted" */
222 return -EPERM; 213 return -EPERM;
223} 214}
215EXPORT_SYMBOL_GPL(blk_verify_command);
216
217int blk_fill_sghdr_rq(request_queue_t *q, struct request *rq,
218 struct sg_io_hdr *hdr, int has_write_perm)
219{
220 memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
221
222 if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len))
223 return -EFAULT;
224 if (blk_verify_command(rq->cmd, has_write_perm))
225 return -EPERM;
226
227 /*
228 * fill in request structure
229 */
230 rq->cmd_len = hdr->cmd_len;
231 rq->cmd_type = REQ_TYPE_BLOCK_PC;
232
233 rq->timeout = (hdr->timeout * HZ) / 1000;
234 if (!rq->timeout)
235 rq->timeout = q->sg_timeout;
236 if (!rq->timeout)
237 rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
238
239 return 0;
240}
241EXPORT_SYMBOL_GPL(blk_fill_sghdr_rq);
242
243/*
244 * unmap a request that was previously mapped to this sg_io_hdr. handles
245 * both sg and non-sg sg_io_hdr.
246 */
247int blk_unmap_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr)
248{
249 blk_rq_unmap_user(rq->bio);
250 blk_put_request(rq);
251 return 0;
252}
253EXPORT_SYMBOL_GPL(blk_unmap_sghdr_rq);
254
255int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
256 struct bio *bio)
257{
258 int r, ret = 0;
259
260 /*
261 * fill in all the output members
262 */
263 hdr->status = rq->errors & 0xff;
264 hdr->masked_status = status_byte(rq->errors);
265 hdr->msg_status = msg_byte(rq->errors);
266 hdr->host_status = host_byte(rq->errors);
267 hdr->driver_status = driver_byte(rq->errors);
268 hdr->info = 0;
269 if (hdr->masked_status || hdr->host_status || hdr->driver_status)
270 hdr->info |= SG_INFO_CHECK;
271 hdr->resid = rq->data_len;
272 hdr->sb_len_wr = 0;
273
274 if (rq->sense_len && hdr->sbp) {
275 int len = min((unsigned int) hdr->mx_sb_len, rq->sense_len);
276
277 if (!copy_to_user(hdr->sbp, rq->sense, len))
278 hdr->sb_len_wr = len;
279 else
280 ret = -EFAULT;
281 }
282
283 rq->bio = bio;
284 r = blk_unmap_sghdr_rq(rq, hdr);
285 if (ret)
286 r = ret;
287
288 return r;
289}
290EXPORT_SYMBOL_GPL(blk_complete_sghdr_rq);
224 291
225static int sg_io(struct file *file, request_queue_t *q, 292static int sg_io(struct file *file, request_queue_t *q,
226 struct gendisk *bd_disk, struct sg_io_hdr *hdr) 293 struct gendisk *bd_disk, struct sg_io_hdr *hdr)
227{ 294{
228 unsigned long start_time, timeout; 295 unsigned long start_time;
229 int writing = 0, ret = 0; 296 int writing = 0, ret = 0, has_write_perm = 0;
230 struct request *rq; 297 struct request *rq;
231 char sense[SCSI_SENSE_BUFFERSIZE]; 298 char sense[SCSI_SENSE_BUFFERSIZE];
232 unsigned char cmd[BLK_MAX_CDB];
233 struct bio *bio; 299 struct bio *bio;
234 300
235 if (hdr->interface_id != 'S') 301 if (hdr->interface_id != 'S')
236 return -EINVAL; 302 return -EINVAL;
237 if (hdr->cmd_len > BLK_MAX_CDB) 303 if (hdr->cmd_len > BLK_MAX_CDB)
238 return -EINVAL; 304 return -EINVAL;
239 if (copy_from_user(cmd, hdr->cmdp, hdr->cmd_len))
240 return -EFAULT;
241 if (verify_command(file, cmd))
242 return -EPERM;
243 305
244 if (hdr->dxfer_len > (q->max_hw_sectors << 9)) 306 if (hdr->dxfer_len > (q->max_hw_sectors << 9))
245 return -EIO; 307 return -EIO;
@@ -260,25 +322,13 @@ static int sg_io(struct file *file, request_queue_t *q,
260 if (!rq) 322 if (!rq)
261 return -ENOMEM; 323 return -ENOMEM;
262 324
263 /* 325 if (file)
264 * fill in request structure 326 has_write_perm = file->f_mode & FMODE_WRITE;
265 */
266 rq->cmd_len = hdr->cmd_len;
267 memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
268 memcpy(rq->cmd, cmd, hdr->cmd_len);
269
270 memset(sense, 0, sizeof(sense));
271 rq->sense = sense;
272 rq->sense_len = 0;
273
274 rq->cmd_type = REQ_TYPE_BLOCK_PC;
275 327
276 timeout = msecs_to_jiffies(hdr->timeout); 328 if (blk_fill_sghdr_rq(q, rq, hdr, has_write_perm)) {
277 rq->timeout = (timeout < INT_MAX) ? timeout : INT_MAX; 329 blk_put_request(rq);
278 if (!rq->timeout) 330 return -EFAULT;
279 rq->timeout = q->sg_timeout; 331 }
280 if (!rq->timeout)
281 rq->timeout = BLK_DEFAULT_TIMEOUT;
282 332
283 if (hdr->iovec_count) { 333 if (hdr->iovec_count) {
284 const int size = sizeof(struct sg_iovec) * hdr->iovec_count; 334 const int size = sizeof(struct sg_iovec) * hdr->iovec_count;
@@ -306,6 +356,9 @@ static int sg_io(struct file *file, request_queue_t *q,
306 goto out; 356 goto out;
307 357
308 bio = rq->bio; 358 bio = rq->bio;
359 memset(sense, 0, sizeof(sense));
360 rq->sense = sense;
361 rq->sense_len = 0;
309 rq->retries = 0; 362 rq->retries = 0;
310 363
311 start_time = jiffies; 364 start_time = jiffies;
@@ -316,31 +369,9 @@ static int sg_io(struct file *file, request_queue_t *q,
316 */ 369 */
317 blk_execute_rq(q, bd_disk, rq, 0); 370 blk_execute_rq(q, bd_disk, rq, 0);
318 371
319 /* write to all output members */
320 hdr->status = 0xff & rq->errors;
321 hdr->masked_status = status_byte(rq->errors);
322 hdr->msg_status = msg_byte(rq->errors);
323 hdr->host_status = host_byte(rq->errors);
324 hdr->driver_status = driver_byte(rq->errors);
325 hdr->info = 0;
326 if (hdr->masked_status || hdr->host_status || hdr->driver_status)
327 hdr->info |= SG_INFO_CHECK;
328 hdr->resid = rq->data_len;
329 hdr->duration = ((jiffies - start_time) * 1000) / HZ; 372 hdr->duration = ((jiffies - start_time) * 1000) / HZ;
330 hdr->sb_len_wr = 0;
331
332 if (rq->sense_len && hdr->sbp) {
333 int len = min((unsigned int) hdr->mx_sb_len, rq->sense_len);
334
335 if (!copy_to_user(hdr->sbp, rq->sense, len))
336 hdr->sb_len_wr = len;
337 }
338 373
339 if (blk_rq_unmap_user(bio)) 374 return blk_complete_sghdr_rq(rq, hdr, bio);
340 ret = -EFAULT;
341
342 /* may not have succeeded, but output values written to control
343 * structure (struct sg_io_hdr). */
344out: 375out:
345 blk_put_request(rq); 376 blk_put_request(rq);
346 return ret; 377 return ret;
@@ -427,7 +458,7 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q,
427 if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len)) 458 if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len))
428 goto error; 459 goto error;
429 460
430 err = verify_command(file, rq->cmd); 461 err = blk_verify_command(rq->cmd, file->f_mode & FMODE_WRITE);
431 if (err) 462 if (err)
432 goto error; 463 goto error;
433 464
@@ -454,7 +485,7 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q,
454 rq->retries = 1; 485 rq->retries = 1;
455 break; 486 break;
456 default: 487 default:
457 rq->timeout = BLK_DEFAULT_TIMEOUT; 488 rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
458 break; 489 break;
459 } 490 }
460 491
@@ -501,7 +532,7 @@ static int __blk_send_generic(request_queue_t *q, struct gendisk *bd_disk, int c
501 rq->cmd_type = REQ_TYPE_BLOCK_PC; 532 rq->cmd_type = REQ_TYPE_BLOCK_PC;
502 rq->data = NULL; 533 rq->data = NULL;
503 rq->data_len = 0; 534 rq->data_len = 0;
504 rq->timeout = BLK_DEFAULT_TIMEOUT; 535 rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
505 memset(rq->cmd, 0, sizeof(rq->cmd)); 536 memset(rq->cmd, 0, sizeof(rq->cmd));
506 rq->cmd[0] = cmd; 537 rq->cmd[0] = cmd;
507 rq->cmd[4] = data; 538 rq->cmd[4] = data;
@@ -517,16 +548,12 @@ static inline int blk_send_start_stop(request_queue_t *q, struct gendisk *bd_dis
517 return __blk_send_generic(q, bd_disk, GPCMD_START_STOP_UNIT, data); 548 return __blk_send_generic(q, bd_disk, GPCMD_START_STOP_UNIT, data);
518} 549}
519 550
520int scsi_cmd_ioctl(struct file *file, struct gendisk *bd_disk, unsigned int cmd, void __user *arg) 551int scsi_cmd_ioctl(struct file *file, struct request_queue *q,
552 struct gendisk *bd_disk, unsigned int cmd, void __user *arg)
521{ 553{
522 request_queue_t *q;
523 int err; 554 int err;
524 555
525 q = bd_disk->queue; 556 if (!q || blk_get_queue(q))
526 if (!q)
527 return -ENXIO;
528
529 if (blk_get_queue(q))
530 return -ENXIO; 557 return -ENXIO;
531 558
532 switch (cmd) { 559 switch (cmd) {