diff options
Diffstat (limited to 'drivers/scsi/sg.c')
-rw-r--r-- | drivers/scsi/sg.c | 203 |
1 files changed, 132 insertions, 71 deletions
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index cf6b1f0fb124..ce8332297dfa 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c | |||
@@ -18,8 +18,8 @@ | |||
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | static int sg_version_num = 30532; /* 2 digits for each component */ | 21 | static int sg_version_num = 30533; /* 2 digits for each component */ |
22 | #define SG_VERSION_STR "3.5.32" | 22 | #define SG_VERSION_STR "3.5.33" |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: | 25 | * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: |
@@ -61,7 +61,7 @@ static int sg_version_num = 30532; /* 2 digits for each component */ | |||
61 | 61 | ||
62 | #ifdef CONFIG_SCSI_PROC_FS | 62 | #ifdef CONFIG_SCSI_PROC_FS |
63 | #include <linux/proc_fs.h> | 63 | #include <linux/proc_fs.h> |
64 | static char *sg_version_date = "20050117"; | 64 | static char *sg_version_date = "20050328"; |
65 | 65 | ||
66 | static int sg_proc_init(void); | 66 | static int sg_proc_init(void); |
67 | static void sg_proc_cleanup(void); | 67 | static void sg_proc_cleanup(void); |
@@ -331,14 +331,13 @@ sg_release(struct inode *inode, struct file *filp) | |||
331 | static ssize_t | 331 | static ssize_t |
332 | sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) | 332 | sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) |
333 | { | 333 | { |
334 | int res; | ||
335 | Sg_device *sdp; | 334 | Sg_device *sdp; |
336 | Sg_fd *sfp; | 335 | Sg_fd *sfp; |
337 | Sg_request *srp; | 336 | Sg_request *srp; |
338 | int req_pack_id = -1; | 337 | int req_pack_id = -1; |
339 | struct sg_header old_hdr; | ||
340 | sg_io_hdr_t new_hdr; | ||
341 | sg_io_hdr_t *hp; | 338 | sg_io_hdr_t *hp; |
339 | struct sg_header *old_hdr = NULL; | ||
340 | int retval = 0; | ||
342 | 341 | ||
343 | if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) | 342 | if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) |
344 | return -ENXIO; | 343 | return -ENXIO; |
@@ -347,98 +346,138 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) | |||
347 | if (!access_ok(VERIFY_WRITE, buf, count)) | 346 | if (!access_ok(VERIFY_WRITE, buf, count)) |
348 | return -EFAULT; | 347 | return -EFAULT; |
349 | if (sfp->force_packid && (count >= SZ_SG_HEADER)) { | 348 | if (sfp->force_packid && (count >= SZ_SG_HEADER)) { |
350 | if (__copy_from_user(&old_hdr, buf, SZ_SG_HEADER)) | 349 | old_hdr = kmalloc(SZ_SG_HEADER, GFP_KERNEL); |
351 | return -EFAULT; | 350 | if (!old_hdr) |
352 | if (old_hdr.reply_len < 0) { | 351 | return -ENOMEM; |
352 | if (__copy_from_user(old_hdr, buf, SZ_SG_HEADER)) { | ||
353 | retval = -EFAULT; | ||
354 | goto free_old_hdr; | ||
355 | } | ||
356 | if (old_hdr->reply_len < 0) { | ||
353 | if (count >= SZ_SG_IO_HDR) { | 357 | if (count >= SZ_SG_IO_HDR) { |
354 | if (__copy_from_user | 358 | sg_io_hdr_t *new_hdr; |
355 | (&new_hdr, buf, SZ_SG_IO_HDR)) | 359 | new_hdr = kmalloc(SZ_SG_IO_HDR, GFP_KERNEL); |
356 | return -EFAULT; | 360 | if (!new_hdr) { |
357 | req_pack_id = new_hdr.pack_id; | 361 | retval = -ENOMEM; |
362 | goto free_old_hdr; | ||
363 | } | ||
364 | retval =__copy_from_user | ||
365 | (new_hdr, buf, SZ_SG_IO_HDR); | ||
366 | req_pack_id = new_hdr->pack_id; | ||
367 | kfree(new_hdr); | ||
368 | if (retval) { | ||
369 | retval = -EFAULT; | ||
370 | goto free_old_hdr; | ||
371 | } | ||
358 | } | 372 | } |
359 | } else | 373 | } else |
360 | req_pack_id = old_hdr.pack_id; | 374 | req_pack_id = old_hdr->pack_id; |
361 | } | 375 | } |
362 | srp = sg_get_rq_mark(sfp, req_pack_id); | 376 | srp = sg_get_rq_mark(sfp, req_pack_id); |
363 | if (!srp) { /* now wait on packet to arrive */ | 377 | if (!srp) { /* now wait on packet to arrive */ |
364 | if (sdp->detached) | 378 | if (sdp->detached) { |
365 | return -ENODEV; | 379 | retval = -ENODEV; |
366 | if (filp->f_flags & O_NONBLOCK) | 380 | goto free_old_hdr; |
367 | return -EAGAIN; | 381 | } |
382 | if (filp->f_flags & O_NONBLOCK) { | ||
383 | retval = -EAGAIN; | ||
384 | goto free_old_hdr; | ||
385 | } | ||
368 | while (1) { | 386 | while (1) { |
369 | res = 0; /* following is a macro that beats race condition */ | 387 | retval = 0; /* following macro beats race condition */ |
370 | __wait_event_interruptible(sfp->read_wait, | 388 | __wait_event_interruptible(sfp->read_wait, |
371 | (sdp->detached || (srp = sg_get_rq_mark(sfp, req_pack_id))), | 389 | (sdp->detached || |
372 | res); | 390 | (srp = sg_get_rq_mark(sfp, req_pack_id))), |
373 | if (sdp->detached) | 391 | retval); |
374 | return -ENODEV; | 392 | if (sdp->detached) { |
375 | if (0 == res) | 393 | retval = -ENODEV; |
394 | goto free_old_hdr; | ||
395 | } | ||
396 | if (0 == retval) | ||
376 | break; | 397 | break; |
377 | return res; /* -ERESTARTSYS because signal hit process */ | 398 | |
399 | /* -ERESTARTSYS as signal hit process */ | ||
400 | goto free_old_hdr; | ||
378 | } | 401 | } |
379 | } | 402 | } |
380 | if (srp->header.interface_id != '\0') | 403 | if (srp->header.interface_id != '\0') { |
381 | return sg_new_read(sfp, buf, count, srp); | 404 | retval = sg_new_read(sfp, buf, count, srp); |
405 | goto free_old_hdr; | ||
406 | } | ||
382 | 407 | ||
383 | hp = &srp->header; | 408 | hp = &srp->header; |
384 | memset(&old_hdr, 0, SZ_SG_HEADER); | 409 | if (old_hdr == NULL) { |
385 | old_hdr.reply_len = (int) hp->timeout; | 410 | old_hdr = kmalloc(SZ_SG_HEADER, GFP_KERNEL); |
386 | old_hdr.pack_len = old_hdr.reply_len; /* very old, strange behaviour */ | 411 | if (! old_hdr) { |
387 | old_hdr.pack_id = hp->pack_id; | 412 | retval = -ENOMEM; |
388 | old_hdr.twelve_byte = | 413 | goto free_old_hdr; |
414 | } | ||
415 | } | ||
416 | memset(old_hdr, 0, SZ_SG_HEADER); | ||
417 | old_hdr->reply_len = (int) hp->timeout; | ||
418 | old_hdr->pack_len = old_hdr->reply_len; /* old, strange behaviour */ | ||
419 | old_hdr->pack_id = hp->pack_id; | ||
420 | old_hdr->twelve_byte = | ||
389 | ((srp->data.cmd_opcode >= 0xc0) && (12 == hp->cmd_len)) ? 1 : 0; | 421 | ((srp->data.cmd_opcode >= 0xc0) && (12 == hp->cmd_len)) ? 1 : 0; |
390 | old_hdr.target_status = hp->masked_status; | 422 | old_hdr->target_status = hp->masked_status; |
391 | old_hdr.host_status = hp->host_status; | 423 | old_hdr->host_status = hp->host_status; |
392 | old_hdr.driver_status = hp->driver_status; | 424 | old_hdr->driver_status = hp->driver_status; |
393 | if ((CHECK_CONDITION & hp->masked_status) || | 425 | if ((CHECK_CONDITION & hp->masked_status) || |
394 | (DRIVER_SENSE & hp->driver_status)) | 426 | (DRIVER_SENSE & hp->driver_status)) |
395 | memcpy(old_hdr.sense_buffer, srp->sense_b, | 427 | memcpy(old_hdr->sense_buffer, srp->sense_b, |
396 | sizeof (old_hdr.sense_buffer)); | 428 | sizeof (old_hdr->sense_buffer)); |
397 | switch (hp->host_status) { | 429 | switch (hp->host_status) { |
398 | /* This setup of 'result' is for backward compatibility and is best | 430 | /* This setup of 'result' is for backward compatibility and is best |
399 | ignored by the user who should use target, host + driver status */ | 431 | ignored by the user who should use target, host + driver status */ |
400 | case DID_OK: | 432 | case DID_OK: |
401 | case DID_PASSTHROUGH: | 433 | case DID_PASSTHROUGH: |
402 | case DID_SOFT_ERROR: | 434 | case DID_SOFT_ERROR: |
403 | old_hdr.result = 0; | 435 | old_hdr->result = 0; |
404 | break; | 436 | break; |
405 | case DID_NO_CONNECT: | 437 | case DID_NO_CONNECT: |
406 | case DID_BUS_BUSY: | 438 | case DID_BUS_BUSY: |
407 | case DID_TIME_OUT: | 439 | case DID_TIME_OUT: |
408 | old_hdr.result = EBUSY; | 440 | old_hdr->result = EBUSY; |
409 | break; | 441 | break; |
410 | case DID_BAD_TARGET: | 442 | case DID_BAD_TARGET: |
411 | case DID_ABORT: | 443 | case DID_ABORT: |
412 | case DID_PARITY: | 444 | case DID_PARITY: |
413 | case DID_RESET: | 445 | case DID_RESET: |
414 | case DID_BAD_INTR: | 446 | case DID_BAD_INTR: |
415 | old_hdr.result = EIO; | 447 | old_hdr->result = EIO; |
416 | break; | 448 | break; |
417 | case DID_ERROR: | 449 | case DID_ERROR: |
418 | old_hdr.result = (srp->sense_b[0] == 0 && | 450 | old_hdr->result = (srp->sense_b[0] == 0 && |
419 | hp->masked_status == GOOD) ? 0 : EIO; | 451 | hp->masked_status == GOOD) ? 0 : EIO; |
420 | break; | 452 | break; |
421 | default: | 453 | default: |
422 | old_hdr.result = EIO; | 454 | old_hdr->result = EIO; |
423 | break; | 455 | break; |
424 | } | 456 | } |
425 | 457 | ||
426 | /* Now copy the result back to the user buffer. */ | 458 | /* Now copy the result back to the user buffer. */ |
427 | if (count >= SZ_SG_HEADER) { | 459 | if (count >= SZ_SG_HEADER) { |
428 | if (__copy_to_user(buf, &old_hdr, SZ_SG_HEADER)) | 460 | if (__copy_to_user(buf, old_hdr, SZ_SG_HEADER)) { |
429 | return -EFAULT; | 461 | retval = -EFAULT; |
462 | goto free_old_hdr; | ||
463 | } | ||
430 | buf += SZ_SG_HEADER; | 464 | buf += SZ_SG_HEADER; |
431 | if (count > old_hdr.reply_len) | 465 | if (count > old_hdr->reply_len) |
432 | count = old_hdr.reply_len; | 466 | count = old_hdr->reply_len; |
433 | if (count > SZ_SG_HEADER) { | 467 | if (count > SZ_SG_HEADER) { |
434 | if ((res = | 468 | if (sg_read_oxfer(srp, buf, count - SZ_SG_HEADER)) { |
435 | sg_read_oxfer(srp, buf, count - SZ_SG_HEADER))) | 469 | retval = -EFAULT; |
436 | return -EFAULT; | 470 | goto free_old_hdr; |
471 | } | ||
437 | } | 472 | } |
438 | } else | 473 | } else |
439 | count = (old_hdr.result == 0) ? 0 : -EIO; | 474 | count = (old_hdr->result == 0) ? 0 : -EIO; |
440 | sg_finish_rem_req(srp); | 475 | sg_finish_rem_req(srp); |
441 | return count; | 476 | retval = count; |
477 | free_old_hdr: | ||
478 | if (old_hdr) | ||
479 | kfree(old_hdr); | ||
480 | return retval; | ||
442 | } | 481 | } |
443 | 482 | ||
444 | static ssize_t | 483 | static ssize_t |
@@ -725,7 +764,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, | |||
725 | srp->data.sglist_len = 0; | 764 | srp->data.sglist_len = 0; |
726 | srp->data.bufflen = 0; | 765 | srp->data.bufflen = 0; |
727 | srp->data.buffer = NULL; | 766 | srp->data.buffer = NULL; |
728 | hp->duration = jiffies; /* unit jiffies now, millisecs after done */ | 767 | hp->duration = jiffies_to_msecs(jiffies); |
729 | /* Now send everything of to mid-level. The next time we hear about this | 768 | /* Now send everything of to mid-level. The next time we hear about this |
730 | packet is when sg_cmd_done() is called (i.e. a callback). */ | 769 | packet is when sg_cmd_done() is called (i.e. a callback). */ |
731 | scsi_do_req(SRpnt, (void *) cmnd, | 770 | scsi_do_req(SRpnt, (void *) cmnd, |
@@ -938,8 +977,13 @@ sg_ioctl(struct inode *inode, struct file *filp, | |||
938 | if (!access_ok(VERIFY_WRITE, p, SZ_SG_REQ_INFO * SG_MAX_QUEUE)) | 977 | if (!access_ok(VERIFY_WRITE, p, SZ_SG_REQ_INFO * SG_MAX_QUEUE)) |
939 | return -EFAULT; | 978 | return -EFAULT; |
940 | else { | 979 | else { |
941 | sg_req_info_t rinfo[SG_MAX_QUEUE]; | 980 | sg_req_info_t *rinfo; |
942 | Sg_request *srp; | 981 | unsigned int ms; |
982 | |||
983 | rinfo = kmalloc(SZ_SG_REQ_INFO * SG_MAX_QUEUE, | ||
984 | GFP_KERNEL); | ||
985 | if (!rinfo) | ||
986 | return -ENOMEM; | ||
943 | read_lock_irqsave(&sfp->rq_list_lock, iflags); | 987 | read_lock_irqsave(&sfp->rq_list_lock, iflags); |
944 | for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE; | 988 | for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE; |
945 | ++val, srp = srp ? srp->nextrp : srp) { | 989 | ++val, srp = srp ? srp->nextrp : srp) { |
@@ -950,19 +994,30 @@ sg_ioctl(struct inode *inode, struct file *filp, | |||
950 | srp->header.masked_status & | 994 | srp->header.masked_status & |
951 | srp->header.host_status & | 995 | srp->header.host_status & |
952 | srp->header.driver_status; | 996 | srp->header.driver_status; |
953 | rinfo[val].duration = | 997 | if (srp->done) |
954 | srp->done ? srp->header.duration : | 998 | rinfo[val].duration = |
955 | jiffies_to_msecs( | 999 | srp->header.duration; |
956 | jiffies - srp->header.duration); | 1000 | else { |
1001 | ms = jiffies_to_msecs(jiffies); | ||
1002 | rinfo[val].duration = | ||
1003 | (ms > srp->header.duration) ? | ||
1004 | (ms - srp->header.duration) : 0; | ||
1005 | } | ||
957 | rinfo[val].orphan = srp->orphan; | 1006 | rinfo[val].orphan = srp->orphan; |
958 | rinfo[val].sg_io_owned = srp->sg_io_owned; | 1007 | rinfo[val].sg_io_owned = |
959 | rinfo[val].pack_id = srp->header.pack_id; | 1008 | srp->sg_io_owned; |
960 | rinfo[val].usr_ptr = srp->header.usr_ptr; | 1009 | rinfo[val].pack_id = |
1010 | srp->header.pack_id; | ||
1011 | rinfo[val].usr_ptr = | ||
1012 | srp->header.usr_ptr; | ||
961 | } | 1013 | } |
962 | } | 1014 | } |
963 | read_unlock_irqrestore(&sfp->rq_list_lock, iflags); | 1015 | read_unlock_irqrestore(&sfp->rq_list_lock, iflags); |
964 | return (__copy_to_user(p, rinfo, | 1016 | result = __copy_to_user(p, rinfo, |
965 | SZ_SG_REQ_INFO * SG_MAX_QUEUE) ? -EFAULT : 0); | 1017 | SZ_SG_REQ_INFO * SG_MAX_QUEUE); |
1018 | result = result ? -EFAULT : 0; | ||
1019 | kfree(rinfo); | ||
1020 | return result; | ||
966 | } | 1021 | } |
967 | case SG_EMULATED_HOST: | 1022 | case SG_EMULATED_HOST: |
968 | if (sdp->detached) | 1023 | if (sdp->detached) |
@@ -1209,11 +1264,12 @@ static int | |||
1209 | sg_mmap(struct file *filp, struct vm_area_struct *vma) | 1264 | sg_mmap(struct file *filp, struct vm_area_struct *vma) |
1210 | { | 1265 | { |
1211 | Sg_fd *sfp; | 1266 | Sg_fd *sfp; |
1212 | unsigned long req_sz = vma->vm_end - vma->vm_start; | 1267 | unsigned long req_sz; |
1213 | Sg_scatter_hold *rsv_schp; | 1268 | Sg_scatter_hold *rsv_schp; |
1214 | 1269 | ||
1215 | if ((!filp) || (!vma) || (!(sfp = (Sg_fd *) filp->private_data))) | 1270 | if ((!filp) || (!vma) || (!(sfp = (Sg_fd *) filp->private_data))) |
1216 | return -ENXIO; | 1271 | return -ENXIO; |
1272 | req_sz = vma->vm_end - vma->vm_start; | ||
1217 | SCSI_LOG_TIMEOUT(3, printk("sg_mmap starting, vm_start=%p, len=%d\n", | 1273 | SCSI_LOG_TIMEOUT(3, printk("sg_mmap starting, vm_start=%p, len=%d\n", |
1218 | (void *) vma->vm_start, (int) req_sz)); | 1274 | (void *) vma->vm_start, (int) req_sz)); |
1219 | if (vma->vm_pgoff) | 1275 | if (vma->vm_pgoff) |
@@ -1260,6 +1316,7 @@ sg_cmd_done(Scsi_Cmnd * SCpnt) | |||
1260 | Sg_fd *sfp; | 1316 | Sg_fd *sfp; |
1261 | Sg_request *srp = NULL; | 1317 | Sg_request *srp = NULL; |
1262 | unsigned long iflags; | 1318 | unsigned long iflags; |
1319 | unsigned int ms; | ||
1263 | 1320 | ||
1264 | if (SCpnt && (SRpnt = SCpnt->sc_request)) | 1321 | if (SCpnt && (SRpnt = SCpnt->sc_request)) |
1265 | srp = (Sg_request *) SRpnt->upper_private_data; | 1322 | srp = (Sg_request *) SRpnt->upper_private_data; |
@@ -1296,9 +1353,9 @@ sg_cmd_done(Scsi_Cmnd * SCpnt) | |||
1296 | SCSI_LOG_TIMEOUT(4, printk("sg_cmd_done: %s, pack_id=%d, res=0x%x\n", | 1353 | SCSI_LOG_TIMEOUT(4, printk("sg_cmd_done: %s, pack_id=%d, res=0x%x\n", |
1297 | sdp->disk->disk_name, srp->header.pack_id, (int) SRpnt->sr_result)); | 1354 | sdp->disk->disk_name, srp->header.pack_id, (int) SRpnt->sr_result)); |
1298 | srp->header.resid = SCpnt->resid; | 1355 | srp->header.resid = SCpnt->resid; |
1299 | /* N.B. unit of duration changes here from jiffies to millisecs */ | 1356 | ms = jiffies_to_msecs(jiffies); |
1300 | srp->header.duration = | 1357 | srp->header.duration = (ms > srp->header.duration) ? |
1301 | jiffies_to_msecs(jiffies - srp->header.duration); | 1358 | (ms - srp->header.duration) : 0; |
1302 | if (0 != SRpnt->sr_result) { | 1359 | if (0 != SRpnt->sr_result) { |
1303 | struct scsi_sense_hdr sshdr; | 1360 | struct scsi_sense_hdr sshdr; |
1304 | 1361 | ||
@@ -2396,7 +2453,7 @@ sg_add_request(Sg_fd * sfp) | |||
2396 | } | 2453 | } |
2397 | if (resp) { | 2454 | if (resp) { |
2398 | resp->nextrp = NULL; | 2455 | resp->nextrp = NULL; |
2399 | resp->header.duration = jiffies; | 2456 | resp->header.duration = jiffies_to_msecs(jiffies); |
2400 | resp->my_cmdp = NULL; | 2457 | resp->my_cmdp = NULL; |
2401 | } | 2458 | } |
2402 | write_unlock_irqrestore(&sfp->rq_list_lock, iflags); | 2459 | write_unlock_irqrestore(&sfp->rq_list_lock, iflags); |
@@ -2991,6 +3048,7 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) | |||
2991 | Sg_fd *fp; | 3048 | Sg_fd *fp; |
2992 | const sg_io_hdr_t *hp; | 3049 | const sg_io_hdr_t *hp; |
2993 | const char * cp; | 3050 | const char * cp; |
3051 | unsigned int ms; | ||
2994 | 3052 | ||
2995 | for (k = 0; (fp = sg_get_nth_sfp(sdp, k)); ++k) { | 3053 | for (k = 0; (fp = sg_get_nth_sfp(sdp, k)); ++k) { |
2996 | seq_printf(s, " FD(%d): timeout=%dms bufflen=%d " | 3054 | seq_printf(s, " FD(%d): timeout=%dms bufflen=%d " |
@@ -3029,10 +3087,13 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) | |||
3029 | srp->header.pack_id, blen); | 3087 | srp->header.pack_id, blen); |
3030 | if (srp->done) | 3088 | if (srp->done) |
3031 | seq_printf(s, " dur=%d", hp->duration); | 3089 | seq_printf(s, " dur=%d", hp->duration); |
3032 | else | 3090 | else { |
3091 | ms = jiffies_to_msecs(jiffies); | ||
3033 | seq_printf(s, " t_o/elap=%d/%d", | 3092 | seq_printf(s, " t_o/elap=%d/%d", |
3034 | new_interface ? hp->timeout : jiffies_to_msecs(fp->timeout), | 3093 | (new_interface ? hp->timeout : |
3035 | jiffies_to_msecs(hp->duration ? (jiffies - hp->duration) : 0)); | 3094 | jiffies_to_msecs(fp->timeout)), |
3095 | (ms > hp->duration ? ms - hp->duration : 0)); | ||
3096 | } | ||
3036 | seq_printf(s, "ms sgat=%d op=0x%02x\n", usg, | 3097 | seq_printf(s, "ms sgat=%d op=0x%02x\n", usg, |
3037 | (int) srp->data.cmd_opcode); | 3098 | (int) srp->data.cmd_opcode); |
3038 | } | 3099 | } |