📄 mptbase.c
字号:
/* * linux/drivers/message/fusion/mptbase.c * High performance SCSI + LAN / Fibre Channel device drivers. * This is the Fusion MPT base driver which supports multiple * (SCSI + LAN) specialized protocol drivers. * For use with PCI chip/adapter(s): * LSIFC9xx/LSI409xx Fibre Channel * running LSI Logic Fusion MPT (Message Passing Technology) firmware. * * Credits: * There are lots of people not mentioned below that deserve credit * and thanks but won't get it here - sorry in advance that you * got overlooked. * * This driver would not exist if not for Alan Cox's development * of the linux i2o driver. * * A special thanks to Noah Romer (LSI Logic) for tons of work * and tough debugging on the LAN driver, especially early on;-) * And to Roger Hickerson (LSI Logic) for tirelessly supporting * this driver project. * * A special thanks to Pamela Delaney (LSI Logic) for tons of work * and countless enhancements while adding support for the 1030 * chip family. Pam has been instrumental in the development of * of the 2.xx.xx series fusion drivers, and her contributions are * far too numerous to hope to list in one place. * * All manner of help from Stephen Shirron (LSI Logic): * low-level FC analysis, debug + various fixes in FCxx firmware, * initial port to alpha platform, various driver code optimizations, * being a faithful sounding board on all sorts of issues & ideas, * etc. * * A huge debt of gratitude is owed to David S. Miller (DaveM) * for fixing much of the stupid and broken stuff in the early * driver while porting to sparc64 platform. THANK YOU! * * Special thanks goes to the I2O LAN driver people at the * University of Helsinki, who, unbeknownst to them, provided * the inspiration and initial structure for this driver. * * A really huge debt of gratitude is owed to Eddie C. Dost * for gobs of hard work fixing and optimizing LAN code. * THANK YOU! * * Copyright (c) 1999-2004 LSI Logic Corporation * Originally By: Steven J. Ralston * (mailto:sjralston1@netscape.net) * (mailto:mpt_linux_developer@lsil.com) * * $Id: mptbase.c,v 1.126 2002/12/16 15:28:45 pdelaney Exp $ *//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* 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; version 2 of the License. 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. NO WARRANTY THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. DISCLAIMER OF LIABILITY NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*//*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/#include <linux/config.h>#include <linux/version.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/kdev_t.h>#include <linux/blkdev.h>#include <linux/delay.h>#include <linux/interrupt.h> /* needed for in_interrupt() proto */#include <asm/io.h>#ifdef CONFIG_MTRR#include <asm/mtrr.h>#endif#ifdef __sparc__#include <asm/irq.h> /* needed for __irq_itoa() proto */#endif#include "mptbase.h"/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/#define my_NAME "Fusion MPT base driver"#define my_VERSION MPT_LINUX_VERSION_COMMON#define MYNAM "mptbase"MODULE_AUTHOR(MODULEAUTHOR);MODULE_DESCRIPTION(my_NAME);MODULE_LICENSE("GPL");/* * cmd line parameters */#ifdef MFCNTstatic int mfcounter = 0;#define PRINT_MF_COUNT 20000#endif/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * Public data... */int mpt_lan_index = -1;int mpt_stm_index = -1;struct proc_dir_entry *mpt_proc_root_dir;#define WHOINIT_UNKNOWN 0xAA/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * Private data... */ /* Adapter link list */LIST_HEAD(ioc_list); /* Callback lookup table */static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS]; /* Protocol driver class lookup table */static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS]; /* Event handler lookup table */static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS]; /* Reset handler lookup table */static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];static int mpt_base_index = -1;static int last_drv_idx = -1;static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * Forward protos... */static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, int replyBytes, u16 *u16reply, int maxwait, int sleepFlag);static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);static void mpt_adapter_disable(MPT_ADAPTER *ioc);static void mpt_adapter_dispose(MPT_ADAPTER *ioc);static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);//static u32 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);static int mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag);static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);static int PrimeIocFifos(MPT_ADAPTER *ioc);static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);static int GetLanConfigPages(MPT_ADAPTER *ioc);static int GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);static int GetIoUnitPage2(MPT_ADAPTER *ioc);static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);static void mpt_timer_expired(unsigned long data);static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);#ifdef CONFIG_PROC_FSstatic int procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data);static int procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data);static int procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data);#endifstatic void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);static void mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info);/* module entry point */static int __devinit mptbase_probe (struct pci_dev *, const struct pci_device_id *);static void __devexit mptbase_remove(struct pci_dev *);static void mptbase_shutdown(struct device * );static int __init fusion_init (void);static void __exit fusion_exit (void);/**************************************************************************** * Supported hardware */static struct pci_device_id mptbase_pci_table[] = { { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC909, PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC929, PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC919, PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC929X, PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC919X, PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1030, PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_1030_53C1035, PCI_ANY_ID, PCI_ANY_ID }, {0} /* Terminating entry */};MODULE_DEVICE_TABLE(pci, mptbase_pci_table);#define CHIPREG_READ32(addr) readl_relaxed(addr)#define CHIPREG_READ32_dmasync(addr) readl(addr)#define CHIPREG_WRITE32(addr,val) writel(val, addr)#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*//* * mpt_interrupt - MPT adapter (IOC) specific interrupt handler. * @irq: irq number (not used) * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure * @r: pt_regs pointer (not used) * * This routine is registered via the request_irq() kernel API call, * and handles all interrupts generated from a specific MPT adapter * (also referred to as a IO Controller or IOC). * This routine must clear the interrupt from the adapter and does * so by reading the reply FIFO. Multiple replies may be processed * per single call to this routine; up to MPT_MAX_REPLIES_PER_ISR * which is currently set to 32 in mptbase.h. * * This routine handles register-level access of the adapter but * dispatches (calls) a protocol-specific callback routine to handle * the protocol-specific details of the MPT request completion. */static irqreturn_tmpt_interrupt(int irq, void *bus_id, struct pt_regs *r){ MPT_ADAPTER *ioc; MPT_FRAME_HDR *mf; MPT_FRAME_HDR *mr; u32 pa; int req_idx; int cb_idx; int type; int freeme; ioc = (MPT_ADAPTER *)bus_id; /* * Drain the reply FIFO! * * NOTES: I've seen up to 10 replies processed in this loop, so far... * Update: I've seen up to 9182 replies processed in this loop! ?? * Update: Limit ourselves to processing max of N replies * (bottom of loop). */ while (1) { if ((pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo)) == 0xFFFFFFFF) return IRQ_HANDLED; cb_idx = 0; freeme = 0; /* * Check for non-TURBO reply! */ if (pa & MPI_ADDRESS_REPLY_A_BIT) { u32 reply_dma_low; u16 ioc_stat; /* non-TURBO reply! Hmmm, something may be up... * Newest turbo reply mechanism; get address * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)! */ /* Map DMA address of reply header to cpu address. * pa is 32 bits - but the dma address may be 32 or 64 bits * get offset based only only the low addresses */ reply_dma_low = (pa = (pa << 1)); mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames + (reply_dma_low - ioc->reply_frames_low_dma)); req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx); cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx; mf = MPT_INDEX_2_MFPTR(ioc, req_idx); dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x\n", ioc->name, mr, req_idx)); DBG_DUMP_REPLY_FRAME(mr) /* NEW! 20010301 -sralston * Check/log IOC log info */ ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus); if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo); if (ioc->bus_type == FC) mpt_fc_log_info(ioc, log_info); else if (ioc->bus_type == SCSI) mpt_sp_log_info(ioc, log_info); } if (ioc_stat & MPI_IOCSTATUS_MASK) { if (ioc->bus_type == SCSI) mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf); } } else { /* * Process turbo (context) reply... */ dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n", ioc->name, pa)); type = (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT); if (type == MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET) { cb_idx = mpt_stm_index; mf = NULL; mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); } else if (type == MPI_CONTEXT_REPLY_TYPE_LAN) { cb_idx = mpt_lan_index; /* * BUG FIX! 20001218 -sralston * Blind set of mf to NULL here was fatal * after lan_reply says "freeme" * Fix sort of combined with an optimization here; * added explicit check for case where lan_reply * was just returning 1 and doing nothing else. * For this case skip the callback, but set up * proper mf value first here:-) */ if ((pa & 0x58000000) == 0x58000000) { req_idx = pa & 0x0000FFFF; mf = MPT_INDEX_2_MFPTR(ioc, req_idx); freeme = 1; /* * IMPORTANT! Invalidate the callback! */ cb_idx = 0; } else { mf = NULL; } mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); } else { req_idx = pa & 0x0000FFFF; cb_idx = (pa & 0x00FF0000) >> 16; mf = MPT_INDEX_2_MFPTR(ioc, req_idx); mr = NULL; } pa = 0; /* No reply flush! */ }#ifdef MPT_DEBUG_IRQ if (ioc->bus_type == SCSI) { /* Verify mf, mr are reasonable. */ if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth)) || (mf < ioc->req_frames)) ) { printk(MYIOC_s_WARN_FMT "mpt_interrupt: Invalid mf (%p) req_idx (%d)!\n", ioc->name, (void *)mf, req_idx); cb_idx = 0; pa = 0; freeme = 0; } if ((pa) && (mr) && ((mr >= MPT_INDEX_2_RFPTR(ioc, ioc->req_depth)) || (mr < ioc->reply_frames)) ) { printk(MYIOC_s_WARN_FMT "mpt_interrupt: Invalid rf (%p)!\n", ioc->name, (void *)mr); cb_idx = 0; pa = 0; freeme = 0; } if (cb_idx > (MPT_MAX_PROTOCOL_DRIVERS-1)) { printk(MYIOC_s_WARN_FMT "mpt_interrupt: Invalid cb_idx (%d)!\n", ioc->name, cb_idx); cb_idx = 0; pa = 0; freeme = 0; } }#endif /* Check for (valid) IO callback! */ if (cb_idx) { /* Do the callback! */ freeme = (*(MptCallbacks[cb_idx]))(ioc, mf, mr); } if (pa) { /* Flush (non-TURBO) reply with a WRITE! */ CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa); } if (freeme) { unsigned long flags; /* Put Request back on FreeQ! */ spin_lock_irqsave(&ioc->FreeQlock, flags); list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);#ifdef MFCNT ioc->mfcnt--;#endif spin_unlock_irqrestore(&ioc->FreeQlock, flags); } mb(); } /* drain reply FIFO */ return IRQ_HANDLED;}/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -