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

📄 scsi.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  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> * *  Added request_module("scsi_hostadapter") for kerneld: *  (Put an "alias scsi_hostadapter your_hostadapter" in /etc/conf.modules) *  Bjorn Ekwall  <bj0rn@blox.se> * *  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> *//* * Don't import our own symbols, as this would severely mess up our * symbol tables. */#define _SCSI_SYMS_VER_#include <linux/config.h>#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"#ifdef CONFIG_KERNELD#include <linux/kerneld.h>#endif#undef USE_STATIC_SCSI_MEMORY/*static const char RCSid[] = "$Header: /cvsroot/hurd/gnumach/linux/dev/drivers/scsi/Attic/scsi.c,v 1.1 1999/04/26 05:44:26 tb Exp $";*//* Command groups 3 and 4 are reserved and should never be used.  */const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, 12, 12, 10, 10 };#define INTERNAL_ERROR (panic ("Internal error in file %s, line %d.\n", __FILE__, __LINE__))/* * PAGE_SIZE must be a multiple of the sector size (512).  True * for all reasonably recent architectures (even the VAX...). */#define SECTOR_SIZE		512#define SECTORS_PER_PAGE	(PAGE_SIZE/SECTOR_SIZE)#if SECTORS_PER_PAGE <= 8 typedef unsigned char	FreeSectorBitmap;#elif SECTORS_PER_PAGE <= 32 typedef unsigned int	FreeSectorBitmap;#else# error You lose.#endifstatic void scsi_done (Scsi_Cmnd *SCpnt);static int update_timeout (Scsi_Cmnd *, int);static void print_inquiry(unsigned char *data);static void scsi_times_out (Scsi_Cmnd * SCpnt);static int scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev ,                 int * sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,                 struct Scsi_Host *shpnt, char * scsi_result);void scsi_build_commandblocks(Scsi_Device * SDpnt);#ifdef CONFIG_MODULESextern struct symbol_table scsi_symbol_table;#endifstatic FreeSectorBitmap * dma_malloc_freelist = NULL;static int scsi_need_isa_bounce_buffers;static unsigned int dma_sectors = 0;unsigned int dma_free_sectors = 0;unsigned int need_isa_buffer = 0;static unsigned char ** dma_malloc_pages = NULL;static int time_start;static int time_elapsed;static volatile struct Scsi_Host * host_active = NULL;#define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \			  || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] ={    "Direct-Access    ",    "Sequential-Access",    "Printer          ",    "Processor        ",    "WORM             ",    "CD-ROM           ",    "Scanner          ",    "Optical Device   ",    "Medium Changer   ",    "Communications   "};/* * global variables : * scsi_devices an array of these specifying the address for each * (host, id, LUN) */Scsi_Device * scsi_devices = NULL;/* Process ID of SCSI commands */unsigned long scsi_pid = 0;static unsigned long serial_number = 0;static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};static void resize_dma_pool(void);/* This variable is merely a hook so that we can debug the kernel with gdb. */Scsi_Cmnd * last_cmnd = NULL;/* This is the pointer to the /proc/scsi code.  * It is only initialized to !=0 if the scsi code is present  */ #if CONFIG_PROC_FS extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start, 				      off_t offset, int length, int inout); extern int dispatch_scsi_info(int ino, char *buffer, char **start, 			      off_t offset, int length, int inout); struct proc_dir_entry proc_scsi_scsi = {    PROC_SCSI_SCSI, 4, "scsi",    S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0,     NULL,    NULL, NULL,    NULL, NULL, NULL};#endif/* *  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#define MIN_RESET_DELAY (2*HZ)/* Do not call reset on error if we just did a reset within 15 sec. */#define MIN_RESET_PERIOD (15*HZ)/* The following devices are known not to tolerate a lun != 0 scan for * one reason or another.  Some will respond to all luns, others will * lock up.  */#define BLIST_NOLUN     0x01#define BLIST_FORCELUN  0x02#define BLIST_BORKEN    0x04#define BLIST_KEY       0x08#define BLIST_SINGLELUN 0x10#define BLIST_NOTQ	0x20#define BLIST_SPARSELUN 0x40#define BLIST_MAX5LUN	0x80struct dev_info{    const char * vendor;    const char * model;    const char * revision; /* Latest revision known to be bad.  Not used yet */    unsigned flags;};/* * This is what was previously known as the blacklist.  The concept * has been expanded so that we can specify other types of things we * need to be aware of. */static struct dev_info device_list[] ={{"TEAC","CD-R55S","1.0H", BLIST_NOLUN},         /* Locks up if polled for lun != 0 */{"CHINON","CD-ROM CDS-431","H42", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */{"CHINON","CD-ROM CDS-535","Q14", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */{"DENON","DRD-25X","V", BLIST_NOLUN},           /* Locks up if probed for lun != 0 */{"HITACHI","DK312C","CM81", BLIST_NOLUN},       /* Responds to all lun - dtg */{"HITACHI","DK314C","CR21" , BLIST_NOLUN},      /* responds to all lun */{"IMS", "CDD521/10","2.06", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */{"MAXTOR","XT-3280","PR02", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */{"MAXTOR","XT-4380S","B3C", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */{"MAXTOR","MXT-1240S","I1.2", BLIST_NOLUN},     /* Locks up when LUN>0 polled */{"MAXTOR","XT-4170S","B5A", BLIST_NOLUN},       /* Locks-up sometimes when LUN>0 polled. */{"MAXTOR","XT-8760S","B7B", BLIST_NOLUN},       /* guess what? */{"MEDIAVIS","RENO CD-ROMX2A","2.03",BLIST_NOLUN},/*Responds to all lun */{"MICROP", "4110", "*", BLIST_NOTQ},		/* Buggy Tagged Queuing */{"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN},  /* Locks-up when LUN>0 polled. */{"RODIME","RO3000S","2.33", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */{"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},     /* causes failed REQUEST SENSE on lun 1 						 * for aha152x controller, which causes 						 * SCSI code to reset bus.*/{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},   /* causes failed REQUEST SENSE on lun 1 						 * for aha152x controller, which causes 						 * SCSI code to reset bus.*/{"SEAGATE", "ST296","921", BLIST_NOLUN},        /* Responds to all lun */{"SEAGATE","ST1581","6538",BLIST_NOLUN},	/* Responds to all lun */{"SONY","CD-ROM CDU-541","4.3d", BLIST_NOLUN},{"SONY","CD-ROM CDU-55S","1.0i", BLIST_NOLUN},{"SONY","CD-ROM CDU-561","1.7x", BLIST_NOLUN},{"TANDBERG","TDC 3600","U07", BLIST_NOLUN},     /* Locks up if polled for lun != 0 */{"TEAC","CD-ROM","1.06", BLIST_NOLUN},          /* causes failed REQUEST SENSE on lun 1 						 * for seagate controller, which causes 						 * SCSI code to reset bus.*/{"TEXEL","CD-ROM","1.06", BLIST_NOLUN},         /* causes failed REQUEST SENSE on lun 1 						 * for seagate controller, which causes 						 * SCSI code to reset bus.*/{"QUANTUM","LPS525S","3110", BLIST_NOLUN},      /* Locks sometimes if polled for lun != 0 */{"QUANTUM","PD1225S","3110", BLIST_NOLUN},      /* Locks sometimes if polled for lun != 0 */{"MEDIAVIS","CDR-H93MV","1.31", BLIST_NOLUN},   /* Locks up if polled for lun != 0 */{"SANKYO", "CP525","6.64", BLIST_NOLUN},        /* causes failed REQ SENSE, extra reset */{"HP", "C1750A", "3226", BLIST_NOLUN},          /* scanjet iic */{"HP", "C1790A", "", BLIST_NOLUN},              /* scanjet iip */{"HP", "C2500A", "", BLIST_NOLUN},              /* scanjet iicx *//* * Other types of devices that have special flags. */{"SONY","CD-ROM CDU-8001","*", BLIST_BORKEN},{"TEXEL","CD-ROM","1.06", BLIST_BORKEN},{"IOMEGA","Io20S         *F","*", BLIST_KEY},{"INSITE","Floptical   F*8I","*", BLIST_KEY},{"INSITE","I325VM","*", BLIST_KEY},{"NRC","MBR-7","*", BLIST_FORCELUN | BLIST_SINGLELUN},{"NRC","MBR-7.4","*", BLIST_FORCELUN | BLIST_SINGLELUN},{"REGAL","CDC-4X","*", BLIST_MAX5LUN | BLIST_SINGLELUN},{"NAKAMICH","MJ-4.8S","*", BLIST_FORCELUN | BLIST_SINGLELUN},{"NAKAMICH","MJ-5.16S","*", BLIST_FORCELUN | BLIST_SINGLELUN},{"PIONEER","CD-ROM DRM-600","*", BLIST_FORCELUN | BLIST_SINGLELUN},{"PIONEER","CD-ROM DRM-602X","*", BLIST_FORCELUN | BLIST_SINGLELUN},{"PIONEER","CD-ROM DRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN},{"EMULEX","MD21/S2     ESDI","*", BLIST_SINGLELUN},{"CANON","IPUBJD","*", BLIST_SPARSELUN},{"MATSHITA","PD","*", BLIST_FORCELUN | BLIST_SINGLELUN},{"YAMAHA","CDR100","1.00", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */{"YAMAHA","CDR102","1.00", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */{"nCipher","Fastness Crypto","*", BLIST_FORCELUN},/* * Must be at end of list... */{NULL, NULL, NULL}};static int get_device_flags(unsigned char * response_data){    int i = 0;    unsigned char * pnt;    for(i=0; 1; i++){	if(device_list[i].vendor == NULL) return 0;	pnt = &response_data[8];	while(*pnt && *pnt == ' ') pnt++;	if(memcmp(device_list[i].vendor, pnt,		  strlen(device_list[i].vendor))) continue;	pnt = &response_data[16];	while(*pnt && *pnt == ' ') pnt++;	if(memcmp(device_list[i].model, pnt,		  strlen(device_list[i].model))) continue;	return device_list[i].flags;    }    return 0;}void scsi_make_blocked_list(void)  {    int block_count = 0, index;    unsigned long flags;    struct Scsi_Host * sh[128], * shpnt;        /*     * Create a circular linked list from the scsi hosts which have     * the "wish_block" field in the Scsi_Host structure set.     * The blocked list should include all the scsi hosts using ISA DMA.     * In some systems, using two dma channels simultaneously causes     * unpredictable results.     * Among the scsi hosts in the blocked list, only one host at a time     * is allowed to have active commands queued. The transition from     * one active host to the next one is allowed only when host_busy == 0     * for the active host (which implies host_busy == 0 for all the hosts     * in the list). Moreover for block devices the transition to a new     * active host is allowed only when a request is completed, since a     * block device request can be divided into multiple scsi commands     * (when there are few sg lists or clustering is disabled).     *     * (DB, 4 Feb 1995)     */        save_flags(flags);    cli();    host_active = NULL;        for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) {	#if 0	/*	 * Is this is a candidate for the blocked list?	 * Useful to put into the blocked list all the hosts whose driver	 * does not know about the host->block feature.	 */	if (shpnt->unchecked_isa_dma) shpnt->wish_block = 1;#endif		if (shpnt->wish_block) sh[block_count++] = shpnt;    }        if (block_count == 1) sh[0]->block = NULL;        else if (block_count > 1) {		for(index = 0; index < block_count - 1; index++) {	    sh[index]->block = sh[index + 1];	    printk("scsi%d : added to blocked host list.\n",		   sh[index]->host_no);	}		sh[block_count - 1]->block = sh[0];	printk("scsi%d : added to blocked host list.\n",	       sh[index]->host_no);    }        restore_flags(flags);}static void scan_scsis_done (Scsi_Cmnd * SCpnt){    #ifdef DEBUG    printk ("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result);#endif    SCpnt->request.rq_status = RQ_SCSI_DONE;        if (SCpnt->request.sem != NULL)	up(SCpnt->request.sem);}#ifdef CONFIG_SCSI_MULTI_LUNstatic int max_scsi_luns = 8;#elsestatic int max_scsi_luns = 1;#endifvoid scsi_luns_setup(char *str, int *ints) {    if (ints[0] != 1)	printk("scsi_luns_setup : usage max_scsi_luns=n (n should be between 1 and 8)\n");    else	max_scsi_luns = ints[1];}/* *  Detecting SCSI devices : *  We scan all present host adapter's busses,  from ID 0 to ID (max_id). *  We use the INQUIRY command, determine device type, and pass the ID / *  lun address of all sequential devices to the tape driver, all random *  devices to the disk driver. */static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded,                 unchar hchannel, unchar hid, unchar hlun){  int dev, lun, channel;  unsigned char scsi_result0[256];  unsigned char *scsi_result;  Scsi_Device *SDpnt;  int max_dev_lun, sparse_lun;  Scsi_Cmnd *SCpnt;  SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA);  SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);  memset (SCpnt, 0, sizeof (Scsi_Cmnd));  /* Make sure we have something that is valid for DMA purposes */  scsi_result = ( ( !shpnt->unchecked_isa_dma )                 ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA));  if (scsi_result == NULL) {    printk ("Unable to obtain scsi_result buffer\n");    goto leave;  }  /* We must chain ourself in the host_queue, so commands can time out */  if(shpnt->host_queue)      shpnt->host_queue->prev = SCpnt;  SCpnt->next = shpnt->host_queue;  SCpnt->prev = NULL;  shpnt->host_queue = SCpnt;  if (hardcoded == 1) {    Scsi_Device *oldSDpnt=SDpnt;    struct Scsi_Device_Template * sdtpnt;

⌨️ 快捷键说明

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