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 + -
显示快捷键?