📄 megaraid.c
字号:
#include <linux/delay.h>#include <linux/pci.h>#include <linux/proc_fs.h>#include <linux/blk.h>#include <linux/wait.h>#include <linux/tqueue.h>#include <linux/interrupt.h>#include <linux/mm.h>#include <asm/pgtable.h>#include <linux/sched.h>#include <linux/stat.h>#include <linux/slab.h> /* for kmalloc() */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */#include <linux/bios32.h>#else#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) /* 0x20300 */#include <asm/spinlock.h>#else#include <linux/spinlock.h>#endif#endif#include <asm/io.h>#include <asm/irq.h>#if LINUX_VERSION_CODE > KERNEL_VERSION(2,0,24) /* 0x020024 */#include <asm/uaccess.h>#endif/* * These header files are required for Shutdown Notification routines */#include <linux/notifier.h>#include <linux/reboot.h>#include <linux/init.h>#include "sd.h"#include "scsi.h"#include "hosts.h"#include "megaraid.h"/* *================================================================ * #Defines *================================================================ */#define MAX_SERBUF 160#define COM_BASE 0x2f8static ulong RDINDOOR (mega_host_config * megaCfg){ return readl (megaCfg->base + 0x20);}static void WRINDOOR (mega_host_config * megaCfg, ulong value){ writel (value, megaCfg->base + 0x20);}static ulong RDOUTDOOR (mega_host_config * megaCfg){ return readl (megaCfg->base + 0x2C);}static void WROUTDOOR (mega_host_config * megaCfg, ulong value){ writel (value, megaCfg->base + 0x2C);}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) /* 0x020200 */#include <linux/smp.h>#define cpuid smp_processor_id()#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)#define scsi_set_pci_device(x,y)#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020400 *//* * Linux 2.4 and higher * * No driver private lock * Use the io_request_lock not cli/sti * queue task is a simple api without irq forms */MODULE_AUTHOR ("LSI Logic Corporation");MODULE_DESCRIPTION ("LSI Logic MegaRAID driver");MODULE_LICENSE ("GPL");#define DRIVER_LOCK_T#define DRIVER_LOCK_INIT(p)#define DRIVER_LOCK(p)#define DRIVER_UNLOCK(p)#define IO_LOCK_T unsigned long io_flags = 0#define IO_LOCK spin_lock_irqsave(&io_request_lock,io_flags);#define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags);#define queue_task_irq(a,b) queue_task(a,b)#define queue_task_irq_off(a,b) queue_task(a,b)#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) /* 0x020200 *//* * Linux 2.2 and higher * * No driver private lock * Use the io_request_lock not cli/sti * No pci region api * queue_task is now a single simple API */static char kernel_version[] = UTS_RELEASE;MODULE_AUTHOR ("LSI Logic Corporation");MODULE_DESCRIPTION ("LSI Logic MegaRAID driver");#define DRIVER_LOCK_T#define DRIVER_LOCK_INIT(p)#define DRIVER_LOCK(p)#define DRIVER_UNLOCK(p)#define IO_LOCK_T unsigned long io_flags = 0#define IO_LOCK spin_lock_irqsave(&io_request_lock,io_flags);#define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags);#define pci_free_consistent(a,b,c,d)#define pci_unmap_single(a,b,c,d)#define pci_enable_device(x) (0)#define queue_task_irq(a,b) queue_task(a,b)#define queue_task_irq_off(a,b) queue_task(a,b)#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19) /* 0x020219 */#define init_MUTEX_LOCKED(x) (*(x)=MUTEX_LOCKED)#define init_MUTEX(x) (*(x)=MUTEX)#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL#endif#else/* * Linux 2.0 macros. Here we have to provide some of our own * functionality. We also only work little endian 32bit. * Again no pci_alloc/free api * IO_LOCK/IO_LOCK_T were never used in 2.0 so now are empty */ #define cpuid 0#define DRIVER_LOCK_T long cpu_flags;#define DRIVER_LOCK_INIT(p)#define DRIVER_LOCK(p) \ save_flags(cpu_flags); \ cli();#define DRIVER_UNLOCK(p) \ restore_flags(cpu_flags);#define IO_LOCK_T#define IO_LOCK(p)#define IO_UNLOCK(p)#define le32_to_cpu(x) (x)#define cpu_to_le32(x) (x)#define pci_free_consistent(a,b,c,d)#define pci_unmap_single(a,b,c,d)#define init_MUTEX_LOCKED(x) (*(x)=MUTEX_LOCKED)#define init_MUTEX(x) (*(x)=MUTEX)#define pci_enable_device(x) (0)/* * 2.0 lacks spinlocks, iounmap/ioremap */#define ioremap vremap#define iounmap vfree /* simulate spin locks */typedef struct { volatile char lock;} spinlock_t;#define spin_lock_init(x) { (x)->lock = 0;}#define spin_lock_irqsave(x,flags) { while ((x)->lock) barrier();\ (x)->lock=1; save_flags(flags);\ cli();}#define spin_unlock_irqrestore(x,flags) { (x)->lock=0; restore_flags(flags);}#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020400 */#define dma_alloc_consistent pci_alloc_consistent#define dma_free_consistent pci_free_consistent#else#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19) /* 0x020219 */typedef unsigned long dma_addr_t;#endifvoid *dma_alloc_consistent(void *, size_t, dma_addr_t *);void dma_free_consistent(void *, size_t, void *, dma_addr_t);int mega_get_order(int);int pow_2(int);#endif/* set SERDEBUG to 1 to enable serial debugging */#define SERDEBUG 0#if SERDEBUGstatic void ser_init (void);static void ser_puts (char *str);static void ser_putc (char c);static int ser_printk (const char *fmt, ...);#endif#ifdef CONFIG_PROC_FS#define COPY_BACK if (offset > megaCfg->procidx) { \ *eof = TRUE; \ megaCfg->procidx = 0; \ megaCfg->procbuf[0] = 0; \ return 0;} \ if ((count + offset) > megaCfg->procidx) { \ count = megaCfg->procidx - offset; \ *eof = TRUE; } \ memcpy(page, &megaCfg->procbuf[offset], count); \ megaCfg->procidx = 0; \ megaCfg->procbuf[0] = 0;#endif/* * ================================================================ * Global variables *================================================================ *//* Use "megaraid=skipXX" as LILO option to prohibit driver from scanning XX scsi id on each channel. Used for Madrona motherboard, where SAF_TE processor id cannot be scanned */static char *megaraid;#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) /* 0x20100 */#ifdef MODULEMODULE_PARM (megaraid, "s");#endif#endifstatic int skip_id = -1;static int numCtlrs = 0;static mega_host_config *megaCtlrs[FC_MAX_CHANNELS] = { 0 };static struct proc_dir_entry *mega_proc_dir_entry;#if DEBUGstatic u32 maxCmdTime = 0;#endifstatic mega_scb *pLastScb = NULL;static struct notifier_block mega_notifier = { megaraid_reboot_notify, NULL, 0};/* For controller re-ordering */struct mega_hbas mega_hbas[MAX_CONTROLLERS];/* * The File Operations structure for the serial/ioctl interface of the driver *//* For controller re-ordering */ static struct file_operations megadev_fops = { ioctl:megadev_ioctl_entry, open:megadev_open, release:megadev_close,};/* * Array to structures for storing the information about the controllers. This * information is sent to the user level applications, when they do an ioctl * for this information. */static struct mcontroller mcontroller[MAX_CONTROLLERS];/* The current driver version */static u32 driver_ver = 114;/* major number used by the device for character interface */static int major;static struct semaphore mimd_ioctl_sem;static struct semaphore mimd_entry_mtx;#if SERDEBUGvolatile static spinlock_t serial_lock;#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) /* 0x20300 */static struct proc_dir_entry proc_scsi_megaraid = { PROC_SCSI_MEGARAID, 8, "megaraid", S_IFDIR | S_IRUGO | S_IXUGO, 2};#endif#ifdef CONFIG_PROC_FSextern struct proc_dir_entry proc_root;#endifstatic char mega_ch_class; /* channels are raid or scsi */#define IS_RAID_CH(ch) ( (mega_ch_class >> (ch)) & 0x01 )#if SERDEBUGstatic char strbuf[MAX_SERBUF + 1];static void ser_init (void){ unsigned port = COM_BASE; outb (0x80, port + 3); outb (0, port + 1); /* 9600 Baud, if 19200: outb(6,port) */ outb (12, port); outb (3, port + 3); outb (0, port + 1);}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; long flags; spin_lock_irqsave (&serial_lock, flags); va_start (args, fmt); i = vsprintf (strbuf, fmt, args); ser_puts (strbuf); va_end (args); spin_unlock_irqrestore (&serial_lock, flags); return i;}#define TRACE(a) { ser_printk a;}#else#define TRACE(A)#endif#define TRACE1(a)static void callDone (Scsi_Cmnd * SCpnt){ if (SCpnt->result) { TRACE (("*** %.08lx %.02x <%d.%d.%d> = %x\n", SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->result)); } SCpnt->scsi_done (SCpnt);}/*------------------------------------------------------------------------- * * Local functions * *-------------------------------------------------------------------------*//*======================= * Free a SCB structure *======================= */static void mega_freeSCB (mega_host_config * megaCfg, mega_scb * pScb){ mega_scb *pScbtmp; if ((pScb == NULL) || (pScb->idx >= 0xFE)) { return; }#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) switch (pScb->dma_type) { case M_RD_DMA_TYPE_NONE: break; case M_RD_PTHRU_WITH_BULK_DATA: pci_unmap_single (megaCfg->dev, pScb->dma_h_bulkdata, pScb->pthru->dataxferlen, pScb->dma_direction); break; case M_RD_EPTHRU_WITH_BULK_DATA: pci_unmap_single (megaCfg->dev, pScb->dma_h_bulkdata, pScb->epthru->dataxferlen, pScb->dma_direction); break; case M_RD_PTHRU_WITH_SGLIST: { int count; for (count = 0; count < pScb->sglist_count; count++) { pci_unmap_single (megaCfg->dev, pScb->dma_h_sglist[count], pScb->sgList[count].length, pScb->dma_direction); } break; } case M_RD_BULK_DATA_ONLY: pci_unmap_single (megaCfg->dev, pScb->dma_h_bulkdata, pScb->iDataSize, pScb->dma_direction); break; case M_RD_SGLIST_ONLY: pci_unmap_sg (megaCfg->dev, pScb->SCpnt->request_buffer, pScb->SCpnt->use_sg, pScb->dma_direction); break; default: break; }#endif /* Unlink from pending queue */ if (pScb == megaCfg->qPendingH) { if (megaCfg->qPendingH == megaCfg->qPendingT) megaCfg->qPendingH = megaCfg->qPendingT = NULL; else megaCfg->qPendingH = megaCfg->qPendingH->next; megaCfg->qPcnt--; } else { for (pScbtmp = megaCfg->qPendingH; pScbtmp; pScbtmp = pScbtmp->next) { if (pScbtmp->next == pScb) { pScbtmp->next = pScb->next; if (pScb == megaCfg->qPendingT) { megaCfg->qPendingT = pScbtmp; } megaCfg->qPcnt--; break; } } } /* Link back into free list */ pScb->state = SCB_FREE; pScb->SCpnt = NULL; if (megaCfg->qFreeH == (mega_scb *) NULL) { megaCfg->qFreeH = megaCfg->qFreeT = pScb; } else { megaCfg->qFreeT->next = pScb; megaCfg->qFreeT = pScb; } megaCfg->qFreeT->next = NULL; megaCfg->qFcnt++;}/*=========================== * Allocate a SCB structure
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -