📄 scsi_obsolete.c
字号:
/* * scsi_obsolete.c Copyright (C) 1992 Drew Eckhardt * Copyright (C) 1993, 1994, 1995 Eric Youngdale * * generic mid-level SCSI driver * Initial versions: Drew Eckhardt * Subsequent revisions: Eric Youngdale * * <drew@colorado.edu> * * Bug correction thanks go to : * Rik Faith <faith@cs.unc.edu> * Tommy Thorn <tthorn> * Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de> * * Modified by Eric Youngdale eric@andante.org to * add scatter-gather, multiple outstanding request, and other * enhancements. * * Native multichannel, wide scsi, /proc/scsi and hot plugging * support added by Michael Neuffer <mike@i-connect.net> * * Major improvements to the timeout, abort, and reset processing, * as well as performance modifications for large queue depths by * Leonard N. Zubkoff <lnz@dandelion.com> * * Improved compatibility with 2.0 behaviour by Manfred Spraul * <masp0008@stud.uni-sb.de> *//* *######################################################################### *######################################################################### *######################################################################### *######################################################################### * NOTE - NOTE - NOTE - NOTE - NOTE - NOTE - NOTE * *######################################################################### *######################################################################### *######################################################################### *######################################################################### * * This file contains the 'old' scsi error handling. It is only present * while the new error handling code is being debugged, and while the low * level drivers are being converted to use the new code. Once the last * driver uses the new code this *ENTIRE* file will be nuked. */#define __NO_VERSION__#include <linux/module.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/string.h>#include <linux/malloc.h>#include <linux/ioport.h>#include <linux/kernel.h>#include <linux/stat.h>#include <linux/blk.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <asm/system.h>#include <asm/irq.h>#include <asm/dma.h>#include "scsi.h"#include "hosts.h"#include "constants.h"#undef USE_STATIC_SCSI_MEMORY/* static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_obsolete.c,v 1.1 1997/05/18 23:27:21 eric Exp $"; */#define INTERNAL_ERROR (panic ("Internal error in file %s, line %d.\n", __FILE__, __LINE__))static int scsi_abort(Scsi_Cmnd *, int code);static int scsi_reset(Scsi_Cmnd *, unsigned int);extern void scsi_old_done(Scsi_Cmnd * SCpnt);int update_timeout(Scsi_Cmnd *, int);extern void scsi_old_times_out(Scsi_Cmnd * SCpnt);extern int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt);#define SCSI_BLOCK(HOST) (HOST->can_queue && HOST->host_busy >= HOST->can_queue)static unsigned char generic_sense[6] ={REQUEST_SENSE, 0, 0, 0, 255, 0};/* * This is the number of clock ticks we should wait before we time out * and abort the command. This is for where the scsi.c module generates * the command, not where it originates from a higher level, in which * case the timeout is specified there. * * ABORT_TIMEOUT and RESET_TIMEOUT are the timeouts for RESET and ABORT * respectively. */#ifdef DEBUG_TIMEOUTstatic void scsi_dump_status(void);#endif#ifdef DEBUG#define SCSI_TIMEOUT (5*HZ)#else#define SCSI_TIMEOUT (2*HZ)#endif#ifdef DEBUG#define SENSE_TIMEOUT SCSI_TIMEOUT#define ABORT_TIMEOUT SCSI_TIMEOUT#define RESET_TIMEOUT SCSI_TIMEOUT#else#define SENSE_TIMEOUT (5*HZ/10)#define RESET_TIMEOUT (5*HZ/10)#define ABORT_TIMEOUT (5*HZ/10)#endif/* Do not call reset on error if we just did a reset within 15 sec. */#define MIN_RESET_PERIOD (15*HZ)/* * Flag bits for the internal_timeout array */#define IN_ABORT 1#define IN_RESET 2#define IN_RESET2 4#define IN_RESET3 8/* * This is our time out function, called when the timer expires for a * given host adapter. It will attempt to abort the currently executing * command, that failing perform a kernel panic. */void scsi_old_times_out(Scsi_Cmnd * SCpnt){ unsigned long flags; spin_lock_irqsave(&io_request_lock, flags); /* Set the serial_number_at_timeout to the current serial_number */ SCpnt->serial_number_at_timeout = SCpnt->serial_number; switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3)) { case NORMAL_TIMEOUT: {#ifdef DEBUG_TIMEOUT scsi_dump_status();#endif } if (!scsi_abort(SCpnt, DID_TIME_OUT)) break; case IN_ABORT: printk("SCSI host %d abort (pid %ld) timed out - resetting\n", SCpnt->host->host_no, SCpnt->pid); if (!scsi_reset(SCpnt, SCSI_RESET_ASYNCHRONOUS)) break; case IN_RESET: case (IN_ABORT | IN_RESET): /* This might be controversial, but if there is a bus hang, * you might conceivably want the machine up and running * esp if you have an ide disk. */ printk("SCSI host %d channel %d reset (pid %ld) timed out - " "trying harder\n", SCpnt->host->host_no, SCpnt->channel, SCpnt->pid); SCpnt->internal_timeout &= ~IN_RESET; SCpnt->internal_timeout |= IN_RESET2; scsi_reset(SCpnt, SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET); break; case IN_RESET2: case (IN_ABORT | IN_RESET2): /* Obviously the bus reset didn't work. * Let's try even harder and call for an HBA reset. * Maybe the HBA itself crashed and this will shake it loose. */ printk("SCSI host %d reset (pid %ld) timed out - trying to shake it loose\n", SCpnt->host->host_no, SCpnt->pid); SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2); SCpnt->internal_timeout |= IN_RESET3; scsi_reset(SCpnt, SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET); break; default: printk("SCSI host %d reset (pid %ld) timed out again -\n", SCpnt->host->host_no, SCpnt->pid); printk("probably an unrecoverable SCSI bus or device hang.\n"); break; } spin_unlock_irqrestore(&io_request_lock, flags);}/* * From what I can find in scsi_obsolete.c, this function is only called * by scsi_old_done and scsi_reset. Both of these functions run with the * io_request_lock already held, so we need do nothing here about grabbing * any locks. */static void scsi_request_sense(Scsi_Cmnd * SCpnt){ SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE; update_timeout(SCpnt, SENSE_TIMEOUT); memcpy((void *) SCpnt->cmnd, (void *) generic_sense, sizeof(generic_sense)); memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); SCpnt->cmnd[1] = SCpnt->lun << 5; SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer); SCpnt->request_buffer = &SCpnt->sense_buffer; SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer); SCpnt->use_sg = 0; SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); SCpnt->result = 0; SCpnt->sc_data_direction = SCSI_DATA_READ; /* * Ugly, ugly. The newer interfaces all assume that the lock * isn't held. Mustn't disappoint, or we deadlock the system. */ spin_unlock_irq(&io_request_lock); scsi_dispatch_cmd(SCpnt); spin_lock_irq(&io_request_lock);}static int check_sense(Scsi_Cmnd * SCpnt){ /* If there is no sense information, request it. If we have already * requested it, there is no point in asking again - the firmware must * be confused. */ if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) { if (!(SCpnt->flags & ASKED_FOR_SENSE)) return SUGGEST_SENSE; else return SUGGEST_RETRY; } SCpnt->flags &= ~ASKED_FOR_SENSE;#ifdef DEBUG_INIT printk("scsi%d, channel%d : ", SCpnt->host->host_no, SCpnt->channel); print_sense("", SCpnt); printk("\n");#endif if (SCpnt->sense_buffer[2] & 0xe0) return SUGGEST_ABORT; switch (SCpnt->sense_buffer[2] & 0xf) { case NO_SENSE: return 0; case RECOVERED_ERROR: return SUGGEST_IS_OK; case ABORTED_COMMAND: return SUGGEST_RETRY; case NOT_READY: case UNIT_ATTENTION: /* * If we are expecting a CC/UA because of a bus reset that we * performed, treat this just as a retry. Otherwise this is * information that we should pass up to the upper-level driver * so that we can deal with it there. */ if (SCpnt->device->expecting_cc_ua) { SCpnt->device->expecting_cc_ua = 0; return SUGGEST_RETRY; } return SUGGEST_ABORT; /* these three are not supported */ case COPY_ABORTED: case VOLUME_OVERFLOW: case MISCOMPARE: case MEDIUM_ERROR: return SUGGEST_REMAP; case BLANK_CHECK: case DATA_PROTECT: case HARDWARE_ERROR: case ILLEGAL_REQUEST: default: return SUGGEST_ABORT; }}/* This function is the mid-level interrupt routine, which decides how * to handle error conditions. Each invocation of this function must * do one and *only* one of the following: * * (1) Call last_cmnd[host].done. This is done for fatal errors and * normal completion, and indicates that the handling for this * request is complete. * (2) Call internal_cmnd to requeue the command. This will result in * scsi_done being called again when the retry is complete. * (3) Call scsi_request_sense. This asks the host adapter/drive for * more information about the error condition. When the information * is available, scsi_done will be called again. * (4) Call reset(). This is sort of a last resort, and the idea is that * this may kick things loose and get the drive working again. reset() * automatically calls scsi_request_sense, and thus scsi_done will be * called again once the reset is complete. * * If none of the above actions are taken, the drive in question * will hang. If more than one of the above actions are taken by * scsi_done, then unpredictable behavior will result. */void scsi_old_done(Scsi_Cmnd * SCpnt){ int status = 0; int exit = 0; int checked; int oldto; struct Scsi_Host *host = SCpnt->host; Scsi_Device * device = SCpnt->device; int result = SCpnt->result; SCpnt->serial_number = 0; SCpnt->serial_number_at_timeout = 0; oldto = update_timeout(SCpnt, 0);#ifdef DEBUG_TIMEOUT if (result) printk("Non-zero result in scsi_done %x %d:%d\n", result, SCpnt->target, SCpnt->lun);#endif /* If we requested an abort, (and we got it) then fix up the return * status to say why */ if (host_byte(result) == DID_ABORT && SCpnt->abort_reason) SCpnt->result = result = (result & 0xff00ffff) | (SCpnt->abort_reason << 16);#define CMD_FINISHED 0#define MAYREDO 1#define REDO 3#define PENDING 4#ifdef DEBUG printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result);#endif if (SCpnt->flags & SYNC_RESET) { /* * The behaviou of scsi_reset(SYNC) was changed in 2.1.? . * The scsi mid-layer does a REDO after every sync reset, the driver * must not do that any more. In order to prevent old drivers from * crashing, all scsi_done() calls during sync resets are ignored. */ printk("scsi%d: device driver called scsi_done() " "for a synchronous reset.\n", SCpnt->host->host_no);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -