gdth.c

来自「linux 内核源代码」· C语言 代码 · 共 1,832 行 · 第 1/5 页

C
1,832
字号
/************************************************************************ * Linux driver for                                                     *   * ICP vortex GmbH:    GDT ISA/EISA/PCI Disk Array Controllers          * * Intel Corporation:  Storage RAID Controllers                         * *                                                                      * * gdth.c                                                               * * Copyright (C) 1995-06 ICP vortex GmbH, Achim Leubner                 * * Copyright (C) 2002-04 Intel Corporation                              * * Copyright (C) 2003-06 Adaptec Inc.                                   * * <achim_leubner@adaptec.com>                                          * *                                                                      * * Additions/Fixes:                                                     * * Boji Tony Kannanthanam <boji.t.kannanthanam@intel.com>               * * Johannes Dinner <johannes_dinner@adaptec.com>                        * *                                                                      * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published    * * by the Free Software Foundation; either version 2 of the License,    * * or (at your option) any later version.                               * *                                                                      * * This program is distributed in the hope that it will be useful,      * * but WITHOUT ANY WARRANTY; without even the implied warranty of       * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the         * * GNU General Public License for more details.                         * *                                                                      * * You should have received a copy of the GNU General Public License    * * along with this kernel; if not, write to the Free Software           * * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            * *                                                                      * * Linux kernel 2.6.x supported						* *                                                                      * ************************************************************************//* All GDT Disk Array Controllers are fully supported by this driver. * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the * PCI Fibre Channel Disk Array Controllers. See gdth.h for a complete * list of all controller types. *  * If you have one or more GDT3000/3020 EISA controllers with  * controller BIOS disabled, you have to set the IRQ values with the  * command line option "gdth=irq1,irq2,...", where the irq1,irq2,... are * the IRQ values for the EISA controllers. *  * After the optional list of IRQ values, other possible  * command line options are: * disable:Y                    disable driver * disable:N                    enable driver * reserve_mode:0               reserve no drives for the raw service * reserve_mode:1               reserve all not init., removable drives * reserve_mode:2               reserve all not init. drives * reserve_list:h,b,t,l,h,b,t,l,...     reserve particular drive(s) with  *                              h- controller no., b- channel no.,  *                              t- target ID, l- LUN * reverse_scan:Y               reverse scan order for PCI controllers          * reverse_scan:N               scan PCI controllers like BIOS * max_ids:x                    x - target ID count per channel (1..MAXID) * rescan:Y                     rescan all channels/IDs  * rescan:N                     use all devices found until now * hdr_channel:x                x - number of virtual bus for host drives * shared_access:Y              disable driver reserve/release protocol to  *                              access a shared resource from several nodes,  *                              appropriate controller firmware required * shared_access:N              enable driver reserve/release protocol * probe_eisa_isa:Y             scan for EISA/ISA controllers * probe_eisa_isa:N             do not scan for EISA/ISA controllers * force_dma32:Y                use only 32 bit DMA mode * force_dma32:N                use 64 bit DMA mode, if supported * * The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N, *                          max_ids:127,rescan:N,hdr_channel:0, *                          shared_access:Y,probe_eisa_isa:N,force_dma32:N". * Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y". *  * When loading the gdth driver as a module, the same options are available.  * You can set the IRQs with "IRQ=...". However, the syntax to specify the * options changes slightly. You must replace all ',' between options  * with ' ' and all ':' with '=' and you must use  * '1' in place of 'Y' and '0' in place of 'N'. *  * Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0 *           max_ids=127 rescan=0 hdr_channel=0 shared_access=0 *           probe_eisa_isa=0 force_dma32=0" * The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1". *//* The meaning of the Scsi_Pointer members in this driver is as follows: * ptr:                     Chaining * this_residual:           gdth_bufflen * buffer:                  gdth_sglist * dma_handle:              unused * buffers_residual:        gdth_sg_count * Status:                  unused * Message:                 unused * have_data_in:            unused * sent_command:            unused * phase:                   unused *//* interrupt coalescing *//* #define INT_COAL *//* statistics */#define GDTH_STATISTICS#include <linux/module.h>#include <linux/version.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/string.h>#include <linux/ctype.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/in.h>#include <linux/proc_fs.h>#include <linux/time.h>#include <linux/timer.h>#include <linux/dma-mapping.h>#include <linux/list.h>#ifdef GDTH_RTC#include <linux/mc146818rtc.h>#endif#include <linux/reboot.h>#include <asm/dma.h>#include <asm/system.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/spinlock.h>#include <linux/blkdev.h>#include <linux/scatterlist.h>#include "scsi.h"#include <scsi/scsi_host.h>#include "gdth.h"static void gdth_delay(int milliseconds);static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs);static irqreturn_t gdth_interrupt(int irq, void *dev_id);static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,                                    int gdth_from_wait, int* pIndex);static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,                                                               Scsi_Cmnd *scp);static int gdth_async_event(gdth_ha_str *ha);static void gdth_log_event(gdth_evt_data *dvr, char *buffer);static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority);static void gdth_next(gdth_ha_str *ha);static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b);static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp);static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, ushort source,                                      ushort idx, gdth_evt_data *evt);static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr);static void gdth_readapp_event(gdth_ha_str *ha, unchar application,                                gdth_evt_str *estr);static void gdth_clear_events(void);static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp,                                    char *buffer, ushort count, int to_buffer);static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp);static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive);static void gdth_enable_int(gdth_ha_str *ha);static unchar gdth_get_status(gdth_ha_str *ha, int irq);static int gdth_test_busy(gdth_ha_str *ha);static int gdth_get_cmd_index(gdth_ha_str *ha);static void gdth_release_event(gdth_ha_str *ha);static int gdth_wait(gdth_ha_str *ha, int index,ulong32 time);static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode,                                             ulong32 p1, ulong64 p2,ulong64 p3);static int gdth_search_drives(gdth_ha_str *ha);static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive);static const char *gdth_ctr_name(gdth_ha_str *ha);static int gdth_open(struct inode *inode, struct file *filep);static int gdth_close(struct inode *inode, struct file *filep);static int gdth_ioctl(struct inode *inode, struct file *filep,                      unsigned int cmd, unsigned long arg);static void gdth_flush(gdth_ha_str *ha);static int gdth_halt(struct notifier_block *nb, ulong event, void *buf);static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *));static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp,				struct gdth_cmndinfo *cmndinfo);static void gdth_scsi_done(struct scsi_cmnd *scp);#ifdef DEBUG_GDTHstatic unchar   DebugState = DEBUG_GDTH;#ifdef __SERIAL__#define MAX_SERBUF 160static void ser_init(void);static void ser_puts(char *str);static void ser_putc(char c);static int  ser_printk(const char *fmt, ...);static char strbuf[MAX_SERBUF+1];#ifdef __COM2__#define COM_BASE 0x2f8#else#define COM_BASE 0x3f8#endifstatic void ser_init(){    unsigned port=COM_BASE;    outb(0x80,port+3);    outb(0,port+1);    /* 19200 Baud, if 9600: outb(12,port) */    outb(6, port);    outb(3,port+3);    outb(0,port+1);    /*    ser_putc('I');    ser_putc(' ');    */}static void ser_puts(char *str){    char *ptr;    ser_init();    for (ptr=str;*ptr;++ptr)        ser_putc(*ptr);}static void ser_putc(char c){    unsigned port=COM_BASE;    while ((inb(port+5) & 0x20)==0);    outb(c,port);    if (c==0x0a)    {        while ((inb(port+5) & 0x20)==0);        outb(0x0d,port);    }}static int ser_printk(const char *fmt, ...){    va_list args;    int i;    va_start(args,fmt);    i = vsprintf(strbuf,fmt,args);    ser_puts(strbuf);    va_end(args);    return i;}#define TRACE(a)    {if (DebugState==1) {ser_printk a;}}#define TRACE2(a)   {if (DebugState==1 || DebugState==2) {ser_printk a;}}#define TRACE3(a)   {if (DebugState!=0) {ser_printk a;}}#else /* !__SERIAL__ */#define TRACE(a)    {if (DebugState==1) {printk a;}}#define TRACE2(a)   {if (DebugState==1 || DebugState==2) {printk a;}}#define TRACE3(a)   {if (DebugState!=0) {printk a;}}#endif#else /* !DEBUG */#define TRACE(a)#define TRACE2(a)#define TRACE3(a)#endif#ifdef GDTH_STATISTICSstatic ulong32 max_rq=0, max_index=0, max_sg=0;#ifdef INT_COALstatic ulong32 max_int_coal=0;#endifstatic ulong32 act_ints=0, act_ios=0, act_stats=0, act_rq=0;static struct timer_list gdth_timer;#endif#define PTR2USHORT(a)   (ushort)(ulong)(a)#define GDTOFFSOF(a,b)  (size_t)&(((a*)0)->b)#define INDEX_OK(i,t)   ((i)<ARRAY_SIZE(t))#define BUS_L2P(a,b)    ((b)>(a)->virt_bus ? (b-1):(b))#ifdef CONFIG_ISAstatic unchar   gdth_drq_tab[4] = {5,6,7,7};            /* DRQ table */#endif#if defined(CONFIG_EISA) || defined(CONFIG_ISA)static unchar   gdth_irq_tab[6] = {0,10,11,12,14,0};    /* IRQ table */#endifstatic unchar   gdth_polling;                           /* polling if TRUE */static int      gdth_ctr_count  = 0;                    /* controller count */static LIST_HEAD(gdth_instances);                       /* controller list */static unchar   gdth_write_through = FALSE;             /* write through */static gdth_evt_str ebuffer[MAX_EVENTS];                /* event buffer */static int elastidx;static int eoldidx;static int major;#define DIN     1                               /* IN data direction */#define DOU     2                               /* OUT data direction */#define DNO     DIN                             /* no data transfer */#define DUN     DIN                             /* unknown data direction */static unchar gdth_direction_tab[0x100] = {    DNO,DNO,DIN,DIN,DOU,DIN,DIN,DOU,DIN,DUN,DOU,DOU,DUN,DUN,DUN,DIN,    DNO,DIN,DIN,DOU,DIN,DOU,DNO,DNO,DOU,DNO,DIN,DNO,DIN,DOU,DNO,DUN,    DIN,DUN,DIN,DUN,DOU,DIN,DUN,DUN,DIN,DIN,DOU,DNO,DUN,DIN,DOU,DOU,    DOU,DOU,DOU,DNO,DIN,DNO,DNO,DIN,DOU,DOU,DOU,DOU,DIN,DOU,DIN,DOU,    DOU,DOU,DIN,DIN,DIN,DNO,DUN,DNO,DNO,DNO,DUN,DNO,DOU,DIN,DUN,DUN,    DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DUN,    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DIN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DIN,DUN,    DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DOU,DUN,DNO,DUN,DOU,DOU,    DOU,DOU,DOU,DNO,DUN,DIN,DOU,DIN,DIN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,    DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN};/* LILO and modprobe/insmod parameters *//* IRQ list for GDT3000/3020 EISA controllers */static int irq[MAXHA] __initdata = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};/* disable driver flag */static int disable __initdata = 0;/* reserve flag */static int reserve_mode = 1;                  /* reserve list */static int reserve_list[MAX_RES_ARGS] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};/* scan order for PCI controllers */static int reverse_scan = 0;/* virtual channel for the host drives */static int hdr_channel = 0;/* max. IDs per channel */static int max_ids = MAXID;/* rescan all IDs */static int rescan = 0;/* shared access */static int shared_access = 1;/* enable support for EISA and ISA controllers */static int probe_eisa_isa = 0;/* 64 bit DMA mode, support for drives > 2 TB, if force_dma32 = 0 */static int force_dma32 = 0;/* parameters for modprobe/insmod */module_param_array(irq, int, NULL, 0);module_param(disable, int, 0);module_param(reserve_mode, int, 0);module_param_array(reserve_list, int, NULL, 0);module_param(reverse_scan, int, 0);module_param(hdr_channel, int, 0);module_param(max_ids, int, 0);module_param(rescan, int, 0);module_param(shared_access, int, 0);module_param(probe_eisa_isa, int, 0);module_param(force_dma32, int, 0);MODULE_AUTHOR("Achim Leubner");

⌨️ 快捷键说明

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