diff -uNr linux-2.4.18.nohdstat/Documentation/Configure.help linux-2.4.18.S18.scsimany/Documentation/Configure.help --- linux-2.4.18.nohdstat/Documentation/Configure.help Sun Jul 14 17:26:34 2002 +++ linux-2.4.18.S18.scsimany/Documentation/Configure.help Fri Jul 26 02:01:16 2002 @@ -7099,19 +7099,18 @@ is located on a SCSI disk. In this case, do not compile the driver for your SCSI host adapter (below) as a module either. -Maximum number of SCSI disks that can be loaded as modules -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 - the event that the SCSI core itself was loaded as a module, this - value is the number of additional disks that can be loaded after the - first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - - If you don't understand what's going on, go with the default. +CONFIG_SD_MAX_MAJORS + There are 16 block major numers assigned to SCSI disks which means + that you may attach up to 256 SCSI disks to one Linux machine. + The driver does allows to dynamically allocate more major numbers + when more disks get attached. You will need a userspace script to + parse /proc/partitions though to dynamically create the device + nodes then. The driver allocates the memory as disks get attached, + so there's no cost for allowing more majors here. The theoretical + maximum is 244. + However, it's not recommended to use values higher than 16, as you + will end using unassigned numbers. So, unless you'll potentially + connect more than 256 SCSI disks, stay with the default (16). Maximum number of SCSI tapes that can be loaded as modules CONFIG_ST_EXTRA_DEVS diff -uNr linux-2.4.18.nohdstat/drivers/char/sysrq.c linux-2.4.18.S18.scsimany/drivers/char/sysrq.c --- linux-2.4.18.nohdstat/drivers/char/sysrq.c Wed Jun 12 11:37:02 2002 +++ linux-2.4.18.S18.scsimany/drivers/char/sysrq.c Fri Jul 26 02:42:04 2002 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -104,33 +105,31 @@ /* do_emergency_sync helper function */ /* Guesses if the device is a local hard drive */ static int is_local_disk(kdev_t dev) { - unsigned int major; - major = MAJOR(dev); - - switch (major) { - case IDE0_MAJOR: - case IDE1_MAJOR: - case IDE2_MAJOR: - case IDE3_MAJOR: - case IDE4_MAJOR: - case IDE5_MAJOR: - case IDE6_MAJOR: - case IDE7_MAJOR: - case IDE8_MAJOR: - case IDE9_MAJOR: - case SCSI_DISK0_MAJOR: - case SCSI_DISK1_MAJOR: - case SCSI_DISK2_MAJOR: - case SCSI_DISK3_MAJOR: - case SCSI_DISK4_MAJOR: - case SCSI_DISK5_MAJOR: - case SCSI_DISK6_MAJOR: - case SCSI_DISK7_MAJOR: - case XT_DISK_MAJOR: - return 1; - default: - return 0; + struct gendisk * gd = get_gendisk(dev); + if (gd && gd->major_name) { + if (!strcmp(gd->major_name, "hd")) /* IDE_MAJOR_NAME */ + return 1; + if (!strcmp(gd->major_name, "sd")) + return 1; + if (!strcmp(gd->major_name, "xd")) + return 1; + if (!strcmp(gd->major_name, "rd")) /* DAC960 */ + return 1; + if (!strcmp(gd->major_name, "dasd")) + return 1; + /* + * FIXME: More real devices missing ! + * i2o, iseriesvd, ppdd, pd, ftl, ed, ad, mfm, cbd, + * dos_hd, fd, pf + * + * What about meta devices, such as md, LVM, loop, ... + * + * Note that all disks with mounted filesystems are synced, + * only the ones listed here are considered stable and + * should be synced first. + */ } + return 0; } /* do_emergency_sync helper function */ diff -uNr linux-2.4.18.nohdstat/drivers/ide/ide-probe.c linux-2.4.18.S18.scsimany/drivers/ide/ide-probe.c --- linux-2.4.18.nohdstat/drivers/ide/ide-probe.c Wed Jun 12 11:37:15 2002 +++ linux-2.4.18.S18.scsimany/drivers/ide/ide-probe.c Wed Jul 17 14:49:29 2002 @@ -779,6 +779,7 @@ gd = kmalloc (sizeof(struct gendisk), GFP_KERNEL); if (!gd) goto err_kmalloc_gd; + memset (gd, 0, sizeof(struct gendisk)); gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL); if (!gd->sizes) goto err_kmalloc_gd_sizes; diff -uNr linux-2.4.18.nohdstat/drivers/scsi/Config.in linux-2.4.18.S18.scsimany/drivers/scsi/Config.in --- linux-2.4.18.nohdstat/drivers/scsi/Config.in Wed Jun 12 11:37:14 2002 +++ linux-2.4.18.S18.scsimany/drivers/scsi/Config.in Fri Jul 26 01:51:49 2002 @@ -1,9 +1,8 @@ comment 'SCSI support type (disk, tape, CD-ROM)' 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 + int 'Maximum number of SCSI major numbers' CONFIG_SD_MAX_MAJORS 16 fi dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI diff -uNr linux-2.4.18.nohdstat/drivers/scsi/Makefile linux-2.4.18.S18.scsimany/drivers/scsi/Makefile --- linux-2.4.18.nohdstat/drivers/scsi/Makefile Wed Jun 12 11:37:15 2002 +++ linux-2.4.18.S18.scsimany/drivers/scsi/Makefile Mon Jul 15 14:36:40 2002 @@ -162,7 +162,7 @@ scsi_obsolete.o scsi_queue.o scsi_lib.o \ scsi_merge.o scsi_dma.o scsi_scan.o \ scsi_syms.o -sd_mod-objs := sd.o +sd_mod-objs := sd.o sd_dynalloc.o sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o initio-objs := ini9100u.o i91uscsi.o a100u2w-objs := inia100.o i60uscsi.o diff -uNr linux-2.4.18.nohdstat/drivers/scsi/hosts.h linux-2.4.18.S18.scsimany/drivers/scsi/hosts.h --- linux-2.4.18.nohdstat/drivers/scsi/hosts.h Mon Jul 15 15:48:28 2002 +++ linux-2.4.18.S18.scsimany/drivers/scsi/hosts.h Fri Jul 26 02:42:27 2002 @@ -516,8 +516,6 @@ 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 nr_dev; /* Number currently attached */ unsigned int dev_noticed; /* Number of devices detected. */ unsigned int dev_max; /* Current size of arrays */ @@ -531,6 +529,7 @@ int (*init_command)(Scsi_Cmnd *); /* Used by new queueing code. Selects command for blkdevs */ int (*find_kdev)(Scsi_Device *, char*, kdev_t*); /* find back dev. */ + int (*drives_dev)(kdev_t); /* Does HL driver drive this major? */ }; void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt); diff -uNr linux-2.4.18.nohdstat/drivers/scsi/scsi_lib.c linux-2.4.18.S18.scsimany/drivers/scsi/scsi_lib.c --- linux-2.4.18.nohdstat/drivers/scsi/scsi_lib.c Sun Jul 14 17:34:01 2002 +++ linux-2.4.18.S18.scsimany/drivers/scsi/scsi_lib.c Tue Jul 16 12:07:05 2002 @@ -806,22 +806,8 @@ 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 ) - { + if (spnt->drives_dev && (spnt->drives_dev)(dev)) return spnt; - } } return NULL; } diff -uNr linux-2.4.18.nohdstat/drivers/scsi/sd.c linux-2.4.18.S18.scsimany/drivers/scsi/sd.c --- linux-2.4.18.nohdstat/drivers/scsi/sd.c Sun Jul 14 17:17:49 2002 +++ linux-2.4.18.S18.scsimany/drivers/scsi/sd.c Fri Jul 26 11:46:22 2002 @@ -28,6 +28,9 @@ * * Modified by Alex Davis * Fix problem where removable media could be ejected after sd_open. + * + * Modified by Kurt Garloff + * Dynamically allocate majors and support > 128 disks. */ #include @@ -49,12 +52,12 @@ #include #include -#define MAJOR_NR SCSI_DISK0_MAJOR #include #include #include "scsi.h" #include "hosts.h" #include "sd.h" +#include "sd_dynalloc.h" #include #include "constants.h" #include /* must follow "hosts.h" */ @@ -65,21 +68,6 @@ * static const char RCSid[] = "$Header:"; */ -/* system major --> sd_gendisks index */ -#define SD_MAJOR_IDX(i) (MAJOR(i) & SD_MAJOR_MASK) -/* sd_gendisks index --> system major */ -#define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i)) - -#define SD_PARTITION(dev) ((SD_MAJOR_IDX(dev) << 8) | (MINOR(dev) & 255)) - -#define SCSI_DISKS_PER_MAJOR 16 -#define SD_MAJOR_NUMBER(i) SD_MAJOR((i) >> 8) -#define SD_MINOR_NUMBER(i) ((i) & 255) -#define MKDEV_SD_PARTITION(i) MKDEV(SD_MAJOR_NUMBER(i), (i) & 255) -#define MKDEV_SD(index) MKDEV_SD_PARTITION((index) << 4) -#define N_USED_SCSI_DISKS (sd_template.dev_max + SCSI_DISKS_PER_MAJOR - 1) -#define N_USED_SD_MAJORS (N_USED_SCSI_DISKS / SCSI_DISKS_PER_MAJOR) - #define MAX_RETRIES 5 /* @@ -89,19 +77,10 @@ #define SD_TIMEOUT (60 * HZ) #define SD_MOD_TIMEOUT (75 * HZ) -static Scsi_Disk *rscsi_disks; -static struct gendisk *sd_gendisks; -static int *sd_sizes; -static int *sd_blocksizes; -static int *sd_hardsizes; /* Hardware sector size */ -static int *sd_max_sectors; -static char *sd_varyio; - static int check_scsidisk_media_change(kdev_t); static int fop_revalidate_scsidisk(kdev_t); -static int sd_init_onedisk(int); - +static int sd_init_onedisk(int, int); static int sd_init(void); static void sd_finish(void); @@ -110,17 +89,13 @@ static void sd_detach(Scsi_Device *); static int sd_init_command(Scsi_Cmnd *); static int sd_find_kdev(Scsi_Device*, char*, kdev_t*); +static int sd_drives_dev(kdev_t); static struct Scsi_Device_Template sd_template = { 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, @@ -129,6 +104,7 @@ detach:sd_detach, init_command:sd_init_command, find_kdev:sd_find_kdev, + drives_dev:sd_drives_dev, }; @@ -141,13 +117,19 @@ kdev_t __init sd_find_target(void *host, int tgt) { - Scsi_Disk *dp; - int i; - for (dp = rscsi_disks, i = 0; i < sd_template.dev_max; ++i, ++dp) - if (dp->device != NULL && dp->device->host == host - && dp->device->id == tgt) - return MKDEV_SD(i); - return 0; + SD_Major *sd_major; + Scsi_Device *SDev; + int midx, didx; + for (midx = 0; midx < sd_majors; ++midx) { + sd_major = SD_MAJOR_PTR(midx); + for (didx = 0; didx < SCSI_DISKS_PER_MAJOR; ++didx) { + SDev = SD_DISK_PTR(sd_major, didx)->device; + if (SDev && SDev->device->host == host + && SDev->device->id = tgt) + return MDIDX_TO_KDEV(midx,didx); + } + } + return 0; } #endif @@ -157,8 +139,18 @@ struct Scsi_Host * host; Scsi_Device * SDev; int diskinfo[4]; + int midx, didx; + SD_Major *sd_major; + Scsi_Disk *scsi_disk; - SDev = rscsi_disks[DEVICE_NR(dev)].device; + midx = MAJOR_TO_MIDX(MAJOR(dev)); + didx = MINOR_TO_DIDX(MINOR(dev)); + + if (midx == SD_NO_MIDX) + return -ENODEV; + sd_major = SD_MAJOR_PTR(midx); + scsi_disk = SD_DISK_PTR(sd_major,didx); + SDev = scsi_disk->device; if (!SDev) return -ENODEV; @@ -170,9 +162,7 @@ */ if( !scsi_block_when_processing_errors(SDev) ) - { return -ENODEV; - } switch (cmd) { @@ -182,29 +172,27 @@ if(!loc) return -EINVAL; - host = rscsi_disks[DEVICE_NR(dev)].device->host; + host = SDev->host; /* default to most commonly used values */ diskinfo[0] = 0x40; diskinfo[1] = 0x20; - diskinfo[2] = rscsi_disks[DEVICE_NR(dev)].capacity >> 11; + diskinfo[2] = scsi_disk->capacity >> 11; /* override with calculated, extended default, or driver values */ if(host->hostt->bios_param != NULL) - host->hostt->bios_param(&rscsi_disks[DEVICE_NR(dev)], - dev, - &diskinfo[0]); - else scsicam_bios_param(&rscsi_disks[DEVICE_NR(dev)], - dev, &diskinfo[0]); + host->hostt->bios_param(scsi_disk, + dev, &diskinfo[0]); + else scsicam_bios_param(scsi_disk, + dev, &diskinfo[0]); if (put_user(diskinfo[0], &loc->heads) || - put_user(diskinfo[1], &loc->sectors) || - put_user(diskinfo[2], &loc->cylinders) || - put_user(sd_gendisks[SD_MAJOR_IDX( - inode->i_rdev)].part[MINOR( - inode->i_rdev)].start_sect, &loc->start)) + put_user(diskinfo[1], &loc->sectors) || + put_user(diskinfo[2], &loc->cylinders) || + put_user(sd_major->sd_gendisk.part[MINOR(dev)].start_sect, + &loc->start)) return -EFAULT; return 0; } @@ -215,29 +203,27 @@ if(!loc) return -EINVAL; - host = rscsi_disks[DEVICE_NR(dev)].device->host; + host = SDev->host; /* default to most commonly used values */ diskinfo[0] = 0x40; diskinfo[1] = 0x20; - diskinfo[2] = rscsi_disks[DEVICE_NR(dev)].capacity >> 11; + diskinfo[2] = scsi_disk->capacity >> 11; /* override with calculated, extended default, or driver values */ if(host->hostt->bios_param != NULL) - host->hostt->bios_param(&rscsi_disks[DEVICE_NR(dev)], - dev, - &diskinfo[0]); - else scsicam_bios_param(&rscsi_disks[DEVICE_NR(dev)], - dev, &diskinfo[0]); + host->hostt->bios_param(scsi_disk, + dev, &diskinfo[0]); + else scsicam_bios_param(scsi_disk, + dev, &diskinfo[0]); if (put_user(diskinfo[0], &loc->heads) || - put_user(diskinfo[1], &loc->sectors) || - put_user(diskinfo[2], (unsigned int *) &loc->cylinders) || - put_user(sd_gendisks[SD_MAJOR_IDX( - inode->i_rdev)].part[MINOR( - inode->i_rdev)].start_sect, &loc->start)) + put_user(diskinfo[1], &loc->sectors) || + put_user(diskinfo[2], (unsigned int *) &loc->cylinders) || + put_user(sd_major->sd_gendisk.part[MINOR(dev)].start_sect, + &loc->start)) return -EFAULT; return 0; } @@ -262,67 +248,106 @@ return revalidate_scsidisk(dev, 1); default: - return scsi_ioctl(rscsi_disks[DEVICE_NR(dev)].device , cmd, (void *) arg); + return scsi_ioctl(SDev, cmd, (void *) arg); } } -static void sd_devname(unsigned int disknum, char *buffer) +int sd_devname(kdev_t dev, char *buffer) { + const unsigned int disknum = KDEV_TO_DISKNO(dev); + const unsigned int part = MINOR(dev) & (SCSI_DISK_MAX_PART-1); + if (disknum >= SD_NO_MIDX << SCSI_DISK_DISK_SHIFT) + return -1; if (disknum < 26) sprintf(buffer, "sd%c", 'a' + disknum); - else { - unsigned int min1; - unsigned int min2; - /* - * For larger numbers of disks, we need to go to a new - * naming scheme. - */ - min1 = disknum / 26; - min2 = disknum % 26; - sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2); + else if (disknum < (26*27)) { + const unsigned int min1 = disknum / 26 - 1; + const unsigned int min2 = disknum % 26; + sprintf(buffer, "sd%c%c", 'a' + min1, 'a' + min2); + } else { + const unsigned int min1 = (disknum / 26 - 1) / 26 - 1; + const unsigned int min2 = (disknum / 26 - 1) % 26; + const unsigned int min3 = disknum % 26; + sprintf(buffer, "sd%c%c%c", 'a' + min1, 'a' + min2, 'a' + min3); + } + /* Used by fs/partition/check.c */ + if (part) { + const int pos = strlen(buffer); + sprintf (buffer+pos, "%d", part); } + return 0; } static int sd_find_kdev(Scsi_Device *sdp, char* nm, kdev_t *dev) { - Scsi_Disk *dp; - int i; + SD_Major *sd_major; + int midx, didx; if (sdp && (sdp->type == TYPE_DISK || sdp->type == TYPE_MOD)) { - for (dp = rscsi_disks, i = 0; i < sd_template.dev_max; ++i, ++dp) { - if (dp->device == sdp) { - sd_devname(i, nm); - *dev = MKDEV_SD(i); - return 0; + for (midx = 0; midx < sd_majors; ++midx) { + sd_major = SD_MAJOR_PTR(midx); + for (didx = 0; didx < SCSI_DISKS_PER_MAJOR; ++didx) { + if (SD_DISK_PTR(sd_major, didx)->device == sdp) { + *dev = MDIDX_TO_KDEV(midx, didx); + sd_devname(*dev, nm); + return 0; + } } } } return 1; } -static request_queue_t *sd_find_queue(kdev_t dev) +request_queue_t *sd_find_queue(kdev_t dev) { Scsi_Disk *dpnt; - int target; - target = DEVICE_NR(dev); - - dpnt = &rscsi_disks[target]; + int midx, didx; + + midx = MAJOR_TO_MIDX (MAJOR(dev)); + didx = MINOR_TO_DIDX (MINOR(dev)); + if (midx == SD_NO_MIDX) { + printk (KERN_ERR "sd_find_queue %02x:%02x not found!\n", + MAJOR(dev), MINOR(dev)); + return NULL; + } + dpnt = SD_DISK_PTR(SD_MAJOR_PTR(midx), didx); if (!dpnt->device) return NULL; /* No such device */ return &dpnt->device->request_queue; } +static int sd_drives_dev(kdev_t dev) +{ + int midx = MAJOR_TO_MIDX(MAJOR(dev)); + if (midx == SD_NO_MIDX) + return 0; + else + return 1; +} + static int sd_init_command(Scsi_Cmnd * SCpnt) { - int dev, block, this_count, hw_ssize; + int block, this_count, hw_ssize; struct hd_struct *ppnt; Scsi_Disk *dpnt; #if CONFIG_SCSI_LOGGING - char nbuff[6]; + char nbuff[10]; #endif + int midx, didx; + SD_Major *sd_major; - ppnt = &sd_gendisks[SD_MAJOR_IDX(SCpnt->request.rq_dev)].part[MINOR(SCpnt->request.rq_dev)]; - dev = DEVICE_NR(SCpnt->request.rq_dev); + midx = MAJOR_TO_MIDX(MAJOR(SCpnt->request.rq_dev)); + didx = MINOR_TO_DIDX(MINOR(SCpnt->request.rq_dev)); + if (midx == SD_NO_MIDX) { + printk ("Can not sd_init_command for dev %02x:%02x!\n", + MAJOR(SCpnt->request.rq_dev), + MINOR(SCpnt->request.rq_dev)); + return 0; + } + + sd_major = SD_MAJOR_PTR(midx); + dpnt = SD_DISK_PTR(sd_major, didx); + ppnt = sd_major->sd_gendisk.part+MINOR(SCpnt->request.rq_dev); block = SCpnt->request.sector; this_count = SCpnt->request_bufflen >> 9; @@ -333,13 +358,11 @@ return 0; SCSI_LOG_HLQUEUE(1, printk("Doing sd request, dev = 0x%x, block = %d\n", - SCpnt->request.rq_dev, block)); + SCpnt->request.rq_dev, block)); - dpnt = &rscsi_disks[dev]; - if (dev >= sd_template.dev_max || - !dpnt->device || + if (!dpnt->device || !dpnt->device->online || - block + SCpnt->request.nr_sectors > ppnt->nr_sects) { + block + SCpnt->request.nr_sectors > ppnt->nr_sects) { SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors)); SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt)); return 0; @@ -353,9 +376,10 @@ /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */ return 0; } - SCSI_LOG_HLQUEUE(2, sd_devname(dev, nbuff)); - SCSI_LOG_HLQUEUE(2, printk("%s : real dev = /dev/%d, block = %d\n", - nbuff, dev, block)); + SCSI_LOG_HLQUEUE(2, sd_devname(SCpnt->request.rq_dev, nbuff)); + SCSI_LOG_HLQUEUE(2, printk("%s : %02x:%02x, block = %d\n", + nbuff, MAJOR(SCpnt->request.rq_dev), + MINOR(SCpnt->request.rq_dev), block)); /* * If we have a 1K hardware sectorsize, prevent access to single @@ -469,44 +493,54 @@ static int sd_open(struct inode *inode, struct file *filp) { - int target, retval = -ENXIO; + int retval = -ENXIO; Scsi_Device * SDev; - target = DEVICE_NR(inode->i_rdev); + int midx, didx; + SD_Major *sd_major; + Scsi_Disk *scsi_disk; + + midx = MAJOR_TO_MIDX(MAJOR(inode->i_rdev)); + didx = MINOR_TO_DIDX(MINOR(inode->i_rdev)); - SCSI_LOG_HLQUEUE(1, printk("target=%d, max=%d\n", target, sd_template.dev_max)); + SCSI_LOG_HLQUEUE(1, printk("target=%d\n", MDIDX_TO_DISKNO(midx, didx))); - if (target >= sd_template.dev_max || !rscsi_disks[target].device) + if (midx == SD_NO_MIDX) + return -ENXIO; + sd_major = SD_MAJOR_PTR(midx); + scsi_disk = SD_DISK_PTR(sd_major, didx); + SDev = scsi_disk->device; + + if (!SDev) return -ENXIO; /* No such device */ /* * If the device is in error recovery, wait until it is done. * If the device is offline, then disallow any access to it. */ - if (!scsi_block_when_processing_errors(rscsi_disks[target].device)) { + if (!scsi_block_when_processing_errors(SDev)) { return -ENXIO; } /* - * Make sure that only one process can do a check_change_disk at one time. - * This is also used to lock out further access when the partition table - * is being re-read. - */ - - while (rscsi_disks[target].device->busy) { - barrier(); - cpu_relax(); - } - /* * The following code can sleep. * Module unloading must be prevented */ - SDev = rscsi_disks[target].device; if (SDev->host->hostt->module) __MOD_INC_USE_COUNT(SDev->host->hostt->module); if (sd_template.module) __MOD_INC_USE_COUNT(sd_template.module); SDev->access_count++; + /* + * Make sure that only one process can do a check_change_disk at one time. + * This is also used to lock out further access when the partition table + * is being re-read. + */ + + while (SDev->busy) { + barrier(); + cpu_relax(); + } - if (rscsi_disks[target].device->removable) { + if (SDev->removable) { SDev->allow_revalidate = 1; check_disk_change(inode->i_rdev); SDev->allow_revalidate = 0; @@ -514,7 +548,7 @@ /* * If the drive is empty, just let the open fail. */ - if ((!rscsi_disks[target].ready) && !(filp->f_flags & O_NDELAY)) { + if ((!scsi_disk->ready) && !(filp->f_flags & O_NDELAY)) { retval = -ENOMEDIUM; goto error_out; } @@ -524,7 +558,7 @@ * have the open fail if the user expects to be able to write * to the thing. */ - if ((rscsi_disks[target].write_prot) && (filp->f_mode & 2)) { + if ((scsi_disk->write_prot) && (filp->f_mode & 2)) { retval = -EROFS; goto error_out; } @@ -542,7 +576,7 @@ * See if we are requesting a non-existent partition. Do this * after checking for disk change. */ - if (sd_sizes[SD_PARTITION(inode->i_rdev)] == 0) { + if (sd_major->sd_sizes[MINOR(inode->i_rdev)] == 0) { goto error_out; } @@ -565,11 +599,20 @@ static int sd_release(struct inode *inode, struct file *file) { - int target; - Scsi_Device * SDev; + Scsi_Device *SDev; + int midx, didx; + + midx = MAJOR_TO_MIDX(MAJOR(inode->i_rdev)); + didx = MINOR_TO_DIDX(MINOR(inode->i_rdev)); - target = DEVICE_NR(inode->i_rdev); - SDev = rscsi_disks[target].device; + if (midx == SD_NO_MIDX) { + printk (KERN_ERR "sd_release: dev %02x:%02x does not belong to sd!\n", + MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); + return -ENODEV; + } + + SDev = SD_DISK_PTR(SD_MAJOR_PTR(midx), didx)->device; + if (!SDev) return -ENODEV; @@ -598,22 +641,6 @@ }; /* - * If we need more than one SCSI disk major (i.e. more than - * 16 SCSI disks), we'll have to kmalloc() more gendisks later. - */ - -static struct gendisk sd_gendisk = -{ - major: SCSI_DISK0_MAJOR, - major_name: "sd", - minor_shift: 4, - max_p: 1 << 4, - fops: &sd_fops, -}; - -#define SD_GENDISK(i) sd_gendisks[(i) / SCSI_DISKS_PER_MAJOR] - -/* * rw_intr is the interrupt routine for the device driver. * It will be notified on the end of a SCSI read / write, and * will take one of several actions based on success or failure. @@ -623,14 +650,18 @@ { int result = SCpnt->result; #if CONFIG_SCSI_LOGGING - char nbuff[6]; + char nbuff[10]; #endif int this_count = SCpnt->bufflen >> 9; int good_sectors = (result == 0 ? this_count : 0); int block_sectors = 1; long error_sector; + int midx, didx; + + midx = MAJOR_TO_MIDX(MAJOR(SCpnt->request.rq_dev)); + didx = MINOR_TO_DIDX(MINOR(SCpnt->request.rq_dev)); - SCSI_LOG_HLCOMPLETE(1, sd_devname(DEVICE_NR(SCpnt->request.rq_dev), nbuff)); + SCSI_LOG_HLCOMPLETE(1, sd_devname(SCpnt->request.rq_dev, nbuff)); SCSI_LOG_HLCOMPLETE(1, printk("%s : rw_intr(%d, %x [%x %x])\n", nbuff, SCpnt->host->host_no, @@ -677,9 +708,10 @@ default: break; } - error_sector -= sd_gendisks[SD_MAJOR_IDX( - SCpnt->request.rq_dev)].part[MINOR( - SCpnt->request.rq_dev)].start_sect; + /* find offset into partition */ + error_sector -= SD_MAJOR_PTR(midx) + ->sd_gendisk.part[MINOR(SCpnt->request.rq_dev)] + .start_sect; error_sector &= ~(block_sectors - 1); good_sectors = error_sector - SCpnt->request.sector; if (good_sectors < 0 || good_sectors >= this_count) @@ -726,19 +758,26 @@ static int check_scsidisk_media_change(kdev_t full_dev) { - int retval; - int target; - int flag = 0; - Scsi_Device * SDev; - - target = DEVICE_NR(full_dev); - SDev = rscsi_disks[target].device; + int retval = 0; + int midx, didx; + SD_Major *sd_major; + Scsi_Disk *scsi_disk; + + midx = MAJOR_TO_MIDX(MAJOR(full_dev)); + didx = MINOR_TO_DIDX(MINOR(full_dev)); + + if (midx == SD_NO_MIDX) { + printk("SCSI disk request error: invalid major.\n"); + return 0; + } + sd_major = SD_MAJOR_PTR(midx); + scsi_disk = SD_DISK_PTR(sd_major, didx); - if (target >= sd_template.dev_max || !SDev) { + if (!scsi_disk->device) { printk("SCSI disk request error: invalid device.\n"); return 0; } - if (!SDev->removable) + if (!scsi_disk->device->removable) return 0; /* @@ -747,9 +786,9 @@ * can deal with it then. It is only because of unrecoverable errors * that we would ever take a device offline in the first place. */ - if (SDev->online == FALSE) { - rscsi_disks[target].ready = 0; - SDev->changed = 1; + if (scsi_disk->device->online == FALSE) { + scsi_disk->ready = 0; + scsi_disk->device->changed = 1; return 1; /* This will force a flush, if called from * check_disk_change */ } @@ -761,8 +800,8 @@ * as this will spin up the drive. */ retval = -ENODEV; - if (scsi_block_when_processing_errors(SDev)) - retval = scsi_ioctl(SDev, SCSI_IOCTL_START_UNIT, NULL); + if (scsi_block_when_processing_errors(scsi_disk->device)) + retval = scsi_ioctl(scsi_disk->device, SCSI_IOCTL_START_UNIT, NULL); if (retval) { /* Unable to test, unit probably not ready. * This usually means there is no disc in the @@ -770,8 +809,8 @@ * it out later once the drive is available * again. */ - rscsi_disks[target].ready = 0; - SDev->changed = 1; + scsi_disk->ready = 0; + scsi_disk->device->changed = 1; return 1; /* This will force a flush, if called from * check_disk_change */ } @@ -781,35 +820,43 @@ * struct and tested at open ! Daniel Roche ( dan@lectra.fr ) */ - rscsi_disks[target].ready = 1; /* FLOPTICAL */ + scsi_disk->ready = 1; /* FLOPTICAL */ - retval = SDev->changed; - if (!flag) - SDev->changed = 0; + retval = scsi_disk->device->changed; + /* FIXME: The next statement was behind a if (!flag) conditional + * with flag initialized to 0 and never changed ... KG. */ + scsi_disk->device->changed = 0; return retval; } -static int sd_init_onedisk(int i) +static int sd_init_onedisk(int midx, int didx) { unsigned char cmd[10]; - char nbuff[6]; + char nbuff[8]; unsigned char *buffer; unsigned long spintime_value = 0; int the_result, retries, spintime; - int sector_size; + int sector_size, sz; + int part; + unsigned char cdb1; Scsi_Request *SRpnt; + SD_Major *sd_major = SD_MAJOR_PTR(midx); + Scsi_Disk *scsi_disk = SD_DISK_PTR(sd_major, didx); /* * Get the name of the disk, in case we need to log it somewhere. */ - sd_devname(i, nbuff); + sd_devname(MDIDX_TO_KDEV(midx,didx), nbuff); /* * If the device is offline, don't try and read capacity or any * of the other niceties. */ - if (rscsi_disks[i].device->online == FALSE) - return i; + if (scsi_disk->device->online == FALSE) + return -1; + + printk (KERN_DEBUG "sd_init_onedisk (%i,%i), %s %02x:%02x\n", + midx, didx, nbuff, MIDX_TO_MAJOR(midx), DIDX_TO_MINOR(didx)); /* * We need to retry the READ_CAPACITY because a UNIT_ATTENTION is @@ -817,19 +864,21 @@ * just after a scsi bus reset. */ - SRpnt = scsi_allocate_request(rscsi_disks[i].device); + SRpnt = scsi_allocate_request(scsi_disk->device); if (!SRpnt) { printk(KERN_WARNING "(sd_init_onedisk:) Request allocation failure.\n"); - return i; + return -1; } - buffer = (unsigned char *) scsi_malloc(512); + buffer = (unsigned char *) scsi_malloc(256); if (!buffer) { printk(KERN_WARNING "(sd_init_onedisk:) Memory allocation failure.\n"); scsi_release_request(SRpnt); - return i; + return -1; } + cdb1 = (scsi_disk->device->scsi_level <= SCSI_2) ? + ((scsi_disk->device->lun << 5) & 0xe0) : 0; spintime = 0; /* Spin up drives, as required. Only do this at boot time */ @@ -839,8 +888,7 @@ while (retries < 3) { cmd[0] = TEST_UNIT_READY; - cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? - ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; + cmd[1] = cdb1; memset((void *) &cmd[2], 0, 8); SRpnt->sr_cmd_len = 0; SRpnt->sr_sense_buffer[0] = 0; @@ -848,7 +896,7 @@ SRpnt->sr_data_direction = SCSI_DATA_NONE; scsi_wait_req (SRpnt, (void *) cmd, (void *) buffer, - 0/*512*/, SD_TIMEOUT, MAX_RETRIES); + 0/*512*/, SD_TIMEOUT, MAX_RETRIES); the_result = SRpnt->sr_result; retries++; @@ -866,24 +914,22 @@ && ((driver_byte(the_result) & DRIVER_SENSE) != 0) && SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION && SRpnt->sr_sense_buffer[12] == 0x3A ) { - rscsi_disks[i].capacity = 0x1fffff; + scsi_disk->capacity = 0x1fffff; sector_size = 512; - rscsi_disks[i].device->changed = 1; - rscsi_disks[i].ready = 0; + scsi_disk->device->changed = 1; + scsi_disk->ready = 0; break; } /* Look for non-removable devices that return NOT_READY. * Issue command to spin up drive for these cases. */ - if (the_result && !rscsi_disks[i].device->removable && + if (the_result && !scsi_disk->device->removable && SRpnt->sr_sense_buffer[2] == NOT_READY) { unsigned long time1; if (!spintime) { printk("%s: Spinning up disk...", nbuff); cmd[0] = START_STOP; - cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? - ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; - cmd[1] |= 1; /* Return immediately */ + cmd[1] = cdb1 | 1; /* Return immediately */ memset((void *) &cmd[2], 0, 8); cmd[4] = 1; /* Start spin cycle */ SRpnt->sr_cmd_len = 0; @@ -915,8 +961,7 @@ retries = 3; do { cmd[0] = READ_CAPACITY; - cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? - ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; + cmd[1] = cdb1; memset((void *) &cmd[2], 0, 8); memset((void *) buffer, 0, 8); SRpnt->sr_cmd_len = 0; @@ -925,7 +970,7 @@ SRpnt->sr_data_direction = SCSI_DATA_READ; scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer, - 8, SD_TIMEOUT, MAX_RETRIES); + 8, SD_TIMEOUT, MAX_RETRIES); the_result = SRpnt->sr_result; retries--; @@ -963,28 +1008,28 @@ printk("%s : block size assumed to be 512 bytes, disk size 1GB. \n", nbuff); - rscsi_disks[i].capacity = 0x1fffff; + scsi_disk->capacity = 0x1fffff; sector_size = 512; /* Set dirty bit for removable devices if not ready - * sometimes drives will not report this properly. */ - if (rscsi_disks[i].device->removable && + if (scsi_disk->device->removable && SRpnt->sr_sense_buffer[2] == NOT_READY) - rscsi_disks[i].device->changed = 1; + scsi_disk->device->changed = 1; } else { /* * FLOPTICAL, if read_capa is ok, drive is assumed to be ready */ - rscsi_disks[i].ready = 1; + scsi_disk->ready = 1; - rscsi_disks[i].capacity = 1 + ((buffer[0] << 24) | - (buffer[1] << 16) | - (buffer[2] << 8) | - buffer[3]); + scsi_disk->capacity = 1 + ((buffer[0] << 24) | + (buffer[1] << 16) | + (buffer[2] << 8) | + buffer[3]); sector_size = (buffer[4] << 24) | - (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; + (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; if (sector_size == 0) { sector_size = 512; @@ -1004,58 +1049,52 @@ * would be relatively trivial to set the thing up. * For this reason, we leave the thing in the table. */ - rscsi_disks[i].capacity = 0; + scsi_disk->capacity = 0; } if (sector_size > 1024) { - int m; - /* * We must fix the sd_blocksizes and sd_hardsizes * to allow us to read the partition tables. * The disk reading code does not allow for reading * of partial sectors. */ - for (m = i << 4; m < ((i + 1) << 4); m++) { - sd_blocksizes[m] = sector_size; - } - } { - /* - * The msdos fs needs to know the hardware sector size - * So I have created this table. See ll_rw_blk.c - * Jacques Gelinas (Jacques@solucorp.qc.ca) - */ - int m; - int hard_sector = sector_size; - int sz = rscsi_disks[i].capacity * (hard_sector/256); - - /* There are 16 minors allocated for each major device */ - for (m = i << 4; m < ((i + 1) << 4); m++) { - sd_hardsizes[m] = hard_sector; - } - - printk("SCSI device %s: " - "%d %d-byte hdwr sectors (%d MB)\n", - nbuff, rscsi_disks[i].capacity, - hard_sector, (sz/2 - sz/1250 + 974)/1950); + for (part = 0; part < SCSI_DISK_MAX_PART; ++part) + sd_major->sd_blocksizes[DIDX_TO_MINOR(didx) + part] + = sector_size; } + /* + * The msdos fs needs to know the hardware sector size + * So I have created this table. See ll_rw_blk.c + * Jacques Gelinas (Jacques@solucorp.qc.ca) + */ + sz = scsi_disk->capacity * (sector_size/256); + for (part = 0; part < SCSI_DISK_MAX_PART; ++part) + sd_major->sd_hardsizes[DIDX_TO_MINOR(didx) + part] + = sector_size; + + printk("SCSI device %s: " + "%d %d-byte hdwr sectors (%d MB)\n", + nbuff, scsi_disk->capacity, + sector_size, (sz/2 - sz/1250 + 974)/1950); + /* Rescale capacity to 512-byte units */ if (sector_size == 4096) - rscsi_disks[i].capacity <<= 3; + scsi_disk->capacity <<= 3; if (sector_size == 2048) - rscsi_disks[i].capacity <<= 2; + scsi_disk->capacity <<= 2; if (sector_size == 1024) - rscsi_disks[i].capacity <<= 1; + scsi_disk->capacity <<= 1; if (sector_size == 256) - rscsi_disks[i].capacity >>= 1; + scsi_disk->capacity >>= 1; } /* * Unless otherwise specified, this is not write protected. */ - rscsi_disks[i].write_prot = 0; - if (rscsi_disks[i].device->removable && rscsi_disks[i].ready) { + scsi_disk->write_prot = 0; + if (scsi_disk->device->removable && scsi_disk->ready) { /* FLOPTICAL */ /* @@ -1073,10 +1112,9 @@ memset((void *) &cmd[0], 0, 8); cmd[0] = MODE_SENSE; - cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? - ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; + cmd[1] = cdb1; cmd[2] = 0x3f; /* Get all pages */ - cmd[4] = 255; /* Ask for 255 bytes, even tho we want just the first 8 */ + cmd[4] = 252; /* Ask for 252 bytes, even tho we want just the first 8 */ SRpnt->sr_cmd_len = 0; SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_sense_buffer[2] = 0; @@ -1084,19 +1122,20 @@ /* same code as READCAPA !! */ SRpnt->sr_data_direction = SCSI_DATA_READ; scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer, - 512, SD_TIMEOUT, MAX_RETRIES); + 252, SD_TIMEOUT, MAX_RETRIES); the_result = SRpnt->sr_result; if (the_result) { printk("%s: test WP failed, assume Write Enabled\n", nbuff); } else { - rscsi_disks[i].write_prot = ((buffer[2] & 0x80) != 0); + scsi_disk->write_prot = ((buffer[2] & 0x80) != 0); printk("%s: Write Protect is %s\n", nbuff, - rscsi_disks[i].write_prot ? "on" : "off"); + scsi_disk->write_prot ? "on" : "off"); } } /* check for write protect */ + SRpnt->sr_device->ten = 1; SRpnt->sr_device->remap = 1; SRpnt->sr_device->sector_size = sector_size; @@ -1104,193 +1143,81 @@ scsi_release_request(SRpnt); SRpnt = NULL; - scsi_free(buffer, 512); - return i; + scsi_free(buffer, 256); + return 0; } /* - * The sd_init() function looks at all SCSI drives present, determines - * their size, and reads partition table entries for them. + * We are called on behalf scan_scsis() for every Device. + * First init(), then attach(Scsi_Device*), finally finish(). + * It's inconvenient: In finish(), we don't know what device + * has been attached. So we iterate over all disk in + * sd_finish(). Sigh! KG. */ static int sd_registered; static int sd_init() { - int i; - - if (sd_template.dev_noticed == 0) + int err = 0; + if (!sd_template.dev_noticed) return 0; - - if (!rscsi_disks) - 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_registered) { - for (i = 0; i < N_USED_SD_MAJORS; i++) { - if (devfs_register_blkdev(SD_MAJOR(i), "sd", &sd_fops)) { - printk("Unable to get major %d for SCSI disk\n", SD_MAJOR(i)); - sd_template.dev_noticed = 0; - return 1; - } - } + sd_template.dev_max = MAX_SCSI_DYN_MAJORS * SCSI_DISKS_PER_MAJOR; + SD_LOCK_W; + printk(KERN_DEBUG "sd_init()\n"); + if (!sd_majors) { + /* Register one sd_major at startup */ + err = sd_alloc_major (); + } + SD_UNLOCK_W; + if (err == SD_NO_MAJOR) { + sd_template.dev_noticed = 0; + return 1; + } else { sd_registered++; - } - /* We do not support attaching loadable devices yet. */ - if (rscsi_disks) return 0; - - rscsi_disks = kmalloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC); - if (!rscsi_disks) - goto cleanup_devfs; - memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk)); - - /* for every (necessary) major: */ - sd_sizes = kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); - if (!sd_sizes) - goto cleanup_disks; - memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int)); - - sd_blocksizes = kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); - if (!sd_blocksizes) - goto cleanup_sizes; - - sd_hardsizes = kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); - if (!sd_hardsizes) - goto cleanup_blocksizes; - - sd_max_sectors = kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); - if (!sd_max_sectors) - goto cleanup_max_sectors; - - sd_varyio = kmalloc((sd_template.dev_max << 4), GFP_ATOMIC); - if (!sd_varyio) - goto cleanup_varyio; - - memset(sd_varyio, 0, (sd_template.dev_max << 4)); - - for (i = 0; i < sd_template.dev_max << 4; i++) { - sd_blocksizes[i] = 1024; - sd_hardsizes[i] = 512; - /* - * Allow lowlevel device drivers to generate 512k large scsi - * commands if they know what they're doing and they ask for it - * explicitly via the SHpnt->max_sectors API. - */ - sd_max_sectors[i] = MAX_SEGMENTS*8; - } - - for (i = 0; i < N_USED_SD_MAJORS; i++) { - blksize_size[SD_MAJOR(i)] = sd_blocksizes + i * (SCSI_DISKS_PER_MAJOR << 4); - hardsect_size[SD_MAJOR(i)] = sd_hardsizes + i * (SCSI_DISKS_PER_MAJOR << 4); - max_sectors[SD_MAJOR(i)] = sd_max_sectors + i * (SCSI_DISKS_PER_MAJOR << 4); - } - - sd_gendisks = kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC); - if (!sd_gendisks) - goto cleanup_sd_gendisks; - for (i = 0; i < N_USED_SD_MAJORS; i++) { - sd_gendisks[i] = sd_gendisk; /* memcpy */ - sd_gendisks[i].de_arr = kmalloc (SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].de_arr, - GFP_ATOMIC); - if (!sd_gendisks[i].de_arr) - goto cleanup_gendisks_de_arr; - memset (sd_gendisks[i].de_arr, 0, - SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].de_arr); - sd_gendisks[i].flags = kmalloc (SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].flags, - GFP_ATOMIC); - if (!sd_gendisks[i].flags) - goto cleanup_gendisks_flags; - memset (sd_gendisks[i].flags, 0, - SCSI_DISKS_PER_MAJOR * sizeof *sd_gendisks[i].flags); - sd_gendisks[i].major = SD_MAJOR(i); - sd_gendisks[i].major_name = "sd"; - sd_gendisks[i].minor_shift = 4; - sd_gendisks[i].max_p = 1 << 4; - sd_gendisks[i].part = kmalloc((SCSI_DISKS_PER_MAJOR << 4) * sizeof(struct hd_struct), - GFP_ATOMIC); - if (!sd_gendisks[i].part) - goto cleanup_gendisks_part; - memset(sd_gendisks[i].part, 0, (SCSI_DISKS_PER_MAJOR << 4) * sizeof(struct hd_struct)); - sd_gendisks[i].sizes = sd_sizes + (i * SCSI_DISKS_PER_MAJOR << 4); - sd_gendisks[i].nr_real = 0; - sd_gendisks[i].real_devices = - (void *) (rscsi_disks + i * SCSI_DISKS_PER_MAJOR); - } - - return 0; - -cleanup_gendisks_part: - kfree(sd_gendisks[i].flags); -cleanup_gendisks_flags: - kfree(sd_gendisks[i].de_arr); -cleanup_gendisks_de_arr: - while (--i >= 0 ) { - kfree(sd_gendisks[i].de_arr); - kfree(sd_gendisks[i].flags); - kfree(sd_gendisks[i].part); - } - kfree(sd_gendisks); - sd_gendisks = NULL; -cleanup_sd_gendisks: - kfree(sd_varyio); -cleanup_varyio: - kfree(sd_max_sectors); -cleanup_max_sectors: - kfree(sd_hardsizes); -cleanup_blocksizes: - kfree(sd_blocksizes); -cleanup_sizes: - kfree(sd_sizes); -cleanup_disks: - kfree(rscsi_disks); - rscsi_disks = NULL; -cleanup_devfs: - for (i = 0; i < N_USED_SD_MAJORS; i++) { - devfs_unregister_blkdev(SD_MAJOR(i), "sd"); } - sd_registered--; - sd_template.dev_noticed = 0; - return 1; } static void sd_finish() { - int i; - - for (i = 0; i < N_USED_SD_MAJORS; i++) { - blk_dev[SD_MAJOR(i)].queue = sd_find_queue; - add_gendisk(&sd_gendisks[i]); - } - - for (i = 0; i < sd_template.dev_max; ++i) - if (!rscsi_disks[i].capacity && rscsi_disks[i].device) { - sd_init_onedisk(i); - if (!rscsi_disks[i].has_part_table) { - sd_sizes[i << 4] = rscsi_disks[i].capacity; - register_disk(&SD_GENDISK(i), MKDEV_SD(i), - 1<<4, &sd_fops, - rscsi_disks[i].capacity); - rscsi_disks[i].has_part_table = 1; + int midx, didx; + SD_Major *sd_major; + Scsi_Disk *scsi_disk; + /* Everything moved to attach() */ + printk (KERN_DEBUG "sd_finish()\n"); + + for (midx = 0; midx < sd_majors; ++midx) { + sd_major = SD_MAJOR_PTR(midx); + for (didx = 0; didx < SCSI_DISKS_PER_MAJOR; ++didx) { + scsi_disk = SD_DISK_PTR(sd_major, didx); + if (scsi_disk->device && !scsi_disk->capacity) { + if (sd_init_onedisk(midx, didx) == -1) { + scsi_disk->attached = 0; + sd_major->sd_gendisk.nr_real--; + sd_template.nr_dev--; + scsi_disk->device->attached--; + //sd_next--; + continue; + } + + if (!scsi_disk->has_part_table) { + sd_major->sd_sizes[DIDX_TO_MINOR(didx)] = scsi_disk->capacity; + register_disk(&sd_major->sd_gendisk, MDIDX_TO_KDEV(midx,didx), + SCSI_DISK_MAX_PART, &sd_fops, + scsi_disk->capacity); + scsi_disk->has_part_table = 1; + } + /* If our host adapter is capable of scatter-gather, then we increase + * the read-ahead to 128 sectors (64k). If not, we stay to a 8 sectors + * (4k) default. We can only respect this on a per major basis. + */ + if (scsi_disk->device->host->sg_tablesize) + read_ahead[MIDX_TO_MAJOR(midx)] = 128; } } - /* If our host adapter is capable of scatter-gather, then we increase - * the read-ahead to 60 blocks (120 sectors). If not, we use - * a two block (4 sector) read ahead. We can only respect this with the - * granularity of every 16 disks (one device major). - */ - for (i = 0; i < N_USED_SD_MAJORS; i++) { - read_ahead[SD_MAJOR(i)] = - (rscsi_disks[i * SCSI_DISKS_PER_MAJOR].device - && rscsi_disks[i * SCSI_DISKS_PER_MAJOR].device->host->sg_tablesize) - ? 120 /* 120 sector read-ahead */ - : 4; /* 4 sector read-ahead */ } - - return; } static int sd_detect(Scsi_Device * SDp) @@ -1301,62 +1228,56 @@ return 1; } -#define SD_DISK_MAJOR(i) SD_MAJOR((i) >> 4) - static int sd_attach(Scsi_Device * SDp) { - unsigned int devnum; - Scsi_Disk *dpnt; - int i; - char nbuff[6]; + SD_Major *sd_major; + Scsi_Disk *scsi_disk; + struct gendisk *gdp; + + int midx, didx; + char nbuff[8]; + printk (KERN_DEBUG "sd_attach()\n"); if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0; - if (sd_template.nr_dev >= sd_template.dev_max || rscsi_disks == NULL) { - SDp->attached--; - return 1; - } - for (dpnt = rscsi_disks, i = 0; i < sd_template.dev_max; i++, dpnt++) - if (!dpnt->device) - break; - - if (i >= sd_template.dev_max) { - printk(KERN_WARNING "scsi_devices corrupt (sd)," - " nr_dev %d dev_max %d\n", - sd_template.nr_dev, sd_template.dev_max); + if (sd_find_free_slot (SDp, &midx, &didx)) { SDp->attached--; return 1; } - - rscsi_disks[i].device = SDp; - rscsi_disks[i].has_part_table = 0; + + sd_major = SD_MAJOR_PTR(midx); + scsi_disk = SD_DISK_PTR(sd_major, didx); + + scsi_disk->device = SDp; + scsi_disk->has_part_table = 0; + scsi_disk->attached = 1; sd_template.nr_dev++; - SD_GENDISK(i).nr_real++; - devnum = i % SCSI_DISKS_PER_MAJOR; - SD_GENDISK(i).de_arr[devnum] = SDp->de; + + gdp = &sd_major->sd_gendisk; + gdp->nr_real++; + gdp->de_arr[didx] = SDp->de; + if (SDp->removable) - SD_GENDISK(i).flags[devnum] |= GENHD_FL_REMOVABLE; - sd_devname(i, nbuff); + gdp->flags[didx] |= GENHD_FL_REMOVABLE; + sd_devname(MDIDX_TO_KDEV(midx,didx), nbuff); printk("Attached scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n", SDp->removable ? "removable " : "", nbuff, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); - if (SDp->host->hostt->can_do_varyio) { - if (blkdev_varyio[SD_DISK_MAJOR(i)] == NULL) { - blkdev_varyio[SD_DISK_MAJOR(i)] = - sd_varyio + ((i / SCSI_DISKS_PER_MAJOR) >> 8); - } - memset(blkdev_varyio[SD_DISK_MAJOR(i)] + (devnum << 4), 1, 16); - } + if (SDp->host->hostt->can_do_varyio) + memset(sd_major->sd_varyio + DIDX_TO_MINOR(didx), 1, SCSI_DISK_MAX_PART); + + blk_dev[MIDX_TO_MAJOR(midx)].queue = sd_find_queue; + return 0; } -#define DEVICE_BUSY rscsi_disks[target].device->busy -#define ALLOW_REVALIDATE rscsi_disks[target].device->allow_revalidate -#define USAGE rscsi_disks[target].device->access_count -#define CAPACITY rscsi_disks[target].capacity -#define MAYBE_REINIT sd_init_onedisk(target) +#define DEVICE_BUSY scsi_disk->device->busy +#define ALLOW_REVALIDATE scsi_disk->device->allow_revalidate +#define USAGE scsi_disk->device->access_count +#define CAPACITY scsi_disk->capacity +#define MAYBE_REINIT sd_init_onedisk(midx,didx) /* This routine is called to flush all partitions and partition tables * for a changed scsi disk, and then re-read the new partition table. @@ -1368,12 +1289,17 @@ int revalidate_scsidisk(kdev_t dev, int maxusage) { struct gendisk *sdgd; - int target; - int max_p; - int start; - int i; - - target = DEVICE_NR(dev); + SD_Major *sd_major; + Scsi_Disk *scsi_disk; + int midx, didx; + int max_p, part; + int major, minor; + + major = MAJOR(dev); minor = MINOR(dev); + midx = MAJOR_TO_MIDX(major); + sd_major = SD_MAJOR_PTR(midx); + didx = MINOR_TO_DIDX(minor); + scsi_disk = SD_DISK_PTR(sd_major, didx); if (DEVICE_BUSY || (ALLOW_REVALIDATE == 0 && USAGE > maxusage)) { printk("Device busy for revalidation (usage=%d)\n", USAGE); @@ -1381,34 +1307,31 @@ } DEVICE_BUSY = 1; - sdgd = &SD_GENDISK(target); - max_p = sd_gendisk.max_p; - start = target << sd_gendisk.minor_shift; - - for (i = max_p - 1; i >= 0; i--) { - int index = start + i; - invalidate_device(MKDEV_SD_PARTITION(index), 1); - sdgd->part[SD_MINOR_NUMBER(index)].start_sect = 0; - sdgd->part[SD_MINOR_NUMBER(index)].nr_sects = 0; + sdgd = &sd_major->sd_gendisk; + max_p = sdgd->max_p; + minor = DIDX_TO_MINOR(didx); /* equiv to: minor &= ~(SCSI_DISK_MAX_PART-1) */ + + for (part = max_p - 1; part >= 0; --part) { + invalidate_device(MKDEV(major, minor+part), 1); + sdgd->part[minor+part].start_sect = 0; + sdgd->part[minor+part].nr_sects = 0; /* * Reset the blocksize for everything so that we can read * the partition table. Technically we will determine the * correct block size when we revalidate, but we do this just * to make sure that everything remains consistent. */ - sd_blocksizes[index] = 1024; - if (rscsi_disks[target].device->sector_size == 2048) - sd_blocksizes[index] = 2048; + if (scsi_disk->device->sector_size == 2048) + sd_major->sd_blocksizes[minor+part] = 2048; else - sd_blocksizes[index] = 1024; + sd_major->sd_blocksizes[minor+part] = 1024; } #ifdef MAYBE_REINIT MAYBE_REINIT; #endif - grok_partitions(&SD_GENDISK(target), target % SCSI_DISKS_PER_MAJOR, - 1<<4, CAPACITY); + grok_partitions(sdgd, didx, SCSI_DISK_MAX_PART, CAPACITY); DEVICE_BUSY = 0; return 0; @@ -1420,43 +1343,51 @@ } static void sd_detach(Scsi_Device * SDp) { - Scsi_Disk *dpnt; + SD_Major *sd_major; + Scsi_Disk *scsi_disk; + int midx, didx; /* major, disk */ struct gendisk *sdgd; - int i, j; + int part; int max_p; - int start; + int major, minor; - if (rscsi_disks == NULL) + if (sd_majors == 0) return; - for (dpnt = rscsi_disks, i = 0; i < sd_template.dev_max; i++, dpnt++) - if (dpnt->device == SDp) { - - /* If we are disconnecting a disk driver, sync and invalidate - * everything */ - sdgd = &SD_GENDISK(i); - max_p = sd_gendisk.max_p; - start = i << sd_gendisk.minor_shift; - - for (j = max_p - 1; j >= 0; j--) { - int index = start + j; - invalidate_device(MKDEV_SD_PARTITION(index), 1); - sdgd->part[SD_MINOR_NUMBER(index)].start_sect = 0; - sdgd->part[SD_MINOR_NUMBER(index)].nr_sects = 0; - sd_sizes[index] = 0; + for (midx = 0; midx < sd_majors; ++midx) { + sd_major = SD_MAJOR_PTR(midx); + for (didx = 0; didx < SCSI_DISKS_PER_MAJOR; ++didx) { + scsi_disk = SD_DISK_PTR(sd_major, didx); + if (scsi_disk->device == SDp) { + /* If we are disconnecting a disk driver, sync and invalidate + * everything */ + sdgd = &sd_major->sd_gendisk; + major = sdgd->major; + max_p = sdgd->max_p; + minor = DIDX_TO_MINOR(didx); + + for (part = max_p - 1; part >= 0; --part) { + invalidate_device(MKDEV(major,minor+part), 1); + sdgd->part[minor+part].start_sect = 0; + sdgd->part[minor+part].nr_sects = 0; + sd_major->sd_sizes[minor+part] = 0; + } + devfs_register_partitions (sdgd, minor+part, 1); + + /* unregister_disk() */ + scsi_disk->device = NULL; + scsi_disk->has_part_table = 0; + scsi_disk->capacity = 0; + scsi_disk->attached = 0; + SDp->attached--; + sd_template.dev_noticed--; + sd_template.nr_dev--; + sd_major->sd_gendisk.nr_real--; + memset(sd_major->sd_varyio + minor, 0, SCSI_DISK_MAX_PART); + return; } - devfs_register_partitions (sdgd, - SD_MINOR_NUMBER (start), 1); - /* unregister_disk() */ - dpnt->has_part_table = 0; - dpnt->device = NULL; - dpnt->capacity = 0; - SDp->attached--; - sd_template.dev_noticed--; - sd_template.nr_dev--; - SD_GENDISK(i).nr_real--; - return; } + } return; } @@ -1468,35 +1399,10 @@ static void __exit exit_sd(void) { - int i; - scsi_unregister_module(MODULE_SCSI_DEV, &sd_template); - 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(sd_hardsizes); - kfree(sd_varyio); - for (i = 0; i < N_USED_SD_MAJORS; i++) { - kfree(sd_gendisks[i].de_arr); - kfree(sd_gendisks[i].flags); - kfree(sd_gendisks[i].part); - } - } - for (i = 0; i < N_USED_SD_MAJORS; i++) { - del_gendisk(&sd_gendisks[i]); - blksize_size[SD_MAJOR(i)] = NULL; - hardsect_size[SD_MAJOR(i)] = NULL; - read_ahead[SD_MAJOR(i)] = 0; - } - sd_template.dev_max = 0; - if (sd_gendisks != NULL) /* kfree tests for 0, but leave explicit */ - kfree(sd_gendisks); + sd_deallocate_all (); } module_init(init_sd); diff -uNr linux-2.4.18.nohdstat/drivers/scsi/sd.h linux-2.4.18.S18.scsimany/drivers/scsi/sd.h --- linux-2.4.18.nohdstat/drivers/scsi/sd.h Sun Jul 14 17:32:35 2002 +++ linux-2.4.18.S18.scsimany/drivers/scsi/sd.h Fri Jul 26 02:42:27 2002 @@ -15,23 +15,13 @@ $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/sd.h,v 1.1 1992/07/24 06:27:38 root Exp root $ */ -#ifndef _SCSI_H #include "scsi.h" -#endif - -#ifndef _GENDISK_H #include -#endif -typedef struct scsi_disk { - unsigned capacity; /* size in blocks */ - Scsi_Device *device; - unsigned char ready; /* flag ready for FLOPTICAL */ - unsigned char write_prot; /* flag write_protect for rmvable dev */ - unsigned char sector_bit_size; /* sector_size = 2 to the bit size power */ - unsigned char sector_bit_shift; /* power of 2 sectors per FS block */ - unsigned has_part_table:1; /* has partition table */ -} Scsi_Disk; +#define SCSI_DISK_PART_BITS 4 +#define SCSI_DISK_MAX_PART (1U<, 7/2002 + * License: GNU GPL v2 + */ +/* 2002-07-14: (sd_many-2) + * Initial write. + * + * 2002-07-15: (sd_many-3) + * Fixes + * Fix dynamic block major allocation to work with + * non-devfs systems. + * + * 2002-07-17: (sd_many-4) + * Reversed major mapping array: + * We now map majors to an index in our ptr array. + * Fix /proc/partitions by calling sd_devname() via gendisk + * + * TODO: - Check locking issues. + * - More intelligent reuse of sd slots(?) + * - Remove debug printks + * + * 2002-07-25: (sd_many-5) + * - Added the officially assigned SCSI majors 9--15. + * (Thanks to Pete Zaitvec for telling!) + * - Made maximum number of SCSI majors a config option + * - SysRq preference for all SCSI disk majors (Pete ...) + */ + + +#include "sd_dynalloc.h" +#include + +#define SD_REUSE_SLOTS 1 +#define SD_DYN_DEBUG 1 + +# define SDD_PRINTK(ARGS...) printk(KERN_WARNING "sd: " ARGS) +#ifdef SD_DYN_DEBUG +# define SDD_DPRINTK(ARGS...) printk(KERN_DEBUG "sd: " ARGS) +#else +# define SDD_DPRINTK(ARGS...) +#endif + +/* Locking: + * We protect the following variables by a spinlock: + * sd_majors, sd_per_major_ptrs, sd_major_to_midx, next_sd + * Actually, we try to only use the locks for writing. + * This should be possible, as we do build and fill + * structs before we link them into a list and we never + * remove any majors. + * So we only need to protect against two CPUs trying to + * change the structures. + */ + +rwlock_t sd_dyn_lock = RW_LOCK_UNLOCKED; + +static int sd_majors; +/* Index into the last sd_major struct for next free sd */ +static int sd_next = SCSI_DISKS_PER_MAJOR; + +/* Maps majors to indices into sd_major_ptrs */ +unsigned char sd_major_to_midx[MAJORS]; +/* List of pointers to SD_Major structs */ +struct sd_per_major *sd_major_ptrs[MAX_SCSI_DYN_MAJORS]; + +int sd_midx_to_major (const int midx) +{ + if (midx < 0 || midx >= sd_majors) + return SD_NO_MAJOR; + return SD_MAJOR_PTR(midx)->sd_gendisk.major; +} + +/* Fill in defaults (except 0) */ +static void sd_fill_defaults (SD_Major *sd_major) +{ + int i; + /* per part */ + for (i = 0; i < MINORS; ++i) { + sd_major->sd_blocksizes[i] = 1024; + sd_major->sd_max_sectors[i] = MAX_SEGMENTS*8; + sd_major->sd_hardsizes[i] = 512; + } +} + +/* Global per major arrays :-O need to be filled in */ +static void sd_set_major_arrays (SD_Major *sd_major) +{ + const int major = sd_major->sd_gendisk.major; + blksize_size[major] = sd_major->sd_blocksizes; + hardsect_size[major] = sd_major->sd_hardsizes; + max_sectors[major] = sd_major->sd_max_sectors; + blkdev_varyio[major] = sd_major->sd_varyio; + /* To be set to a higher value in attach() if HBA support s-g */ + read_ahead[major] = 8; +} + +static void sd_gendisk_defaults (struct gendisk *gdp) +{ + gdp->major_name = "sd"; + gdp->minor_shift = SCSI_DISK_PART_BITS; //? + gdp->max_p = SCSI_DISK_MAX_PART; + gdp->fops = &sd_fops; + gdp->devname = sd_devname; +} + +/* Fill in gendisk */ +static void sd_fill_in_gendisk (SD_Major *sd_major) +{ + struct gendisk * const gdp = &sd_major->sd_gendisk; + sd_gendisk_defaults (gdp); + gdp->de_arr = sd_major->de_arr; + gdp->flags = sd_major->flags; + gdp->part = sd_major->sd_hds; + gdp->sizes = sd_major->sd_sizes; + gdp->nr_real= 0; + gdp->real_devices = (void*) sd_major->disks; +} + +#ifndef CONFIG_DEVFS_FS +#define FIRST_MAJOR 143 +static int sd_find_major (void) +{ + /* The get_blkfops() has the side-effect of triggering kmod + * on blockdevs. This makes it safe not to accidently + * take the major of sb. else. + * We try to avoid conflicts by allocating + * 8, 65--71, 128--135 ( 16, officially assigned to sd) + * 144--254 (111, not yet assigned) + * 72--127 ( 56, assigned to other devices) + * 136--143 ( 8, assigned to Mylex DAC960) + * 12-- 64 ( 53, assigned to other devices) + * Summary: 16 safe, 127 almost safe (poss. future confl.), + * 244 theoretical maximum, IOW 3904 disks. + */ + int maj = FIRST_MAJOR; + while (++maj < 255) /* 255 is RESERVED */ + if (!get_blkfops(maj)) + return maj; + maj = SCSI_DISK7_MAJOR; /* The search goes on */ + while (++maj < SCSI_DISK10_MAJOR) + if (!get_blkfops(maj)) + return maj; + maj = SCSI_DISK17_MAJOR; + while (++maj < FIRST_MAJOR) + if (!get_blkfops(maj)) + return maj; + maj = 11; + while (++maj < SCSI_DISK1_MAJOR) + if (!get_blkfops(maj)) + return maj; + return SD_NO_MAJOR; +} +#endif + +extern request_queue_t *sd_find_queue(kdev_t dev); +/* We should already have the lock in write mode when entering */ +int sd_alloc_major (void) +{ + int major; + SD_Major *sd_major; + + /* Initialize sd_major_to_midx array */ + if (sd_majors == 0) + memset (sd_major_to_midx, SD_NO_MIDX, MAJORS); + + if (sd_majors >= MAX_SCSI_DYN_MAJORS) + return SD_NO_MAJOR; + if (!sd_majors) + major = SCSI_DISK0_MAJOR; + else if (sd_majors < 8) + major = SCSI_DISK1_MAJOR-1+sd_majors; + else if (sd_majors < 16) + major = SCSI_DISK10_MAJOR-8+sd_majors; + else { +#ifdef CONFIG_DEVFS_FS + major = devfs_alloc_major(DEVFS_SPECIAL_BLK); +#else + major = sd_find_major (); +#endif + if (major == SD_NO_MAJOR) { + SDD_PRINTK("alloc_major: could not get major\n"); + return major; + } + } + /* Now perform memory allocations */ + sd_major = kmalloc (sizeof (*sd_major), GFP_ATOMIC); + if (!sd_major) { + SDD_PRINTK("alloc_major: could not allocate sd_major structure\n"); + goto dealloc_major; + } + memset (sd_major, 0, sizeof (*sd_major)); + + sd_major->sd_gendisk.major = major; + + if (devfs_register_blkdev(major, "sd", &sd_fops)) { + SDD_PRINTK("alloc_major: could not register major %i\n", + major); + goto dealloc_sd_major; + } + + /* Now, nothing can fail ... except the programmer, of course */ + sd_fill_defaults (sd_major); + sd_set_major_arrays (sd_major); + sd_fill_in_gendisk (sd_major); + blk_dev[major].queue = sd_find_queue; + sd_major_ptrs[sd_majors] = sd_major; + sd_major_to_midx[major] = sd_majors++; + sd_next = 0; + /* FIXME: used to be done at finish time, should be OK here. KG. */ + add_gendisk(&sd_major->sd_gendisk); + SDD_PRINTK("allocated major %i\n", major); + return major; + + dealloc_sd_major: + kfree (sd_major); + + dealloc_major: +#ifdef CONFIG_DEVFS_FS + if (sd_majors >= 16) + devfs_dealloc_major(DEVFS_SPECIAL_BLK, major); +#endif + return SD_NO_MAJOR; +} + +/* Deallocate one major */ +void sd_dealloc_major (const int midx) +{ + SD_Major *sd_major = SD_MAJOR_PTR(midx); + const int major = MIDX_TO_MAJOR(midx); + del_gendisk(&sd_major->sd_gendisk); + devfs_unregister_blkdev(major, "sd"); + sd_major_ptrs[midx] = NULL; + sd_major_to_midx[major] = SD_NO_MIDX; + read_ahead[major] = 0; + blksize_size[major] = NULL; + hardsect_size[major] = NULL; + max_sectors[major] = NULL; + blkdev_varyio[major] = NULL; + blk_dev[major].queue = NULL; +#ifdef CONFIG_DEVFS_FS + if (midx >= 16) + devfs_dealloc_major(DEVFS_SPECIAL_BLK, major); +#endif + kfree (sd_major); + SDD_PRINTK("deallocated major %i\n", major); +} + +/* Deallocate all majors */ +void sd_deallocate_all (void) +{ + while (sd_majors--) + sd_dealloc_major (sd_majors); +} + +/* Currently, sd_find_free_slot() does not use SDp. + * One could think of clever heuristics, that attaches a detached + * disk at the same slot again. KG. */ + +/* Find a free slot to attach a SCSI disk */ +int sd_find_free_slot (Scsi_Device *SDp, int *midx, int *didx) +{ + SD_Major *sd_major; + Scsi_Disk *scsi_disk; + SDD_DPRINTK("find_free_slot ..."); + SD_LOCK_W; +#ifdef SD_REUSE_SLOTS + for (*midx = 0; *midx < sd_majors; ++*midx) { + sd_major = SD_MAJOR_PTR(*midx); + for (*didx = 0; *didx < SCSI_DISKS_PER_MAJOR; ++*didx) { + scsi_disk = SD_DISK_PTR(sd_major, *didx); + if (!scsi_disk->attached) + goto found; + } + } +#else + if (sd_next < SCSI_DISKS_PER_MAJOR) { + *midx = sd_majors-1; + *didx = sd_next; + goto found; + } +#endif + /* OK, we need to allocate a new major */ + if (sd_alloc_major () == -1) { + SD_UNLOCK_W; + return SD_NO_MAJOR; + } + *midx = sd_majors-1; + *didx = sd_next; /* 0 */ + + found: + SDD_DPRINTK("... found %02x:%02x\n", + MIDX_TO_MAJOR(*midx), DIDX_TO_MINOR(*didx)); + sd_major = SD_MAJOR_PTR(*midx); + scsi_disk = SD_DISK_PTR(sd_major, *didx); + ++sd_next; + SD_UNLOCK_W; + return 0; +} diff -uNr linux-2.4.18.nohdstat/drivers/scsi/sd_dynalloc.h linux-2.4.18.S18.scsimany/drivers/scsi/sd_dynalloc.h --- linux-2.4.18.nohdstat/drivers/scsi/sd_dynalloc.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.18.S18.scsimany/drivers/scsi/sd_dynalloc.h Fri Jul 26 03:43:43 2002 @@ -0,0 +1,79 @@ +/* sd_dynalloc.h + * dynamically allocated structures for the sd driver + * (c) Kurt Garloff , 7/2002 + * License: GNU GPL v2 + */ + +#ifndef _SD_DYNALLOC_H +#define _SD_DYNALLOC_H + +#include +#include "sd.h" + +/* Should default to the officially assigned 16 */ +#define MAX_SCSI_DYN_MAJORS CONFIG_SD_MAX_MAJORS +#define MINORS (1U<>SCSI_DISK_PART_BITS) + +#define DISKNO_TO_MIDX(i) ((i)>>SCSI_DISK_DISK_SHIFT) +#define DISKNO_TO_DIDX(i) ((i) & (SCSI_DISKS_PER_MAJOR-1)) +#define DISKNO_TO_MAJOR(i) (MIDX_TO_MAJOR(DISKNO_TO_MIDX(i))) +#define DISKNO_TO_MINOR(i) (DIDX_TO_MINOR(DISKNO_TO_DIDX(i))) + +#define MDIDX_TO_DISKNO(mi,di) (((mi)<>SCSI_DISK_PART_BITS) +#define KDEV_TO_DISKNO(dev) MAJMIN_TO_DISKNO(MAJOR(dev),MINOR(dev)) + +#define MDIDX_TO_KDEV(mi,di) (MKDEV(MIDX_TO_MAJOR(mi),DIDX_TO_MINOR(di))) + + +#define SD_MAJOR_PTR(i) (sd_major_ptrs[i]) +#define SD_DISK_PTR(sdm,i) (&((sdm)->disks[i])) + +/* It would have made more sense to have per_partition structures, + * embedded into per_disk structures embedded into per_major + * structures. However, this would not have fit into the gendisk + * scheme. Therefore have these arrays in per_major struct */ + +typedef struct sd_per_major { + int sd_sizes[MINORS]; /* size of partitions */ + int sd_blocksizes[MINORS]; /* fs block size */ + int sd_hardsizes[MINORS]; /* hw block size */ + int sd_max_sectors[MINORS]; /* max request size in sectors */ + char sd_varyio[MINORS]; + + Scsi_Disk disks[SCSI_DISKS_PER_MAJOR]; + devfs_handle_t de_arr[SCSI_DISKS_PER_MAJOR]; + char flags[SCSI_DISKS_PER_MAJOR]; + struct gendisk sd_gendisk; + struct hd_struct sd_hds[MINORS]; +} SD_Major; + +/* The dynamically allocated majors */ +extern int sd_majors; +extern unsigned char sd_major_to_midx[MAJORS]; +extern struct sd_per_major *sd_major_ptrs[MAX_SCSI_DYN_MAJORS]; + +#define SD_NO_MIDX 255 +#define SD_NO_MAJOR -1 + +extern rwlock_t sd_dyn_lock; +#define SD_LOCK_W write_lock(&sd_dyn_lock) +#define SD_UNLOCK_W write_unlock(&sd_dyn_lock) + +int sd_midx_to_major (const int midex); +int sd_alloc_major (void); +void sd_dealloc_major (const int idx); +void sd_deallocate_all (void); +int sd_find_free_slot (Scsi_Device *SDp, int *midx, int *didx); + + +#endif /* _SD_DYNALLOC_H */ diff -uNr linux-2.4.18.nohdstat/fs/partitions/check.c linux-2.4.18.S18.scsimany/fs/partitions/check.c --- linux-2.4.18.nohdstat/fs/partitions/check.c Wed Jun 12 11:37:11 2002 +++ linux-2.4.18.S18.scsimany/fs/partitions/check.c Wed Jul 17 14:52:16 2002 @@ -107,6 +107,16 @@ return buf + pos; } + /* The device driver can provide its own naming */ + if (hd->devname) { + kdev_t dev = MKDEV(hd->major, minor); + *buf = 0; + if ((hd->devname)(dev, buf)) + printk (KERN_ERR "disk_name():devname() failed!\n"); + else + return buf; + } + #ifdef CONFIG_ARCH_S390 if (genhd_dasd_name && genhd_dasd_name (buf, unit, part, hd) == 0) @@ -143,16 +153,9 @@ sprintf(buf, "%s%d", maj, unit); return buf; } - if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) { - unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16; - if (unit+'a' > 'z') { - unit -= 26; - sprintf(buf, "sd%c%c", 'a' + unit / 26, 'a' + unit % 26); - if (part) - sprintf(buf + 4, "%d", part); - return buf; - } - } + + /* SCSI uses (*devname)() */ + if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) { int ctlr = hd->major - COMPAQ_SMART2_MAJOR; if (part == 0) diff -uNr linux-2.4.18.nohdstat/include/linux/blk.h linux-2.4.18.S18.scsimany/include/linux/blk.h --- linux-2.4.18.nohdstat/include/linux/blk.h Wed Jul 17 13:17:39 2002 +++ linux-2.4.18.S18.scsimany/include/linux/blk.h Fri Jul 26 02:33:11 2002 @@ -143,7 +143,10 @@ #define DEVICE_NAME "scsidisk" #define TIMEOUT_VALUE (2*HZ) -#define DEVICE_NR(device) (((MAJOR(device) & SD_MAJOR_MASK) << (8 - 4)) + (MINOR(device) >> 4)) +/* The major calculation part duplicates SD_MAJOR_INDEX verbatim. */ +#define DEVICE_NR(device) \ + (( ( ((MAJOR(device) & 0x80) >> 4) + (MAJOR(device) & 7) ) << (8 - 4)) + \ + (MINOR(device) >> 4)) /* Kludge to use the same number for both char and block major numbers */ #elif (MAJOR_NR == MD_MAJOR) && defined(MD_DRIVER) diff -uNr linux-2.4.18.nohdstat/include/linux/fs.h linux-2.4.18.S18.scsimany/include/linux/fs.h --- linux-2.4.18.nohdstat/include/linux/fs.h Mon Jul 15 15:47:16 2002 +++ linux-2.4.18.S18.scsimany/include/linux/fs.h Fri Jul 26 02:32:50 2002 @@ -1168,6 +1168,7 @@ enum {BDEV_FILE, BDEV_SWAP, BDEV_FS, BDEV_RAW}; extern int register_blkdev(unsigned int, const char *, struct block_device_operations *); extern int unregister_blkdev(unsigned int, const char *); +extern const struct block_device_operations * get_blkfops(unsigned int major); extern struct block_device *bdget(dev_t); extern int bd_acquire(struct inode *inode); extern void bd_forget(struct inode *inode); diff -uNr linux-2.4.18.nohdstat/include/linux/genhd.h linux-2.4.18.S18.scsimany/include/linux/genhd.h --- linux-2.4.18.nohdstat/include/linux/genhd.h Sun Jul 14 17:21:24 2002 +++ linux-2.4.18.S18.scsimany/include/linux/genhd.h Fri Jul 26 02:32:50 2002 @@ -101,6 +101,7 @@ devfs_handle_t *de_arr; /* one per physical disc */ char *flags; /* one per physical disc */ + int (*devname) (kdev_t dev, char *buffer); }; /* drivers/block/genhd.c */ diff -uNr linux-2.4.18.nohdstat/include/linux/major.h linux-2.4.18.S18.scsimany/include/linux/major.h --- linux-2.4.18.nohdstat/include/linux/major.h Wed Jun 12 11:37:13 2002 +++ linux-2.4.18.S18.scsimany/include/linux/major.h Fri Jul 26 02:32:42 2002 @@ -111,16 +111,25 @@ #define COMPAQ_CISS_MAJOR 104 #define COMPAQ_CISS_MAJOR1 105 -#define COMPAQ_CISS_MAJOR2 106 -#define COMPAQ_CISS_MAJOR3 107 -#define COMPAQ_CISS_MAJOR4 108 -#define COMPAQ_CISS_MAJOR5 109 -#define COMPAQ_CISS_MAJOR6 110 -#define COMPAQ_CISS_MAJOR7 111 +#define COMPAQ_CISS_MAJOR2 106 +#define COMPAQ_CISS_MAJOR3 107 +#define COMPAQ_CISS_MAJOR4 108 +#define COMPAQ_CISS_MAJOR5 109 +#define COMPAQ_CISS_MAJOR6 110 +#define COMPAQ_CISS_MAJOR7 111 #define ATARAID_MAJOR 114 -#define SCSI_CHANGER_MAJOR 86 +#define SCSI_CHANGER_MAJOR 86 + +#define SCSI_DISK10_MAJOR 128 +#define SCSI_DISK11_MAJOR 129 +#define SCSI_DISK12_MAJOR 130 +#define SCSI_DISK13_MAJOR 131 +#define SCSI_DISK14_MAJOR 132 +#define SCSI_DISK15_MAJOR 133 +#define SCSI_DISK16_MAJOR 134 +#define SCSI_DISK17_MAJOR 135 #define DASD_MAJOR 94 /* Official assignations from Peter */ @@ -173,7 +182,8 @@ */ #define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ - ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR)) + ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR) || \ + ((M) >= SCSI_DISK10_MAJOR && (M) <= SCSI_DISK17_MAJOR)) #define SCSI_BLK_MAJOR(M) \ (SCSI_DISK_MAJOR(M) \ diff -uNr linux-2.4.18.nohdstat/kernel/ksyms.c linux-2.4.18.S18.scsimany/kernel/ksyms.c --- linux-2.4.18.nohdstat/kernel/ksyms.c Wed Jun 12 11:37:15 2002 +++ linux-2.4.18.S18.scsimany/kernel/ksyms.c Tue Jul 16 13:25:07 2002 @@ -328,6 +328,7 @@ EXPORT_SYMBOL(unregister_chrdev); EXPORT_SYMBOL(register_blkdev); EXPORT_SYMBOL(unregister_blkdev); +EXPORT_SYMBOL(get_blkfops); EXPORT_SYMBOL(tty_register_driver); EXPORT_SYMBOL(tty_unregister_driver); EXPORT_SYMBOL(tty_std_termios);