gdth.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,814 行 · 第 1/5 页
C
1,814 行
* sent_command: Opcode special command * phase: Service/parameter/return code special command *//* 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/sched.h>#include <linux/interrupt.h>#include <linux/in.h>#include <linux/proc_fs.h>#include <linux/time.h>#include <linux/timer.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>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)#include <linux/spinlock.h>#else#include <asm/spinlock.h>#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)#include <linux/blkdev.h>#else#include <linux/blk.h>#include "sd.h"#endif#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);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)static irqreturn_t gdth_interrupt(int irq, void *dev_id, struct pt_regs *regs);#elsestatic void gdth_interrupt(int irq, void *dev_id, struct pt_regs *regs);#endifstatic int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp);static int gdth_async_event(int hanum);static void gdth_log_event(gdth_evt_data *dvr, char *buffer);static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority);static void gdth_next(int hanum);static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b);static int gdth_special_cmd(int hanum,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(int hanum,Scsi_Cmnd *scp, char *buffer,ushort count);static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp);static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive);static int gdth_search_eisa(ushort eisa_adr);static int gdth_search_isa(ulong32 bios_adr);static int gdth_search_pci(gdth_pci_str *pcistr);static void gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt, ushort vendor, ushort dev);static void gdth_sort_pci(gdth_pci_str *pcistr, int cnt);static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha);static int gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha);static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha);static void gdth_enable_int(int hanum);static int gdth_get_status(unchar *pIStatus,int irq);static int gdth_test_busy(int hanum);static int gdth_get_cmd_index(int hanum);static void gdth_release_event(int hanum);static int gdth_wait(int hanum,int index,ulong32 time);static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1, ulong64 p2,ulong64 p3);static int gdth_search_drives(int hanum);static int gdth_analyse_hdrive(int hanum, ushort hdrive);static const char *gdth_ctr_name(int hanum);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(int hanum);static int gdth_halt(struct notifier_block *nb, ulong event, void *buf);#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)<sizeof(t)/sizeof((t)[0]))#define NUMDATA(a) ( (gdth_num_str *)((a)->hostdata))#define HADATA(a) (&((gdth_ext_str *)((a)->hostdata))->haext)#define CMDDATA(a) (&((gdth_ext_str *)((a)->hostdata))->cmdext)#define BUS_L2P(a,b) ((b)>(a)->virt_bus ? (b-1):(b))#define gdth_readb(addr) readb(addr)#define gdth_readw(addr) readw(addr)#define gdth_readl(addr) readl(addr)#define gdth_writeb(b,addr) writeb((b),(addr))#define gdth_writew(b,addr) writew((b),(addr))#define gdth_writel(b,addr) writel((b),(addr))static unchar gdth_drq_tab[4] = {5,6,7,7}; /* DRQ table */static unchar gdth_irq_tab[6] = {0,10,11,12,14,0}; /* IRQ table */static unchar gdth_polling; /* polling if TRUE */static unchar gdth_from_wait = FALSE; /* gdth_wait() */static int wait_index,wait_hanum; /* gdth_wait() */static int gdth_ctr_count = 0; /* controller count */static int gdth_ctr_vcount = 0; /* virt. ctr. count */static int gdth_ctr_released = 0; /* gdth_release() */static struct Scsi_Host *gdth_ctr_tab[MAXHA]; /* controller table */static struct Scsi_Host *gdth_ctr_vtab[MAXHA*MAXBUS]; /* virt. ctr. table */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};/* __initfunc, __initdata macros */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)#define GDTH_INITFUNC(type, func) type __init func #include <linux/init.h>#else#define GDTH_INITFUNC(type, func) __initfunc(type func)#include <linux/init.h>#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)#define GDTH_INIT_LOCK_HA(ha) spin_lock_init(&(ha)->smp_lock)#define GDTH_LOCK_HA(ha,flags) spin_lock_irqsave(&(ha)->smp_lock,flags)#define GDTH_UNLOCK_HA(ha,flags) spin_unlock_irqrestore(&(ha)->smp_lock,flags)#define GDTH_LOCK_SCSI_DONE(dev, flags) spin_lock_irqsave(dev->host_lock,flags)#define GDTH_UNLOCK_SCSI_DONE(dev, flags) spin_unlock_irqrestore(dev->host_lock,flags)#else#define GDTH_INIT_LOCK_HA(ha) spin_lock_init(&(ha)->smp_lock)#define GDTH_LOCK_HA(ha,flags) spin_lock_irqsave(&(ha)->smp_lock,flags)#define GDTH_UNLOCK_HA(ha,flags) spin_unlock_irqrestore(&(ha)->smp_lock,flags)#define GDTH_LOCK_SCSI_DONE(flags) spin_lock_irqsave(&io_request_lock,flags)#define GDTH_UNLOCK_SCSI_DONE(flags) spin_unlock_irqrestore(&io_request_lock,flags)#endif/* 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;/* map channels to virtual controllers */static int virt_ctr = 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;#ifdef MODULE/* parameters for modprobe/insmod */MODULE_PARM(irq, "i");MODULE_PARM(disable, "i");MODULE_PARM(reserve_mode, "i");MODULE_PARM(reserve_list, "4-" __MODULE_STRING(MAX_RES_ARGS) "i");MODULE_PARM(reverse_scan, "i");MODULE_PARM(hdr_channel, "i");MODULE_PARM(max_ids, "i");MODULE_PARM(rescan, "i");MODULE_PARM(virt_ctr, "i");MODULE_PARM(shared_access, "i");MODULE_PARM(probe_eisa_isa, "i");MODULE_PARM(force_dma32, "i");MODULE_AUTHOR("Achim Leubner");#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,11)MODULE_LICENSE("GPL");#endif#endif/* ioctl interface */static struct file_operations gdth_fops = {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) .ioctl = gdth_ioctl, .open = gdth_open, .release = gdth_close,#else ioctl:gdth_ioctl, open:gdth_open, release:gdth_close,#endif};/* /proc support */#include <linux/stat.h> #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)struct proc_dir_entry proc_scsi_gdth = { PROC_SCSI_GDTH, 4, "gdth", S_IFDIR | S_IRUGO | S_IXUGO, 2};#endif#include "gdth_proc.h"#include "gdth_proc.c"/* notifier block to get a notify on system shutdown/halt/reboot */static struct notifier_block gdth_notifier = { gdth_halt, NULL, 0};
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?