⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsi_obsolete.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  scsi.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@aib.com 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 void internal_cmnd (Scsi_Cmnd * SCpnt);extern volatile struct Scsi_Host * host_active;#define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \			  || (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 NORMAL_TIMEOUT 0#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;    internal_cmnd (SCpnt);}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;    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 syncronous reset.\n", SCpnt->host->host_no);        return;    }    if(SCpnt->flags & WAS_SENSE)    {	SCpnt->use_sg = SCpnt->old_use_sg;	SCpnt->cmd_len = SCpnt->old_cmd_len;    }    switch (host_byte(result))    {    case DID_OK:	if (status_byte(result) && (SCpnt->flags & WAS_SENSE))

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -