Commit ad13d5f4 authored by James Bottomley's avatar James Bottomley

Merge mulgrave.(none):/home/jejb/BK/linux-2.5

into mulgrave.(none):/home/jejb/BK/scsi-2.5
parents c39e9205 c60eeb1f
......@@ -164,6 +164,11 @@ const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
extern void scsi_times_out(Scsi_Cmnd * SCpnt);
void scsi_build_commandblocks(Scsi_Device * SDpnt);
/*
* Private interface into the new error handling code.
*/
extern int scsi_new_reset(Scsi_Cmnd *SCpnt, unsigned int flag);
/*
* Function: scsi_initialize_queue()
*
......@@ -2662,6 +2667,94 @@ void scsi_free_host_dev(Scsi_Device * SDpnt)
kfree(SDpnt);
}
/*
* Function: scsi_reset_provider_done_command
*
* Purpose: Dummy done routine.
*
* Notes: Some low level drivers will call scsi_done and end up here,
* others won't bother.
* We don't want the bogus command used for the bus/device
* reset to find its way into the mid-layer so we intercept
* it here.
*/
static void
scsi_reset_provider_done_command(Scsi_Cmnd *SCpnt)
{
}
/*
* Function: scsi_reset_provider
*
* Purpose: Send requested reset to a bus or device at any phase.
*
* Arguments: device - device to send reset to
* flag - reset type (see scsi.h)
*
* Returns: SUCCESS/FAILURE.
*
* Notes: This is used by the SCSI Generic driver to provide
* Bus/Device reset capability.
*/
int
scsi_reset_provider(Scsi_Device *dev, int flag)
{
Scsi_Cmnd SC, *SCpnt = ≻
int rtn;
memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout));
SCpnt->host = dev->host;
SCpnt->device = dev;
SCpnt->target = dev->id;
SCpnt->lun = dev->lun;
SCpnt->channel = dev->channel;
SCpnt->request.rq_status = RQ_SCSI_BUSY;
SCpnt->request.waiting = NULL;
SCpnt->use_sg = 0;
SCpnt->old_use_sg = 0;
SCpnt->old_cmd_len = 0;
SCpnt->underflow = 0;
SCpnt->transfersize = 0;
SCpnt->resid = 0;
SCpnt->serial_number = 0;
SCpnt->serial_number_at_timeout = 0;
SCpnt->host_scribble = NULL;
SCpnt->next = NULL;
SCpnt->state = SCSI_STATE_INITIALIZING;
SCpnt->owner = SCSI_OWNER_MIDLEVEL;
memset(&SCpnt->cmnd, '\0', sizeof(SCpnt->cmnd));
SCpnt->scsi_done = scsi_reset_provider_done_command;
SCpnt->done = NULL;
SCpnt->reset_chain = NULL;
SCpnt->buffer = NULL;
SCpnt->bufflen = 0;
SCpnt->request_buffer = NULL;
SCpnt->request_bufflen = 0;
SCpnt->internal_timeout = NORMAL_TIMEOUT;
SCpnt->abort_reason = DID_ABORT;
SCpnt->cmd_len = 0;
SCpnt->sc_data_direction = SCSI_DATA_UNKNOWN;
SCpnt->sc_request = NULL;
SCpnt->sc_magic = SCSI_CMND_MAGIC;
/*
* Sometimes the command can get back into the timer chain,
* so use the pid as an identifier.
*/
SCpnt->pid = 0;
rtn = scsi_new_reset(SCpnt, flag);
scsi_delete_timer(SCpnt);
return rtn;
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
......
......@@ -834,6 +834,16 @@ struct scsi_cmnd {
current->state = TASK_RUNNING; \
}; }
/*
* old style reset request from external source
* (private to sg.c and scsi_error.c, supplied by scsi_obsolete.c)
*/
#define SCSI_TRY_RESET_DEVICE 1
#define SCSI_TRY_RESET_BUS 2
#define SCSI_TRY_RESET_HOST 3
extern int scsi_reset_provider(Scsi_Device *, int);
#endif
/*
......
......@@ -979,15 +979,24 @@ int scsi_decide_disposition(Scsi_Cmnd * SCpnt)
case DID_SOFT_ERROR:
goto maybe_retry;
case DID_ERROR:
if (msg_byte(SCpnt->result) == COMMAND_COMPLETE &&
status_byte(SCpnt->result) == RESERVATION_CONFLICT)
/*
* execute reservation conflict processing code
* lower down
*/
break;
/* FALLTHROUGH */
case DID_BUS_BUSY:
case DID_PARITY:
case DID_ERROR:
goto maybe_retry;
case DID_TIME_OUT:
/*
* When we scan the bus, we get timeout messages for
* these commands if there is no device available.
* Other hosts report DID_NO_CONNECT for the same thing.
* When we scan the bus, we get timeout messages for
* these commands if there is no device available.
* Other hosts report DID_NO_CONNECT for the same thing.
*/
if ((SCpnt->cmnd[0] == TEST_UNIT_READY ||
SCpnt->cmnd[0] == INQUIRY)) {
......@@ -1048,8 +1057,13 @@ int scsi_decide_disposition(Scsi_Cmnd * SCpnt)
*/
return SUCCESS;
case BUSY:
case RESERVATION_CONFLICT:
goto maybe_retry;
case RESERVATION_CONFLICT:
printk("scsi%d (%d,%d,%d) : RESERVATION CONFLICT\n",
SCpnt->host->host_no, SCpnt->channel,
SCpnt->device->id, SCpnt->device->lun);
return SUCCESS; /* causes immediate I/O error */
default:
return FAILED;
}
......@@ -1949,6 +1963,45 @@ void scsi_error_handler(void *data)
up(host->eh_notify);
}
/*
* Function: scsi_new_reset
*
* Purpose: Send requested reset to a bus or device at any phase.
*
* Arguments: SCpnt - command ptr to send reset with (usually a dummy)
* flag - reset type (see scsi.h)
*
* Returns: SUCCESS/FAILURE.
*
* Notes: This is used by the SCSI Generic driver to provide
* Bus/Device reset capability.
*/
int
scsi_new_reset(Scsi_Cmnd *SCpnt, int flag)
{
int rtn;
switch(flag) {
case SCSI_TRY_RESET_DEVICE:
rtn = scsi_try_bus_device_reset(SCpnt, 0);
if (rtn == SUCCESS)
break;
/* FALLTHROUGH */
case SCSI_TRY_RESET_BUS:
rtn = scsi_try_bus_reset(SCpnt);
if (rtn == SUCCESS)
break;
/* FALLTHROUGH */
case SCSI_TRY_RESET_HOST:
rtn = scsi_try_host_reset(SCpnt);
break;
default:
rtn = FAILED;
}
return rtn;
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
......
......@@ -80,6 +80,11 @@ EXPORT_SYMBOL(scsi_end_request);
EXPORT_SYMBOL(scsi_register_blocked_host);
EXPORT_SYMBOL(scsi_deregister_blocked_host);
/*
* This symbol is for the highlevel drivers (e.g. sg) only.
*/
EXPORT_SYMBOL(scsi_reset_provider);
/*
* These are here only while I debug the rest of the scsi stuff.
*/
......
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