X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmessage%2Ffusion%2Fmptbase.c;h=b3f28a03b6a99f247648c9f12dc19f348d26213f;hb=a2f44b27303a5353859d77a3e96a1d3f33f56ab7;hp=fba96eb6d224b2de1c31f8753df0eb2bf4ceb5e4;hpb=bc77d24c47b89f1e0efed0b8e4be5f8aad102883;p=linux-2.6.git diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index fba96eb6d..b3f28a03b 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -1,55 +1,13 @@ /* * 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 + * For use with LSI Logic PCI chip/adapter(s) * 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) + * Copyright (c) 1999-2007 LSI Logic Corporation * (mailto:mpt_linux_developer@lsil.com) * - * $Id: mptbase.c,v 1.126 2002/12/16 15:28:45 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -88,8 +46,6 @@ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -#include -#include #include #include #include @@ -101,13 +57,11 @@ #include #include #include /* needed for in_interrupt() proto */ +#include #include #ifdef CONFIG_MTRR #include #endif -#ifdef __sparc__ -#include /* needed for __irq_itoa() proto */ -#endif #include "mptbase.h" @@ -119,10 +73,15 @@ MODULE_AUTHOR(MODULEAUTHOR); MODULE_DESCRIPTION(my_NAME); MODULE_LICENSE("GPL"); +MODULE_VERSION(my_VERSION); /* * cmd line parameters */ +static int mpt_msi_enable; +module_param(mpt_msi_enable, int, 0); +MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)"); + #ifdef MFCNT static int mfcounter = 0; #define PRINT_MF_COUNT 20000 @@ -137,22 +96,14 @@ int mpt_stm_index = -1; struct proc_dir_entry *mpt_proc_root_dir; -DmpServices_t *DmpService; - -void *mpt_v_ASCQ_TablePtr; -const char **mpt_ScsiOpcodesPtr; -int mpt_ASCQ_TableSz; - - #define WHOINIT_UNKNOWN 0xAA /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * Private data... */ - /* Adapter lookup table */ - MPT_ADAPTER *mpt_adapters[MPT_MAX_ADAPTERS]; -static MPT_ADAPTER_TRACKER MptAdapters; + /* Adapter link list */ +LIST_HEAD(ioc_list); /* Callback lookup table */ static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS]; /* Protocol driver class lookup table */ @@ -163,10 +114,8 @@ static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS]; static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS]; static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS]; -static int FusionInitCalled = 0; static int mpt_base_index = -1; static int last_drv_idx = -1; -static int isense_idx = -1; static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq); @@ -174,23 +123,24 @@ static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq); /* * Forward protos... */ -static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r); +static irqreturn_t mpt_interrupt(int irq, void *bus_id); 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 *this, struct pci_dev *pdev); -static void mpt_adapter_disable(MPT_ADAPTER *ioc, int freeup); +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_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, 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); @@ -199,8 +149,8 @@ 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); +int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode); 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); @@ -208,10 +158,10 @@ 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); +static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag); +static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init); #ifdef CONFIG_PROC_FS -static int procmpt_create(void); -static int procmpt_destroy(void); static 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, @@ -225,291 +175,230 @@ static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc); 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); +static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info); +static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info); +static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc); /* 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); -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#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) + +static void +pci_disable_io_access(struct pci_dev *pdev) +{ + u16 command_reg; + + pci_read_config_word(pdev, PCI_COMMAND, &command_reg); + command_reg &= ~1; + pci_write_config_word(pdev, PCI_COMMAND, command_reg); +} + +static void +pci_enable_io_access(struct pci_dev *pdev) +{ + u16 command_reg; + + pci_read_config_word(pdev, PCI_COMMAND, &command_reg); + command_reg |= 1; + pci_write_config_word(pdev, PCI_COMMAND, command_reg); +} + /* - * more Private data... + * Process turbo (context) reply... */ -#ifdef CONFIG_PROC_FS -struct _mpt_proc_list { - const char *name; - int (*f)(char *, char **, off_t, int, int *, void *); -} mpt_proc_list[] = { - { "summary", procmpt_summary_read}, - { "version", procmpt_version_read}, -}; -#define MPT_PROC_ENTRIES (sizeof(mpt_proc_list)/sizeof(mpt_proc_list[0])) - -struct _mpt_ioc_proc_list { - const char *name; - int (*f)(char *, char **, off_t, int, int *, void *); -} mpt_ioc_proc_list[] = { - { "info", procmpt_iocinfo_read}, - { "summary", procmpt_summary_read}, -}; -#define MPT_IOC_PROC_ENTRIES (sizeof(mpt_ioc_proc_list)/sizeof(mpt_ioc_proc_list[0])) +static void +mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa) +{ + MPT_FRAME_HDR *mf = NULL; + MPT_FRAME_HDR *mr = NULL; + int req_idx = 0; + int cb_idx; + + dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n", + ioc->name, pa)); + + switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) { + case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT: + req_idx = pa & 0x0000FFFF; + cb_idx = (pa & 0x00FF0000) >> 16; + mf = MPT_INDEX_2_MFPTR(ioc, req_idx); + break; + case MPI_CONTEXT_REPLY_TYPE_LAN: + cb_idx = mpt_lan_index; + /* + * 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); + mpt_free_msg_frame(ioc, mf); + mb(); + return; + break; + } + mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); + break; + case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET: + cb_idx = mpt_stm_index; + mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); + break; + default: + cb_idx = 0; + BUG(); + } -#endif + /* Check for (valid) IO callback! */ + if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || + MptCallbacks[cb_idx] == NULL) { + printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", + __FUNCTION__, ioc->name, cb_idx); + goto out; + } -/**************************************************************************** - * Supported hardware - */ + if (MptCallbacks[cb_idx](ioc, mf, mr)) + mpt_free_msg_frame(ioc, mf); + out: + mb(); +} -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); +static void +mpt_reply(MPT_ADAPTER *ioc, u32 pa) +{ + MPT_FRAME_HDR *mf; + MPT_FRAME_HDR *mr; + int req_idx; + int cb_idx; + int freeme; -#define CHIPREG_READ32(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) + 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 <<= 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 cb_idx=%x Function=%x\n", + ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function)); + DBG_DUMP_REPLY_FRAME(mr) + + /* 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 == SPI) + mpt_spi_log_info(ioc, log_info); + else if (ioc->bus_type == SAS) + mpt_sas_log_info(ioc, log_info); + } + if (ioc_stat & MPI_IOCSTATUS_MASK) { + if (ioc->bus_type == SPI && + cb_idx != mpt_stm_index && + cb_idx != mpt_lan_index) + mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf); + } + + + /* Check for (valid) IO callback! */ + if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || + MptCallbacks[cb_idx] == NULL) { + printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", + __FUNCTION__, ioc->name, cb_idx); + freeme = 0; + goto out; + } + + freeme = MptCallbacks[cb_idx](ioc, mf, mr); + + out: + /* Flush (non-TURBO) reply with a WRITE! */ + CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa); + + if (freeme) + mpt_free_msg_frame(ioc, mf); + mb(); +} /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * 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. + * per single call to this routine. * * 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_t -mpt_interrupt(int irq, void *bus_id, struct pt_regs *r) +mpt_interrupt(int irq, void *bus_id) { - MPT_ADAPTER *ioc; - MPT_FRAME_HDR *mf; - MPT_FRAME_HDR *mr; - u32 pa; - int req_idx; - int cb_idx; - int type; - int freeme; + MPT_ADAPTER *ioc = bus_id; + u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); - ioc = bus_id; - -#ifdef MPT_DEBUG_IRQ - /* - * Verify ioc pointer is ok - */ - { - MPT_ADAPTER *iocCmp; - iocCmp = mpt_adapter_find_first(); - while ((ioc != iocCmp) && iocCmp) - iocCmp = mpt_adapter_find_next(iocCmp); - - if (!iocCmp) { - printk(KERN_WARNING "mpt_interrupt: Invalid ioc!\n"); - return IRQ_NONE; - } - } -#endif + if (pa == 0xFFFFFFFF) + return IRQ_NONE; /* * 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(&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); - - dprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p\n", - ioc->name, mr)); - 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 ((int)ioc->chip_type <= (int)FC929) - mpt_fc_log_info(ioc, log_info); - else - mpt_sp_log_info(ioc, log_info); - } - if (ioc_stat & MPI_IOCSTATUS_MASK) { - if ((int)ioc->chip_type <= (int)FC929) - ; - else - mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf); - } - } else { - /* - * Process turbo (context) reply... - */ - dirqprintk((MYIOC_s_INFO_FMT "Got TURBO reply(=%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 ((int)ioc->chip_type > (int)FC929) { - /* 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); - Q_ADD_TAIL(&ioc->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR); -#ifdef MFCNT - ioc->mfcnt--; -#endif - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - } - - mb(); - } /* drain reply FIFO */ + do { + if (pa & MPI_ADDRESS_REPLY_A_BIT) + mpt_reply(ioc, pa); + else + mpt_turbo_reply(ioc, pa); + pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); + } while (pa != 0xFFFFFFFF); return IRQ_HANDLED; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mpt_base_reply - MPT base driver's callback routine; all base driver - * "internal" request/reply processing is routed here. - * Currently used for EventNotification and EventAck handling. +/** + * mpt_base_reply - MPT base driver's callback routine * @ioc: Pointer to MPT_ADAPTER structure * @mf: Pointer to original MPT request frame * @reply: Pointer to MPT reply frame (NULL if TurboReply) * - * Returns 1 indicating original alloc'd request frame ptr + * MPT base driver's callback routine; all base driver + * "internal" request/reply processing is routed here. + * Currently used for EventNotification and EventAck handling. + * + * Returns 1 indicating original alloc'd request frame ptr * should be freed, or 0 if it shouldn't. */ static int @@ -518,28 +407,17 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) int freereq = 1; u8 func; - dprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name)); - - if ((mf == NULL) || - (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { - printk(MYIOC_s_ERR_FMT "NULL or BAD request frame ptr! (=%p)\n", - ioc->name, (void *)mf); - return 1; - } - - if (reply == NULL) { - dprintk((MYIOC_s_ERR_FMT "Unexpected NULL Event (turbo?) reply!\n", - ioc->name)); - return 1; - } + dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name)); +#if defined(MPT_DEBUG_MSG_FRAME) if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) { dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf)); DBG_DUMP_REQUEST_FRAME_HDR(mf) } +#endif func = reply->u.hdr.Function; - dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n", + dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n", ioc->name, func)); if (func == MPI_FUNCTION_EVENT_NOTIFICATION) { @@ -550,7 +428,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) results = ProcessEventNotification(ioc, pEvReply, &evHandlers); if (results != evHandlers) { /* CHECKME! Any special handling needed here? */ - dprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n", + devtverboseprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n", ioc->name, evHandlers, results)); } @@ -558,8 +436,12 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) * Hmmm... It seems that EventNotificationReply is an exception * to the rule of one reply per request. */ - if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) + if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) { freereq = 0; + } else { + devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n", + ioc->name, pEvReply)); + } #ifdef CONFIG_PROC_FS // LogEvent(ioc, pEvReply); @@ -568,8 +450,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) } else if (func == MPI_FUNCTION_EVENT_ACK) { dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n", ioc->name)); - } else if (func == MPI_FUNCTION_CONFIG || - func == MPI_FUNCTION_TOOLBOX) { + } else if (func == MPI_FUNCTION_CONFIG) { CONFIGPARMS *pCfg; unsigned long flags; @@ -583,7 +464,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) del_timer(&pCfg->timer); spin_lock_irqsave(&ioc->FreeQlock, flags); - Q_DEL_ITEM(&pCfg->linkage); + list_del(&pCfg->linkage); spin_unlock_irqrestore(&ioc->FreeQlock, flags); /* @@ -601,10 +482,21 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) pCfg->status = status; if (status == MPI_IOCSTATUS_SUCCESS) { - pCfg->hdr->PageVersion = pReply->Header.PageVersion; - pCfg->hdr->PageLength = pReply->Header.PageLength; - pCfg->hdr->PageNumber = pReply->Header.PageNumber; - pCfg->hdr->PageType = pReply->Header.PageType; + if ((pReply->Header.PageType & + MPI_CONFIG_PAGETYPE_MASK) == + MPI_CONFIG_PAGETYPE_EXTENDED) { + pCfg->cfghdr.ehdr->ExtPageLength = + le16_to_cpu(pReply->ExtPageLength); + pCfg->cfghdr.ehdr->ExtPageType = + pReply->ExtPageType; + } + pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion; + + /* If this is a regular header, save PageLength. */ + /* LMP Do this better so not using a reserved field! */ + pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength; + pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber; + pCfg->cfghdr.hdr->PageType = pReply->Header.PageType; } } @@ -614,6 +506,14 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) pCfg->wait_done = 1; wake_up(&mpt_waitq); } + } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) { + /* we should be always getting a reply frame */ + memcpy(ioc->persist_reply_frame, reply, + min(MPT_DEFAULT_FRAME_SIZE, + 4*reply->u.reply.MsgLength)); + del_timer(&ioc->persist_timer); + ioc->persist_wait_done = 1; + wake_up(&mpt_waitq); } else { printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n", ioc->name, func); @@ -633,7 +533,7 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value) * * This routine is called by a protocol-specific driver (SCSI host, - * LAN, SCSI target) to register it's reply callback routine. Each + * LAN, SCSI target) to register its reply callback routine. Each * protocol-specific driver must do this before it will be able to * use any IOC resources, such as obtaining request frames. * @@ -653,22 +553,6 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass) last_drv_idx = -1; -#ifndef MODULE - /* - * Handle possibility of the mptscsih_detect() routine getting - * called *before* fusion_init! - */ - if (!FusionInitCalled) { - dprintk((KERN_INFO MYNAM ": Hmmm, calling fusion_init from mpt_register!\n")); - /* - * NOTE! We'll get recursion here, as fusion_init() - * calls mpt_register()! - */ - fusion_init(); - FusionInitCalled++; - } -#endif - /* * Search for empty callback slot in this order: {N,...,7,6,5,...,1} * (slot/handle 0 is reserved!) @@ -691,7 +575,7 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass) * mpt_deregister - Deregister a protocol drivers resources. * @cb_idx: previously registered callback handle * - * Each protocol-specific driver should call this routine when it's + * Each protocol-specific driver should call this routine when its * module is unloaded. */ void @@ -703,8 +587,6 @@ mpt_deregister(int cb_idx) MptEvHandlers[cb_idx] = NULL; last_drv_idx++; - if (isense_idx != -1 && isense_idx <= cb_idx) - isense_idx++; } } @@ -738,7 +620,7 @@ mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc) * * Each protocol-specific driver should call this routine * when it does not (or can no longer) handle events, - * or when it's module is unloaded. + * or when its module is unloaded. */ void mpt_event_deregister(int cb_idx) @@ -777,7 +659,7 @@ mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func) * * Each protocol-specific driver should call this routine * when it does not (or can no longer) handle IOC reset handling, - * or when it's module is unloaded. + * or when its module is unloaded. */ void mpt_reset_deregister(int cb_idx) @@ -791,44 +673,52 @@ mpt_reset_deregister(int cb_idx) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_device_driver_register - Register device driver hooks + * @dd_cbfunc: driver callbacks struct + * @cb_idx: MPT protocol driver index */ int mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx) { MPT_ADAPTER *ioc; - int error=0; + const struct pci_device_id *id; - if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) { - error= -EINVAL; - return error; - } + if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) + return -EINVAL; MptDeviceDriverHandlers[cb_idx] = dd_cbfunc; /* call per pci device probe entry point */ - for(ioc = mpt_adapter_find_first(); ioc != NULL; - ioc = mpt_adapter_find_next(ioc)) { - if(dd_cbfunc->probe) { - error = dd_cbfunc->probe(ioc->pcidev, - ioc->pcidev->driver->id_table); - if(error != 0) - return error; - } + list_for_each_entry(ioc, &ioc_list, list) { + id = ioc->pcidev->driver ? + ioc->pcidev->driver->id_table : NULL; + if (dd_cbfunc->probe) + dd_cbfunc->probe(ioc->pcidev, id); } - return error; + return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_device_driver_deregister - DeRegister device driver hooks + * @cb_idx: MPT protocol driver index */ void mpt_device_driver_deregister(int cb_idx) { + struct mpt_pci_driver *dd_cbfunc; + MPT_ADAPTER *ioc; + if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) return; + dd_cbfunc = MptDeviceDriverHandlers[cb_idx]; + + list_for_each_entry(ioc, &ioc_list, list) { + if (dd_cbfunc->remove) + dd_cbfunc->remove(ioc->pcidev); + } + MptDeviceDriverHandlers[cb_idx] = NULL; } @@ -838,60 +728,62 @@ mpt_device_driver_deregister(int cb_idx) * mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024) * allocated per MPT adapter. * @handle: Handle of registered MPT protocol driver - * @iocid: IOC unique identifier (integer) + * @ioc: Pointer to MPT adapter structure * * Returns pointer to a MPT request frame or %NULL if none are available * or IOC is not active. */ MPT_FRAME_HDR* -mpt_get_msg_frame(int handle, int iocid) +mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc) { MPT_FRAME_HDR *mf; - MPT_ADAPTER *iocp; unsigned long flags; + u16 req_idx; /* Request index */ /* validate handle and ioc identifier */ - iocp = mpt_adapters[iocid]; #ifdef MFCNT - if (!iocp->active) + if (!ioc->active) printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n"); #endif /* If interrupts are not attached, do not return a request frame */ - if (!iocp->active) + if (!ioc->active) return NULL; - spin_lock_irqsave(&iocp->FreeQlock, flags); - if (! Q_IS_EMPTY(&iocp->FreeQ)) { + spin_lock_irqsave(&ioc->FreeQlock, flags); + if (!list_empty(&ioc->FreeQ)) { int req_offset; - mf = iocp->FreeQ.head; - Q_DEL_ITEM(&mf->u.frame.linkage); + mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR, + u.frame.linkage.list); + list_del(&mf->u.frame.linkage.list); + mf->u.frame.linkage.arg1 = 0; mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */ - req_offset = (u8 *)mf - (u8 *)iocp->req_frames; + req_offset = (u8 *)mf - (u8 *)ioc->req_frames; /* u16! */ - mf->u.frame.hwhdr.msgctxu.fld.req_idx = - cpu_to_le16(req_offset / iocp->req_sz); + req_idx = req_offset / ioc->req_sz; + mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; + ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */ #ifdef MFCNT - iocp->mfcnt++; + ioc->mfcnt++; #endif } else mf = NULL; - spin_unlock_irqrestore(&iocp->FreeQlock, flags); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); #ifdef MFCNT if (mf == NULL) - printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", iocp->mfcnt, iocp->req_depth); + printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth); mfcounter++; if (mfcounter == PRINT_MF_COUNT) - printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", iocp->mfcnt, iocp->req_depth); + printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth); #endif dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n", - iocp->name, handle, iocid, mf)); + ioc->name, handle, ioc->id, mf)); return mf; } @@ -900,83 +792,74 @@ mpt_get_msg_frame(int handle, int iocid) * mpt_put_msg_frame - Send a protocol specific MPT request frame * to a IOC. * @handle: Handle of registered MPT protocol driver - * @iocid: IOC unique identifier (integer) + * @ioc: Pointer to MPT adapter structure * @mf: Pointer to MPT request frame * * This routine posts a MPT request frame to the request post FIFO of a * specific MPT adapter. */ void -mpt_put_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf) +mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) { - MPT_ADAPTER *iocp; - - iocp = mpt_adapters[iocid]; - if (iocp != NULL) { - u32 mf_dma_addr; - int req_offset; + u32 mf_dma_addr; + int req_offset; + u16 req_idx; /* Request index */ - /* ensure values are reset properly! */ - mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */ - req_offset = (u8 *)mf - (u8 *)iocp->req_frames; - /* u16! */ - mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_offset / iocp->req_sz); - mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; + /* ensure values are reset properly! */ + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */ + req_offset = (u8 *)mf - (u8 *)ioc->req_frames; + /* u16! */ + req_idx = req_offset / ioc->req_sz; + mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); + mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; #ifdef MPT_DEBUG_MSG_FRAME - { - u32 *m = mf->u.frame.hwhdr.__hdr; - int ii, n; - - printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ", - iocp->name, m); - n = iocp->req_sz/4 - 1; - while (m[n] == 0) - n--; - for (ii=0; ii<=n; ii++) { - if (ii && ((ii%8)==0)) - printk("\n" KERN_INFO " "); - printk(" %08x", le32_to_cpu(m[ii])); - } - printk("\n"); + { + u32 *m = mf->u.frame.hwhdr.__hdr; + int ii, n; + + printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ", + ioc->name, m); + n = ioc->req_sz/4 - 1; + while (m[n] == 0) + n--; + for (ii=0; ii<=n; ii++) { + if (ii && ((ii%8)==0)) + printk("\n" KERN_INFO " "); + printk(" %08x", le32_to_cpu(m[ii])); } -#endif - - mf_dma_addr = iocp->req_frames_low_dma + req_offset; - CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr); - } else { - printk (KERN_ERR - "mpt_put_msg_frame: Invalid iocid=%d\n", iocid); + printk("\n"); } +#endif + mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx]; + dsgprintk((MYIOC_s_INFO_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx])); + CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_free_msg_frame - Place MPT request frame back on FreeQ. * @handle: Handle of registered MPT protocol driver - * @iocid: IOC unique identifier (integer) + * @ioc: Pointer to MPT adapter structure * @mf: Pointer to MPT request frame * * This routine places a MPT request frame back on the MPT adapter's * FreeQ. */ void -mpt_free_msg_frame(int handle, int iocid, MPT_FRAME_HDR *mf) +mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) { - MPT_ADAPTER *iocp; unsigned long flags; - iocp = mpt_adapters[iocid]; - if (iocp != NULL) { - /* Put Request back on FreeQ! */ - spin_lock_irqsave(&iocp->FreeQlock, flags); - Q_ADD_TAIL(&iocp->FreeQ, &mf->u.frame.linkage, MPT_FRAME_HDR); + /* Put Request back on FreeQ! */ + spin_lock_irqsave(&ioc->FreeQlock, flags); + mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */ + list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ); #ifdef MFCNT - iocp->mfcnt--; + ioc->mfcnt--; #endif - spin_unlock_irqrestore(&iocp->FreeQlock, flags); - } + spin_unlock_irqrestore(&ioc->FreeQlock, flags); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1010,45 +893,9 @@ mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_add_chain - Place a chain SGE at address pAddr. - * @pAddr: virtual address for SGE - * @next: nextChainOffset value (u32's) - * @length: length of next SGL segment - * @dma_addr: Physical address - * - * This routine places a MPT request frame back on the MPT adapter's - * FreeQ. - */ -void -mpt_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr) -{ - if (sizeof(dma_addr_t) == sizeof(u64)) { - SGEChain64_t *pChain = (SGEChain64_t *) pAddr; - u32 tmp = dma_addr & 0xFFFFFFFF; - - pChain->Length = cpu_to_le16(length); - pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); - - pChain->NextChainOffset = next; - - pChain->Address.Low = cpu_to_le32(tmp); - tmp = (u32) ((u64)dma_addr >> 32); - pChain->Address.High = cpu_to_le32(tmp); - } else { - SGEChain32_t *pChain = (SGEChain32_t *) pAddr; - pChain->Length = cpu_to_le16(length); - pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT | mpt_addr_size(); - pChain->NextChainOffset = next; - pChain->Address = cpu_to_le32(dma_addr); - } -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mpt_send_handshake_request - Send MPT request via doorbell - * handshake method. + * mpt_send_handshake_request - Send MPT request via doorbell handshake method. * @handle: Handle of registered MPT protocol driver - * @iocid: IOC unique identifier (integer) + * @ioc: Pointer to MPT adapter structure * @reqBytes: Size of the request in bytes * @req: Pointer to MPT request frame * @sleepFlag: Use schedule if CAN_SLEEP else use udelay. @@ -1062,157 +909,227 @@ mpt_add_chain(char *pAddr, u8 next, u16 length, dma_addr_t dma_addr) * Returns 0 for success, non-zero for failure. */ int -mpt_send_handshake_request(int handle, int iocid, int reqBytes, u32 *req, int sleepFlag) +mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag) { - MPT_ADAPTER *iocp; int r = 0; + u8 *req_as_bytes; + int ii; - iocp = mpt_adapters[iocid]; - if (iocp != NULL) { - u8 *req_as_bytes; - int ii; + /* State is known to be good upon entering + * this function so issue the bus reset + * request. + */ - /* State is known to be good upon entering - * this function so issue the bus reset - * request. - */ + /* + * Emulate what mpt_put_msg_frame() does /wrt to sanity + * setting cb_idx/req_idx. But ONLY if this request + * is in proper (pre-alloc'd) request buffer range... + */ + ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req); + if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) { + MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req; + mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii); + mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; + } - /* - * Emulate what mpt_put_msg_frame() does /wrt to sanity - * setting cb_idx/req_idx. But ONLY if this request - * is in proper (pre-alloc'd) request buffer range... - */ - ii = MFPTR_2_MPT_INDEX(iocp,(MPT_FRAME_HDR*)req); - if (reqBytes >= 12 && ii >= 0 && ii < iocp->req_depth) { - MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req; - mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii); - mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; - } + /* Make sure there are no doorbells */ + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - /* Make sure there are no doorbells */ - CHIPREG_WRITE32(&iocp->chip->IntStatus, 0); + CHIPREG_WRITE32(&ioc->chip->Doorbell, + ((MPI_FUNCTION_HANDSHAKE<chip->Doorbell, - ((MPI_FUNCTION_HANDSHAKE<chip->Doorbell) & MPI_DOORBELL_ACTIVE)) + return -5; - /* Read doorbell and check for active bit */ - if (!(CHIPREG_READ32(&iocp->chip->Doorbell) & MPI_DOORBELL_ACTIVE)) - return -5; + dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n", + ioc->name, ii)); - dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n", - iocp->name, ii)); + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - CHIPREG_WRITE32(&iocp->chip->IntStatus, 0); + if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { + return -2; + } - if ((r = WaitForDoorbellAck(iocp, 5, sleepFlag)) < 0) { - return -2; - } + /* Send request via doorbell handshake */ + req_as_bytes = (u8 *) req; + for (ii = 0; ii < reqBytes/4; ii++) { + u32 word; - /* Send request via doorbell handshake */ - req_as_bytes = (u8 *) req; - for (ii = 0; ii < reqBytes/4; ii++) { - u32 word; - - word = ((req_as_bytes[(ii*4) + 0] << 0) | - (req_as_bytes[(ii*4) + 1] << 8) | - (req_as_bytes[(ii*4) + 2] << 16) | - (req_as_bytes[(ii*4) + 3] << 24)); - CHIPREG_WRITE32(&iocp->chip->Doorbell, word); - if ((r = WaitForDoorbellAck(iocp, 5, sleepFlag)) < 0) { - r = -3; - break; - } + word = ((req_as_bytes[(ii*4) + 0] << 0) | + (req_as_bytes[(ii*4) + 1] << 8) | + (req_as_bytes[(ii*4) + 2] << 16) | + (req_as_bytes[(ii*4) + 3] << 24)); + CHIPREG_WRITE32(&ioc->chip->Doorbell, word); + if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { + r = -3; + break; } + } - if (r >= 0 && WaitForDoorbellInt(iocp, 10, sleepFlag) >= 0) - r = 0; - else - r = -4; + if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0) + r = 0; + else + r = -4; - /* Make sure there are no doorbells */ - CHIPREG_WRITE32(&iocp->chip->IntStatus, 0); - } + /* Make sure there are no doorbells */ + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); return r; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_adapter_find_first - Find first MPT adapter pointer. + * mpt_host_page_access_control - control the IOC's Host Page Buffer access + * @ioc: Pointer to MPT adapter structure + * @access_control_value: define bits below + * @sleepFlag: Specifies whether the process can sleep + * + * Provides mechanism for the host driver to control the IOC's + * Host Page Buffer access. + * + * Access Control Value - bits[15:12] + * 0h Reserved + * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS } + * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS } + * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER } * - * Returns first MPT adapter pointer or %NULL if no MPT adapters - * are present. + * Returns 0 for success, non-zero for failure. */ -MPT_ADAPTER * -mpt_adapter_find_first(void) + +static int +mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag) { - MPT_ADAPTER *this; + int r = 0; - if (! Q_IS_EMPTY(&MptAdapters)) - this = MptAdapters.head; - else - this = NULL; + /* return if in use */ + if (CHIPREG_READ32(&ioc->chip->Doorbell) + & MPI_DOORBELL_ACTIVE) + return -1; - return this; -} + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + + CHIPREG_WRITE32(&ioc->chip->Doorbell, + ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL + <forw != (MPT_ADAPTER*)&MptAdapters.head)) - next = prev->forw; - else - next = NULL; + if(!ioc->HostPageBuffer) { - return next; -} + host_page_buffer_sz = + le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF; + + if(!host_page_buffer_sz) + return 0; /* fw doesn't need any host buffers */ + + /* spin till we get enough memory */ + while(host_page_buffer_sz > 0) { + + if((ioc->HostPageBuffer = pci_alloc_consistent( + ioc->pcidev, + host_page_buffer_sz, + &ioc->HostPageBuffer_dma)) != NULL) { + + dinitprintk((MYIOC_s_INFO_FMT + "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n", + ioc->name, ioc->HostPageBuffer, + (u32)ioc->HostPageBuffer_dma, + host_page_buffer_sz)); + ioc->alloc_total += host_page_buffer_sz; + ioc->HostPageBuffer_sz = host_page_buffer_sz; + break; + } + + host_page_buffer_sz -= (4*1024); + } + } + + if(!ioc->HostPageBuffer) { + printk(MYIOC_s_ERR_FMT + "Failed to alloc memory for host_page_buffer!\n", + ioc->name); + return -999; + } + + psge = (char *)&ioc_init->HostPageBufferSGE; + flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_SYSTEM_ADDRESS | + MPI_SGE_FLAGS_32_BIT_ADDRESSING | + MPI_SGE_FLAGS_HOST_TO_IOC | + MPI_SGE_FLAGS_END_OF_BUFFER; + if (sizeof(dma_addr_t) == sizeof(u64)) { + flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING; + } + flags_length = flags_length << MPI_SGE_FLAGS_SHIFT; + flags_length |= ioc->HostPageBuffer_sz; + mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma); + ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE; +return 0; +} /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_verify_adapter - Given a unique IOC identifier, set pointer to - * the associated MPT adapter structure. + * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure. * @iocid: IOC unique identifier (integer) * @iocpp: Pointer to pointer to IOC adapter * - * Returns iocid and sets iocpp. + * Given a unique IOC identifier, set pointer to the associated MPT + * adapter structure. + * + * Returns iocid and sets iocpp if iocid is found. + * Returns -1 if iocid is not found. */ int mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp) { - MPT_ADAPTER *p; - - *iocpp = NULL; - if (iocid >= MPT_MAX_ADAPTERS) - return -1; + MPT_ADAPTER *ioc; - p = mpt_adapters[iocid]; - if (p == NULL) - return -1; + list_for_each_entry(ioc,&ioc_list,list) { + if (ioc->id == iocid) { + *iocpp =ioc; + return iocid; + } + } - *iocpp = p; - return iocid; + *iocpp = NULL; + return -1; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mptbase_probe - Install a PCI intelligent MPT adapter. +/** + * mpt_attach - Install a PCI intelligent MPT adapter. * @pdev: Pointer to pci_dev structure + * @id: PCI device ID information * * This routine performs all the steps necessary to bring the IOC of * a MPT adapter to a OPERATIONAL state. This includes registering @@ -1226,53 +1143,57 @@ mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp) * * TODO: Add support for polled controllers */ -static int __devinit -mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id) +int +mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) { MPT_ADAPTER *ioc; - u8 *mem; + u8 __iomem *mem; unsigned long mem_phys; unsigned long port; u32 msize; u32 psize; int ii; int r = -ENODEV; - u64 mask = 0xffffffffffffffffULL; u8 revision; u8 pcixcmd; + static int mpt_ids = 0; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *dent, *ent; +#endif if (pci_enable_device(pdev)) return r; - - if (!pci_set_dma_mask(pdev, mask)) { + + dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n")); + + if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { dprintk((KERN_INFO MYNAM ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n")); - } else if (pci_set_dma_mask(pdev, (u64) 0xffffffff)) { + } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n"); return r; } - if (!pci_set_consistent_dma_mask(pdev, mask)) + if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) dprintk((KERN_INFO MYNAM ": Using 64 bit consistent mask\n")); else dprintk((KERN_INFO MYNAM ": Not using 64 bit consistent mask\n")); - ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC); + ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC); if (ioc == NULL) { printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n"); return -ENOMEM; } - memset(ioc, 0, sizeof(MPT_ADAPTER)); ioc->alloc_total = sizeof(MPT_ADAPTER); ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */ ioc->reply_sz = MPT_REPLY_FRAME_SIZE; ioc->pcidev = pdev; - ioc->diagPending = 0; spin_lock_init(&ioc->diagLock); + spin_lock_init(&ioc->initializing_hba_lock); /* Initialize the event logging. */ @@ -1289,91 +1210,79 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* Initilize SCSI Config Data structure */ - memset(&ioc->spi_data, 0, sizeof(ScsiCfgData)); + memset(&ioc->spi_data, 0, sizeof(SpiCfgData)); /* Initialize the running configQ head. */ - Q_INIT(&ioc->configQ, Q_ITEM); + INIT_LIST_HEAD(&ioc->configQ); + + /* Initialize the fc rport list head. + */ + INIT_LIST_HEAD(&ioc->fc_rports); /* Find lookup slot. */ - for (ii=0; ii < MPT_MAX_ADAPTERS; ii++) { - if (mpt_adapters[ii] == NULL) { - ioc->id = ii; /* Assign adapter unique id (lookup) */ - break; - } - } - if (ii == MPT_MAX_ADAPTERS) { - printk(KERN_ERR MYNAM ": ERROR - mpt_adapters[%d] table overflow!\n", ii); - kfree(ioc); - return -ENFILE; - } + INIT_LIST_HEAD(&ioc->list); + ioc->id = mpt_ids++; mem_phys = msize = 0; port = psize = 0; for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) { - if (pdev->PCI_BASEADDR_FLAGS(ii) & PCI_BASE_ADDRESS_SPACE_IO) { + if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) { + if (psize) + continue; /* Get I/O space! */ - port = pdev->PCI_BASEADDR_START(ii); - psize = PCI_BASEADDR_SIZE(pdev,ii); + port = pci_resource_start(pdev, ii); + psize = pci_resource_len(pdev,ii); } else { + if (msize) + continue; /* Get memmap */ - mem_phys = pdev->PCI_BASEADDR_START(ii); - msize = PCI_BASEADDR_SIZE(pdev,ii); - break; + mem_phys = pci_resource_start(pdev, ii); + msize = pci_resource_len(pdev,ii); } } ioc->mem_size = msize; - if (ii == DEVICE_COUNT_RESOURCE) { - printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n"); - kfree(ioc); - return -EINVAL; - } - - dprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize)); - dprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize)); - mem = NULL; /* Get logical ptr for PciMem0 space */ /*mem = ioremap(mem_phys, msize);*/ - mem = ioremap(mem_phys, 0x100); + mem = ioremap(mem_phys, msize); if (mem == NULL) { printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n"); kfree(ioc); return -EINVAL; } ioc->memmap = mem; - dprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys)); + dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys)); - dprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n", + dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n", &ioc->facts, &ioc->pfacts[0])); ioc->mem_phys = mem_phys; - ioc->chip = (SYSIF_REGS*)mem; + ioc->chip = (SYSIF_REGS __iomem *)mem; - /* Save Port IO values incase we need to do downloadboot */ + /* Save Port IO values in case we need to do downloadboot */ { u8 *pmem = (u8*)port; ioc->pio_mem_phys = port; - ioc->pio_chip = (SYSIF_REGS*)pmem; + ioc->pio_chip = (SYSIF_REGS __iomem *)pmem; } - ioc->chip_type = FCUNK; if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) { - ioc->chip_type = FC909; ioc->prod_name = "LSIFC909"; + ioc->bus_type = FC; } - if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) { - ioc->chip_type = FC929; + else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) { ioc->prod_name = "LSIFC929"; + ioc->bus_type = FC; } else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) { - ioc->chip_type = FC919; ioc->prod_name = "LSIFC919"; + ioc->bus_type = FC; } else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) { - ioc->chip_type = FC929X; pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + ioc->bus_type = FC; if (revision < XL_929) { ioc->prod_name = "LSIFC929X"; /* 929X Chip Fix. Set Split transactions level @@ -1392,8 +1301,8 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id) } } else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) { - ioc->chip_type = FC919X; ioc->prod_name = "LSIFC919X"; + ioc->bus_type = FC; /* 919X Chip Fix. Set Split transactions level * for PCIX. Set MOST bits to zero. */ @@ -1401,9 +1310,23 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id) pcixcmd &= 0x8F; pci_write_config_byte(pdev, 0x6a, pcixcmd); } + else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) { + ioc->prod_name = "LSIFC939X"; + ioc->bus_type = FC; + ioc->errata_flag_1064 = 1; + } + else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) { + ioc->prod_name = "LSIFC949X"; + ioc->bus_type = FC; + ioc->errata_flag_1064 = 1; + } + else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) { + ioc->prod_name = "LSIFC949E"; + ioc->bus_type = FC; + } else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) { - ioc->chip_type = C1030; ioc->prod_name = "LSI53C1030"; + ioc->bus_type = SPI; /* 1030 Chip Fix. Disable Split transactions * for PCIX. Set MOST bits to zero if Rev < C0( = 8). */ @@ -1415,13 +1338,37 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id) } } else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) { - ioc->chip_type = C1035; ioc->prod_name = "LSI53C1035"; + ioc->bus_type = SPI; + } + else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) { + ioc->prod_name = "LSISAS1064"; + ioc->bus_type = SAS; + ioc->errata_flag_1064 = 1; + } + else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) { + ioc->prod_name = "LSISAS1068"; + ioc->bus_type = SAS; + ioc->errata_flag_1064 = 1; } + else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) { + ioc->prod_name = "LSISAS1064E"; + ioc->bus_type = SAS; + } + else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) { + ioc->prod_name = "LSISAS1068E"; + ioc->bus_type = SAS; + } + else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) { + ioc->prod_name = "LSISAS1078"; + ioc->bus_type = SAS; + } + + if (ioc->errata_flag_1064) + pci_disable_io_access(pdev); sprintf(ioc->name, "ioc%d", ioc->id); - Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR); spin_lock_init(&ioc->FreeQlock); /* Disable all! */ @@ -1429,59 +1376,22 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->active = 0; CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - /* tack onto tail of our MPT adapter list */ - Q_ADD_TAIL(&MptAdapters, ioc, MPT_ADAPTER); - /* Set lookup ptr. */ - mpt_adapters[ioc->id] = ioc; - - ioc->pci_irq = -1; - if (pdev->irq) { - r = request_irq(pdev->irq, mpt_interrupt, SA_SHIRQ, ioc->name, ioc); - - if (r < 0) { -#ifndef __sparc__ - printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %d!\n", - ioc->name, pdev->irq); -#else - printk(MYIOC_s_ERR_FMT "Unable to allocate interrupt %s!\n", - ioc->name, __irq_itoa(pdev->irq)); -#endif - Q_DEL_ITEM(ioc); - mpt_adapters[ioc->id] = NULL; - iounmap(mem); - kfree(ioc); - return -EBUSY; - } - - ioc->pci_irq = pdev->irq; + list_add_tail(&ioc->list, &ioc_list); - pci_set_master(pdev); /* ?? */ - pci_set_drvdata(pdev, ioc); - -#ifndef __sparc__ - dprintk((KERN_INFO MYNAM ": %s installed at interrupt %d\n", ioc->name, pdev->irq)); -#else - dprintk((KERN_INFO MYNAM ": %s installed at interrupt %s\n", ioc->name, __irq_itoa(pdev->irq))); -#endif - } - - /* NEW! 20010220 -sralston - * Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets. + /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets. */ - if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030) - || (ioc->chip_type == C1035) || (ioc->chip_type == FC929X)) - mpt_detect_bound_ports(ioc, pdev); + mpt_detect_bound_ports(ioc, pdev); - if ((r = mpt_do_ioc_recovery(ioc, - MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) { + if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, + CAN_SLEEP)) != 0){ printk(KERN_WARNING MYNAM ": WARNING - %s did not initialize properly! (%d)\n", ioc->name, r); - Q_DEL_ITEM(ioc); - mpt_adapters[ioc->id] = NULL; - free_irq(ioc->pci_irq, ioc); + list_del(&ioc->list); + if (ioc->alt_ioc) + ioc->alt_ioc->alt_ioc = NULL; iounmap(mem); kfree(ioc); pci_set_drvdata(pdev, NULL); @@ -1496,22 +1406,48 @@ mptbase_probe(struct pci_dev *pdev, const struct pci_device_id *id) } } +#ifdef CONFIG_PROC_FS + /* + * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter. + */ + dent = proc_mkdir(ioc->name, mpt_proc_root_dir); + if (dent) { + ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent); + if (ent) { + ent->read_proc = procmpt_iocinfo_read; + ent->data = ioc; + } + ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent); + if (ent) { + ent->read_proc = procmpt_summary_read; + ent->data = ioc; + } + } +#endif + return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mptbase_remove - Remove a PCI intelligent MPT adapter. +/** + * mpt_detach - Remove a PCI intelligent MPT adapter. * @pdev: Pointer to pci_dev structure - * */ -static void __devexit -mptbase_remove(struct pci_dev *pdev) +void +mpt_detach(struct pci_dev *pdev) { MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + char pname[32]; int ii; + sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name); + remove_proc_entry(pname, NULL); + sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name); + remove_proc_entry(pname, NULL); + sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name); + remove_proc_entry(pname, NULL); + /* call per device driver remove entry point */ for(ii=0; iichip->IntMask, 0xFFFFFFFF); ioc->active = 0; - mpt_sync_irq(pdev->irq); + synchronize_irq(pdev->irq); /* Clear any lingering interrupt */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); CHIPREG_READ32(&ioc->chip->IntStatus); - Q_DEL_ITEM(ioc); mpt_adapter_dispose(ioc); pci_set_drvdata(pdev, NULL); } -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mptbase_shutdown - - * - */ -static void -mptbase_shutdown(struct device * dev) -{ - int ii; - - /* call per device driver shutdown entry point */ - for(ii=0; iishutdown) { - MptDeviceDriverHandlers[ii]->shutdown(dev); - } - } - -} - - /************************************************************************** * Power Management */ #ifdef CONFIG_PM /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mptbase_suspend - Fusion MPT base driver suspend routine. - * - * +/** + * mpt_suspend - Fusion MPT base driver suspend routine. + * @pdev: Pointer to pci_dev structure + * @state: new state to enter */ -static int -mptbase_suspend(struct pci_dev *pdev, u32 state) +int +mpt_suspend(struct pci_dev *pdev, pm_message_t state) { u32 device_state; MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - int ii; - switch(state) - { - case 1: /* S1 */ - device_state=1; /* D1 */; - break; - case 3: /* S3 */ - case 4: /* S4 */ - device_state=3; /* D3 */; - break; - default: - return -EAGAIN /*FIXME*/; - break; - } + device_state=pci_choose_state(pdev, state); printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n", ioc->name, pdev, pci_name(pdev), device_state); - /* call per device driver suspend entry point */ - for(ii=0; iisuspend) { - MptDeviceDriverHandlers[ii]->suspend(pdev, state); - } - } - - pci_save_state(pdev, ioc->PciState); + pci_save_state(pdev); /* put ioc into READY_STATE */ if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) { @@ -1623,39 +1516,29 @@ mptbase_suspend(struct pci_dev *pdev, u32 state) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mptbase_resume - Fusion MPT base driver resume routine. - * - * +/** + * mpt_resume - Fusion MPT base driver resume routine. + * @pdev: Pointer to pci_dev structure */ -static int -mptbase_resume(struct pci_dev *pdev) +int +mpt_resume(struct pci_dev *pdev) { MPT_ADAPTER *ioc = pci_get_drvdata(pdev); u32 device_state = pdev->current_state; int recovery_state; - int ii; printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n", ioc->name, pdev, pci_name(pdev), device_state); pci_set_power_state(pdev, 0); - pci_restore_state(pdev, ioc->PciState); + pci_restore_state(pdev); pci_enable_device(pdev); /* enable interrupts */ - CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM)); + CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); ioc->active = 1; - /* F/W not running */ - if(!CHIPREG_READ32(&ioc->chip->Doorbell)) { - /* enable domain validation flags */ - for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { - ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_NEED_DV; - } - } - printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n", ioc->name, @@ -1673,20 +1556,27 @@ mptbase_resume(struct pci_dev *pdev) "pci-resume: success\n", ioc->name); } - /* call per device driver resume entry point */ - for(ii=0; iiresume) { - MptDeviceDriverHandlers[ii]->resume(pdev); - } - } - return 0; } #endif +static int +mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase) +{ + if ((MptDriverClass[index] == MPTSPI_DRIVER && + ioc->bus_type != SPI) || + (MptDriverClass[index] == MPTFC_DRIVER && + ioc->bus_type != FC) || + (MptDriverClass[index] == MPTSAS_DRIVER && + ioc->bus_type != SAS)) + /* make sure we only call the relevant reset handler + * for the bus */ + return 0; + return (MptResetHandlers[index])(ioc, reset_phase); +} + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_do_ioc_recovery - Initialize or recover MPT adapter. * @ioc: Pointer to MPT adapter structure * @reason: Event word / reason @@ -1711,11 +1601,12 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) int hard_reset_done = 0; int alt_ioc_ready = 0; int hard; - int r; + int rc=0; int ii; int handlers; int ret = 0; int reset_alt_ioc_active = 0; + int irq_allocated = 0; printk(KERN_INFO MYNAM ": Initiating %s %s\n", ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery"); @@ -1746,7 +1637,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */ dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n", ioc->alt_ioc->name)); - CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM)); + CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); ioc->alt_ioc->active = 1; } @@ -1761,31 +1652,37 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) * and 1 if a hard reset was performed. */ if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) { - if ((r = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) + if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) alt_ioc_ready = 1; else printk(KERN_WARNING MYNAM - ": alt-%s: (%d) Not ready WARNING!\n", - ioc->alt_ioc->name, r); + ": alt-%s: Not ready WARNING!\n", + ioc->alt_ioc->name); + } + + for (ii=0; ii<5; ii++) { + /* Get IOC facts! Allow 5 retries */ + if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0) + break; } - /* Get IOC facts! Allow 1 retry */ - if ((r = GetIocFacts(ioc, sleepFlag, reason)) != 0) - r = GetIocFacts(ioc, sleepFlag, reason); - if (r) { + if (ii == 5) { + dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc)); ret = -2; } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { MptDisplayIocCapabilities(ioc); } if (alt_ioc_ready) { - if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { + if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { + dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc)); /* Retry - alt IOC was initialized once */ - r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason); + rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason); } - if (r) { + if (rc) { + dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc)); alt_ioc_ready = 0; reset_alt_ioc_active = 0; } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { @@ -1793,34 +1690,64 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) } } + /* + * Device is reset now. It must have de-asserted the interrupt line + * (if it was asserted) and it should be safe to register for the + * interrupt now. + */ + if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { + ioc->pci_irq = -1; + if (ioc->pcidev->irq) { + if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev)) + printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n", + ioc->name); + rc = request_irq(ioc->pcidev->irq, mpt_interrupt, + IRQF_SHARED, ioc->name, ioc); + if (rc < 0) { + printk(MYIOC_s_ERR_FMT "Unable to allocate " + "interrupt %d!\n", ioc->name, + ioc->pcidev->irq); + if (mpt_msi_enable) + pci_disable_msi(ioc->pcidev); + return -EBUSY; + } + irq_allocated = 1; + ioc->pci_irq = ioc->pcidev->irq; + pci_set_master(ioc->pcidev); /* ?? */ + pci_set_drvdata(ioc->pcidev, ioc); + dprintk((KERN_INFO MYNAM ": %s installed at interrupt " + "%d\n", ioc->name, ioc->pcidev->irq)); + } + } + /* Prime reply & request queues! * (mucho alloc's) Must be done prior to * init as upper addresses are needed for init. * If fails, continue with alt-ioc processing */ - if ((ret == 0) && ((r = PrimeIocFifos(ioc)) != 0)) + if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0)) ret = -3; /* May need to check/upload firmware & data here! * If fails, continue with alt-ioc processing */ - if ((ret == 0) && ((r = SendIocInit(ioc, sleepFlag)) != 0)) + if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0)) ret = -4; // NEW! - if (alt_ioc_ready && ((r = PrimeIocFifos(ioc->alt_ioc)) != 0)) { + if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) { printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n", - ioc->alt_ioc->name, r); + ioc->alt_ioc->name, rc); alt_ioc_ready = 0; reset_alt_ioc_active = 0; } if (alt_ioc_ready) { - if ((r = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { + if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { alt_ioc_ready = 0; reset_alt_ioc_active = 0; printk(KERN_WARNING MYNAM ": alt-%s: (%d) init failure WARNING!\n", - ioc->alt_ioc->name, r); + ioc->alt_ioc->name, rc); } } @@ -1832,39 +1759,43 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) /* Controller is not operational, cannot do upload */ if (ret == 0) { - r = mpt_do_upload(ioc, sleepFlag); - if (r != 0) - printk(KERN_WARNING MYNAM ": firmware upload failure!\n"); - } - - /* Handle the alt IOC too */ - if ((alt_ioc_ready) && (ioc->alt_ioc->upload_fw)){ - ddlprintk((MYIOC_s_INFO_FMT - "Alt-ioc firmware upload required!\n", - ioc->name)); - r = mpt_do_upload(ioc->alt_ioc, sleepFlag); - if (r != 0) + rc = mpt_do_upload(ioc, sleepFlag); + if (rc == 0) { + if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) { + /* + * Maintain only one pointer to FW memory + * so there will not be two attempt to + * downloadboot onboard dual function + * chips (mpt_adapter_disable, + * mpt_diag_reset) + */ + ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n", + ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw)); + ioc->alt_ioc->cached_fw = NULL; + } + } else { printk(KERN_WARNING MYNAM ": firmware upload failure!\n"); + ret = -5; + } } } } if (ret == 0) { /* Enable! (reply interrupt) */ - CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM)); + CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); ioc->active = 1; } if (reset_alt_ioc_active && ioc->alt_ioc) { /* (re)Enable alt-IOC! (reply interrupt) */ - dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n", + dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n", ioc->alt_ioc->name)); - CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM)); + CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); ioc->alt_ioc->active = 1; } - /* NEW! 20010120 -sralston - * Enable MPT base driver management of EventNotification + /* Enable MPT base driver management of EventNotification * and EventAck handling. */ if ((ret == 0) && (!ioc->facts.EventState)) @@ -1873,24 +1804,29 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */ - /* (Bugzilla:fibrebugs, #513) - * Bug fix (part 2)! 20010905 -sralston - * Add additional "reason" check before call to GetLanConfigPages + /* Add additional "reason" check before call to GetLanConfigPages * (combined with GetIoUnitPage2 call). This prevents a somewhat * recursive scenario; GetLanConfigPages times out, timer expired * routine calls HardResetHandler, which calls into here again, * and we try GetLanConfigPages again... */ if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { - if ((int)ioc->chip_type <= (int)FC929) { - /* - * Pre-fetch FC port WWN and stuff... - * (FCPortPage0_t stuff) - */ - for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { - (void) GetFcPortPage0(ioc, ii); + if (ioc->bus_type == SAS) { + + /* clear persistency table */ + if(ioc->facts.IOCExceptions & + MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) { + ret = mptbase_sas_persist_operation(ioc, + MPI_SAS_OP_CLEAR_NOT_PRESENT); + if(ret != 0) + goto out; } + /* Find IM volumes + */ + mpt_findImVolumes(ioc); + + } else if (ioc->bus_type == FC) { if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) && (ioc->lan_cnfg_page0.Header.PageLength == 0)) { /* @@ -1917,7 +1853,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) /* Find IM volumes */ - if (ioc->facts.MsgVersion >= 0x0102) + if (ioc->facts.MsgVersion >= MPI_VERSION_01_02) mpt_findImVolumes(ioc); /* Check, and possibly reset, the coalescing value @@ -1937,234 +1873,245 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) * MptResetHandlers[] registered yet. */ if (hard_reset_done) { - r = handlers = 0; + rc = handlers = 0; for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { if ((ret == 0) && MptResetHandlers[ii]) { dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n", ioc->name, ii)); - r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET); + rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET); handlers++; } if (alt_ioc_ready && MptResetHandlers[ii]) { - dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n", + drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n", ioc->name, ioc->alt_ioc->name, ii)); - r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET); + rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET); handlers++; } } /* FIXME? Examine results here? */ } + out: + if ((ret != 0) && irq_allocated) { + free_irq(ioc->pci_irq, ioc); + if (mpt_msi_enable) + pci_disable_msi(ioc->pcidev); + } return ret; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mpt_detect_bound_ports - Search for PCI bus/dev_function - * which matches PCI bus/dev_function (+/-1) for newly discovered 929, - * 929X, 1030 or 1035. +/** + * mpt_detect_bound_ports - Search for matching PCI bus/dev_function * @ioc: Pointer to MPT adapter structure * @pdev: Pointer to (struct pci_dev) structure * + * Search for PCI bus/dev_function which matches + * PCI bus/dev_function (+/-1) for newly discovered 929, + * 929X, 1030 or 1035. + * * If match on PCI dev_function +/-1 is found, bind the two MPT adapters * using alt_ioc pointer fields in their %MPT_ADAPTER structures. */ static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) { - MPT_ADAPTER *ioc_srch = mpt_adapter_find_first(); - unsigned int match_lo, match_hi; - - match_lo = pdev->devfn-1; - match_hi = pdev->devfn+1; - dprintk((MYIOC_s_INFO_FMT "PCI bus/devfn=%x/%x, searching for devfn match on %x or %x\n", - ioc->name, pdev->bus->number, pdev->devfn, match_lo, match_hi)); + struct pci_dev *peer=NULL; + unsigned int slot = PCI_SLOT(pdev->devfn); + unsigned int func = PCI_FUNC(pdev->devfn); + MPT_ADAPTER *ioc_srch; + + dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x," + " searching for devfn match on %x or %x\n", + ioc->name, pci_name(pdev), pdev->bus->number, + pdev->devfn, func-1, func+1)); + + peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1)); + if (!peer) { + peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1)); + if (!peer) + return; + } - while (ioc_srch != NULL) { + list_for_each_entry(ioc_srch, &ioc_list, list) { struct pci_dev *_pcidev = ioc_srch->pcidev; - - if ((_pcidev->device == pdev->device) && - (_pcidev->bus->number == pdev->bus->number) && - (_pcidev->devfn == match_lo || _pcidev->devfn == match_hi) ) { + if (_pcidev == peer) { /* Paranoia checks */ if (ioc->alt_ioc != NULL) { printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n", - ioc->name, ioc->alt_ioc->name); + ioc->name, ioc->alt_ioc->name); break; } else if (ioc_srch->alt_ioc != NULL) { printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n", - ioc_srch->name, ioc_srch->alt_ioc->name); + ioc_srch->name, ioc_srch->alt_ioc->name); break; } dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n", - ioc->name, ioc_srch->name)); + ioc->name, ioc_srch->name)); ioc_srch->alt_ioc = ioc; ioc->alt_ioc = ioc_srch; - break; } - ioc_srch = mpt_adapter_find_next(ioc_srch); } + pci_dev_put(peer); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_adapter_disable - Disable misbehaving MPT adapter. - * @this: Pointer to MPT adapter structure - * @free: Free up alloc'd reply, request, etc. + * @ioc: Pointer to MPT adapter structure */ static void -mpt_adapter_disable(MPT_ADAPTER *this, int freeup) +mpt_adapter_disable(MPT_ADAPTER *ioc) { - if (this != NULL) { - int sz=0; - u32 state; - int ret; - - /* Disable the FW */ - state = mpt_GetIocState(this, 1); - if (state == MPI_IOC_STATE_OPERATIONAL) { - SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, NO_SLEEP); - } - - if (this->cached_fw != NULL) { - ddlprintk((KERN_INFO MYNAM ": Pushing FW onto adapter\n")); + int sz; + int ret; - if ((ret = mpt_downloadboot(this, NO_SLEEP)) < 0) { - printk(KERN_WARNING MYNAM - ": firmware downloadboot failure (%d)!\n", ret); - } + if (ioc->cached_fw != NULL) { + ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n")); + if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) { + printk(KERN_WARNING MYNAM + ": firmware downloadboot failure (%d)!\n", ret); } + } - /* Disable adapter interrupts! */ - CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF); - this->active = 0; - /* Clear any lingering interrupt */ - CHIPREG_WRITE32(&this->chip->IntStatus, 0); - - if (freeup && this->fifo_pool != NULL) { - pci_free_consistent(this->pcidev, - this->fifo_pool_sz, - this->fifo_pool, this->fifo_pool_dma); - this->reply_frames = NULL; - this->reply_alloc = NULL; - this->req_frames = NULL; - this->req_alloc = NULL; - this->chain_alloc = NULL; - this->fifo_pool = NULL; - this->alloc_total -= this->fifo_pool_sz; - } - if (freeup && this->sense_buf_pool != NULL) { - sz = (this->req_depth * MPT_SENSE_BUFFER_ALLOC); - pci_free_consistent(this->pcidev, sz, - this->sense_buf_pool, this->sense_buf_pool_dma); - this->sense_buf_pool = NULL; - this->alloc_total -= sz; - } + /* Disable adapter interrupts! */ + CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); + ioc->active = 0; + /* Clear any lingering interrupt */ + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - if (freeup && this->events != NULL){ - sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS); - kfree(this->events); - this->events = NULL; - this->alloc_total -= sz; - } + if (ioc->alloc != NULL) { + sz = ioc->alloc_sz; + dexitprintk((KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n", + ioc->name, ioc->alloc, ioc->alloc_sz)); + pci_free_consistent(ioc->pcidev, sz, + ioc->alloc, ioc->alloc_dma); + ioc->reply_frames = NULL; + ioc->req_frames = NULL; + ioc->alloc = NULL; + ioc->alloc_total -= sz; + } - if (freeup && this->cached_fw != NULL) { - int ii = 0; + if (ioc->sense_buf_pool != NULL) { + sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); + pci_free_consistent(ioc->pcidev, sz, + ioc->sense_buf_pool, ioc->sense_buf_pool_dma); + ioc->sense_buf_pool = NULL; + ioc->alloc_total -= sz; + } - while ((ii < this->num_fw_frags) && (this->cached_fw[ii]!= NULL)) { - sz = this->cached_fw[ii]->size; - pci_free_consistent(this->pcidev, sz, - this->cached_fw[ii]->fw, this->cached_fw[ii]->fw_dma); - this->cached_fw[ii]->fw = NULL; - this->alloc_total -= sz; + if (ioc->events != NULL){ + sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS); + kfree(ioc->events); + ioc->events = NULL; + ioc->alloc_total -= sz; + } - kfree(this->cached_fw[ii]); - this->cached_fw[ii] = NULL; - this->alloc_total -= sizeof(fw_image_t); + if (ioc->cached_fw != NULL) { + sz = ioc->facts.FWImageSize; + pci_free_consistent(ioc->pcidev, sz, + ioc->cached_fw, ioc->cached_fw_dma); + ioc->cached_fw = NULL; + ioc->alloc_total -= sz; + } - ii++; - } + kfree(ioc->spi_data.nvram); + kfree(ioc->raid_data.pIocPg3); + ioc->spi_data.nvram = NULL; + ioc->raid_data.pIocPg3 = NULL; - kfree(this->cached_fw); - this->cached_fw = NULL; - sz = this->num_fw_frags * sizeof(void *); - this->alloc_total -= sz; - } + if (ioc->spi_data.pIocPg4 != NULL) { + sz = ioc->spi_data.IocPg4Sz; + pci_free_consistent(ioc->pcidev, sz, + ioc->spi_data.pIocPg4, + ioc->spi_data.IocPg4_dma); + ioc->spi_data.pIocPg4 = NULL; + ioc->alloc_total -= sz; + } - if (freeup && this->spi_data.nvram != NULL) { - kfree(this->spi_data.nvram); - this->spi_data.nvram = NULL; - } + if (ioc->ReqToChain != NULL) { + kfree(ioc->ReqToChain); + kfree(ioc->RequestNB); + ioc->ReqToChain = NULL; + } - if (freeup && this->spi_data.pIocPg3 != NULL) { - kfree(this->spi_data.pIocPg3); - this->spi_data.pIocPg3 = NULL; - } + kfree(ioc->ChainToChain); + ioc->ChainToChain = NULL; - if (freeup && this->spi_data.pIocPg4 != NULL) { - sz = this->spi_data.IocPg4Sz; - pci_free_consistent(this->pcidev, sz, - this->spi_data.pIocPg4, - this->spi_data.IocPg4_dma); - this->spi_data.pIocPg4 = NULL; - this->alloc_total -= sz; + if (ioc->HostPageBuffer != NULL) { + if((ret = mpt_host_page_access_control(ioc, + MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) { + printk(KERN_ERR MYNAM + ": %s: host page buffers free failed (%d)!\n", + __FUNCTION__, ret); } + dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n", + ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz)); + pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz, + ioc->HostPageBuffer, + ioc->HostPageBuffer_dma); + ioc->HostPageBuffer = NULL; + ioc->HostPageBuffer_sz = 0; + ioc->alloc_total -= ioc->HostPageBuffer_sz; } } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mpt_adapter_dispose - Free all resources associated with a MPT - * adapter. - * @this: Pointer to MPT adapter structure +/** + * mpt_adapter_dispose - Free all resources associated with an MPT adapter + * @ioc: Pointer to MPT adapter structure * * This routine unregisters h/w resources and frees all alloc'd memory * associated with a MPT adapter structure. */ static void -mpt_adapter_dispose(MPT_ADAPTER *this) +mpt_adapter_dispose(MPT_ADAPTER *ioc) { - if (this != NULL) { - int sz_first, sz_last; + int sz_first, sz_last; - sz_first = this->alloc_total; + if (ioc == NULL) + return; - if (this->alt_ioc != NULL) { - this->alt_ioc->alt_ioc = NULL; - this->alt_ioc = NULL; - } + sz_first = ioc->alloc_total; - mpt_adapter_disable(this, 1); + mpt_adapter_disable(ioc); - if (this->pci_irq != -1) { - free_irq(this->pci_irq, this); - this->pci_irq = -1; - } + if (ioc->pci_irq != -1) { + free_irq(ioc->pci_irq, ioc); + if (mpt_msi_enable) + pci_disable_msi(ioc->pcidev); + ioc->pci_irq = -1; + } - if (this->memmap != NULL) - iounmap((u8 *) this->memmap); + if (ioc->memmap != NULL) { + iounmap(ioc->memmap); + ioc->memmap = NULL; + } #if defined(CONFIG_MTRR) && 0 - if (this->mtrr_reg > 0) { - mtrr_del(this->mtrr_reg, 0, 0); - dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", this->name)); - } + if (ioc->mtrr_reg > 0) { + mtrr_del(ioc->mtrr_reg, 0, 0); + dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name)); + } #endif - /* Zap the adapter lookup ptr! */ - mpt_adapters[this->id] = NULL; + /* Zap the adapter lookup ptr! */ + list_del(&ioc->list); - sz_last = this->alloc_total; - dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n", - this->name, sz_first-sz_last+(int)sizeof(*this), sz_first)); - kfree(this); - } + sz_last = ioc->alloc_total; + dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n", + ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first)); + + if (ioc->alt_ioc) + ioc->alt_ioc->alt_ioc = NULL; + + kfree(ioc); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * MptDisplayIocCapabilities - Disply IOC's capacilities. +/** + * MptDisplayIocCapabilities - Disply IOC's capabilities. * @ioc: Pointer to MPT adapter structure */ static void @@ -2206,7 +2153,7 @@ MptDisplayIocCapabilities(MPT_ADAPTER *ioc) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * MakeIocReady - Get IOC to a READY state, using KickStart if needed. * @ioc: Pointer to MPT_ADAPTER structure * @force: Force hard KickStart of IOC @@ -2246,19 +2193,8 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) } /* Is it already READY? */ - if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) { - if ((int)ioc->chip_type <= (int)FC929) - return 0; - else { - /* Workaround from broken 1030 FW. - * Force a diagnostic reset if fails. - */ - if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0) - return 0; - else - statefault = 4; - } - } + if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) + return 0; /* * Check to see if IOC is in FAULT state. @@ -2275,7 +2211,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) * Hmmm... Did it get left operational? */ if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) { - dprintk((MYIOC_s_WARN_FMT "IOC operational unexpected\n", + dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n", ioc->name)); /* Check WhoInit. @@ -2284,8 +2220,8 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) * Else, fall through to KickStart case */ whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT; - dprintk((KERN_WARNING MYNAM - ": whoinit 0x%x\n statefault %d force %d\n", + dinitprintk((KERN_INFO MYNAM + ": whoinit 0x%x statefault %d force %d\n", whoinit, statefault, force)); if (whoinit == MPI_WHOINIT_PCI_PEER) return -4; @@ -2306,7 +2242,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) * Loop here waiting for IOC to come READY. */ ii = 0; - cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */ + cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */ while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) { if (ioc_state == MPI_IOC_STATE_OPERATIONAL) { @@ -2332,13 +2268,12 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) ii++; cntdn--; if (!cntdn) { printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n", - ioc->name, (ii+5)/HZ); + ioc->name, (int)((ii+5)/HZ)); return -ETIME; } if (sleepFlag == CAN_SLEEP) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + msleep(1); } else { mdelay (1); /* 1 msec delay */ } @@ -2355,7 +2290,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_GetIocState - Get the current state of a MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure * @cooked: Request raw or cooked IOC state @@ -2380,7 +2315,7 @@ mpt_GetIocState(MPT_ADAPTER *ioc, int cooked) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * GetIocFacts - Send IOCFacts request to MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure * @sleepFlag: Specifies whether the process can sleep @@ -2396,7 +2331,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) int r; int req_sz; int reply_sz; - u32 status; + int sz; + u32 status, vv; + u8 shiftFactor=1; /* IOC *must* NOT be in RESET state! */ if (ioc->last_state == MPI_IOC_STATE_RESET) { @@ -2419,7 +2356,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) get_facts.Function = MPI_FUNCTION_IOC_FACTS; /* Assert: All other get_facts fields are zero! */ - dprintk((MYIOC_s_INFO_FMT "Sending get IocFacts request\n", ioc->name)); + dinitprintk((MYIOC_s_INFO_FMT + "Sending get IocFacts request req_sz=%d reply_sz=%d\n", + ioc->name, req_sz, reply_sz)); /* No non-zero fields in the get_facts request are greater than * 1 byte in size, so we can just fire it off as is. @@ -2451,7 +2390,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions); facts->IOCStatus = le16_to_cpu(facts->IOCStatus); facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo); - status = facts->IOCStatus & MPI_IOCSTATUS_MASK; + status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK; /* CHECKME! IOCStatus, IOCLogInfo */ facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth); @@ -2481,6 +2420,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) le32_to_cpu(facts->CurrentSenseBufferHighAddr); facts->CurReplyFrameSize = le16_to_cpu(facts->CurReplyFrameSize); + facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities); /* * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx @@ -2492,6 +2432,13 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) facts->FWImageSize = le32_to_cpu(facts->FWImageSize); } + sz = facts->FWImageSize; + if ( sz & 0x01 ) + sz += 1; + if ( sz & 0x02 ) + sz += 2; + facts->FWImageSize = sz; + if (!facts->RequestFrameSize) { /* Something is wrong! */ printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n", @@ -2499,6 +2446,18 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) return -55; } + r = sz = facts->BlockSize; + vv = ((63 / (sz * 4)) + 1) & 0x03; + ioc->NB_for_64_byte_frame = vv; + while ( sz ) + { + shiftFactor++; + sz = sz >> 1; + } + ioc->NBShiftFactor = shiftFactor; + dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n", + ioc->name, vv, shiftFactor, r)); + if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { /* * Set values for this IOC's request & reply frame sizes, @@ -2509,9 +2468,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) ioc->reply_sz = MPT_REPLY_FRAME_SIZE; ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth); - dprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n", + dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n", ioc->name, ioc->reply_sz, ioc->reply_depth)); - dprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n", + dinitprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n", ioc->name, ioc->req_sz, ioc->req_depth)); /* Get port facts! */ @@ -2519,8 +2478,10 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) return r; } } else { - printk(MYIOC_s_ERR_FMT "Invalid IOC facts reply!\n", - ioc->name); + printk(MYIOC_s_ERR_FMT + "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n", + ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t, + RequestFrameSize)/sizeof(u32))); return -66; } @@ -2528,7 +2489,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * GetPortFacts - Send PortFacts request to MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure * @portnum: Port number @@ -2567,7 +2528,7 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag) get_pfacts.PortNumber = portnum; /* Assert: All other get_pfacts fields are zero! */ - dprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n", + dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n", ioc->name, portnum)); /* No non-zero fields in the get_pfacts request are greater than @@ -2595,7 +2556,7 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * SendIocInit - Send IOCInit request to MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure * @sleepFlag: Specifies whether the process can sleep @@ -2618,67 +2579,78 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) memset(&init_reply, 0, sizeof(init_reply)); ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER; -/* ioc_init.ChainOffset = 0; */ ioc_init.Function = MPI_FUNCTION_IOC_INIT; -/* ioc_init.Flags = 0; */ /* If we are in a recovery mode and we uploaded the FW image, * then this pointer is not NULL. Skip the upload a second time. * Set this flag if cached_fw set for either IOC. */ - ioc->upload_fw = 0; - ioc_init.Flags = 0; - if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) { - if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) - ioc_init.Flags = MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE; - else - ioc->upload_fw = 1; - } - ddlprintk((MYIOC_s_INFO_FMT "flags %d, upload_fw %d \n", - ioc->name, ioc_init.Flags, ioc->upload_fw)); + if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) + ioc->upload_fw = 1; + else + ioc->upload_fw = 0; + ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n", + ioc->name, ioc->upload_fw, ioc->facts.Flags)); - if ((int)ioc->chip_type <= (int)FC929) { + if(ioc->bus_type == SAS) + ioc_init.MaxDevices = ioc->facts.MaxDevices; + else if(ioc->bus_type == FC) ioc_init.MaxDevices = MPT_MAX_FC_DEVICES; - } else { + else ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES; - } ioc_init.MaxBuses = MPT_MAX_BUS; - -/* ioc_init.MsgFlags = 0; */ -/* ioc_init.MsgContext = cpu_to_le32(0x00000000); */ + dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n", + ioc->name, ioc->facts.MsgVersion)); + if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) { + // set MsgVersion and HeaderVersion host driver was built with + ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION); + ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION); + + if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) { + ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE; + } else if(mpt_host_page_alloc(ioc, &ioc_init)) + return -99; + } ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */ - - ioc->facts.RequestFrameSize = ioc_init.ReplyFrameSize; if (sizeof(dma_addr_t) == sizeof(u64)) { /* Save the upper 32-bits of the request * (reply) and sense buffers. */ - ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32)); + ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32)); ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32)); } else { /* Force 32-bit addressing */ ioc_init.HostMfaHighAddr = cpu_to_le32(0); ioc_init.SenseBufferHighAddr = cpu_to_le32(0); } - + ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr; ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr; + ioc->facts.MaxDevices = ioc_init.MaxDevices; + ioc->facts.MaxBuses = ioc_init.MaxBuses; - dprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n", + dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n", ioc->name, &ioc_init)); r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init, sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag); - if (r != 0) + if (r != 0) { + printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r); return r; + } /* No need to byte swap the multibyte fields in the reply - * since we don't even look at it's contents. + * since we don't even look at its contents. */ - if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) + dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n", + ioc->name, &ioc_init)); + + if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) { + printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r); return r; + } /* YIKES! SUPER IMPORTANT!!! * Poll IocState until _OPERATIONAL while IOC is doing @@ -2689,29 +2661,29 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) state = mpt_GetIocState(ioc, 1); while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) { if (sleepFlag == CAN_SLEEP) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + msleep(1); } else { mdelay(1); } if (!cntdn) { printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n", - ioc->name, (count+5)/HZ); + ioc->name, (int)((count+5)/HZ)); return -9; } state = mpt_GetIocState(ioc, 1); count++; } - dhsprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n", + dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n", ioc->name, count)); + ioc->aen_event_read_flag=0; return r; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * SendPortEnable - Send PortEnable request to MPT adapter port. * @ioc: Pointer to MPT_ADAPTER structure * @portnum: Port number to enable @@ -2726,7 +2698,7 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) { PortEnable_t port_enable; MPIDefaultReply_t reply_buf; - int ii; + int rc; int req_sz; int reply_sz; @@ -2743,167 +2715,73 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) /* port_enable.MsgFlags = 0; */ /* port_enable.MsgContext = 0; */ - dprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n", + dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n", ioc->name, portnum, &port_enable)); /* RAID FW may take a long time to enable */ - if ((int)ioc->chip_type <= (int)FC929) { - ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable, - reply_sz, (u16*)&reply_buf, 65 /*seconds*/, sleepFlag); + if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK) + > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) || + (ioc->bus_type == SAS)) { + rc = mpt_handshake_req_reply_wait(ioc, req_sz, + (u32*)&port_enable, reply_sz, (u16*)&reply_buf, + 300 /*seconds*/, sleepFlag); } else { - ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable, - reply_sz, (u16*)&reply_buf, 300 /*seconds*/, sleepFlag); + rc = mpt_handshake_req_reply_wait(ioc, req_sz, + (u32*)&port_enable, reply_sz, (u16*)&reply_buf, + 30 /*seconds*/, sleepFlag); } - - if (ii != 0) - return ii; - - /* We do not even look at the reply, so we need not - * swap the multi-byte fields. - */ - - return 0; + return rc; } -/* - * Inputs: size - total FW bytes - * Outputs: frags - number of fragments needed - * Return NULL if failed. +/** + * mpt_alloc_fw_memory - allocate firmware memory + * @ioc: Pointer to MPT_ADAPTER structure + * @size: total FW bytes + * + * If memory has already been allocated, the same (cached) value + * is returned. */ -void * -mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz) +void +mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size) { - fw_image_t **cached_fw; - u8 *mem; - dma_addr_t fw_dma; - int alloc_total = 0; - int bytes_left, bytes, num_frags; - int sz, ii; - - /* cached_fw - */ - sz = ioc->num_fw_frags * sizeof(void *); - mem = kmalloc(sz, GFP_ATOMIC); - if (mem == NULL) - return NULL; - - memset(mem, 0, sz); - cached_fw = (fw_image_t **)mem; - alloc_total += sz; - - /* malloc fragment memory - * fw_image_t struct and dma for fw data - */ - bytes_left = size; - ii = 0; - num_frags = 0; - bytes = bytes_left; - while((bytes_left) && (num_frags < ioc->num_fw_frags)) { - if (cached_fw[ii] == NULL) { - mem = kmalloc(sizeof(fw_image_t), GFP_ATOMIC); - if (mem == NULL) - break; - - memset(mem, 0, sizeof(fw_image_t)); - cached_fw[ii] = (fw_image_t *)mem; - alloc_total += sizeof(fw_image_t); - } - - mem = pci_alloc_consistent(ioc->pcidev, bytes, &fw_dma); - if (mem == NULL) { - if (bytes > 0x10000) - bytes = 0x10000; - else if (bytes > 0x8000) - bytes = 0x8000; - else if (bytes > 0x4000) - bytes = 0x4000; - else if (bytes > 0x2000) - bytes = 0x2000; - else if (bytes > 0x1000) - bytes = 0x1000; - else - break; - - continue; - } - - cached_fw[ii]->fw = mem; - cached_fw[ii]->fw_dma = fw_dma; - cached_fw[ii]->size = bytes; - memset(mem, 0, bytes); - alloc_total += bytes; - - bytes_left -= bytes; - - num_frags++; - ii++; - } - - if (bytes_left ) { - /* Major Failure. - */ - mpt_free_fw_memory(ioc, cached_fw); - return NULL; + if (ioc->cached_fw) + return; /* use already allocated memory */ + if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) { + ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */ + ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma; + ioc->alloc_total += size; + ioc->alt_ioc->alloc_total -= size; + } else { + if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) ) + ioc->alloc_total += size; } - - *frags = num_frags; - *alloc_sz = alloc_total; - - return (void *) cached_fw; } - -/* - * If alt_img is NULL, delete from ioc structure. - * Else, delete a secondary image in same format. +/** + * mpt_free_fw_memory - free firmware memory + * @ioc: Pointer to MPT_ADAPTER structure + * + * If alt_img is NULL, delete from ioc structure. + * Else, delete a secondary image in same format. */ void -mpt_free_fw_memory(MPT_ADAPTER *ioc, fw_image_t **alt_img) +mpt_free_fw_memory(MPT_ADAPTER *ioc) { - fw_image_t **cached_fw; - int ii; int sz; - int alloc_freed = 0; - - if (alt_img != NULL) - cached_fw = alt_img; - else - cached_fw = ioc->cached_fw; - - if (cached_fw == NULL) - return; - ii = 0; - while ((ii < ioc->num_fw_frags) && (cached_fw[ii]!= NULL)) { - sz = cached_fw[ii]->size; - if (sz > 0) { - pci_free_consistent(ioc->pcidev, sz, - cached_fw[ii]->fw, cached_fw[ii]->fw_dma); - } - cached_fw[ii]->fw = NULL; - alloc_freed += sz; - - kfree(cached_fw[ii]); - cached_fw[ii] = NULL; - alloc_freed += sizeof(fw_image_t); - - ii++; - } - - kfree(cached_fw); - cached_fw = NULL; - sz = ioc->num_fw_frags * sizeof(void *); - alloc_freed += sz; - - if (alt_img == NULL) - ioc->alloc_total -= alloc_freed; + sz = ioc->facts.FWImageSize; + dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n", + ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); + pci_free_consistent(ioc->pcidev, sz, + ioc->cached_fw, ioc->cached_fw_dma); + ioc->cached_fw = NULL; return; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port. * @ioc: Pointer to MPT_ADAPTER structure * @sleepFlag: Specifies whether the process can sleep @@ -2925,34 +2803,25 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) FWUploadReply_t *preply; FWUploadTCSGE_t *ptcsge; int sgeoffset; + u32 flagsLength; int ii, sz, reply_sz; - int cmdStatus, freeMem = 0; - int num_frags, alloc_sz; + int cmdStatus; - /* If the image size is 0 or if the pointer is - * not NULL (error), we are done. + /* If the image size is 0, we are done. */ - if (((sz = ioc->facts.FWImageSize) == 0) || ioc->cached_fw) + if ((sz = ioc->facts.FWImageSize) == 0) return 0; - ioc->num_fw_frags = ioc->req_sz - sizeof(FWUpload_t) + sizeof(dma_addr_t) + sizeof(u32) -1; - ioc->num_fw_frags /= sizeof(dma_addr_t) + sizeof(u32); + mpt_alloc_fw_memory(ioc, sz); - ioc->cached_fw = (fw_image_t **) mpt_alloc_fw_memory(ioc, - ioc->facts.FWImageSize, &num_frags, &alloc_sz); + dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n", + ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); if (ioc->cached_fw == NULL) { /* Major Failure. */ - mpt_free_fw_memory(ioc, NULL); - ioc->cached_fw = NULL; - return -ENOMEM; } - ioc->alloc_total += alloc_sz; - - ddlprintk((KERN_INFO MYNAM ": FW Image @ %p, sz=%d bytes\n", - (void *)(ulong)ioc->cached_fw, ioc->facts.FWImageSize)); prequest = (FWUpload_t *)&request; preply = (FWUploadReply_t *)&reply; @@ -2965,39 +2834,27 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM; prequest->Function = MPI_FUNCTION_FW_UPLOAD; - prequest->MsgContext = 0; /* anything */ ptcsge = (FWUploadTCSGE_t *) &prequest->SGL; - ptcsge->Reserved = 0; - ptcsge->ContextSize = 0; ptcsge->DetailsLength = 12; ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT; - ptcsge->Reserved1 = 0; - ptcsge->ImageOffset = 0; ptcsge->ImageSize = cpu_to_le32(sz); sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t); - for (ii = 0; ii < (num_frags-1); ii++) { - mpt_add_sge(&request[sgeoffset], MPT_SGE_FLAGS_SIMPLE_ELEMENT | - MPT_SGE_FLAGS_ADDRESSING | MPT_TRANSFER_IOC_TO_HOST | - (u32) ioc->cached_fw[ii]->size, ioc->cached_fw[ii]->fw_dma); - - sgeoffset += sizeof(u32) + sizeof(dma_addr_t); - } - - mpt_add_sge(&request[sgeoffset], - MPT_SGE_FLAGS_SSIMPLE_READ |(u32) ioc->cached_fw[ii]->size, - ioc->cached_fw[ii]->fw_dma); + flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz; + mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma); sgeoffset += sizeof(u32) + sizeof(dma_addr_t); - - dprintk((MYIOC_s_INFO_FMT "Sending FW Upload (req @ %p) size %d \n", - ioc->name, prequest, sgeoffset)); + dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n", + prequest, sgeoffset)); + DBG_DUMP_FW_REQUEST_FRAME(prequest) ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest, reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag); + dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii)); + cmdStatus = -EFAULT; if (ii == 0) { /* Handshake transfer was complete and successful. @@ -3011,38 +2868,25 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) cmdStatus = 0; } } - ddlprintk((MYIOC_s_INFO_FMT ": do_upload status %d \n", + dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n", ioc->name, cmdStatus)); - /* Check to see if we have a copy of this image in - * host memory already. - */ - if (cmdStatus == 0) { - ioc->upload_fw = 0; - if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) - freeMem = 1; - } - /* We already have a copy of this image or - * we had some type of an error - either the handshake - * failed (i != 0) or the command did not complete successfully. - */ - if (cmdStatus || freeMem) { + if (cmdStatus) { - ddlprintk((MYIOC_s_INFO_FMT ": do_upload freeing %s image \n", - ioc->name, cmdStatus ? "incomplete" : "duplicate")); - mpt_free_fw_memory(ioc, NULL); - ioc->cached_fw = NULL; + ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n", + ioc->name)); + mpt_free_fw_memory(ioc); } return cmdStatus; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_downloadboot - DownloadBoot code * @ioc: Pointer to MPT_ADAPTER structure - * @flag: Specify which part of IOC memory is to be uploaded. + * @pFwHeader: Pointer to firmware header info * @sleepFlag: Specifies whether the process can sleep * * FwDownloadBoot requires Programmed IO access. @@ -3053,266 +2897,199 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) * <0 for fw upload failure. */ static int -mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) +mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag) { - MpiFwHeader_t *FwHdr; - MpiExtImageHeader_t *ExtHdr; - fw_image_t **pCached=NULL; - int fw_sz; + MpiExtImageHeader_t *pExtImage; + u32 fwSize; u32 diag0val; -#ifdef MPT_DEBUG - u32 diag1val = 0; -#endif - int count = 0; - u32 *ptru32; + int count; + u32 *ptrFw; u32 diagRwData; u32 nextImage; - u32 ext_offset; u32 load_addr; - int max_idx, fw_idx, ext_idx; - int left_u32s; + u32 ioc_state=0; - ddlprintk((MYIOC_s_INFO_FMT "DbGb0: downloadboot entered.\n", - ioc->name)); -#ifdef MPT_DEBUG - diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - if (ioc->alt_ioc) - diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); - ddlprintk((MYIOC_s_INFO_FMT "DbGb1: diag0=%08x, diag1=%08x\n", - ioc->name, diag0val, diag1val)); -#endif + ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n", + ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader)); - ddlprintk((MYIOC_s_INFO_FMT "fw size 0x%x, ioc FW Ptr %p\n", - ioc->name, ioc->facts.FWImageSize, ioc->cached_fw)); - if (ioc->alt_ioc) - ddlprintk((MYIOC_s_INFO_FMT "alt ioc FW Ptr %p\n", - ioc->name, ioc->alt_ioc->cached_fw)); - - /* Get dma_addr and data transfer size. - */ - if ((fw_sz = ioc->facts.FWImageSize) == 0) - return -1; + CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); - /* Get the DMA from ioc or ioc->alt_ioc */ - if (ioc->cached_fw != NULL) - pCached = (fw_image_t **)ioc->cached_fw; - else if (ioc->alt_ioc && (ioc->alt_ioc->cached_fw != NULL)) - pCached = (fw_image_t **)ioc->alt_ioc->cached_fw; - else - return -2; + CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM)); - ddlprintk((MYIOC_s_INFO_FMT "DbGb2: FW Image @ %p\n", - ioc->name, pCached)); + /* wait 1 msec */ + if (sleepFlag == CAN_SLEEP) { + msleep(1); + } else { + mdelay (1); + } - /* Write magic sequence to WriteSequence register - * until enter diagnostic mode - */ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - while ((diag0val & MPI_DIAG_DRWE) == 0) { - CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); - CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); - CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); - CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); - CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); - CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER); - /* wait 100 msec */ + for (count = 0; count < 30; count ++) { + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) { + ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n", + ioc->name, count)); + break; + } + /* wait .1 sec */ if (sleepFlag == CAN_SLEEP) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(100 * HZ / 1000); + msleep (100); } else { mdelay (100); } - - count++; - if (count > 20) { - printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n", - ioc->name, diag0val); - return -EFAULT; - - } - - diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); -#ifdef MPT_DEBUG - if (ioc->alt_ioc) - diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); - ddlprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n", - ioc->name, diag0val, diag1val)); -#endif - ddlprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n", - ioc->name, diag0val)); } - /* Set the DiagRwEn and Disable ARM bits */ - diag0val |= (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM); - CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); - -#ifdef MPT_DEBUG - if (ioc->alt_ioc) - diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); + if ( count == 30 ) { + ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! " + "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n", + ioc->name, diag0val)); + return -3; + } - ddlprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n", - ioc->name, diag0val, diag1val)); -#endif + CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); - /* max_idx = 1 + maximum valid buffer index - */ - max_idx = 0; - while (pCached[max_idx]) - max_idx++; + /* Set the DiagRwEn and Disable ARM bits */ + CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM)); - fw_idx = 0; - FwHdr = (MpiFwHeader_t *) pCached[fw_idx]->fw; - ptru32 = (u32 *) FwHdr; - count = (FwHdr->ImageSize + 3)/4; - nextImage = FwHdr->NextImageHeaderOffset; + fwSize = (pFwHeader->ImageSize + 3)/4; + ptrFw = (u32 *) pFwHeader; /* Write the LoadStartAddress to the DiagRw Address Register * using Programmed IO */ - CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->LoadStartAddress); + if (ioc->errata_flag_1064) + pci_enable_io_access(ioc->pcidev); + + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress); ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n", - ioc->name, FwHdr->LoadStartAddress)); - - ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x u32's @ %p\n", - ioc->name, count, ptru32)); - left_u32s = pCached[fw_idx]->size/4; - while (count--) { - if (left_u32s == 0) { - fw_idx++; - if (fw_idx >= max_idx) { - /* FIXME - ERROR CASE - */ - ; - } - ptru32 = (u32 *) pCached[fw_idx]->fw; - left_u32s = pCached[fw_idx]->size / 4; - } - left_u32s--; - CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32); - ptru32++; + ioc->name, pFwHeader->LoadStartAddress)); + + ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n", + ioc->name, fwSize*4, ptrFw)); + while (fwSize--) { + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++); } - /* left_u32s, fw_idx and ptru32 are all valid - */ + nextImage = pFwHeader->NextImageHeaderOffset; while (nextImage) { - ext_idx = 0; - ext_offset = nextImage; - while (ext_offset > pCached[ext_idx]->size) { - ext_idx++; - if (ext_idx >= max_idx) { - /* FIXME - ERROR CASE - */ - ; - } - ext_offset -= pCached[ext_idx]->size; - } - ptru32 = (u32 *) ((char *)pCached[ext_idx]->fw + ext_offset); - left_u32s = pCached[ext_idx]->size - ext_offset; - - if ((left_u32s * 4) >= sizeof(MpiExtImageHeader_t)) { - ExtHdr = (MpiExtImageHeader_t *) ptru32; - count = (ExtHdr->ImageSize + 3 )/4; - nextImage = ExtHdr->NextImageHeaderOffset; - load_addr = ExtHdr->LoadStartAddress; - } else { - u32 * ptmp = (u32 *)pCached[ext_idx+1]->fw; + pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage); - switch (left_u32s) { - case 5: - count = *(ptru32 + 2); - nextImage = *(ptru32 + 3); - load_addr = *(ptru32 + 4); - break; - case 4: - count = *(ptru32 + 2); - nextImage = *(ptru32 + 3); - load_addr = *ptmp; - break; - case 3: - count = *(ptru32 + 2); - nextImage = *ptmp; - load_addr = *(ptmp + 1); - break; - case 2: - count = *ptmp; - nextImage = *(ptmp + 1); - load_addr = *(ptmp + 2); - break; + load_addr = pExtImage->LoadStartAddress; - case 1: - count = *(ptmp + 1); - nextImage = *(ptmp + 2); - load_addr = *(ptmp + 3); - break; - - default: - count = 0; - nextImage = 0; - load_addr = 0; - /* FIXME - ERROR CASE - */ - ; - - } - count = (count +3)/4; - } + fwSize = (pExtImage->ImageSize + 3) >> 2; + ptrFw = (u32 *)pExtImage; - ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x u32's @ %p\n", - ioc->name, count, ptru32)); + ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n", + ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr)); CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr); - while (count--) { - if (left_u32s == 0) { - fw_idx++; - if (fw_idx >= max_idx) { - /* FIXME - ERROR CASE - */ - ; - } - ptru32 = (u32 *) pCached[fw_idx]->fw; - left_u32s = pCached[fw_idx]->size / 4; - } - left_u32s--; - CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32); - ptru32++; + while (fwSize--) { + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++); } + nextImage = pExtImage->NextImageHeaderOffset; } /* Write the IopResetVectorRegAddr */ - ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr! \n", ioc->name)); - CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->IopResetRegAddr); + ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr)); + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr); /* Write the IopResetVectorValue */ - ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value! \n", ioc->name)); - CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, FwHdr->IopResetVectorValue); + ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue)); + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue); /* Clear the internal flash bad bit - autoincrementing register, * so must do two writes. */ - CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); - diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData); - diagRwData |= 0x4000000; - CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); - CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData); + if (ioc->bus_type == SPI) { + /* + * 1030 and 1035 H/W errata, workaround to access + * the ClearFlashBadSignatureBit + */ + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); + diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData); + diagRwData |= 0x40000000; + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData); + + } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ { + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | + MPI_DIAG_CLEAR_FLASH_BAD_SIG); + + /* wait 1 msec */ + if (sleepFlag == CAN_SLEEP) { + msleep (1); + } else { + mdelay (1); + } + } + + if (ioc->errata_flag_1064) + pci_disable_io_access(ioc->pcidev); - /* clear the RW enable and DISARM bits */ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - diag0val &= ~(MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE | MPI_DIAG_FLASH_BAD_SIG); + ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, " + "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n", + ioc->name, diag0val)); + diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE); + ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n", + ioc->name, diag0val)); CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); /* Write 0xFF to reset the sequencer */ CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); - return 0; + if (ioc->bus_type == SAS) { + ioc_state = mpt_GetIocState(ioc, 0); + if ( (GetIocFacts(ioc, sleepFlag, + MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) { + ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n", + ioc->name, ioc_state)); + return -EFAULT; + } + } + + for (count=0; countname, count, ioc_state)); + if (ioc->bus_type == SAS) { + return 0; + } + if ((SendIocInit(ioc, sleepFlag)) != 0) { + ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n", + ioc->name)); + return -EFAULT; + } + ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n", + ioc->name)); + return 0; + } + if (sleepFlag == CAN_SLEEP) { + msleep (10); + } else { + mdelay (10); + } + } + ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n", + ioc->name, ioc_state)); + return -EFAULT; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * KickStart - Perform hard reset of MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure * @force: Force hard reset @@ -3330,9 +3107,9 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) * 0 else * * Returns: - * 1 - hard reset, READY - * 0 - no reset due to History bit, READY - * -1 - no reset due to History bit but not READY + * 1 - hard reset, READY + * 0 - no reset due to History bit, READY + * -1 - no reset due to History bit but not READY * OR reset but failed to come READY * -2 - no reset, could not enter DIAG mode * -3 - reset but bad FW bit @@ -3341,19 +3118,18 @@ static int KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) { int hard_reset_done = 0; - u32 ioc_state; - int cntdn, cnt = 0; + u32 ioc_state=0; + int cnt,cntdn; - dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name)); - if ((int)ioc->chip_type > (int)FC929) { + dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name)); + if (ioc->bus_type == SPI) { /* Always issue a Msg Unit Reset first. This will clear some * SCSI bus hang conditions. */ SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag); if (sleepFlag == CAN_SLEEP) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + msleep (1000); } else { mdelay (1000); } @@ -3363,36 +3139,36 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) if (hard_reset_done < 0) return hard_reset_done; - dprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n", + dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n", ioc->name)); - cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 20; /* 20 seconds */ + cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */ for (cnt=0; cntname, cnt)); + ioc_state = mpt_GetIocState(ioc, 1); + if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) { + dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n", + ioc->name, cnt)); return hard_reset_done; } if (sleepFlag == CAN_SLEEP) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + msleep (10); } else { mdelay (10); } } - printk(MYIOC_s_ERR_FMT "Failed to come READY after reset!\n", - ioc->name); + printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n", + ioc->name, ioc_state); return -1; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_diag_reset - Perform hard reset of the adapter. * @ioc: Pointer to MPT_ADAPTER structure * @ignore: Set if to honor and clear to ignore * the reset history bit - * @sleepflag: CAN_SLEEP if called in a non-interrupt thread, + * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread, * else set to NO_SLEEP (use mdelay instead) * * This routine places the adapter in diagnostic mode via the @@ -3408,6 +3184,7 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) { + MPT_ADAPTER *iocp=NULL; u32 diag0val; u32 doorbell; int hard_reset_done = 0; @@ -3416,6 +3193,37 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) u32 diag1val = 0; #endif + if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) { + drsprintk((MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset " + "address=%p\n", ioc->name, __FUNCTION__, + &ioc->chip->Doorbell, &ioc->chip->Reset_1078)); + CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07); + if (sleepFlag == CAN_SLEEP) + msleep(1); + else + mdelay(1); + + for (count = 0; count < 60; count ++) { + doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); + doorbell &= MPI_IOC_STATE_MASK; + + drsprintk((MYIOC_s_INFO_FMT + "looking for READY STATE: doorbell=%x" + " count=%d\n", + ioc->name, doorbell, count)); + if (doorbell == MPI_IOC_STATE_READY) { + return 0; + } + + /* wait 1 sec */ + if (sleepFlag == CAN_SLEEP) + msleep(1000); + else + mdelay(1000); + } + return -1; + } + /* Clear any existing interrupts */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); @@ -3446,8 +3254,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) /* wait 100 msec */ if (sleepFlag == CAN_SLEEP) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(100 * HZ / 1000); + msleep (100); } else { mdelay (100); } @@ -3472,18 +3279,12 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n", ioc->name, diag0val, diag1val)); #endif - /* Write the PreventIocBoot bit */ - if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) { - diag0val |= MPI_DIAG_PREVENT_IOC_BOOT; - CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); - } - /* * Disable the ARM (Bug fix) * */ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM); - mdelay (1); + mdelay(1); /* * Now hit the reset bit in the Diagnostic register @@ -3508,44 +3309,43 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) if (MptResetHandlers[ii]) { dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n", ioc->name, ii)); - r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_PRE_RESET); + r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET); if (ioc->alt_ioc) { dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n", ioc->name, ioc->alt_ioc->name, ii)); - r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_PRE_RESET); + r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET); } } } /* FIXME? Examine results here? */ } - if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) { + if (ioc->cached_fw) + iocp = ioc; + else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) + iocp = ioc->alt_ioc; + if (iocp) { /* If the DownloadBoot operation fails, the * IOC will be left unusable. This is a fatal error * case. _diag_reset will return < 0 */ for (count = 0; count < 30; count ++) { - diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); -#ifdef MPT_DEBUG - if (ioc->alt_ioc) - diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); - dprintk((MYIOC_s_INFO_FMT - "DbG2b: diag0=%08x, diag1=%08x\n", - ioc->name, diag0val, diag1val)); -#endif + diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic); if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) { break; } + dprintk((MYIOC_s_INFO_FMT "cached_fw: diag0val=%x count=%d\n", + iocp->name, diag0val, count)); /* wait 1 sec */ if (sleepFlag == CAN_SLEEP) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + msleep (1000); } else { mdelay (1000); } } - if ((count = mpt_downloadboot(ioc, sleepFlag)) < 0) { + if ((count = mpt_downloadboot(ioc, + (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) { printk(KERN_WARNING MYNAM ": firmware downloadboot failure (%d)!\n", count); } @@ -3567,8 +3367,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) /* wait 1 sec */ if (sleepFlag == CAN_SLEEP) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + msleep (1000); } else { mdelay (1000); } @@ -3593,6 +3392,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) /* Write magic sequence to WriteSequence register * Loop until in diagnostic mode */ + CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); @@ -3601,8 +3401,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) /* wait 100 msec */ if (sleepFlag == CAN_SLEEP) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(100 * HZ / 1000); + msleep (100); } else { mdelay (100); } @@ -3655,11 +3454,12 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * SendIocReset - Send IOCReset request to MPT adapter. * @ioc: Pointer to MPT_ADAPTER structure * @reset_type: reset type, expected values are * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET + * @sleepFlag: Specifies whether the process can sleep * * Send IOCReset request to the MPT adapter. * @@ -3672,7 +3472,7 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag) u32 state; int cntdn, count; - dprintk((KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n", + drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n", ioc->name, reset_type)); CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<name, (count+5)/HZ); + ioc->name, (int)((count+5)/HZ)); return -ETIME; } if (sleepFlag == CAN_SLEEP) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + msleep(1); } else { mdelay (1); /* 1 msec delay */ } @@ -3714,36 +3513,47 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * PrimeIocFifos - Initialize IOC request and reply FIFOs. +/** + * initChainBuffers - Allocate memory for and initialize chain buffers * @ioc: Pointer to MPT_ADAPTER structure * - * This routine allocates memory for the MPT reply and request frame - * pools (if necessary), and primes the IOC reply FIFO with - * reply frames. - * - * Returns 0 for success, non-zero for failure. + * Allocates memory for and initializes chain buffers, + * chain buffer control arrays and spinlock. */ static int -PrimeIocFifos(MPT_ADAPTER *ioc) +initChainBuffers(MPT_ADAPTER *ioc) { - MPT_FRAME_HDR *mf; - unsigned long b; - unsigned long flags; - dma_addr_t aligned_mem_dma; - u8 *aligned_mem; - int i, sz; - int chain_buffer_sz, reply_buffer_sz, request_buffer_sz; - int scale, num_sge, num_chain; + u8 *mem; + int sz, ii, num_chain; + int scale, num_sge, numSGE; - /* request buffer size, rounding UP to nearest 4-kB boundary */ - request_buffer_sz = (ioc->req_sz * ioc->req_depth) + 128; - request_buffer_sz = ((request_buffer_sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; + /* ReqToChain size must equal the req_depth + * index = req_idx + */ + if (ioc->ReqToChain == NULL) { + sz = ioc->req_depth * sizeof(int); + mem = kmalloc(sz, GFP_ATOMIC); + if (mem == NULL) + return -1; - /* reply buffer size */ - reply_buffer_sz = (ioc->reply_sz * ioc->reply_depth) + 128; + ioc->ReqToChain = (int *) mem; + dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc @ %p, sz=%d bytes\n", + ioc->name, mem, sz)); + mem = kmalloc(sz, GFP_ATOMIC); + if (mem == NULL) + return -1; + + ioc->RequestNB = (int *) mem; + dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc @ %p, sz=%d bytes\n", + ioc->name, mem, sz)); + } + for (ii = 0; ii < ioc->req_depth; ii++) { + ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN; + } - /* chain buffer size, copied from from mptscsih_initChainBuffers() + /* ChainToChain size must equal the total number + * of chain buffers to be allocated. + * index = chain_idx * * Calculate the number of chain buffers needed(plus 1) per I/O * then multiply the the maximum number of simultaneous cmds @@ -3751,77 +3561,137 @@ PrimeIocFifos(MPT_ADAPTER *ioc) * num_sge = num sge in request frame + last chain buffer * scale = num sge per chain buffer if no chain element */ - scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); if (sizeof(dma_addr_t) == sizeof(u64)) num_sge = scale + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); else - num_sge = 1 + scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); + num_sge = 1+ scale + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); + + if (sizeof(dma_addr_t) == sizeof(u64)) { + numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); + } else { + numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); + } + dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n", + ioc->name, num_sge, numSGE)); + + if ( numSGE > MPT_SCSI_SG_DEPTH ) + numSGE = MPT_SCSI_SG_DEPTH; + + num_chain = 1; + while (numSGE - num_sge > 0) { + num_chain++; + num_sge += (scale - 1); + } + num_chain++; + + dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n", + ioc->name, numSGE, num_sge, num_chain)); + + if (ioc->bus_type == SPI) + num_chain *= MPT_SCSI_CAN_QUEUE; + else + num_chain *= MPT_FC_CAN_QUEUE; + + ioc->num_chain = num_chain; + + sz = num_chain * sizeof(int); + if (ioc->ChainToChain == NULL) { + mem = kmalloc(sz, GFP_ATOMIC); + if (mem == NULL) + return -1; + + ioc->ChainToChain = (int *) mem; + dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n", + ioc->name, mem, sz)); + } else { + mem = (u8 *) ioc->ChainToChain; + } + memset(mem, 0xFF, sz); + return num_chain; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * PrimeIocFifos - Initialize IOC request and reply FIFOs. + * @ioc: Pointer to MPT_ADAPTER structure + * + * This routine allocates memory for the MPT reply and request frame + * pools (if necessary), and primes the IOC reply FIFO with + * reply frames. + * + * Returns 0 for success, non-zero for failure. + */ +static int +PrimeIocFifos(MPT_ADAPTER *ioc) +{ + MPT_FRAME_HDR *mf; + unsigned long flags; + dma_addr_t alloc_dma; + u8 *mem; + int i, reply_sz, sz, total_size, num_chain; - num_chain = 1; - while (MPT_SCSI_SG_DEPTH - num_sge > 0) { - num_chain++; - num_sge += (scale - 1); - } - num_chain++; + /* Prime reply FIFO... */ - if ((int)ioc->chip_type > (int) FC929) - num_chain *= MPT_SCSI_CAN_QUEUE; - else - num_chain *= MPT_FC_CAN_QUEUE; + if (ioc->reply_frames == NULL) { + if ( (num_chain = initChainBuffers(ioc)) < 0) + return -1; - chain_buffer_sz = num_chain * ioc->req_sz; + total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth); + dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n", + ioc->name, ioc->reply_sz, ioc->reply_depth)); + dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n", + ioc->name, reply_sz, reply_sz)); + + sz = (ioc->req_sz * ioc->req_depth); + dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n", + ioc->name, ioc->req_sz, ioc->req_depth)); + dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n", + ioc->name, sz, sz)); + total_size += sz; + + sz = num_chain * ioc->req_sz; /* chain buffer pool size */ + dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n", + ioc->name, ioc->req_sz, num_chain)); + dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n", + ioc->name, sz, sz, num_chain)); + + total_size += sz; + mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma); + if (mem == NULL) { + printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n", + ioc->name); + goto out_fail; + } - if(ioc->fifo_pool == NULL) { + dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n", + ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size)); - ioc->fifo_pool_sz = request_buffer_sz + - reply_buffer_sz + chain_buffer_sz; + memset(mem, 0, total_size); + ioc->alloc_total += total_size; + ioc->alloc = mem; + ioc->alloc_dma = alloc_dma; + ioc->alloc_sz = total_size; + ioc->reply_frames = (MPT_FRAME_HDR *) mem; + ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); - ioc->fifo_pool = pci_alloc_consistent(ioc->pcidev, - ioc->fifo_pool_sz, &ioc->fifo_pool_dma); + dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n", + ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma)); - if( ioc->fifo_pool == NULL) - goto out_fail; + alloc_dma += reply_sz; + mem += reply_sz; - ioc->alloc_total += ioc->fifo_pool_sz; - memset(ioc->fifo_pool, 0, ioc->fifo_pool_sz); - - /* reply fifo pointers */ - ioc->reply_alloc = ioc->fifo_pool; - ioc->reply_alloc_dma = ioc->fifo_pool_dma; - /* request fifo pointers */ - ioc->req_alloc = ioc->reply_alloc+reply_buffer_sz; - ioc->req_alloc_dma = ioc->reply_alloc_dma+reply_buffer_sz; - /* chain buffer pointers */ - ioc->chain_alloc = ioc->req_alloc+request_buffer_sz; - ioc->chain_alloc_dma = ioc->req_alloc_dma+request_buffer_sz; - ioc->chain_alloc_sz = chain_buffer_sz; - - /* Prime reply FIFO... */ - dprintk((KERN_INFO MYNAM ": %s.reply_alloc @ %p[%p], sz=%d bytes\n", - ioc->name, mem, (void *)(ulong)ioc->reply_alloc_dma, reply_buffer_sz)); - - b = (unsigned long) ioc->reply_alloc; - b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */ - aligned_mem = (u8 *) b; - ioc->reply_frames = (MPT_FRAME_HDR *) aligned_mem; - ioc->reply_frames_dma = - (ioc->reply_alloc_dma + (aligned_mem - ioc->reply_alloc)); - - ioc->reply_frames_low_dma = (u32) (ioc->reply_frames_dma & 0xFFFFFFFF); - /* Request FIFO - WE manage this! */ - dprintk((KERN_INFO MYNAM ": %s.req_alloc @ %p[%p], sz=%d bytes\n", - ioc->name, mem, (void *)(ulong)ioc->req_alloc_dma, request_buffer_sz)); - b = (unsigned long) ioc->req_alloc; - b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */ - aligned_mem = (u8 *) b; - ioc->req_frames = (MPT_FRAME_HDR *) aligned_mem; - ioc->req_frames_dma = - (ioc->req_alloc_dma + (aligned_mem - ioc->req_alloc)); + ioc->req_frames = (MPT_FRAME_HDR *) mem; + ioc->req_frames_dma = alloc_dma; - ioc->req_frames_low_dma = (u32) (ioc->req_frames_dma & 0xFFFFFFFF); + dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n", + ioc->name, mem, (void *)(ulong)alloc_dma)); + + ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); #if defined(CONFIG_MTRR) && 0 /* @@ -3829,79 +3699,94 @@ PrimeIocFifos(MPT_ADAPTER *ioc) * (at least as much as we can; "size and base must be * multiples of 4 kiB" */ - ioc->mtrr_reg = mtrr_add(ioc->fifo_pool, - ioc->fifo_pool_sz, + ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma, + sz, MTRR_TYPE_WRCOMB, 1); dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n", - ioc->name, ioc->fifo_pool, ioc->fifo_pool_sz)); + ioc->name, ioc->req_frames_dma, sz)); #endif - } /* ioc->fifo_pool == NULL */ - - /* Post Reply frames to FIFO - */ - aligned_mem_dma = ioc->reply_frames_dma; - dprintk((KERN_INFO MYNAM ": %s.reply_frames @ %p[%p]\n", - ioc->name, ioc->reply_frames, (void *)(ulong)aligned_mem_dma)); + for (i = 0; i < ioc->req_depth; i++) { + alloc_dma += ioc->req_sz; + mem += ioc->req_sz; + } - for (i = 0; i < ioc->reply_depth; i++) { - /* Write each address to the IOC! */ - CHIPREG_WRITE32(&ioc->chip->ReplyFifo, aligned_mem_dma); - aligned_mem_dma += ioc->reply_sz; - } + ioc->ChainBuffer = mem; + ioc->ChainBufferDMA = alloc_dma; + dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n", + ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA)); - /* Initialize Request frames linked list - */ - aligned_mem_dma = ioc->req_frames_dma; - aligned_mem = (u8 *) ioc->req_frames; - dprintk((KERN_INFO MYNAM ": %s.req_frames @ %p[%p]\n", - ioc->name, aligned_mem, (void *)(ulong)aligned_mem_dma)); + /* Initialize the free chain Q. + */ - spin_lock_irqsave(&ioc->FreeQlock, flags); - Q_INIT(&ioc->FreeQ, MPT_FRAME_HDR); - for (i = 0; i < ioc->req_depth; i++) { - mf = (MPT_FRAME_HDR *) aligned_mem; + INIT_LIST_HEAD(&ioc->FreeChainQ); - /* Queue REQUESTs *internally*! */ - Q_ADD_TAIL(&ioc->FreeQ.head, &mf->u.frame.linkage, MPT_FRAME_HDR); - aligned_mem += ioc->req_sz; - } - spin_unlock_irqrestore(&ioc->FreeQlock, flags); + /* Post the chain buffers to the FreeChainQ. + */ + mem = (u8 *)ioc->ChainBuffer; + for (i=0; i < num_chain; i++) { + mf = (MPT_FRAME_HDR *) mem; + list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ); + mem += ioc->req_sz; + } + + /* Initialize Request frames linked list + */ + alloc_dma = ioc->req_frames_dma; + mem = (u8 *) ioc->req_frames; + spin_lock_irqsave(&ioc->FreeQlock, flags); + INIT_LIST_HEAD(&ioc->FreeQ); + for (i = 0; i < ioc->req_depth; i++) { + mf = (MPT_FRAME_HDR *) mem; + + /* Queue REQUESTs *internally*! */ + list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ); + + mem += ioc->req_sz; + } + spin_unlock_irqrestore(&ioc->FreeQlock, flags); - if (ioc->sense_buf_pool == NULL) { sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); ioc->sense_buf_pool = - pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma); - if (ioc->sense_buf_pool == NULL) + pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma); + if (ioc->sense_buf_pool == NULL) { + printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n", + ioc->name); goto out_fail; + } ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF); ioc->alloc_total += sz; + dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n", + ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma)); + + } + + /* Post Reply frames to FIFO + */ + alloc_dma = ioc->alloc_dma; + dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n", + ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma)); + + for (i = 0; i < ioc->reply_depth; i++) { + /* Write each address to the IOC! */ + CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma); + alloc_dma += ioc->reply_sz; } return 0; out_fail: - if (ioc->fifo_pool != NULL) { + if (ioc->alloc != NULL) { + sz = ioc->alloc_sz; pci_free_consistent(ioc->pcidev, - ioc->fifo_pool_sz, - ioc->fifo_pool, ioc->fifo_pool_dma); + sz, + ioc->alloc, ioc->alloc_dma); ioc->reply_frames = NULL; - ioc->reply_alloc = NULL; ioc->req_frames = NULL; - ioc->req_alloc = NULL; - ioc->chain_alloc = NULL; - ioc->fifo_pool = NULL; - ioc->alloc_total -= ioc->fifo_pool_sz; -#if defined(CONFIG_MTRR) && 0 - if (ioc->mtrr_reg > 0) { - mtrr_del(ioc->mtrr_reg, 0, 0); - dprintk((MYIOC_s_INFO_FMT "MTRR region de-registered\n", - ioc->name)); - } -#endif + ioc->alloc_total -= sz; } if (ioc->sense_buf_pool != NULL) { sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); @@ -3932,9 +3817,9 @@ out_fail: * * Returns 0 for success, non-zero for failure. */ -int +static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, - int replyBytes, u16 *u16reply, int maxwait, int sleepFlag) + int replyBytes, u16 *u16reply, int maxwait, int sleepFlag) { MPIDefaultReply_t *mptReply; int failcnt = 0; @@ -3963,8 +3848,8 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) failcnt++; - dhsprintk((MYIOC_s_INFO_FMT "HandShake request start, WaitCnt=%d%s\n", - ioc->name, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); + dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n", + ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); /* Read doorbell and check for active bit */ if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE)) @@ -3998,7 +3883,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, failcnt++; } - dmfprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req)); + dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req)); DBG_DUMP_REQUEST_FRAME_HDR(req) dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n", @@ -4010,6 +3895,9 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0) failcnt++; + dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n", + ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : "")); + /* * Copy out the cached reply... */ @@ -4023,15 +3911,15 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * WaitForDoorbellAck - Wait for IOC to clear the IOP_DOORBELL_STATUS bit - * in it's IntStatus register. +/** + * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge * @ioc: Pointer to MPT_ADAPTER structure * @howlong: How long to wait (in seconds) * @sleepFlag: Specifies whether the process can sleep * * This routine waits (up to ~2 seconds max) for IOC doorbell - * handshake ACKnowledge. + * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS + * bit in its IntStatus register being clear. * * Returns a negative value on failure, else wait loop count. */ @@ -4040,49 +3928,48 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag) { int cntdn; int count = 0; - u32 intstat; + u32 intstat=0; - cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong; + cntdn = 1000 * howlong; if (sleepFlag == CAN_SLEEP) { while (--cntdn) { + msleep (1); intstat = CHIPREG_READ32(&ioc->chip->IntStatus); if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS)) break; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); count++; } } else { while (--cntdn) { + mdelay (1); intstat = CHIPREG_READ32(&ioc->chip->IntStatus); if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS)) break; - mdelay (1); count++; } } if (cntdn) { - dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (cnt=%d)\n", + dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n", ioc->name, count)); return count; } - printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout(%d)!\n", - ioc->name, (count+5)/HZ); + printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n", + ioc->name, count, intstat); return -1; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * WaitForDoorbellInt - Wait for IOC to set the HIS_DOORBELL_INTERRUPT bit - * in it's IntStatus register. +/** + * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit * @ioc: Pointer to MPT_ADAPTER structure * @howlong: How long to wait (in seconds) * @sleepFlag: Specifies whether the process can sleep * - * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt. + * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt + * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register. * * Returns a negative value on failure, else wait loop count. */ @@ -4091,16 +3978,15 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag) { int cntdn; int count = 0; - u32 intstat; + u32 intstat=0; - cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong; + cntdn = 1000 * howlong; if (sleepFlag == CAN_SLEEP) { while (--cntdn) { intstat = CHIPREG_READ32(&ioc->chip->IntStatus); if (intstat & MPI_HIS_DOORBELL_INTERRUPT) break; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + msleep(1); count++; } } else { @@ -4114,19 +4000,19 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag) } if (cntdn) { - dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d)\n", - ioc->name, count)); + dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n", + ioc->name, count, howlong)); return count; } - printk(MYIOC_s_ERR_FMT "Doorbell INT timeout(%d)!\n", - ioc->name, (count+5)/HZ); + printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n", + ioc->name, count, intstat); return -1; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * WaitForDoorbellReply - Wait for and capture a IOC handshake reply. +/** + * WaitForDoorbellReply - Wait for and capture an IOC handshake reply. * @ioc: Pointer to MPT_ADAPTER structure * @howlong: How long to wait (in seconds) * @sleepFlag: Specifies whether the process can sleep @@ -4166,8 +4052,8 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag) } } - dhsprintk((MYIOC_s_INFO_FMT "First handshake reply word=%08x%s\n", - ioc->name, le32_to_cpu(*(u32 *)hs_reply), + dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n", + ioc->name, t, le32_to_cpu(*(u32 *)hs_reply), failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); /* @@ -4202,16 +4088,16 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag) } #endif - dmfprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name)); + dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name)); DBG_DUMP_REPLY_FRAME(mptReply) - dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY (sz=%d)\n", - ioc->name, u16cnt/2)); + dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n", + ioc->name, t, u16cnt/2)); return u16cnt/2; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * GetLanConfigPages - Fetch LANConfig pages. * @ioc: Pointer to MPT_ADAPTER structure * @@ -4239,7 +4125,7 @@ GetLanConfigPages(MPT_ADAPTER *ioc) hdr.PageLength = 0; hdr.PageNumber = 0; hdr.PageType = MPI_CONFIG_PAGETYPE_LAN; - cfg.hdr = &hdr; + cfg.cfghdr.hdr = &hdr; cfg.physAddr = -1; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; @@ -4283,7 +4169,7 @@ GetLanConfigPages(MPT_ADAPTER *ioc) hdr.PageLength = 0; hdr.PageNumber = 1; hdr.PageType = MPI_CONFIG_PAGETYPE_LAN; - cfg.hdr = &hdr; + cfg.cfghdr.hdr = &hdr; cfg.physAddr = -1; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; @@ -4322,92 +4208,215 @@ GetLanConfigPages(MPT_ADAPTER *ioc) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * GetFcPortPage0 - Fetch FCPort config Page0. +/** + * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table * @ioc: Pointer to MPT_ADAPTER structure - * @portnum: IOC Port number + * @persist_opcode: see below * - * Return: 0 for success - * -ENOMEM if no memory available - * -EPERM if not allowed due to ISR context - * -EAGAIN if no msg frames currently available - * -EFAULT for non-successful reply or no reply (timeout) + * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for + * devices not currently present. + * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings + * + * NOTE: Don't use not this function during interrupt time. + * + * Returns 0 for success, non-zero error */ -static int -GetFcPortPage0(MPT_ADAPTER *ioc, int portnum) + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +int +mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode) { - ConfigPageHeader_t hdr; - CONFIGPARMS cfg; - FCPortPage0_t *ppage0_alloc; - FCPortPage0_t *pp0dest; - dma_addr_t page0_dma; - int data_sz; - int copy_sz; - int rc; + SasIoUnitControlRequest_t *sasIoUnitCntrReq; + SasIoUnitControlReply_t *sasIoUnitCntrReply; + MPT_FRAME_HDR *mf = NULL; + MPIHeader_t *mpi_hdr; - /* Get FCPort Page 0 header */ - hdr.PageVersion = 0; - hdr.PageLength = 0; - hdr.PageNumber = 0; - hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT; - cfg.hdr = &hdr; - cfg.physAddr = -1; - cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - cfg.dir = 0; - cfg.pageAddr = portnum; - cfg.timeout = 0; - if ((rc = mpt_config(ioc, &cfg)) != 0) - return rc; + /* insure garbage is not sent to fw */ + switch(persist_opcode) { - if (hdr.PageLength == 0) - return 0; + case MPI_SAS_OP_CLEAR_NOT_PRESENT: + case MPI_SAS_OP_CLEAR_ALL_PERSISTENT: + break; - data_sz = hdr.PageLength * 4; - rc = -ENOMEM; - ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma); - if (ppage0_alloc) { - memset((u8 *)ppage0_alloc, 0, data_sz); - cfg.physAddr = page0_dma; - cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + default: + return -1; + break; + } - if ((rc = mpt_config(ioc, &cfg)) == 0) { - /* save the data */ - pp0dest = &ioc->fc_port_page0[portnum]; - copy_sz = min_t(int, sizeof(FCPortPage0_t), data_sz); - memcpy(pp0dest, ppage0_alloc, copy_sz); + printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode); - /* - * Normalize endianness of structure data, - * by byte-swapping all > 1 byte fields! - */ - pp0dest->Flags = le32_to_cpu(pp0dest->Flags); - pp0dest->PortIdentifier = le32_to_cpu(pp0dest->PortIdentifier); - pp0dest->WWNN.Low = le32_to_cpu(pp0dest->WWNN.Low); - pp0dest->WWNN.High = le32_to_cpu(pp0dest->WWNN.High); - pp0dest->WWPN.Low = le32_to_cpu(pp0dest->WWPN.Low); - pp0dest->WWPN.High = le32_to_cpu(pp0dest->WWPN.High); - pp0dest->SupportedServiceClass = le32_to_cpu(pp0dest->SupportedServiceClass); - pp0dest->SupportedSpeeds = le32_to_cpu(pp0dest->SupportedSpeeds); - pp0dest->CurrentSpeed = le32_to_cpu(pp0dest->CurrentSpeed); - pp0dest->MaxFrameSize = le32_to_cpu(pp0dest->MaxFrameSize); - pp0dest->FabricWWNN.Low = le32_to_cpu(pp0dest->FabricWWNN.Low); - pp0dest->FabricWWNN.High = le32_to_cpu(pp0dest->FabricWWNN.High); - pp0dest->FabricWWPN.Low = le32_to_cpu(pp0dest->FabricWWPN.Low); - pp0dest->FabricWWPN.High = le32_to_cpu(pp0dest->FabricWWPN.High); - pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount); - pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators); + /* Get a MF for this command. + */ + if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { + printk("%s: no msg frames!\n",__FUNCTION__); + return -1; + } + + mpi_hdr = (MPIHeader_t *) mf; + sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf; + memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t)); + sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; + sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext; + sasIoUnitCntrReq->Operation = persist_opcode; + + init_timer(&ioc->persist_timer); + ioc->persist_timer.data = (unsigned long) ioc; + ioc->persist_timer.function = mpt_timer_expired; + ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */; + ioc->persist_wait_done=0; + add_timer(&ioc->persist_timer); + mpt_put_msg_frame(mpt_base_index, ioc, mf); + wait_event(mpt_waitq, ioc->persist_wait_done); + + sasIoUnitCntrReply = + (SasIoUnitControlReply_t *)ioc->persist_reply_frame; + if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) { + printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", + __FUNCTION__, + sasIoUnitCntrReply->IOCStatus, + sasIoUnitCntrReply->IOCLogInfo); + return -1; + } - } + printk("%s: success\n",__FUNCTION__); + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma); +static void +mptbase_raid_process_event_data(MPT_ADAPTER *ioc, + MpiEventDataRaid_t * pRaidEventData) +{ + int volume; + int reason; + int disk; + int status; + int flags; + int state; + + volume = pRaidEventData->VolumeID; + reason = pRaidEventData->ReasonCode; + disk = pRaidEventData->PhysDiskNum; + status = le32_to_cpu(pRaidEventData->SettingsStatus); + flags = (status >> 0) & 0xff; + state = (status >> 8) & 0xff; + + if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) { + return; } - return rc; + if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED && + reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) || + (reason == MPI_EVENT_RAID_RC_SMART_DATA)) { + printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d\n", + ioc->name, disk); + } else { + printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n", + ioc->name, volume); + } + + switch(reason) { + case MPI_EVENT_RAID_RC_VOLUME_CREATED: + printk(MYIOC_s_INFO_FMT " volume has been created\n", + ioc->name); + break; + + case MPI_EVENT_RAID_RC_VOLUME_DELETED: + + printk(MYIOC_s_INFO_FMT " volume has been deleted\n", + ioc->name); + break; + + case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED: + printk(MYIOC_s_INFO_FMT " volume settings have been changed\n", + ioc->name); + break; + + case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: + printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n", + ioc->name, + state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL + ? "optimal" + : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED + ? "degraded" + : state == MPI_RAIDVOL0_STATUS_STATE_FAILED + ? "failed" + : "state unknown", + flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED + ? ", enabled" : "", + flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED + ? ", quiesced" : "", + flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS + ? ", resync in progress" : "" ); + break; + + case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED: + printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n", + ioc->name, disk); + break; + + case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: + printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n", + ioc->name); + break; + + case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: + printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n", + ioc->name); + break; + + case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED: + printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n", + ioc->name); + break; + + case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: + printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n", + ioc->name, + state == MPI_PHYSDISK0_STATUS_ONLINE + ? "online" + : state == MPI_PHYSDISK0_STATUS_MISSING + ? "missing" + : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE + ? "not compatible" + : state == MPI_PHYSDISK0_STATUS_FAILED + ? "failed" + : state == MPI_PHYSDISK0_STATUS_INITIALIZING + ? "initializing" + : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED + ? "offline requested" + : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED + ? "failed requested" + : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE + ? "offline" + : "state unknown", + flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC + ? ", out of sync" : "", + flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED + ? ", quiesced" : "" ); + break; + + case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED: + printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n", + ioc->name, disk); + break; + + case MPI_EVENT_RAID_RC_SMART_DATA: + printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n", + ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ); + break; + + case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED: + printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n", + ioc->name, disk); + break; + } } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * GetIoUnitPage2 - Retrieve BIOS version and boot order information. * @ioc: Pointer to MPT_ADAPTER structure * @@ -4432,7 +4441,7 @@ GetIoUnitPage2(MPT_ADAPTER *ioc) hdr.PageLength = 0; hdr.PageNumber = 2; hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT; - cfg.hdr = &hdr; + cfg.cfghdr.hdr = &hdr; cfg.physAddr = -1; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; @@ -4465,7 +4474,8 @@ GetIoUnitPage2(MPT_ADAPTER *ioc) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2 +/** + * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2 * @ioc: Pointer to a Adapter Strucutre * @portnum: IOC port number * @@ -4522,7 +4532,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) header.PageLength = 0; header.PageNumber = 0; header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT; - cfg.hdr = &header; + cfg.cfghdr.hdr = &header; cfg.physAddr = -1; cfg.pageAddr = portnum; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; @@ -4542,6 +4552,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) ioc->spi_data.minSyncFactor = MPT_ASYNC; ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN; rc = 1; + ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n", + ioc->name, ioc->spi_data.minSyncFactor)); } else { /* Save the Port Page 0 data */ @@ -4549,15 +4561,19 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities); pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface); - if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) + if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) { ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS; - + ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n", + ioc->name, pPP0->Capabilities)); + } ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0; data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK; if (data) { ioc->spi_data.maxSyncOffset = (u8) (data >> 16); data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK; ioc->spi_data.minSyncFactor = (u8) (data >> 8); + ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n", + ioc->name, ioc->spi_data.minSyncFactor)); } else { ioc->spi_data.maxSyncOffset = 0; ioc->spi_data.minSyncFactor = MPT_ASYNC; @@ -4570,8 +4586,11 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) || (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) { - if (ioc->spi_data.minSyncFactor < MPT_ULTRA) + if (ioc->spi_data.minSyncFactor < MPT_ULTRA) { ioc->spi_data.minSyncFactor = MPT_ULTRA; + ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n", + ioc->name, ioc->spi_data.minSyncFactor)); + } } } if (pbuf) { @@ -4586,7 +4605,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) header.PageLength = 0; header.PageNumber = 2; header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT; - cfg.hdr = &header; + cfg.cfghdr.hdr = &header; cfg.physAddr = -1; cfg.pageAddr = portnum; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; @@ -4609,6 +4628,14 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf; MpiDeviceInfo_t *pdevice = NULL; + /* + * Save "Set to Avoid SCSI Bus Resets" flag + */ + ioc->spi_data.bus_reset = + (le32_to_cpu(pPP2->PortFlags) & + MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ? + 0 : 1 ; + /* Save the Port Page 2 data * (reformat into a 32bit quantity) */ @@ -4635,7 +4662,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mpt_readScsiDevicePageHeaders - save version and length of SDP1 +/** + * mpt_readScsiDevicePageHeaders - save version and length of SDP1 * @ioc: Pointer to a Adapter Strucutre * @portnum: IOC port number * @@ -4654,7 +4682,7 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum) header.PageLength = 0; header.PageNumber = 1; header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; - cfg.hdr = &header; + cfg.cfghdr.hdr = &header; cfg.physAddr = -1; cfg.pageAddr = portnum; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; @@ -4663,8 +4691,8 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum) if (mpt_config(ioc, &cfg) != 0) return -EFAULT; - ioc->spi_data.sdp1version = cfg.hdr->PageVersion; - ioc->spi_data.sdp1length = cfg.hdr->PageLength; + ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion; + ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength; header.PageVersion = 0; header.PageLength = 0; @@ -4673,8 +4701,8 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum) if (mpt_config(ioc, &cfg) != 0) return -EFAULT; - ioc->spi_data.sdp0version = cfg.hdr->PageVersion; - ioc->spi_data.sdp0length = cfg.hdr->PageLength; + ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion; + ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength; dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n", ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length)); @@ -4716,7 +4744,7 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) header.PageLength = 0; header.PageNumber = 2; header.PageType = MPI_CONFIG_PAGETYPE_IOC; - cfg.hdr = &header; + cfg.cfghdr.hdr = &header; cfg.physAddr = -1; cfg.pageAddr = 0; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; @@ -4738,10 +4766,10 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) if (mpt_config(ioc, &cfg) != 0) goto done_and_free; - if ( (mem = (u8 *)ioc->spi_data.pIocPg2) == NULL ) { + if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) { mem = kmalloc(iocpage2sz, GFP_ATOMIC); if (mem) { - ioc->spi_data.pIocPg2 = (IOCPage2_t *) mem; + ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem; } else { goto done_and_free; } @@ -4758,7 +4786,7 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) /* At least 1 RAID Volume */ pIocRv = pIoc2->RaidVolume; - ioc->spi_data.isRaid = 0; + ioc->raid_data.isRaid = 0; for (jj = 0; jj < nVols; jj++, pIocRv++) { vid = pIocRv->VolumeID; vbus = pIocRv->VolumeBus; @@ -4767,7 +4795,7 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) /* find the match */ if (vbus == 0) { - ioc->spi_data.isRaid |= (1 << vid); + ioc->raid_data.isRaid |= (1 << vid); } else { /* Error! Always bus 0 */ @@ -4790,7 +4818,7 @@ done_and_free: return rc; } -int +static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc) { IOCPage3_t *pIoc3; @@ -4802,10 +4830,8 @@ mpt_read_ioc_pg_3(MPT_ADAPTER *ioc) /* Free the old page */ - if (ioc->spi_data.pIocPg3) { - kfree(ioc->spi_data.pIocPg3); - ioc->spi_data.pIocPg3 = NULL; - } + kfree(ioc->raid_data.pIocPg3); + ioc->raid_data.pIocPg3 = NULL; /* There is at least one physical disk. * Read and save IOC Page 3 @@ -4814,7 +4840,7 @@ mpt_read_ioc_pg_3(MPT_ADAPTER *ioc) header.PageLength = 0; header.PageNumber = 3; header.PageType = MPI_CONFIG_PAGETYPE_IOC; - cfg.hdr = &header; + cfg.cfghdr.hdr = &header; cfg.physAddr = -1; cfg.pageAddr = 0; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; @@ -4842,7 +4868,7 @@ mpt_read_ioc_pg_3(MPT_ADAPTER *ioc) mem = kmalloc(iocpage3sz, GFP_ATOMIC); if (mem) { memcpy(mem, (u8 *)pIoc3, iocpage3sz); - ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem; + ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem; } } @@ -4866,7 +4892,7 @@ mpt_read_ioc_pg_4(MPT_ADAPTER *ioc) header.PageLength = 0; header.PageNumber = 4; header.PageType = MPI_CONFIG_PAGETYPE_IOC; - cfg.hdr = &header; + cfg.cfghdr.hdr = &header; cfg.physAddr = -1; cfg.pageAddr = 0; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; @@ -4883,6 +4909,7 @@ mpt_read_ioc_pg_4(MPT_ADAPTER *ioc) pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma); if (!pIoc4) return; + ioc->alloc_total += iocpage4sz; } else { ioc4_dma = ioc->spi_data.IocPg4_dma; iocpage4sz = ioc->spi_data.IocPg4Sz; @@ -4899,6 +4926,7 @@ mpt_read_ioc_pg_4(MPT_ADAPTER *ioc) } else { pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma); ioc->spi_data.pIocPg4 = NULL; + ioc->alloc_total -= iocpage4sz; } } @@ -4918,7 +4946,7 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc) header.PageLength = 0; header.PageNumber = 1; header.PageType = MPI_CONFIG_PAGETYPE_IOC; - cfg.hdr = &header; + cfg.cfghdr.hdr = &header; cfg.physAddr = -1; cfg.pageAddr = 0; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; @@ -4987,9 +5015,8 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * SendEventNotification - Send EventNotification (on or off) request - * to MPT adapter. +/** + * SendEventNotification - Send EventNotification (on or off) request to adapter * @ioc: Pointer to MPT_ADAPTER structure * @EvSwitch: Event switch flags */ @@ -4998,22 +5025,22 @@ SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch) { EventNotification_t *evnp; - evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc->id); + evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc); if (evnp == NULL) { - dprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n", + devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n", ioc->name)); return 0; } memset(evnp, 0, sizeof(*evnp)); - dprintk((MYIOC_s_INFO_FMT "Sending EventNotification(%d)\n", ioc->name, EvSwitch)); + devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp)); evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION; evnp->ChainOffset = 0; evnp->MsgFlags = 0; evnp->Switch = EvSwitch; - mpt_put_msg_frame(mpt_base_index, ioc->id, (MPT_FRAME_HDR *)evnp); + mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp); return 0; } @@ -5029,22 +5056,23 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp) { EventAck_t *pAck; - if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) { - printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK request frame!\n", - ioc->name); + if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { + dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames!!\n", + ioc->name,__FUNCTION__)); return -1; } - memset(pAck, 0, sizeof(*pAck)); - dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name)); + devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name)); pAck->Function = MPI_FUNCTION_EVENT_ACK; pAck->ChainOffset = 0; + pAck->Reserved[0] = pAck->Reserved[1] = 0; pAck->MsgFlags = 0; + pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0; pAck->Event = evnp->Event; pAck->EventContext = evnp->EventContext; - mpt_put_msg_frame(mpt_base_index, ioc->id, (MPT_FRAME_HDR *)pAck); + mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck); return 0; } @@ -5052,8 +5080,8 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_config - Generic function to issue config message - * @ioc - Pointer to an adapter structure - * @cfg - Pointer to a configuration structure. Struct contains + * @ioc: Pointer to an adapter structure + * @pCfg: Pointer to a configuration structure. Struct contains * action, page address, direction, physical address * and pointer to a configuration page header * Page header is updated. @@ -5067,15 +5095,14 @@ int mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) { Config_t *pReq; + ConfigExtendedPageHeader_t *pExtHdr = NULL; MPT_FRAME_HDR *mf; unsigned long flags; int ii, rc; int flagsLength; int in_isr; - /* (Bugzilla:fibrebugs, #513) - * Bug fix (part 1)! 20010905 -sralston - * Prevent calling wait_event() (below), if caller happens + /* Prevent calling wait_event() (below), if caller happens * to be in ISR context, because that is fatal! */ in_isr = in_interrupt(); @@ -5087,7 +5114,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) /* Get and Populate a free Frame */ - if ((mf = mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) { + if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n", ioc->name)); return -EAGAIN; @@ -5097,137 +5124,53 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) pReq->Reserved = 0; pReq->ChainOffset = 0; pReq->Function = MPI_FUNCTION_CONFIG; + + /* Assume page type is not extended and clear "reserved" fields. */ pReq->ExtPageLength = 0; pReq->ExtPageType = 0; pReq->MsgFlags = 0; + for (ii=0; ii < 8; ii++) pReq->Reserved2[ii] = 0; - pReq->Header.PageVersion = pCfg->hdr->PageVersion; - pReq->Header.PageLength = pCfg->hdr->PageLength; - pReq->Header.PageNumber = pCfg->hdr->PageNumber; - pReq->Header.PageType = (pCfg->hdr->PageType & MPI_CONFIG_PAGETYPE_MASK); - pReq->PageAddress = cpu_to_le32(pCfg->pageAddr); - - /* Add a SGE to the config request. - */ - if (pCfg->dir) - flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; - else - flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; - - flagsLength |= pCfg->hdr->PageLength * 4; - - mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr); - - dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n", - ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action)); - - /* Append pCfg pointer to end of mf - */ - *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg; - - /* Initalize the timer - */ - init_timer(&pCfg->timer); - pCfg->timer.data = (unsigned long) ioc; - pCfg->timer.function = mpt_timer_expired; - pCfg->wait_done = 0; - - /* Set the timer; ensure 10 second minimum */ - if (pCfg->timeout < 10) - pCfg->timer.expires = jiffies + HZ*10; - else - pCfg->timer.expires = jiffies + HZ*pCfg->timeout; - - /* Add to end of Q, set timer and then issue this command */ - spin_lock_irqsave(&ioc->FreeQlock, flags); - Q_ADD_TAIL(&ioc->configQ.head, &pCfg->linkage, Q_ITEM); - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - - add_timer(&pCfg->timer); - mpt_put_msg_frame(mpt_base_index, ioc->id, mf); - wait_event(mpt_waitq, pCfg->wait_done); - - /* mf has been freed - do not access */ - - rc = pCfg->status; - - return rc; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mpt_toolbox - Generic function to issue toolbox message - * @ioc - Pointer to an adapter structure - * @cfg - Pointer to a toolbox structure. Struct contains - * action, page address, direction, physical address - * and pointer to a configuration page header - * Page header is updated. - * - * Returns 0 for success - * -EPERM if not allowed due to ISR context - * -EAGAIN if no msg frames currently available - * -EFAULT for non-successful reply or no reply (timeout) - */ -int -mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) -{ - ToolboxIstwiReadWriteRequest_t *pReq; - MPT_FRAME_HDR *mf; - unsigned long flags; - int rc; - int flagsLength; - int in_isr; - - /* (Bugzilla:fibrebugs, #513) - * Bug fix (part 1)! 20010905 -sralston - * Prevent calling wait_event() (below), if caller happens - * to be in ISR context, because that is fatal! - */ - in_isr = in_interrupt(); - if (in_isr) { - dcprintk((MYIOC_s_WARN_FMT "toobox request not allowed in ISR context!\n", - ioc->name)); - return -EPERM; - } + pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion; + pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength; + pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber; + pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK); - /* Get and Populate a free Frame - */ - if ((mf = mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) { - dcprintk((MYIOC_s_WARN_FMT "mpt_toolbox: no msg frames!\n", - ioc->name)); - return -EAGAIN; + if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) { + pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr; + pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength); + pReq->ExtPageType = pExtHdr->ExtPageType; + pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + + /* Page Length must be treated as a reserved field for the extended header. */ + pReq->Header.PageLength = 0; } - pReq = (ToolboxIstwiReadWriteRequest_t *)mf; - pReq->Tool = pCfg->action; - pReq->Reserved = 0; - pReq->ChainOffset = 0; - pReq->Function = MPI_FUNCTION_TOOLBOX; - pReq->Reserved1 = 0; - pReq->Reserved2 = 0; - pReq->MsgFlags = 0; - pReq->Flags = pCfg->dir; - pReq->BusNum = 0; - pReq->Reserved3 = 0; - pReq->NumAddressBytes = 0x01; - pReq->Reserved4 = 0; - pReq->DataLength = 0x04; - pReq->DeviceAddr = 0xB0; - pReq->Addr1 = 0; - pReq->Addr2 = 0; - pReq->Addr3 = 0; - pReq->Reserved5 = 0; + + pReq->PageAddress = cpu_to_le32(pCfg->pageAddr); /* Add a SGE to the config request. */ + if (pCfg->dir) + flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; + else + flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; - flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | 4; + if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) { + flagsLength |= pExtHdr->ExtPageLength * 4; + + dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n", + ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action)); + } + else { + flagsLength |= pCfg->cfghdr.hdr->PageLength * 4; - mpt_add_sge((char *)&pReq->SGL, flagsLength, pCfg->physAddr); + dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n", + ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action)); + } - dcprintk((MYIOC_s_INFO_FMT "Sending Toolbox request, Tool=%x\n", - ioc->name, pReq->Tool)); + mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr); /* Append pCfg pointer to end of mf */ @@ -5248,11 +5191,11 @@ mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) /* Add to end of Q, set timer and then issue this command */ spin_lock_irqsave(&ioc->FreeQlock, flags); - Q_ADD_TAIL(&ioc->configQ.head, &pCfg->linkage, Q_ITEM); + list_add_tail(&pCfg->linkage, &ioc->configQ); spin_unlock_irqrestore(&ioc->FreeQlock, flags); add_timer(&pCfg->timer); - mpt_put_msg_frame(mpt_base_index, ioc->id, mf); + mpt_put_msg_frame(mpt_base_index, ioc, mf); wait_event(mpt_waitq, pCfg->wait_done); /* mf has been freed - do not access */ @@ -5263,8 +5206,8 @@ mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mpt_timer_expired - Call back for timer process. +/** + * mpt_timer_expired - Callback for timer process. * Used only internal config functionality. * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long */ @@ -5289,12 +5232,12 @@ mpt_timer_expired(unsigned long data) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_ioc_reset - Base cleanup for hard reset * @ioc: Pointer to the adapter structure * @reset_phase: Indicates pre- or post-reset functionality * - * Remark: Free's resources with internally generated commands. + * Remark: Frees resources with internally generated commands. */ static int mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) @@ -5315,13 +5258,8 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) * the FIFO's are primed. */ spin_lock_irqsave(&ioc->FreeQlock, flags); - if (! Q_IS_EMPTY(&ioc->configQ)){ - pCfg = (CONFIGPARMS *)ioc->configQ.head; - do { - del_timer(&pCfg->timer); - pCfg = (CONFIGPARMS *) (pCfg->linkage.forw); - } while (pCfg != (CONFIGPARMS *)&ioc->configQ); - } + list_for_each_entry(pCfg, &ioc->configQ, linkage) + del_timer(&pCfg->timer); spin_unlock_irqrestore(&ioc->FreeQlock, flags); } else { @@ -5331,19 +5269,12 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) * Flush the Q, and wake up all suspended threads. */ spin_lock_irqsave(&ioc->FreeQlock, flags); - if (! Q_IS_EMPTY(&ioc->configQ)){ - pCfg = (CONFIGPARMS *)ioc->configQ.head; - do { - pNext = (CONFIGPARMS *) pCfg->linkage.forw; + list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) { + list_del(&pCfg->linkage); - Q_DEL_ITEM(&pCfg->linkage); - - pCfg->status = MPT_CONFIG_ERROR; - pCfg->wait_done = 1; - wake_up(&mpt_waitq); - - pCfg = pNext; - } while (pCfg != (CONFIGPARMS *)&ioc->configQ); + pCfg->status = MPT_CONFIG_ERROR; + pCfg->wait_done = 1; + wake_up(&mpt_waitq); } spin_unlock_irqrestore(&ioc->FreeQlock, flags); } @@ -5358,7 +5289,7 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff... */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries. * * Returns 0 for success, non-zero for failure. @@ -5366,127 +5297,48 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) static int procmpt_create(void) { - MPT_ADAPTER *ioc; struct proc_dir_entry *ent; - int ii; - /* - * BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt" - * (single level) to multi level (e.g. "driver/message/fusion") - * something here needs to change. -sralston - */ mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL); if (mpt_proc_root_dir == NULL) return -ENOTDIR; - for (ii=0; ii < MPT_PROC_ENTRIES; ii++) { - ent = create_proc_entry(mpt_proc_list[ii].name, - S_IFREG|S_IRUGO, mpt_proc_root_dir); - if (!ent) { - printk(KERN_WARNING MYNAM - ": WARNING - Could not create /proc/mpt/%s entry\n", - mpt_proc_list[ii].name); - continue; - } - ent->read_proc = mpt_proc_list[ii].f; - ent->data = NULL; - } + ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir); + if (ent) + ent->read_proc = procmpt_summary_read; - ioc = mpt_adapter_find_first(); - while (ioc != NULL) { - struct proc_dir_entry *dent; - /* - * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter. - */ - if ((dent = proc_mkdir(ioc->name, mpt_proc_root_dir)) != NULL) { - /* - * And populate it with mpt_ioc_proc_list[] entries. - */ - for (ii=0; ii < MPT_IOC_PROC_ENTRIES; ii++) { - ent = create_proc_entry(mpt_ioc_proc_list[ii].name, - S_IFREG|S_IRUGO, dent); - if (!ent) { - printk(KERN_WARNING MYNAM - ": WARNING - Could not create /proc/mpt/%s/%s entry!\n", - ioc->name, - mpt_ioc_proc_list[ii].name); - continue; - } - ent->read_proc = mpt_ioc_proc_list[ii].f; - ent->data = ioc; - } - } else { - printk(MYIOC_s_WARN_FMT "Could not create /proc/mpt/%s subdir entry!\n", - ioc->name, mpt_ioc_proc_list[ii].name); - } - ioc = mpt_adapter_find_next(ioc); - } + ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir); + if (ent) + ent->read_proc = procmpt_version_read; return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries. * * Returns 0 for success, non-zero for failure. */ -static int +static void procmpt_destroy(void) { - MPT_ADAPTER *ioc; - int ii; - - if (!mpt_proc_root_dir) - return 0; - - /* - * BEWARE: If/when MPT_PROCFS_MPTBASEDIR changes from "mpt" - * (single level) to multi level (e.g. "driver/message/fusion") - * something here needs to change. -sralston - */ - - ioc = mpt_adapter_find_first(); - while (ioc != NULL) { - char pname[32]; - int namelen; - - namelen = sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name); - - /* - * Tear down each "/proc/mpt/iocN" subdirectory. - */ - for (ii=0; ii < MPT_IOC_PROC_ENTRIES; ii++) { - (void) sprintf(pname+namelen, "/%s", mpt_ioc_proc_list[ii].name); - remove_proc_entry(pname, NULL); - } - remove_proc_entry(ioc->name, mpt_proc_root_dir); - ioc = mpt_adapter_find_next(ioc); - } - - for (ii=0; ii < MPT_PROC_ENTRIES; ii++) - remove_proc_entry(mpt_proc_list[ii].name, mpt_proc_root_dir); - - if (atomic_read((atomic_t *)&mpt_proc_root_dir->count) == 0) { - remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL); - mpt_proc_root_dir = NULL; - return 0; - } - - return -1; + remove_proc_entry("version", mpt_proc_root_dir); + remove_proc_entry("summary", mpt_proc_root_dir); + remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * procmpt_summary_read - Handle read request from /proc/mpt/summary - * or from /proc/mpt/iocN/summary. +/** + * procmpt_summary_read - Handle read request of a summary file * @buf: Pointer to area to write information * @start: Pointer to start pointer * @offset: Offset to start writing - * @request: + * @request: Amount of read data requested * @eof: Pointer to EOF integer * @data: Pointer * + * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary. * Returns number of characters written to process performing the read. */ static int @@ -5496,38 +5348,37 @@ procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eo char *out = buf; int len; - if (data == NULL) - ioc = mpt_adapter_find_first(); - else - ioc = data; - - while (ioc) { - int more = 0; + if (data) { + int more = 0; + ioc = data; mpt_print_ioc_summary(ioc, out, &more, 0, 1); out += more; - if ((out-buf) >= request) { - break; - } + } else { + list_for_each_entry(ioc, &ioc_list, list) { + int more = 0; - if (data == NULL) - ioc = mpt_adapter_find_next(ioc); - else - ioc = NULL; /* force exit for iocN */ + mpt_print_ioc_summary(ioc, out, &more, 0, 1); + + out += more; + if ((out-buf) >= request) + break; + } } + len = out - buf; MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * procmpt_version_read - Handle read request from /proc/mpt/version. * @buf: Pointer to area to write information * @start: Pointer to start pointer * @offset: Offset to start writing - * @request: + * @request: Amount of read data requested * @eof: Pointer to EOF integer * @data: Pointer * @@ -5537,20 +5388,26 @@ static int procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data) { int ii; - int scsi, lan, ctl, targ, dmp; + int scsi, fc, sas, lan, ctl, targ, dmp; char *drvname; int len; len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON); len += sprintf(buf+len, " Fusion MPT base driver\n"); - scsi = lan = ctl = targ = dmp = 0; + scsi = fc = sas = lan = ctl = targ = dmp = 0; for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { drvname = NULL; if (MptCallbacks[ii]) { switch (MptDriverClass[ii]) { - case MPTSCSIH_DRIVER: - if (!scsi++) drvname = "SCSI host"; + case MPTSPI_DRIVER: + if (!scsi++) drvname = "SPI host"; + break; + case MPTFC_DRIVER: + if (!fc++) drvname = "FC host"; + break; + case MPTSAS_DRIVER: + if (!sas++) drvname = "SAS host"; break; case MPTLAN_DRIVER: if (!lan++) drvname = "LAN"; @@ -5561,19 +5418,10 @@ procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eo case MPTCTL_DRIVER: if (!ctl++) drvname = "ioctl"; break; - case MPTDMP_DRIVER: - if (!dmp++) drvname = "DMP"; - break; } if (drvname) len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname); - /* - * Handle isense special case, because it - * doesn't do a formal mpt_register call. - */ - if (isense_idx == ii) - len += sprintf(buf+len, " Fusion MPT isense driver\n"); } } @@ -5581,12 +5429,12 @@ procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eo } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info. * @buf: Pointer to area to write information * @start: Pointer to start pointer * @offset: Offset to start writing - * @request: + * @request: Amount of read data requested * @eof: Pointer to EOF integer * @data: Pointer * @@ -5628,7 +5476,7 @@ procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eo len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize); len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n", - (void *)ioc->req_alloc, (void *)(ulong)ioc->req_alloc_dma); + (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma); /* * Rounding UP to nearest 4-kB boundary here... */ @@ -5640,8 +5488,8 @@ procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eo 4*ioc->facts.RequestFrameSize, ioc->facts.GlobalCredits); - len += sprintf(buf+len, " ReplyFrames @ 0x%p (Dma @ 0x%p)\n", - (void *)ioc->reply_alloc, (void *)(ulong)ioc->reply_alloc_dma); + len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n", + (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma); sz = (ioc->reply_sz * ioc->reply_depth) + 128; len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n", ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz); @@ -5658,7 +5506,7 @@ procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eo len += sprintf(buf+len, " PortNumber = %d (of %d)\n", p+1, ioc->facts.NumberOfPorts); - if ((int)ioc->chip_type <= (int)FC929) { + if (ioc->bus_type == FC) { if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", @@ -5731,11 +5579,7 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh a[5], a[4], a[3], a[2], a[1], a[0]); } -#ifndef __sparc__ y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq); -#else - y += sprintf(buffer+len+y, ", IRQ=%s", __irq_itoa(ioc->pci_irq)); -#endif if (!ioc->active) y += sprintf(buffer+len+y, " (disabled)"); @@ -5751,16 +5595,17 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_HardResetHandler - Generic reset handler, issue SCSI Task - * Management call based on input arg values. If TaskMgmt fails, - * return associated SCSI request. + * mpt_HardResetHandler - Generic reset handler * @ioc: Pointer to MPT_ADAPTER structure * @sleepFlag: Indicates if sleep or schedule must be called. * + * Issues SCSI Task Management call based on input arg values. + * If TaskMgmt fails, returns associated SCSI request. + * * Remark: _HardResetHandler can be invoked from an interrupt thread (timer) * or a non-interrupt thread. In the former, must not call schedule(). * - * Remark: A return of -1 is a FATAL error case, as it means a + * Note: A return of -1 is a FATAL error case, as it means a * FW reload/initialization failed. * * Returns 0 for SUCCESS or -1 if FAILED. @@ -5794,7 +5639,7 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) /* The SCSI driver needs to adjust timeouts on all current * commands prior to the diagnostic reset being issued. - * Prevents timeouts occuring during a diagnostic reset...very bad. + * Prevents timeouts occurring during a diagnostic reset...very bad. * For all other protocol drivers, this is a no-op. */ { @@ -5805,11 +5650,11 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) if (MptResetHandlers[ii]) { dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n", ioc->name, ii)); - r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_SETUP_RESET); + r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET); if (ioc->alt_ioc) { dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n", ioc->name, ioc->alt_ioc->name, ii)); - r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_SETUP_RESET); + r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET); } } } @@ -5834,11 +5679,13 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) return rc; } +# define EVENT_DESCR_STR_SZ 100 + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static char * -EventDescriptionStr(u8 event, u32 evData0) +static void +EventDescriptionStr(u8 event, u32 evData0, char *evStr) { - char *ds; + char *ds = NULL; switch(event) { case MPI_EVENT_NONE: @@ -5875,22 +5722,226 @@ EventDescriptionStr(u8 event, u32 evData0) if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP) ds = "Loop State(LIP) Change"; else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE) - ds = "Loop State(LPE) Change"; /* ??? */ + ds = "Loop State(LPE) Change"; /* ??? */ else - ds = "Loop State(LPB) Change"; /* ??? */ + ds = "Loop State(LPB) Change"; /* ??? */ break; case MPI_EVENT_LOGOUT: ds = "Logout"; break; case MPI_EVENT_EVENT_CHANGE: if (evData0) - ds = "Events(ON) Change"; + ds = "Events ON"; else - ds = "Events(OFF) Change"; + ds = "Events OFF"; break; case MPI_EVENT_INTEGRATED_RAID: - ds = "Integrated Raid"; + { + u8 ReasonCode = (u8)(evData0 >> 16); + switch (ReasonCode) { + case MPI_EVENT_RAID_RC_VOLUME_CREATED : + ds = "Integrated Raid: Volume Created"; + break; + case MPI_EVENT_RAID_RC_VOLUME_DELETED : + ds = "Integrated Raid: Volume Deleted"; + break; + case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED : + ds = "Integrated Raid: Volume Settings Changed"; + break; + case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED : + ds = "Integrated Raid: Volume Status Changed"; + break; + case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED : + ds = "Integrated Raid: Volume Physdisk Changed"; + break; + case MPI_EVENT_RAID_RC_PHYSDISK_CREATED : + ds = "Integrated Raid: Physdisk Created"; + break; + case MPI_EVENT_RAID_RC_PHYSDISK_DELETED : + ds = "Integrated Raid: Physdisk Deleted"; + break; + case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED : + ds = "Integrated Raid: Physdisk Settings Changed"; + break; + case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED : + ds = "Integrated Raid: Physdisk Status Changed"; + break; + case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED : + ds = "Integrated Raid: Domain Validation Needed"; + break; + case MPI_EVENT_RAID_RC_SMART_DATA : + ds = "Integrated Raid; Smart Data"; + break; + case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED : + ds = "Integrated Raid: Replace Action Started"; + break; + default: + ds = "Integrated Raid"; + break; + } + break; + } + case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE: + ds = "SCSI Device Status Change"; + break; + case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: + { + u8 id = (u8)(evData0); + u8 ReasonCode = (u8)(evData0 >> 16); + switch (ReasonCode) { + case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Added: id=%d", id); + break; + case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Deleted: id=%d", id); + break; + case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: SMART Data: id=%d", + id); + break; + case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: No Persistancy: id=%d", id); + break; + case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Internal Device Reset : id=%d", id); + break; + case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Internal Task Abort : id=%d", id); + break; + case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Internal Abort Task Set : id=%d", id); + break; + case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Internal Clear Task Set : id=%d", id); + break; + case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Internal Query Task : id=%d", id); + break; + default: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS Device Status Change: Unknown: id=%d", id); + break; + } + break; + } + case MPI_EVENT_ON_BUS_TIMER_EXPIRED: + ds = "Bus Timer Expired"; + break; + case MPI_EVENT_QUEUE_FULL: + ds = "Queue Full"; + break; + case MPI_EVENT_SAS_SES: + ds = "SAS SES Event"; + break; + case MPI_EVENT_PERSISTENT_TABLE_FULL: + ds = "Persistent Table Full"; + break; + case MPI_EVENT_SAS_PHY_LINK_STATUS: + { + u8 LinkRates = (u8)(evData0 >> 8); + u8 PhyNumber = (u8)(evData0); + LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >> + MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT; + switch (LinkRates) { + case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" + " Rate Unknown",PhyNumber); + break; + case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" + " Phy Disabled",PhyNumber); + break; + case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" + " Failed Speed Nego",PhyNumber); + break; + case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" + " Sata OOB Completed",PhyNumber); + break; + case MPI_EVENT_SAS_PLS_LR_RATE_1_5: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" + " Rate 1.5 Gbps",PhyNumber); + break; + case MPI_EVENT_SAS_PLS_LR_RATE_3_0: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d:" + " Rate 3.0 Gpbs",PhyNumber); + break; + default: + snprintf(evStr, EVENT_DESCR_STR_SZ, + "SAS PHY Link Status: Phy=%d", PhyNumber); + break; + } + break; + } + case MPI_EVENT_SAS_DISCOVERY_ERROR: + ds = "SAS Discovery Error"; + break; + case MPI_EVENT_IR_RESYNC_UPDATE: + { + u8 resync_complete = (u8)(evData0 >> 16); + snprintf(evStr, EVENT_DESCR_STR_SZ, + "IR Resync Update: Complete = %d:",resync_complete); + break; + } + case MPI_EVENT_IR2: + { + u8 ReasonCode = (u8)(evData0 >> 16); + switch (ReasonCode) { + case MPI_EVENT_IR2_RC_LD_STATE_CHANGED: + ds = "IR2: LD State Changed"; + break; + case MPI_EVENT_IR2_RC_PD_STATE_CHANGED: + ds = "IR2: PD State Changed"; + break; + case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL: + ds = "IR2: Bad Block Table Full"; + break; + case MPI_EVENT_IR2_RC_PD_INSERTED: + ds = "IR2: PD Inserted"; + break; + case MPI_EVENT_IR2_RC_PD_REMOVED: + ds = "IR2: PD Removed"; + break; + case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: + ds = "IR2: Foreign CFG Detected"; + break; + case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR: + ds = "IR2: Rebuild Medium Error"; + break; + default: + ds = "IR2"; break; + } + break; + } + case MPI_EVENT_SAS_DISCOVERY: + { + if (evData0) + ds = "SAS Discovery: Start"; + else + ds = "SAS Discovery: Stop"; + break; + } + case MPI_EVENT_LOG_ENTRY_ADDED: + ds = "SAS Log Entry Added"; + break; + /* * MPT base "custom" events may be added here... */ @@ -5898,17 +5949,19 @@ EventDescriptionStr(u8 event, u32 evData0) ds = "Unknown"; break; } - return ds; + if (ds) + strncpy(evStr, ds, EVENT_DESCR_STR_SZ); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * ProcessEventNotification - Route a received EventNotificationReply to - * all currently regeistered event handlers. +/** + * ProcessEventNotification - Route EventNotificationReply to all event handlers * @ioc: Pointer to MPT_ADAPTER structure * @pEventReply: Pointer to EventNotification reply frame * @evHandlers: Pointer to integer, number of event handlers * + * Routes a received EventNotificationReply to all currently registered + * event handlers. * Returns sum of event handlers return values. */ static int @@ -5920,7 +5973,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply int ii; int r = 0; int handlers = 0; - char *evStr; + char evStr[EVENT_DESCR_STR_SZ]; u8 event; /* @@ -5933,13 +5986,13 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply evData0 = le32_to_cpu(pEventReply->Data[0]); } - evStr = EventDescriptionStr(event, evData0); - dprintk((MYIOC_s_INFO_FMT "MPT event (%s=%02Xh) detected!\n", + EventDescriptionStr(event, evData0, evStr); + devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n", ioc->name, - evStr, - event)); + event, + evStr)); -#if defined(MPT_DEBUG) || defined(MPT_DEBUG_EVENTS) +#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS) printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO); for (ii = 0; ii < evDataLen; ii++) printk(" %08x", le32_to_cpu(pEventReply->Data[ii])); @@ -5950,20 +6003,6 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply * Do general / base driver event processing */ switch(event) { - case MPI_EVENT_NONE: /* 00 */ - case MPI_EVENT_LOG_DATA: /* 01 */ - case MPI_EVENT_STATE_CHANGE: /* 02 */ - case MPI_EVENT_UNIT_ATTENTION: /* 03 */ - case MPI_EVENT_IOC_BUS_RESET: /* 04 */ - case MPI_EVENT_EXT_BUS_RESET: /* 05 */ - case MPI_EVENT_RESCAN: /* 06 */ - case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ - case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ - case MPI_EVENT_LOGOUT: /* 09 */ - case MPI_EVENT_INTEGRATED_RAID: /* 0B */ - case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE: /* 0C */ - default: - break; case MPI_EVENT_EVENT_CHANGE: /* 0A */ if (evDataLen) { u8 evState = evData0 & 0xFF; @@ -5976,6 +6015,12 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply } } break; + case MPI_EVENT_INTEGRATED_RAID: + mptbase_raid_process_event_data(ioc, + (MpiEventDataRaid_t *)pEventReply->Data); + break; + default: + break; } /* @@ -5985,7 +6030,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply if (ioc->events && (ioc->eventTypes & ( 1 << event))) { int idx; - idx = ioc->eventContext % ioc->eventLogSize; + idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE; ioc->events[idx].event = event; ioc->events[idx].eventContext = ioc->eventContext; @@ -6006,7 +6051,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply */ for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { if (MptEvHandlers[ii]) { - dprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n", + devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n", ioc->name, ii)); r += (*(MptEvHandlers[ii]))(ioc, pEventReply); handlers++; @@ -6018,9 +6063,11 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply * If needed, send (a single) EventAck. */ if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) { + devtverboseprintk((MYIOC_s_WARN_FMT + "EventAck required\n",ioc->name)); if ((ii = SendEventAck(ioc, pEventReply)) != 0) { - printk(MYIOC_s_WARN_FMT "SendEventAck returned %d\n", - ioc->name, ii); + devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n", + ioc->name, ii)); } } @@ -6029,12 +6076,12 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * mpt_fc_log_info - Log information returned from Fibre Channel IOC. * @ioc: Pointer to MPT_ADAPTER structure * @log_info: U32 LogInfo reply word from the IOC * - * Refer to lsi/fc_log.h. + * Refer to lsi/mpi_log_fc.h. */ static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info) @@ -6044,15 +6091,14 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info) "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info" }; u8 subcl = (log_info >> 24) & 0x7; -// u32 SubCl = log_info & 0x27000000; - printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}", + printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n", ioc->name, log_info, subcl_str[subcl]); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mpt_sp_log_info - Log information returned from SCSI Parallel IOC. +/** + * mpt_spi_log_info - Log information returned from SCSI Parallel IOC. * @ioc: Pointer to MPT_ADAPTER structure * @mr: Pointer to MPT reply frame * @log_info: U32 LogInfo word from the IOC @@ -6060,7 +6106,7 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info) * Refer to lsi/sp_log.h. */ static void -mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info) +mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) { u32 info = log_info & 0x00FF0000; char *desc = "unknown"; @@ -6099,7 +6145,7 @@ mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info) case 0x00080000: desc = "Outbound DMA Overrun"; break; - + case 0x00090000: desc = "Task Management"; break; @@ -6115,14 +6161,121 @@ mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info) case 0x000C0000: desc = "Untagged Table Size"; break; - + } printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc); } +/* strings for sas loginfo */ + static char *originator_str[] = { + "IOP", /* 00h */ + "PL", /* 01h */ + "IR" /* 02h */ + }; + static char *iop_code_str[] = { + NULL, /* 00h */ + "Invalid SAS Address", /* 01h */ + NULL, /* 02h */ + "Invalid Page", /* 03h */ + "Diag Message Error", /* 04h */ + "Task Terminated", /* 05h */ + "Enclosure Management", /* 06h */ + "Target Mode" /* 07h */ + }; + static char *pl_code_str[] = { + NULL, /* 00h */ + "Open Failure", /* 01h */ + "Invalid Scatter Gather List", /* 02h */ + "Wrong Relative Offset or Frame Length", /* 03h */ + "Frame Transfer Error", /* 04h */ + "Transmit Frame Connected Low", /* 05h */ + "SATA Non-NCQ RW Error Bit Set", /* 06h */ + "SATA Read Log Receive Data Error", /* 07h */ + "SATA NCQ Fail All Commands After Error", /* 08h */ + "SATA Error in Receive Set Device Bit FIS", /* 09h */ + "Receive Frame Invalid Message", /* 0Ah */ + "Receive Context Message Valid Error", /* 0Bh */ + "Receive Frame Current Frame Error", /* 0Ch */ + "SATA Link Down", /* 0Dh */ + "Discovery SATA Init W IOS", /* 0Eh */ + "Config Invalid Page", /* 0Fh */ + "Discovery SATA Init Timeout", /* 10h */ + "Reset", /* 11h */ + "Abort", /* 12h */ + "IO Not Yet Executed", /* 13h */ + "IO Executed", /* 14h */ + "Persistent Reservation Out Not Affiliation Owner", /* 15h */ + "Open Transmit DMA Abort", /* 16h */ + "IO Device Missing Delay Retry", /* 17h */ + NULL, /* 18h */ + NULL, /* 19h */ + NULL, /* 1Ah */ + NULL, /* 1Bh */ + NULL, /* 1Ch */ + NULL, /* 1Dh */ + NULL, /* 1Eh */ + NULL, /* 1Fh */ + "Enclosure Management" /* 20h */ + }; + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** + * mpt_sas_log_info - Log information returned from SAS IOC. + * @ioc: Pointer to MPT_ADAPTER structure + * @log_info: U32 LogInfo reply word from the IOC + * + * Refer to lsi/mpi_log_sas.h. + */ +static void +mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info) +{ +union loginfo_type { + u32 loginfo; + struct { + u32 subcode:16; + u32 code:8; + u32 originator:4; + u32 bus_type:4; + }dw; +}; + union loginfo_type sas_loginfo; + char *code_desc = NULL; + + sas_loginfo.loginfo = log_info; + if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) && + (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*))) + return; + if ((sas_loginfo.dw.originator == 0 /*IOP*/) && + (sas_loginfo.dw.code < sizeof(iop_code_str)/sizeof(char*))) { + code_desc = iop_code_str[sas_loginfo.dw.code]; + }else if ((sas_loginfo.dw.originator == 1 /*PL*/) && + (sas_loginfo.dw.code < sizeof(pl_code_str)/sizeof(char*) )) { + code_desc = pl_code_str[sas_loginfo.dw.code]; + } + + if (code_desc != NULL) + printk(MYIOC_s_INFO_FMT + "LogInfo(0x%08x): Originator={%s}, Code={%s}," + " SubCode(0x%04x)\n", + ioc->name, + log_info, + originator_str[sas_loginfo.dw.originator], + code_desc, + sas_loginfo.dw.subcode); + else + printk(MYIOC_s_INFO_FMT + "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x)," + " SubCode(0x%04x)\n", + ioc->name, + log_info, + originator_str[sas_loginfo.dw.originator], + sas_loginfo.dw.code, + sas_loginfo.dw.subcode); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC. * @ioc: Pointer to MPT_ADAPTER structure * @ioc_status: U32 IOCStatus word from IOC @@ -6134,7 +6287,7 @@ static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf) { u32 status = ioc_status & MPI_IOCSTATUS_MASK; - char *desc = ""; + char *desc = NULL; switch (status) { case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */ @@ -6207,7 +6360,7 @@ mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf) break; case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ - /* This error is checked in scsi_io_done(). Skip. + /* This error is checked in scsi_io_done(). Skip. desc = "SCSI Data Underrun"; */ break; @@ -6244,58 +6397,19 @@ mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf) desc = "Others"; break; } - if (desc != "") + if (desc != NULL) printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mpt_register_ascqops_strings - Register SCSI ASC/ASCQ and SCSI - * OpCode strings from the (optional) isense module. - * @ascqTable: Pointer to ASCQ_Table_t structure - * @ascqtbl_sz: Number of entries in ASCQ_Table - * @opsTable: Pointer to array of SCSI OpCode strings (char pointers) - * - * Specialized driver registration routine for the isense driver. - */ -int -mpt_register_ascqops_strings(void *ascqTable, int ascqtbl_sz, const char **opsTable) -{ - int r = 0; - - if (ascqTable && ascqtbl_sz && opsTable) { - mpt_v_ASCQ_TablePtr = ascqTable; - mpt_ASCQ_TableSz = ascqtbl_sz; - mpt_ScsiOpcodesPtr = opsTable; - printk(KERN_INFO MYNAM ": English readable SCSI-3 strings enabled:-)\n"); - isense_idx = last_drv_idx; - r = 1; - } - return r; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/** - * mpt_deregister_ascqops_strings - Deregister SCSI ASC/ASCQ and SCSI - * OpCode strings from the isense driver. - * - * Specialized driver deregistration routine for the isense driver. - */ -void -mpt_deregister_ascqops_strings(void) -{ - mpt_v_ASCQ_TablePtr = NULL; - mpt_ASCQ_TableSz = 0; - mpt_ScsiOpcodesPtr = NULL; - printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n"); - isense_idx = -1; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - -EXPORT_SYMBOL(mpt_adapters); +EXPORT_SYMBOL(mpt_attach); +EXPORT_SYMBOL(mpt_detach); +#ifdef CONFIG_PM +EXPORT_SYMBOL(mpt_resume); +EXPORT_SYMBOL(mpt_suspend); +#endif +EXPORT_SYMBOL(ioc_list); EXPORT_SYMBOL(mpt_proc_root_dir); -EXPORT_SYMBOL(DmpService); EXPORT_SYMBOL(mpt_register); EXPORT_SYMBOL(mpt_deregister); EXPORT_SYMBOL(mpt_event_register); @@ -6308,11 +6422,7 @@ EXPORT_SYMBOL(mpt_get_msg_frame); EXPORT_SYMBOL(mpt_put_msg_frame); EXPORT_SYMBOL(mpt_free_msg_frame); EXPORT_SYMBOL(mpt_add_sge); -EXPORT_SYMBOL(mpt_add_chain); EXPORT_SYMBOL(mpt_send_handshake_request); -EXPORT_SYMBOL(mpt_handshake_req_reply_wait); -EXPORT_SYMBOL(mpt_adapter_find_first); -EXPORT_SYMBOL(mpt_adapter_find_next); EXPORT_SYMBOL(mpt_verify_adapter); EXPORT_SYMBOL(mpt_GetIocState); EXPORT_SYMBOL(mpt_print_ioc_summary); @@ -6320,35 +6430,13 @@ EXPORT_SYMBOL(mpt_lan_index); EXPORT_SYMBOL(mpt_stm_index); EXPORT_SYMBOL(mpt_HardResetHandler); EXPORT_SYMBOL(mpt_config); -EXPORT_SYMBOL(mpt_toolbox); EXPORT_SYMBOL(mpt_findImVolumes); -EXPORT_SYMBOL(mpt_read_ioc_pg_3); EXPORT_SYMBOL(mpt_alloc_fw_memory); EXPORT_SYMBOL(mpt_free_fw_memory); - -EXPORT_SYMBOL(mpt_register_ascqops_strings); -EXPORT_SYMBOL(mpt_deregister_ascqops_strings); -EXPORT_SYMBOL(mpt_v_ASCQ_TablePtr); -EXPORT_SYMBOL(mpt_ASCQ_TableSz); -EXPORT_SYMBOL(mpt_ScsiOpcodesPtr); - - -static struct pci_driver mptbase_driver = { - .name = "mptbase", - .id_table = mptbase_pci_table, - .probe = mptbase_probe, - .remove = __devexit_p(mptbase_remove), - .driver = { - .shutdown = mptbase_shutdown, - }, -#ifdef CONFIG_PM - .suspend = mptbase_suspend, - .resume = mptbase_resume, -#endif -}; +EXPORT_SYMBOL(mptbase_sas_persist_operation); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * fusion_init - Fusion MPT base driver initialization routine. * * Returns 0 for success, non-zero for failure. @@ -6357,17 +6445,10 @@ static int __init fusion_init(void) { int i; - int r; - - if (FusionInitCalled++) { - dprintk((KERN_INFO MYNAM ": INFO - Driver late-init entry point called\n")); - return 0; - } show_mptmod_ver(my_NAME, my_VERSION); printk(KERN_INFO COPYRIGHT "\n"); - Q_INIT(&MptAdapters, MPT_ADAPTER); /* set to empty */ for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) { MptCallbacks[i] = NULL; MptDriverClass[i] = MPTUNKNOWN_DRIVER; @@ -6375,10 +6456,7 @@ fusion_init(void) MptResetHandlers[i] = NULL; } - DmpService = NULL; - - /* NEW! 20010120 -sralston - * Register ourselves (mptbase) in order to facilitate + /* Register ourselves (mptbase) in order to facilitate * EventNotification handling. */ mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER); @@ -6391,19 +6469,14 @@ fusion_init(void) /* FIXME! */ } - r = pci_module_init(&mptbase_driver); - if(r) - return(r); - #ifdef CONFIG_PROC_FS (void) procmpt_create(); #endif - - return r; + return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* +/** * fusion_exit - Perform driver unload cleanup. * * This routine frees all resources associated with each MPT adapter @@ -6413,18 +6486,14 @@ static void __exit fusion_exit(void) { - dprintk((KERN_INFO MYNAM ": fusion_exit() called!\n")); + dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n")); + + mpt_reset_deregister(mpt_base_index); - /* Whups? 20010120 -sralston - * Moved this *above* removal of all MptAdapters! - */ #ifdef CONFIG_PROC_FS - (void) procmpt_destroy(); + procmpt_destroy(); #endif - pci_unregister_driver(&mptbase_driver); - mpt_reset_deregister(mpt_base_index); } - module_init(fusion_init); module_exit(fusion_exit);