summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/sr.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/sr.c')
-rw-r--r--drivers/scsi/sr.c376
1 files changed, 254 insertions, 122 deletions
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 82dfe55e0..5d58df15a 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -1,6 +1,6 @@
/*
* sr.c Copyright (C) 1992 David Giller
- * Copyright (C) 1993, 1994 Eric Youngdale
+ * Copyright (C) 1993, 1994, 1995 Eric Youngdale
*
* adapted from:
* sd.c Copyright (C) 1992 Drew Eckhardt
@@ -12,11 +12,15 @@
* Modified by Eric Youngdale ericy@cais.com to
* add scatter-gather, multiple outstanding request, and other
* enhancements.
+ *
+ * Modified by Eric Youngdale eric@aib.com to support loadable
+ * low-level scsi drivers.
*/
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/mm.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/cdrom.h>
@@ -31,17 +35,18 @@
#include "constants.h"
#define MAX_RETRIES 3
-#define SR_TIMEOUT 5000
+#define SR_TIMEOUT 15000
static void sr_init(void);
static void sr_finish(void);
-static void sr_attach(Scsi_Device *);
+static int sr_attach(Scsi_Device *);
static int sr_detect(Scsi_Device *);
+static void sr_detach(Scsi_Device *);
struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", TYPE_ROM,
SCSI_CDROM_MAJOR, 0, 0, 0, 1,
sr_detect, sr_init,
- sr_finish, sr_attach, NULL};
+ sr_finish, sr_attach, sr_detach};
Scsi_CD * scsi_CDs;
static int * sr_sizes;
@@ -61,6 +66,8 @@ static void sr_release(struct inode * inode, struct file * file)
sync_dev(inode->i_rdev);
if(! --scsi_CDs[MINOR(inode->i_rdev)].device->access_count)
sr_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
+ if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)
+ (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)--;
}
static struct file_operations sr_fops =
@@ -233,14 +240,16 @@ static void rw_intr (Scsi_Cmnd * SCpnt)
}
if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) {
- printk("CD-ROM error: Drive reports ILLEGAL REQUEST.\n");
+ printk("CD-ROM error: ");
+ print_sense("sr", SCpnt);
+ printk("command was: ");
+ print_command(SCpnt->cmnd);
if (scsi_CDs[DEVICE_NR(SCpnt->request.dev)].ten) {
scsi_CDs[DEVICE_NR(SCpnt->request.dev)].ten = 0;
requeue_sr_request(SCpnt);
result = 0;
return;
} else {
- printk("CD-ROM error: Drive reports %d.\n", SCpnt->sense_buffer[2]);
SCpnt = end_scsi_request(SCpnt, 0, this_count);
requeue_sr_request(SCpnt); /* Do next request */
return;
@@ -278,119 +287,185 @@ static void rw_intr (Scsi_Cmnd * SCpnt)
* Much of this has do be done with vendor-specific SCSI-commands.
* So I have to complete it step by step. Useful information is welcome.
*
- * Actually works: (should work ;-)
+ * Actually works:
* - NEC: Detection and support of multisession CD's. Special handling
* for XA-disks is not necessary.
*
* - TOSHIBA: setting density is done here now, mounting PhotoCD's should
* work now without running the program "set_density"
- * multisession-CD's are supported too.
+ * Multisession CD's are supported too.
*
- * Gerd Knorr (mailto:kraxel@cs.tu-berlin.de,
- * http://www.cs.tu-berlin.de/~kraxel/)
+ * kraxel@cs.tu-berlin.de (Gerd Knorr)
*/
-static void sr_photocd_done(Scsi_Cmnd *SCpnt)
-{
- SCpnt->request.dev = 0xfffe;
-}
-
static void sr_photocd(struct inode *inode)
{
unsigned long sector,min,sec,frame;
- Scsi_Cmnd *SCpnt;
- unsigned char scsi_cmd[10];
- unsigned char *buffer;
- int rc;
+ unsigned char buf[40]; /* the buffer for the ioctl */
+ unsigned char *cmd; /* the scsi-command */
+ unsigned char *send; /* the data we send to the drive ... */
+ unsigned char *rec; /* ... and get back */
+ int rc,is_xa,no_multi;
+
+ if (scsi_CDs[MINOR(inode->i_rdev)].xa_flags & 0x02) {
+#ifdef DEBUG
+ printk("sr_photocd: CDROM and/or the driver does not support multisession CD's");
+#endif
+ return;
+ }
+
+ if (!suser()) {
+ /* I'm not the superuser, so SCSI_IOCTL_SEND_COMMAND isn't allowed for me.
+ * That's why mpcd_sector will be initialized with zero, because I'm not
+ * able to get the right value. Necessary only if access_count is 1, else
+ * no disk change happened since the last call of this function and we can
+ * keep the old value.
+ */
+ if (1 == scsi_CDs[MINOR(inode->i_rdev)].device->access_count) {
+ scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = 0;
+ scsi_CDs[MINOR(inode->i_rdev)].xa_flags &= ~0x01;
+ }
+ return;
+ }
+
+ sector = 0;
+ is_xa = 0;
+ no_multi = 0;
+ cmd = rec = &buf[8];
switch(scsi_CDs[MINOR(inode->i_rdev)].device->manufacturer) {
case SCSI_MAN_NEC:
+#ifdef DEBUG
printk("sr_photocd: use NEC code\n");
- SCpnt = allocate_device(NULL, scsi_CDs[MINOR(inode->i_rdev)].device,1);
- memset(scsi_cmd,0,10);
- scsi_cmd[0] = 0xde;
- scsi_cmd[1] = ((scsi_CDs[MINOR(inode->i_rdev)].device->lun) << 5) | 0x03;
- scsi_cmd[2] = 0xb0;
- buffer = (unsigned char*) scsi_malloc(512);
- scsi_do_cmd(SCpnt, scsi_cmd, buffer, 0x16,
- sr_photocd_done, SR_TIMEOUT, MAX_RETRIES);
- while (SCpnt->request.dev != 0xfffe);
- rc = SCpnt->result;
- if (driver_byte(rc) != 0) {
- printk("sr_photocd: oops, CD-ROM reports an error.\n");
- sector = 0; }
- else {
- min = (unsigned long)buffer[15]/16*10 + (unsigned long)buffer[15]%16;
- sec = (unsigned long)buffer[16]/16*10 + (unsigned long)buffer[16]%16;
- frame = (unsigned long)buffer[17]/16*10 + (unsigned long)buffer[17]%16;
- sector = min*60*75 + sec*75 + frame;
- if (sector) {
- sector -= CD_BLOCK_OFFSET;
- printk("sr_photocd: multisession PhotoCD detected\n");
- }
+#endif
+ memset(buf,0,40);
+ *((unsigned long*)buf) = 0x0; /* we send nothing... */
+ *((unsigned long*)buf+1) = 0x16; /* and receive 0x16 bytes */
+ cmd[0] = 0xde;
+ cmd[1] = 0x03;
+ cmd[2] = 0xb0;
+ rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
+ SCSI_IOCTL_SEND_COMMAND, buf);
+ if (rc != 0) {
+ printk("sr_photocd: ioctl error (NEC): 0x%x\n",rc);
+ break;
}
- scsi_free(buffer,512);
- SCpnt->request.dev = -1;
+ if (rec[14] != 0 && rec[14] != 0xb0) {
+ printk("sr_photocd: Hmm, seems the CDROM doesn't support multisession CD's\n");
+ no_multi = 1;
+ break;
+ }
+ min = (unsigned long) rec[15]/16*10 + (unsigned long) rec[15]%16;
+ sec = (unsigned long) rec[16]/16*10 + (unsigned long) rec[16]%16;
+ frame = (unsigned long) rec[17]/16*10 + (unsigned long) rec[17]%16;
+ sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
+ is_xa = (rec[14] == 0xb0);
+#ifdef DEBUG
+ if (sector) {
+ printk("sr_photocd: multisession CD detected. start: %lu\n",sector);
+ }
+#endif
break;
case SCSI_MAN_TOSHIBA:
+#ifdef DEBUG
printk("sr_photocd: use TOSHIBA code\n");
+#endif
+
+ /* we request some disc information (is it a XA-CD ?,
+ where starts the last session ?) */
+ memset(buf,0,40);
+ *((unsigned long*)buf) = 0;
+ *((unsigned long*)buf+1) = 4; /* we receive 4 bytes from the drive */
+ cmd[0] = 0xc7;
+ cmd[1] = 3;
+ rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
+ SCSI_IOCTL_SEND_COMMAND, buf);
+ if (rc != 0) {
+ if (rc == 0x28000002) {
+ /* Got a "not ready" - error. No chance to find out if this is
+ because there is no CD in the drive or because the drive
+ don't knows multisession CD's. So I need to do an extra check... */
+ if (kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
+ SCSI_IOCTL_TEST_UNIT_READY, NULL)) {
+ printk("sr_photocd: drive not ready\n");
+ } else {
+ printk("sr_photocd: Hmm, seems the CDROM doesn't support multisession CD's\n");
+ no_multi = 1;
+ }
+ } else
+ printk("sr_photocd: ioctl error (TOSHIBA #1): 0x%x\n",rc);
+ break; /* if the first ioctl fails, we don't call the second one */
+ }
+ is_xa = (rec[0] == 0x20);
+ min = (unsigned long) rec[1]/16*10 + (unsigned long) rec[1]%16;
+ sec = (unsigned long) rec[2]/16*10 + (unsigned long) rec[2]%16;
+ frame = (unsigned long) rec[3]/16*10 + (unsigned long) rec[3]%16;
+ sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
+ if (sector) {
+ sector -= CD_BLOCK_OFFSET;
+#ifdef DEBUG
+ printk("sr_photocd: multisession CD detected: start: %lu\n",sector);
+#endif
+ }
- /* first I do a set_density-call (for reading XA-sectors) ... */
- SCpnt = allocate_device(NULL, scsi_CDs[MINOR(inode->i_rdev)].device,1);
- memset(scsi_cmd,0,10);
- scsi_cmd[0] = 0x15;
- scsi_cmd[1] = ((scsi_CDs[MINOR(inode->i_rdev)].device->lun) << 5)|(1 << 4);
- scsi_cmd[4] = 12;
- buffer = (unsigned char*) scsi_malloc(512);
- memset(buffer,0,512);
- buffer[ 3] = 0x08;
- buffer[ 4] = 0x83;
- buffer[10] = 0x08;
- scsi_do_cmd(SCpnt, scsi_cmd, buffer, 12,
- sr_photocd_done, SR_TIMEOUT, MAX_RETRIES);
- while (SCpnt->request.dev != 0xfffe);
- rc = SCpnt->result;
- if (driver_byte(rc) != 0) {
- printk("sr_photocd: oops, CD-ROM reports an error.\n"); }
- scsi_free(buffer,512);
- SCpnt->request.dev = -1;
-
- /* ... and then I ask, if there is a multisession-Disk */
- SCpnt = allocate_device(NULL, scsi_CDs[MINOR(inode->i_rdev)].device,1);
- memset(scsi_cmd,0,10);
- scsi_cmd[0] = 0xc7;
- scsi_cmd[1] = ((scsi_CDs[MINOR(inode->i_rdev)].device->lun) << 5) | 3;
- buffer = (unsigned char*) scsi_malloc(512);
- memset(buffer,0,512);
- scsi_do_cmd(SCpnt, scsi_cmd, buffer, 4,
- sr_photocd_done, SR_TIMEOUT, MAX_RETRIES);
- while (SCpnt->request.dev != 0xfffe);
- rc = SCpnt->result;
- if (driver_byte(rc) != 0) {
- printk("sr_photocd: oops, CD-ROM reports an error.\n");
- sector = 0; }
- else {
- min = (unsigned long)buffer[1]/16*10 + (unsigned long)buffer[1]%16;
- sec = (unsigned long)buffer[2]/16*10 + (unsigned long)buffer[2]%16;
- frame = (unsigned long)buffer[3]/16*10 + (unsigned long)buffer[3]%16;
- sector = min*60*75 + sec*75 + frame;
- if (sector) {
- sector -= CD_BLOCK_OFFSET;
- printk("sr_photocd: multisession PhotoCD detected: %lu\n",sector);
+ /* now we do a get_density... */
+ memset(buf,0,40);
+ *((unsigned long*)buf) = 0;
+ *((unsigned long*)buf+1) = 12;
+ cmd[0] = 0x1a;
+ cmd[2] = 1;
+ cmd[4] = 12;
+ rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
+ SCSI_IOCTL_SEND_COMMAND, buf);
+ if (rc != 0) {
+ printk("sr_photocd: ioctl error (TOSHIBA #2): 0x%x\n",rc);
+ break;
+ }
+#ifdef DEBUG
+ printk("sr_photocd: get_density: 0x%x\n",rec[4]);
+#endif
+
+ /* ...and only if necessary a set_density */
+ if ((rec[4] != 0x81 && is_xa) || (rec[4] != 0 && !is_xa)) {
+#ifdef DEBUG
+ printk("sr_photocd: doing set_density\n");
+#endif
+ memset(buf,0,40);
+ *((unsigned long*)buf) = 12; /* sending 12 bytes... */
+ *((unsigned long*)buf+1) = 0;
+ cmd[0] = 0x15;
+ cmd[1] = (1 << 4);
+ cmd[4] = 12;
+ send = &cmd[6]; /* this is a 6-Byte command */
+ send[ 3] = 0x08; /* the data for the command */
+ send[ 4] = (is_xa) ? 0x81 : 0; /* density 0x81 for XA-CD's, 0 else */
+ send[10] = 0x08;
+ rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
+ SCSI_IOCTL_SEND_COMMAND, buf);
+ if (rc != 0) {
+ printk("sr_photocd: ioctl error (TOSHIBA #3): 0x%x\n",rc);
}
+ /* The set_density command may have changed the sector size or capacity. */
+ scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size = 1;
}
- scsi_free(buffer,512);
- SCpnt->request.dev = -1;
break;
+
+ case SCSI_MAN_NEC_OLDCDR:
case SCSI_MAN_UNKNOWN:
default:
- printk("sr_photocd: there is no special photocd-code for this drive\n");
sector = 0;
+ no_multi = 1;
break; }
scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = sector;
+ if (is_xa)
+ scsi_CDs[MINOR(inode->i_rdev)].xa_flags |= 0x01;
+ else
+ scsi_CDs[MINOR(inode->i_rdev)].xa_flags &= ~0x01;
+ if (no_multi)
+ scsi_CDs[MINOR(inode->i_rdev)].xa_flags |= 0x02;
return;
}
@@ -406,6 +481,10 @@ static int sr_open(struct inode * inode, struct file * filp)
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)
+ (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)++;
+
+ 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
@@ -415,10 +494,6 @@ static int sr_open(struct inode * inode, struct file * filp)
if(scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size)
get_sectorsize(MINOR(inode->i_rdev));
-#if 0 /* don't use for now - it doesn't seem to work for everybody */
- sr_photocd(inode);
-#endif
-
return 0;
}
@@ -432,12 +507,14 @@ static void do_sr_request (void)
{
Scsi_Cmnd * SCpnt = NULL;
struct request * req = NULL;
+ unsigned long flags;
int flag = 0;
while (1==1){
+ save_flags(flags);
cli();
if (CURRENT != NULL && CURRENT->dev == -1) {
- sti();
+ restore_flags(flags);
return;
};
@@ -447,7 +524,7 @@ static void do_sr_request (void)
SCpnt = allocate_device(&CURRENT,
scsi_CDs[DEVICE_NR(MINOR(CURRENT->dev))].device, 0);
else SCpnt = NULL;
- sti();
+ restore_flags(flags);
/* This is a performance enhancement. We dig down into the request list and
try and find a queueable request (i.e. device not busy, and host able to
@@ -459,6 +536,7 @@ static void do_sr_request (void)
if (!SCpnt && sr_template.nr_dev > 1){
struct request *req1;
req1 = NULL;
+ save_flags(flags);
cli();
req = CURRENT;
while(req){
@@ -474,7 +552,7 @@ static void do_sr_request (void)
else
req1->next = req->next;
};
- sti();
+ restore_flags(flags);
};
if (!SCpnt)
@@ -564,10 +642,6 @@ work around the fact that the buffer cache has a block size of 1024,
and we have 2048 byte sectors. This code should work for buffers that
are any multiple of 512 bytes long. */
- /* this is for support of multisession-CD's */
- if (block >= 64 && block < 68) {
- block += scsi_CDs[dev].mpcd_sector*4; }
-
SCpnt->use_sg = 0;
if (SCpnt->host->sg_tablesize > 0 &&
@@ -637,7 +711,7 @@ are any multiple of 512 bytes long. */
if (count+1 != SCpnt->use_sg) panic("Bad sr request list");
break;
};
- if (((int) sgpnt[count].address) + sgpnt[count].length >
+ if (((long) sgpnt[count].address) + sgpnt[count].length >
ISA_DMA_THRESHOLD & (SCpnt->host->unchecked_isa_dma)) {
sgpnt[count].alt_address = sgpnt[count].address;
/* We try and avoid exhausting the DMA pool, since it is easier
@@ -666,7 +740,7 @@ are any multiple of 512 bytes long. */
}; /* if need DMA fixup */
}; /* for loop to fill list */
#ifdef DEBUG
- printk("SG: %d %d %d %d %d *** ",SCpnt->use_sg, SCpnt->request.sector,
+ printk("SR: %d %d %d %d %d *** ",SCpnt->use_sg, SCpnt->request.sector,
this_count,
SCpnt->request.current_nr_sectors,
SCpnt->request.nr_sectors);
@@ -701,7 +775,7 @@ are any multiple of 512 bytes long. */
{
this_count -= this_count % 4;
buffer = (unsigned char *) SCpnt->request.buffer;
- if (((int) buffer) + (this_count << 9) > ISA_DMA_THRESHOLD &
+ if (((long) buffer) + (this_count << 9) > ISA_DMA_THRESHOLD &
(SCpnt->host->unchecked_isa_dma))
buffer = (unsigned char *) scsi_malloc(this_count << 9);
}
@@ -780,8 +854,6 @@ are any multiple of 512 bytes long. */
static int sr_detect(Scsi_Device * SDp){
- /* We do not support attaching loadable devices yet. */
- if(scsi_loadable_module_flag) return 0;
if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0;
printk("Detected scsi CD-ROM sr%d at scsi%d, id %d, lun %d\n",
@@ -791,17 +863,17 @@ static int sr_detect(Scsi_Device * SDp){
return 1;
}
-static void sr_attach(Scsi_Device * SDp){
+static int sr_attach(Scsi_Device * SDp){
Scsi_CD * cpnt;
int i;
- /* We do not support attaching loadable devices yet. */
-
- if(scsi_loadable_module_flag) return;
- if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return;
+ if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 1;
if (sr_template.nr_dev >= sr_template.dev_max)
- panic ("scsi_devices corrupt (sr)");
+ {
+ SDp->attached--;
+ return 1;
+ }
for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++)
if(!cpnt->device) break;
@@ -813,6 +885,7 @@ static void sr_attach(Scsi_Device * SDp){
sr_template.nr_dev++;
if(sr_template.nr_dev > sr_template.dev_max)
panic ("scsi_devices corrupt (sr)");
+ return 0;
}
@@ -853,7 +926,7 @@ static void get_sectorsize(int i){
MAX_RETRIES);
if (current == task[0])
- while(SCpnt->request.dev != 0xfffe);
+ while(SCpnt->request.dev != 0xfffe) barrier();
else
if (SCpnt->request.dev != 0xfffe){
struct semaphore sem = MUTEX_LOCKED;
@@ -892,6 +965,7 @@ static void get_sectorsize(int i){
if(scsi_CDs[i].sector_size == 2048)
scsi_CDs[i].capacity *= 4;
scsi_CDs[i].needs_sector_size = 0;
+ sr_sizes[i] = scsi_CDs[i].capacity;
};
scsi_free(buffer, 512);
}
@@ -908,20 +982,20 @@ static void sr_init()
printk("Unable to get major %d for SCSI-CD\n",MAJOR_NR);
return;
}
+ sr_registered++;
}
- /* We do not support attaching loadable devices yet. */
- if(scsi_loadable_module_flag) return;
-
- sr_template.dev_max = sr_template.dev_noticed;
- scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD));
+
+ if (scsi_CDs) return;
+ 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));
+ 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));
+ sizeof(int), GFP_ATOMIC);
for(i=0;i<sr_template.dev_max;i++) sr_blocksizes[i] = 2048;
blksize_size[MAJOR_NR] = sr_blocksizes;
@@ -931,26 +1005,84 @@ 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)
{
+ /* If we have already seen this, then skip it. Comes up
+ with loadable modules. */
+ if (scsi_CDs[i].capacity) continue;
+ scsi_CDs[i].capacity = 0x1fffff;
+ scsi_CDs[i].sector_size = 2048; /* A guess, just in case */
+ scsi_CDs[i].needs_sector_size = 1;
+#if 0
+ /* seems better to leave this for later */
get_sectorsize(i);
- printk("Scd sectorsize = %d bytes\n", scsi_CDs[i].sector_size);
+ printk("Scd sectorsize = %d bytes.\n", scsi_CDs[i].sector_size);
+#endif
scsi_CDs[i].use = 1;
scsi_CDs[i].ten = 1;
scsi_CDs[i].remap = 1;
sr_sizes[i] = scsi_CDs[i].capacity;
}
- blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
- blk_size[MAJOR_NR] = sr_sizes;
/* 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->host->sg_tablesize)
+ if(scsi_CDs[0].device && scsi_CDs[0].device->host->sg_tablesize)
read_ahead[MAJOR_NR] = 32; /* 32 sector read-ahead. Always removable. */
else
read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */
return;
}
+
+static void sr_detach(Scsi_Device * SDp)
+{
+ Scsi_CD * cpnt;
+ int i, major;
+
+ major = MAJOR_NR << 8;
+
+ for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++)
+ if(cpnt->device == SDp) {
+ /*
+ * Since the cdrom is read-only, no need to sync the device.
+ * We should be kind to our buffer cache, however.
+ */
+ invalidate_inodes(major | i);
+ invalidate_buffers(major | i);
+
+ /*
+ * Reset things back to a sane state so that one can re-load a new
+ * driver (perhaps the same one).
+ */
+ cpnt->device = NULL;
+ cpnt->capacity = 0;
+ SDp->attached--;
+ sr_template.nr_dev--;
+ sr_template.dev_noticed--;
+ sr_sizes[i] = 0;
+ return;
+ }
+ return;
+}
+
+/*
+ * 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: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */