[PATCH] scsi stuff

Andries.Brouwer@cwi.nl
Mon, 10 Jun 2002 11:12:06 +0200 (MEST)


The patch below cleans up some SCSI stuff.

The main purpose is to avoid trying to read the partition table
of a removable disk when the drive has told us that no media
are present. (Right now we try to read a 4K block and fail and
retry and fail, and give an I/O error on the first sector,
then try to read the second sector and fail and retry ...)

Unused fields sector_bit_size and sector_bit_shift in
struct scsi_disk were removed. The field has_part_table
(that has nothing to do with partition tables) was
renamed to has_been_registered . The field ready was
renamed to media_present .
The overly long sd_init_onedisk() was split up.

When we notice that no media are present anymore, the
partitions are removed from /proc/partitions, but the
drive remains, with size 0.

A future patch will remove the field capacity - there are
all too many places where capacities are stored - but the
present patch is large enough already.

There is also a quite independent patch in scsi_error.c
(yesterday someone had an infinite loop retrying to read
bad media) - this patch honours the SCpnt->retries.
In case you applied this already, just ignore the scsi_error.c part.

Also some "Overrides for Emacs" were removed.

Andries

diff -u --recursive --new-file andries/drivers/block/genhd.c brouwer/drivers/block/genhd.c
--- andries/drivers/block/genhd.c Sun Jun 9 07:29:50 2002
+++ brouwer/drivers/block/genhd.c Mon Jun 10 01:58:36 2002
@@ -177,9 +177,10 @@
if (sgp == gendisk_head)
seq_puts(part, "major minor #blocks name\n\n");

- /* show all non-0 size partitions of this disk */
+ /* show the full disk and all non-0 size partitions of it */
for (n = 0; n < (sgp->nr_real << sgp->minor_shift); n++) {
- if (sgp->part[n].nr_sects == 0)
+ int minormask = (1<<sgp->minor_shift) - 1;
+ if ((n & minormask) && sgp->part[n].nr_sects == 0)
continue;
seq_printf(part, "%4d %4d %10d %s\n",
sgp->major, n, sgp->sizes[n],
diff -u --recursive --new-file andries/drivers/scsi/NCR53C9x.c brouwer/drivers/scsi/NCR53C9x.c
--- andries/drivers/scsi/NCR53C9x.c Sun Jun 9 07:28:04 2002
+++ brouwer/drivers/scsi/NCR53C9x.c Sun Jun 9 16:32:34 2002
@@ -2048,7 +2048,7 @@
* and not only for the entire host adapter as it is now, the workaround
* is way to expensive performance wise.
* Instead, it turns out that when this happens the target has disconnected
- * allready but it doesn't show in the interrupt register. Compensate for
+ * already but it doesn't show in the interrupt register. Compensate for
* that here to try and avoid a SCSI bus reset.
*/
if(!esp->fas_premature_intr_workaround && (fifocnt == 1) &&
diff -u --recursive --new-file andries/drivers/scsi/scsi_error.c brouwer/drivers/scsi/scsi_error.c
--- andries/drivers/scsi/scsi_error.c Sun Jun 9 07:26:30 2002
+++ brouwer/drivers/scsi/scsi_error.c Sun Jun 9 22:17:53 2002
@@ -1095,6 +1095,8 @@
*/
STATIC int scsi_eh_completed_normally(Scsi_Cmnd * SCpnt)
{
+ int rtn;
+
/*
* First check the host byte, to see if there is anything in there
* that would indicate what we need to do.
@@ -1102,20 +1104,25 @@
if (host_byte(SCpnt->result) == DID_RESET) {
if (SCpnt->flags & IS_RESETTING) {
/*
- * OK, this is normal. We don't know whether in fact the
- * command in question really needs to be rerun or not -
- * if this was the original data command then the answer is yes,
- * otherwise we just flag it as success.
+ * OK, this is normal. We don't know whether in fact
+ * the command in question really needs to be rerun
+ * or not - if this was the original data command then
+ * the answer is yes, otherwise we just flag it as
+ * success.
*/
SCpnt->flags &= ~IS_RESETTING;
- return NEEDS_RETRY;
+ goto maybe_retry;
}
/*
- * Rats. We are already in the error handler, so we now get to try
- * and figure out what to do next. If the sense is valid, we have
- * a pretty good idea of what to do. If not, we mark it as failed.
+ * Rats. We are already in the error handler, so we now
+ * get to try and figure out what to do next. If the sense
+ * is valid, we have a pretty good idea of what to do.
+ * If not, we mark it as failed.
*/
- return scsi_check_sense(SCpnt);
+ rtn = scsi_check_sense(SCpnt);
+ if (rtn == NEEDS_RETRY)
+ goto maybe_retry;
+ return rtn;
}
if (host_byte(SCpnt->result) != DID_OK) {
return FAILED;
@@ -1127,14 +1134,18 @@
return FAILED;
}
/*
- * Now, check the status byte to see if this indicates anything special.
+ * Now, check the status byte to see if this indicates
+ * anything special.
*/
switch (status_byte(SCpnt->result)) {
case GOOD:
case COMMAND_TERMINATED:
return SUCCESS;
case CHECK_CONDITION:
- return scsi_check_sense(SCpnt);
+ rtn = scsi_check_sense(SCpnt);
+ if (rtn == NEEDS_RETRY)
+ goto maybe_retry;
+ return rtn;
case CONDITION_GOOD:
case INTERMEDIATE_GOOD:
case INTERMEDIATE_C_GOOD:
@@ -1149,6 +1160,14 @@
return FAILED;
}
return FAILED;
+
+ maybe_retry:
+ if ((++SCpnt->retries) < SCpnt->allowed) {
+ return NEEDS_RETRY;
+ } else {
+ /* No more retries - report this one back to upper level */
+ return SUCCESS;
+ }
}

/*
diff -u --recursive --new-file andries/drivers/scsi/scsi_ioctl.c brouwer/drivers/scsi/scsi_ioctl.c
--- andries/drivers/scsi/scsi_ioctl.c Sun Jun 9 07:31:27 2002
+++ brouwer/drivers/scsi/scsi_ioctl.c Mon Jun 10 02:21:16 2002
@@ -127,7 +127,7 @@
/* gag this error, VFS will log it anyway /axboe */
/* printk(KERN_INFO "Disc change detected.\n"); */
break;
- };
+ }
default: /* Fall through for non-removable media */
printk("SCSI error: host %d id %d lun %d return code = %x\n",
dev->host->host_no,
@@ -139,7 +139,7 @@
sense_error(SRpnt->sr_sense_buffer[0]),
SRpnt->sr_sense_buffer[2] & 0xf);

