patch-pre2.0.12 linux/drivers/scsi/sr.c
Next file: linux/drivers/sound/Config.in
Previous file: linux/drivers/scsi/sd.c
Back to the patch index
Back to the overall index
- Lines: 375
- Date:
Tue Jun 4 12:56:48 1996
- Orig file:
pre2.0.11/linux/drivers/scsi/sr.c
- Orig date:
Mon Jun 3 16:46:56 1996
diff -u --recursive --new-file pre2.0.11/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
@@ -40,7 +40,7 @@
#include "constants.h"
#define MAX_RETRIES 3
-#define SR_TIMEOUT (150 * HZ)
+#define SR_TIMEOUT (15 * HZ)
static int sr_init(void);
static void sr_finish(void);
@@ -152,12 +152,50 @@
{
int result = SCpnt->result;
int this_count = SCpnt->this_count;
+ int good_sectors = (result == 0 ? this_count : 0);
+ int block_sectors = 0;
#ifdef DEBUG
printk("sr.c done: %x %x\n",result, SCpnt->request.bh->b_data);
#endif
- if (!result)
- { /* No error */
+ /*
+ Handle MEDIUM ERRORs or VOLUME OVERFLOWs that indicate partial success.
+ Since this is a relatively rare error condition, no care is taken to
+ avoid unnecessary additional work such as memcpy's that could be avoided.
+ */
+
+ if (driver_byte(result) != 0 && /* An error occurred */
+ SCpnt->sense_buffer[0] == 0xF0 && /* Sense data is valid */
+ (SCpnt->sense_buffer[2] == MEDIUM_ERROR ||
+ SCpnt->sense_buffer[2] == VOLUME_OVERFLOW))
+ {
+ long error_sector = (SCpnt->sense_buffer[3] << 24) |
+ (SCpnt->sense_buffer[4] << 16) |
+ (SCpnt->sense_buffer[5] << 8) |
+ SCpnt->sense_buffer[6];
+ int device_nr = DEVICE_NR(SCpnt->request.rq_dev);
+ if (SCpnt->request.bh != NULL)
+ block_sectors = SCpnt->request.bh->b_size >> 9;
+ if (block_sectors < 4) block_sectors = 4;
+ if (scsi_CDs[device_nr].sector_size == 2048)
+ error_sector <<= 2;
+ error_sector &= ~ (block_sectors - 1);
+ good_sectors = error_sector - SCpnt->request.sector;
+ if (good_sectors < 0 || good_sectors >= this_count)
+ good_sectors = 0;
+ /*
+ The SCSI specification allows for the value returned by READ
+ CAPACITY to be up to 75 2K sectors past the last readable
+ block. Therefore, if we hit a medium error within the last
+ 75 2K sectors, we decrease the saved size value.
+ */
+ if ((error_sector >> 1) < sr_sizes[device_nr] &&
+ scsi_CDs[device_nr].capacity - error_sector < 4*75)
+ sr_sizes[device_nr] = error_sector >> 1;
+ }
+
+ if (good_sectors > 0)
+ { /* Some sectors were read successfully. */
if (SCpnt->use_sg == 0) {
if (SCpnt->buffer != SCpnt->request.buffer)
{
@@ -165,20 +203,20 @@
offset = (SCpnt->request.sector % 4) << 9;
memcpy((char *)SCpnt->request.buffer,
(char *)SCpnt->buffer + offset,
- this_count << 9);
+ good_sectors << 9);
/* Even though we are not using scatter-gather, we look
* ahead and see if there is a linked request for the
* other half of this buffer. If there is, then satisfy
* it. */
- if((offset == 0) && this_count == 2 &&
- SCpnt->request.nr_sectors > this_count &&
+ if((offset == 0) && good_sectors == 2 &&
+ SCpnt->request.nr_sectors > good_sectors &&
SCpnt->request.bh &&
SCpnt->request.bh->b_reqnext &&
SCpnt->request.bh->b_reqnext->b_size == 1024) {
memcpy((char *)SCpnt->request.bh->b_reqnext->b_data,
(char *)SCpnt->buffer + 1024,
1024);
- this_count += 2;
+ good_sectors += 2;
};
scsi_free(SCpnt->buffer, 2048);
@@ -196,15 +234,15 @@
};
};
scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */
- if(SCpnt->request.sector % 4) this_count -= 2;
+ if(SCpnt->request.sector % 4) good_sectors -= 2;
/* See if there is a padding record at the end that needs to be removed */
- if(this_count > SCpnt->request.nr_sectors)
- this_count -= 2;
+ if(good_sectors > SCpnt->request.nr_sectors)
+ good_sectors -= 2;
};
#ifdef DEBUG
printk("(%x %x %x) ",SCpnt->request.bh, SCpnt->request.nr_sectors,
- this_count);
+ good_sectors);
#endif
if (SCpnt->request.nr_sectors > this_count)
{
@@ -214,12 +252,16 @@
SCpnt->request.sector, this_count);
}
- SCpnt = end_scsi_request(SCpnt, 1, this_count); /* All done */
- requeue_sr_request(SCpnt);
- return;
- } /* Normal completion */
+ SCpnt = end_scsi_request(SCpnt, 1, good_sectors); /* All done */
+ if (result == 0)
+ {
+ requeue_sr_request(SCpnt);
+ return;
+ }
+ }
- /* We only come through here if we have an error of some kind */
+ if (good_sectors == 0) {
+ /* We only come through here if no sectors were read successfully. */
/* Free up any indirection buffers we allocated for DMA purposes. */
if (SCpnt->use_sg) {
@@ -229,14 +271,16 @@
for(i=0; i<SCpnt->use_sg; i++) {
if (sgpnt[i].alt_address) {
scsi_free(sgpnt[i].address, sgpnt[i].length);
- };
- };
+ }
+ }
scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */
} else {
if (SCpnt->buffer != SCpnt->request.buffer)
scsi_free(SCpnt->buffer, SCpnt->bufflen);
- };
+ }
+ }
+
if (driver_byte(result) != 0) {
if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) {
if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
@@ -267,13 +311,37 @@
}
}
-
+
if (SCpnt->sense_buffer[2] == NOT_READY) {
- printk("CDROM not ready. Make sure you have a disc in the drive.\n");
+ printk("CD-ROM not ready. Make sure you have a disc in the drive.\n");
SCpnt = end_scsi_request(SCpnt, 0, this_count);
requeue_sr_request(SCpnt); /* Do next request */
return;
- };
+ }
+
+ if (SCpnt->sense_buffer[2] == MEDIUM_ERROR) {
+ printk("scsi%d: MEDIUM ERROR on "
+ "channel %d, id %d, lun %d, CDB: ",
+ SCpnt->host->host_no, (int) SCpnt->channel,
+ (int) SCpnt->target, (int) SCpnt->lun);
+ print_command(SCpnt->cmnd);
+ print_sense("sr", SCpnt);
+ SCpnt = end_scsi_request(SCpnt, 0, block_sectors);
+ requeue_sr_request(SCpnt);
+ return;
+ }
+
+ if (SCpnt->sense_buffer[2] == VOLUME_OVERFLOW) {
+ printk("scsi%d: VOLUME OVERFLOW on "
+ "channel %d, id %d, lun %d, CDB: ",
+ SCpnt->host->host_no, (int) SCpnt->channel,
+ (int) SCpnt->target, (int) SCpnt->lun);
+ print_command(SCpnt->cmnd);
+ print_sense("sr", SCpnt);
+ SCpnt = end_scsi_request(SCpnt, 0, block_sectors);
+ requeue_sr_request(SCpnt);
+ return;
+ }
}
/* We only get this far if we have an error we have not recognized */
@@ -433,7 +501,7 @@
memset(buf,0,40);
*((unsigned long*)buf) = 0;
*((unsigned long*)buf+1) = 12;
- cmd[0] = 0x1a;
+ cmd[0] = MODE_SENSE;
cmd[2] = 1;
cmd[4] = 12;
rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
@@ -454,7 +522,7 @@
memset(buf,0,40);
*((unsigned long*)buf) = 12; /* sending 12 bytes... */
*((unsigned long*)buf+1) = 0;
- cmd[0] = 0x15;
+ cmd[0] = MODE_SELECT;
cmd[1] = (1 << 4);
cmd[4] = 12;
send = &cmd[6]; /* this is a 6-Byte command */
@@ -477,10 +545,11 @@
#ifdef DEBUG
printk(KERN_DEBUG "sr_photocd: use SONY/PIONEER code\n");
#endif
+ get_sectorsize(MINOR(inode->i_rdev)); /* spinup (avoid timeout) */
memset(buf,0,40);
*((unsigned long*)buf) = 0x0; /* we send nothing... */
*((unsigned long*)buf+1) = 0x0c; /* and receive 0x0c bytes */
- cmd[0] = 0x43; /* Read TOC */
+ cmd[0] = READ_TOC;
cmd[8] = 0x0c;
cmd[9] = 0x40;
rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
@@ -488,11 +557,11 @@
if (rc != 0) {
if (rc != 0x28000002) /* drop "not ready" */
- printk(KERN_WARNING "sr_photocd: ioctl error (SONY): 0x%x\n",rc);
+ printk(KERN_WARNING "sr_photocd: ioctl error (SONY/PIONEER): 0x%x\n",rc);
break;
}
if ((rec[0] << 8) + rec[1] != 0x0a) {
- printk(KERN_INFO "sr_photocd: (SONY) Hmm, seems the CDROM doesn't support multisession CD's\n");
+ printk(KERN_INFO "sr_photocd: (SONY/PIONEER) Hmm, seems the CDROM doesn't support multisession CD's\n");
no_multi = 1;
break;
}
@@ -523,31 +592,31 @@
static int sr_open(struct inode * inode, struct file * filp)
{
- if(MINOR(inode->i_rdev) >= sr_template.nr_dev ||
- !scsi_CDs[MINOR(inode->i_rdev)].device) return -ENXIO; /* No such device */
-
- if (filp->f_mode & 2)
- return -EROFS;
-
+ if(MINOR(inode->i_rdev) >= sr_template.nr_dev ||
+ !scsi_CDs[MINOR(inode->i_rdev)].device) return -ENXIO; /* No such device */
+
+ if (filp->f_mode & 2)
+ return -EROFS;
+
check_disk_change(inode->i_rdev);
- if(!scsi_CDs[MINOR(inode->i_rdev)].device->access_count++)
+ if(!scsi_CDs[MINOR(inode->i_rdev)].device->access_count++)
sr_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
- if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)
+ if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)
(*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)++;
- if(sr_template.usage_count) (*sr_template.usage_count)++;
+ if(sr_template.usage_count) (*sr_template.usage_count)++;
- sr_photocd(inode);
+ sr_photocd(inode);
- /* If this device did not have media in the drive at boot time, then
- * we would have been unable to get the sector size. Check to see if
- * this is the case, and try again.
- */
-
- if(scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size)
+ /* If this device did not have media in the drive at boot time, then
+ * we would have been unable to get the sector size. Check to see if
+ * this is the case, and try again.
+ */
+
+ if(scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size)
get_sectorsize(MINOR(inode->i_rdev));
-
- return 0;
+
+ return 0;
}
@@ -1058,42 +1127,42 @@
static int sr_init()
{
- int i;
-
- if(sr_template.dev_noticed == 0) return 0;
-
- if(!sr_registered) {
+ int i;
+
+ if(sr_template.dev_noticed == 0) return 0;
+
+ if(!sr_registered) {
if (register_blkdev(MAJOR_NR,"sr",&sr_fops)) {
printk("Unable to get major %d for SCSI-CD\n",MAJOR_NR);
return 1;
}
sr_registered++;
- }
+ }
+
-
- if (scsi_CDs) return 0;
- sr_template.dev_max = sr_template.dev_noticed + SR_EXTRA_DEVS;
- scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC);
- memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD));
-
- sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC);
- memset(sr_sizes, 0, sr_template.dev_max * sizeof(int));
-
- sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max *
- sizeof(int), GFP_ATOMIC);
- for(i=0;i<sr_template.dev_max;i++) sr_blocksizes[i] = 2048;
- blksize_size[MAJOR_NR] = sr_blocksizes;
- return 0;
+ if (scsi_CDs) return 0;
+ sr_template.dev_max = sr_template.dev_noticed + SR_EXTRA_DEVS;
+ scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC);
+ memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD));
+
+ sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC);
+ memset(sr_sizes, 0, sr_template.dev_max * sizeof(int));
+
+ sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max *
+ sizeof(int), GFP_ATOMIC);
+ for(i=0;i<sr_template.dev_max;i++) sr_blocksizes[i] = 2048;
+ blksize_size[MAJOR_NR] = sr_blocksizes;
+ return 0;
}
void sr_finish()
{
int i;
- blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
- blk_size[MAJOR_NR] = sr_sizes;
-
- for (i = 0; i < sr_template.nr_dev; ++i)
+ blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+ blk_size[MAJOR_NR] = sr_sizes;
+
+ for (i = 0; i < sr_template.nr_dev; ++i)
{
/* If we have already seen this, then skip it. Comes up
* with loadable modules. */
@@ -1114,15 +1183,15 @@
}
- /* If our host adapter is capable of scatter-gather, then we increase
- * the read-ahead to 16 blocks (32 sectors). If not, we use
- * a two block (4 sector) read ahead. */
- if(scsi_CDs[0].device && scsi_CDs[0].device->host->sg_tablesize)
+ /* If our host adapter is capable of scatter-gather, then we increase
+ * the read-ahead to 16 blocks (32 sectors). If not, we use
+ * a two block (4 sector) read ahead. */
+ if(scsi_CDs[0].device && scsi_CDs[0].device->host->sg_tablesize)
read_ahead[MAJOR_NR] = 32; /* 32 sector read-ahead. Always removable. */
- else
+ else
read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */
-
- return;
+
+ return;
}
static void sr_detach(Scsi_Device * SDp)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this