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)
*/
int scsi_retry_command(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;
/*
* Restore the SCSI command state.
*/
scsi_setup_cmd_retry(SCpnt);
/*
* 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,
int sectors);
extern struct Scsi_Device_Template *scsi_get_request_dev(struct request *);
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 void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
int block_sectors);
......@@ -597,9 +598,10 @@ struct scsi_device {
unsigned changed:1; /* Data invalid due to media change */
unsigned busy:1; /* Used to prevent races */
unsigned lockable:1; /* Able to prevent media removal */
unsigned locked:1; /* Media removal disabled */
unsigned borken:1; /* Tell the Seagate driver to be
* painfully slow on this device */
// unsigned disconnect:1; /* can disconnect */
unsigned disconnect:1; /* can disconnect */
unsigned soft_reset:1; /* Uses soft reset option */
unsigned sdtr:1; /* Device supports SDTR 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,
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)
* 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)
return scsi_ioctl_send_command((Scsi_Device *) dev,
(Scsi_Ioctl_Command *) arg);
case SCSI_IOCTL_DOORLOCK:
if (!dev->removable || !dev->lockable)
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;
return scsi_set_medium_removal(dev, SCSI_REMOVAL_PREVENT);
case SCSI_IOCTL_DOORUNLOCK:
if (!dev->removable || !dev->lockable)
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);
return scsi_set_medium_removal(dev, SCSI_REMOVAL_ALLOW);
case SCSI_IOCTL_TEST_UNIT_READY:
scsi_cmd[0] = TEST_UNIT_READY;
scsi_cmd[1] = cmd_byte1;
......
......@@ -159,6 +159,30 @@ int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt)
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()
*
......@@ -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: ",
SCpnt->host->host_no, (int) SCpnt->channel,
(int) SCpnt->target, (int) SCpnt->lun);
print_command(SCpnt->cmnd);
print_command(SCpnt->data_cmnd);
print_sense("sd", SCpnt);
SCpnt = scsi_end_request(SCpnt, 0, block_sectors);
return;
......@@ -798,33 +822,6 @@ void scsi_request_fn(request_queue_t * q)
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
* can also quit.
......
......@@ -54,6 +54,7 @@ EXPORT_SYMBOL(scsi_release_command);
EXPORT_SYMBOL(print_Scsi_Cmnd);
EXPORT_SYMBOL(scsi_block_when_processing_errors);
EXPORT_SYMBOL(scsi_ioctl_send_command);
EXPORT_SYMBOL(scsi_set_medium_removal);
#if defined(CONFIG_SCSI_LOGGING) /* { */
EXPORT_SYMBOL(scsi_logging_level);
#endif
......
......@@ -529,7 +529,7 @@ static int sd_open(struct inode *inode, struct file *filp)
if (sdp->removable)
if (sdp->access_count==1)
if (scsi_block_when_processing_errors(sdp))
scsi_ioctl(sdp, SCSI_IOCTL_DOORLOCK, NULL);
scsi_set_medium_removal(sdp, SCSI_REMOVAL_PREVENT);
return 0;
......@@ -573,7 +573,7 @@ static int sd_release(struct inode *inode, struct file *filp)
if (sdp->removable) {
if (!sdp->access_count)
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)
__MOD_DEC_USE_COUNT(sdp->host->hostt->module);
......@@ -1623,7 +1623,6 @@ static int sd_synchronize_cache(int index, int verbose)
}
the_result = SRpnt->sr_result;
scsi_release_request(SRpnt);
if(verbose) {
if(the_result != 0) {
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)
}
}
scsi_release_request(SRpnt);
return (the_result == 0);
}
......
......@@ -575,7 +575,7 @@ static void get_sectorsize(Scsi_CD *cd)
void get_capabilities(Scsi_CD *cd)
{
unsigned char cmd[6];
struct cdrom_generic_command cgc;
unsigned char *buffer;
int rc, n;
......@@ -597,13 +597,18 @@ void get_capabilities(Scsi_CD *cd)
printk(KERN_ERR "sr: out of memory.\n");
return;
}
cmd[0] = MODE_SENSE;
cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
memset(&cgc, 0, sizeof(struct cdrom_generic_command));
cgc.cmd[0] = MODE_SENSE;
cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
((cd->device->lun << 5) & 0xe0) : 0;
cmd[2] = 0x2a;
cmd[4] = 128;
cmd[3] = cmd[5] = 0;
rc = sr_do_ioctl(cd, cmd, buffer, 128, 1, SCSI_DATA_READ, NULL);
cgc.cmd[2] = 0x2a;
cgc.cmd[4] = 128;
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) {
/* 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
if (device->scsi_level <= SCSI_2)
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;
}
......
......@@ -20,6 +20,10 @@
#include "scsi.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 {
unsigned capacity; /* size in blocks */
Scsi_Device *device;
......@@ -34,7 +38,7 @@ typedef struct {
struct gendisk *disk;
} 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_tray_move(struct cdrom_device_info *, int);
......
This diff is collapsed.
......@@ -58,6 +58,8 @@
#define VENDOR_TOSHIBA 3
#define VENDOR_WRITER 4 /* pre-scsi3 writers */
#define VENDOR_TIMEOUT 30*HZ
void sr_vendor_init(Scsi_CD *cd)
{
#ifndef CONFIG_BLK_DEV_SR_VENDOR
......@@ -104,7 +106,7 @@ void sr_vendor_init(Scsi_CD *cd)
int sr_set_blocklength(Scsi_CD *cd, int blocklength)
{
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;
int rc, density = 0;
......@@ -120,19 +122,23 @@ int sr_set_blocklength(Scsi_CD *cd, int blocklength)
#ifdef DEBUG
printk("%s: MODE SELECT 0x%x/%d\n", cd->cdi.name, density, blocklength);
#endif
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = MODE_SELECT;
cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
memset(&cgc, 0, sizeof(struct cdrom_generic_command));
cgc.cmd[0] = MODE_SELECT;
cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
(cd->device->lun << 5) : 0;
cmd[1] |= (1 << 4);
cmd[4] = 12;
cgc.cmd[1] |= (1 << 4);
cgc.cmd[4] = 12;
modesel = (struct ccs_modesel_head *) buffer;
memset(modesel, 0, sizeof(*modesel));
modesel->block_desc_length = 0x08;
modesel->density = density;
modesel->block_length_med = (blocklength >> 8) & 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;
}
#ifdef DEBUG
......@@ -154,7 +160,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
Scsi_CD *cd = cdi->handle;
unsigned long sector;
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;
if (cd->cdi.mask & CDC_MULTI_SESSION)
......@@ -168,16 +174,22 @@ int sr_cd_check(struct cdrom_device_info *cdi)
no_multi = 0; /* flag: the drive can't handle multisession */
rc = 0;
memset(&cgc, 0, sizeof(struct cdrom_generic_command));
switch (cd->vendor) {
case VENDOR_SCSI3:
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = READ_TOC;
cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
cgc.cmd[0] = READ_TOC;
cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
(cd->device->lun << 5) : 0;
cmd[8] = 12;
cmd[9] = 0x40;
rc = sr_do_ioctl(cd, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL);
cgc.cmd[8] = 12;
cgc.cmd[9] = 0x40;
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)
break;
if ((buffer[0] << 8) + buffer[1] < 0x0a) {
......@@ -197,13 +209,17 @@ int sr_cd_check(struct cdrom_device_info *cdi)
#ifdef CONFIG_BLK_DEV_SR_VENDOR
case VENDOR_NEC:{
unsigned long min, sec, frame;
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = 0xde;
cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
cgc.cmd[0] = 0xde;
cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
(cd->device->lun << 5) : 0;
cmd[1] |= 0x03;
cmd[2] = 0xb0;
rc = sr_do_ioctl(cd, cmd, buffer, 0x16, 1, SCSI_DATA_READ, NULL);
cgc.cmd[1] |= 0x03;
cgc.cmd[2] = 0xb0;
cgc.buffer = buffer;
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)
break;
if (buffer[14] != 0 && buffer[14] != 0xb0) {
......@@ -225,12 +241,16 @@ int sr_cd_check(struct cdrom_device_info *cdi)
/* we request some disc information (is it a XA-CD ?,
* where starts the last session ?) */
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = 0xc7;
cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
cgc.cmd[0] = 0xc7;
cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
(cd->device->lun << 5) : 0;
cmd[1] |= 0x03;
rc = sr_do_ioctl(cd, cmd, buffer, 4, 1, SCSI_DATA_READ, NULL);
cgc.cmd[1] |= 0x03;
cgc.buffer = buffer;
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) {
printk(KERN_INFO "%s: Hmm, seems the drive "
"doesn't support multisession CD's\n",
......@@ -251,13 +271,17 @@ int sr_cd_check(struct cdrom_device_info *cdi)
}
case VENDOR_WRITER:
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = READ_TOC;
cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
cgc.cmd[0] = READ_TOC;
cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
(cd->device->lun << 5) : 0;
cmd[8] = 0x04;
cmd[9] = 0x40;
rc = sr_do_ioctl(cd, cmd, buffer, 0x04, 1, SCSI_DATA_READ, NULL);
cgc.cmd[8] = 0x04;
cgc.cmd[9] = 0x40;
cgc.buffer = buffer;
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) {
break;
}
......@@ -266,13 +290,18 @@ int sr_cd_check(struct cdrom_device_info *cdi)
"%s: No finished session\n", cd->cdi.name);
break;
}
cmd[0] = READ_TOC; /* Read TOC */
cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
cgc.cmd[0] = READ_TOC; /* Read TOC */
cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
(cd->device->lun << 5) : 0;
cmd[6] = rc & 0x7f; /* number of last session */
cmd[8] = 0x0c;
cmd[9] = 0x40;
rc = sr_do_ioctl(cd, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL);
cgc.cmd[6] = rc & 0x7f; /* number of last session */
cgc.cmd[8] = 0x0c;
cgc.cmd[9] = 0x40;
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) {
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