diff options
author | Jens Axboe <jens.axboe@oracle.com> | 2007-07-09 06:38:05 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2007-07-16 02:52:44 -0400 |
commit | 3d6392cfbd7dc11f23058e3493683afab4ac13a3 (patch) | |
tree | 70c2b65c479f5feb7a5214a4a4930d489a069b1f /block/scsi_ioctl.c | |
parent | 8f41958bdd577731f7411c9605cfaa9db6766809 (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.c | 163 |
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 | ||
42 | EXPORT_SYMBOL(scsi_command_size); | 42 | EXPORT_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 | ||
48 | static int sg_get_version(int __user *p) | 46 | static 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 | ||
117 | static int verify_command(struct file *file, unsigned char *cmd) | 115 | static 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 | ||
216 | int 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 | } | ||
240 | EXPORT_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 | */ | ||
246 | int 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 | } | ||
262 | EXPORT_SYMBOL_GPL(blk_unmap_sghdr_rq); | ||
263 | |||
264 | int 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 | } | ||
299 | EXPORT_SYMBOL_GPL(blk_complete_sghdr_rq); | ||
300 | |||
225 | static int sg_io(struct file *file, request_queue_t *q, | 301 | static 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). */ | ||
344 | out: | 385 | out: |
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; |