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 */
......
...@@ -8,6 +8,10 @@ ...@@ -8,6 +8,10 @@
* *
* Restructured scsi_unjam_host and associated functions. * Restructured scsi_unjam_host and associated functions.
* September 04, 2002 Mike Anderson (andmike@us.ibm.com) * September 04, 2002 Mike Anderson (andmike@us.ibm.com)
*
* Forward port of Russell King's (rmk@arm.linux.org.uk) changes and
* minor cleanups.
* September 30, 2002 Mike Anderson (andmike@us.ibm.com)
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -35,6 +39,8 @@ ...@@ -35,6 +39,8 @@
#include "scsi.h" #include "scsi.h"
#include "hosts.h" #include "hosts.h"
#include <scsi/scsi_ioctl.h> /* grr */
/* /*
* We must always allow SHUTDOWN_SIGS. Even if we are not a module, * We must always allow SHUTDOWN_SIGS. Even if we are not a module,
* the host drivers that we are using may be loaded as modules, and * the host drivers that we are using may be loaded as modules, and
...@@ -59,7 +65,7 @@ ...@@ -59,7 +65,7 @@
* These should *probably* be handled by the host itself. * These should *probably* be handled by the host itself.
* Since it is allowed to sleep, it probably should. * Since it is allowed to sleep, it probably should.
*/ */
#define BUS_RESET_SETTLE_TIME 5*HZ #define BUS_RESET_SETTLE_TIME 10*HZ
#define HOST_RESET_SETTLE_TIME 10*HZ #define HOST_RESET_SETTLE_TIME 10*HZ
/** /**
...@@ -91,9 +97,9 @@ void scsi_add_timer(Scsi_Cmnd *scmd, int timeout, void (*complete) ...@@ -91,9 +97,9 @@ void scsi_add_timer(Scsi_Cmnd *scmd, int timeout, void (*complete)
scmd->eh_timeout.expires = jiffies + timeout; scmd->eh_timeout.expires = jiffies + timeout;
scmd->eh_timeout.function = (void (*)(unsigned long)) complete; scmd->eh_timeout.function = (void (*)(unsigned long)) complete;
SCSI_LOG_ERROR_RECOVERY(5, printk("Adding timer for command %p at" SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:"
"%d (%p)\n", scmd, timeout, " %d, (%p)\n", __FUNCTION__,
complete)); scmd, timeout, complete));
add_timer(&scmd->eh_timeout); add_timer(&scmd->eh_timeout);
...@@ -116,8 +122,9 @@ int scsi_delete_timer(Scsi_Cmnd *scmd) ...@@ -116,8 +122,9 @@ int scsi_delete_timer(Scsi_Cmnd *scmd)
rtn = del_timer(&scmd->eh_timeout); rtn = del_timer(&scmd->eh_timeout);
SCSI_LOG_ERROR_RECOVERY(5, printk("Clearing timer for command %p" SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p,"
" %d\n", scmd, rtn)); " rtn: %d\n", __FUNCTION__,
scmd, rtn));
scmd->eh_timeout.data = (unsigned long) NULL; scmd->eh_timeout.data = (unsigned long) NULL;
scmd->eh_timeout.function = NULL; scmd->eh_timeout.function = NULL;
...@@ -150,7 +157,7 @@ void scsi_times_out(Scsi_Cmnd *scmd) ...@@ -150,7 +157,7 @@ void scsi_times_out(Scsi_Cmnd *scmd)
scsi_host_failed_inc_and_test(scmd->host); scsi_host_failed_inc_and_test(scmd->host);
SCSI_LOG_TIMEOUT(3, printk("Command timed out active=%d busy=%d " SCSI_LOG_TIMEOUT(3, printk("Command timed out active=%d busy=%d "
"failed=%d\n", " failed=%d\n",
atomic_read(&scmd->host->host_active), atomic_read(&scmd->host->host_active),
scmd->host->host_busy, scmd->host->host_busy,
scmd->host->host_failed)); scmd->host->host_failed));
...@@ -173,7 +180,7 @@ int scsi_block_when_processing_errors(Scsi_Device *sdev) ...@@ -173,7 +180,7 @@ int scsi_block_when_processing_errors(Scsi_Device *sdev)
SCSI_SLEEP(&sdev->host->host_wait, sdev->host->in_recovery); SCSI_SLEEP(&sdev->host->host_wait, sdev->host->in_recovery);
SCSI_LOG_ERROR_RECOVERY(5, printk("Open returning %d\n", SCSI_LOG_ERROR_RECOVERY(5, printk("%s: rtn: %d\n", __FUNCTION__,
sdev->online)); sdev->online));
return sdev->online; return sdev->online;
...@@ -209,10 +216,10 @@ static void scsi_eh_prt_fail_stats(Scsi_Cmnd *sc_list, struct Scsi_Host *shost) ...@@ -209,10 +216,10 @@ static void scsi_eh_prt_fail_stats(Scsi_Cmnd *sc_list, struct Scsi_Host *shost)
if (cmd_timed_out || cmd_failed) { if (cmd_timed_out || cmd_failed) {
SCSI_LOG_ERROR_RECOVERY(3, SCSI_LOG_ERROR_RECOVERY(3,
printk("scsi_eh: %d:%d:%d:%d cmds failed: %d," printk("%s: %d:%d:%d:%d cmds failed: %d,"
"timedout: %d\n", " timedout: %d\n",
shost->host_no, sdev->channel, __FUNCTION__, shost->host_no,
sdev->id, sdev->lun, sdev->channel, sdev->id, sdev->lun,
cmd_failed, cmd_timed_out)); cmd_failed, cmd_timed_out));
cmd_timed_out = 0; cmd_timed_out = 0;
cmd_failed = 0; cmd_failed = 0;
...@@ -220,8 +227,8 @@ static void scsi_eh_prt_fail_stats(Scsi_Cmnd *sc_list, struct Scsi_Host *shost) ...@@ -220,8 +227,8 @@ static void scsi_eh_prt_fail_stats(Scsi_Cmnd *sc_list, struct Scsi_Host *shost)
} }
} }
SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d commands on %d " SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d commands on %d"
"devices require eh work\n", " devices require eh work\n",
total_failures, devices_failed)); total_failures, devices_failed));
} }
#endif #endif
...@@ -265,10 +272,10 @@ static void scsi_eh_get_failed(Scsi_Cmnd **sc_list, struct Scsi_Host *shost) ...@@ -265,10 +272,10 @@ static void scsi_eh_get_failed(Scsi_Cmnd **sc_list, struct Scsi_Host *shost)
* queued and will be finished along the * queued and will be finished along the
* way. * way.
*/ */
SCSI_LOG_ERROR_RECOVERY(1, printk("Error hdlr " SCSI_LOG_ERROR_RECOVERY(1, printk("Error hdlr"
"prematurely woken " " prematurely woken"
"cmds still active " " cmds still active"
"(%p %x %d)\n", " (%p %x %d)\n",
scmd, scmd->state, scmd, scmd->state,
scmd->target)); scmd->target));
} }
...@@ -278,12 +285,17 @@ static void scsi_eh_get_failed(Scsi_Cmnd **sc_list, struct Scsi_Host *shost) ...@@ -278,12 +285,17 @@ static void scsi_eh_get_failed(Scsi_Cmnd **sc_list, struct Scsi_Host *shost)
SCSI_LOG_ERROR_RECOVERY(1, scsi_eh_prt_fail_stats(*sc_list, shost)); SCSI_LOG_ERROR_RECOVERY(1, scsi_eh_prt_fail_stats(*sc_list, shost));
BUG_ON(shost->host_failed != found); if (shost->host_failed != found)
printk(KERN_ERR "%s: host_failed: %d != found: %d\n",
__FUNCTION__, shost->host_failed, found);
} }
/** /**
* scsi_check_sense - Examine scsi cmd sense * scsi_check_sense - Examine scsi cmd sense
* @scmd: Cmd to have sense checked. * @scmd: Cmd to have sense checked.
*
* Return value:
* SUCCESS or FAILED or NEEDS_RETRY
**/ **/
static int scsi_check_sense(Scsi_Cmnd *scmd) static int scsi_check_sense(Scsi_Cmnd *scmd)
{ {
...@@ -353,7 +365,6 @@ static int scsi_check_sense(Scsi_Cmnd *scmd) ...@@ -353,7 +365,6 @@ static int scsi_check_sense(Scsi_Cmnd *scmd)
**/ **/
static int scsi_eh_completed_normally(Scsi_Cmnd *scmd) static int scsi_eh_completed_normally(Scsi_Cmnd *scmd)
{ {
int rtn;
/* /*
* first check the host byte, to see if there is anything in there * first check the host byte, to see if there is anything in there
...@@ -369,7 +380,7 @@ static int scsi_eh_completed_normally(Scsi_Cmnd *scmd) ...@@ -369,7 +380,7 @@ static int scsi_eh_completed_normally(Scsi_Cmnd *scmd)
* SUCCESS. * SUCCESS.
*/ */
scmd->flags &= ~IS_RESETTING; scmd->flags &= ~IS_RESETTING;
goto maybe_retry; return NEEDS_RETRY;
} }
/* /*
* rats. we are already in the error handler, so we now * rats. we are already in the error handler, so we now
...@@ -377,10 +388,7 @@ static int scsi_eh_completed_normally(Scsi_Cmnd *scmd) ...@@ -377,10 +388,7 @@ static int scsi_eh_completed_normally(Scsi_Cmnd *scmd)
* is valid, we have a pretty good idea of what to do. * is valid, we have a pretty good idea of what to do.
* if not, we mark it as FAILED. * if not, we mark it as FAILED.
*/ */
rtn = scsi_check_sense(scmd); return scsi_check_sense(scmd);
if (rtn == NEEDS_RETRY)
goto maybe_retry;
return rtn;
} }
if (host_byte(scmd->result) != DID_OK) { if (host_byte(scmd->result) != DID_OK) {
return FAILED; return FAILED;
...@@ -400,10 +408,7 @@ static int scsi_eh_completed_normally(Scsi_Cmnd *scmd) ...@@ -400,10 +408,7 @@ static int scsi_eh_completed_normally(Scsi_Cmnd *scmd)
case COMMAND_TERMINATED: case COMMAND_TERMINATED:
return SUCCESS; return SUCCESS;
case CHECK_CONDITION: case CHECK_CONDITION:
rtn = scsi_check_sense(scmd); return scsi_check_sense(scmd);
if (rtn == NEEDS_RETRY)
goto maybe_retry;
return rtn;
case CONDITION_GOOD: case CONDITION_GOOD:
case INTERMEDIATE_GOOD: case INTERMEDIATE_GOOD:
case INTERMEDIATE_C_GOOD: case INTERMEDIATE_C_GOOD:
...@@ -418,14 +423,6 @@ static int scsi_eh_completed_normally(Scsi_Cmnd *scmd) ...@@ -418,14 +423,6 @@ static int scsi_eh_completed_normally(Scsi_Cmnd *scmd)
return FAILED; return FAILED;
} }
return FAILED; return FAILED;
maybe_retry:
if ((++scmd->retries) < scmd->allowed) {
return NEEDS_RETRY;
} else {
/* no more retries - report this one back to upper level */
return SUCCESS;
}
} }
/** /**
...@@ -440,12 +437,13 @@ static int scsi_eh_completed_normally(Scsi_Cmnd *scmd) ...@@ -440,12 +437,13 @@ static int scsi_eh_completed_normally(Scsi_Cmnd *scmd)
static void scsi_eh_times_out(Scsi_Cmnd *scmd) static void scsi_eh_times_out(Scsi_Cmnd *scmd)
{ {
scsi_eh_eflags_set(scmd, SCSI_EH_REC_TIMEOUT); scsi_eh_eflags_set(scmd, SCSI_EH_REC_TIMEOUT);
SCSI_LOG_ERROR_RECOVERY(3, printk("in scsi_eh_times_out %p\n", scmd)); SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd:%p\n", __FUNCTION__,
scmd));
if (scmd->host->eh_action != NULL) if (scmd->host->eh_action != NULL)
up(scmd->host->eh_action); up(scmd->host->eh_action);
else else
printk("missing scsi error handler thread\n"); printk("%s: eh_action NULL\n", __FUNCTION__);
} }
/** /**
...@@ -471,8 +469,8 @@ static void scsi_eh_done(Scsi_Cmnd *scmd) ...@@ -471,8 +469,8 @@ static void scsi_eh_done(Scsi_Cmnd *scmd)
scmd->owner = SCSI_OWNER_ERROR_HANDLER; scmd->owner = SCSI_OWNER_ERROR_HANDLER;
SCSI_LOG_ERROR_RECOVERY(3, printk("in eh_done %p result:%x\n", scmd, SCSI_LOG_ERROR_RECOVERY(3, printk("%s scmd: %p result: %x\n",
scmd->result)); __FUNCTION__, scmd, scmd->result));
if (scmd->host->eh_action != NULL) if (scmd->host->eh_action != NULL)
up(scmd->host->eh_action); up(scmd->host->eh_action);
...@@ -488,7 +486,7 @@ static void scsi_eh_done(Scsi_Cmnd *scmd) ...@@ -488,7 +486,7 @@ static void scsi_eh_done(Scsi_Cmnd *scmd)
* this case, and furthermore, there is a different completion handler * this case, and furthermore, there is a different completion handler
* vs scsi_dispatch_cmd. * vs scsi_dispatch_cmd.
* Return value: * Return value:
* SUCCESS/FAILED * SUCCESS or FAILED or NEEDS_RETRY
**/ **/
static int scsi_send_eh_cmnd(Scsi_Cmnd *scmd, int timeout) static int scsi_send_eh_cmnd(Scsi_Cmnd *scmd, int timeout)
{ {
...@@ -498,7 +496,6 @@ static int scsi_send_eh_cmnd(Scsi_Cmnd *scmd, int timeout) ...@@ -498,7 +496,6 @@ static int scsi_send_eh_cmnd(Scsi_Cmnd *scmd, int timeout)
ASSERT_LOCK(host->host_lock, 0); ASSERT_LOCK(host->host_lock, 0);
retry:
/* /*
* we will use a queued command if possible, otherwise we will * we will use a queued command if possible, otherwise we will
* emulate the queuing and calling of completion function ourselves. * emulate the queuing and calling of completion function ourselves.
...@@ -552,9 +549,8 @@ static int scsi_send_eh_cmnd(Scsi_Cmnd *scmd, int timeout) ...@@ -552,9 +549,8 @@ static int scsi_send_eh_cmnd(Scsi_Cmnd *scmd, int timeout)
rtn = FAILED; rtn = FAILED;
} }
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: %p rtn:%x\n", SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd: %p, rtn:%x\n",
__FUNCTION__, scmd, __FUNCTION__, scmd, rtn));
rtn));
} else { } else {
int temp; int temp;
...@@ -576,16 +572,15 @@ static int scsi_send_eh_cmnd(Scsi_Cmnd *scmd, int timeout) ...@@ -576,16 +572,15 @@ static int scsi_send_eh_cmnd(Scsi_Cmnd *scmd, int timeout)
* actually did complete normally. * actually did complete normally.
*/ */
if (rtn == SUCCESS) { if (rtn == SUCCESS) {
int ret = scsi_eh_completed_normally(scmd); int rtn = scsi_eh_completed_normally(scmd);
SCSI_LOG_ERROR_RECOVERY(3, SCSI_LOG_ERROR_RECOVERY(3,
printk("%s: scsi_eh_completed_normally %x\n", printk("%s: scsi_eh_completed_normally %x\n",
__FUNCTION__, ret)); __FUNCTION__, rtn));
switch (ret) { switch (rtn) {
case SUCCESS: case SUCCESS:
break;
case NEEDS_RETRY: case NEEDS_RETRY:
goto retry;
case FAILED: case FAILED:
break;
default: default:
rtn = FAILED; rtn = FAILED;
break; break;
...@@ -622,7 +617,7 @@ static int scsi_request_sense(Scsi_Cmnd *scmd) ...@@ -622,7 +617,7 @@ static int scsi_request_sense(Scsi_Cmnd *scmd)
? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA); ? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA);
if (scsi_result == NULL) { if (scsi_result == NULL) {
printk("cannot allocate scsi_result in scsi_request_sense.\n"); printk("%s: cannot allocate scsi_result.\n", __FUNCTION__);
return FAILED; return FAILED;
} }
/* /*
...@@ -657,15 +652,8 @@ static int scsi_request_sense(Scsi_Cmnd *scmd) ...@@ -657,15 +652,8 @@ static int scsi_request_sense(Scsi_Cmnd *scmd)
* when we eventually call scsi_finish, we really wish to complete * when we eventually call scsi_finish, we really wish to complete
* the original request, so let's restore the original data. (db) * the original request, so let's restore the original data. (db)
*/ */
memcpy((void *) scmd->cmnd, (void *) scmd->data_cmnd, scsi_setup_cmd_retry(scmd);
sizeof(scmd->data_cmnd));
scmd->result = saved_result; scmd->result = saved_result;
scmd->request_buffer = scmd->buffer;
scmd->request_bufflen = scmd->bufflen;
scmd->use_sg = scmd->old_use_sg;
scmd->cmd_len = scmd->old_cmd_len;
scmd->sc_data_direction = scmd->sc_old_data_direction;
scmd->underflow = scmd->old_underflow;
/* /*
* hey, we are done. let's look to see what happened. * hey, we are done. let's look to see what happened.
...@@ -683,16 +671,16 @@ static int scsi_request_sense(Scsi_Cmnd *scmd) ...@@ -683,16 +671,16 @@ static int scsi_request_sense(Scsi_Cmnd *scmd)
**/ **/
static int scsi_eh_retry_cmd(Scsi_Cmnd *scmd) static int scsi_eh_retry_cmd(Scsi_Cmnd *scmd)
{ {
memcpy((void *) scmd->cmnd, (void *) scmd->data_cmnd, int rtn = SUCCESS;
sizeof(scmd->data_cmnd));
scmd->request_buffer = scmd->buffer; for (; scmd->retries < scmd->allowed; scmd->retries++) {
scmd->request_bufflen = scmd->bufflen; scsi_setup_cmd_retry(scmd);
scmd->use_sg = scmd->old_use_sg; rtn = scsi_send_eh_cmnd(scmd, scmd->timeout_per_command);
scmd->cmd_len = scmd->old_cmd_len; if (rtn != NEEDS_RETRY)
scmd->sc_data_direction = scmd->sc_old_data_direction; break;
scmd->underflow = scmd->old_underflow; }
return scsi_send_eh_cmnd(scmd, scmd->timeout_per_command); return rtn;
} }
/** /**
...@@ -717,9 +705,7 @@ static void scsi_eh_finish_cmd(Scsi_Cmnd *scmd, struct Scsi_Host *shost) ...@@ -717,9 +705,7 @@ static void scsi_eh_finish_cmd(Scsi_Cmnd *scmd, struct Scsi_Host *shost)
* set this back so that the upper level can correctly free up * set this back so that the upper level can correctly free up
* things. * things.
*/ */
scmd->use_sg = scmd->old_use_sg; scsi_setup_cmd_retry(scmd);
scmd->sc_data_direction = scmd->sc_old_data_direction;
scmd->underflow = scmd->old_underflow;
} }
/** /**
...@@ -758,14 +744,14 @@ static int scsi_eh_get_sense(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost) ...@@ -758,14 +744,14 @@ static int scsi_eh_get_sense(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
continue; continue;
SCSI_LOG_ERROR_RECOVERY(2, printk("%s: requesting sense" SCSI_LOG_ERROR_RECOVERY(2, printk("%s: requesting sense"
"for %d\n", __FUNCTION__, " for tgt: %d\n",
scmd->target)); __FUNCTION__, scmd->target));
rtn = scsi_request_sense(scmd); rtn = scsi_request_sense(scmd);
if (rtn != SUCCESS) if (rtn != SUCCESS)
continue; continue;
SCSI_LOG_ERROR_RECOVERY(3, printk("sense requested for %p" SCSI_LOG_ERROR_RECOVERY(3, printk("sense requested for %p"
"- result %x\n", scmd, " result %x\n", scmd,
scmd->result)); scmd->result));
SCSI_LOG_ERROR_RECOVERY(3, print_sense("bh", scmd)); SCSI_LOG_ERROR_RECOVERY(3, print_sense("bh", scmd));
...@@ -847,7 +833,9 @@ static int scsi_eh_tur(Scsi_Cmnd *scmd) ...@@ -847,7 +833,9 @@ static int scsi_eh_tur(Scsi_Cmnd *scmd)
static unsigned char tur_command[6] = static unsigned char tur_command[6] =
{TEST_UNIT_READY, 0, 0, 0, 0, 0}; {TEST_UNIT_READY, 0, 0, 0, 0, 0};
int rtn; int rtn;
int retry_cnt = 1;
retry_tur:
memcpy((void *) scmd->cmnd, (void *) tur_command, memcpy((void *) scmd->cmnd, (void *) tur_command,
sizeof(tur_command)); sizeof(tur_command));
...@@ -873,32 +861,18 @@ static int scsi_eh_tur(Scsi_Cmnd *scmd) ...@@ -873,32 +861,18 @@ static int scsi_eh_tur(Scsi_Cmnd *scmd)
* when we eventually call scsi_finish, we really wish to complete * when we eventually call scsi_finish, we really wish to complete
* the original request, so let's restore the original data. (db) * the original request, so let's restore the original data. (db)
*/ */
memcpy((void *) scmd->cmnd, (void *) scmd->data_cmnd, scsi_setup_cmd_retry(scmd);
sizeof(scmd->data_cmnd));
scmd->request_buffer = scmd->buffer;
scmd->request_bufflen = scmd->bufflen;
scmd->use_sg = scmd->old_use_sg;
scmd->cmd_len = scmd->old_cmd_len;
scmd->sc_data_direction = scmd->sc_old_data_direction;
scmd->underflow = scmd->old_underflow;
/* /*
* hey, we are done. let's look to see what happened. * hey, we are done. let's look to see what happened.
*/ */
SCSI_LOG_ERROR_RECOVERY(3, SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n",
printk("%s: scmd %p rtn %x\n",
__FUNCTION__, scmd, rtn)); __FUNCTION__, scmd, rtn));
if ((rtn == SUCCESS) && scmd->result) { if (rtn == SUCCESS)
if (((driver_byte(scmd->result) & DRIVER_SENSE) ||
(status_byte(scmd->result) & CHECK_CONDITION)) &&
(SCSI_SENSE_VALID(scmd))) {
if (((scmd->sense_buffer[2] & 0xf) != NOT_READY) &&
((scmd->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
((scmd->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST)) {
return 0; return 0;
} else if (rtn == NEEDS_RETRY)
} if (retry_cnt--)
} goto retry_tur;
return 1; return 1;
} }
...@@ -929,7 +903,7 @@ static int scsi_eh_abort_cmd(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost) ...@@ -929,7 +903,7 @@ static int scsi_eh_abort_cmd(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
rtn = scsi_try_to_abort_cmd(scmd); rtn = scsi_try_to_abort_cmd(scmd);
if (rtn == SUCCESS) { if (rtn == SUCCESS) {
if (scsi_eh_tur(scmd)) { if (!scsi_eh_tur(scmd)) {
rtn = scsi_eh_retry_cmd(scmd); rtn = scsi_eh_retry_cmd(scmd);
if (rtn == SUCCESS) if (rtn == SUCCESS)
scsi_eh_finish_cmd(scmd, shost); scsi_eh_finish_cmd(scmd, shost);
...@@ -963,6 +937,11 @@ static int scsi_try_bus_device_reset(Scsi_Cmnd *scmd) ...@@ -963,6 +937,11 @@ static int scsi_try_bus_device_reset(Scsi_Cmnd *scmd)
rtn = scmd->host->hostt->eh_device_reset_handler(scmd); rtn = scmd->host->hostt->eh_device_reset_handler(scmd);
spin_unlock_irqrestore(scmd->host->host_lock, flags); spin_unlock_irqrestore(scmd->host->host_lock, flags);
if (rtn == SUCCESS) {
scmd->device->was_reset = 1;
scmd->device->expecting_cc_ua = 1;
}
return rtn; return rtn;
} }
...@@ -999,7 +978,7 @@ static int scsi_eh_bus_device_reset(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost) ...@@ -999,7 +978,7 @@ static int scsi_eh_bus_device_reset(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
* a bus device reset to it. * a bus device reset to it.
*/ */
rtn = scsi_try_bus_device_reset(scmd); rtn = scsi_try_bus_device_reset(scmd);
if ((rtn == SUCCESS) && (scsi_eh_tur(scmd))) if ((rtn == SUCCESS) && (!scsi_eh_tur(scmd)))
for (scmd = sc_todo; scmd; scmd = scmd->bh_next) for (scmd = sc_todo; scmd; scmd = scmd->bh_next)
if ((scmd->device == sdev) && if ((scmd->device == sdev) &&
scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR)) { scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR)) {
...@@ -1141,7 +1120,7 @@ static int scsi_eh_bus_host_reset(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost) ...@@ -1141,7 +1120,7 @@ static int scsi_eh_bus_host_reset(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
if (!scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR) if (!scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR)
|| channel != scmd->channel) || channel != scmd->channel)
continue; continue;
if (scsi_eh_tur(scmd)) { if (!scsi_eh_tur(scmd)) {
rtn = scsi_eh_retry_cmd(scmd); rtn = scsi_eh_retry_cmd(scmd);
if (rtn == SUCCESS) if (rtn == SUCCESS)
...@@ -1168,10 +1147,10 @@ static void scsi_eh_offline_sdevs(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost) ...@@ -1168,10 +1147,10 @@ static void scsi_eh_offline_sdevs(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
if (!scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR)) if (!scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR))
continue; continue;
printk(KERN_INFO "%s: Device set offline - not" printk(KERN_INFO "%s: Device offlined - not"
"ready or command retry failed" " ready or command retry failed"
"after error recovery: host" " after error recovery: host"
"%d channel %d id %d lun %d\n", " %d channel %d id %d lun %d\n",
__FUNCTION__, shost->host_no, __FUNCTION__, shost->host_no,
scmd->device->channel, scmd->device->channel,
scmd->device->id, scmd->device->id,
...@@ -1243,7 +1222,7 @@ int scsi_decide_disposition(Scsi_Cmnd *scmd) ...@@ -1243,7 +1222,7 @@ int scsi_decide_disposition(Scsi_Cmnd *scmd)
*/ */
if (scmd->device->online == FALSE) { if (scmd->device->online == FALSE) {
SCSI_LOG_ERROR_RECOVERY(5, printk("%s: device offline - report" SCSI_LOG_ERROR_RECOVERY(5, printk("%s: device offline - report"
"as SUCCESS\n", " as SUCCESS\n",
__FUNCTION__)); __FUNCTION__));
return SUCCESS; return SUCCESS;
} }
...@@ -1388,6 +1367,75 @@ int scsi_decide_disposition(Scsi_Cmnd *scmd) ...@@ -1388,6 +1367,75 @@ int scsi_decide_disposition(Scsi_Cmnd *scmd)
} }
} }
/**
* scsi_eh_lock_done - done function for eh door lock request
* @scmd: SCSI command block for the door lock request
*
* Notes:
* We completed the asynchronous door lock request, and it has either
* locked the door or failed. We must free the command structures
* associated with this request.
**/
static void scsi_eh_lock_done(struct scsi_cmnd *scmd)
{
struct scsi_request *sreq = scmd->sc_request;
scmd->sc_request = NULL;
sreq->sr_command = NULL;
scsi_release_command(scmd);
scsi_release_request(sreq);
}
/**
* scsi_eh_lock_door - Prevent medium removal for the specified device
* @sdev: SCSI device to prevent medium removal
*
* Locking:
* We must be called from process context; scsi_allocate_request()
* may sleep.
*
* Notes:
* We queue up an asynchronous "ALLOW MEDIUM REMOVAL" request on the
* head of the devices request queue, and continue.
*
* Bugs:
* scsi_allocate_request() may sleep waiting for existing requests to
* be processed. However, since we haven't kicked off any request
* processing for this host, this may deadlock.
*
* If scsi_allocate_request() fails for what ever reason, we
* completely forget to lock the door.
**/
static void scsi_eh_lock_door(struct scsi_device *sdev)
{
struct scsi_request *sreq = scsi_allocate_request(sdev);
if (sreq == NULL) {
printk(KERN_ERR "%s: request allocate failed,"
"prevent media removal cmd not sent", __FUNCTION__);
return;
}
sreq->sr_cmnd[0] = ALLOW_MEDIUM_REMOVAL;
sreq->sr_cmnd[1] = (sdev->scsi_level <= SCSI_2) ? (sdev->lun << 5) : 0;
sreq->sr_cmnd[2] = 0;
sreq->sr_cmnd[3] = 0;
sreq->sr_cmnd[4] = SCSI_REMOVAL_PREVENT;
sreq->sr_cmnd[5] = 0;
sreq->sr_data_direction = SCSI_DATA_NONE;
sreq->sr_bufflen = 0;
sreq->sr_buffer = NULL;
sreq->sr_allowed = 5;
sreq->sr_done = scsi_eh_lock_done;
sreq->sr_timeout_per_command = 10 * HZ;
sreq->sr_cmd_len = COMMAND_SIZE(sreq->sr_cmnd[0]);
scsi_insert_special_req(sreq, 1);
}
/** /**
* scsi_restart_operations - restart io operations to the specified host. * scsi_restart_operations - restart io operations to the specified host.
* @shost: Host we are restarting. * @shost: Host we are restarting.
...@@ -1403,6 +1451,15 @@ static void scsi_restart_operations(struct Scsi_Host *shost) ...@@ -1403,6 +1451,15 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
ASSERT_LOCK(shost->host_lock, 0); ASSERT_LOCK(shost->host_lock, 0);
/*
* If the door was locked, we need to insert a door lock request
* onto the head of the SCSI request queue for the device. There
* is no point trying to lock the door of an off-line device.
*/
for (sdev = shost->host_queue; sdev; sdev = sdev->next)
if (sdev->online && sdev->locked)
scsi_eh_lock_door(sdev);
/* /*
* next free up anything directly waiting upon the host. this * next free up anything directly waiting upon the host. this
* will be requests for character device operations, and also for * will be requests for character device operations, and also for
...@@ -1426,8 +1483,7 @@ static void scsi_restart_operations(struct Scsi_Host *shost) ...@@ -1426,8 +1483,7 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
if ((shost->can_queue > 0 && if ((shost->can_queue > 0 &&
(shost->host_busy >= shost->can_queue)) (shost->host_busy >= shost->can_queue))
|| (shost->host_blocked) || (shost->host_blocked)
|| (shost->host_self_blocked) || (shost->host_self_blocked)) {
|| (sdev->device_blocked)) {
break; break;
} }
...@@ -1475,7 +1531,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost) ...@@ -1475,7 +1531,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost)
if (scsi_eh_get_sense(sc_todo, shost)) if (scsi_eh_get_sense(sc_todo, shost))
if (scsi_eh_abort_cmd(sc_todo, shost)) if (scsi_eh_abort_cmd(sc_todo, shost))
if (scsi_eh_bus_device_reset(sc_todo, shost)) if (scsi_eh_bus_device_reset(sc_todo, shost))
if(scsi_eh_bus_host_reset(sc_todo, shost)) if (scsi_eh_bus_host_reset(sc_todo, shost))
scsi_eh_offline_sdevs(sc_todo, shost); scsi_eh_offline_sdevs(sc_todo, shost);
BUG_ON(shost->host_failed); BUG_ON(shost->host_failed);
...@@ -1563,8 +1619,7 @@ void scsi_error_handler(void *data) ...@@ -1563,8 +1619,7 @@ void scsi_error_handler(void *data)
/* /*
* Wake up the thread that created us. * Wake up the thread that created us.
*/ */
SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent %d\n", SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent \n"));
shost->eh_notify->count.counter));
up(shost->eh_notify); up(shost->eh_notify);
......
...@@ -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;
cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
((cd->device->lun << 5) & 0xe0) : 0; ((cd->device->lun << 5) & 0xe0) : 0;
cmd[2] = 0x2a; cgc.cmd[2] = 0x2a;
cmd[4] = 128; cgc.cmd[4] = 128;
cmd[3] = cmd[5] = 0; cgc.buffer = buffer;
rc = sr_do_ioctl(cd, cmd, buffer, 128, 1, SCSI_DATA_READ, NULL); 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);
......
...@@ -25,9 +25,6 @@ ...@@ -25,9 +25,6 @@
static int xa_test = 0; static int xa_test = 0;
#define IOCTL_RETRIES 3 #define IOCTL_RETRIES 3
/* 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
/* ATAPI drives don't have a SCMD_PLAYAUDIO_TI command. When these drives /* ATAPI drives don't have a SCMD_PLAYAUDIO_TI command. When these drives
are emulating a SCSI device via the idescsi module, they need to have are emulating a SCSI device via the idescsi module, they need to have
...@@ -37,7 +34,7 @@ static int sr_fake_playtrkind(struct cdrom_device_info *cdi, struct cdrom_ti *ti ...@@ -37,7 +34,7 @@ static int sr_fake_playtrkind(struct cdrom_device_info *cdi, struct cdrom_ti *ti
{ {
struct cdrom_tocentry trk0_te, trk1_te; struct cdrom_tocentry trk0_te, trk1_te;
struct cdrom_tochdr tochdr; struct cdrom_tochdr tochdr;
u_char sr_cmd[10]; struct cdrom_generic_command cgc;
int ntracks, ret; int ntracks, ret;
if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCHDR, &tochdr))) if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCHDR, &tochdr)))
...@@ -60,21 +57,24 @@ static int sr_fake_playtrkind(struct cdrom_device_info *cdi, struct cdrom_ti *ti ...@@ -60,21 +57,24 @@ static int sr_fake_playtrkind(struct cdrom_device_info *cdi, struct cdrom_ti *ti
if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &trk1_te))) if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &trk1_te)))
return ret; return ret;
sr_cmd[0] = GPCMD_PLAY_AUDIO_MSF; memset(&cgc, 0, sizeof(struct cdrom_generic_command));
sr_cmd[3] = trk0_te.cdte_addr.msf.minute; cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
sr_cmd[4] = trk0_te.cdte_addr.msf.second; cgc.cmd[3] = trk0_te.cdte_addr.msf.minute;
sr_cmd[5] = trk0_te.cdte_addr.msf.frame; cgc.cmd[4] = trk0_te.cdte_addr.msf.second;
sr_cmd[6] = trk1_te.cdte_addr.msf.minute; cgc.cmd[5] = trk0_te.cdte_addr.msf.frame;
sr_cmd[7] = trk1_te.cdte_addr.msf.second; cgc.cmd[6] = trk1_te.cdte_addr.msf.minute;
sr_cmd[8] = trk1_te.cdte_addr.msf.frame; cgc.cmd[7] = trk1_te.cdte_addr.msf.second;
return sr_do_ioctl(cdi->handle, sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL); cgc.cmd[8] = trk1_te.cdte_addr.msf.frame;
cgc.data_direction = SCSI_DATA_NONE;
cgc.timeout = IOCTL_TIMEOUT;
return sr_do_ioctl(cdi->handle, &cgc);
} }
/* We do our own retries because we want to know what the specific /* We do our own retries because we want to know what the specific
error code is. Normally the UNIT_ATTENTION code will automatically error code is. Normally the UNIT_ATTENTION code will automatically
clear after one error */ clear after one error */
int sr_do_ioctl(Scsi_CD *cd, unsigned char *sr_cmd, void *buffer, unsigned buflength, int quiet, int readwrite, struct request_sense *sense) int sr_do_ioctl(Scsi_CD *cd, struct cdrom_generic_command *cgc)
{ {
Scsi_Request *SRpnt; Scsi_Request *SRpnt;
Scsi_Device *SDev; Scsi_Device *SDev;
...@@ -86,29 +86,32 @@ int sr_do_ioctl(Scsi_CD *cd, unsigned char *sr_cmd, void *buffer, unsigned bufle ...@@ -86,29 +86,32 @@ int sr_do_ioctl(Scsi_CD *cd, unsigned char *sr_cmd, void *buffer, unsigned bufle
SRpnt = scsi_allocate_request(SDev); SRpnt = scsi_allocate_request(SDev);
if (!SRpnt) { if (!SRpnt) {
printk("Unable to allocate SCSI request in sr_do_ioctl"); printk("Unable to allocate SCSI request in sr_do_ioctl");
return -ENOMEM; err = -ENOMEM;
goto out;
} }
SRpnt->sr_data_direction = readwrite; SRpnt->sr_data_direction = cgc->data_direction;
/* use ISA DMA buffer if necessary */ /* use ISA DMA buffer if necessary */
SRpnt->sr_request->buffer = buffer; SRpnt->sr_request->buffer = cgc->buffer;
if (buffer && SRpnt->sr_host->unchecked_isa_dma && if (cgc->buffer && SRpnt->sr_host->unchecked_isa_dma &&
(virt_to_phys(buffer) + buflength - 1 > ISA_DMA_THRESHOLD)) { (virt_to_phys(cgc->buffer) + cgc->buflen - 1 > ISA_DMA_THRESHOLD)) {
bounce_buffer = (char *) kmalloc(buflength, GFP_DMA); bounce_buffer = (char *) kmalloc(cgc->buflen, GFP_DMA);
if (bounce_buffer == NULL) { if (bounce_buffer == NULL) {
printk("SCSI DMA pool exhausted."); printk("SCSI DMA pool exhausted.");
return -ENOMEM; err = -ENOMEM;
goto out;
} }
memcpy(bounce_buffer, (char *) buffer, buflength); memcpy(bounce_buffer, cgc->buffer, cgc->buflen);
buffer = bounce_buffer; cgc->buffer = bounce_buffer;
} }
retry: retry:
if (!scsi_block_when_processing_errors(SDev)) if (!scsi_block_when_processing_errors(SDev)) {
return -ENODEV; err = -ENODEV;
goto out;
}
scsi_wait_req(SRpnt, (void *) sr_cmd, (void *) buffer, buflength, scsi_wait_req(SRpnt, cgc->cmd, cgc->buffer, cgc->buflen,
IOCTL_TIMEOUT, IOCTL_RETRIES); cgc->timeout, IOCTL_RETRIES);
req = SRpnt->sr_request; req = SRpnt->sr_request;
if (SRpnt->sr_buffer && req->buffer && SRpnt->sr_buffer != req->buffer) { if (SRpnt->sr_buffer && req->buffer && SRpnt->sr_buffer != req->buffer) {
...@@ -124,7 +127,7 @@ int sr_do_ioctl(Scsi_CD *cd, unsigned char *sr_cmd, void *buffer, unsigned bufle ...@@ -124,7 +127,7 @@ int sr_do_ioctl(Scsi_CD *cd, unsigned char *sr_cmd, void *buffer, unsigned bufle
switch (SRpnt->sr_sense_buffer[2] & 0xf) { switch (SRpnt->sr_sense_buffer[2] & 0xf) {
case UNIT_ATTENTION: case UNIT_ATTENTION:
SDev->changed = 1; SDev->changed = 1;
if (!quiet) if (!cgc->quiet)
printk(KERN_INFO "%s: disc change detected.\n", cd->cdi.name); printk(KERN_INFO "%s: disc change detected.\n", cd->cdi.name);
if (retries++ < 10) if (retries++ < 10)
goto retry; goto retry;
...@@ -134,7 +137,7 @@ int sr_do_ioctl(Scsi_CD *cd, unsigned char *sr_cmd, void *buffer, unsigned bufle ...@@ -134,7 +137,7 @@ int sr_do_ioctl(Scsi_CD *cd, unsigned char *sr_cmd, void *buffer, unsigned bufle
if (SRpnt->sr_sense_buffer[12] == 0x04 && if (SRpnt->sr_sense_buffer[12] == 0x04 &&
SRpnt->sr_sense_buffer[13] == 0x01) { SRpnt->sr_sense_buffer[13] == 0x01) {
/* sense: Logical unit is in process of becoming ready */ /* sense: Logical unit is in process of becoming ready */
if (!quiet) if (!cgc->quiet)
printk(KERN_INFO "%s: CDROM not ready yet.\n", cd->cdi.name); printk(KERN_INFO "%s: CDROM not ready yet.\n", cd->cdi.name);
if (retries++ < 10) { if (retries++ < 10) {
/* sleep 2 sec and try again */ /* sleep 2 sec and try again */
...@@ -146,7 +149,7 @@ int sr_do_ioctl(Scsi_CD *cd, unsigned char *sr_cmd, void *buffer, unsigned bufle ...@@ -146,7 +149,7 @@ int sr_do_ioctl(Scsi_CD *cd, unsigned char *sr_cmd, void *buffer, unsigned bufle
break; break;
} }
} }
if (!quiet) if (!cgc->quiet)
printk(KERN_INFO "%s: CDROM not ready. Make sure there is a disc in the drive.\n", cd->cdi.name); printk(KERN_INFO "%s: CDROM not ready. Make sure there is a disc in the drive.\n", cd->cdi.name);
#ifdef DEBUG #ifdef DEBUG
print_req_sense("sr", SRpnt); print_req_sense("sr", SRpnt);
...@@ -154,7 +157,7 @@ int sr_do_ioctl(Scsi_CD *cd, unsigned char *sr_cmd, void *buffer, unsigned bufle ...@@ -154,7 +157,7 @@ int sr_do_ioctl(Scsi_CD *cd, unsigned char *sr_cmd, void *buffer, unsigned bufle
err = -ENOMEDIUM; err = -ENOMEDIUM;
break; break;
case ILLEGAL_REQUEST: case ILLEGAL_REQUEST:
if (!quiet) if (!cgc->quiet)
printk(KERN_ERR "%s: CDROM (ioctl) reports ILLEGAL " printk(KERN_ERR "%s: CDROM (ioctl) reports ILLEGAL "
"REQUEST.\n", cd->cdi.name); "REQUEST.\n", cd->cdi.name);
if (SRpnt->sr_sense_buffer[12] == 0x20 && if (SRpnt->sr_sense_buffer[12] == 0x20 &&
...@@ -165,24 +168,26 @@ int sr_do_ioctl(Scsi_CD *cd, unsigned char *sr_cmd, void *buffer, unsigned bufle ...@@ -165,24 +168,26 @@ int sr_do_ioctl(Scsi_CD *cd, unsigned char *sr_cmd, void *buffer, unsigned bufle
err = -EINVAL; err = -EINVAL;
} }
#ifdef DEBUG #ifdef DEBUG
print_command(sr_cmd); print_command(cgc->cmd);
print_req_sense("sr", SRpnt); print_req_sense("sr", SRpnt);
#endif #endif
break; break;
default: default:
printk(KERN_ERR "%s: CDROM (ioctl) error, command: ", cd->cdi.name); printk(KERN_ERR "%s: CDROM (ioctl) error, command: ", cd->cdi.name);
print_command(sr_cmd); print_command(cgc->cmd);
print_req_sense("sr", SRpnt); print_req_sense("sr", SRpnt);
err = -EIO; err = -EIO;
} }
} }
if (sense) if (cgc->sense)
memcpy(sense, SRpnt->sr_sense_buffer, sizeof(*sense)); memcpy(cgc->sense, SRpnt->sr_sense_buffer, sizeof(*cgc->sense));
/* Wake up a process waiting for device */ /* Wake up a process waiting for device */
scsi_release_request(SRpnt); scsi_release_request(SRpnt);
SRpnt = NULL; SRpnt = NULL;
out:
cgc->stat = err;
return err; return err;
} }
...@@ -191,35 +196,39 @@ int sr_do_ioctl(Scsi_CD *cd, unsigned char *sr_cmd, void *buffer, unsigned bufle ...@@ -191,35 +196,39 @@ int sr_do_ioctl(Scsi_CD *cd, unsigned char *sr_cmd, void *buffer, unsigned bufle
static int test_unit_ready(Scsi_CD *cd) static int test_unit_ready(Scsi_CD *cd)
{ {
u_char sr_cmd[10]; struct cdrom_generic_command cgc;
sr_cmd[0] = GPCMD_TEST_UNIT_READY; memset(&cgc, 0, sizeof(struct cdrom_generic_command));
sr_cmd[1] = (cd->device->scsi_level <= SCSI_2) ? cgc.cmd[0] = GPCMD_TEST_UNIT_READY;
cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
((cd->device->lun) << 5) : 0; ((cd->device->lun) << 5) : 0;
sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; cgc.quiet = 1;
return sr_do_ioctl(cd, sr_cmd, NULL, 0, 1, SCSI_DATA_NONE, NULL); cgc.data_direction = SCSI_DATA_NONE;
cgc.timeout = IOCTL_TIMEOUT;
return sr_do_ioctl(cd, &cgc);
} }
int sr_tray_move(struct cdrom_device_info *cdi, int pos) int sr_tray_move(struct cdrom_device_info *cdi, int pos)
{ {
Scsi_CD *cd = cdi->handle; Scsi_CD *cd = cdi->handle;
u_char sr_cmd[10]; struct cdrom_generic_command cgc;
sr_cmd[0] = GPCMD_START_STOP_UNIT; memset(&cgc, 0, sizeof(struct cdrom_generic_command));
sr_cmd[1] = (cd->device->scsi_level <= SCSI_2) ? cgc.cmd[0] = GPCMD_START_STOP_UNIT;
cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
((cd->device->lun) << 5) : 0; ((cd->device->lun) << 5) : 0;
sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; cgc.cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ;
sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ; cgc.data_direction = SCSI_DATA_NONE;
cgc.timeout = IOCTL_TIMEOUT;
return sr_do_ioctl(cd, sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL); return sr_do_ioctl(cd, &cgc);
} }
int sr_lock_door(struct cdrom_device_info *cdi, int lock) int sr_lock_door(struct cdrom_device_info *cdi, int lock)
{ {
Scsi_CD *cd = cdi->handle; Scsi_CD *cd = cdi->handle;
return scsi_ioctl(cd->device, lock ? SCSI_IOCTL_DOORLOCK : return scsi_set_medium_removal(cd->device, lock ?
SCSI_IOCTL_DOORUNLOCK, 0); SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW);
} }
int sr_drive_status(struct cdrom_device_info *cdi, int slot) int sr_drive_status(struct cdrom_device_info *cdi, int slot)
...@@ -278,22 +287,22 @@ int sr_get_last_session(struct cdrom_device_info *cdi, ...@@ -278,22 +287,22 @@ int sr_get_last_session(struct cdrom_device_info *cdi,
int sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) int sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
{ {
Scsi_CD *cd = cdi->handle; Scsi_CD *cd = cdi->handle;
u_char sr_cmd[10]; struct cdrom_generic_command cgc;
char buffer[32]; char buffer[32];
int result; int result;
sr_cmd[0] = GPCMD_READ_SUBCHANNEL; memset(&cgc, 0, sizeof(struct cdrom_generic_command));
sr_cmd[1] = (cd->device->scsi_level <= SCSI_2) ? cgc.cmd[0] = GPCMD_READ_SUBCHANNEL;
cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
((cd->device->lun) << 5) : 0; ((cd->device->lun) << 5) : 0;
sr_cmd[2] = 0x40; /* I do want the subchannel info */ cgc.cmd[2] = 0x40; /* I do want the subchannel info */
sr_cmd[3] = 0x02; /* Give me medium catalog number info */ cgc.cmd[3] = 0x02; /* Give me medium catalog number info */
sr_cmd[4] = sr_cmd[5] = 0; cgc.cmd[8] = 24;
sr_cmd[6] = 0; cgc.buffer = buffer;
sr_cmd[7] = 0; cgc.buflen = 24;
sr_cmd[8] = 24; cgc.data_direction = SCSI_DATA_READ;
sr_cmd[9] = 0; cgc.timeout = IOCTL_TIMEOUT;
result = sr_do_ioctl(cd, &cgc);
result = sr_do_ioctl(cd, sr_cmd, buffer, 24, 0, SCSI_DATA_READ, NULL);
memcpy(mcn->medium_catalog_number, buffer + 9, 13); memcpy(mcn->medium_catalog_number, buffer + 9, 13);
mcn->medium_catalog_number[13] = 0; mcn->medium_catalog_number[13] = 0;
...@@ -309,21 +318,23 @@ int sr_reset(struct cdrom_device_info *cdi) ...@@ -309,21 +318,23 @@ int sr_reset(struct cdrom_device_info *cdi)
int sr_select_speed(struct cdrom_device_info *cdi, int speed) int sr_select_speed(struct cdrom_device_info *cdi, int speed)
{ {
Scsi_CD *cd = cdi->handle; Scsi_CD *cd = cdi->handle;
u_char sr_cmd[MAX_COMMAND_SIZE]; struct cdrom_generic_command cgc;
if (speed == 0) if (speed == 0)
speed = 0xffff; /* set to max */ speed = 0xffff; /* set to max */
else else
speed *= 177; /* Nx to kbyte/s */ speed *= 177; /* Nx to kbyte/s */
memset(sr_cmd, 0, MAX_COMMAND_SIZE); memset(&cgc, 0, sizeof(struct cdrom_generic_command));
sr_cmd[0] = GPCMD_SET_SPEED; /* SET CD SPEED */ cgc.cmd[0] = GPCMD_SET_SPEED; /* SET CD SPEED */
sr_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;
sr_cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */ cgc.cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */
sr_cmd[3] = speed & 0xff; /* LSB */ cgc.cmd[3] = speed & 0xff; /* LSB */
cgc.data_direction = SCSI_DATA_NONE;
cgc.timeout = IOCTL_TIMEOUT;
if (sr_do_ioctl(cd, sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL)) if (sr_do_ioctl(cd, &cgc))
return -EIO; return -EIO;
return 0; return 0;
} }
...@@ -337,24 +348,28 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed) ...@@ -337,24 +348,28 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed)
int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg) int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
{ {
Scsi_CD *cd = cdi->handle; Scsi_CD *cd = cdi->handle;
u_char sr_cmd[10]; struct cdrom_generic_command cgc;
int result; int result;
unsigned char buffer[32]; unsigned char buffer[32];
memset(sr_cmd, 0, sizeof(sr_cmd)); memset(&cgc, 0, sizeof(struct cdrom_generic_command));
cgc.timeout = IOCTL_TIMEOUT;
switch (cmd) { switch (cmd) {
case CDROMREADTOCHDR: case CDROMREADTOCHDR:
{ {
struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg; struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg;
sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP; cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
sr_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;
sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; cgc.cmd[8] = 12; /* LSB of length */
sr_cmd[8] = 12; /* LSB of length */ cgc.buffer = buffer;
cgc.buflen = 12;
cgc.quiet = 1;
cgc.data_direction = SCSI_DATA_READ;
result = sr_do_ioctl(cd, sr_cmd, buffer, 12, 1, SCSI_DATA_READ, NULL); result = sr_do_ioctl(cd, &cgc);
tochdr->cdth_trk0 = buffer[2]; tochdr->cdth_trk0 = buffer[2];
tochdr->cdth_trk1 = buffer[3]; tochdr->cdth_trk1 = buffer[3];
...@@ -366,15 +381,17 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg) ...@@ -366,15 +381,17 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
{ {
struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg; struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg;
sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP; cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
sr_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;
sr_cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0; cgc.cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0;
sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; cgc.cmd[6] = tocentry->cdte_track;
sr_cmd[6] = tocentry->cdte_track; cgc.cmd[8] = 12; /* LSB of length */
sr_cmd[8] = 12; /* LSB of length */ cgc.buffer = buffer;
cgc.buflen = 12;
cgc.data_direction = SCSI_DATA_READ;
result = sr_do_ioctl(cd, sr_cmd, buffer, 12, 0, SCSI_DATA_READ, NULL); result = sr_do_ioctl(cd, &cgc);
tocentry->cdte_ctrl = buffer[5] & 0xf; tocentry->cdte_ctrl = buffer[5] & 0xf;
tocentry->cdte_adr = buffer[5] >> 4; tocentry->cdte_adr = buffer[5] >> 4;
...@@ -393,15 +410,16 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg) ...@@ -393,15 +410,16 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
case CDROMPLAYTRKIND: { case CDROMPLAYTRKIND: {
struct cdrom_ti* ti = (struct cdrom_ti*)arg; struct cdrom_ti* ti = (struct cdrom_ti*)arg;
sr_cmd[0] = GPCMD_PLAYAUDIO_TI; cgc.cmd[0] = GPCMD_PLAYAUDIO_TI;
sr_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;
sr_cmd[4] = ti->cdti_trk0; cgc.cmd[4] = ti->cdti_trk0;
sr_cmd[5] = ti->cdti_ind0; cgc.cmd[5] = ti->cdti_ind0;
sr_cmd[7] = ti->cdti_trk1; cgc.cmd[7] = ti->cdti_trk1;
sr_cmd[8] = ti->cdti_ind1; cgc.cmd[8] = ti->cdti_ind1;
cgc.data_direction = SCSI_DATA_NONE;
result = sr_do_ioctl(cd, sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL); result = sr_do_ioctl(cd, &cgc);
if (result == -EDRIVE_CANT_DO_THIS) if (result == -EDRIVE_CANT_DO_THIS)
result = sr_fake_playtrkind(cdi, ti); result = sr_fake_playtrkind(cdi, ti);
...@@ -436,38 +454,42 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg) ...@@ -436,38 +454,42 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
static int sr_read_cd(Scsi_CD *cd, unsigned char *dest, int lba, int format, int blksize) static int sr_read_cd(Scsi_CD *cd, unsigned char *dest, int lba, int format, int blksize)
{ {
unsigned char cmd[MAX_COMMAND_SIZE]; struct cdrom_generic_command cgc;
#ifdef DEBUG #ifdef DEBUG
printk("%s: sr_read_cd lba=%d format=%d blksize=%d\n", printk("%s: sr_read_cd lba=%d format=%d blksize=%d\n",
cd->cdi.name, lba, format, blksize); cd->cdi.name, lba, format, blksize);
#endif #endif
memset(cmd, 0, MAX_COMMAND_SIZE); memset(&cgc, 0, sizeof(struct cdrom_generic_command));
cmd[0] = GPCMD_READ_CD; /* READ_CD */ cgc.cmd[0] = GPCMD_READ_CD; /* READ_CD */
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] |= ((format & 7) << 2); cgc.cmd[1] |= ((format & 7) << 2);
cmd[2] = (unsigned char) (lba >> 24) & 0xff; cgc.cmd[2] = (unsigned char) (lba >> 24) & 0xff;
cmd[3] = (unsigned char) (lba >> 16) & 0xff; cgc.cmd[3] = (unsigned char) (lba >> 16) & 0xff;
cmd[4] = (unsigned char) (lba >> 8) & 0xff; cgc.cmd[4] = (unsigned char) (lba >> 8) & 0xff;
cmd[5] = (unsigned char) lba & 0xff; cgc.cmd[5] = (unsigned char) lba & 0xff;
cmd[8] = 1; cgc.cmd[8] = 1;
switch (blksize) { switch (blksize) {
case 2336: case 2336:
cmd[9] = 0x58; cgc.cmd[9] = 0x58;
break; break;
case 2340: case 2340:
cmd[9] = 0x78; cgc.cmd[9] = 0x78;
break; break;
case 2352: case 2352:
cmd[9] = 0xf8; cgc.cmd[9] = 0xf8;
break; break;
default: default:
cmd[9] = 0x10; cgc.cmd[9] = 0x10;
break; break;
} }
return sr_do_ioctl(cd, cmd, dest, blksize, 0, SCSI_DATA_READ, NULL); cgc.buffer = dest;
cgc.buflen = blksize;
cgc.data_direction = SCSI_DATA_READ;
cgc.timeout = IOCTL_TIMEOUT;
return sr_do_ioctl(cd, &cgc);
} }
/* /*
...@@ -476,7 +498,7 @@ static int sr_read_cd(Scsi_CD *cd, unsigned char *dest, int lba, int format, int ...@@ -476,7 +498,7 @@ static int sr_read_cd(Scsi_CD *cd, unsigned char *dest, int lba, int format, int
static int sr_read_sector(Scsi_CD *cd, int lba, int blksize, unsigned char *dest) static int sr_read_sector(Scsi_CD *cd, int lba, int blksize, unsigned char *dest)
{ {
unsigned char cmd[MAX_COMMAND_SIZE]; /* the scsi-command */ struct cdrom_generic_command cgc;
int rc; int rc;
/* we try the READ CD command first... */ /* we try the READ CD command first... */
...@@ -497,16 +519,20 @@ static int sr_read_sector(Scsi_CD *cd, int lba, int blksize, unsigned char *dest ...@@ -497,16 +519,20 @@ static int sr_read_sector(Scsi_CD *cd, int lba, int blksize, unsigned char *dest
printk("%s: sr_read_sector lba=%d blksize=%d\n", cd->cdi.name, lba, blksize); printk("%s: sr_read_sector lba=%d blksize=%d\n", cd->cdi.name, lba, blksize);
#endif #endif
memset(cmd, 0, MAX_COMMAND_SIZE); memset(&cgc, 0, sizeof(struct cdrom_generic_command));
cmd[0] = GPCMD_READ_10; cgc.cmd[0] = GPCMD_READ_10;
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[2] = (unsigned char) (lba >> 24) & 0xff; cgc.cmd[2] = (unsigned char) (lba >> 24) & 0xff;
cmd[3] = (unsigned char) (lba >> 16) & 0xff; cgc.cmd[3] = (unsigned char) (lba >> 16) & 0xff;
cmd[4] = (unsigned char) (lba >> 8) & 0xff; cgc.cmd[4] = (unsigned char) (lba >> 8) & 0xff;
cmd[5] = (unsigned char) lba & 0xff; cgc.cmd[5] = (unsigned char) lba & 0xff;
cmd[8] = 1; cgc.cmd[8] = 1;
rc = sr_do_ioctl(cd, cmd, dest, blksize, 0, SCSI_DATA_READ, NULL); cgc.buffer = dest;
cgc.buflen = blksize;
cgc.data_direction = SCSI_DATA_READ;
cgc.timeout = IOCTL_TIMEOUT;
rc = sr_do_ioctl(cd, &cgc);
return rc; return rc;
} }
...@@ -562,7 +588,6 @@ int sr_dev_ioctl(struct cdrom_device_info *cdi, ...@@ -562,7 +588,6 @@ int sr_dev_ioctl(struct cdrom_device_info *cdi,
* c-label-offset: -4 * c-label-offset: -4
* c-continued-statement-offset: 4 * c-continued-statement-offset: 4
* c-continued-brace-offset: 0 * c-continued-brace-offset: 0
* indent-tabs-mode: nil
* tab-width: 8 * tab-width: 8
* End: * End:
*/ */
...@@ -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;
cmd[8] = 12; cgc.cmd[8] = 12;
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;
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;
cmd[1] |= 0x03; cgc.cmd[1] |= 0x03;
cmd[2] = 0xb0; cgc.cmd[2] = 0xb0;
rc = sr_do_ioctl(cd, cmd, buffer, 0x16, 1, SCSI_DATA_READ, NULL); 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) 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;
cmd[1] |= 0x03; cgc.cmd[1] |= 0x03;
rc = sr_do_ioctl(cd, cmd, buffer, 4, 1, SCSI_DATA_READ, NULL); 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) { 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;
cmd[8] = 0x04; cgc.cmd[8] = 0x04;
cmd[9] = 0x40; cgc.cmd[9] = 0x40;
rc = sr_do_ioctl(cd, cmd, buffer, 0x04, 1, SCSI_DATA_READ, NULL); 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) { 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