aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/ch.c71
1 files changed, 40 insertions, 31 deletions
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index 765f2fc001aa..2b07014cbc83 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>");
@@ -113,9 +115,8 @@ typedef struct {
113 struct mutex lock; 115 struct mutex lock;
114} scsi_changer; 116} scsi_changer;
115 117
116static LIST_HEAD(ch_devlist); 118static DEFINE_IDR(ch_index_idr);
117static DEFINE_SPINLOCK(ch_devlist_lock); 119static DEFINE_SPINLOCK(ch_index_lock);
118static int ch_devcount;
119 120
120static struct scsi_driver ch_template = 121static struct scsi_driver ch_template =
121{ 122{
@@ -598,20 +599,17 @@ ch_release(struct inode *inode, struct file *file)
598static int 599static int
599ch_open(struct inode *inode, struct file *file) 600ch_open(struct inode *inode, struct file *file)
600{ 601{
601 scsi_changer *tmp, *ch; 602 scsi_changer *ch;
602 int minor = iminor(inode); 603 int minor = iminor(inode);
603 604
604 spin_lock(&ch_devlist_lock); 605 spin_lock(&ch_index_lock);
605 ch = NULL; 606 ch = idr_find(&ch_index_idr, minor);
606 list_for_each_entry(tmp,&ch_devlist,list) { 607
607 if (tmp->minor == minor)
608 ch = tmp;
609 }
610 if (NULL == ch || scsi_device_get(ch->device)) { 608 if (NULL == ch || scsi_device_get(ch->device)) {
611 spin_unlock(&ch_devlist_lock); 609 spin_unlock(&ch_index_lock);
612 return -ENXIO; 610 return -ENXIO;
613 } 611 }
614 spin_unlock(&ch_devlist_lock); 612 spin_unlock(&ch_index_lock);
615 613
616 file->private_data = ch; 614 file->private_data = ch;
617 return 0; 615 return 0;
@@ -914,6 +912,7 @@ static int ch_probe(struct device *dev)
914{ 912{
915 struct scsi_device *sd = to_scsi_device(dev); 913 struct scsi_device *sd = to_scsi_device(dev);
916 struct class_device *class_dev; 914 struct class_device *class_dev;
915 int minor, ret = -ENOMEM;
917 scsi_changer *ch; 916 scsi_changer *ch;
918 917
919 if (sd->type != TYPE_MEDIUM_CHANGER) 918 if (sd->type != TYPE_MEDIUM_CHANGER)
@@ -923,7 +922,22 @@ static int ch_probe(struct device *dev)
923 if (NULL == ch) 922 if (NULL == ch)
924 return -ENOMEM; 923 return -ENOMEM;
925 924
926 ch->minor = ch_devcount; 925 if (!idr_pre_get(&ch_index_idr, GFP_KERNEL))
926 goto free_ch;
927
928 spin_lock(&ch_index_lock);
929 ret = idr_get_new(&ch_index_idr, ch, &minor);
930 spin_unlock(&ch_index_lock);
931
932 if (ret)
933 goto free_ch;
934
935 if (minor > CH_MAX_DEVS) {
936 ret = -ENODEV;
937 goto remove_idr;
938 }
939
940 ch->minor = minor;
927 sprintf(ch->name,"ch%d",ch->minor); 941 sprintf(ch->name,"ch%d",ch->minor);
928 942
929 class_dev = class_device_create(ch_sysfs_class, NULL, 943 class_dev = class_device_create(ch_sysfs_class, NULL,
@@ -932,8 +946,8 @@ static int ch_probe(struct device *dev)
932 if (IS_ERR(class_dev)) { 946 if (IS_ERR(class_dev)) {
933 printk(KERN_WARNING "ch%d: class_device_create failed\n", 947 printk(KERN_WARNING "ch%d: class_device_create failed\n",
934 ch->minor); 948 ch->minor);
935 kfree(ch); 949 ret = PTR_ERR(class_dev);
936 return PTR_ERR(class_dev); 950 goto remove_idr;
937 } 951 }
938 952
939 mutex_init(&ch->lock); 953 mutex_init(&ch->lock);
@@ -942,35 +956,29 @@ static int ch_probe(struct device *dev)
942 if (init) 956 if (init)
943 ch_init_elem(ch); 957 ch_init_elem(ch);
944 958
959 dev_set_drvdata(dev, ch);
945 sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name); 960 sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
946 961
947 spin_lock(&ch_devlist_lock);
948 list_add_tail(&ch->list,&ch_devlist);
949 ch_devcount++;
950 spin_unlock(&ch_devlist_lock);
951 return 0; 962 return 0;
963remove_idr:
964 idr_remove(&ch_index_idr, minor);
965free_ch:
966 kfree(ch);
967 return ret;
952} 968}
953 969
954static int ch_remove(struct device *dev) 970static int ch_remove(struct device *dev)
955{ 971{
956 struct scsi_device *sd = to_scsi_device(dev); 972 scsi_changer *ch = dev_get_drvdata(dev);
957 scsi_changer *tmp, *ch;
958 973
959 spin_lock(&ch_devlist_lock); 974 spin_lock(&ch_index_lock);
960 ch = NULL; 975 idr_remove(&ch_index_idr, ch->minor);
961 list_for_each_entry(tmp,&ch_devlist,list) { 976 spin_unlock(&ch_index_lock);
962 if (tmp->device == sd)
963 ch = tmp;
964 }
965 BUG_ON(NULL == ch);
966 list_del(&ch->list);
967 spin_unlock(&ch_devlist_lock);
968 977
969 class_device_destroy(ch_sysfs_class, 978 class_device_destroy(ch_sysfs_class,
970 MKDEV(SCSI_CHANGER_MAJOR,ch->minor)); 979 MKDEV(SCSI_CHANGER_MAJOR,ch->minor));
971 kfree(ch->dt); 980 kfree(ch->dt);
972 kfree(ch); 981 kfree(ch);
973 ch_devcount--;
974 return 0; 982 return 0;
975} 983}
976 984
@@ -1007,6 +1015,7 @@ static void __exit exit_ch_module(void)
1007 scsi_unregister_driver(&ch_template.gendrv); 1015 scsi_unregister_driver(&ch_template.gendrv);
1008 unregister_chrdev(SCSI_CHANGER_MAJOR, "ch"); 1016 unregister_chrdev(SCSI_CHANGER_MAJOR, "ch");
1009 class_destroy(ch_sysfs_class); 1017 class_destroy(ch_sysfs_class);
1018 idr_destroy(&ch_index_idr);
1010} 1019}
1011 1020
1012module_init(init_ch_module); 1021module_init(init_ch_module);