diff -urN linux-2.5.3/drivers/scsi/Config.help linux/drivers/scsi/Config.help --- linux-2.5.3/drivers/scsi/Config.help Fri Jan 25 17:04:16 2002 +++ linux/drivers/scsi/Config.help Thu Jan 31 00:34:49 2002 @@ -34,6 +34,16 @@ is located on a SCSI disk. In this case, do not compile the driver for your SCSI host adapter (below) as a module either. +CONFIG_SD_MANY + This allows you to support a very large number of SCSI discs + (approximately 2080). You will also need to set CONFIG_DEVFS_FS=y + later. This option may consume all unassigned block majors + (i.e. those which do not have an allocation in + Documentation/devices.txt). Enabling this will consume a few extra + kilobytes of kernel memory. + + Unless you have a large storage array, say N. + CONFIG_SD_EXTRA_DEVS This controls the amount of additional space allocated in tables for drivers that are loaded as modules after the kernel is booted. In diff -urN linux-2.5.3/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- linux-2.5.3/drivers/scsi/Config.in Tue Nov 27 10:23:27 2001 +++ linux/drivers/scsi/Config.in Thu Jan 31 00:34:49 2002 @@ -3,7 +3,8 @@ dep_tristate ' SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then - int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40 + bool ' Many (~2080) SCSI discs support (requires devfs)' CONFIG_SD_MANY + int ' Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40 fi dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI diff -urN linux-2.5.3/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h --- linux-2.5.3/drivers/scsi/hosts.h Tue Jan 29 22:44:26 2002 +++ linux/drivers/scsi/hosts.h Thu Jan 31 00:37:21 2002 @@ -501,9 +501,8 @@ const char * tag; struct module * module; /* Used for loadable modules */ unsigned char scsi_type; - unsigned int major; - unsigned int min_major; /* Minimum major in range. */ - unsigned int max_major; /* Maximum major in range. */ + unsigned int *majors; /* Array of majors used by driver */ + unsigned int num_majors; /* Number of majors used by driver */ unsigned int nr_dev; /* Number currently attached */ unsigned int dev_noticed; /* Number of devices detected. */ unsigned int dev_max; /* Current size of arrays */ diff -urN linux-2.5.3/drivers/scsi/osst.c linux/drivers/scsi/osst.c --- linux-2.5.3/drivers/scsi/osst.c Tue Dec 25 18:04:40 2001 +++ linux/drivers/scsi/osst.c Thu Jan 31 00:34:49 2002 @@ -163,7 +163,6 @@ name: "OnStream tape", tag: "osst", scsi_type: TYPE_TAPE, - major: OSST_MAJOR, detect: osst_detect, init: osst_init, attach: osst_attach, diff -urN linux-2.5.3/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c --- linux-2.5.3/drivers/scsi/scsi_lib.c Mon Jan 14 12:25:29 2002 +++ linux/drivers/scsi/scsi_lib.c Thu Jan 31 00:34:49 2002 @@ -749,25 +749,12 @@ * Search for a block device driver that supports this * major. */ - if (spnt->blk && spnt->major == major) { - return spnt; - } - /* - * I am still not entirely satisfied with this solution, - * but it is good enough for now. Disks have a number of - * major numbers associated with them, the primary - * 8, which we test above, and a secondary range of 7 - * different consecutive major numbers. If this ever - * becomes insufficient, then we could add another function - * to the structure, and generalize this completely. - */ - if( spnt->min_major != 0 - && spnt->max_major != 0 - && major >= spnt->min_major - && major <= spnt->max_major ) - { - return spnt; - } + int i; + if (!spnt->blk || !spnt->majors) + continue; + for (i = 0; i < spnt->num_majors; ++i) + if (spnt->majors[i] == major) + return spnt; } return NULL; } diff -urN linux-2.5.3/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- linux-2.5.3/drivers/scsi/sd.c Mon Dec 31 19:01:44 2001 +++ linux/drivers/scsi/sd.c Thu Jan 31 00:44:50 2002 @@ -28,6 +28,8 @@ * * Modified by Alex Davis * Fix problem where removable media could be ejected after sd_open. + * + * Modified by Richard Gooch rgooch@atnf.csiro.au to support >128 discs. */ #include @@ -61,7 +63,11 @@ #include +#ifdef CONFIG_SD_MANY +#define SD_MAJOR(i) sd_template.majors[(i)] +#else #define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i)) +#endif #define SCSI_DISKS_PER_MAJOR 16 #define SD_MAJOR_NUMBER(i) SD_MAJOR((i) >> 8) @@ -72,6 +78,14 @@ #define MAX_RETRIES 5 +#ifdef CONFIG_SD_MANY +#define sdmalloc(size) vmalloc((size)) +#define sdfree(ptr) vfree((ptr)) +#else +#define sdmalloc(size) kmalloc((size),GFP_ATOMIC) +#define sdfree(ptr) kfree((ptr)) +#endif + /* * Time out in seconds for disks and Magneto-opticals (which are slower). */ @@ -103,12 +117,6 @@ name:"disk", tag:"sd", scsi_type:TYPE_DISK, - major:SCSI_DISK0_MAJOR, - /* - * Secondary range of majors that this driver handles. - */ - min_major:SCSI_DISK1_MAJOR, - max_major:SCSI_DISK7_MAJOR, blk:1, detect:sd_detect, init:sd_init, @@ -137,6 +145,20 @@ } #endif +#ifdef CONFIG_SD_MANY +static inline int sd_kdev_to_index(kdev_t dev) +{ + int i, major = major (dev); + + for (i = 0; i < sd_template.num_majors; ++i) { + if (sd_template.majors[i] != major) + continue; + return (i << 4) | (minor (dev) >> 4); + } + return -ENODEV; +} +#endif + static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { kdev_t dev = inode->i_rdev; @@ -665,7 +687,6 @@ * them to SCSI commands. */ - static int check_scsidisk_media_change(kdev_t full_dev) { int retval; @@ -1046,6 +1067,43 @@ return i; } +static int sd_alloc_majors(void) +/* Allocate as many majors as required + */ +{ + int i, major; + + if ( ( sd_template.majors = + kmalloc(sizeof *sd_template.majors * N_USED_SD_MAJORS, + GFP_KERNEL) ) == NULL ) { + printk("sd.c: unable to allocate major array\n"); + return -ENOMEM; + } + sd_template.majors[0] = SCSI_DISK0_MAJOR; + for (i = 1; (i < N_USED_SD_MAJORS) && (i = N_SD_PREASSIGNED_MAJORS) && (i < N_USED_SD_MAJORS); ++i) { + if ( ( major = devfs_alloc_major(DEVFS_SPECIAL_BLK) ) < 0 ) { + printk(KERN_WARNING __FUNCTION__ "() major[%d] allocation failed\n", i); + break; + } + sd_template.majors[i] = major; + } + sd_template.dev_max = i * SCSI_DISKS_PER_MAJOR; + sd_template.num_majors = i; + return 0; +} /* End Function sd_alloc_majors */ + +static void sd_dealloc_majors(void) +/* Deallocate all the allocated majors + */ +{ + int i; + + for (i = sd_template.num_majors - 1; i >= N_SD_PREASSIGNED_MAJORS; --i) + devfs_dealloc_major(DEVFS_SPECIAL_BLK, sd_template.majors[i]); +} /* End Function sd_dealloc_majors */ + /* * The sd_init() function looks at all SCSI drives present, determines * their size, and reads partition table entries for them. @@ -1060,11 +1118,15 @@ if (sd_template.dev_noticed == 0) return 0; - if (!rscsi_disks) + if (!rscsi_disks) { + if ( in_interrupt() ) { + printk (__FUNCTION__ "(): called from interrupt\n"); + return 1; + } sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS; - - if (sd_template.dev_max > N_SD_MAJORS * SCSI_DISKS_PER_MAJOR) - sd_template.dev_max = N_SD_MAJORS * SCSI_DISKS_PER_MAJOR; + if ( sd_alloc_majors() ) + return 1; + } /* At most 16 partitions on each scsi disk. */ maxparts = (sd_template.dev_max << 4); @@ -1077,6 +1139,7 @@ &sd_fops)) { printk("Unable to get major %d for SCSI disk\n", SD_MAJOR(i)); + sd_dealloc_majors(); return 1; } } @@ -1087,7 +1150,7 @@ return 0; /* allocate memory */ -#define init_mem_lth(x,n) x = kmalloc((n) * sizeof(*x), GFP_ATOMIC) +#define init_mem_lth(x,n) x = sdmalloc((n) * sizeof(*x)) #define zero_mem_lth(x,n) memset(x, 0, (n) * sizeof(*x)) init_mem_lth(rscsi_disks, sd_template.dev_max); @@ -1153,19 +1216,20 @@ cleanup_gendisks: /* kfree can handle NULL, so no test is required here */ for (i = 0; i < N_USED_SD_MAJORS; i++) { - kfree(sd_gendisks[i].de_arr); - kfree(sd_gendisks[i].flags); + sdfree(sd_gendisks[i].de_arr); + sdfree(sd_gendisks[i].flags); } cleanup_mem: - kfree(sd_gendisks); - kfree(sd); - kfree(sd_blocksizes); - kfree(sd_sizes); - kfree(rscsi_disks); + sdfree(sd_gendisks); + sdfree(sd); + sdfree(sd_blocksizes); + sdfree(sd_sizes); + sdfree(rscsi_disks); for (i = 0; i < N_USED_SD_MAJORS; i++) { devfs_unregister_blkdev(SD_MAJOR(i), "sd"); } sd_registered--; + sd_dealloc_majors(); return 1; } @@ -1338,15 +1402,16 @@ scsi_unregister_device(&sd_template); + sd_dealloc_majors(); for (i = 0; i < N_USED_SD_MAJORS; i++) devfs_unregister_blkdev(SD_MAJOR(i), "sd"); sd_registered--; if (rscsi_disks != NULL) { - kfree(rscsi_disks); - kfree(sd_sizes); - kfree(sd_blocksizes); - kfree((char *) sd); + sdfree(rscsi_disks); + sdfree(sd_sizes); + sdfree(sd_blocksizes); + sdfree((char *) sd); } for (i = 0; i < N_USED_SD_MAJORS; i++) { del_gendisk(&(sd_gendisks[i])); @@ -1354,7 +1419,7 @@ } sd_template.dev_max = 0; if (sd_gendisks != &sd_gendisk) - kfree(sd_gendisks); + sdfree(sd_gendisks); } module_init(init_sd); diff -urN linux-2.5.3/drivers/scsi/sd.h linux/drivers/scsi/sd.h --- linux-2.5.3/drivers/scsi/sd.h Tue Jan 29 22:44:26 2002 +++ linux/drivers/scsi/sd.h Thu Jan 31 00:51:47 2002 @@ -42,10 +42,14 @@ */ extern kdev_t sd_find_target(void *host, int tgt); -#define N_SD_MAJORS 8 +#define N_SD_PREASSIGNED_MAJORS 8 -#define SD_MAJOR_MASK (N_SD_MAJORS - 1) +#ifdef CONFIG_SD_MANY +#define SD_PARTITION(i) ((sd_kdev_to_index((i)) << 4) | (minor(i)&0x0f)) +#else +#define SD_MAJOR_MASK (N_SD_PREASSIGNED_MAJORS - 1) #define SD_PARTITION(i) (((major(i) & SD_MAJOR_MASK) << 8) | (minor(i) & 255)) +#endif #endif diff -urN linux-2.5.3/drivers/scsi/sg.c linux/drivers/scsi/sg.c --- linux-2.5.3/drivers/scsi/sg.c Thu Jan 17 14:59:33 2002 +++ linux/drivers/scsi/sg.c Thu Jan 31 00:34:49 2002 @@ -124,7 +124,6 @@ module:THIS_MODULE, tag:"sg", scsi_type:0xff, - major:SCSI_GENERIC_MAJOR, detect:sg_detect, init:sg_init, finish:sg_finish, diff -urN linux-2.5.3/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- linux-2.5.3/drivers/scsi/sr.c Thu Jan 17 14:59:33 2002 +++ linux/drivers/scsi/sr.c Thu Jan 31 00:34:49 2002 @@ -69,13 +69,16 @@ static int sr_init_command(Scsi_Cmnd *); +static unsigned int sr_major = SCSI_CDROM_MAJOR; + static struct Scsi_Device_Template sr_template = { module:THIS_MODULE, name:"cdrom", tag:"sr", scsi_type:TYPE_ROM, - major:SCSI_CDROM_MAJOR, + majors:&sr_major, + num_majors:1, blk:1, detect:sr_detect, init:sr_init, diff -urN linux-2.5.3/drivers/scsi/st.c linux/drivers/scsi/st.c --- linux-2.5.3/drivers/scsi/st.c Wed Jan 23 16:30:47 2002 +++ linux/drivers/scsi/st.c Thu Jan 31 00:34:49 2002 @@ -166,7 +166,6 @@ name: "tape", tag: "st", scsi_type: TYPE_TAPE, - major: SCSI_TAPE_MAJOR, detect: st_detect, attach: st_attach, detach: st_detach diff -urN linux-2.5.3/include/linux/blk.h linux/include/linux/blk.h --- linux-2.5.3/include/linux/blk.h Tue Jan 29 22:42:34 2002 +++ linux/include/linux/blk.h Thu Jan 31 00:37:01 2002 @@ -148,7 +148,11 @@ #define DEVICE_NAME "scsidisk" #define TIMEOUT_VALUE (2*HZ) +#ifdef CONFIG_SD_MANY +#define DEVICE_NR(device) sd_kdev_to_index((device)) +#else #define DEVICE_NR(device) (((major(device) & SD_MAJOR_MASK) << (8 - 4)) + (minor(device) >> 4)) +#endif /* Kludge to use the same number for both char and block major numbers */ #elif (MAJOR_NR == MD_MAJOR) && defined(MD_DRIVER)