- };
+ }

result = SRpnt->sr_result;

@@ -152,7 +152,7 @@
}

/*
- * This interface is depreciated - users should use the scsi generic (sg)
+ * This interface is deprecated - users should use the scsi generic (sg)
* interface instead, as this is a more flexible approach to performing
* generic SCSI commands on a device.
*
@@ -516,22 +516,3 @@
set_fs(oldfs);
return tmp;
}
-
-/*
- * Overrides for Emacs so that we almost follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff -u --recursive --new-file andries/drivers/scsi/sd.c brouwer/drivers/scsi/sd.c
--- andries/drivers/scsi/sd.c Sun Jun 9 07:27:53 2002
+++ brouwer/drivers/scsi/sd.c Mon Jun 10 10:16:24 2002
@@ -95,7 +95,7 @@
static int check_scsidisk_media_change(kdev_t);
static int fop_revalidate_scsidisk(kdev_t);

-static int sd_init_onedisk(Scsi_Disk * sdkp, int dsk_nr);
+static void sd_init_onedisk(Scsi_Disk * sdkp, int dsk_nr);

static int sd_init(void);
static void sd_finish(void);
@@ -151,22 +151,24 @@
Scsi_Device *sdp;
struct Scsi_Host *shp = hp;
int dsk_nr;
+ kdev_t retval = NODEV;
unsigned long iflags;

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]))
+ sdkp = sd_dsk_arr[dsk_nr];
+ if (sdkp == NULL)
continue;
sdp = sdkp->device;
if (sdp && (sdp->host == shp) && (sdp->id == scsi_id)) {
- read_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
- return MKDEV_SD(dsk_nr);
+ retval = MKDEV_SD(dsk_nr);
+ break;
}
}
read_unlock_irqrestore(&sd_dsk_arr_lock, iflags);
- return NODEV;
+ return retval;
}
#endif

@@ -221,8 +223,8 @@

/* default to most commonly used values */

