Index: linux/2.4/drivers/scsi/scsi.c diff -c linux/2.4/drivers/scsi/scsi.c:1.1.1.5 linux/2.4/drivers/scsi/scsi.c:1.1.1.5.2.3 *** linux/2.4/drivers/scsi/scsi.c:1.1.1.5 Thu Feb 22 16:36:55 2001 --- linux/2.4/drivers/scsi/scsi.c Fri Mar 9 14:45:43 2001 *************** *** 146,152 **** --- 146,157 ---- */ extern void scsi_old_done(Scsi_Cmnd * SCpnt); extern void scsi_old_times_out(Scsi_Cmnd * SCpnt); + extern int scsi_old_reset(Scsi_Cmnd *SCpnt, unsigned int flag); + /* + * private interface into the new error handling code + */ + extern int scsi_new_reset(Scsi_Cmnd *SCpnt, unsigned int flag); /* * Function: scsi_initialize_queue() *************** *** 2657,2662 **** --- 2662,2758 ---- */ scsi_release_commandblocks(SDpnt); kfree(SDpnt); + } + + /* Dummy done routine. 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) { + /* Empty function. Some low level drivers will call scsi_done + * (and end up here), others won't bother */ + } + + + /* + * 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; + Scsi_Cmnd SC; + Scsi_Cmnd *SCpnt = ≻ + + 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; + + + if(dev->host->hostt->use_new_eh_code) { + rtn = scsi_new_reset(SCpnt, flag); + } else { + unsigned long flags; + spin_lock_irqsave(&io_request_lock, flags); + rtn = scsi_old_reset(SCpnt, flag); + spin_unlock_irqrestore(&io_request_lock, flags); + } + + scsi_delete_timer(SCpnt); + + return rtn; } /* Index: linux/2.4/drivers/scsi/scsi.h diff -c linux/2.4/drivers/scsi/scsi.h:1.1.1.3 linux/2.4/drivers/scsi/scsi.h:1.1.1.3.6.1 *** linux/2.4/drivers/scsi/scsi.h:1.1.1.3 Thu Jan 11 11:39:27 2001 --- linux/2.4/drivers/scsi/scsi.h Wed Feb 28 17:37:27 2001 *************** *** 842,847 **** --- 842,855 ---- 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_reset_provider(Scsi_Device *, int); #endif Index: linux/2.4/drivers/scsi/scsi_error.c diff -c linux/2.4/drivers/scsi/scsi_error.c:1.1.1.3 linux/2.4/drivers/scsi/scsi_error.c:1.1.1.3.2.2 *** linux/2.4/drivers/scsi/scsi_error.c:1.1.1.3 Thu Feb 22 16:36:51 2001 --- linux/2.4/drivers/scsi/scsi_error.c Fri Mar 16 10:22:36 2001 *************** *** 996,1004 **** case DID_SOFT_ERROR: goto maybe_retry; case DID_BUS_BUSY: case DID_PARITY: - case DID_ERROR: goto maybe_retry; case DID_TIME_OUT: /* --- 996,1012 ---- 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; + /* fall through */ + + case DID_BUS_BUSY: case DID_PARITY: goto maybe_retry; case DID_TIME_OUT: /* *************** *** 1065,1072 **** */ return SUCCESS; case BUSY: - case RESERVATION_CONFLICT: goto maybe_retry; default: return FAILED; } --- 1073,1085 ---- */ return SUCCESS; case BUSY: 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; } *************** *** 1959,1964 **** --- 1972,2015 ---- */ 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; + /* 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; + } + return rtn; } /* Index: linux/2.4/drivers/scsi/scsi_obsolete.c diff -c linux/2.4/drivers/scsi/scsi_obsolete.c:1.1.1.3 linux/2.4/drivers/scsi/scsi_obsolete.c:1.1.1.3.2.1 *** linux/2.4/drivers/scsi/scsi_obsolete.c:1.1.1.3 Thu Feb 22 16:37:01 2001 --- linux/2.4/drivers/scsi/scsi_obsolete.c Wed Feb 28 17:37:27 2001 *************** *** 502,512 **** 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; default: printk("Internal error %s %d \n" "status byte = %d \n", __FILE__, --- 502,518 ---- break; case RESERVATION_CONFLICT: ! /* 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__, *************** *** 556,561 **** --- 562,575 ---- 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; *************** *** 1097,1102 **** --- 1111,1141 ---- 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 rtn; + unsigned int old_flags = SCSI_RESET_SYNCHRONOUS; + + switch(flag) { + case SCSI_TRY_RESET_DEVICE: + /* no suggestion flags to add, device reset is default */ + break; + 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; + default: + return FAILED; + } + return (scsi_reset(SCpnt, old_flags) == 0) ? SUCCESS : FAILED; + } /* * Overrides for Emacs so that we follow Linus's tabbing style. Index: linux/2.4/drivers/scsi/scsi_syms.c diff -c linux/2.4/drivers/scsi/scsi_syms.c:1.1.1.3 linux/2.4/drivers/scsi/scsi_syms.c:1.1.1.3.2.1 *** linux/2.4/drivers/scsi/scsi_syms.c:1.1.1.3 Thu Feb 22 16:37:31 2001 --- linux/2.4/drivers/scsi/scsi_syms.c Wed Feb 28 17:37:27 2001 *************** *** 84,89 **** --- 84,93 ---- EXPORT_SYMBOL(scsi_deregister_blocked_host); /* + * This symbol is for the sg device only + */ + EXPORT_SYMBOL(scsi_reset_provider); + /* * These are here only while I debug the rest of the scsi stuff. */ EXPORT_SYMBOL(scsi_hostlist);