aboutsummaryrefslogtreecommitdiffstats
path: root/block/scsi_ioctl.c
diff options
context:
space:
mode:
authorJens Axboe <jens.axboe@oracle.com>2007-07-09 06:38:05 -0400
committerJens Axboe <jens.axboe@oracle.com>2007-07-16 02:52:44 -0400
commit3d6392cfbd7dc11f23058e3493683afab4ac13a3 (patch)
tree70c2b65c479f5feb7a5214a4a4930d489a069b1f /block/scsi_ioctl.c
parent8f41958bdd577731f7411c9605cfaa9db6766809 (diff)
bsg: support for full generic block layer SG v3
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'block/scsi_ioctl.c')
-rw-r--r--block/scsi_ioctl.c163
1 files changed, 102 insertions, 61 deletions
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index e83f1dbf7c29..88fd008d38bd 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) 115static int 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;
@@ -222,24 +213,104 @@ static int verify_command(struct file *file, unsigned char *cmd)
222 return -EPERM; 213 return -EPERM;
223} 214}
224 215
216int blk_fill_sghdr_rq(request_queue_t *q, struct request *rq,
217 struct sg_io_hdr *hdr, int has_write_perm)
218{
219 memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
220
221 if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len))
222 return -EFAULT;
223 if (verify_command(rq->cmd, has_write_perm))
224 return -EPERM;
225
226 /*
227 * fill in request structure
228 */
229 rq->cmd_len = hdr->cmd_len;
230 rq->cmd_type = REQ_TYPE_BLOCK_PC;
231
232 rq->timeout = (hdr->timeout * HZ) / 1000;
233 if (!rq->timeout)
234 rq->timeout = q->sg_timeout;
235 if (!rq->timeout)
236 rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
237
238 return 0;
239}
240EXPORT_SYMBOL_GPL(blk_fill_sghdr_rq);
241
242/*
243 * unmap a request that was previously mapped to this sg_io_hdr. handles
244 * both sg and non-sg sg_io_hdr.
245 */
246int blk_unmap_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr)
247{
248 struct bio *bio = rq->bio;
249
250 /*
251 * also releases request
252 */
253 if (!hdr->iovec_count)
254 return blk_rq_unmap_user(bio, hdr->dxfer_len);
255
256 rq_for_each_bio(bio, rq)
257 bio_unmap_user(bio);
258
259 blk_put_request(rq);
260 return 0;
261}
262EXPORT_SYMBOL_GPL(blk_unmap_sghdr_rq);
263
264int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
265 struct bio *bio)
266{
267 int r, ret = 0;
268
269 /*
270 * fill in all the output members
271 */
272 hdr->status = rq->errors & 0xff;
273 hdr->masked_status = status_byte(rq->errors);
274 hdr->msg_status = msg_byte(rq->errors);
275 hdr->host_status = host_byte(rq->errors);
276 hdr->driver_status = driver_byte(rq->errors);
277 hdr->info = 0;
278 if (hdr->masked_status || hdr->host_status || hdr->driver_status)
279 hdr->info |= SG_INFO_CHECK;
280 hdr->resid = rq->data_len;
281 hdr->sb_len_wr = 0;
282
283 if (rq->sense_len && hdr->sbp) {
284 int len = min((unsigned int) hdr->mx_sb_len, rq->sense_len);
285
286 if (!copy_to_user(hdr->sbp, rq->sense, len))
287 hdr->sb_len_wr = len;
288 else
289 ret = -EFAULT;
290 }
291
292 rq->bio = bio;
293 r = blk_unmap_sghdr_rq(rq, hdr);
294 if (ret)
295 r = ret;
296
297 return r;
298}
299EXPORT_SYMBOL_GPL(blk_complete_sghdr_rq);
300
225static int sg_io(struct file *file, request_queue_t *q, 301static int sg_io(struct file *file, request_queue_t *q,
226 struct gendisk *bd_disk, struct sg_io_hdr *hdr) 302 struct gendisk *bd_disk, struct sg_io_hdr *hdr)
227{ 303{
228 unsigned long start_time, timeout; 304 unsigned long start_time;
229 int writing = 0, ret = 0; 305 int writing = 0, ret = 0, has_write_perm = 0;
230 struct request *rq; 306 struct request *rq;
231 char sense[SCSI_SENSE_BUFFERSIZE]; 307 char sense[SCSI_SENSE_BUFFERSIZE];
232 unsigned char cmd[BLK_MAX_CDB];
233 struct bio *bio; 308 struct bio *bio;
234 309
235 if (hdr->interface_id != 'S') 310 if (hdr->interface_id != 'S')
236 return -EINVAL; 311 return -EINVAL;
237 if (hdr->cmd_len > BLK_MAX_CDB) 312 if (hdr->cmd_len > BLK_MAX_CDB)
238 return -EINVAL; 313 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 314
244 if (hdr->dxfer_len > (q->max_hw_sectors << 9)) 315 if (hdr->dxfer_len > (q->max_hw_sectors << 9))
245 return -EIO; 316 return -EIO;
@@ -260,25 +331,14 @@ static int sg_io(struct file *file, request_queue_t *q,
260 if (!rq) 331 if (!rq)
261 return -ENOMEM; 332 return -ENOMEM;
262 333
263 /* 334 if (file)
264 * fill in request structure 335 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 336
276 timeout = msecs_to_jiffies(hdr->timeout); 337 if (blk_fill_sghdr_rq(q, rq, hdr, has_write_perm)) {
277 rq->timeout = (timeout < INT_MAX) ? timeout : INT_MAX; 338 blk_rq_unmap_user(bio, hdr->dxfer_len);
278 if (!rq->timeout) 339 blk_put_request(rq);
279 rq->timeout = q->sg_timeout; 340 return -EFAULT;
280 if (!rq->timeout) 341 }
281 rq->timeout = BLK_DEFAULT_TIMEOUT;
282 342
283 if (hdr->iovec_count) { 343 if (hdr->iovec_count) {
284 const int size = sizeof(struct sg_iovec) * hdr->iovec_count; 344 const int size = sizeof(struct sg_iovec) * hdr->iovec_count;
@@ -306,6 +366,9 @@ static int sg_io(struct file *file, request_queue_t *q,
306 goto out; 366 goto out;
307 367
308 bio = rq->bio; 368 bio = rq->bio;
369 memset(sense, 0, sizeof(sense));
370 rq->sense = sense;
371 rq->sense_len = 0;
309 rq->retries = 0; 372 rq->retries = 0;
310 373
311 start_time = jiffies; 374 start_time = jiffies;
@@ -316,31 +379,9 @@ static int sg_io(struct file *file, request_queue_t *q,
316 */ 379 */
317 blk_execute_rq(q, bd_disk, rq, 0); 380 blk_execute_rq(q, bd_disk, rq, 0);
318 381
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; 382 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
339 if (blk_rq_unmap_user(bio))
340 ret = -EFAULT;
341 383
342 /* may not have succeeded, but output values written to control 384 return blk_complete_sghdr_rq(rq, hdr, bio);
343 * structure (struct sg_io_hdr). */
344out: 385out:
345 blk_put_request(rq); 386 blk_put_request(rq);
346 return ret; 387 return ret;
@@ -427,7 +468,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)) 468 if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len))
428 goto error; 469 goto error;
429 470
430 err = verify_command(file, rq->cmd); 471 err = verify_command(rq->cmd, file->f_mode & FMODE_WRITE);
431 if (err) 472 if (err)
432 goto error; 473 goto error;
433 474
@@ -454,7 +495,7 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q,
454 rq->retries = 1; 495 rq->retries = 1;
455 break; 496 break;
456 default: 497 default:
457 rq->timeout = BLK_DEFAULT_TIMEOUT; 498 rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
458 break; 499 break;
459 } 500 }
460 501
@@ -501,7 +542,7 @@ static int __blk_send_generic(request_queue_t *q, struct gendisk *bd_disk, int c
501 rq->cmd_type = REQ_TYPE_BLOCK_PC; 542 rq->cmd_type = REQ_TYPE_BLOCK_PC;
502 rq->data = NULL; 543 rq->data = NULL;
503 rq->data_len = 0; 544 rq->data_len = 0;
504 rq->timeout = BLK_DEFAULT_TIMEOUT; 545 rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
505 memset(rq->cmd, 0, sizeof(rq->cmd)); 546 memset(rq->cmd, 0, sizeof(rq->cmd));
506 rq->cmd[0] = cmd; 547 rq->cmd[0] = cmd;
507 rq->cmd[4] = data; 548 rq->cmd[4] = data;