- diskinfo[0] = 0x40;
- diskinfo[1] = 0x20;
+ diskinfo[0] = 0x40; /* 1 << 6 */
+ diskinfo[1] = 0x20; /* 1 << 5 */
diskinfo[2] = sdkp->capacity >> 11;

/* override with calculated, extended default,
@@ -530,7 +532,7 @@
/*
* If the drive is empty, just let the open fail.
*/
- if ((!sdkp->ready) && !(filp->f_flags & O_NDELAY)) {
+ if ((!sdkp->media_present) && !(filp->f_flags & O_NDELAY)) {
retval = -ENOMEDIUM;
goto error_out;
}
@@ -786,8 +788,7 @@
* that we would ever take a device offline in the first place.
*/
if (sdp->online == FALSE) {
- sdkp->ready = 0;
- sdp->changed = 1;
+ sd_set_media_not_present(sdkp);
return 1; /* This will force a flush, if called from
* check_disk_change */
}
@@ -808,18 +809,17 @@
* it out later once the drive is available
* again. */

- sdkp->ready = 0;
- sdp->changed = 1;
+ sd_set_media_not_present(sdkp);
return 1; /* This will force a flush, if called from
* check_disk_change */
}
/*
- * for removable scsi disk ( FLOPTICAL ) we have to recognise the
- * presence of disk in the drive. This is kept in the Scsi_Disk
+ * For removable scsi disk we have to recognise the presence
+ * of a disk in the drive. This is kept in the Scsi_Disk
* struct and tested at open ! Daniel Roche ( dan@lectra.fr )
*/

- sdkp->ready = 1; /* FLOPTICAL */
+ sdkp->media_present = 1;

retval = sdp->changed;
if (!flag)
@@ -827,63 +827,38 @@
return retval;
}

-/**
- * 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];
- char nbuff[6];
- unsigned char *buffer;
- unsigned long spintime_value = 0;
- int the_result, retries, spintime;
- int sector_size;
- Scsi_Device *sdp;
- 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.
- */
- sd_dskname(dsk_nr, nbuff);
-
- /*
- * If the device is offline, don't try and read capacity or any
- * of the other niceties.
- */
- sdp = sdkp->device;
- if (sdp->online == FALSE)
- return dsk_nr;
-
- /*
- * We need to retry the READ_CAPACITY because a UNIT_ATTENTION is
- * considered a fatal error, and many devices report such an error
- * just after a scsi bus reset.
- */
+static void
+sd_set_media_not_present(Scsi_Disk *sdkp) {
+ sdkp->media_present = 0;
+ sdkp->capacity = 0;
+ sdkp->device->changed = 1;
+}

