diff options
Diffstat (limited to 'drivers/block/scsi_ioctl.c')
-rw-r--r-- | drivers/block/scsi_ioctl.c | 60 |
1 files changed, 36 insertions, 24 deletions
diff --git a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c index 681871ca5d60..abb2df249fd3 100644 --- a/drivers/block/scsi_ioctl.c +++ b/drivers/block/scsi_ioctl.c | |||
@@ -216,7 +216,7 @@ static int sg_io(struct file *file, request_queue_t *q, | |||
216 | struct gendisk *bd_disk, struct sg_io_hdr *hdr) | 216 | struct gendisk *bd_disk, struct sg_io_hdr *hdr) |
217 | { | 217 | { |
218 | unsigned long start_time; | 218 | unsigned long start_time; |
219 | int reading, writing; | 219 | int writing = 0, ret = 0; |
220 | struct request *rq; | 220 | struct request *rq; |
221 | struct bio *bio; | 221 | struct bio *bio; |
222 | char sense[SCSI_SENSE_BUFFERSIZE]; | 222 | char sense[SCSI_SENSE_BUFFERSIZE]; |
@@ -231,38 +231,48 @@ static int sg_io(struct file *file, request_queue_t *q, | |||
231 | if (verify_command(file, cmd)) | 231 | if (verify_command(file, cmd)) |
232 | return -EPERM; | 232 | return -EPERM; |
233 | 233 | ||
234 | /* | ||
235 | * we'll do that later | ||
236 | */ | ||
237 | if (hdr->iovec_count) | ||
238 | return -EOPNOTSUPP; | ||
239 | |||
240 | if (hdr->dxfer_len > (q->max_sectors << 9)) | 234 | if (hdr->dxfer_len > (q->max_sectors << 9)) |
241 | return -EIO; | 235 | return -EIO; |
242 | 236 | ||
243 | reading = writing = 0; | 237 | if (hdr->dxfer_len) |
244 | if (hdr->dxfer_len) { | ||
245 | switch (hdr->dxfer_direction) { | 238 | switch (hdr->dxfer_direction) { |
246 | default: | 239 | default: |
247 | return -EINVAL; | 240 | return -EINVAL; |
248 | case SG_DXFER_TO_FROM_DEV: | 241 | case SG_DXFER_TO_FROM_DEV: |
249 | reading = 1; | ||
250 | /* fall through */ | ||
251 | case SG_DXFER_TO_DEV: | 242 | case SG_DXFER_TO_DEV: |
252 | writing = 1; | 243 | writing = 1; |
253 | break; | 244 | break; |
254 | case SG_DXFER_FROM_DEV: | 245 | case SG_DXFER_FROM_DEV: |
255 | reading = 1; | ||
256 | break; | 246 | break; |
257 | } | 247 | } |
258 | 248 | ||
259 | rq = blk_rq_map_user(q, writing ? WRITE : READ, hdr->dxferp, | 249 | rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL); |
260 | hdr->dxfer_len); | 250 | if (!rq) |
251 | return -ENOMEM; | ||
252 | |||
253 | if (hdr->iovec_count) { | ||
254 | const int size = sizeof(struct sg_iovec) * hdr->iovec_count; | ||
255 | struct sg_iovec *iov; | ||
256 | |||
257 | iov = kmalloc(size, GFP_KERNEL); | ||
258 | if (!iov) { | ||
259 | ret = -ENOMEM; | ||
260 | goto out; | ||
261 | } | ||
262 | |||
263 | if (copy_from_user(iov, hdr->dxferp, size)) { | ||
264 | kfree(iov); | ||
265 | ret = -EFAULT; | ||
266 | goto out; | ||
267 | } | ||
268 | |||
269 | ret = blk_rq_map_user_iov(q, rq, iov, hdr->iovec_count); | ||
270 | kfree(iov); | ||
271 | } else if (hdr->dxfer_len) | ||
272 | ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len); | ||
261 | 273 | ||
262 | if (IS_ERR(rq)) | 274 | if (ret) |
263 | return PTR_ERR(rq); | 275 | goto out; |
264 | } else | ||
265 | rq = blk_get_request(q, READ, __GFP_WAIT); | ||
266 | 276 | ||
267 | /* | 277 | /* |
268 | * fill in request structure | 278 | * fill in request structure |
@@ -298,7 +308,7 @@ static int sg_io(struct file *file, request_queue_t *q, | |||
298 | * (if he doesn't check that is his problem). | 308 | * (if he doesn't check that is his problem). |
299 | * N.B. a non-zero SCSI status is _not_ necessarily an error. | 309 | * N.B. a non-zero SCSI status is _not_ necessarily an error. |
300 | */ | 310 | */ |
301 | blk_execute_rq(q, bd_disk, rq); | 311 | blk_execute_rq(q, bd_disk, rq, 0); |
302 | 312 | ||
303 | /* write to all output members */ | 313 | /* write to all output members */ |
304 | hdr->status = 0xff & rq->errors; | 314 | hdr->status = 0xff & rq->errors; |
@@ -320,12 +330,14 @@ static int sg_io(struct file *file, request_queue_t *q, | |||
320 | hdr->sb_len_wr = len; | 330 | hdr->sb_len_wr = len; |
321 | } | 331 | } |
322 | 332 | ||
323 | if (blk_rq_unmap_user(rq, bio, hdr->dxfer_len)) | 333 | if (blk_rq_unmap_user(bio, hdr->dxfer_len)) |
324 | return -EFAULT; | 334 | ret = -EFAULT; |
325 | 335 | ||
326 | /* may not have succeeded, but output values written to control | 336 | /* may not have succeeded, but output values written to control |
327 | * structure (struct sg_io_hdr). */ | 337 | * structure (struct sg_io_hdr). */ |
328 | return 0; | 338 | out: |
339 | blk_put_request(rq); | ||
340 | return ret; | ||
329 | } | 341 | } |
330 | 342 | ||
331 | #define OMAX_SB_LEN 16 /* For backward compatibility */ | 343 | #define OMAX_SB_LEN 16 /* For backward compatibility */ |
@@ -408,7 +420,7 @@ static int sg_scsi_ioctl(struct file *file, request_queue_t *q, | |||
408 | rq->data_len = bytes; | 420 | rq->data_len = bytes; |
409 | rq->flags |= REQ_BLOCK_PC; | 421 | rq->flags |= REQ_BLOCK_PC; |
410 | 422 | ||
411 | blk_execute_rq(q, bd_disk, rq); | 423 | blk_execute_rq(q, bd_disk, rq, 0); |
412 | err = rq->errors & 0xff; /* only 8 bit SCSI status */ | 424 | err = rq->errors & 0xff; /* only 8 bit SCSI status */ |
413 | if (err) { | 425 | if (err) { |
414 | if (rq->sense_len && rq->sense) { | 426 | if (rq->sense_len && rq->sense) { |
@@ -561,7 +573,7 @@ int scsi_cmd_ioctl(struct file *file, struct gendisk *bd_disk, unsigned int cmd, | |||
561 | rq->cmd[0] = GPCMD_START_STOP_UNIT; | 573 | rq->cmd[0] = GPCMD_START_STOP_UNIT; |
562 | rq->cmd[4] = 0x02 + (close != 0); | 574 | rq->cmd[4] = 0x02 + (close != 0); |
563 | rq->cmd_len = 6; | 575 | rq->cmd_len = 6; |
564 | err = blk_execute_rq(q, bd_disk, rq); | 576 | err = blk_execute_rq(q, bd_disk, rq, 0); |
565 | blk_put_request(rq); | 577 | blk_put_request(rq); |
566 | break; | 578 | break; |
567 | default: | 579 | default: |