diff options
Diffstat (limited to 'drivers/scsi/ch.c')
-rw-r--r-- | drivers/scsi/ch.c | 215 |
1 files changed, 109 insertions, 106 deletions
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 2311019304c0..7aad15436d24 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/compat.h> | 21 | #include <linux/compat.h> |
22 | #include <linux/chio.h> /* here are all the ioctls */ | 22 | #include <linux/chio.h> /* here are all the ioctls */ |
23 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
24 | #include <linux/idr.h> | ||
24 | 25 | ||
25 | #include <scsi/scsi.h> | 26 | #include <scsi/scsi.h> |
26 | #include <scsi/scsi_cmnd.h> | 27 | #include <scsi/scsi_cmnd.h> |
@@ -33,6 +34,7 @@ | |||
33 | 34 | ||
34 | #define CH_DT_MAX 16 | 35 | #define CH_DT_MAX 16 |
35 | #define CH_TYPES 8 | 36 | #define CH_TYPES 8 |
37 | #define CH_MAX_DEVS 128 | ||
36 | 38 | ||
37 | MODULE_DESCRIPTION("device driver for scsi media changer devices"); | 39 | MODULE_DESCRIPTION("device driver for scsi media changer devices"); |
38 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org>"); | 40 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org>"); |
@@ -88,17 +90,6 @@ static const char * vendor_labels[CH_TYPES-4] = { | |||
88 | 90 | ||
89 | #define MAX_RETRIES 1 | 91 | #define MAX_RETRIES 1 |
90 | 92 | ||
91 | static int ch_probe(struct device *); | ||
92 | static int ch_remove(struct device *); | ||
93 | static int ch_open(struct inode * inode, struct file * filp); | ||
94 | static int ch_release(struct inode * inode, struct file * filp); | ||
95 | static int ch_ioctl(struct inode * inode, struct file * filp, | ||
96 | unsigned int cmd, unsigned long arg); | ||
97 | #ifdef CONFIG_COMPAT | ||
98 | static long ch_ioctl_compat(struct file * filp, | ||
99 | unsigned int cmd, unsigned long arg); | ||
100 | #endif | ||
101 | |||
102 | static struct class * ch_sysfs_class; | 93 | static struct class * ch_sysfs_class; |
103 | 94 | ||
104 | typedef struct { | 95 | typedef struct { |
@@ -114,30 +105,8 @@ typedef struct { | |||
114 | struct mutex lock; | 105 | struct mutex lock; |
115 | } scsi_changer; | 106 | } scsi_changer; |
116 | 107 | ||
117 | static LIST_HEAD(ch_devlist); | 108 | static DEFINE_IDR(ch_index_idr); |
118 | static DEFINE_SPINLOCK(ch_devlist_lock); | 109 | static DEFINE_SPINLOCK(ch_index_lock); |
119 | static int ch_devcount; | ||
120 | |||
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 | .ioctl = ch_ioctl, | ||
137 | #ifdef CONFIG_COMPAT | ||
138 | .compat_ioctl = ch_ioctl_compat, | ||
139 | #endif | ||
140 | }; | ||
141 | 110 | ||
142 | static const struct { | 111 | static const struct { |
143 | unsigned char sense; | 112 | unsigned char sense; |
@@ -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 |
@@ -599,20 +568,17 @@ ch_release(struct inode *inode, struct file *file) | |||
599 | static int | 568 | static int |
600 | ch_open(struct inode *inode, struct file *file) | 569 | ch_open(struct inode *inode, struct file *file) |
601 | { | 570 | { |
602 | scsi_changer *tmp, *ch; | 571 | scsi_changer *ch; |
603 | int minor = iminor(inode); | 572 | int minor = iminor(inode); |
604 | 573 | ||
605 | spin_lock(&ch_devlist_lock); | 574 | spin_lock(&ch_index_lock); |
606 | ch = NULL; | 575 | ch = idr_find(&ch_index_idr, minor); |
607 | list_for_each_entry(tmp,&ch_devlist,list) { | 576 | |
608 | if (tmp->minor == minor) | ||
609 | ch = tmp; | ||
610 | } | ||
611 | if (NULL == ch || scsi_device_get(ch->device)) { | 577 | if (NULL == ch || scsi_device_get(ch->device)) { |
612 | spin_unlock(&ch_devlist_lock); | 578 | spin_unlock(&ch_index_lock); |
613 | return -ENXIO; | 579 | return -ENXIO; |
614 | } | 580 | } |
615 | spin_unlock(&ch_devlist_lock); | 581 | spin_unlock(&ch_index_lock); |
616 | 582 | ||
617 | file->private_data = ch; | 583 | file->private_data = ch; |
618 | return 0; | 584 | return 0; |
@@ -626,24 +592,24 @@ ch_checkrange(scsi_changer *ch, unsigned int type, unsigned int unit) | |||
626 | return 0; | 592 | return 0; |
627 | } | 593 | } |
628 | 594 | ||
629 | static int ch_ioctl(struct inode * inode, struct file * file, | 595 | static long ch_ioctl(struct file *file, |
630 | unsigned int cmd, unsigned long arg) | 596 | unsigned int cmd, unsigned long arg) |
631 | { | 597 | { |
632 | scsi_changer *ch = file->private_data; | 598 | scsi_changer *ch = file->private_data; |
633 | int retval; | 599 | int retval; |
634 | void __user *argp = (void __user *)arg; | 600 | void __user *argp = (void __user *)arg; |
635 | 601 | ||
636 | switch (cmd) { | 602 | switch (cmd) { |
637 | case CHIOGPARAMS: | 603 | case CHIOGPARAMS: |
638 | { | 604 | { |
639 | struct changer_params params; | 605 | struct changer_params params; |
640 | 606 | ||
641 | params.cp_curpicker = 0; | 607 | params.cp_curpicker = 0; |
642 | params.cp_npickers = ch->counts[CHET_MT]; | 608 | params.cp_npickers = ch->counts[CHET_MT]; |
643 | params.cp_nslots = ch->counts[CHET_ST]; | 609 | params.cp_nslots = ch->counts[CHET_ST]; |
644 | params.cp_nportals = ch->counts[CHET_IE]; | 610 | params.cp_nportals = ch->counts[CHET_IE]; |
645 | params.cp_ndrives = ch->counts[CHET_DT]; | 611 | params.cp_ndrives = ch->counts[CHET_DT]; |
646 | 612 | ||
647 | if (copy_to_user(argp, ¶ms, sizeof(params))) | 613 | if (copy_to_user(argp, ¶ms, sizeof(params))) |
648 | return -EFAULT; | 614 | return -EFAULT; |
649 | return 0; | 615 | return 0; |
@@ -673,11 +639,11 @@ static int ch_ioctl(struct inode * inode, struct file * file, | |||
673 | return -EFAULT; | 639 | return -EFAULT; |
674 | return 0; | 640 | return 0; |
675 | } | 641 | } |
676 | 642 | ||
677 | case CHIOPOSITION: | 643 | case CHIOPOSITION: |
678 | { | 644 | { |
679 | struct changer_position pos; | 645 | struct changer_position pos; |
680 | 646 | ||
681 | if (copy_from_user(&pos, argp, sizeof (pos))) | 647 | if (copy_from_user(&pos, argp, sizeof (pos))) |
682 | return -EFAULT; | 648 | return -EFAULT; |
683 | 649 | ||
@@ -692,7 +658,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, | |||
692 | mutex_unlock(&ch->lock); | 658 | mutex_unlock(&ch->lock); |
693 | return retval; | 659 | return retval; |
694 | } | 660 | } |
695 | 661 | ||
696 | case CHIOMOVE: | 662 | case CHIOMOVE: |
697 | { | 663 | { |
698 | struct changer_move mv; | 664 | struct changer_move mv; |
@@ -705,7 +671,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, | |||
705 | dprintk("CHIOMOVE: invalid parameter\n"); | 671 | dprintk("CHIOMOVE: invalid parameter\n"); |
706 | return -EBADSLT; | 672 | return -EBADSLT; |
707 | } | 673 | } |
708 | 674 | ||
709 | mutex_lock(&ch->lock); | 675 | mutex_lock(&ch->lock); |
710 | retval = ch_move(ch,0, | 676 | retval = ch_move(ch,0, |
711 | ch->firsts[mv.cm_fromtype] + mv.cm_fromunit, | 677 | ch->firsts[mv.cm_fromtype] + mv.cm_fromunit, |
@@ -718,7 +684,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, | |||
718 | case CHIOEXCHANGE: | 684 | case CHIOEXCHANGE: |
719 | { | 685 | { |
720 | struct changer_exchange mv; | 686 | struct changer_exchange mv; |
721 | 687 | ||
722 | if (copy_from_user(&mv, argp, sizeof (mv))) | 688 | if (copy_from_user(&mv, argp, sizeof (mv))) |
723 | return -EFAULT; | 689 | return -EFAULT; |
724 | 690 | ||
@@ -728,7 +694,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, | |||
728 | dprintk("CHIOEXCHANGE: invalid parameter\n"); | 694 | dprintk("CHIOEXCHANGE: invalid parameter\n"); |
729 | return -EBADSLT; | 695 | return -EBADSLT; |
730 | } | 696 | } |
731 | 697 | ||
732 | mutex_lock(&ch->lock); | 698 | mutex_lock(&ch->lock); |
733 | retval = ch_exchange | 699 | retval = ch_exchange |
734 | (ch,0, | 700 | (ch,0, |
@@ -743,7 +709,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, | |||
743 | case CHIOGSTATUS: | 709 | case CHIOGSTATUS: |
744 | { | 710 | { |
745 | struct changer_element_status ces; | 711 | struct changer_element_status ces; |
746 | 712 | ||
747 | if (copy_from_user(&ces, argp, sizeof (ces))) | 713 | if (copy_from_user(&ces, argp, sizeof (ces))) |
748 | return -EFAULT; | 714 | return -EFAULT; |
749 | if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES) | 715 | if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES) |
@@ -759,19 +725,19 @@ static int ch_ioctl(struct inode * inode, struct file * file, | |||
759 | u_char *buffer; | 725 | u_char *buffer; |
760 | unsigned int elem; | 726 | unsigned int elem; |
761 | int result,i; | 727 | int result,i; |
762 | 728 | ||
763 | if (copy_from_user(&cge, argp, sizeof (cge))) | 729 | if (copy_from_user(&cge, argp, sizeof (cge))) |
764 | return -EFAULT; | 730 | return -EFAULT; |
765 | 731 | ||
766 | if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit)) | 732 | if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit)) |
767 | return -EINVAL; | 733 | return -EINVAL; |
768 | elem = ch->firsts[cge.cge_type] + cge.cge_unit; | 734 | elem = ch->firsts[cge.cge_type] + cge.cge_unit; |
769 | 735 | ||
770 | buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); | 736 | buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); |
771 | if (!buffer) | 737 | if (!buffer) |
772 | return -ENOMEM; | 738 | return -ENOMEM; |
773 | mutex_lock(&ch->lock); | 739 | mutex_lock(&ch->lock); |
774 | 740 | ||
775 | voltag_retry: | 741 | voltag_retry: |
776 | memset(cmd,0,sizeof(cmd)); | 742 | memset(cmd,0,sizeof(cmd)); |
777 | cmd[0] = READ_ELEMENT_STATUS; | 743 | cmd[0] = READ_ELEMENT_STATUS; |
@@ -782,7 +748,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, | |||
782 | cmd[3] = elem & 0xff; | 748 | cmd[3] = elem & 0xff; |
783 | cmd[5] = 1; | 749 | cmd[5] = 1; |
784 | cmd[9] = 255; | 750 | cmd[9] = 255; |
785 | 751 | ||
786 | 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))) { |
787 | cge.cge_status = buffer[18]; | 753 | cge.cge_status = buffer[18]; |
788 | cge.cge_flags = 0; | 754 | cge.cge_flags = 0; |
@@ -822,7 +788,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, | |||
822 | } | 788 | } |
823 | kfree(buffer); | 789 | kfree(buffer); |
824 | mutex_unlock(&ch->lock); | 790 | mutex_unlock(&ch->lock); |
825 | 791 | ||
826 | if (copy_to_user(argp, &cge, sizeof (cge))) | 792 | if (copy_to_user(argp, &cge, sizeof (cge))) |
827 | return -EFAULT; | 793 | return -EFAULT; |
828 | return result; | 794 | return result; |
@@ -835,7 +801,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, | |||
835 | mutex_unlock(&ch->lock); | 801 | mutex_unlock(&ch->lock); |
836 | return retval; | 802 | return retval; |
837 | } | 803 | } |
838 | 804 | ||
839 | case CHIOSVOLTAG: | 805 | case CHIOSVOLTAG: |
840 | { | 806 | { |
841 | struct changer_set_voltag csv; | 807 | struct changer_set_voltag csv; |
@@ -876,7 +842,7 @@ static long ch_ioctl_compat(struct file * file, | |||
876 | unsigned int cmd, unsigned long arg) | 842 | unsigned int cmd, unsigned long arg) |
877 | { | 843 | { |
878 | scsi_changer *ch = file->private_data; | 844 | scsi_changer *ch = file->private_data; |
879 | 845 | ||
880 | switch (cmd) { | 846 | switch (cmd) { |
881 | case CHIOGPARAMS: | 847 | case CHIOGPARAMS: |
882 | case CHIOGVPARAMS: | 848 | case CHIOGVPARAMS: |
@@ -887,13 +853,12 @@ static long ch_ioctl_compat(struct file * file, | |||
887 | case CHIOINITELEM: | 853 | case CHIOINITELEM: |
888 | case CHIOSVOLTAG: | 854 | case CHIOSVOLTAG: |
889 | /* compatible */ | 855 | /* compatible */ |
890 | return ch_ioctl(NULL /* inode, unused */, | 856 | return ch_ioctl(file, cmd, arg); |
891 | file, cmd, arg); | ||
892 | case CHIOGSTATUS32: | 857 | case CHIOGSTATUS32: |
893 | { | 858 | { |
894 | struct changer_element_status32 ces32; | 859 | struct changer_element_status32 ces32; |
895 | unsigned char __user *data; | 860 | unsigned char __user *data; |
896 | 861 | ||
897 | if (copy_from_user(&ces32, (void __user *)arg, sizeof (ces32))) | 862 | if (copy_from_user(&ces32, (void __user *)arg, sizeof (ces32))) |
898 | return -EFAULT; | 863 | return -EFAULT; |
899 | if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES) | 864 | if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES) |
@@ -915,63 +880,100 @@ static long ch_ioctl_compat(struct file * file, | |||
915 | static int ch_probe(struct device *dev) | 880 | static int ch_probe(struct device *dev) |
916 | { | 881 | { |
917 | struct scsi_device *sd = to_scsi_device(dev); | 882 | struct scsi_device *sd = to_scsi_device(dev); |
883 | struct class_device *class_dev; | ||
884 | int minor, ret = -ENOMEM; | ||
918 | scsi_changer *ch; | 885 | scsi_changer *ch; |
919 | 886 | ||
920 | if (sd->type != TYPE_MEDIUM_CHANGER) | 887 | if (sd->type != TYPE_MEDIUM_CHANGER) |
921 | return -ENODEV; | 888 | return -ENODEV; |
922 | 889 | ||
923 | ch = kzalloc(sizeof(*ch), GFP_KERNEL); | 890 | ch = kzalloc(sizeof(*ch), GFP_KERNEL); |
924 | if (NULL == ch) | 891 | if (NULL == ch) |
925 | return -ENOMEM; | 892 | return -ENOMEM; |
926 | 893 | ||
927 | ch->minor = ch_devcount; | 894 | if (!idr_pre_get(&ch_index_idr, GFP_KERNEL)) |
895 | goto free_ch; | ||
896 | |||
897 | spin_lock(&ch_index_lock); | ||
898 | ret = idr_get_new(&ch_index_idr, ch, &minor); | ||
899 | spin_unlock(&ch_index_lock); | ||
900 | |||
901 | if (ret) | ||
902 | goto free_ch; | ||
903 | |||
904 | if (minor > CH_MAX_DEVS) { | ||
905 | ret = -ENODEV; | ||
906 | goto remove_idr; | ||
907 | } | ||
908 | |||
909 | ch->minor = minor; | ||
928 | sprintf(ch->name,"ch%d",ch->minor); | 910 | sprintf(ch->name,"ch%d",ch->minor); |
911 | |||
912 | class_dev = class_device_create(ch_sysfs_class, NULL, | ||
913 | MKDEV(SCSI_CHANGER_MAJOR, ch->minor), | ||
914 | dev, "s%s", ch->name); | ||
915 | if (IS_ERR(class_dev)) { | ||
916 | printk(KERN_WARNING "ch%d: class_device_create failed\n", | ||
917 | ch->minor); | ||
918 | ret = PTR_ERR(class_dev); | ||
919 | goto remove_idr; | ||
920 | } | ||
921 | |||
929 | mutex_init(&ch->lock); | 922 | mutex_init(&ch->lock); |
930 | ch->device = sd; | 923 | ch->device = sd; |
931 | ch_readconfig(ch); | 924 | ch_readconfig(ch); |
932 | if (init) | 925 | if (init) |
933 | ch_init_elem(ch); | 926 | ch_init_elem(ch); |
934 | 927 | ||
935 | class_device_create(ch_sysfs_class, NULL, | 928 | dev_set_drvdata(dev, ch); |
936 | MKDEV(SCSI_CHANGER_MAJOR,ch->minor), | ||
937 | dev, "s%s", ch->name); | ||
938 | |||
939 | sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name); | 929 | sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name); |
940 | 930 | ||
941 | spin_lock(&ch_devlist_lock); | ||
942 | list_add_tail(&ch->list,&ch_devlist); | ||
943 | ch_devcount++; | ||
944 | spin_unlock(&ch_devlist_lock); | ||
945 | return 0; | 931 | return 0; |
932 | remove_idr: | ||
933 | idr_remove(&ch_index_idr, minor); | ||
934 | free_ch: | ||
935 | kfree(ch); | ||
936 | return ret; | ||
946 | } | 937 | } |
947 | 938 | ||
948 | static int ch_remove(struct device *dev) | 939 | static int ch_remove(struct device *dev) |
949 | { | 940 | { |
950 | struct scsi_device *sd = to_scsi_device(dev); | 941 | scsi_changer *ch = dev_get_drvdata(dev); |
951 | scsi_changer *tmp, *ch; | ||
952 | 942 | ||
953 | spin_lock(&ch_devlist_lock); | 943 | spin_lock(&ch_index_lock); |
954 | ch = NULL; | 944 | idr_remove(&ch_index_idr, ch->minor); |
955 | list_for_each_entry(tmp,&ch_devlist,list) { | 945 | spin_unlock(&ch_index_lock); |
956 | if (tmp->device == sd) | ||
957 | ch = tmp; | ||
958 | } | ||
959 | BUG_ON(NULL == ch); | ||
960 | list_del(&ch->list); | ||
961 | spin_unlock(&ch_devlist_lock); | ||
962 | 946 | ||
963 | class_device_destroy(ch_sysfs_class, | 947 | class_device_destroy(ch_sysfs_class, |
964 | MKDEV(SCSI_CHANGER_MAJOR,ch->minor)); | 948 | MKDEV(SCSI_CHANGER_MAJOR,ch->minor)); |
965 | kfree(ch->dt); | 949 | kfree(ch->dt); |
966 | kfree(ch); | 950 | kfree(ch); |
967 | ch_devcount--; | ||
968 | return 0; | 951 | return 0; |
969 | } | 952 | } |
970 | 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 | |||
971 | static int __init init_ch_module(void) | 973 | static int __init init_ch_module(void) |
972 | { | 974 | { |
973 | int rc; | 975 | int rc; |
974 | 976 | ||
975 | printk(KERN_INFO "SCSI Media Changer driver v" VERSION " \n"); | 977 | printk(KERN_INFO "SCSI Media Changer driver v" VERSION " \n"); |
976 | ch_sysfs_class = class_create(THIS_MODULE, "scsi_changer"); | 978 | ch_sysfs_class = class_create(THIS_MODULE, "scsi_changer"); |
977 | if (IS_ERR(ch_sysfs_class)) { | 979 | if (IS_ERR(ch_sysfs_class)) { |
@@ -996,11 +998,12 @@ static int __init init_ch_module(void) | |||
996 | return rc; | 998 | return rc; |
997 | } | 999 | } |
998 | 1000 | ||
999 | static void __exit exit_ch_module(void) | 1001 | static void __exit exit_ch_module(void) |
1000 | { | 1002 | { |
1001 | scsi_unregister_driver(&ch_template.gendrv); | 1003 | scsi_unregister_driver(&ch_template.gendrv); |
1002 | unregister_chrdev(SCSI_CHANGER_MAJOR, "ch"); | 1004 | unregister_chrdev(SCSI_CHANGER_MAJOR, "ch"); |
1003 | class_destroy(ch_sysfs_class); | 1005 | class_destroy(ch_sysfs_class); |
1006 | idr_destroy(&ch_index_idr); | ||
1004 | } | 1007 | } |
1005 | 1008 | ||
1006 | module_init(init_ch_module); | 1009 | module_init(init_ch_module); |