📄 megaraid.c
字号:
/*=================================================================== * * Linux MegaRAID device driver * * Copyright 1999 American Megatrends Inc. * * 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. * * Version : 1.07b * * Description: Linux device driver for AMI MegaRAID controller * * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 490 * * History: * * Version 0.90: * Original source contributed by Dell; integrated it into the kernel and * cleaned up some things. Added support for 438/466 controllers. * * Version 0.91: * Aligned mailbox area on 16-byte boundry. * Added schedule() at the end to properly clean up. * Made improvements for conformity to linux driver standards. * * Version 0.92: * Added support for 2.1 kernels. * Reads from pci_dev struct, so it's not dependent on pcibios. * Added some missing virt_to_bus() translations. * Added support for SMP. * Changed global cli()'s to spinlocks for 2.1, and simulated * spinlocks for 2.0. * Removed setting of SA_INTERRUPT flag when requesting Irq. * * Version 0.92ac: * Small changes to the comments/formatting. Plus a couple of * added notes. Returned to the authors. No actual code changes * save printk levels. * 8 Oct 98 Alan Cox <alan.cox@linux.org> * * Merged with 2.1.131 source tree. * 12 Dec 98 K. Baranowski <kgb@knm.org.pl> * * Version 0.93: * Added support for vendor specific ioctl commands (0x80+xxh) * Changed some fields in MEGARAID struct to better values. * Added signature check for Rp controllers under 2.0 kernels * Changed busy-wait loop to be time-based * Fixed SMP race condition in isr * Added kfree (sgList) on release * Added #include linux/version.h to megaraid.h for hosts.h * Changed max_id to represent max logical drives instead of targets. * * Version 0.94: * Got rid of some excess locking/unlocking * Fixed slight memory corruption problem while memcpy'ing into mailbox * Changed logical drives to be reported as luns rather than targets * Changed max_id to 16 since it is now max targets/chan again. * Improved ioctl interface for upcoming megamgr * * Version 0.95: * Fixed problem of queueing multiple commands to adapter; * still has some strange problems on some setups, so still * defaults to single. To enable parallel commands change * #define MULTI_IO in megaraid.h * Changed kmalloc allocation to be done in beginning. * Got rid of C++ style comments * * Version 0.96: * 762 fully supported. * * Version 0.97: * Changed megaraid_command to use wait_queue. * Fixed bug of undesirably detecting HP onboard controllers which * are disabled. * * Version 1.00: * Checks to see if an irq ocurred while in isr, and runs through * routine again. * Copies mailbox to temp area before processing in isr * Added barrier() in busy wait to fix volatility bug * Uses separate list for freed Scbs, keeps track of cmd state * Put spinlocks around entire queue function for now... * Full multi-io commands working stablely without previous problems * Added skipXX LILO option for Madrona motherboard support * * Version 1.01: * Fixed bug in mega_cmd_done() for megamgr control commands, * the host_byte in the result code from the scsi request to * scsi midlayer is set to DID_BAD_TARGET when adapter's * returned codes are 0xF0 and 0xF4. * * Version 1.02: * Fixed the tape drive bug by extending the adapter timeout value * for passthrough command to 60 seconds in mega_build_cmd(). * * Version 1.03: * Fixed Madrona support. * Changed the adapter timeout value from 60 sec in 1.02 to 10 min * for bigger and slower tape drive. * Added driver version printout at driver loadup time * * Version 1.04 * Added code for 40 ld FW support. * Added new ioctl command 0x81 to support NEW_READ/WRITE_CONFIG with * data area greater than 4 KB, which is the upper bound for data * tranfer through scsi_ioctl interface. * The addtional 32 bit field for 64bit address in the newly defined * mailbox64 structure is set to 0 at this point. * * Version 1.05 * Changed the queing implementation for handling SCBs and completed * commands. * Added spinlocks in the interrupt service routine to enable the dirver * function in the SMP environment. * Fixed the problem of unnecessary aborts in the abort entry point, which * also enables the driver to handle large amount of I/O requests for * long duration of time. * * Version 1.07 * Removed the usage of uaccess.h file for kernel versions less than * 2.0.36, as this file is not present in those versions. * * Version 1.07b * The MegaRAID 466 cards with 3.00 firmware lockup and seem to very * occasionally hang. We check such cards and report them. You can * get firmware upgrades to flash the board to 3.10 for free. * * BUGS: * Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that * fails to detect the controller as a pci device on the system. * * Timeout period for upper scsi layer, i.e. SD_TIMEOUT in * /drivers/scsi/sd.c, is too short for this controller. SD_TIMEOUT * value must be increased to (30 * HZ) otherwise false timeouts * will occur in the upper layer. * *===================================================================*/#define CRLFSTR "\n"#define IOCTL_CMD_NEW 0x81#define MEGARAID_VERSION "v107 (December 22, 1999)"#include <linux/version.h>#ifdef MODULE#include <linux/modversions.h>#include <linux/module.h>char kernel_version[] = UTS_RELEASE;MODULE_AUTHOR ("American Megatrends Inc.");MODULE_DESCRIPTION ("AMI MegaRAID driver");#endif#include <linux/init.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/ioport.h>#include <linux/fcntl.h>#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/stat.h>#include <linux/spinlock.h>#include <asm/io.h>#include <asm/irq.h>#if LINUX_VERSION_CODE > 0x020024#include <asm/uaccess.h>#endif#include "sd.h"#include "scsi.h"#include "hosts.h"#include "megaraid.h"/*================================================================ * * #Defines * *================================================================ */#define MAX_SERBUF 160#define COM_BASE 0x2f8u32 RDINDOOR (mega_host_config * megaCfg){ return readl (megaCfg->base + 0x20);}void WRINDOOR (mega_host_config * megaCfg, u32 value){ writel (value, megaCfg->base + 0x20);}u32 RDOUTDOOR (mega_host_config * megaCfg){ return readl (megaCfg->base + 0x2C);}void WROUTDOOR (mega_host_config * megaCfg, u32 value){ writel (value, megaCfg->base + 0x2C);}/*================================================================ * * Function prototypes * *================================================================ */static int __init megaraid_setup(char *);static int megaIssueCmd (mega_host_config * megaCfg, u_char * mboxData, mega_scb * scb, int intr);static int mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb, u32 * buffer, u32 * length);static int mega_busyWaitMbox(mega_host_config *);static void mega_runpendq (mega_host_config *);static void mega_rundoneq (mega_host_config *);static void mega_cmd_done (mega_host_config *, mega_scb *, int);static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt);static inline void mega_freeSgList(mega_host_config *megaCfg);static void mega_Convert8ldTo40ld( mega_RAIDINQ *inquiry, mega_Enquiry3 *enquiry3, megaRaidProductInfo *productInfo );#include <linux/smp.h>#define cpuid smp_processor_id()#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);/* 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/*================================================================ * * 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 */#ifdef MODULEstatic char *megaraid = NULL;MODULE_PARM(megaraid, "s");#endifstatic int skip_id;static int numCtlrs = 0;static mega_host_config *megaCtlrs[FC_MAX_CHANNELS] = {0};#if DEBUGstatic u32 maxCmdTime = 0;#endifstatic mega_scb *pLastScb = NULL;#if SERDEBUGstatic spinlock_t serial_lock = SPIN_LOCK_UNLOCKED;#endif#if SERDEBUGstatic char strbuf[MAX_SERBUF + 1];static void ser_init (){ 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)#endifstatic 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 ; } /* 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 *=========================== */static mega_scb * mega_allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt){ mega_scb *pScb; /* Unlink command from Free List */ if ((pScb = megaCfg->qFreeH) != NULL) { megaCfg->qFreeH = pScb->next; megaCfg->qFcnt--; pScb->isrcount = jiffies; pScb->next = NULL; pScb->state = SCB_ACTIVE; pScb->SCpnt = SCpnt; return pScb; } printk (KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n"); return NULL;}/*================================================ * Initialize SCB structures *================================================ */static int mega_initSCB (mega_host_config * megaCfg){ int idx; megaCfg->qFreeH = NULL; megaCfg->qFcnt = 0;#if DEBUGif(megaCfg->max_cmds >= MAX_COMMANDS) {printk("megaraid:ctlr max cmds = %x : MAX_CMDS = %x", megaCfg->max_cmds, MAX_COMMANDS);}#endif for (idx = megaCfg->max_cmds-1; idx >= 0; idx--) { megaCfg->scbList[idx].idx = idx; megaCfg->scbList[idx].sgList = kmalloc(sizeof(mega_sglist) * MAX_SGLIST, GFP_ATOMIC | GFP_DMA); if (megaCfg->scbList[idx].sgList == NULL) { printk(KERN_WARNING "Can't allocate sglist for id %d\n",idx); mega_freeSgList(megaCfg); return -1; } if (idx < MAX_COMMANDS) { /* Link to free list */ mega_freeSCB(megaCfg, &megaCfg->scbList[idx]); } } return 0;}/* Run through the list of completed requests */static void mega_rundoneq (mega_host_config *megaCfg){ Scsi_Cmnd *SCpnt; while ((SCpnt = megaCfg->qCompletedH) != NULL) { megaCfg->qCompletedH = (Scsi_Cmnd *)SCpnt->host_scribble; megaCfg->qCcnt--; SCpnt->host_scribble = (unsigned char *) NULL ; // XC : sep 14 /* Callback */ callDone (SCpnt); } megaCfg->qCompletedH = megaCfg->qCompletedT = NULL;}/* * Runs through the list of pending requests * Assumes that mega_lock spin_lock has been acquired. */static void mega_runpendq(mega_host_config *megaCfg){ mega_scb *pScb;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -