Index: linux/drivers/scsi/scsi.c diff -u linux/drivers/scsi/scsi.c:1.1.1.7 linux/drivers/scsi/scsi.c:1.1.1.7.2.1 --- linux/drivers/scsi/scsi.c:1.1.1.7 Tue Jun 13 17:24:04 2000 +++ linux/drivers/scsi/scsi.c Tue Jun 13 18:01:08 2000 @@ -716,7 +716,7 @@ SCSI_LOG_SCAN_BUS(3,print_hostbyte(SCpnt->result)); SCSI_LOG_SCAN_BUS(3,printk("\n")); - if (SCpnt->result) { + if (SCpnt->result && status_byte(SCpnt->result) != RESERVATION_CONFLICT) { if (((driver_byte (SCpnt->result) & DRIVER_SENSE) || (status_byte (SCpnt->result) & CHECK_CONDITION)) && ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) { Index: linux/drivers/scsi/scsi.h diff -u linux/drivers/scsi/scsi.h:1.1.1.4 linux/drivers/scsi/scsi.h:1.1.1.4.6.1 --- linux/drivers/scsi/scsi.h:1.1.1.4 Wed Jan 5 12:24:50 2000 +++ linux/drivers/scsi/scsi.h Tue Jun 13 17:59:02 2000 @@ -732,6 +732,14 @@ remove_wait_queue(QUEUE, &wait);\ 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_old_reset(Scsi_Cmnd *, unsigned int); +extern int scsi_reset_provider(Scsi_Device *, int); #endif Index: linux/drivers/scsi/scsi_error.c diff -u linux/drivers/scsi/scsi_error.c:1.1.1.3 linux/drivers/scsi/scsi_error.c:1.1.1.3.12.2 --- linux/drivers/scsi/scsi_error.c:1.1.1.3 Thu Aug 26 08:18:40 1999 +++ linux/drivers/scsi/scsi_error.c Tue Jun 13 18:01:08 2000 @@ -34,6 +34,7 @@ #include "scsi.h" #include "hosts.h" #include "constants.h" +#include #define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM)) @@ -981,9 +982,14 @@ case DID_SOFT_ERROR: return NEEDS_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; + /* fall through */ case DID_BUS_BUSY: case DID_PARITY: - case DID_ERROR: goto maybe_retry; case DID_TIME_OUT: /* @@ -1059,8 +1065,12 @@ */ 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; } @@ -2041,6 +2051,62 @@ */ if( host->eh_notify != NULL ) up(host->eh_notify); +} + +/* + * 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) +{ + int rtn; + /* get a dummy command to issue the reset to */ + Scsi_Cmnd *SCpnt = scsi_allocate_device(NULL, dev, 1); + switch(flag) { + case SCSI_TRY_RESET_DEVICE: + rtn = scsi_try_bus_device_reset(SCpnt, 0); + if(rtn == SUCCESS) + break; + /* fall through */ + case SCSI_TRY_RESET_BUS: + rtn = scsi_try_bus_reset(SCpnt); + if(rtn == SUCCESS) + break; + /* fall through */ + case SCSI_TRY_RESET_HOST: + rtn = scsi_try_host_reset(SCpnt); + break; + default: + rtn = FAILED; + goto error_out; + } + if(rtn == FAILED) { + /* if we get here, the new code all failed, so try the old + * reset code */ + unsigned int old_flags = SCSI_RESET_SYNCHRONOUS; + switch(flag) { + case SCSI_TRY_RESET_BUS: + old_flags |= SCSI_RESET_SUGGEST_BUS_RESET; + break; + case SCSI_TRY_RESET_HOST: + old_flags |= SCSI_RESET_SUGGEST_HOST_RESET; + break; + } + rtn = (scsi_old_reset(SCpnt, old_flags) == 0) ? SUCCESS : FAILED; + } + error_out: + scsi_release_command(SCpnt); + return rtn; } /* Index: linux/drivers/scsi/scsi_obsolete.c diff -u linux/drivers/scsi/scsi_obsolete.c:1.1.1.1 linux/drivers/scsi/scsi_obsolete.c:1.1.1.1.48.2 --- linux/drivers/scsi/scsi_obsolete.c:1.1.1.1 Thu Mar 18 10:33:14 1999 +++ linux/drivers/scsi/scsi_obsolete.c Tue Jun 13 18:01:09 2000 @@ -507,11 +507,14 @@ break; case RESERVATION_CONFLICT: - printk("scsi%d, channel %d : RESERVATION CONFLICT performing" - " reset.\n", SCpnt->host->host_no, SCpnt->channel); - scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS); - status = REDO; - break; + /* Most HAs will return an error for this, so usually + * reservation conflicts will be processed under DID_ERROR + * code */ + printk("scsi%d (%d,%d,%d) : RESERVATION CONFLICT\n", + SCpnt->host->host_no, SCpnt->channel, + SCpnt->device->id, SCpnt->device->lun); + status = CMD_FINISHED; /* returns I/O error */ + break; default: printk ("Internal error %s %d \n" "status byte = %d \n", __FILE__, @@ -564,6 +567,14 @@ exit = (DRIVER_HARD | SUGGEST_ABORT); break; case DID_ERROR: + if(msg_byte(result) == COMMAND_COMPLETE + && status_byte(result) == RESERVATION_CONFLICT) { + printk("scsi%d (%d,%d,%d) : RESERVATION CONFLICT\n", + SCpnt->host->host_no, SCpnt->channel, + SCpnt->device->id, SCpnt->device->lun); + status = CMD_FINISHED; /* returns I/O error */ + break; + } status = MAYREDO; exit = (DRIVER_HARD | SUGGEST_ABORT); break; @@ -1119,6 +1130,16 @@ return rtn; } + +/* This function exports SCSI Bus, Device or Host reset capability + * and is for use with the SCSI generic driver. + */ +int scsi_old_reset(Scsi_Cmnd *SCpnt, unsigned int flag) +{ + int retval = scsi_reset(SCpnt, flag); + return retval; +} + /* Index: linux/drivers/scsi/scsi_syms.c diff -u linux/drivers/scsi/scsi_syms.c:1.1.1.2 linux/drivers/scsi/scsi_syms.c:1.1.1.2.12.1 --- linux/drivers/scsi/scsi_syms.c:1.1.1.2 Thu Aug 26 08:18:33 1999 +++ linux/drivers/scsi/scsi_syms.c Tue Jun 13 17:59:02 2000 @@ -80,5 +80,10 @@ EXPORT_SYMBOL(scsi_devicelist); EXPORT_SYMBOL(scsi_device_types); +/* + * This symbol is for the sg device only + */ +EXPORT_SYMBOL(scsi_reset_provider); + #endif /* CONFIG_MODULES */