- SRpnt = scsi_allocate_request(sdp);
- if (!SRpnt) {
- printk(KERN_WARNING "(sd_init_onedisk:) Request allocation "
- "failure.\n");
- return dsk_nr;
+static int
+sd_media_not_present(Scsi_Disk *sdkp, Scsi_Request *SRpnt) {
+ int the_result = SRpnt->sr_result;
+
+ if (the_result != 0
+ && (driver_byte(the_result) & DRIVER_SENSE) != 0
+ && (SRpnt->sr_sense_buffer[2] == NOT_READY ||
+ SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION)
+ && SRpnt->sr_sense_buffer[12] == 0x3A /* medium not present */) {
+ sd_set_media_not_present(sdkp);
+ return 1;
}
+ return 0;
+}

- buffer = kmalloc(512, GFP_DMA);
- if (!buffer) {
- printk(KERN_WARNING "(sd_init_onedisk:) Memory allocation "
- "failure.\n");
- scsi_release_request(SRpnt);
- return dsk_nr;
- }
+/*
+ * spinup disk - called only in sd_init_onedisk()
+ */
+static void
+sd_spinup_disk(Scsi_Disk *sdkp, char *diskname,
+ Scsi_Request *SRpnt, unsigned char *buffer) {
+ unsigned char cmd[10];
+ Scsi_Device *sdp = sdkp->device;
+ unsigned long spintime_value = 0;
+ int the_result, retries, spintime;

spintime = 0;

@@ -895,15 +870,16 @@
while (retries < 3) {
cmd[0] = TEST_UNIT_READY;
cmd[1] = (sdp->scsi_level <= SCSI_2) ?
- ((sdp->lun << 5) & 0xe0) : 0;
+ ((sdp->lun << 5) & 0xe0) : 0;
memset((void *) &cmd[2], 0, 8);
+
SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0;
SRpnt->sr_sense_buffer[2] = 0;
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++;
@@ -917,16 +893,8 @@
* any media in it, don't bother with any of the rest of
* this crap.
*/
- if( the_result != 0
- && ((driver_byte(the_result) & DRIVER_SENSE) != 0)
- && SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION
- && SRpnt->sr_sense_buffer[12] == 0x3A ) {
- sdkp->capacity = 0x1fffff;
- sector_size = 512;
- sdp->changed = 1;
- sdkp->ready = 0;
- break;
- }
+ if (sd_media_not_present(sdkp, SRpnt))
+ return;

/* Look for non-removable devices that return NOT_READY.
* Issue command to spin up drive for these cases. */
@@ -935,10 +903,10 @@
unsigned long time1;
if (!spintime) {
printk(KERN_NOTICE "%s: Spinning up disk...",
- nbuff);
+ diskname);
cmd[0] = START_STOP;
cmd[1] = (sdp->scsi_level <= SCSI_2) ?
- ((sdp->lun << 5) & 0xe0) : 0;
+ ((sdp->lun << 5) & 0xe0) : 0;
cmd[1] |= 1; /* Return immediately */
memset((void *) &cmd[2], 0, 8);
cmd[4] = 1; /* Start spin cycle */
@@ -963,65 +931,63 @@
}
} while (the_result && spintime &&
time_after(spintime_value + 100 * HZ, jiffies));
+
if (spintime) {
if (the_result)
printk("not responding...\n");
else
printk("ready\n");
}
+}
+
+/*
+ * read disk capacity - called only in sd_init_onedisk()
+ */
+static void
+sd_read_capacity(Scsi_Disk *sdkp, char *diskname,
+ Scsi_Request *SRpnt, unsigned char *buffer) {
+ unsigned char cmd[10];
+ Scsi_Device *sdp = sdkp->device;
+ int the_result, retries;
+ int sector_size;
+
retries = 3;
do {
cmd[0] = READ_CAPACITY;
cmd[1] = (sdp->scsi_level <= SCSI_2) ?
- ((sdp->lun << 5) & 0xe0) : 0;
+ ((sdp->lun << 5) & 0xe0) : 0;
memset((void *) &cmd[2], 0, 8);
memset((void *) buffer, 0, 8);
+
SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0;
SRpnt->sr_sense_buffer[2] = 0;
-
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);
+
+ if (sd_media_not_present(sdkp, SRpnt))
+ return;

the_result = SRpnt->sr_result;
retries--;

} while (the_result && retries);

- /*
- * The SCSI standard says:
- * "READ CAPACITY is necessary for self configuring software"
- * While not mandatory, support of READ CAPACITY is strongly
- * encouraged.
- * We used to die if we couldn't successfully do a READ CAPACITY.
- * But, now we go on about our way. The side effects of this are
- *
- * 1. We can't know block size with certainty. I have said
- * "512 bytes is it" as this is most common.
- *
- * 2. Recovery from when someone attempts to read past the
- * end of the raw device will be slower.
- */
-
if (the_result) {
printk(KERN_NOTICE "%s : READ CAPACITY failed.\n"
"%s : status=%x, message=%02x, host=%d, driver=%02x \n",
- nbuff, nbuff,
+ diskname, diskname,
status_byte(the_result),
msg_byte(the_result),
host_byte(the_result),
- driver_byte(the_result)
- );
+ driver_byte(the_result));
+
if (driver_byte(the_result) & DRIVER_SENSE)
print_req_sense("sd", SRpnt);
else
- printk("%s : sense not available. \n", nbuff);
-
- printk(KERN_NOTICE "%s : block size assumed to be 512 "
- "bytes, disk size 1GB. \n", nbuff);
- sdkp->capacity = 0x1fffff;
- sector_size = 512;
+ printk("%s : sense not available. \n", diskname);

