Commit 7bfe7426 authored by Linus Torvalds's avatar Linus Torvalds

Manual merge for problems between Al Viro's blocksize removal and

Douglas Gilbert's SCSI cleanups
parents 7831a09f 0e46579e
...@@ -5,29 +5,28 @@ ...@@ -5,29 +5,28 @@
* Linux scsi disk driver * Linux scsi disk driver
* Initial versions: Drew Eckhardt * Initial versions: Drew Eckhardt
* Subsequent revisions: Eric Youngdale * Subsequent revisions: Eric Youngdale
* Modification history:
* - Drew Eckhardt <drew@colorado.edu> original
* - Eric Youngdale <eric@andante.org> add scatter-gather, multiple
* outstanding request, and other enhancements.
* Support loadable low-level scsi drivers.
* - Jirka Hanika <geo@ff.cuni.cz> support more scsi disks using
* eight major numbers.
* - Richard Gooch <rgooch@atnf.csiro.au> support devfs.
* - Torben Mathiasen <tmm@image.dk> Resource allocation fixes in
* sd_init and cleanups.
* - Alex Davis <letmein@erols.com> Fix problem where partition info
* not being read in sd_open. Fix problem where removable media
* could be ejected after sd_open.
* - Douglas Gilbert <dgilbert@interlog.com> cleanup for lk 2.5 series
* *
* <drew@colorado.edu> * Logging policy (needs CONFIG_SCSI_LOGGING defined):
* * - setting up transfer: SCSI_LOG_HLQUEUE levels 1 and 2
* Modified by Eric Youngdale ericy@andante.org to * - end of transfer (bh + scsi_lib): SCSI_LOG_HLCOMPLETE level 1
* add scatter-gather, multiple outstanding request, and other * - entering sd_ioctl: SCSI_LOG_IOCTL level 1
* enhancements. * - entering other commands: SCSI_LOG_HLQUEUE level 3
* * Note: when the logging level is set by the user, it must be greater
* Modified by Eric Youngdale eric@andante.org to support loadable * than the level indicated above to trigger output.
* low-level scsi drivers.
*
* Modified by Jirka Hanika geo@ff.cuni.cz to support more
* scsi disks using eight major numbers.
*
* Modified by Richard Gooch rgooch@atnf.csiro.au to support devfs.
*
* Modified by Torben Mathiasen tmm@image.dk
* Resource allocation fixes in sd_init and cleanups.
*
* Modified by Alex Davis <letmein@erols.com>
* Fix problem where partition info not being read in sd_open.
*
* Modified by Alex Davis <letmein@erols.com>
* Fix problem where removable media could be ejected after sd_open.
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -50,6 +49,7 @@ ...@@ -50,6 +49,7 @@
#include <asm/io.h> #include <asm/io.h>
#define MAJOR_NR SCSI_DISK0_MAJOR #define MAJOR_NR SCSI_DISK0_MAJOR
#define LOCAL_END_REQUEST
#include <linux/blk.h> #include <linux/blk.h>
#include <linux/blkpg.h> #include <linux/blkpg.h>
#include "scsi.h" #include "scsi.h"
...@@ -61,6 +61,8 @@ ...@@ -61,6 +61,8 @@
#include <linux/genhd.h> #include <linux/genhd.h>
static char sd_version_str[] = "Version: 2.0.3 (20020417)";
#define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i)) #define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i))
#define SCSI_DISKS_PER_MAJOR 16 #define SCSI_DISKS_PER_MAJOR 16
...@@ -79,16 +81,21 @@ ...@@ -79,16 +81,21 @@
#define SD_TIMEOUT (30 * HZ) #define SD_TIMEOUT (30 * HZ)
#define SD_MOD_TIMEOUT (75 * HZ) #define SD_MOD_TIMEOUT (75 * HZ)
#define SD_DSK_ARR_LUMP 6 /* amount to over allocate sd_dsk_arr by */
struct hd_struct *sd; struct hd_struct *sd;
static Scsi_Disk *rscsi_disks; static Scsi_Disk ** sd_dsk_arr;
static rwlock_t sd_dsk_arr_lock = RW_LOCK_UNLOCKED;
static int *sd_sizes; static int *sd_sizes;
static int *sd_max_sectors; static int *sd_max_sectors;
static int check_scsidisk_media_change(kdev_t); static int check_scsidisk_media_change(kdev_t);
static int fop_revalidate_scsidisk(kdev_t); static int fop_revalidate_scsidisk(kdev_t);
static int sd_init_onedisk(int); static int sd_init_onedisk(Scsi_Disk * sdkp, int dsk_nr);
static int sd_init(void); static int sd_init(void);
static void sd_finish(void); static void sd_finish(void);
...@@ -117,36 +124,81 @@ static struct Scsi_Device_Template sd_template = { ...@@ -117,36 +124,81 @@ static struct Scsi_Device_Template sd_template = {
init_command:sd_init_command, init_command:sd_init_command,
}; };
static void rw_intr(Scsi_Cmnd * SCpnt); static void sd_rw_intr(Scsi_Cmnd * SCpnt);
static Scsi_Disk * sd_get_sdisk(int index);
#if defined(CONFIG_PPC) #if defined(CONFIG_PPC)
/* /**
* Moved from arch/ppc/pmac_setup.c. This is where it really belongs. * sd_find_target - find kdev_t of first scsi disk that matches
*/ * given host and scsi_id.
* @host: Scsi_Host object pointer that owns scsi device of interest
* @scsi_id: scsi (target) id number of device of interest
*
* Returns kdev_t of first scsi device that matches arguments or
* NODEV of no match.
*
* Notes: Looks like a hack, should scan for <host,channel,id,lin>
* tuple.
* [Architectural dependency: ppc only.] Moved here from
* arch/ppc/pmac_setup.c.
**/
kdev_t __init kdev_t __init
sd_find_target(void *host, int tgt) sd_find_target(void *hp, int scsi_id)
{ {
Scsi_Disk *dp; Scsi_Disk *sdkp;
int i; Scsi_Device *sdp;
for (dp = rscsi_disks, i = 0; i < sd_template.dev_max; ++i, ++dp) Scsi_Host *shp = hp;
if (dp->device != NULL && dp->device->host == host int dsk_nr;
&& dp->device->id == tgt) unsigned long iflags;
return MKDEV_SD(i);
return NODEV; SCSI_LOG_HLQUEUE(3, printk("sd_find_target: host_nr=%d, "
"scsi_id=%d\n", shp->host_no, scsi_id));
read_lock_irqsave(&sd_dsk_arr_lock, iflags);
for (dsk_nr = 0; dsk_nr < sd_template.dev_max; ++dsk_nr) {
if (NULL == (sdkp = sd_dsk_arr[dsk_nr]))
continue;
sdp = sdkp->device;
if (sdp && (sdp->host == shp) && (sdp->id == scsi_id)) {
read_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
return MKDEV_SD(k);
}
}
read_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
return NODEV;
} }
#endif #endif
static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) /**
* sd_ioctl - process an ioctl
* @inode: only i_rdev member may be used
* @filp: only f_mode and f_flags may be used
* @cmd: ioctl command number
* @arg: this is third argument given to ioctl(2) system call.
* Often contains a pointer.
*
* Returns 0 if successful (some ioctls return postive numbers on
* success as well). Returns a negated errno value in case of error.
*
* Note: most ioctls are forward onto the block subsystem or further
* down in the scsi subsytem.
**/
static int sd_ioctl(struct inode * inode, struct file * filp,
unsigned int cmd, unsigned long arg)
{ {
kdev_t dev = inode->i_rdev; kdev_t dev = inode->i_rdev;
Scsi_Disk * sdkp;
struct Scsi_Host * host; struct Scsi_Host * host;
Scsi_Device * SDev; Scsi_Device * sdp;
int diskinfo[4]; int diskinfo[4];
int dsk_nr = DEVICE_NR(dev);
SDev = rscsi_disks[DEVICE_NR(dev)].device; SCSI_LOG_IOCTL(1, printk("sd_ioctl: dsk_nr=%d, cmd=0x%x\n",
if (!SDev) dsk_nr, cmd));
sdkp = sd_get_sdisk(dsk_nr);
if ((NULL == sdkp) || (NULL == (sdp = sdkp->device)))
return -ENODEV; return -ENODEV;
/* /*
* If we are in the middle of error recovery, don't let anyone * If we are in the middle of error recovery, don't let anyone
* else try and use this device. Also, if error recovery fails, it * else try and use this device. Also, if error recovery fails, it
...@@ -154,10 +206,8 @@ static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, ...@@ -154,10 +206,8 @@ static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd,
* access to the device is prohibited. * access to the device is prohibited.
*/ */
if( !scsi_block_when_processing_errors(SDev) ) if( !scsi_block_when_processing_errors(sdp) )
{
return -ENODEV; return -ENODEV;
}
switch (cmd) switch (cmd)
{ {
...@@ -167,58 +217,59 @@ static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, ...@@ -167,58 +217,59 @@ static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd,
if(!loc) if(!loc)
return -EINVAL; return -EINVAL;
host = rscsi_disks[DEVICE_NR(dev)].device->host; host = sdp->host;
/* default to most commonly used values */ /* default to most commonly used values */
diskinfo[0] = 0x40; diskinfo[0] = 0x40;
diskinfo[1] = 0x20; diskinfo[1] = 0x20;
diskinfo[2] = rscsi_disks[DEVICE_NR(dev)].capacity >> 11; diskinfo[2] = sdkp->capacity >> 11;
/* override with calculated, extended default, or driver values */ /* override with calculated, extended default,
or driver values */
if(host->hostt->bios_param != NULL) if(host->hostt->bios_param != NULL)
host->hostt->bios_param(&rscsi_disks[DEVICE_NR(dev)], host->hostt->bios_param(sdkp, dev,
dev, &diskinfo[0]);
&diskinfo[0]); else
else scsicam_bios_param(&rscsi_disks[DEVICE_NR(dev)], scsicam_bios_param(sdkp, dev, &diskinfo[0]);
dev, &diskinfo[0]);
if (put_user(diskinfo[0], &loc->heads) || if (put_user(diskinfo[0], &loc->heads) ||
put_user(diskinfo[1], &loc->sectors) || put_user(diskinfo[1], &loc->sectors) ||
put_user(diskinfo[2], &loc->cylinders) || put_user(diskinfo[2], &loc->cylinders) ||
put_user((unsigned) get_start_sect(inode->i_rdev), put_user((unsigned)
get_start_sect(inode->i_rdev),
(unsigned long *) &loc->start)) (unsigned long *) &loc->start))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
case HDIO_GETGEO_BIG: case HDIO_GETGEO_BIG:
{ {
struct hd_big_geometry *loc = (struct hd_big_geometry *) arg; struct hd_big_geometry *loc =
(struct hd_big_geometry *) arg;
if(!loc) if(!loc)
return -EINVAL; return -EINVAL;
host = sdp->host;
host = rscsi_disks[DEVICE_NR(dev)].device->host;
/* default to most commonly used values */ /* default to most commonly used values */
diskinfo[0] = 0x40; diskinfo[0] = 0x40;
diskinfo[1] = 0x20; diskinfo[1] = 0x20;
diskinfo[2] = rscsi_disks[DEVICE_NR(dev)].capacity >> 11; diskinfo[2] = sdkp->capacity >> 11;
/* override with calculated, extended default, or driver values */ /* override with calculated, extended default,
or driver values */
if(host->hostt->bios_param != NULL) if(host->hostt->bios_param != NULL)
host->hostt->bios_param(&rscsi_disks[DEVICE_NR(dev)], host->hostt->bios_param(sdkp, dev,
dev, &diskinfo[0]);
&diskinfo[0]); else
else scsicam_bios_param(&rscsi_disks[DEVICE_NR(dev)], scsicam_bios_param(sdkp, dev, &diskinfo[0]);
dev, &diskinfo[0]);
if (put_user(diskinfo[0], &loc->heads) || if (put_user(diskinfo[0], &loc->heads) ||
put_user(diskinfo[1], &loc->sectors) || put_user(diskinfo[1], &loc->sectors) ||
put_user(diskinfo[2], (unsigned int *) &loc->cylinders) || put_user(diskinfo[2],
put_user((unsigned)get_start_sect(inode->i_rdev), (unsigned int *) &loc->cylinders) ||
put_user((unsigned)
get_start_sect(inode->i_rdev),
(unsigned long *)&loc->start)) (unsigned long *)&loc->start))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -242,15 +293,14 @@ static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, ...@@ -242,15 +293,14 @@ static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd,
return revalidate_scsidisk(dev, 1); return revalidate_scsidisk(dev, 1);
default: default:
return scsi_ioctl(rscsi_disks[DEVICE_NR(dev)].device, return scsi_ioctl(sdp, cmd, (void *) arg);
cmd, (void *) arg);
} }
} }
static void sd_devname(unsigned int disknum, char *buffer) static void sd_dskname(unsigned int dsk_nr, char *buffer)
{ {
if (disknum < 26) if (dsk_nr < 26)
sprintf(buffer, "sd%c", 'a' + disknum); sprintf(buffer, "sd%c", 'a' + dsk_nr);
else { else {
unsigned int min1; unsigned int min1;
unsigned int min2; unsigned int min2;
...@@ -258,67 +308,88 @@ static void sd_devname(unsigned int disknum, char *buffer) ...@@ -258,67 +308,88 @@ static void sd_devname(unsigned int disknum, char *buffer)
* For larger numbers of disks, we need to go to a new * For larger numbers of disks, we need to go to a new
* naming scheme. * naming scheme.
*/ */
min1 = disknum / 26; min1 = dsk_nr / 26;
min2 = disknum % 26; min2 = dsk_nr % 26;
sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2); sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2);
} }
} }
/**
* sd_find_queue - yields queue associated with device
* @dev: kernel device descriptor (kdev_t)
*
* Returns NULL if no match, otherwise returns pointer to associated
* request queue.
*
* Note: this function is invoked (often) from the block subsystem
* and should not wait on anything (sd_get_sdisk() does have a read
* spinlock).
**/
static request_queue_t *sd_find_queue(kdev_t dev) static request_queue_t *sd_find_queue(kdev_t dev)
{ {
Scsi_Disk *dpnt; Scsi_Disk *sdkp;
int target; int dsk_nr = DEVICE_NR(dev);
target = DEVICE_NR(dev);
dpnt = &rscsi_disks[target]; sdkp = sd_get_sdisk(dsk_nr);
if (!dpnt) if (sdkp && sdkp->device)
return &sdkp->device->request_queue;
else
return NULL; /* No such device */ return NULL; /* No such device */
return &dpnt->device->request_queue;
} }
/**
* sd_init_command - build a scsi (read or write) command from
* information in the request structure.
* @SCpnt: pointer to mid-level's per scsi command structure that
* contains request and into which the scsi command is written
*
* Returns 1 if successful and 0 if error (or cannot be done now).
**/
static int sd_init_command(Scsi_Cmnd * SCpnt) static int sd_init_command(Scsi_Cmnd * SCpnt)
{ {
int dev, devm, block, this_count; int dsk_nr, part_nr, block, this_count;
Scsi_Disk *dpnt; Scsi_Device *sdp;
#if CONFIG_SCSI_LOGGING #if CONFIG_SCSI_LOGGING
char nbuff[6]; char nbuff[6];
#endif #endif
/* /*
* don't support specials for nwo * don't support specials for nwo
*/ */
if (!(SCpnt->request.flags & REQ_CMD)) if (!(SCpnt->request.flags & REQ_CMD))
return 0; return 0;
devm = SD_PARTITION(SCpnt->request.rq_dev); part_nr = SD_PARTITION(SCpnt->request.rq_dev);
dev = DEVICE_NR(SCpnt->request.rq_dev); dsk_nr = DEVICE_NR(SCpnt->request.rq_dev);
block = SCpnt->request.sector; block = SCpnt->request.sector;
this_count = SCpnt->request_bufflen >> 9; this_count = SCpnt->request_bufflen >> 9;
SCSI_LOG_HLQUEUE(1, printk("Doing sd request, dev = %d, block = %d\n", devm, block)); SCSI_LOG_HLQUEUE(1, printk("sd_command_init: dsk_nr=%d, block=%d, "
"count=%d\n", dsk_nr, block, this_count));
dpnt = &rscsi_disks[dev];
if (devm >= (sd_template.dev_max << 4) || (devm & 0xf) || sdp = SCpnt->device;
!dpnt || /* >>>>> the "(part_nr & 0xf)" excludes 15th partition, why?? */
!dpnt->device->online || /* >>>>> this change is not in the lk 2.5 series */
block + SCpnt->request.nr_sectors > sd[devm].nr_sects) { if (part_nr >= (sd_template.dev_max << 4) || (part_nr & 0xf) ||
SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors)); !sdp || !sdp->online ||
block + SCpnt->request.nr_sectors > sd[part_nr].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)); SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
return 0; return 0;
} }
if (dpnt->device->changed) { if (sdp->changed) {
/* /*
* quietly refuse to do anything to a changed disc until the changed * quietly refuse to do anything to a changed disc until
* bit has been reset * the changed bit has been reset
*/ */
/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */ /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
return 0; return 0;
} }
SCSI_LOG_HLQUEUE(2, sd_devname(devm, nbuff)); SCSI_LOG_HLQUEUE(2, sd_dskname(dsk_nr, nbuff));
SCSI_LOG_HLQUEUE(2, printk("%s : real dev = /dev/%d, block = %d\n", SCSI_LOG_HLQUEUE(2, printk("%s : [part_nr=%d], block=%d\n",
nbuff, dev, block)); nbuff, part_nr, block));
/* /*
* If we have a 1K hardware sectorsize, prevent access to single * If we have a 1K hardware sectorsize, prevent access to single
...@@ -331,27 +402,27 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) ...@@ -331,27 +402,27 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
* and not force the scsi disk driver to use bounce buffers * and not force the scsi disk driver to use bounce buffers
* for this. * for this.
*/ */
if (dpnt->device->sector_size == 1024) { if (sdp->sector_size == 1024) {
if ((block & 1) || (SCpnt->request.nr_sectors & 1)) { if ((block & 1) || (SCpnt->request.nr_sectors & 1)) {
printk("sd.c:Bad block number requested"); printk(KERN_ERR "sd: Bad block number requested");
return 0; return 0;
} else { } else {
block = block >> 1; block = block >> 1;
this_count = this_count >> 1; this_count = this_count >> 1;
} }
} }
if (dpnt->device->sector_size == 2048) { if (sdp->sector_size == 2048) {
if ((block & 3) || (SCpnt->request.nr_sectors & 3)) { if ((block & 3) || (SCpnt->request.nr_sectors & 3)) {
printk("sd.c:Bad block number requested"); printk(KERN_ERR "sd: Bad block number requested");
return 0; return 0;
} else { } else {
block = block >> 2; block = block >> 2;
this_count = this_count >> 2; this_count = this_count >> 2;
} }
} }
if (dpnt->device->sector_size == 4096) { if (sdp->sector_size == 4096) {
if ((block & 7) || (SCpnt->request.nr_sectors & 7)) { if ((block & 7) || (SCpnt->request.nr_sectors & 7)) {
printk("sd.c:Bad block number requested"); printk(KERN_ERR "sd: Bad block number requested");
return 0; return 0;
} else { } else {
block = block >> 3; block = block >> 3;
...@@ -359,7 +430,7 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) ...@@ -359,7 +430,7 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
} }
} }
if (rq_data_dir(&SCpnt->request) == WRITE) { if (rq_data_dir(&SCpnt->request) == WRITE) {
if (!dpnt->device->writeable) { if (!sdp->writeable) {
return 0; return 0;
} }
SCpnt->cmnd[0] = WRITE_6; SCpnt->cmnd[0] = WRITE_6;
...@@ -367,13 +438,16 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) ...@@ -367,13 +438,16 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
} else if (rq_data_dir(&SCpnt->request) == READ) { } else if (rq_data_dir(&SCpnt->request) == READ) {
SCpnt->cmnd[0] = READ_6; SCpnt->cmnd[0] = READ_6;
SCpnt->sc_data_direction = SCSI_DATA_READ; SCpnt->sc_data_direction = SCSI_DATA_READ;
} else } else {
panic("Unknown sd command %lx\n", SCpnt->request.flags); printk(KERN_ERR "sd: Unknown command %lx\n",
SCpnt->request.flags);
/* overkill panic("Unknown sd command %lx\n", SCpnt->request.flags); */
return 0;
}
SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n", SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n",
nbuff, nbuff, (rq_data_dir(&SCpnt->request) == WRITE) ?
(rq_data_dir(&SCpnt->request) == WRITE) ? "writing" : "reading", "writing" : "reading", this_count, SCpnt->request.nr_sectors));
this_count, SCpnt->request.nr_sectors));
SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ? SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
((SCpnt->lun << 5) & 0xe0) : 0; ((SCpnt->lun << 5) & 0xe0) : 0;
...@@ -406,7 +480,7 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) ...@@ -406,7 +480,7 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
* host adapter, it's safe to assume that we can at least transfer * host adapter, it's safe to assume that we can at least transfer
* this many bytes between each connect / disconnect. * this many bytes between each connect / disconnect.
*/ */
SCpnt->transfersize = dpnt->device->sector_size; SCpnt->transfersize = sdp->sector_size;
SCpnt->underflow = this_count << 9; SCpnt->underflow = this_count << 9;
SCpnt->allowed = MAX_RETRIES; SCpnt->allowed = MAX_RETRIES;
...@@ -417,7 +491,7 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) ...@@ -417,7 +491,7 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
* This is the completion routine we use. This is matched in terms * This is the completion routine we use. This is matched in terms
* of capability to this function. * of capability to this function.
*/ */
SCpnt->done = rw_intr; SCpnt->done = sd_rw_intr;
/* /*
* This indicates that the command is ready from our end to be * This indicates that the command is ready from our end to be
...@@ -426,31 +500,46 @@ static int sd_init_command(Scsi_Cmnd * SCpnt) ...@@ -426,31 +500,46 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
return 1; return 1;
} }
/**
* sd_open - open a scsi disk device
* @inode: only i_rdev member may be used
* @filp: only f_mode and f_flags may be used
*
* Returns 0 if successful. Returns a negated errno value in case
* of error.
*
* Note: This can be called from a user context (e.g. fsck(1) )
* or from within the kernel (e.g. as a result of a mount(1) ).
* In the latter case @inode and @filp carry an abridged amount
* of information as noted above.
**/
static int sd_open(struct inode *inode, struct file *filp) static int sd_open(struct inode *inode, struct file *filp)
{ {
int target, retval = -ENXIO; int retval = -ENXIO;
Scsi_Device * SDev; Scsi_Device * sdp;
target = DEVICE_NR(inode->i_rdev); Scsi_Disk * sdkp;
int dsk_nr = DEVICE_NR(inode->i_rdev);
SCSI_LOG_HLQUEUE(1, printk("target=%d, max=%d\n", target, sd_template.dev_max)); SCSI_LOG_HLQUEUE(3, printk("sd_open: dsk_nr=%d, part_nr=%d\n",
dsk_nr, SD_PARTITION(inode->i_rdev)));
if (target >= sd_template.dev_max || !rscsi_disks[target].device) sdkp = sd_get_sdisk(dsk_nr);
if ((NULL == sdkp) || (NULL == (sdp = sdkp->device)))
return -ENXIO; /* No such device */ return -ENXIO; /* No such device */
/* /*
* If the device is in error recovery, wait until it is done. * If the device is in error recovery, wait until it is done.
* If the device is offline, then disallow any access to it. * 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(sdp))
return -ENXIO; return -ENXIO;
}
/* /*
* Make sure that only one process can do a check_change_disk at one time. * Make sure that only one process can do a check_change_disk at
* This is also used to lock out further access when the partition table * one time. This is also used to lock out further access when
* is being re-read. * the partition table is being re-read.
*/ */
while (rscsi_disks[target].device->busy) { while (sdp->busy) {
barrier(); barrier();
cpu_relax(); cpu_relax();
} }
...@@ -458,22 +547,21 @@ static int sd_open(struct inode *inode, struct file *filp) ...@@ -458,22 +547,21 @@ static int sd_open(struct inode *inode, struct file *filp)
* The following code can sleep. * The following code can sleep.
* Module unloading must be prevented * Module unloading must be prevented
*/ */
SDev = rscsi_disks[target].device; if (sdp->host->hostt->module)
if (SDev->host->hostt->module) __MOD_INC_USE_COUNT(sdp->host->hostt->module);
__MOD_INC_USE_COUNT(SDev->host->hostt->module);
if (sd_template.module) if (sd_template.module)
__MOD_INC_USE_COUNT(sd_template.module); __MOD_INC_USE_COUNT(sd_template.module);
SDev->access_count++; sdp->access_count++;
if (rscsi_disks[target].device->removable) { if (sdp->removable) {
SDev->allow_revalidate = 1; sdp->allow_revalidate = 1;
check_disk_change(inode->i_rdev); check_disk_change(inode->i_rdev);
SDev->allow_revalidate = 0; sdp->allow_revalidate = 0;
/* /*
* If the drive is empty, just let the open fail. * If the drive is empty, just let the open fail.
*/ */
if ((!rscsi_disks[target].ready) && !(filp->f_flags & O_NDELAY)) { if ((!sdkp->ready) && !(filp->f_flags & O_NDELAY)) {
retval = -ENOMEDIUM; retval = -ENOMEDIUM;
goto error_out; goto error_out;
} }
...@@ -483,7 +571,7 @@ static int sd_open(struct inode *inode, struct file *filp) ...@@ -483,7 +571,7 @@ static int sd_open(struct inode *inode, struct file *filp)
* have the open fail if the user expects to be able to write * have the open fail if the user expects to be able to write
* to the thing. * to the thing.
*/ */
if ((rscsi_disks[target].write_prot) && (filp->f_mode & 2)) { if ((sdkp->write_prot) && (filp->f_mode & FMODE_WRITE)) {
retval = -EROFS; retval = -EROFS;
goto error_out; goto error_out;
} }
...@@ -494,7 +582,7 @@ static int sd_open(struct inode *inode, struct file *filp) ...@@ -494,7 +582,7 @@ static int sd_open(struct inode *inode, struct file *filp)
* and don't pretend that * and don't pretend that
* the open actually succeeded. * the open actually succeeded.
*/ */
if (!SDev->online) { if (!sdp->online) {
goto error_out; goto error_out;
} }
/* /*
...@@ -505,42 +593,57 @@ static int sd_open(struct inode *inode, struct file *filp) ...@@ -505,42 +593,57 @@ static int sd_open(struct inode *inode, struct file *filp)
goto error_out; goto error_out;
} }
if (SDev->removable) if (sdp->removable)
if (SDev->access_count==1) if (sdp->access_count==1)
if (scsi_block_when_processing_errors(SDev)) if (scsi_block_when_processing_errors(sdp))
scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, NULL); scsi_ioctl(sdp, SCSI_IOCTL_DOORLOCK, NULL);
return 0; return 0;
error_out: error_out:
SDev->access_count--; sdp->access_count--;
if (SDev->host->hostt->module) if (sdp->host->hostt->module)
__MOD_DEC_USE_COUNT(SDev->host->hostt->module); __MOD_DEC_USE_COUNT(sdp->host->hostt->module);
if (sd_template.module) if (sd_template.module)
__MOD_DEC_USE_COUNT(sd_template.module); __MOD_DEC_USE_COUNT(sd_template.module);
return retval; return retval;
} }
static int sd_release(struct inode *inode, struct file *file) /**
* sd_release - invoked when the (last) close(2) is called on this
* scsi disk.
* @inode: only i_rdev member may be used
* @filp: only f_mode and f_flags may be used
*
* Returns 0.
*
* Note: may block (uninterruptible) if error recovery is underway
* on this disk.
**/
static int sd_release(struct inode *inode, struct file *filp)
{ {
int target; Scsi_Disk * sdkp;
Scsi_Device * SDev; int dsk_nr = DEVICE_NR(inode->i_rdev);
Scsi_Device * sdp;
target = DEVICE_NR(inode->i_rdev); SCSI_LOG_HLQUEUE(3, printk("sd_release: dsk_nr=%d, part_nr=%d\n",
SDev = rscsi_disks[target].device; dsk_nr, SD_PARTITION(inode->i_rdev)));
if (!SDev) sdkp = sd_get_sdisk(dsk_nr);
return -ENODEV; if ((NULL == sdkp) || (NULL == (sdp = sdkp->device)))
return -ENODEV; /* open uses ENXIO ?? */
/* ... and what if there are packets in flight and this close()
* is followed by a "rmmod sd_mod" */
SDev->access_count--; sdp->access_count--;
if (SDev->removable) { if (sdp->removable) {
if (!SDev->access_count) if (!sdp->access_count)
if (scsi_block_when_processing_errors(SDev)) if (scsi_block_when_processing_errors(sdp))
scsi_ioctl(SDev, SCSI_IOCTL_DOORUNLOCK, NULL); scsi_ioctl(sdp, SCSI_IOCTL_DOORUNLOCK, NULL);
} }
if (SDev->host->hostt->module) if (sdp->host->hostt->module)
__MOD_DEC_USE_COUNT(SDev->host->hostt->module); __MOD_DEC_USE_COUNT(sdp->host->hostt->module);
if (sd_template.module) if (sd_template.module)
__MOD_DEC_USE_COUNT(sd_template.module); __MOD_DEC_USE_COUNT(sd_template.module);
return 0; return 0;
...@@ -558,7 +661,7 @@ static struct block_device_operations sd_fops = ...@@ -558,7 +661,7 @@ static struct block_device_operations sd_fops =
/* /*
* If we need more than one SCSI disk major (i.e. more than * If we need more than one SCSI disk major (i.e. more than
* 16 SCSI disks), we'll have to kmalloc() more gendisks later. * 16 SCSI disks), we'll have to vmalloc() more gendisks later.
*/ */
static struct gendisk sd_gendisk = static struct gendisk sd_gendisk =
...@@ -573,30 +676,34 @@ static struct gendisk *sd_gendisks = &sd_gendisk; ...@@ -573,30 +676,34 @@ static struct gendisk *sd_gendisks = &sd_gendisk;
#define SD_GENDISK(i) sd_gendisks[(i) / SCSI_DISKS_PER_MAJOR] #define SD_GENDISK(i) sd_gendisks[(i) / SCSI_DISKS_PER_MAJOR]
/* /**
* rw_intr is the interrupt routine for the device driver. * sd_rw_intr - bottom half handler: called when the lower level
* It will be notified on the end of a SCSI read / write, and * driver has completed (successfully or otherwise) a scsi command.
* will take one of several actions based on success or failure. * @SCpnt: mid-level's per command structure.
*/ *
* Note: potentially run from within an ISR. Must not block.
static void rw_intr(Scsi_Cmnd * SCpnt) **/
static void sd_rw_intr(Scsi_Cmnd * SCpnt)
{ {
int result = SCpnt->result; int result = SCpnt->result;
#if CONFIG_SCSI_LOGGING
char nbuff[6];
#endif
int this_count = SCpnt->bufflen >> 9; int this_count = SCpnt->bufflen >> 9;
int good_sectors = (result == 0 ? this_count : 0); int good_sectors = (result == 0 ? this_count : 0);
int block_sectors = 1; int block_sectors = 1;
long error_sector;
#if CONFIG_SCSI_LOGGING
char nbuff[6];
SCSI_LOG_HLCOMPLETE(1, sd_devname(DEVICE_NR(SCpnt->request.rq_dev), nbuff)); SCSI_LOG_HLCOMPLETE(1, sd_dskname(DEVICE_NR(SCpnt->request.rq_dev),
nbuff));
SCSI_LOG_HLCOMPLETE(1, printk("%s : rw_intr(%d, %x [%x %x])\n", nbuff, SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n",
SCpnt->host->host_no, nbuff, result));
result, if (0 != result) {
SCpnt->sense_buffer[0], SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[0,2,asc,ascq]"
SCpnt->sense_buffer[2])); "=%x,%x,%x,%x\n", SCpnt->sense_buffer[0],
SCpnt->sense_buffer[2], SCpnt->sense_buffer[12],
SCpnt->sense_buffer[13]));
}
#endif
/* /*
Handle MEDIUM ERRORs that indicate partial success. Since this is a Handle MEDIUM ERRORs that indicate partial success. Since this is a
relatively rare error condition, no care is taken to avoid relatively rare error condition, no care is taken to avoid
...@@ -604,10 +711,11 @@ static void rw_intr(Scsi_Cmnd * SCpnt) ...@@ -604,10 +711,11 @@ static void rw_intr(Scsi_Cmnd * SCpnt)
*/ */
/* An error occurred */ /* An error occurred */
if (driver_byte(result) != 0) { if (driver_byte(result) != 0 && /* An error occured */
/* Sense data is valid */ SCpnt->sense_buffer[0] != 0xF0) { /* Sense data is valid */
if (SCpnt->sense_buffer[0] == 0xF0 && SCpnt->sense_buffer[2] == MEDIUM_ERROR) { switch (SCpnt->sense_buffer[2]) {
long error_sector = (SCpnt->sense_buffer[3] << 24) | case MEDIUM_ERROR:
error_sector = (SCpnt->sense_buffer[3] << 24) |
(SCpnt->sense_buffer[4] << 16) | (SCpnt->sense_buffer[4] << 16) |
(SCpnt->sense_buffer[5] << 8) | (SCpnt->sense_buffer[5] << 8) |
SCpnt->sense_buffer[6]; SCpnt->sense_buffer[6];
...@@ -640,13 +748,30 @@ static void rw_intr(Scsi_Cmnd * SCpnt) ...@@ -640,13 +748,30 @@ static void rw_intr(Scsi_Cmnd * SCpnt)
good_sectors = error_sector - SCpnt->request.sector; good_sectors = error_sector - SCpnt->request.sector;
if (good_sectors < 0 || good_sectors >= this_count) if (good_sectors < 0 || good_sectors >= this_count)
good_sectors = 0; good_sectors = 0;
} break;
if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) {
case RECOVERED_ERROR:
/*
* An error occured, but it recovered. Inform the
* user, but make sure that it's not treated as a
* hard error.
*/
print_sense("sd", SCpnt);
result = 0;
SCpnt->sense_buffer[0] = 0x0;
good_sectors = this_count;
break;
case ILLEGAL_REQUEST:
if (SCpnt->device->ten == 1) { if (SCpnt->device->ten == 1) {
if (SCpnt->cmnd[0] == READ_10 || if (SCpnt->cmnd[0] == READ_10 ||
SCpnt->cmnd[0] == WRITE_10) SCpnt->cmnd[0] == WRITE_10)
SCpnt->device->ten = 0; SCpnt->device->ten = 0;
} }
break;
default:
break;
} }
} }
/* /*
...@@ -656,28 +781,33 @@ static void rw_intr(Scsi_Cmnd * SCpnt) ...@@ -656,28 +781,33 @@ static void rw_intr(Scsi_Cmnd * SCpnt)
*/ */
scsi_io_completion(SCpnt, good_sectors, block_sectors); scsi_io_completion(SCpnt, good_sectors, block_sectors);
} }
/*
* requeue_sd_request() is the request handler function for the sd driver.
* Its function in life is to take block device requests, and translate
* them to SCSI commands.
*/
/**
* check_scsidisk_media_change - self descriptive
* @full_dev: kernel device descriptor (kdev_t)
*
* Returns 0 if not applicable or no change; 1 if change
*
* Note: this function is invoked from the block subsystem.
**/
static int check_scsidisk_media_change(kdev_t full_dev) static int check_scsidisk_media_change(kdev_t full_dev)
{ {
int retval; int retval;
int target; int flag = 0; /* <<<< what is this for?? */
int flag = 0; Scsi_Disk * sdkp;
Scsi_Device * SDev; Scsi_Device * sdp;
int dsk_nr = DEVICE_NR(full_dev);
target = DEVICE_NR(full_dev);
SDev = rscsi_disks[target].device; sdkp = sd_get_sdisk(dsk_nr);
if (target >= sd_template.dev_max || !SDev) { SCSI_LOG_HLQUEUE(3, printk("check_scsidisk_media_change: "
printk("SCSI disk request error: invalid device.\n"); "dsk_nr=%d\n", dsk_nr));
if ((NULL == sdkp) || (NULL == (sdp = sdkp->device))) {
printk(KERN_ERR "check_scsidisk_media_change: dsk_nr=%d, "
"invalid device\n", dsk_nr);
return 0; return 0;
} }
if (!SDev->removable) if (!sdp->removable)
return 0; return 0;
/* /*
...@@ -686,9 +816,9 @@ static int check_scsidisk_media_change(kdev_t full_dev) ...@@ -686,9 +816,9 @@ static int check_scsidisk_media_change(kdev_t full_dev)
* can deal with it then. It is only because of unrecoverable errors * can deal with it then. It is only because of unrecoverable errors
* that we would ever take a device offline in the first place. * that we would ever take a device offline in the first place.
*/ */
if (SDev->online == FALSE) { if (sdp->online == FALSE) {
rscsi_disks[target].ready = 0; sdkp->ready = 0;
SDev->changed = 1; sdp->changed = 1;
return 1; /* This will force a flush, if called from return 1; /* This will force a flush, if called from
* check_disk_change */ * check_disk_change */
} }
...@@ -700,8 +830,8 @@ static int check_scsidisk_media_change(kdev_t full_dev) ...@@ -700,8 +830,8 @@ static int check_scsidisk_media_change(kdev_t full_dev)
* as this will spin up the drive. * as this will spin up the drive.
*/ */
retval = -ENODEV; retval = -ENODEV;
if (scsi_block_when_processing_errors(SDev)) if (scsi_block_when_processing_errors(sdp))
retval = scsi_ioctl(SDev, SCSI_IOCTL_START_UNIT, NULL); retval = scsi_ioctl(sdp, SCSI_IOCTL_START_UNIT, NULL);
if (retval) { /* Unable to test, unit probably not ready. if (retval) { /* Unable to test, unit probably not ready.
* This usually means there is no disc in the * This usually means there is no disc in the
...@@ -709,8 +839,8 @@ static int check_scsidisk_media_change(kdev_t full_dev) ...@@ -709,8 +839,8 @@ static int check_scsidisk_media_change(kdev_t full_dev)
* it out later once the drive is available * it out later once the drive is available
* again. */ * again. */
rscsi_disks[target].ready = 0; sdkp->ready = 0;
SDev->changed = 1; sdp->changed = 1;
return 1; /* This will force a flush, if called from return 1; /* This will force a flush, if called from
* check_disk_change */ * check_disk_change */
} }
...@@ -720,15 +850,26 @@ static int check_scsidisk_media_change(kdev_t full_dev) ...@@ -720,15 +850,26 @@ static int check_scsidisk_media_change(kdev_t full_dev)
* struct and tested at open ! Daniel Roche ( dan@lectra.fr ) * struct and tested at open ! Daniel Roche ( dan@lectra.fr )
*/ */
rscsi_disks[target].ready = 1; /* FLOPTICAL */ sdkp->ready = 1; /* FLOPTICAL */
retval = SDev->changed; retval = sdp->changed;
if (!flag) if (!flag)
SDev->changed = 0; sdp->changed = 0;
return retval; return retval;
} }
static int sd_init_onedisk(int i) /**
* sd_init_onedisk - called the first time a new disk is seen,
* performs read_capacity, disk spin up (as required), etc.
* @sdkp: pointer to associated Scsi_Disk object
* @dsk_nr: disk number within this driver (e.g. 0->/dev/sda,
* 1->/dev/sdb, etc)
*
* Returns dsk_nr (pointless)
*
* Note: this function is local to this driver.
**/
static int sd_init_onedisk(Scsi_Disk * sdkp, int dsk_nr)
{ {
unsigned char cmd[10]; unsigned char cmd[10];
char nbuff[6]; char nbuff[6];
...@@ -736,19 +877,23 @@ static int sd_init_onedisk(int i) ...@@ -736,19 +877,23 @@ static int sd_init_onedisk(int i)
unsigned long spintime_value = 0; unsigned long spintime_value = 0;
int the_result, retries, spintime; int the_result, retries, spintime;
int sector_size; int sector_size;
Scsi_Device *sdp;
Scsi_Request *SRpnt; Scsi_Request *SRpnt;
SCSI_LOG_HLQUEUE(3, printk("sd_init_onedisk: dsk_nr=%d\n",
dsk_nr));
/* /*
* Get the name of the disk, in case we need to log it somewhere. * Get the name of the disk, in case we need to log it somewhere.
*/ */
sd_devname(i, nbuff); sd_dskname(dsk_nr, nbuff);
/* /*
* If the device is offline, don't try and read capacity or any * If the device is offline, don't try and read capacity or any
* of the other niceties. * of the other niceties.
*/ */
if (rscsi_disks[i].device->online == FALSE) sdp = sdkp->device;
return i; if (sdp->online == FALSE)
return dsk_nr;
/* /*
* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is * We need to retry the READ_CAPACITY because a UNIT_ATTENTION is
...@@ -756,17 +901,19 @@ static int sd_init_onedisk(int i) ...@@ -756,17 +901,19 @@ static int sd_init_onedisk(int i)
* just after a scsi bus reset. * just after a scsi bus reset.
*/ */
SRpnt = scsi_allocate_request(rscsi_disks[i].device); SRpnt = scsi_allocate_request(sdp);
if (!SRpnt) { if (!SRpnt) {
printk(KERN_WARNING "(sd_init_onedisk:) Request allocation failure.\n"); printk(KERN_WARNING "(sd_init_onedisk:) Request allocation "
return i; "failure.\n");
return dsk_nr;
} }
buffer = kmalloc(512, GFP_DMA); buffer = kmalloc(512, GFP_DMA);
if (!buffer) { if (!buffer) {
printk(KERN_WARNING "(sd_init_onedisk:) Memory allocation failure.\n"); printk(KERN_WARNING "(sd_init_onedisk:) Memory allocation "
"failure.\n");
scsi_release_request(SRpnt); scsi_release_request(SRpnt);
return i; return dsk_nr;
} }
spintime = 0; spintime = 0;
...@@ -778,8 +925,8 @@ static int sd_init_onedisk(int i) ...@@ -778,8 +925,8 @@ static int sd_init_onedisk(int i)
while (retries < 3) { while (retries < 3) {
cmd[0] = TEST_UNIT_READY; cmd[0] = TEST_UNIT_READY;
cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? cmd[1] = (sdp->scsi_level <= SCSI_2) ?
((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; ((sdp->lun << 5) & 0xe0) : 0;
memset((void *) &cmd[2], 0, 8); memset((void *) &cmd[2], 0, 8);
SRpnt->sr_cmd_len = 0; SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_sense_buffer[0] = 0;
...@@ -805,23 +952,24 @@ static int sd_init_onedisk(int i) ...@@ -805,23 +952,24 @@ static int sd_init_onedisk(int i)
&& ((driver_byte(the_result) & DRIVER_SENSE) != 0) && ((driver_byte(the_result) & DRIVER_SENSE) != 0)
&& SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION && SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION
&& SRpnt->sr_sense_buffer[12] == 0x3A ) { && SRpnt->sr_sense_buffer[12] == 0x3A ) {
rscsi_disks[i].capacity = 0x1fffff; sdkp->capacity = 0x1fffff;
sector_size = 512; sector_size = 512;
rscsi_disks[i].device->changed = 1; sdp->changed = 1;
rscsi_disks[i].ready = 0; sdkp->ready = 0;
break; break;
} }
/* Look for non-removable devices that return NOT_READY. /* Look for non-removable devices that return NOT_READY.
* Issue command to spin up drive for these cases. */ * Issue command to spin up drive for these cases. */
if (the_result && !rscsi_disks[i].device->removable && if (the_result && !sdp->removable &&
SRpnt->sr_sense_buffer[2] == NOT_READY) { SRpnt->sr_sense_buffer[2] == NOT_READY) {
unsigned long time1; unsigned long time1;
if (!spintime) { if (!spintime) {
printk("%s: Spinning up disk...", nbuff); printk(KERN_NOTICE "%s: Spinning up disk...",
nbuff);
cmd[0] = START_STOP; cmd[0] = START_STOP;
cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? cmd[1] = (sdp->scsi_level <= SCSI_2) ?
((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; ((sdp->lun << 5) & 0xe0) : 0;
cmd[1] |= 1; /* Return immediately */ cmd[1] |= 1; /* Return immediately */
memset((void *) &cmd[2], 0, 8); memset((void *) &cmd[2], 0, 8);
cmd[4] = 1; /* Start spin cycle */ cmd[4] = 1; /* Start spin cycle */
...@@ -830,8 +978,9 @@ static int sd_init_onedisk(int i) ...@@ -830,8 +978,9 @@ static int sd_init_onedisk(int i)
SRpnt->sr_sense_buffer[2] = 0; SRpnt->sr_sense_buffer[2] = 0;
SRpnt->sr_data_direction = SCSI_DATA_READ; SRpnt->sr_data_direction = SCSI_DATA_READ;
scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer, scsi_wait_req(SRpnt, (void *)cmd,
0/*512*/, SD_TIMEOUT, MAX_RETRIES); (void *) buffer, 0/*512*/,
SD_TIMEOUT, MAX_RETRIES);
spintime_value = jiffies; spintime_value = jiffies;
} }
spintime = 1; spintime = 1;
...@@ -854,8 +1003,8 @@ static int sd_init_onedisk(int i) ...@@ -854,8 +1003,8 @@ static int sd_init_onedisk(int i)
retries = 3; retries = 3;
do { do {
cmd[0] = READ_CAPACITY; cmd[0] = READ_CAPACITY;
cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? cmd[1] = (sdp->scsi_level <= SCSI_2) ?
((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; ((sdp->lun << 5) & 0xe0) : 0;
memset((void *) &cmd[2], 0, 8); memset((void *) &cmd[2], 0, 8);
memset((void *) buffer, 0, 8); memset((void *) buffer, 0, 8);
SRpnt->sr_cmd_len = 0; SRpnt->sr_cmd_len = 0;
...@@ -887,8 +1036,8 @@ static int sd_init_onedisk(int i) ...@@ -887,8 +1036,8 @@ static int sd_init_onedisk(int i)
*/ */
if (the_result) { if (the_result) {
printk("%s : READ CAPACITY failed.\n" printk(KERN_NOTICE "%s : READ CAPACITY failed.\n"
"%s : status = %x, message = %02x, host = %d, driver = %02x \n", "%s : status=%x, message=%02x, host=%d, driver=%02x \n",
nbuff, nbuff, nbuff, nbuff,
status_byte(the_result), status_byte(the_result),
msg_byte(the_result), msg_byte(the_result),
...@@ -900,50 +1049,50 @@ static int sd_init_onedisk(int i) ...@@ -900,50 +1049,50 @@ static int sd_init_onedisk(int i)
else else
printk("%s : sense not available. \n", nbuff); printk("%s : sense not available. \n", nbuff);
printk("%s : block size assumed to be 512 bytes, disk size 1GB. \n", printk(KERN_NOTICE "%s : block size assumed to be 512 "
nbuff); "bytes, disk size 1GB. \n", nbuff);
rscsi_disks[i].capacity = 0x1fffff; sdkp->capacity = 0x1fffff;
sector_size = 512; sector_size = 512;
/* Set dirty bit for removable devices if not ready - /* Set dirty bit for removable devices if not ready -
* sometimes drives will not report this properly. */ * sometimes drives will not report this properly. */
if (rscsi_disks[i].device->removable && if (sdp->removable &&
SRpnt->sr_sense_buffer[2] == NOT_READY) SRpnt->sr_sense_buffer[2] == NOT_READY)
rscsi_disks[i].device->changed = 1; sdp->changed = 1;
} else { } else {
/* /*
* FLOPTICAL, if read_capa is ok, drive is assumed to be ready * FLOPTICAL, if read_capa is ok, drive is assumed to be ready
*/ */
rscsi_disks[i].ready = 1; sdkp->ready = 1;
rscsi_disks[i].capacity = 1 + ((buffer[0] << 24) | sdkp->capacity = 1 + ((buffer[0] << 24) |
(buffer[1] << 16) | (buffer[1] << 16) |
(buffer[2] << 8) | (buffer[2] << 8) |
buffer[3]); buffer[3]);
sector_size = (buffer[4] << 24) | 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) { if (sector_size == 0) {
sector_size = 512; sector_size = 512;
printk("%s : sector size 0 reported, assuming 512.\n", printk(KERN_NOTICE "%s : sector size 0 reported, "
nbuff); "assuming 512.\n", nbuff);
} }
if (sector_size != 512 && if (sector_size != 512 &&
sector_size != 1024 && sector_size != 1024 &&
sector_size != 2048 && sector_size != 2048 &&
sector_size != 4096 && sector_size != 4096 &&
sector_size != 256) { sector_size != 256) {
printk("%s : unsupported sector size %d.\n", printk(KERN_NOTICE "%s : unsupported sector size "
nbuff, sector_size); "%d.\n", nbuff, sector_size);
/* /*
* The user might want to re-format the drive with * The user might want to re-format the drive with
* a supported sectorsize. Once this happens, it * a supported sectorsize. Once this happens, it
* would be relatively trivial to set the thing up. * would be relatively trivial to set the thing up.
* For this reason, we leave the thing in the table. * For this reason, we leave the thing in the table.
*/ */
rscsi_disks[i].capacity = 0; sdkp->capacity = 0;
} }
{ {
/* /*
...@@ -952,33 +1101,33 @@ static int sd_init_onedisk(int i) ...@@ -952,33 +1101,33 @@ static int sd_init_onedisk(int i)
* Jacques Gelinas (Jacques@solucorp.qc.ca) * Jacques Gelinas (Jacques@solucorp.qc.ca)
*/ */
int hard_sector = sector_size; int hard_sector = sector_size;
int sz = rscsi_disks[i].capacity * (hard_sector/256); int sz = sdkp->capacity * (hard_sector/256);
request_queue_t *queue = &rscsi_disks[i].device->request_queue; request_queue_t *queue = &sdp->request_queue;
blk_queue_hardsect_size(queue, hard_sector); blk_queue_hardsect_size(queue, hard_sector);
printk("SCSI device %s: " printk(KERN_NOTICE "SCSI device %s: "
"%d %d-byte hdwr sectors (%d MB)\n", "%d %d-byte hdwr sectors (%d MB)\n",
nbuff, rscsi_disks[i].capacity, nbuff, sdkp->capacity,
hard_sector, (sz/2 - sz/1250 + 974)/1950); hard_sector, (sz/2 - sz/1250 + 974)/1950);
} }
/* Rescale capacity to 512-byte units */ /* Rescale capacity to 512-byte units */
if (sector_size == 4096) if (sector_size == 4096)
rscsi_disks[i].capacity <<= 3; sdkp->capacity <<= 3;
if (sector_size == 2048) if (sector_size == 2048)
rscsi_disks[i].capacity <<= 2; sdkp->capacity <<= 2;
if (sector_size == 1024) if (sector_size == 1024)
rscsi_disks[i].capacity <<= 1; sdkp->capacity <<= 1;
if (sector_size == 256) if (sector_size == 256)
rscsi_disks[i].capacity >>= 1; sdkp->capacity >>= 1;
} }
/* /*
* Unless otherwise specified, this is not write protected. * Unless otherwise specified, this is not write protected.
*/ */
rscsi_disks[i].write_prot = 0; sdkp->write_prot = 0;
if (rscsi_disks[i].device->removable && rscsi_disks[i].ready) { if (sdp->removable && sdkp->ready) {
/* FLOPTICAL */ /* FLOPTICAL */
/* /*
...@@ -996,8 +1145,8 @@ static int sd_init_onedisk(int i) ...@@ -996,8 +1145,8 @@ static int sd_init_onedisk(int i)
memset((void *) &cmd[0], 0, 8); memset((void *) &cmd[0], 0, 8);
cmd[0] = MODE_SENSE; cmd[0] = MODE_SENSE;
cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? cmd[1] = (sdp->scsi_level <= SCSI_2) ?
((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; ((sdp->lun << 5) & 0xe0) : 0;
cmd[2] = 0x3f; /* Get all pages */ cmd[2] = 0x3f; /* Get all pages */
cmd[4] = 255; /* Ask for 255 bytes, even tho we want just the first 8 */ cmd[4] = 255; /* Ask for 255 bytes, even tho we want just the first 8 */
SRpnt->sr_cmd_len = 0; SRpnt->sr_cmd_len = 0;
...@@ -1012,11 +1161,12 @@ static int sd_init_onedisk(int i) ...@@ -1012,11 +1161,12 @@ static int sd_init_onedisk(int i)
the_result = SRpnt->sr_result; the_result = SRpnt->sr_result;
if (the_result) { if (the_result) {
printk("%s: test WP failed, assume Write Enabled\n", nbuff); printk(KERN_NOTICE "%s: test WP failed, assume "
"Write Enabled\n", nbuff);
} else { } else {
rscsi_disks[i].write_prot = ((buffer[2] & 0x80) != 0); sdkp->write_prot = ((buffer[2] & 0x80) != 0);
printk("%s: Write Protect is %s\n", nbuff, printk(KERN_NOTICE "%s: Write Protect is %s\n", nbuff,
rscsi_disks[i].write_prot ? "on" : "off"); sdkp->write_prot ? "on" : "off");
} }
} /* check for write protect */ } /* check for write protect */
...@@ -1028,7 +1178,7 @@ static int sd_init_onedisk(int i) ...@@ -1028,7 +1178,7 @@ static int sd_init_onedisk(int i)
SRpnt = NULL; SRpnt = NULL;
kfree(buffer); kfree(buffer);
return i; return dsk_nr;
} }
/* /*
...@@ -1038,14 +1188,25 @@ static int sd_init_onedisk(int i) ...@@ -1038,14 +1188,25 @@ static int sd_init_onedisk(int i)
static int sd_registered; static int sd_registered;
/**
* sd_init- called during driver initialization (after
* sd_detect() is called for each scsi device present).
*
* Returns 0 is successful (or already called); 1 if error
*
* Note: this function is invoked from the scsi mid-level.
**/
static int sd_init() static int sd_init()
{ {
int i, maxparts; int k, maxparts;
Scsi_Disk * sdkp;
SCSI_LOG_HLQUEUE(3, printk("sd_init: dev_noticed=%d\n",
sd_template.dev_noticed));
if (sd_template.dev_noticed == 0) if (sd_template.dev_noticed == 0)
return 0; return 0;
if (!rscsi_disks) if (NULL == sd_dsk_arr)
sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS; sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS;
if (sd_template.dev_max > N_SD_MAJORS * SCSI_DISKS_PER_MAJOR) if (sd_template.dev_max > N_SD_MAJORS * SCSI_DISKS_PER_MAJOR)
...@@ -1057,71 +1218,80 @@ static int sd_init() ...@@ -1057,71 +1218,80 @@ static int sd_init()
return 0; return 0;
if (!sd_registered) { if (!sd_registered) {
for (i = 0; i < N_USED_SD_MAJORS; i++) { for (k = 0; k < N_USED_SD_MAJORS; k++) {
if (devfs_register_blkdev(SD_MAJOR(i), "sd", if (devfs_register_blkdev(SD_MAJOR(k), "sd",
&sd_fops)) { &sd_fops)) {
printk("Unable to get major %d for SCSI disk\n", printk(KERN_NOTICE "Unable to get major %d "
SD_MAJOR(i)); "for SCSI disk\n", SD_MAJOR(k));
return 1; return 1;
} }
} }
sd_registered++; sd_registered++;
} }
/* We do not support attaching loadable devices yet. */ /* We do not support attaching loadable devices yet. */
if (rscsi_disks) if (sd_dsk_arr)
return 0; return 0;
/* allocate memory */ /* allocate memory */
#define init_mem_lth(x,n) x = kmalloc((n) * sizeof(*x), GFP_ATOMIC) #define init_mem_lth(x,n) x = vmalloc((n) * sizeof(*x))
#define zero_mem_lth(x,n) memset(x, 0, (n) * sizeof(*x)) #define zero_mem_lth(x,n) memset(x, 0, (n) * sizeof(*x))
init_mem_lth(rscsi_disks, sd_template.dev_max); init_mem_lth(sd_dsk_arr, sd_template.dev_max);
if (sd_dsk_arr) {
zero_mem_lth(sd_dsk_arr, sd_template.dev_max);
for (k = 0; k < sd_template.dev_max; ++k) {
sdkp = vmalloc(sizeof(Scsi_Disk));
if (NULL == sdkp)
goto cleanup_mem;
memset(sdkp, 0, sizeof(Scsi_Disk));
sd_dsk_arr[k] = sdkp;
}
}
init_mem_lth(sd_sizes, maxparts); init_mem_lth(sd_sizes, maxparts);
init_mem_lth(sd, maxparts); init_mem_lth(sd, maxparts);
init_mem_lth(sd_gendisks, N_USED_SD_MAJORS); init_mem_lth(sd_gendisks, N_USED_SD_MAJORS);
init_mem_lth(sd_max_sectors, sd_template.dev_max << 4); init_mem_lth(sd_max_sectors, sd_template.dev_max << 4);
if (!rscsi_disks || !sd_sizes || !sd || !sd_gendisks) if (!sd_dsk_arr || !sd_sizes || !sd || !sd_gendisks)
goto cleanup_mem; goto cleanup_mem;
zero_mem_lth(rscsi_disks, sd_template.dev_max);
zero_mem_lth(sd_sizes, maxparts); zero_mem_lth(sd_sizes, maxparts);
zero_mem_lth(sd, maxparts); zero_mem_lth(sd, maxparts);
for (i = 0; i < maxparts; i++) { for (k = 0; k < maxparts; k++) {
/* /*
* Allow lowlevel device drivers to generate 512k large scsi * Allow lowlevel device drivers to generate 512k large scsi
* commands if they know what they're doing and they ask for it * commands if they know what they're doing and they ask for it
* explicitly via the SHpnt->max_sectors API. * explicitly via the SHpnt->max_sectors API.
*/ */
sd_max_sectors[i] = MAX_PHYS_SEGMENTS*8; sd_max_sectors[k] = MAX_PHYS_SEGMENTS*8;
} }
for (i = 0; i < N_USED_SD_MAJORS; i++) { for (k = 0; k < N_USED_SD_MAJORS; k++) {
request_queue_t *q = blk_get_queue(mk_kdev(SD_MAJOR(i), 0)); request_queue_t *q = blk_get_queue(mk_kdev(SD_MAJOR(k), 0));
blk_queue_hardsect_size(q, 512); blk_queue_hardsect_size(q, 512);
} }
for (i = 0; i < N_USED_SD_MAJORS; i++) { for (k = 0; k < N_USED_SD_MAJORS; k++) {
int N = SCSI_DISKS_PER_MAJOR; int N = SCSI_DISKS_PER_MAJOR;
sd_gendisks[i] = sd_gendisk; sd_gendisks[k] = sd_gendisk;
init_mem_lth(sd_gendisks[i].de_arr, N); init_mem_lth(sd_gendisks[k].de_arr, N);
init_mem_lth(sd_gendisks[i].flags, N); init_mem_lth(sd_gendisks[k].flags, N);
if (!sd_gendisks[i].de_arr || !sd_gendisks[i].flags) if (!sd_gendisks[k].de_arr || !sd_gendisks[k].flags)
goto cleanup_gendisks; goto cleanup_gendisks;
zero_mem_lth(sd_gendisks[i].de_arr, N); zero_mem_lth(sd_gendisks[k].de_arr, N);
zero_mem_lth(sd_gendisks[i].flags, N); zero_mem_lth(sd_gendisks[k].flags, N);
sd_gendisks[i].major = SD_MAJOR(i); sd_gendisks[k].major = SD_MAJOR(k);
sd_gendisks[i].major_name = "sd"; sd_gendisks[k].major_name = "sd";
sd_gendisks[i].minor_shift = 4; sd_gendisks[k].minor_shift = 4;
sd_gendisks[i].part = sd + i * (N << 4); sd_gendisks[k].part = sd + k * (N << 4);
sd_gendisks[i].sizes = sd_sizes + i * (N << 4); sd_gendisks[k].sizes = sd_sizes + k * (N << 4);
sd_gendisks[i].nr_real = 0; sd_gendisks[k].nr_real = 0;
} }
return 0; return 0;
...@@ -1130,129 +1300,197 @@ static int sd_init() ...@@ -1130,129 +1300,197 @@ static int sd_init()
#undef zero_mem_lth #undef zero_mem_lth
cleanup_gendisks: cleanup_gendisks:
/* kfree can handle NULL, so no test is required here */ /* vfree can handle NULL, so no test is required here */
for (i = 0; i < N_USED_SD_MAJORS; i++) { for (k = 0; k < N_USED_SD_MAJORS; k++) {
kfree(sd_gendisks[i].de_arr); vfree(sd_gendisks[k].de_arr);
kfree(sd_gendisks[i].flags); vfree(sd_gendisks[k].flags);
} }
cleanup_mem: cleanup_mem:
kfree(sd_gendisks); if (sd_gendisks) vfree(sd_gendisks);
kfree(sd); sd_gendisks = NULL;
kfree(sd_sizes); if (sd) vfree(sd);
kfree(rscsi_disks); sd = NULL;
for (i = 0; i < N_USED_SD_MAJORS; i++) { sd_blocksizes = NULL;
devfs_unregister_blkdev(SD_MAJOR(i), "sd"); if (sd_sizes) vfree(sd_sizes);
sd_sizes = NULL;
if (sd_dsk_arr) {
for (k = 0; k < sd_template.dev_max; ++k) {
sdkp = sd_dsk_arr[k];
if (sdkp)
vfree(sdkp);
}
vfree(sd_dsk_arr);
sd_dsk_arr = NULL;
}
for (k = 0; k < N_USED_SD_MAJORS; k++) {
devfs_unregister_blkdev(SD_MAJOR(k), "sd");
} }
sd_registered--; sd_registered--;
return 1; return 1;
} }
/**
* sd_finish- called during driver initialization, after all
* the sd_attach() calls are finished.
*
* Note: this function is invoked from the scsi mid-level.
* This function is not called after driver initialization has completed.
* Specifically later device attachments invoke sd_attach() but not
* this function.
**/
static void sd_finish() static void sd_finish()
{ {
int i; int k;
Scsi_Disk * sdkp;
for (i = 0; i < N_USED_SD_MAJORS; i++) { SCSI_LOG_HLQUEUE(3, printk("sd_finish: \n"));
blk_dev[SD_MAJOR(i)].queue = sd_find_queue; for (k = 0; k < N_USED_SD_MAJORS; k++) {
add_gendisk(&(sd_gendisks[i])); blk_dev[SD_MAJOR(k)].queue = sd_find_queue;
add_gendisk(&(sd_gendisks[k]));
} }
for (i = 0; i < sd_template.dev_max; ++i) for (k = 0; k < sd_template.dev_max; ++k) {
if (!rscsi_disks[i].capacity && rscsi_disks[i].device) { sdkp = sd_get_sdisk(k);
sd_init_onedisk(i); if (sdkp && (0 == sdkp->capacity) && sdkp->device) {
if (!rscsi_disks[i].has_part_table) { sd_init_onedisk(sdkp, k);
sd_sizes[i << 4] = rscsi_disks[i].capacity; if (!sdkp->has_part_table) {
register_disk(&SD_GENDISK(i), MKDEV_SD(i), sd_sizes[k << 4] = sdkp->capacity;
register_disk(&SD_GENDISK(k), MKDEV_SD(k),
1<<4, &sd_fops, 1<<4, &sd_fops,
rscsi_disks[i].capacity); sdkp->capacity);
rscsi_disks[i].has_part_table = 1; sdkp->has_part_table = 1;
} }
} }
}
return; return;
} }
static int sd_detect(Scsi_Device * SDp) /**
* sd_detect- called at the start of driver initialization, once
* for each scsi device (not just disks) present.
*
* Returns 0 if not interested in this scsi device (e.g. scanner);
* 1 if this device is of interest (e.g. a disk).
*
* Note: this function is invoked from the scsi mid-level.
* This function is called before sd_init() so very little is available.
**/
static int sd_detect(Scsi_Device * sdp)
{ {
if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) SCSI_LOG_HLQUEUE(3, printk("sd_detect: type=%d\n", sdp->type));
if (sdp->type != TYPE_DISK && sdp->type != TYPE_MOD)
return 0; return 0;
sd_template.dev_noticed++; sd_template.dev_noticed++;
return 1; return 1;
} }
static int sd_attach(Scsi_Device * SDp) /**
* sd_attach- called during driver initialization and whenever a
* new scsi device is attached to the system. It is called once
* for each scsi device (not just disks) present.
* @sdp: pointer to mid level scsi device object
*
* Returns 0 if successful (or not interested in this scsi device
* (e.g. scanner)); 1 when there is an error.
*
* Note: this function is invoked from the scsi mid-level.
* This function sets up the mapping between a given
* <host,channel,id,lun> (found in sdp) and new device name
* (e.g. /dev/sda). More precisely it is the block device major
* and minor number that is chosen here.
**/
static int sd_attach(Scsi_Device * sdp)
{ {
unsigned int devnum; unsigned int devnum;
Scsi_Disk *dpnt; Scsi_Disk *sdkp;
int i; int dsk_nr;
char nbuff[6]; char nbuff[6];
unsigned long iflags;
if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) if ((NULL == sdp) ||
((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD)))
return 0; return 0;
SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n",
sdp->host->host_no, sdp->channel, sdp->id, sdp->lun));
if (sd_template.nr_dev >= sd_template.dev_max) { if (sd_template.nr_dev >= sd_template.dev_max) {
SDp->attached--; sdp->attached--;
printk(KERN_ERR "sd_init: no more room for device\n");
return 1; return 1;
} }
for (dpnt = rscsi_disks, i = 0; i < sd_template.dev_max; i++, dpnt++)
if (!dpnt->device) /* Assume sd_attach is not re-entrant (for time being) */
/* Also think about sd_attach() and sd_detach() running coincidentally. */
write_lock_irqsave(&sd_dsk_arr_lock, iflags);
for (dsk_nr = 0; dsk_nr < sd_template.dev_max; dsk_nr++) {
sdkp = sd_dsk_arr[dsk_nr];
if (!sdkp->device) {
sdkp->device = sdp;
sdkp->has_part_table = 0;
break; break;
}
}
write_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
if (i >= sd_template.dev_max) if (dsk_nr >= sd_template.dev_max) {
panic("scsi_devices corrupt (sd)"); /* panic("scsi_devices corrupt (sd)"); overkill */
printk(KERN_ERR "sd_init: sd_dsk_arr corrupted\n");
return 1;
}
rscsi_disks[i].device = SDp;
rscsi_disks[i].has_part_table = 0;
sd_template.nr_dev++; sd_template.nr_dev++;
SD_GENDISK(i).nr_real++; SD_GENDISK(dsk_nr).nr_real++;
devnum = i % SCSI_DISKS_PER_MAJOR; devnum = dsk_nr % SCSI_DISKS_PER_MAJOR;
SD_GENDISK(i).de_arr[devnum] = SDp->de; SD_GENDISK(dsk_nr).de_arr[devnum] = sdp->de;
if (SDp->removable) if (sdp->removable)
SD_GENDISK(i).flags[devnum] |= GENHD_FL_REMOVABLE; SD_GENDISK(dsk_nr).flags[devnum] |= GENHD_FL_REMOVABLE;
sd_devname(i, nbuff); sd_dskname(dsk_nr, nbuff);
printk("Attached scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n", printk(KERN_NOTICE "Attached scsi %sdisk %s at scsi%d, channel %d, "
SDp->removable ? "removable " : "", "id %d, lun %d\n", sdp->removable ? "removable " : "",
nbuff, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); nbuff, sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
return 0; return 0;
} }
#define DEVICE_BUSY rscsi_disks[target].device->busy /**
#define ALLOW_REVALIDATE rscsi_disks[target].device->allow_revalidate * revalidate_scsidisk- called to flush all partitions and partition
#define USAGE rscsi_disks[target].device->access_count * tables for a changed scsi disk. sd_init_onedisk() is then called
#define CAPACITY rscsi_disks[target].capacity * followed by re-reading the new partition table.
#define MAYBE_REINIT sd_init_onedisk(target) * @dev: kernel device descriptor (kdev_t)
* @maxusage: 0 when called from block level, 1 when called from
/* This routine is called to flush all partitions and partition tables * sd_ioctl().
* for a changed scsi disk, and then re-read the new partition table. *
* If we are revalidating a disk because of a media change, then we * Returns 0 if successful; negated errno value otherwise.
* enter with usage == 0. If we are using an ioctl, we automatically have
* usage == 1 (we need an open channel to use an ioctl :-), so this
* is our limit.
*/ */
int revalidate_scsidisk(kdev_t dev, int maxusage) int revalidate_scsidisk(kdev_t dev, int maxusage)
{ {
int target; int dsk_nr = DEVICE_NR(dev);
int res; int res;
Scsi_Disk * sdkp;
Scsi_Device * sdp;
target = DEVICE_NR(dev); SCSI_LOG_HLQUEUE(3, printk("revalidate_scsidisk: dsk_nr=%d\n",
DEVICE_NR(dev)));
sdkp = sd_get_sdisk(dsk_nr);
if ((NULL == sdkp) || (NULL == (sdp = sdkp->device)))
return -ENODEV;
if (DEVICE_BUSY || (ALLOW_REVALIDATE == 0 && USAGE > maxusage)) { if (sdp->busy || ((sdp->allow_revalidate == 0) &&
printk("Device busy for revalidation (usage=%d)\n", USAGE); (sdp->access_count > maxusage))) {
printk(KERN_WARNING "Device busy for revalidation "
"(access_count=%d)\n", sdp->access_count);
return -EBUSY; return -EBUSY;
} }
DEVICE_BUSY = 1; sdp->busy = 1;
res = wipe_partitions(dev); res = wipe_partitions(dev);
if (res) if (res)
goto leave; goto leave;
#ifdef MAYBE_REINIT sd_init_onedisk(sdkp, dsk_nr);
MAYBE_REINIT;
#endif
grok_partitions(dev, CAPACITY); grok_partitions(dev, sdkp->capacity);
leave: leave:
DEVICE_BUSY = 0; sdp->busy = 0;
return res; return res;
} }
...@@ -1260,68 +1498,125 @@ static int fop_revalidate_scsidisk(kdev_t dev) ...@@ -1260,68 +1498,125 @@ static int fop_revalidate_scsidisk(kdev_t dev)
{ {
return revalidate_scsidisk(dev, 0); return revalidate_scsidisk(dev, 0);
} }
static void sd_detach(Scsi_Device * SDp)
/**
* sd_detach- called whenever a scsi disk (previously recognized by
* sd_attach) is detached from the system. It is called (potentially
* multiple times) during sd module unload.
* @sdp: pointer to mid level scsi device object
*
* Note: this function is invoked from the scsi mid-level.
* This function potentially frees up a device name (e.g. /dev/sdc)
* that could be re-used by a subsequent sd_attach().
* This function is not called when the built-in sd driver is "exit-ed".
**/
static void sd_detach(Scsi_Device * sdp)
{ {
Scsi_Disk *dpnt; Scsi_Disk *sdkp = NULL;
kdev_t dev; kdev_t dev;
int i, j; int dsk_nr, j;
int max_p; int max_p;
int start; int start;
unsigned long iflags;
for (dpnt = rscsi_disks, i = 0; i < sd_template.dev_max; i++, dpnt++)
if (dpnt->device == SDp) { SCSI_LOG_HLQUEUE(3, printk("sd_detach: <%d,%d,%d,%d>\n",
sdp->host->host_no, sdp->channel, sdp->id,
max_p = 1 << sd_gendisk.minor_shift; sdp->lun));
start = i << sd_gendisk.minor_shift; write_lock_irqsave(&sd_dsk_arr_lock, iflags);
dev = MKDEV_SD_PARTITION(start); for (dsk_nr = 0; dsk_nr < sd_template.dev_max; dsk_nr++) {
wipe_partitions(dev); sdkp = sd_dsk_arr[dsk_nr];
for (j = max_p - 1; j >= 0; j--) if (sdkp->device == sdp) {
sd_sizes[start + j] = 0; sdkp->has_part_table = 0;
sdkp->device = NULL;
devfs_register_partitions (&SD_GENDISK (i), sdkp->capacity = 0;
SD_MINOR_NUMBER (start), 1); /* sdkp->detaching = 1; */
/* unregister_disk() */ break;
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;
} }
}
write_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
if (dsk_nr >= sd_template.dev_max)
return;
max_p = 1 << sd_gendisk.minor_shift;
start = dsk_nr << sd_gendisk.minor_shift;
dev = MKDEV_SD_PARTITION(start);
wipe_partitions(dev);
for (j = max_p - 1; j >= 0; j--)
sd_sizes[start + j] = 0;
devfs_register_partitions (&SD_GENDISK (dsk_nr),
SD_MINOR_NUMBER (start), 1);
/* unregister_disk() */
sdp->attached--;
sd_template.dev_noticed--;
sd_template.nr_dev--;
SD_GENDISK(dsk_nr).nr_real--;
} }
/**
* init_sd- entry point for this driver (both when built in or when
* a module).
*
* Note: this function registers this driver with the scsi mid-level.
**/
static int __init init_sd(void) static int __init init_sd(void)
{ {
SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
sd_template.module = THIS_MODULE; sd_template.module = THIS_MODULE;
return scsi_register_device(&sd_template); return scsi_register_device(&sd_template);
} }
/**
* exit_sd- exit point for this driver (when it is a module).
*
* Note: this function unregisters this driver from the scsi mid-level.
**/
static void __exit exit_sd(void) static void __exit exit_sd(void)
{ {
int i; int k;
Scsi_Disk * sdkp;
SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
scsi_unregister_device(&sd_template); scsi_unregister_device(&sd_template);
for (k = 0; k < N_USED_SD_MAJORS; k++)
for (i = 0; i < N_USED_SD_MAJORS; i++) devfs_unregister_blkdev(SD_MAJOR(k), "sd");
devfs_unregister_blkdev(SD_MAJOR(i), "sd");
sd_registered--; sd_registered--;
if (rscsi_disks != NULL) { if (sd_dsk_arr != NULL) {
kfree(rscsi_disks); for (k = 0; k < sd_template.dev_max; ++k) {
kfree(sd_sizes); sdkp = sd_dsk_arr[k];
kfree((char *) sd); if (sdkp)
vfree(sdkp);
}
vfree(sd_dsk_arr);
} }
for (i = 0; i < N_USED_SD_MAJORS; i++) { if (sd_sizes) vfree(sd_sizes);
del_gendisk(&(sd_gendisks[i])); if (sd) vfree((char *) sd);
blk_clear(SD_MAJOR(i)); for (k = 0; k < N_USED_SD_MAJORS; k++) {
blk_dev[SD_MAJOR(k)].queue = NULL;
del_gendisk(&(sd_gendisks[k]));
blk_clear(SD_MAJOR(k));
} }
sd_template.dev_max = 0; sd_template.dev_max = 0;
if (sd_gendisks != &sd_gendisk) if (sd_gendisks != &sd_gendisk)
kfree(sd_gendisks); vfree(sd_gendisks);
} }
static Scsi_Disk * sd_get_sdisk(int index)
{
Scsi_Disk * sdkp = NULL;
unsigned long iflags;
read_lock_irqsave(&sd_dsk_arr_lock, iflags);
if (sd_dsk_arr && (index >= 0) && (index < sd_template.dev_max))
sdkp = sd_dsk_arr[index];
read_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
return sdkp;
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Eric Youngdale");
MODULE_DESCRIPTION("SCSI disk (sd) driver");
module_init(init_sd); module_init(init_sd);
module_exit(exit_sd); module_exit(exit_sd);
MODULE_LICENSE("GPL");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment