Commit 34d3616d authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

[PATCH] forward port of the various scsi fixes from 2.4

parent 4108966a
...@@ -1399,14 +1399,10 @@ static void scsi_softirq(struct softirq_action *h) ...@@ -1399,14 +1399,10 @@ static void scsi_softirq(struct softirq_action *h)
*/ */
int scsi_retry_command(Scsi_Cmnd * SCpnt) int scsi_retry_command(Scsi_Cmnd * SCpnt)
{ {
memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd, /*
sizeof(SCpnt->data_cmnd)); * Restore the SCSI command state.
SCpnt->request_buffer = SCpnt->buffer; */
SCpnt->request_bufflen = SCpnt->bufflen; scsi_setup_cmd_retry(SCpnt);
SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->cmd_len = SCpnt->old_cmd_len;
SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
SCpnt->underflow = SCpnt->old_underflow;
/* /*
* Zero the sense information from the last time we tried * Zero the sense information from the last time we tried
......
...@@ -467,6 +467,7 @@ extern Scsi_Cmnd *scsi_end_request(Scsi_Cmnd * SCpnt, int uptodate, ...@@ -467,6 +467,7 @@ extern Scsi_Cmnd *scsi_end_request(Scsi_Cmnd * SCpnt, int uptodate,
int sectors); int sectors);
extern struct Scsi_Device_Template *scsi_get_request_dev(struct request *); extern struct Scsi_Device_Template *scsi_get_request_dev(struct request *);
extern int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt); extern int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt);
extern void scsi_setup_cmd_retry(Scsi_Cmnd *SCpnt);
extern int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int); extern int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int);
extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
int block_sectors); int block_sectors);
...@@ -597,9 +598,10 @@ struct scsi_device { ...@@ -597,9 +598,10 @@ struct scsi_device {
unsigned changed:1; /* Data invalid due to media change */ unsigned changed:1; /* Data invalid due to media change */
unsigned busy:1; /* Used to prevent races */ unsigned busy:1; /* Used to prevent races */
unsigned lockable:1; /* Able to prevent media removal */ unsigned lockable:1; /* Able to prevent media removal */
unsigned locked:1; /* Media removal disabled */
unsigned borken:1; /* Tell the Seagate driver to be unsigned borken:1; /* Tell the Seagate driver to be
* painfully slow on this device */ * painfully slow on this device */
// unsigned disconnect:1; /* can disconnect */ unsigned disconnect:1; /* can disconnect */
unsigned soft_reset:1; /* Uses soft reset option */ unsigned soft_reset:1; /* Uses soft reset option */
unsigned sdtr:1; /* Device supports SDTR messages */ unsigned sdtr:1; /* Device supports SDTR messages */
unsigned wdtr:1; /* Device supports WDTR messages */ unsigned wdtr:1; /* Device supports WDTR messages */
......
This diff is collapsed.
...@@ -151,6 +151,29 @@ static int ioctl_internal_command(Scsi_Device * dev, char *cmd, ...@@ -151,6 +151,29 @@ static int ioctl_internal_command(Scsi_Device * dev, char *cmd,
return result; return result;
} }
int scsi_set_medium_removal(Scsi_Device *dev, char state)
{
char scsi_cmd[MAX_COMMAND_SIZE];
int ret;
if (!dev->removable || !dev->lockable)
return 0;
scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
scsi_cmd[1] = (dev->scsi_level <= SCSI_2) ? (dev->lun << 5) : 0;
scsi_cmd[2] = 0;
scsi_cmd[3] = 0;
scsi_cmd[4] = state;
scsi_cmd[5] = 0;
ret = ioctl_internal_command(dev, scsi_cmd, IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
if (ret == 0)
dev->locked = state == SCSI_REMOVAL_PREVENT;
return ret;
}
/* /*
* This interface is deprecated - 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 * interface instead, as this is a more flexible approach to performing
...@@ -456,24 +479,9 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg) ...@@ -456,24 +479,9 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
return scsi_ioctl_send_command((Scsi_Device *) dev, return scsi_ioctl_send_command((Scsi_Device *) dev,
(Scsi_Ioctl_Command *) arg); (Scsi_Ioctl_Command *) arg);
case SCSI_IOCTL_DOORLOCK: case SCSI_IOCTL_DOORLOCK:
if (!dev->removable || !dev->lockable) return scsi_set_medium_removal(dev, SCSI_REMOVAL_PREVENT);
return 0;
scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
scsi_cmd[1] = cmd_byte1;
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
break;
case SCSI_IOCTL_DOORUNLOCK: case SCSI_IOCTL_DOORUNLOCK:
if (!dev->removable || !dev->lockable) return scsi_set_medium_removal(dev, SCSI_REMOVAL_ALLOW);
return 0;
scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
scsi_cmd[1] = cmd_byte1;
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
case SCSI_IOCTL_TEST_UNIT_READY: case SCSI_IOCTL_TEST_UNIT_READY:
scsi_cmd[0] = TEST_UNIT_READY; scsi_cmd[0] = TEST_UNIT_READY;
scsi_cmd[1] = cmd_byte1; scsi_cmd[1] = cmd_byte1;
......
...@@ -159,6 +159,30 @@ int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt) ...@@ -159,6 +159,30 @@ int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt)
return 1; return 1;
} }
/*
* Function: scsi_setup_cmd_retry()
*
* Purpose: Restore the command state for a retry
*
* Arguments: SCpnt - command to be restored
*
* Returns: Nothing
*
* Notes: Immediately prior to retrying a command, we need
* to restore certain fields that we saved above.
*/
void scsi_setup_cmd_retry(Scsi_Cmnd *SCpnt)
{
memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
sizeof(SCpnt->data_cmnd));
SCpnt->request_buffer = SCpnt->buffer;
SCpnt->request_bufflen = SCpnt->bufflen;
SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->cmd_len = SCpnt->old_cmd_len;
SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
SCpnt->underflow = SCpnt->old_underflow;
}
/* /*
* Function: scsi_queue_next_request() * Function: scsi_queue_next_request()
* *
...@@ -614,7 +638,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, ...@@ -614,7 +638,7 @@ void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
printk("scsi%d: ERROR on channel %d, id %d, lun %d, CDB: ", printk("scsi%d: ERROR on channel %d, id %d, lun %d, CDB: ",
SCpnt->host->host_no, (int) SCpnt->channel, SCpnt->host->host_no, (int) SCpnt->channel,
(int) SCpnt->target, (int) SCpnt->lun); (int) SCpnt->target, (int) SCpnt->lun);
print_command(SCpnt->cmnd); print_command(SCpnt->data_cmnd);
print_sense("sd", SCpnt); print_sense("sd", SCpnt);
SCpnt = scsi_end_request(SCpnt, 0, block_sectors); SCpnt = scsi_end_request(SCpnt, 0, block_sectors);
return; return;
...@@ -798,33 +822,6 @@ void scsi_request_fn(request_queue_t * q) ...@@ -798,33 +822,6 @@ void scsi_request_fn(request_queue_t * q)
SDpnt->starved = 0; SDpnt->starved = 0;
} }
/*
* FIXME(eric)
* I am not sure where the best place to do this is. We need
* to hook in a place where we are likely to come if in user
* space. Technically the error handling thread should be
* doing this crap, but the error handler isn't used by
* most hosts.
*/
if (SDpnt->was_reset) {
/*
* We need to relock the door, but we might
* be in an interrupt handler. Only do this
* from user space, since we do not want to
* sleep from an interrupt.
*
* FIXME(eric) - have the error handler thread do
* this work.
*/
SDpnt->was_reset = 0;
if (SDpnt->removable && !in_interrupt()) {
spin_unlock_irq(q->queue_lock);
scsi_ioctl(SDpnt, SCSI_IOCTL_DOORLOCK, 0);
spin_lock_irq(q->queue_lock);
continue;
}
}
/* /*
* If we couldn't find a request that could be queued, then we * If we couldn't find a request that could be queued, then we
* can also quit. * can also quit.
......
...@@ -54,6 +54,7 @@ EXPORT_SYMBOL(scsi_release_command); ...@@ -54,6 +54,7 @@ EXPORT_SYMBOL(scsi_release_command);
EXPORT_SYMBOL(print_Scsi_Cmnd); EXPORT_SYMBOL(print_Scsi_Cmnd);
EXPORT_SYMBOL(scsi_block_when_processing_errors); EXPORT_SYMBOL(scsi_block_when_processing_errors);
EXPORT_SYMBOL(scsi_ioctl_send_command); EXPORT_SYMBOL(scsi_ioctl_send_command);
EXPORT_SYMBOL(scsi_set_medium_removal);
#if defined(CONFIG_SCSI_LOGGING) /* { */ #if defined(CONFIG_SCSI_LOGGING) /* { */
EXPORT_SYMBOL(scsi_logging_level); EXPORT_SYMBOL(scsi_logging_level);
#endif #endif
......
...@@ -529,7 +529,7 @@ static int sd_open(struct inode *inode, struct file *filp) ...@@ -529,7 +529,7 @@ static int sd_open(struct inode *inode, struct file *filp)
if (sdp->removable) if (sdp->removable)
if (sdp->access_count==1) if (sdp->access_count==1)
if (scsi_block_when_processing_errors(sdp)) if (scsi_block_when_processing_errors(sdp))
scsi_ioctl(sdp, SCSI_IOCTL_DOORLOCK, NULL); scsi_set_medium_removal(sdp, SCSI_REMOVAL_PREVENT);
return 0; return 0;
...@@ -573,7 +573,7 @@ static int sd_release(struct inode *inode, struct file *filp) ...@@ -573,7 +573,7 @@ static int sd_release(struct inode *inode, struct file *filp)
if (sdp->removable) { if (sdp->removable) {
if (!sdp->access_count) if (!sdp->access_count)
if (scsi_block_when_processing_errors(sdp)) if (scsi_block_when_processing_errors(sdp))
scsi_ioctl(sdp, SCSI_IOCTL_DOORUNLOCK, NULL); scsi_set_medium_removal(sdp, SCSI_REMOVAL_ALLOW);
} }
if (sdp->host->hostt->module) if (sdp->host->hostt->module)
__MOD_DEC_USE_COUNT(sdp->host->hostt->module); __MOD_DEC_USE_COUNT(sdp->host->hostt->module);
...@@ -1623,7 +1623,6 @@ static int sd_synchronize_cache(int index, int verbose) ...@@ -1623,7 +1623,6 @@ static int sd_synchronize_cache(int index, int verbose)
} }
the_result = SRpnt->sr_result; the_result = SRpnt->sr_result;
scsi_release_request(SRpnt);
if(verbose) { if(verbose) {
if(the_result != 0) { if(the_result != 0) {
printk("FAILED\n status = %x, message = %02x, host = %d, driver = %02x\n ", printk("FAILED\n status = %x, message = %02x, host = %d, driver = %02x\n ",
...@@ -1636,6 +1635,7 @@ static int sd_synchronize_cache(int index, int verbose) ...@@ -1636,6 +1635,7 @@ static int sd_synchronize_cache(int index, int verbose)
} }
} }
scsi_release_request(SRpnt);
return (the_result == 0); return (the_result == 0);
} }
......
...@@ -575,7 +575,7 @@ static void get_sectorsize(Scsi_CD *cd) ...@@ -575,7 +575,7 @@ static void get_sectorsize(Scsi_CD *cd)
void get_capabilities(Scsi_CD *cd) void get_capabilities(Scsi_CD *cd)
{ {
unsigned char cmd[6]; struct cdrom_generic_command cgc;
unsigned char *buffer; unsigned char *buffer;
int rc, n; int rc, n;
...@@ -597,13 +597,18 @@ void get_capabilities(Scsi_CD *cd) ...@@ -597,13 +597,18 @@ void get_capabilities(Scsi_CD *cd)
printk(KERN_ERR "sr: out of memory.\n"); printk(KERN_ERR "sr: out of memory.\n");
return; return;
} }
cmd[0] = MODE_SENSE; memset(&cgc, 0, sizeof(struct cdrom_generic_command));
cmd[1] = (cd->device->scsi_level <= SCSI_2) ? cgc.cmd[0] = MODE_SENSE;
((cd->device->lun << 5) & 0xe0) : 0; cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
cmd[2] = 0x2a; ((cd->device->lun << 5) & 0xe0) : 0;
cmd[4] = 128; cgc.cmd[2] = 0x2a;
cmd[3] = cmd[5] = 0; cgc.cmd[4] = 128;
rc = sr_do_ioctl(cd, cmd, buffer, 128, 1, SCSI_DATA_READ, NULL); cgc.buffer = buffer;
cgc.buflen = 128;
cgc.quiet = 1;
cgc.data_direction = SCSI_DATA_READ;
cgc.timeout = SR_TIMEOUT;
rc = sr_do_ioctl(cd, &cgc);
if (rc) { if (rc) {
/* failed, drive doesn't have capabilities mode page */ /* failed, drive doesn't have capabilities mode page */
...@@ -680,7 +685,10 @@ static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command ...@@ -680,7 +685,10 @@ static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command
if (device->scsi_level <= SCSI_2) if (device->scsi_level <= SCSI_2)
cgc->cmd[1] |= device->lun << 5; cgc->cmd[1] |= device->lun << 5;
cgc->stat = sr_do_ioctl(cdi->handle, cgc->cmd, cgc->buffer, cgc->buflen, cgc->quiet, cgc->data_direction, cgc->sense); if (cgc->timeout <= 0)
cgc->timeout = IOCTL_TIMEOUT;
sr_do_ioctl(cdi->handle, cgc);
return cgc->stat; return cgc->stat;
} }
......
...@@ -20,6 +20,10 @@ ...@@ -20,6 +20,10 @@
#include "scsi.h" #include "scsi.h"
#include <linux/genhd.h> #include <linux/genhd.h>
/* The CDROM is fairly slow, so we need a little extra time */
/* In fact, it is very slow if it has to spin up first */
#define IOCTL_TIMEOUT 30*HZ
typedef struct { typedef struct {
unsigned capacity; /* size in blocks */ unsigned capacity; /* size in blocks */
Scsi_Device *device; Scsi_Device *device;
...@@ -34,7 +38,7 @@ typedef struct { ...@@ -34,7 +38,7 @@ typedef struct {
struct gendisk *disk; struct gendisk *disk;
} Scsi_CD; } Scsi_CD;
int sr_do_ioctl(Scsi_CD *, unsigned char *, void *, unsigned, int, int, struct request_sense *); int sr_do_ioctl(Scsi_CD *, struct cdrom_generic_command *);
int sr_lock_door(struct cdrom_device_info *, int); int sr_lock_door(struct cdrom_device_info *, int);
int sr_tray_move(struct cdrom_device_info *, int); int sr_tray_move(struct cdrom_device_info *, int);
......
This diff is collapsed.
...@@ -58,6 +58,8 @@ ...@@ -58,6 +58,8 @@
#define VENDOR_TOSHIBA 3 #define VENDOR_TOSHIBA 3
#define VENDOR_WRITER 4 /* pre-scsi3 writers */ #define VENDOR_WRITER 4 /* pre-scsi3 writers */
#define VENDOR_TIMEOUT 30*HZ
void sr_vendor_init(Scsi_CD *cd) void sr_vendor_init(Scsi_CD *cd)
{ {
#ifndef CONFIG_BLK_DEV_SR_VENDOR #ifndef CONFIG_BLK_DEV_SR_VENDOR
...@@ -104,7 +106,7 @@ void sr_vendor_init(Scsi_CD *cd) ...@@ -104,7 +106,7 @@ void sr_vendor_init(Scsi_CD *cd)
int sr_set_blocklength(Scsi_CD *cd, int blocklength) int sr_set_blocklength(Scsi_CD *cd, int blocklength)
{ {
unsigned char *buffer; /* the buffer for the ioctl */ unsigned char *buffer; /* the buffer for the ioctl */
unsigned char cmd[MAX_COMMAND_SIZE]; /* the scsi-command */ struct cdrom_generic_command cgc;
struct ccs_modesel_head *modesel; struct ccs_modesel_head *modesel;
int rc, density = 0; int rc, density = 0;
...@@ -120,19 +122,23 @@ int sr_set_blocklength(Scsi_CD *cd, int blocklength) ...@@ -120,19 +122,23 @@ int sr_set_blocklength(Scsi_CD *cd, int blocklength)
#ifdef DEBUG #ifdef DEBUG
printk("%s: MODE SELECT 0x%x/%d\n", cd->cdi.name, density, blocklength); printk("%s: MODE SELECT 0x%x/%d\n", cd->cdi.name, density, blocklength);
#endif #endif
memset(cmd, 0, MAX_COMMAND_SIZE); memset(&cgc, 0, sizeof(struct cdrom_generic_command));
cmd[0] = MODE_SELECT; cgc.cmd[0] = MODE_SELECT;
cmd[1] = (cd->device->scsi_level <= SCSI_2) ? cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
(cd->device->lun << 5) : 0; (cd->device->lun << 5) : 0;
cmd[1] |= (1 << 4); cgc.cmd[1] |= (1 << 4);
cmd[4] = 12; cgc.cmd[4] = 12;
modesel = (struct ccs_modesel_head *) buffer; modesel = (struct ccs_modesel_head *) buffer;
memset(modesel, 0, sizeof(*modesel)); memset(modesel, 0, sizeof(*modesel));
modesel->block_desc_length = 0x08; modesel->block_desc_length = 0x08;
modesel->density = density; modesel->density = density;
modesel->block_length_med = (blocklength >> 8) & 0xff; modesel->block_length_med = (blocklength >> 8) & 0xff;
modesel->block_length_lo = blocklength & 0xff; modesel->block_length_lo = blocklength & 0xff;
if (0 == (rc = sr_do_ioctl(cd, cmd, buffer, sizeof(*modesel), 0, SCSI_DATA_WRITE, NULL))) { cgc.buffer = buffer;
cgc.buflen = sizeof(*modesel);
cgc.data_direction = SCSI_DATA_WRITE;
cgc.timeout = VENDOR_TIMEOUT;
if (0 == (rc = sr_do_ioctl(cd, &cgc))) {
cd->device->sector_size = blocklength; cd->device->sector_size = blocklength;
} }
#ifdef DEBUG #ifdef DEBUG
...@@ -154,7 +160,7 @@ int sr_cd_check(struct cdrom_device_info *cdi) ...@@ -154,7 +160,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
Scsi_CD *cd = cdi->handle; Scsi_CD *cd = cdi->handle;
unsigned long sector; unsigned long sector;
unsigned char *buffer; /* the buffer for the ioctl */ unsigned char *buffer; /* the buffer for the ioctl */
unsigned char cmd[MAX_COMMAND_SIZE]; /* the scsi-command */ struct cdrom_generic_command cgc;
int rc, no_multi; int rc, no_multi;
if (cd->cdi.mask & CDC_MULTI_SESSION) if (cd->cdi.mask & CDC_MULTI_SESSION)
...@@ -168,16 +174,22 @@ int sr_cd_check(struct cdrom_device_info *cdi) ...@@ -168,16 +174,22 @@ int sr_cd_check(struct cdrom_device_info *cdi)
no_multi = 0; /* flag: the drive can't handle multisession */ no_multi = 0; /* flag: the drive can't handle multisession */
rc = 0; rc = 0;
memset(&cgc, 0, sizeof(struct cdrom_generic_command));
switch (cd->vendor) { switch (cd->vendor) {
case VENDOR_SCSI3: case VENDOR_SCSI3:
memset(cmd, 0, MAX_COMMAND_SIZE); cgc.cmd[0] = READ_TOC;
cmd[0] = READ_TOC; cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
cmd[1] = (cd->device->scsi_level <= SCSI_2) ? (cd->device->lun << 5) : 0;
(cd->device->lun << 5) : 0; cgc.cmd[8] = 12;
cmd[8] = 12; cgc.cmd[9] = 0x40;
cmd[9] = 0x40; cgc.buffer = buffer;
rc = sr_do_ioctl(cd, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL); cgc.buflen = 12;
cgc.quiet = 1;
cgc.data_direction = SCSI_DATA_READ;
cgc.timeout = VENDOR_TIMEOUT;
rc = sr_do_ioctl(cd, &cgc);
if (rc != 0) if (rc != 0)
break; break;
if ((buffer[0] << 8) + buffer[1] < 0x0a) { if ((buffer[0] << 8) + buffer[1] < 0x0a) {
...@@ -197,13 +209,17 @@ int sr_cd_check(struct cdrom_device_info *cdi) ...@@ -197,13 +209,17 @@ int sr_cd_check(struct cdrom_device_info *cdi)
#ifdef CONFIG_BLK_DEV_SR_VENDOR #ifdef CONFIG_BLK_DEV_SR_VENDOR
case VENDOR_NEC:{ case VENDOR_NEC:{
unsigned long min, sec, frame; unsigned long min, sec, frame;
memset(cmd, 0, MAX_COMMAND_SIZE); cgc.cmd[0] = 0xde;
cmd[0] = 0xde; cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
cmd[1] = (cd->device->scsi_level <= SCSI_2) ? (cd->device->lun << 5) : 0;
(cd->device->lun << 5) : 0; cgc.cmd[1] |= 0x03;
cmd[1] |= 0x03; cgc.cmd[2] = 0xb0;
cmd[2] = 0xb0; cgc.buffer = buffer;
rc = sr_do_ioctl(cd, cmd, buffer, 0x16, 1, SCSI_DATA_READ, NULL); cgc.buflen = 0x16;
cgc.quiet = 1;
cgc.data_direction = SCSI_DATA_READ;
cgc.timeout = VENDOR_TIMEOUT;
rc = sr_do_ioctl(cd, &cgc);
if (rc != 0) if (rc != 0)
break; break;
if (buffer[14] != 0 && buffer[14] != 0xb0) { if (buffer[14] != 0 && buffer[14] != 0xb0) {
...@@ -225,12 +241,16 @@ int sr_cd_check(struct cdrom_device_info *cdi) ...@@ -225,12 +241,16 @@ int sr_cd_check(struct cdrom_device_info *cdi)
/* we request some disc information (is it a XA-CD ?, /* we request some disc information (is it a XA-CD ?,
* where starts the last session ?) */ * where starts the last session ?) */
memset(cmd, 0, MAX_COMMAND_SIZE); cgc.cmd[0] = 0xc7;
cmd[0] = 0xc7; cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
cmd[1] = (cd->device->scsi_level <= SCSI_2) ? (cd->device->lun << 5) : 0;
(cd->device->lun << 5) : 0; cgc.cmd[1] |= 0x03;
cmd[1] |= 0x03; cgc.buffer = buffer;
rc = sr_do_ioctl(cd, cmd, buffer, 4, 1, SCSI_DATA_READ, NULL); cgc.buflen = 4;
cgc.quiet = 1;
cgc.data_direction = SCSI_DATA_READ;
cgc.timeout = VENDOR_TIMEOUT;
rc = sr_do_ioctl(cd, &cgc);
if (rc == -EINVAL) { if (rc == -EINVAL) {
printk(KERN_INFO "%s: Hmm, seems the drive " printk(KERN_INFO "%s: Hmm, seems the drive "
"doesn't support multisession CD's\n", "doesn't support multisession CD's\n",
...@@ -251,13 +271,17 @@ int sr_cd_check(struct cdrom_device_info *cdi) ...@@ -251,13 +271,17 @@ int sr_cd_check(struct cdrom_device_info *cdi)
} }
case VENDOR_WRITER: case VENDOR_WRITER:
memset(cmd, 0, MAX_COMMAND_SIZE); cgc.cmd[0] = READ_TOC;
cmd[0] = READ_TOC; cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
cmd[1] = (cd->device->scsi_level <= SCSI_2) ? (cd->device->lun << 5) : 0;
(cd->device->lun << 5) : 0; cgc.cmd[8] = 0x04;
cmd[8] = 0x04; cgc.cmd[9] = 0x40;
cmd[9] = 0x40; cgc.buffer = buffer;
rc = sr_do_ioctl(cd, cmd, buffer, 0x04, 1, SCSI_DATA_READ, NULL); cgc.buflen = 0x04;
cgc.quiet = 1;
cgc.data_direction = SCSI_DATA_READ;
cgc.timeout = VENDOR_TIMEOUT;
rc = sr_do_ioctl(cd, &cgc);
if (rc != 0) { if (rc != 0) {
break; break;
} }
...@@ -266,13 +290,18 @@ int sr_cd_check(struct cdrom_device_info *cdi) ...@@ -266,13 +290,18 @@ int sr_cd_check(struct cdrom_device_info *cdi)
"%s: No finished session\n", cd->cdi.name); "%s: No finished session\n", cd->cdi.name);
break; break;
} }
cmd[0] = READ_TOC; /* Read TOC */ cgc.cmd[0] = READ_TOC; /* Read TOC */
cmd[1] = (cd->device->scsi_level <= SCSI_2) ? cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
(cd->device->lun << 5) : 0; (cd->device->lun << 5) : 0;
cmd[6] = rc & 0x7f; /* number of last session */ cgc.cmd[6] = rc & 0x7f; /* number of last session */
cmd[8] = 0x0c; cgc.cmd[8] = 0x0c;
cmd[9] = 0x40; cgc.cmd[9] = 0x40;
rc = sr_do_ioctl(cd, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL); cgc.buffer = buffer;
cgc.buflen = 12;
cgc.quiet = 1;
cgc.data_direction = SCSI_DATA_READ;
cgc.timeout = VENDOR_TIMEOUT;
rc = sr_do_ioctl(cd, &cgc);
if (rc != 0) { if (rc != 0) {
break; break;
} }
......
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