/* Set dirty bit for removable devices if not ready -
* sometimes drives will not report this properly. */
@@ -1029,130 +995,193 @@
SRpnt->sr_sense_buffer[2] == NOT_READY)
sdp->changed = 1;

- } else {
+ /* Either no media are present but the drive didnt tell us,
+ or they are present but the read capacity command fails */
+ /* sdkp->media_present = 0; -- not always correct */
+ sdkp->capacity = 0x200000; /* 1 GB - random */
+
+ return;
+ }
+
+ sdkp->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];
+
+ if (sector_size == 0) {
+ sector_size = 512;
+ printk(KERN_NOTICE "%s : sector size 0 reported, "
+ "assuming 512.\n", diskname);
+ }
+
+ if (sector_size != 512 &&
+ sector_size != 1024 &&
+ sector_size != 2048 &&
+ sector_size != 4096 &&
+ sector_size != 256) {
+ printk(KERN_NOTICE "%s : unsupported sector size "
+ "%d.\n", diskname, sector_size);
/*
- * FLOPTICAL, if read_capa is ok, drive is assumed to be ready
+ * The user might want to re-format the drive with
+ * a supported sectorsize. Once this happens, it
+ * would be relatively trivial to set the thing up.
+ * For this reason, we leave the thing in the table.
*/
- sdkp->ready = 1;
+ sdkp->capacity = 0;
+ }
+ {
+ /*
+ * 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 hard_sector = sector_size;
+ int sz = sdkp->capacity * (hard_sector/256);
+ request_queue_t *queue = &sdp->request_queue;
+
+ blk_queue_hardsect_size(queue, hard_sector);
+ printk(KERN_NOTICE "SCSI device %s: "
+ "%d %d-byte hdwr sectors (%d MB)\n",
+ diskname, sdkp->capacity,
+ hard_sector, (sz/2 - sz/1250 + 974)/1950);
+ }
+
+ /* Rescale capacity to 512-byte units */
+ if (sector_size == 4096)
+ sdkp->capacity <<= 3;
+ if (sector_size == 2048)
+ sdkp->capacity <<= 2;
+ if (sector_size == 1024)
+ sdkp->capacity <<= 1;
+ if (sector_size == 256)
+ sdkp->capacity >>= 1;

- sdkp->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];
-
- if (sector_size == 0) {
- sector_size = 512;
- printk(KERN_NOTICE "%s : sector size 0 reported, "
- "assuming 512.\n", nbuff);
- }
- if (sector_size != 512 &&
- sector_size != 1024 &&
- sector_size != 2048 &&
- sector_size != 4096 &&
- sector_size != 256) {
- printk(KERN_NOTICE "%s : unsupported sector size "
- "%d.\n", nbuff, sector_size);
- /*
- * The user might want to re-format the drive with
- * a supported sectorsize. Once this happens, it
- * would be relatively trivial to set the thing up.
- * For this reason, we leave the thing in the table.
- */
- sdkp->capacity = 0;
- }
- {
- /*
- * 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 hard_sector = sector_size;
- int sz = sdkp->capacity * (hard_sector/256);
- request_queue_t *queue = &sdp->request_queue;
-
- blk_queue_hardsect_size(queue, hard_sector);
- printk(KERN_NOTICE "SCSI device %s: "
- "%d %d-byte hdwr sectors (%d MB)\n",
- nbuff, sdkp->capacity,
- hard_sector, (sz/2 - sz/1250 + 974)/1950);
- }
+ sdkp->device->sector_size = sector_size;
+}

- /* Rescale capacity to 512-byte units */
- if (sector_size == 4096)
- sdkp->capacity <<= 3;
- if (sector_size == 2048)
- sdkp->capacity <<= 2;
- if (sector_size == 1024)
- sdkp->capacity <<= 1;
- if (sector_size == 256)
- sdkp->capacity >>= 1;
+/*
+ * read write protect setting, if possible - called only in sd_init_onedisk()
+ */
+static void
+sd_read_write_protect_flag(Scsi_Disk *sdkp, char *diskname,
+ Scsi_Request *SRpnt, unsigned char *buffer) {
+ Scsi_Device *sdp = sdkp->device;
+ unsigned char cmd[8];
+ int the_result;
+
+ /*
+ * For removable scsi disks we have to recognise the
+ * Write Protect Flag. This flag is kept in the Scsi_Disk
+ * struct and tested at open !
+ * Daniel Roche ( dan@lectra.fr )
+ *
+ * Changed to get all pages (0x3f) rather than page 1 to
+ * get around devices which do not have a page 1. Since
+ * we're only interested in the header anyway, this should
+ * be fine.
+ * -- Matthew Dharm (mdharm-scsi@one-eyed-alien.net)
+ *
+ * As it turns out, some devices return an error for
+ * every MODE_SENSE request except one for page 0.
+ * So, we should also try that. --aeb
+ */
+
+ memset((void *) &cmd[0], 0, 8);
+ cmd[0] = MODE_SENSE;
+ cmd[1] = (sdp->scsi_level <= SCSI_2) ?
+ ((sdp->lun << 5) & 0xe0) : 0;
+ cmd[2] = 0x3f; /* Get all pages */
+ cmd[4] = 255; /* Ask for 255 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;
+ SRpnt->sr_data_direction = SCSI_DATA_READ;
+
+ scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
+ 512, SD_TIMEOUT, MAX_RETRIES);
+
+ the_result = SRpnt->sr_result;
+
+ if (the_result) {
+ printk("%s: test WP failed, assume Write Enabled\n",
+ diskname);
+ /* alternatively, try page 0 */
+ } else {
+ sdkp->write_prot = ((buffer[2] & 0x80) != 0);
+ printk(KERN_NOTICE "%s: Write Protect is %s\n", diskname,
+ sdkp->write_prot ? "on" : "off");
}
+}

