diff options
-rw-r--r-- | drivers/scsi/ch.c | 120 |
1 files changed, 54 insertions, 66 deletions
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 2b07014cbc83..7aad15436d24 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c | |||
@@ -90,16 +90,6 @@ static const char * vendor_labels[CH_TYPES-4] = { | |||
90 | 90 | ||
91 | #define MAX_RETRIES 1 | 91 | #define MAX_RETRIES 1 |
92 | 92 | ||
93 | static int ch_probe(struct device *); | ||
94 | static int ch_remove(struct device *); | ||
95 | static int ch_open(struct inode * inode, struct file * filp); | ||
96 | static int ch_release(struct inode * inode, struct file * filp); | ||
97 | static long ch_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); | ||
98 | #ifdef CONFIG_COMPAT | ||
99 | static long ch_ioctl_compat(struct file * filp, | ||
100 | unsigned int cmd, unsigned long arg); | ||
101 | #endif | ||
102 | |||
103 | static struct class * ch_sysfs_class; | 93 | static struct class * ch_sysfs_class; |
104 | 94 | ||
105 | typedef struct { | 95 | typedef struct { |
@@ -118,27 +108,6 @@ typedef struct { | |||
118 | static DEFINE_IDR(ch_index_idr); | 108 | static DEFINE_IDR(ch_index_idr); |
119 | static DEFINE_SPINLOCK(ch_index_lock); | 109 | static DEFINE_SPINLOCK(ch_index_lock); |
120 | 110 | ||
121 | static struct scsi_driver ch_template = | ||
122 | { | ||
123 | .owner = THIS_MODULE, | ||
124 | .gendrv = { | ||
125 | .name = "ch", | ||
126 | .probe = ch_probe, | ||
127 | .remove = ch_remove, | ||
128 | }, | ||
129 | }; | ||
130 | |||
131 | static const struct file_operations changer_fops = | ||
132 | { | ||
133 | .owner = THIS_MODULE, | ||
134 | .open = ch_open, | ||
135 | .release = ch_release, | ||
136 | .unlocked_ioctl = ch_ioctl, | ||
137 | #ifdef CONFIG_COMPAT | ||
138 | .compat_ioctl = ch_ioctl_compat, | ||
139 | #endif | ||
140 | }; | ||
141 | |||
142 | static const struct { | 111 | static const struct { |
143 | unsigned char sense; | 112 | unsigned char sense; |
144 | unsigned char asc; | 113 | unsigned char asc; |
@@ -207,7 +176,7 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd, | |||
207 | { | 176 | { |
208 | int errno, retries = 0, timeout, result; | 177 | int errno, retries = 0, timeout, result; |
209 | struct scsi_sense_hdr sshdr; | 178 | struct scsi_sense_hdr sshdr; |
210 | 179 | ||
211 | timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS) | 180 | timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS) |
212 | ? timeout_init : timeout_move; | 181 | ? timeout_init : timeout_move; |
213 | 182 | ||
@@ -245,7 +214,7 @@ static int | |||
245 | ch_elem_to_typecode(scsi_changer *ch, u_int elem) | 214 | ch_elem_to_typecode(scsi_changer *ch, u_int elem) |
246 | { | 215 | { |
247 | int i; | 216 | int i; |
248 | 217 | ||
249 | for (i = 0; i < CH_TYPES; i++) { | 218 | for (i = 0; i < CH_TYPES; i++) { |
250 | if (elem >= ch->firsts[i] && | 219 | if (elem >= ch->firsts[i] && |
251 | elem < ch->firsts[i] + | 220 | elem < ch->firsts[i] + |
@@ -261,15 +230,15 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data) | |||
261 | u_char cmd[12]; | 230 | u_char cmd[12]; |
262 | u_char *buffer; | 231 | u_char *buffer; |
263 | int result; | 232 | int result; |
264 | 233 | ||
265 | buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); | 234 | buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); |
266 | if(!buffer) | 235 | if(!buffer) |
267 | return -ENOMEM; | 236 | return -ENOMEM; |
268 | 237 | ||
269 | retry: | 238 | retry: |
270 | memset(cmd,0,sizeof(cmd)); | 239 | memset(cmd,0,sizeof(cmd)); |
271 | cmd[0] = READ_ELEMENT_STATUS; | 240 | cmd[0] = READ_ELEMENT_STATUS; |
272 | cmd[1] = (ch->device->lun << 5) | | 241 | cmd[1] = (ch->device->lun << 5) | |
273 | (ch->voltags ? 0x10 : 0) | | 242 | (ch->voltags ? 0x10 : 0) | |
274 | ch_elem_to_typecode(ch,elem); | 243 | ch_elem_to_typecode(ch,elem); |
275 | cmd[2] = (elem >> 8) & 0xff; | 244 | cmd[2] = (elem >> 8) & 0xff; |
@@ -296,7 +265,7 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data) | |||
296 | return result; | 265 | return result; |
297 | } | 266 | } |
298 | 267 | ||
299 | static int | 268 | static int |
300 | ch_init_elem(scsi_changer *ch) | 269 | ch_init_elem(scsi_changer *ch) |
301 | { | 270 | { |
302 | int err; | 271 | int err; |
@@ -322,7 +291,7 @@ ch_readconfig(scsi_changer *ch) | |||
322 | buffer = kzalloc(512, GFP_KERNEL | GFP_DMA); | 291 | buffer = kzalloc(512, GFP_KERNEL | GFP_DMA); |
323 | if (!buffer) | 292 | if (!buffer) |
324 | return -ENOMEM; | 293 | return -ENOMEM; |
325 | 294 | ||
326 | memset(cmd,0,sizeof(cmd)); | 295 | memset(cmd,0,sizeof(cmd)); |
327 | cmd[0] = MODE_SENSE; | 296 | cmd[0] = MODE_SENSE; |
328 | cmd[1] = ch->device->lun << 5; | 297 | cmd[1] = ch->device->lun << 5; |
@@ -365,7 +334,7 @@ ch_readconfig(scsi_changer *ch) | |||
365 | } else { | 334 | } else { |
366 | vprintk("reading element address assigment page failed!\n"); | 335 | vprintk("reading element address assigment page failed!\n"); |
367 | } | 336 | } |
368 | 337 | ||
369 | /* vendor specific element types */ | 338 | /* vendor specific element types */ |
370 | for (i = 0; i < 4; i++) { | 339 | for (i = 0; i < 4; i++) { |
371 | if (0 == vendor_counts[i]) | 340 | if (0 == vendor_counts[i]) |
@@ -443,7 +412,7 @@ static int | |||
443 | ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate) | 412 | ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate) |
444 | { | 413 | { |
445 | u_char cmd[10]; | 414 | u_char cmd[10]; |
446 | 415 | ||
447 | dprintk("position: 0x%x\n",elem); | 416 | dprintk("position: 0x%x\n",elem); |
448 | if (0 == trans) | 417 | if (0 == trans) |
449 | trans = ch->firsts[CHET_MT]; | 418 | trans = ch->firsts[CHET_MT]; |
@@ -462,7 +431,7 @@ static int | |||
462 | ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate) | 431 | ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate) |
463 | { | 432 | { |
464 | u_char cmd[12]; | 433 | u_char cmd[12]; |
465 | 434 | ||
466 | dprintk("move: 0x%x => 0x%x\n",src,dest); | 435 | dprintk("move: 0x%x => 0x%x\n",src,dest); |
467 | if (0 == trans) | 436 | if (0 == trans) |
468 | trans = ch->firsts[CHET_MT]; | 437 | trans = ch->firsts[CHET_MT]; |
@@ -484,7 +453,7 @@ ch_exchange(scsi_changer *ch, u_int trans, u_int src, | |||
484 | u_int dest1, u_int dest2, int rotate1, int rotate2) | 453 | u_int dest1, u_int dest2, int rotate1, int rotate2) |
485 | { | 454 | { |
486 | u_char cmd[12]; | 455 | u_char cmd[12]; |
487 | 456 | ||
488 | dprintk("exchange: 0x%x => 0x%x => 0x%x\n", | 457 | dprintk("exchange: 0x%x => 0x%x => 0x%x\n", |
489 | src,dest1,dest2); | 458 | src,dest1,dest2); |
490 | if (0 == trans) | 459 | if (0 == trans) |
@@ -501,7 +470,7 @@ ch_exchange(scsi_changer *ch, u_int trans, u_int src, | |||
501 | cmd[8] = (dest2 >> 8) & 0xff; | 470 | cmd[8] = (dest2 >> 8) & 0xff; |
502 | cmd[9] = dest2 & 0xff; | 471 | cmd[9] = dest2 & 0xff; |
503 | cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0); | 472 | cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0); |
504 | 473 | ||
505 | return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE); | 474 | return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE); |
506 | } | 475 | } |
507 | 476 | ||
@@ -539,14 +508,14 @@ ch_set_voltag(scsi_changer *ch, u_int elem, | |||
539 | elem, tag); | 508 | elem, tag); |
540 | memset(cmd,0,sizeof(cmd)); | 509 | memset(cmd,0,sizeof(cmd)); |
541 | cmd[0] = SEND_VOLUME_TAG; | 510 | cmd[0] = SEND_VOLUME_TAG; |
542 | cmd[1] = (ch->device->lun << 5) | | 511 | cmd[1] = (ch->device->lun << 5) | |
543 | ch_elem_to_typecode(ch,elem); | 512 | ch_elem_to_typecode(ch,elem); |
544 | cmd[2] = (elem >> 8) & 0xff; | 513 | cmd[2] = (elem >> 8) & 0xff; |
545 | cmd[3] = elem & 0xff; | 514 | cmd[3] = elem & 0xff; |
546 | cmd[5] = clear | 515 | cmd[5] = clear |
547 | ? (alternate ? 0x0d : 0x0c) | 516 | ? (alternate ? 0x0d : 0x0c) |
548 | : (alternate ? 0x0b : 0x0a); | 517 | : (alternate ? 0x0b : 0x0a); |
549 | 518 | ||
550 | cmd[9] = 255; | 519 | cmd[9] = 255; |
551 | 520 | ||
552 | memcpy(buffer,tag,32); | 521 | memcpy(buffer,tag,32); |
@@ -562,7 +531,7 @@ static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest) | |||
562 | int retval = 0; | 531 | int retval = 0; |
563 | u_char data[16]; | 532 | u_char data[16]; |
564 | unsigned int i; | 533 | unsigned int i; |
565 | 534 | ||
566 | mutex_lock(&ch->lock); | 535 | mutex_lock(&ch->lock); |
567 | for (i = 0; i < ch->counts[type]; i++) { | 536 | for (i = 0; i < ch->counts[type]; i++) { |
568 | if (0 != ch_read_element_status | 537 | if (0 != ch_read_element_status |
@@ -629,18 +598,18 @@ static long ch_ioctl(struct file *file, | |||
629 | scsi_changer *ch = file->private_data; | 598 | scsi_changer *ch = file->private_data; |
630 | int retval; | 599 | int retval; |
631 | void __user *argp = (void __user *)arg; | 600 | void __user *argp = (void __user *)arg; |
632 | 601 | ||
633 | switch (cmd) { | 602 | switch (cmd) { |
634 | case CHIOGPARAMS: | 603 | case CHIOGPARAMS: |
635 | { | 604 | { |
636 | struct changer_params params; | 605 | struct changer_params params; |
637 | 606 | ||
638 | params.cp_curpicker = 0; | 607 | params.cp_curpicker = 0; |
639 | params.cp_npickers = ch->counts[CHET_MT]; | 608 | params.cp_npickers = ch->counts[CHET_MT]; |
640 | params.cp_nslots = ch->counts[CHET_ST]; | 609 | params.cp_nslots = ch->counts[CHET_ST]; |
641 | params.cp_nportals = ch->counts[CHET_IE]; | 610 | params.cp_nportals = ch->counts[CHET_IE]; |
642 | params.cp_ndrives = ch->counts[CHET_DT]; | 611 | params.cp_ndrives = ch->counts[CHET_DT]; |
643 | 612 | ||
644 | if (copy_to_user(argp, ¶ms, sizeof(params))) | 613 | if (copy_to_user(argp, ¶ms, sizeof(params))) |
645 | return -EFAULT; | 614 | return -EFAULT; |
646 | return 0; | 615 | return 0; |
@@ -670,11 +639,11 @@ static long ch_ioctl(struct file *file, | |||
670 | return -EFAULT; | 639 | return -EFAULT; |
671 | return 0; | 640 | return 0; |
672 | } | 641 | } |
673 | 642 | ||
674 | case CHIOPOSITION: | 643 | case CHIOPOSITION: |
675 | { | 644 | { |
676 | struct changer_position pos; | 645 | struct changer_position pos; |
677 | 646 | ||
678 | if (copy_from_user(&pos, argp, sizeof (pos))) | 647 | if (copy_from_user(&pos, argp, sizeof (pos))) |
679 | return -EFAULT; | 648 | return -EFAULT; |
680 | 649 | ||
@@ -689,7 +658,7 @@ static long ch_ioctl(struct file *file, | |||
689 | mutex_unlock(&ch->lock); | 658 | mutex_unlock(&ch->lock); |
690 | return retval; | 659 | return retval; |
691 | } | 660 | } |
692 | 661 | ||
693 | case CHIOMOVE: | 662 | case CHIOMOVE: |
694 | { | 663 | { |
695 | struct changer_move mv; | 664 | struct changer_move mv; |
@@ -702,7 +671,7 @@ static long ch_ioctl(struct file *file, | |||
702 | dprintk("CHIOMOVE: invalid parameter\n"); | 671 | dprintk("CHIOMOVE: invalid parameter\n"); |
703 | return -EBADSLT; | 672 | return -EBADSLT; |
704 | } | 673 | } |
705 | 674 | ||
706 | mutex_lock(&ch->lock); | 675 | mutex_lock(&ch->lock); |
707 | retval = ch_move(ch,0, | 676 | retval = ch_move(ch,0, |
708 | ch->firsts[mv.cm_fromtype] + mv.cm_fromunit, | 677 | ch->firsts[mv.cm_fromtype] + mv.cm_fromunit, |
@@ -715,7 +684,7 @@ static long ch_ioctl(struct file *file, | |||
715 | case CHIOEXCHANGE: | 684 | case CHIOEXCHANGE: |
716 | { | 685 | { |
717 | struct changer_exchange mv; | 686 | struct changer_exchange mv; |
718 | 687 | ||
719 | if (copy_from_user(&mv, argp, sizeof (mv))) | 688 | if (copy_from_user(&mv, argp, sizeof (mv))) |
720 | return -EFAULT; | 689 | return -EFAULT; |
721 | 690 | ||
@@ -725,7 +694,7 @@ static long ch_ioctl(struct file *file, | |||
725 | dprintk("CHIOEXCHANGE: invalid parameter\n"); | 694 | dprintk("CHIOEXCHANGE: invalid parameter\n"); |
726 | return -EBADSLT; | 695 | return -EBADSLT; |
727 | } | 696 | } |
728 | 697 | ||
729 | mutex_lock(&ch->lock); | 698 | mutex_lock(&ch->lock); |
730 | retval = ch_exchange | 699 | retval = ch_exchange |
731 | (ch,0, | 700 | (ch,0, |
@@ -740,7 +709,7 @@ static long ch_ioctl(struct file *file, | |||
740 | case CHIOGSTATUS: | 709 | case CHIOGSTATUS: |
741 | { | 710 | { |
742 | struct changer_element_status ces; | 711 | struct changer_element_status ces; |
743 | 712 | ||
744 | if (copy_from_user(&ces, argp, sizeof (ces))) | 713 | if (copy_from_user(&ces, argp, sizeof (ces))) |
745 | return -EFAULT; | 714 | return -EFAULT; |
746 | if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES) | 715 | if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES) |
@@ -756,19 +725,19 @@ static long ch_ioctl(struct file *file, | |||
756 | u_char *buffer; | 725 | u_char *buffer; |
757 | unsigned int elem; | 726 | unsigned int elem; |
758 | int result,i; | 727 | int result,i; |
759 | 728 | ||
760 | if (copy_from_user(&cge, argp, sizeof (cge))) | 729 | if (copy_from_user(&cge, argp, sizeof (cge))) |
761 | return -EFAULT; | 730 | return -EFAULT; |
762 | 731 | ||
763 | if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit)) | 732 | if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit)) |
764 | return -EINVAL; | 733 | return -EINVAL; |
765 | elem = ch->firsts[cge.cge_type] + cge.cge_unit; | 734 | elem = ch->firsts[cge.cge_type] + cge.cge_unit; |
766 | 735 | ||
767 | buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); | 736 | buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); |
768 | if (!buffer) | 737 | if (!buffer) |
769 | return -ENOMEM; | 738 | return -ENOMEM; |
770 | mutex_lock(&ch->lock); | 739 | mutex_lock(&ch->lock); |
771 | 740 | ||
772 | voltag_retry: | 741 | voltag_retry: |
773 | memset(cmd,0,sizeof(cmd)); | 742 | memset(cmd,0,sizeof(cmd)); |
774 | cmd[0] = READ_ELEMENT_STATUS; | 743 | cmd[0] = READ_ELEMENT_STATUS; |
@@ -779,7 +748,7 @@ static long ch_ioctl(struct file *file, | |||
779 | cmd[3] = elem & 0xff; | 748 | cmd[3] = elem & 0xff; |
780 | cmd[5] = 1; | 749 | cmd[5] = 1; |
781 | cmd[9] = 255; | 750 | cmd[9] = 255; |
782 | 751 | ||
783 | if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256, DMA_FROM_DEVICE))) { | 752 | if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256, DMA_FROM_DEVICE))) { |
784 | cge.cge_status = buffer[18]; | 753 | cge.cge_status = buffer[18]; |
785 | cge.cge_flags = 0; | 754 | cge.cge_flags = 0; |
@@ -819,7 +788,7 @@ static long ch_ioctl(struct file *file, | |||
819 | } | 788 | } |
820 | kfree(buffer); | 789 | kfree(buffer); |
821 | mutex_unlock(&ch->lock); | 790 | mutex_unlock(&ch->lock); |
822 | 791 | ||
823 | if (copy_to_user(argp, &cge, sizeof (cge))) | 792 | if (copy_to_user(argp, &cge, sizeof (cge))) |
824 | return -EFAULT; | 793 | return -EFAULT; |
825 | return result; | 794 | return result; |
@@ -832,7 +801,7 @@ static long ch_ioctl(struct file *file, | |||
832 | mutex_unlock(&ch->lock); | 801 | mutex_unlock(&ch->lock); |
833 | return retval; | 802 | return retval; |
834 | } | 803 | } |
835 | 804 | ||
836 | case CHIOSVOLTAG: | 805 | case CHIOSVOLTAG: |
837 | { | 806 | { |
838 | struct changer_set_voltag csv; | 807 | struct changer_set_voltag csv; |
@@ -873,7 +842,7 @@ static long ch_ioctl_compat(struct file * file, | |||
873 | unsigned int cmd, unsigned long arg) | 842 | unsigned int cmd, unsigned long arg) |
874 | { | 843 | { |
875 | scsi_changer *ch = file->private_data; | 844 | scsi_changer *ch = file->private_data; |
876 | 845 | ||
877 | switch (cmd) { | 846 | switch (cmd) { |
878 | case CHIOGPARAMS: | 847 | case CHIOGPARAMS: |
879 | case CHIOGVPARAMS: | 848 | case CHIOGVPARAMS: |
@@ -889,7 +858,7 @@ static long ch_ioctl_compat(struct file * file, | |||
889 | { | 858 | { |
890 | struct changer_element_status32 ces32; | 859 | struct changer_element_status32 ces32; |
891 | unsigned char __user *data; | 860 | unsigned char __user *data; |
892 | 861 | ||
893 | if (copy_from_user(&ces32, (void __user *)arg, sizeof (ces32))) | 862 | if (copy_from_user(&ces32, (void __user *)arg, sizeof (ces32))) |
894 | return -EFAULT; | 863 | return -EFAULT; |
895 | if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES) | 864 | if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES) |
@@ -982,10 +951,29 @@ static int ch_remove(struct device *dev) | |||
982 | return 0; | 951 | return 0; |
983 | } | 952 | } |
984 | 953 | ||
954 | static struct scsi_driver ch_template = { | ||
955 | .owner = THIS_MODULE, | ||
956 | .gendrv = { | ||
957 | .name = "ch", | ||
958 | .probe = ch_probe, | ||
959 | .remove = ch_remove, | ||
960 | }, | ||
961 | }; | ||
962 | |||
963 | static const struct file_operations changer_fops = { | ||
964 | .owner = THIS_MODULE, | ||
965 | .open = ch_open, | ||
966 | .release = ch_release, | ||
967 | .unlocked_ioctl = ch_ioctl, | ||
968 | #ifdef CONFIG_COMPAT | ||
969 | .compat_ioctl = ch_ioctl_compat, | ||
970 | #endif | ||
971 | }; | ||
972 | |||
985 | static int __init init_ch_module(void) | 973 | static int __init init_ch_module(void) |
986 | { | 974 | { |
987 | int rc; | 975 | int rc; |
988 | 976 | ||
989 | printk(KERN_INFO "SCSI Media Changer driver v" VERSION " \n"); | 977 | printk(KERN_INFO "SCSI Media Changer driver v" VERSION " \n"); |
990 | ch_sysfs_class = class_create(THIS_MODULE, "scsi_changer"); | 978 | ch_sysfs_class = class_create(THIS_MODULE, "scsi_changer"); |
991 | if (IS_ERR(ch_sysfs_class)) { | 979 | if (IS_ERR(ch_sysfs_class)) { |
@@ -1010,7 +998,7 @@ static int __init init_ch_module(void) | |||
1010 | return rc; | 998 | return rc; |
1011 | } | 999 | } |
1012 | 1000 | ||
1013 | static void __exit exit_ch_module(void) | 1001 | static void __exit exit_ch_module(void) |
1014 | { | 1002 | { |
1015 | scsi_unregister_driver(&ch_template.gendrv); | 1003 | scsi_unregister_driver(&ch_template.gendrv); |
1016 | unregister_chrdev(SCSI_CHANGER_MAJOR, "ch"); | 1004 | unregister_chrdev(SCSI_CHANGER_MAJOR, "ch"); |