# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.454 -> 1.455 # drivers/scsi/scsi_error.c 1.8 -> 1.9 # drivers/scsi/scsi.h 1.9 -> 1.10 # drivers/scsi/scsi_syms.c 1.7 -> 1.8 # drivers/scsi/scsi.c 1.24 -> 1.26 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/03/01 jejb@mulgrave.(none) 1.134.1.1 # scsi-reset-2.4.18.diff # # SCSI reservation/reset handling # # - Make both the old and the new error handlers respond correctly # to reservation conflicts (i.e. return an I/O error). # # - Add a scsi_reset_provider() function for use by the sg driver # SCSI reset facility. # -------------------------------------------- # 02/03/02 jejb@mulgrave.(none) 1.369.12.1 # Merge to 2.5.5 # -------------------------------------------- # 02/03/02 jejb@mulgrave.(none) 1.369.12.2 # SCSI reservation/reset handling # # Tidy up and eliminate remaining references to old error handler. # -------------------------------------------- # 02/03/02 jejb@mulgrave.(none) 1.455 # Merge mulgrave.(none):/home/jejb/BK/linux-2.5 # into mulgrave.(none):/home/jejb/BK/scsi-2.5 # -------------------------------------------- # diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c --- a/drivers/scsi/scsi.c Sat Mar 2 12:49:05 2002 +++ b/drivers/scsi/scsi.c Sat Mar 2 12:49:05 2002 @@ -165,6 +165,11 @@ 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() * * Purpose: Selects queue handler function for a device. @@ -2660,6 +2665,94 @@ */ scsi_release_commandblocks(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; } /* diff -Nru a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h --- a/drivers/scsi/scsi.h Sat Mar 2 12:49:05 2002 +++ b/drivers/scsi/scsi.h Sat Mar 2 12:49:05 2002 @@ -834,6 +834,16 @@ 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 /* diff -Nru a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c --- a/drivers/scsi/scsi_error.c Sat Mar 2 12:49:05 2002 +++ b/drivers/scsi/scsi_error.c Sat Mar 2 12:49:05 2002 @@ -979,15 +979,24 @@ 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 @@ */ 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; } @@ -1947,6 +1961,45 @@ */ if (host->eh_notify != NULL) 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; } /* diff -Nru a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c --- a/drivers/scsi/scsi_syms.c Sat Mar 2 12:49:05 2002 +++ b/drivers/scsi/scsi_syms.c Sat Mar 2 12:49:05 2002 @@ -81,6 +81,11 @@ 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. */ EXPORT_SYMBOL(scsi_hostlist);