+/**
+ * sd_init_onedisk - called the first time a new disk is seen,
+ * performs disk spin up, read_capacity, etc.
+ * @sdkp: pointer to associated Scsi_Disk object
+ * @dsk_nr: disk number within this driver (e.g. 0->/dev/sda,
+ * 1->/dev/sdb, etc)
+ *
+ * Note: this function is local to this driver.
+ **/
+static void
+sd_init_onedisk(Scsi_Disk * sdkp, int dsk_nr) {
+ char diskname[40];
+ unsigned char *buffer;
+ Scsi_Device *sdp;
+ Scsi_Request *SRpnt;
+
+ SCSI_LOG_HLQUEUE(3, printk("sd_init_onedisk: dsk_nr=%d\n", dsk_nr));

/*
- * Unless otherwise specified, this is not write protected.
+ * Get the name of the disk, in case we need to log it somewhere.
*/
- sdkp->write_prot = 0;
- if (sdp->removable && sdkp->ready) {
- /* FLOPTICAL */
+ sd_dskname(dsk_nr, diskname);

- /*
- * For removable scsi disk ( FLOPTICAL ) we have to recognise
- * the Write Protect Flag. This flag is kept in the Scsi_Disk
- * struct and tested at open !
- * Daniel Roche ( dan@lectra.fr )
- *
- * Changed to get all pages (0x3f) rather than page 1 to
- * get around devices which do not have a page 1. Since
- * we're only interested in the header anyway, this should
- * be fine.
- * -- Matthew Dharm (mdharm-scsi@one-eyed-alien.net)
- *
- * As it turns out, some devices return an error for
- * every MODE_SENSE request except one for page 0.
- * So, we should also try that. --aeb
- */
+ /*
+ * If the device is offline, don't try and read capacity or any
+ * of the other niceties.
+ */
+ sdp = sdkp->device;
+ if (sdp->online == FALSE)
+ return;

- memset((void *) &cmd[0], 0, 8);
- cmd[0] = MODE_SENSE;
- cmd[1] = (sdp->scsi_level <= SCSI_2) ?
- ((sdp->lun << 5) & 0xe0) : 0;
- cmd[2] = 0x3f; /* Get all pages */
- cmd[4] = 255; /* Ask for 255 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;
+ SRpnt = scsi_allocate_request(sdp);
+ if (!SRpnt) {
+ printk(KERN_WARNING "(sd_init_onedisk:) Request allocation "
+ "failure.\n");
+ return;
+ }

- /* same code as READCAPA !! */
- SRpnt->sr_data_direction = SCSI_DATA_READ;
- scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
- 512, SD_TIMEOUT, MAX_RETRIES);
+ buffer = kmalloc(512, GFP_DMA);
+ if (!buffer) {
+ printk(KERN_WARNING "(sd_init_onedisk:) Memory allocation "
+ "failure.\n");
+ goto leave;
+ }

- the_result = SRpnt->sr_result;
+ /* defaults, until the device tells us otherwise */
+ sdkp->capacity = 0;
+ sdkp->device->sector_size = 512;
+ sdkp->media_present = 1;
+ sdkp->write_prot = 0;

- if (the_result) {
- printk("%s: test WP failed, assume Write Enabled\n",
- nbuff);
- /* alternatively, try page 0 */
- } else {
- sdkp->write_prot = ((buffer[2] & 0x80) != 0);
- printk(KERN_NOTICE "%s: Write Protect is %s\n", nbuff,
- sdkp->write_prot ? "on" : "off");
- }
+ sd_spinup_disk(sdkp, diskname, SRpnt, buffer);
+
+ if (sdkp->media_present)
+ sd_read_capacity(sdkp, diskname, SRpnt, buffer);
+
+ if (sdp->removable && sdkp->media_present)
+ sd_read_write_protect_flag(sdkp, diskname, SRpnt, buffer);

- } /* check for write protect */
SRpnt->sr_device->ten = 1;
SRpnt->sr_device->remap = 1;
- SRpnt->sr_device->sector_size = sector_size;
- /* Wake up a process waiting for device */
+
+ leave:
scsi_release_request(SRpnt);
- SRpnt = NULL;

