aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/ch.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-01-25 20:19:08 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-01-25 20:19:08 -0500
commit9b73e76f3cf63379dcf45fcd4f112f5812418d0a (patch)
tree4e6bef87cd0cd6d848fc39a5ae25b981dbbe035b /drivers/scsi/ch.c
parent50d9a126240f9961cfdd063336bbeb91f77a7dce (diff)
parent23c3e290fb9ce38cabc2822b47583fc8702411bf (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (200 commits) [SCSI] usbstorage: use last_sector_bug flag universally [SCSI] libsas: abstract STP task status into a function [SCSI] ultrastor: clean up inline asm warnings [SCSI] aic7xxx: fix firmware build [SCSI] aacraid: fib context lock for management ioctls [SCSI] ch: remove forward declarations [SCSI] ch: fix device minor number management bug [SCSI] ch: handle class_device_create failure properly [SCSI] NCR5380: fix section mismatch [SCSI] sg: fix /proc/scsi/sg/devices when no SCSI devices [SCSI] IB/iSER: add logical unit reset support [SCSI] don't use __GFP_DMA for sense buffers if not required [SCSI] use dynamically allocated sense buffer [SCSI] scsi.h: add macro for enclosure bit of inquiry data [SCSI] sd: add fix for devices with last sector access problems [SCSI] fix pcmcia compile problem [SCSI] aacraid: add Voodoo Lite class of cards. [SCSI] aacraid: add new driver features flags [SCSI] qla2xxx: Update version number to 8.02.00-k7. [SCSI] qla2xxx: Issue correct MBC_INITIALIZE_FIRMWARE command. ...
Diffstat (limited to 'drivers/scsi/ch.c')
-rw-r--r--drivers/scsi/ch.c215
1 files changed, 109 insertions, 106 deletions
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index 2311019304c..7aad15436d2 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
37MODULE_DESCRIPTION("device driver for scsi media changer devices"); 39MODULE_DESCRIPTION("device driver for scsi media changer devices");
38MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org>"); 40MODULE_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
91static int ch_probe(struct device *);
92static int ch_remove(struct device *);
93static int ch_open(struct inode * inode, struct file * filp);
94static int ch_release(struct inode * inode, struct file * filp);
95static int ch_ioctl(struct inode * inode, struct file * filp,
96 unsigned int cmd, unsigned long arg);
97#ifdef CONFIG_COMPAT
98static long ch_ioctl_compat(struct file * filp,
99 unsigned int cmd, unsigned long arg);
100#endif
101
102static struct class * ch_sysfs_class; 93static struct class * ch_sysfs_class;
103 94
104typedef struct { 95typedef struct {
@@ -114,30 +105,8 @@ typedef struct {
114 struct mutex lock; 105 struct mutex lock;
115} scsi_changer; 106} scsi_changer;
116 107
117static LIST_HEAD(ch_devlist); 108static DEFINE_IDR(ch_index_idr);
118static DEFINE_SPINLOCK(ch_devlist_lock); 109static DEFINE_SPINLOCK(ch_index_lock);
119static int ch_devcount;
120
121static 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
131static 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
142static const struct { 111static 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
245ch_elem_to_typecode(scsi_changer *ch, u_int elem) 214ch_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
299static int 268static int
300ch_init_elem(scsi_changer *ch) 269ch_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
443ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate) 412ch_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
462ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate) 431ch_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)
599static int 568static int
600ch_open(struct inode *inode, struct file *file) 569ch_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
629static int ch_ioctl(struct inode * inode, struct file * file, 595static 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, &params, sizeof(params))) 613 if (copy_to_user(argp, &params, 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,
915static int ch_probe(struct device *dev) 880static 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;
932remove_idr:
933 idr_remove(&ch_index_idr, minor);
934free_ch:
935 kfree(ch);
936 return ret;
946} 937}
947 938
948static int ch_remove(struct device *dev) 939static 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
954static 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
963static 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
971static int __init init_ch_module(void) 973static 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
999static void __exit exit_ch_module(void) 1001static 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
1006module_init(init_ch_module); 1009module_init(init_ch_module);