kfree(buffer);
- return dsk_nr;
}

/*
@@ -1275,18 +1304,15 @@
vfree(sd_gendisks[k].flags);
}
cleanup_mem:
- if (sd_gendisks) vfree(sd_gendisks);
+ vfree(sd_gendisks);
sd_gendisks = NULL;
- if (sd) vfree(sd);
+ vfree(sd);
sd = NULL;
- if (sd_sizes) vfree(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);
- }
+ for (k = 0; k < sd_template.dev_max; ++k)
+ vfree(sd_dsk_arr[k]);
vfree(sd_dsk_arr);
sd_dsk_arr = NULL;
}
@@ -1321,12 +1347,12 @@
sdkp = sd_get_sdisk(k);
if (sdkp && (0 == sdkp->capacity) && sdkp->device) {
sd_init_onedisk(sdkp, k);
- if (!sdkp->has_part_table) {
+ if (!sdkp->has_been_registered) {
sd_sizes[k << 4] = sdkp->capacity;
register_disk(&SD_GENDISK(k), MKDEV_SD(k),
1<<4, &sd_fops,
sdkp->capacity);
- sdkp->has_part_table = 1;
+ sdkp->has_been_registered = 1;
}
}
}
@@ -1372,7 +1398,7 @@
unsigned int devnum;
Scsi_Disk *sdkp;
int dsk_nr;
- char nbuff[6];
+ char diskname[6];
unsigned long iflags;

if ((NULL == sdp) ||
@@ -1393,8 +1419,8 @@
for (dsk_nr = 0; dsk_nr < sd_template.dev_max; dsk_nr++) {
sdkp = sd_dsk_arr[dsk_nr];
if (!sdkp->device) {
+ memset(sdkp, 0, sizeof(Scsi_Disk));
sdkp->device = sdp;
- sdkp->has_part_table = 0;
break;
}
}
@@ -1412,10 +1438,10 @@
SD_GENDISK(dsk_nr).de_arr[devnum] = sdp->de;
if (sdp->removable)
SD_GENDISK(dsk_nr).flags[devnum] |= GENHD_FL_REMOVABLE;
- sd_dskname(dsk_nr, nbuff);
+ sd_dskname(dsk_nr, diskname);
printk(KERN_NOTICE "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);
+ diskname, sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
return 0;
}

@@ -1436,8 +1462,8 @@
Scsi_Disk * sdkp;
Scsi_Device * sdp;

- SCSI_LOG_HLQUEUE(3, printk("revalidate_scsidisk: dsk_nr=%d\n",
- 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;
@@ -1457,6 +1483,7 @@
sd_init_onedisk(sdkp, dsk_nr);

grok_partitions(dev, sdkp->capacity);
+
leave:
sdp->busy = 0;
return res;
@@ -1494,7 +1521,7 @@
for (dsk_nr = 0; dsk_nr < sd_template.dev_max; dsk_nr++) {
sdkp = sd_dsk_arr[dsk_nr];
if (sdkp->device == sdp) {
- sdkp->has_part_table = 0;
+ sdkp->has_been_registered = 0;
sdkp->device = NULL;
sdkp->capacity = 0;
/* sdkp->detaching = 1; */
diff -u --recursive --new-file andries/drivers/scsi/sd.h brouwer/drivers/scsi/sd.h
--- andries/drivers/scsi/sd.h Sun Jun 9 07:30:31 2002
+++ brouwer/drivers/scsi/sd.h Mon Jun 10 10:00:21 2002
@@ -11,9 +11,6 @@
*/
#ifndef _SD_H
#define _SD_H
-/*
- $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"
@@ -26,13 +23,11 @@
extern struct hd_struct *sd;

typedef struct scsi_disk {
- unsigned capacity; /* size in blocks */
+ unsigned capacity; /* size in 512-byte sectors */
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 */
+ unsigned char media_present;
+ unsigned char write_prot;
+ unsigned has_been_registered:1;
} Scsi_Disk;

extern int revalidate_scsidisk(kdev_t dev, int maxusage);
@@ -48,22 +43,3 @@
#define SD_PARTITION(i) (((major(i) & SD_MAJOR_MASK) << 8) | (minor(i) & 255))

#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff -u --recursive --new-file andries/drivers/scsi/sr.h brouwer/drivers/scsi/sr.h
--- andries/drivers/scsi/sr.h Sun Jun 9 07:28:56 2002
+++ brouwer/drivers/scsi/sr.h Sun Jun 9 15:40:26 2002
@@ -24,8 +24,6 @@
Scsi_Device *device;
unsigned int vendor; /* vendor code, see sr_vendor.c */
unsigned long ms_offset; /* for reading multisession-CD's */
- unsigned char sector_bit_size; /* sector size = 2^sector_bit_size */
- unsigned char sector_bit_shift; /* sectors/FS block = 2^sector_bit_shift */
unsigned needs_sector_size:1; /* needs to get sector size */
unsigned use:1; /* is this device still supportable */
unsigned xa_flag:1; /* CD has XA sectors ? */
diff -u --recursive --new-file andries/fs/partitions/check.c brouwer/fs/partitions/check.c
--- andries/fs/partitions/check.c Sun Jun 9 07:28:55 2002
+++ brouwer/fs/partitions/check.c Mon Jun 10 10:19:44 2002
@@ -412,8 +412,8 @@

g->part[first_minor].nr_sects = size;

- /* No such device or no minors to use for partitions */
- if (!size || minors == 1)
+ /* No minors to use for partitions */
+ if (minors == 1)
return;

if (g->sizes) {
@@ -422,6 +422,11 @@
g->sizes[i] = 0;
}
blk_size[g->major] = g->sizes;
+
+ /* No such device (e.g., media were just removed) */
+ if (!size)
+ return;
+
check_partition(g, mk_kdev(g->major, first_minor), 1 + first_minor);

/*
diff -u --recursive --new-file andries/include/scsi/scsi.h brouwer/include/scsi/scsi.h
--- andries/include/scsi/scsi.h Sun Jun 9 07:31:29 2002
+++ brouwer/include/scsi/scsi.h Mon Jun 10 00:34:54 2002
@@ -223,23 +223,4 @@
/* Used to get the PCI location of a device */
#define SCSI_IOCTL_GET_PCI 0x5387

-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
-
#endif
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/