Path: blob/master/drivers/message/fusion/mptbase.c
15109 views
/*1* linux/drivers/message/fusion/mptbase.c2* This is the Fusion MPT base driver which supports multiple3* (SCSI + LAN) specialized protocol drivers.4* For use with LSI PCI chip/adapter(s)5* running LSI Fusion MPT (Message Passing Technology) firmware.6*7* Copyright (c) 1999-2008 LSI Corporation8* (mailto:[email protected])9*10*/11/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/12/*13This program is free software; you can redistribute it and/or modify14it under the terms of the GNU General Public License as published by15the Free Software Foundation; version 2 of the License.1617This program is distributed in the hope that it will be useful,18but WITHOUT ANY WARRANTY; without even the implied warranty of19MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the20GNU General Public License for more details.2122NO WARRANTY23THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR24CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT25LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,26MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is27solely responsible for determining the appropriateness of using and28distributing the Program and assumes all risks associated with its29exercise of rights under this Agreement, including but not limited to30the risks and costs of program errors, damage to or loss of data,31programs or equipment, and unavailability or interruption of operations.3233DISCLAIMER OF LIABILITY34NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY35DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL36DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND37ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR38TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE39USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED40HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES4142You should have received a copy of the GNU General Public License43along with this program; if not, write to the Free Software44Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA45*/46/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/4748#include <linux/kernel.h>49#include <linux/module.h>50#include <linux/errno.h>51#include <linux/init.h>52#include <linux/seq_file.h>53#include <linux/slab.h>54#include <linux/types.h>55#include <linux/pci.h>56#include <linux/kdev_t.h>57#include <linux/blkdev.h>58#include <linux/delay.h>59#include <linux/interrupt.h> /* needed for in_interrupt() proto */60#include <linux/dma-mapping.h>61#include <asm/io.h>62#ifdef CONFIG_MTRR63#include <asm/mtrr.h>64#endif6566#include "mptbase.h"67#include "lsi/mpi_log_fc.h"6869/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/70#define my_NAME "Fusion MPT base driver"71#define my_VERSION MPT_LINUX_VERSION_COMMON72#define MYNAM "mptbase"7374MODULE_AUTHOR(MODULEAUTHOR);75MODULE_DESCRIPTION(my_NAME);76MODULE_LICENSE("GPL");77MODULE_VERSION(my_VERSION);7879/*80* cmd line parameters81*/8283static int mpt_msi_enable_spi;84module_param(mpt_msi_enable_spi, int, 0);85MODULE_PARM_DESC(mpt_msi_enable_spi,86" Enable MSI Support for SPI controllers (default=0)");8788static int mpt_msi_enable_fc;89module_param(mpt_msi_enable_fc, int, 0);90MODULE_PARM_DESC(mpt_msi_enable_fc,91" Enable MSI Support for FC controllers (default=0)");9293static int mpt_msi_enable_sas;94module_param(mpt_msi_enable_sas, int, 0);95MODULE_PARM_DESC(mpt_msi_enable_sas,96" Enable MSI Support for SAS controllers (default=0)");9798static int mpt_channel_mapping;99module_param(mpt_channel_mapping, int, 0);100MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");101102static int mpt_debug_level;103static int mpt_set_debug_level(const char *val, struct kernel_param *kp);104module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,105&mpt_debug_level, 0600);106MODULE_PARM_DESC(mpt_debug_level,107" debug level - refer to mptdebug.h - (default=0)");108109int mpt_fwfault_debug;110EXPORT_SYMBOL(mpt_fwfault_debug);111module_param(mpt_fwfault_debug, int, 0600);112MODULE_PARM_DESC(mpt_fwfault_debug,113"Enable detection of Firmware fault and halt Firmware on fault - (default=0)");114115static char MptCallbacksName[MPT_MAX_PROTOCOL_DRIVERS][50];116117#ifdef MFCNT118static int mfcounter = 0;119#define PRINT_MF_COUNT 20000120#endif121122/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/123/*124* Public data...125*/126127#define WHOINIT_UNKNOWN 0xAA128129/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/130/*131* Private data...132*/133/* Adapter link list */134LIST_HEAD(ioc_list);135/* Callback lookup table */136static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];137/* Protocol driver class lookup table */138static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];139/* Event handler lookup table */140static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];141/* Reset handler lookup table */142static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];143static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];144145#ifdef CONFIG_PROC_FS146static struct proc_dir_entry *mpt_proc_root_dir;147#endif148149/*150* Driver Callback Index's151*/152static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;153static u8 last_drv_idx;154155/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/156/*157* Forward protos...158*/159static irqreturn_t mpt_interrupt(int irq, void *bus_id);160static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,161MPT_FRAME_HDR *reply);162static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,163u32 *req, int replyBytes, u16 *u16reply, int maxwait,164int sleepFlag);165static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);166static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);167static void mpt_adapter_disable(MPT_ADAPTER *ioc);168static void mpt_adapter_dispose(MPT_ADAPTER *ioc);169170static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);171static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);172static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);173static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);174static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);175static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);176static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);177static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);178static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);179static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);180static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);181static int PrimeIocFifos(MPT_ADAPTER *ioc);182static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);183static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);184static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);185static int GetLanConfigPages(MPT_ADAPTER *ioc);186static int GetIoUnitPage2(MPT_ADAPTER *ioc);187int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);188static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);189static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);190static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);191static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);192static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);193static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,194int sleepFlag);195static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);196static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);197static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);198199#ifdef CONFIG_PROC_FS200static const struct file_operations mpt_summary_proc_fops;201static const struct file_operations mpt_version_proc_fops;202static const struct file_operations mpt_iocinfo_proc_fops;203#endif204static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);205206static int ProcessEventNotification(MPT_ADAPTER *ioc,207EventNotificationReply_t *evReply, int *evHandlers);208static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);209static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);210static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);211static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info , u8 cb_idx);212static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);213static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);214215/* module entry point */216static int __init fusion_init (void);217static void __exit fusion_exit (void);218219#define CHIPREG_READ32(addr) readl_relaxed(addr)220#define CHIPREG_READ32_dmasync(addr) readl(addr)221#define CHIPREG_WRITE32(addr,val) writel(val, addr)222#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)223#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)224225static void226pci_disable_io_access(struct pci_dev *pdev)227{228u16 command_reg;229230pci_read_config_word(pdev, PCI_COMMAND, &command_reg);231command_reg &= ~1;232pci_write_config_word(pdev, PCI_COMMAND, command_reg);233}234235static void236pci_enable_io_access(struct pci_dev *pdev)237{238u16 command_reg;239240pci_read_config_word(pdev, PCI_COMMAND, &command_reg);241command_reg |= 1;242pci_write_config_word(pdev, PCI_COMMAND, command_reg);243}244245static int mpt_set_debug_level(const char *val, struct kernel_param *kp)246{247int ret = param_set_int(val, kp);248MPT_ADAPTER *ioc;249250if (ret)251return ret;252253list_for_each_entry(ioc, &ioc_list, list)254ioc->debug_level = mpt_debug_level;255return 0;256}257258/**259* mpt_get_cb_idx - obtain cb_idx for registered driver260* @dclass: class driver enum261*262* Returns cb_idx, or zero means it wasn't found263**/264static u8265mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)266{267u8 cb_idx;268269for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)270if (MptDriverClass[cb_idx] == dclass)271return cb_idx;272return 0;273}274275/**276* mpt_is_discovery_complete - determine if discovery has completed277* @ioc: per adatper instance278*279* Returns 1 when discovery completed, else zero.280*/281static int282mpt_is_discovery_complete(MPT_ADAPTER *ioc)283{284ConfigExtendedPageHeader_t hdr;285CONFIGPARMS cfg;286SasIOUnitPage0_t *buffer;287dma_addr_t dma_handle;288int rc = 0;289290memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));291memset(&cfg, 0, sizeof(CONFIGPARMS));292hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;293hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;294hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;295cfg.cfghdr.ehdr = &hdr;296cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;297298if ((mpt_config(ioc, &cfg)))299goto out;300if (!hdr.ExtPageLength)301goto out;302303buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,304&dma_handle);305if (!buffer)306goto out;307308cfg.physAddr = dma_handle;309cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;310311if ((mpt_config(ioc, &cfg)))312goto out_free_consistent;313314if (!(buffer->PhyData[0].PortFlags &315MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))316rc = 1;317318out_free_consistent:319pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,320buffer, dma_handle);321out:322return rc;323}324325/**326* mpt_fault_reset_work - work performed on workq after ioc fault327* @work: input argument, used to derive ioc328*329**/330static void331mpt_fault_reset_work(struct work_struct *work)332{333MPT_ADAPTER *ioc =334container_of(work, MPT_ADAPTER, fault_reset_work.work);335u32 ioc_raw_state;336int rc;337unsigned long flags;338339if (ioc->ioc_reset_in_progress || !ioc->active)340goto out;341342ioc_raw_state = mpt_GetIocState(ioc, 0);343if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {344printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",345ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);346printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",347ioc->name, __func__);348rc = mpt_HardResetHandler(ioc, CAN_SLEEP);349printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,350__func__, (rc == 0) ? "success" : "failed");351ioc_raw_state = mpt_GetIocState(ioc, 0);352if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)353printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "354"reset (%04xh)\n", ioc->name, ioc_raw_state &355MPI_DOORBELL_DATA_MASK);356} else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {357if ((mpt_is_discovery_complete(ioc))) {358devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "359"discovery_quiesce_io flag\n", ioc->name));360ioc->sas_discovery_quiesce_io = 0;361}362}363364out:365/*366* Take turns polling alternate controller367*/368if (ioc->alt_ioc)369ioc = ioc->alt_ioc;370371/* rearm the timer */372spin_lock_irqsave(&ioc->taskmgmt_lock, flags);373if (ioc->reset_work_q)374queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,375msecs_to_jiffies(MPT_POLLING_INTERVAL));376spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);377}378379380/*381* Process turbo (context) reply...382*/383static void384mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)385{386MPT_FRAME_HDR *mf = NULL;387MPT_FRAME_HDR *mr = NULL;388u16 req_idx = 0;389u8 cb_idx;390391dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",392ioc->name, pa));393394switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {395case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:396req_idx = pa & 0x0000FFFF;397cb_idx = (pa & 0x00FF0000) >> 16;398mf = MPT_INDEX_2_MFPTR(ioc, req_idx);399break;400case MPI_CONTEXT_REPLY_TYPE_LAN:401cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);402/*403* Blind set of mf to NULL here was fatal404* after lan_reply says "freeme"405* Fix sort of combined with an optimization here;406* added explicit check for case where lan_reply407* was just returning 1 and doing nothing else.408* For this case skip the callback, but set up409* proper mf value first here:-)410*/411if ((pa & 0x58000000) == 0x58000000) {412req_idx = pa & 0x0000FFFF;413mf = MPT_INDEX_2_MFPTR(ioc, req_idx);414mpt_free_msg_frame(ioc, mf);415mb();416return;417break;418}419mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);420break;421case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:422cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);423mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);424break;425default:426cb_idx = 0;427BUG();428}429430/* Check for (valid) IO callback! */431if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||432MptCallbacks[cb_idx] == NULL) {433printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",434__func__, ioc->name, cb_idx);435goto out;436}437438if (MptCallbacks[cb_idx](ioc, mf, mr))439mpt_free_msg_frame(ioc, mf);440out:441mb();442}443444static void445mpt_reply(MPT_ADAPTER *ioc, u32 pa)446{447MPT_FRAME_HDR *mf;448MPT_FRAME_HDR *mr;449u16 req_idx;450u8 cb_idx;451int freeme;452453u32 reply_dma_low;454u16 ioc_stat;455456/* non-TURBO reply! Hmmm, something may be up...457* Newest turbo reply mechanism; get address458* via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!459*/460461/* Map DMA address of reply header to cpu address.462* pa is 32 bits - but the dma address may be 32 or 64 bits463* get offset based only only the low addresses464*/465466reply_dma_low = (pa <<= 1);467mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +468(reply_dma_low - ioc->reply_frames_low_dma));469470req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);471cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;472mf = MPT_INDEX_2_MFPTR(ioc, req_idx);473474dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",475ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));476DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);477478/* Check/log IOC log info479*/480ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);481if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {482u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);483if (ioc->bus_type == FC)484mpt_fc_log_info(ioc, log_info);485else if (ioc->bus_type == SPI)486mpt_spi_log_info(ioc, log_info);487else if (ioc->bus_type == SAS)488mpt_sas_log_info(ioc, log_info, cb_idx);489}490491if (ioc_stat & MPI_IOCSTATUS_MASK)492mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);493494/* Check for (valid) IO callback! */495if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||496MptCallbacks[cb_idx] == NULL) {497printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",498__func__, ioc->name, cb_idx);499freeme = 0;500goto out;501}502503freeme = MptCallbacks[cb_idx](ioc, mf, mr);504505out:506/* Flush (non-TURBO) reply with a WRITE! */507CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);508509if (freeme)510mpt_free_msg_frame(ioc, mf);511mb();512}513514/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/515/**516* mpt_interrupt - MPT adapter (IOC) specific interrupt handler.517* @irq: irq number (not used)518* @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure519*520* This routine is registered via the request_irq() kernel API call,521* and handles all interrupts generated from a specific MPT adapter522* (also referred to as a IO Controller or IOC).523* This routine must clear the interrupt from the adapter and does524* so by reading the reply FIFO. Multiple replies may be processed525* per single call to this routine.526*527* This routine handles register-level access of the adapter but528* dispatches (calls) a protocol-specific callback routine to handle529* the protocol-specific details of the MPT request completion.530*/531static irqreturn_t532mpt_interrupt(int irq, void *bus_id)533{534MPT_ADAPTER *ioc = bus_id;535u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);536537if (pa == 0xFFFFFFFF)538return IRQ_NONE;539540/*541* Drain the reply FIFO!542*/543do {544if (pa & MPI_ADDRESS_REPLY_A_BIT)545mpt_reply(ioc, pa);546else547mpt_turbo_reply(ioc, pa);548pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);549} while (pa != 0xFFFFFFFF);550551return IRQ_HANDLED;552}553554/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/555/**556* mptbase_reply - MPT base driver's callback routine557* @ioc: Pointer to MPT_ADAPTER structure558* @req: Pointer to original MPT request frame559* @reply: Pointer to MPT reply frame (NULL if TurboReply)560*561* MPT base driver's callback routine; all base driver562* "internal" request/reply processing is routed here.563* Currently used for EventNotification and EventAck handling.564*565* Returns 1 indicating original alloc'd request frame ptr566* should be freed, or 0 if it shouldn't.567*/568static int569mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)570{571EventNotificationReply_t *pEventReply;572u8 event;573int evHandlers;574int freereq = 1;575576switch (reply->u.hdr.Function) {577case MPI_FUNCTION_EVENT_NOTIFICATION:578pEventReply = (EventNotificationReply_t *)reply;579evHandlers = 0;580ProcessEventNotification(ioc, pEventReply, &evHandlers);581event = le32_to_cpu(pEventReply->Event) & 0xFF;582if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)583freereq = 0;584if (event != MPI_EVENT_EVENT_CHANGE)585break;586case MPI_FUNCTION_CONFIG:587case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:588ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;589if (reply) {590ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;591memcpy(ioc->mptbase_cmds.reply, reply,592min(MPT_DEFAULT_FRAME_SIZE,5934 * reply->u.reply.MsgLength));594}595if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {596ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;597complete(&ioc->mptbase_cmds.done);598} else599freereq = 0;600if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)601freereq = 1;602break;603case MPI_FUNCTION_EVENT_ACK:604devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT605"EventAck reply received\n", ioc->name));606break;607default:608printk(MYIOC_s_ERR_FMT609"Unexpected msg function (=%02Xh) reply received!\n",610ioc->name, reply->u.hdr.Function);611break;612}613614/*615* Conditionally tell caller to free the original616* EventNotification/EventAck/unexpected request frame!617*/618return freereq;619}620621/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/622/**623* mpt_register - Register protocol-specific main callback handler.624* @cbfunc: callback function pointer625* @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)626* @func_name: call function's name627*628* This routine is called by a protocol-specific driver (SCSI host,629* LAN, SCSI target) to register its reply callback routine. Each630* protocol-specific driver must do this before it will be able to631* use any IOC resources, such as obtaining request frames.632*633* NOTES: The SCSI protocol driver currently calls this routine thrice634* in order to register separate callbacks; one for "normal" SCSI IO;635* one for MptScsiTaskMgmt requests; one for Scan/DV requests.636*637* Returns u8 valued "handle" in the range (and S.O.D. order)638* {N,...,7,6,5,...,1} if successful.639* A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be640* considered an error by the caller.641*/642u8643mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name)644{645u8 cb_idx;646last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;647648/*649* Search for empty callback slot in this order: {N,...,7,6,5,...,1}650* (slot/handle 0 is reserved!)651*/652for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {653if (MptCallbacks[cb_idx] == NULL) {654MptCallbacks[cb_idx] = cbfunc;655MptDriverClass[cb_idx] = dclass;656MptEvHandlers[cb_idx] = NULL;657last_drv_idx = cb_idx;658memcpy(MptCallbacksName[cb_idx], func_name,659strlen(func_name) > 50 ? 50 : strlen(func_name));660break;661}662}663664return last_drv_idx;665}666667/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/668/**669* mpt_deregister - Deregister a protocol drivers resources.670* @cb_idx: previously registered callback handle671*672* Each protocol-specific driver should call this routine when its673* module is unloaded.674*/675void676mpt_deregister(u8 cb_idx)677{678if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {679MptCallbacks[cb_idx] = NULL;680MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;681MptEvHandlers[cb_idx] = NULL;682683last_drv_idx++;684}685}686687/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/688/**689* mpt_event_register - Register protocol-specific event callback handler.690* @cb_idx: previously registered (via mpt_register) callback handle691* @ev_cbfunc: callback function692*693* This routine can be called by one or more protocol-specific drivers694* if/when they choose to be notified of MPT events.695*696* Returns 0 for success.697*/698int699mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)700{701if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)702return -1;703704MptEvHandlers[cb_idx] = ev_cbfunc;705return 0;706}707708/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/709/**710* mpt_event_deregister - Deregister protocol-specific event callback handler711* @cb_idx: previously registered callback handle712*713* Each protocol-specific driver should call this routine714* when it does not (or can no longer) handle events,715* or when its module is unloaded.716*/717void718mpt_event_deregister(u8 cb_idx)719{720if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)721return;722723MptEvHandlers[cb_idx] = NULL;724}725726/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/727/**728* mpt_reset_register - Register protocol-specific IOC reset handler.729* @cb_idx: previously registered (via mpt_register) callback handle730* @reset_func: reset function731*732* This routine can be called by one or more protocol-specific drivers733* if/when they choose to be notified of IOC resets.734*735* Returns 0 for success.736*/737int738mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)739{740if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)741return -1;742743MptResetHandlers[cb_idx] = reset_func;744return 0;745}746747/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/748/**749* mpt_reset_deregister - Deregister protocol-specific IOC reset handler.750* @cb_idx: previously registered callback handle751*752* Each protocol-specific driver should call this routine753* when it does not (or can no longer) handle IOC reset handling,754* or when its module is unloaded.755*/756void757mpt_reset_deregister(u8 cb_idx)758{759if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)760return;761762MptResetHandlers[cb_idx] = NULL;763}764765/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/766/**767* mpt_device_driver_register - Register device driver hooks768* @dd_cbfunc: driver callbacks struct769* @cb_idx: MPT protocol driver index770*/771int772mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)773{774MPT_ADAPTER *ioc;775const struct pci_device_id *id;776777if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)778return -EINVAL;779780MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;781782/* call per pci device probe entry point */783list_for_each_entry(ioc, &ioc_list, list) {784id = ioc->pcidev->driver ?785ioc->pcidev->driver->id_table : NULL;786if (dd_cbfunc->probe)787dd_cbfunc->probe(ioc->pcidev, id);788}789790return 0;791}792793/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/794/**795* mpt_device_driver_deregister - DeRegister device driver hooks796* @cb_idx: MPT protocol driver index797*/798void799mpt_device_driver_deregister(u8 cb_idx)800{801struct mpt_pci_driver *dd_cbfunc;802MPT_ADAPTER *ioc;803804if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)805return;806807dd_cbfunc = MptDeviceDriverHandlers[cb_idx];808809list_for_each_entry(ioc, &ioc_list, list) {810if (dd_cbfunc->remove)811dd_cbfunc->remove(ioc->pcidev);812}813814MptDeviceDriverHandlers[cb_idx] = NULL;815}816817818/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/819/**820* mpt_get_msg_frame - Obtain an MPT request frame from the pool821* @cb_idx: Handle of registered MPT protocol driver822* @ioc: Pointer to MPT adapter structure823*824* Obtain an MPT request frame from the pool (of 1024) that are825* allocated per MPT adapter.826*827* Returns pointer to a MPT request frame or %NULL if none are available828* or IOC is not active.829*/830MPT_FRAME_HDR*831mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)832{833MPT_FRAME_HDR *mf;834unsigned long flags;835u16 req_idx; /* Request index */836837/* validate handle and ioc identifier */838839#ifdef MFCNT840if (!ioc->active)841printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "842"returning NULL!\n", ioc->name);843#endif844845/* If interrupts are not attached, do not return a request frame */846if (!ioc->active)847return NULL;848849spin_lock_irqsave(&ioc->FreeQlock, flags);850if (!list_empty(&ioc->FreeQ)) {851int req_offset;852853mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,854u.frame.linkage.list);855list_del(&mf->u.frame.linkage.list);856mf->u.frame.linkage.arg1 = 0;857mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */858req_offset = (u8 *)mf - (u8 *)ioc->req_frames;859/* u16! */860req_idx = req_offset / ioc->req_sz;861mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);862mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;863/* Default, will be changed if necessary in SG generation */864ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;865#ifdef MFCNT866ioc->mfcnt++;867#endif868}869else870mf = NULL;871spin_unlock_irqrestore(&ioc->FreeQlock, flags);872873#ifdef MFCNT874if (mf == NULL)875printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "876"Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,877ioc->req_depth);878mfcounter++;879if (mfcounter == PRINT_MF_COUNT)880printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,881ioc->mfcnt, ioc->req_depth);882#endif883884dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",885ioc->name, cb_idx, ioc->id, mf));886return mf;887}888889/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/890/**891* mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC892* @cb_idx: Handle of registered MPT protocol driver893* @ioc: Pointer to MPT adapter structure894* @mf: Pointer to MPT request frame895*896* This routine posts an MPT request frame to the request post FIFO of a897* specific MPT adapter.898*/899void900mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)901{902u32 mf_dma_addr;903int req_offset;904u16 req_idx; /* Request index */905906/* ensure values are reset properly! */907mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */908req_offset = (u8 *)mf - (u8 *)ioc->req_frames;909/* u16! */910req_idx = req_offset / ioc->req_sz;911mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);912mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;913914DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);915916mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];917dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "918"RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,919ioc->RequestNB[req_idx]));920CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);921}922923/**924* mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame925* @cb_idx: Handle of registered MPT protocol driver926* @ioc: Pointer to MPT adapter structure927* @mf: Pointer to MPT request frame928*929* Send a protocol-specific MPT request frame to an IOC using930* hi-priority request queue.931*932* This routine posts an MPT request frame to the request post FIFO of a933* specific MPT adapter.934**/935void936mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)937{938u32 mf_dma_addr;939int req_offset;940u16 req_idx; /* Request index */941942/* ensure values are reset properly! */943mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;944req_offset = (u8 *)mf - (u8 *)ioc->req_frames;945req_idx = req_offset / ioc->req_sz;946mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);947mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;948949DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);950951mf_dma_addr = (ioc->req_frames_low_dma + req_offset);952dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",953ioc->name, mf_dma_addr, req_idx));954CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);955}956957/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/958/**959* mpt_free_msg_frame - Place MPT request frame back on FreeQ.960* @ioc: Pointer to MPT adapter structure961* @mf: Pointer to MPT request frame962*963* This routine places a MPT request frame back on the MPT adapter's964* FreeQ.965*/966void967mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)968{969unsigned long flags;970971/* Put Request back on FreeQ! */972spin_lock_irqsave(&ioc->FreeQlock, flags);973if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf)974goto out;975/* signature to know if this mf is freed */976mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf);977list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);978#ifdef MFCNT979ioc->mfcnt--;980#endif981out:982spin_unlock_irqrestore(&ioc->FreeQlock, flags);983}984985/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/986/**987* mpt_add_sge - Place a simple 32 bit SGE at address pAddr.988* @pAddr: virtual address for SGE989* @flagslength: SGE flags and data transfer length990* @dma_addr: Physical address991*992* This routine places a MPT request frame back on the MPT adapter's993* FreeQ.994*/995static void996mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)997{998SGESimple32_t *pSge = (SGESimple32_t *) pAddr;999pSge->FlagsLength = cpu_to_le32(flagslength);1000pSge->Address = cpu_to_le32(dma_addr);1001}10021003/**1004* mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.1005* @pAddr: virtual address for SGE1006* @flagslength: SGE flags and data transfer length1007* @dma_addr: Physical address1008*1009* This routine places a MPT request frame back on the MPT adapter's1010* FreeQ.1011**/1012static void1013mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)1014{1015SGESimple64_t *pSge = (SGESimple64_t *) pAddr;1016pSge->Address.Low = cpu_to_le321017(lower_32_bits(dma_addr));1018pSge->Address.High = cpu_to_le321019(upper_32_bits(dma_addr));1020pSge->FlagsLength = cpu_to_le321021((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));1022}10231024/**1025* mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround).1026* @pAddr: virtual address for SGE1027* @flagslength: SGE flags and data transfer length1028* @dma_addr: Physical address1029*1030* This routine places a MPT request frame back on the MPT adapter's1031* FreeQ.1032**/1033static void1034mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)1035{1036SGESimple64_t *pSge = (SGESimple64_t *) pAddr;1037u32 tmp;10381039pSge->Address.Low = cpu_to_le321040(lower_32_bits(dma_addr));1041tmp = (u32)(upper_32_bits(dma_addr));10421043/*1044* 1078 errata workaround for the 36GB limitation1045*/1046if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {1047flagslength |=1048MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);1049tmp |= (1<<31);1050if (mpt_debug_level & MPT_DEBUG_36GB_MEM)1051printk(KERN_DEBUG "1078 P0M2 addressing for "1052"addr = 0x%llx len = %d\n",1053(unsigned long long)dma_addr,1054MPI_SGE_LENGTH(flagslength));1055}10561057pSge->Address.High = cpu_to_le32(tmp);1058pSge->FlagsLength = cpu_to_le32(1059(flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));1060}10611062/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1063/**1064* mpt_add_chain - Place a 32 bit chain SGE at address pAddr.1065* @pAddr: virtual address for SGE1066* @next: nextChainOffset value (u32's)1067* @length: length of next SGL segment1068* @dma_addr: Physical address1069*1070*/1071static void1072mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)1073{1074SGEChain32_t *pChain = (SGEChain32_t *) pAddr;1075pChain->Length = cpu_to_le16(length);1076pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;1077pChain->NextChainOffset = next;1078pChain->Address = cpu_to_le32(dma_addr);1079}10801081/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1082/**1083* mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.1084* @pAddr: virtual address for SGE1085* @next: nextChainOffset value (u32's)1086* @length: length of next SGL segment1087* @dma_addr: Physical address1088*1089*/1090static void1091mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)1092{1093SGEChain64_t *pChain = (SGEChain64_t *) pAddr;1094u32 tmp = dma_addr & 0xFFFFFFFF;10951096pChain->Length = cpu_to_le16(length);1097pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |1098MPI_SGE_FLAGS_64_BIT_ADDRESSING);10991100pChain->NextChainOffset = next;11011102pChain->Address.Low = cpu_to_le32(tmp);1103tmp = (u32)(upper_32_bits(dma_addr));1104pChain->Address.High = cpu_to_le32(tmp);1105}11061107/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1108/**1109* mpt_send_handshake_request - Send MPT request via doorbell handshake method.1110* @cb_idx: Handle of registered MPT protocol driver1111* @ioc: Pointer to MPT adapter structure1112* @reqBytes: Size of the request in bytes1113* @req: Pointer to MPT request frame1114* @sleepFlag: Use schedule if CAN_SLEEP else use udelay.1115*1116* This routine is used exclusively to send MptScsiTaskMgmt1117* requests since they are required to be sent via doorbell handshake.1118*1119* NOTE: It is the callers responsibility to byte-swap fields in the1120* request which are greater than 1 byte in size.1121*1122* Returns 0 for success, non-zero for failure.1123*/1124int1125mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)1126{1127int r = 0;1128u8 *req_as_bytes;1129int ii;11301131/* State is known to be good upon entering1132* this function so issue the bus reset1133* request.1134*/11351136/*1137* Emulate what mpt_put_msg_frame() does /wrt to sanity1138* setting cb_idx/req_idx. But ONLY if this request1139* is in proper (pre-alloc'd) request buffer range...1140*/1141ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);1142if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {1143MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;1144mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);1145mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;1146}11471148/* Make sure there are no doorbells */1149CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);11501151CHIPREG_WRITE32(&ioc->chip->Doorbell,1152((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |1153((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));11541155/* Wait for IOC doorbell int */1156if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {1157return ii;1158}11591160/* Read doorbell and check for active bit */1161if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))1162return -5;11631164dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",1165ioc->name, ii));11661167CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);11681169if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {1170return -2;1171}11721173/* Send request via doorbell handshake */1174req_as_bytes = (u8 *) req;1175for (ii = 0; ii < reqBytes/4; ii++) {1176u32 word;11771178word = ((req_as_bytes[(ii*4) + 0] << 0) |1179(req_as_bytes[(ii*4) + 1] << 8) |1180(req_as_bytes[(ii*4) + 2] << 16) |1181(req_as_bytes[(ii*4) + 3] << 24));1182CHIPREG_WRITE32(&ioc->chip->Doorbell, word);1183if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {1184r = -3;1185break;1186}1187}11881189if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)1190r = 0;1191else1192r = -4;11931194/* Make sure there are no doorbells */1195CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);11961197return r;1198}11991200/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1201/**1202* mpt_host_page_access_control - control the IOC's Host Page Buffer access1203* @ioc: Pointer to MPT adapter structure1204* @access_control_value: define bits below1205* @sleepFlag: Specifies whether the process can sleep1206*1207* Provides mechanism for the host driver to control the IOC's1208* Host Page Buffer access.1209*1210* Access Control Value - bits[15:12]1211* 0h Reserved1212* 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }1213* 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }1214* 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }1215*1216* Returns 0 for success, non-zero for failure.1217*/12181219static int1220mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)1221{1222int r = 0;12231224/* return if in use */1225if (CHIPREG_READ32(&ioc->chip->Doorbell)1226& MPI_DOORBELL_ACTIVE)1227return -1;12281229CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);12301231CHIPREG_WRITE32(&ioc->chip->Doorbell,1232((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL1233<<MPI_DOORBELL_FUNCTION_SHIFT) |1234(access_control_value<<12)));12351236/* Wait for IOC to clear Doorbell Status bit */1237if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {1238return -2;1239}else1240return 0;1241}12421243/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1244/**1245* mpt_host_page_alloc - allocate system memory for the fw1246* @ioc: Pointer to pointer to IOC adapter1247* @ioc_init: Pointer to ioc init config page1248*1249* If we already allocated memory in past, then resend the same pointer.1250* Returns 0 for success, non-zero for failure.1251*/1252static int1253mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)1254{1255char *psge;1256int flags_length;1257u32 host_page_buffer_sz=0;12581259if(!ioc->HostPageBuffer) {12601261host_page_buffer_sz =1262le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;12631264if(!host_page_buffer_sz)1265return 0; /* fw doesn't need any host buffers */12661267/* spin till we get enough memory */1268while(host_page_buffer_sz > 0) {12691270if((ioc->HostPageBuffer = pci_alloc_consistent(1271ioc->pcidev,1272host_page_buffer_sz,1273&ioc->HostPageBuffer_dma)) != NULL) {12741275dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT1276"host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",1277ioc->name, ioc->HostPageBuffer,1278(u32)ioc->HostPageBuffer_dma,1279host_page_buffer_sz));1280ioc->alloc_total += host_page_buffer_sz;1281ioc->HostPageBuffer_sz = host_page_buffer_sz;1282break;1283}12841285host_page_buffer_sz -= (4*1024);1286}1287}12881289if(!ioc->HostPageBuffer) {1290printk(MYIOC_s_ERR_FMT1291"Failed to alloc memory for host_page_buffer!\n",1292ioc->name);1293return -999;1294}12951296psge = (char *)&ioc_init->HostPageBufferSGE;1297flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |1298MPI_SGE_FLAGS_SYSTEM_ADDRESS |1299MPI_SGE_FLAGS_HOST_TO_IOC |1300MPI_SGE_FLAGS_END_OF_BUFFER;1301flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;1302flags_length |= ioc->HostPageBuffer_sz;1303ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);1304ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;13051306return 0;1307}13081309/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1310/**1311* mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.1312* @iocid: IOC unique identifier (integer)1313* @iocpp: Pointer to pointer to IOC adapter1314*1315* Given a unique IOC identifier, set pointer to the associated MPT1316* adapter structure.1317*1318* Returns iocid and sets iocpp if iocid is found.1319* Returns -1 if iocid is not found.1320*/1321int1322mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)1323{1324MPT_ADAPTER *ioc;13251326list_for_each_entry(ioc,&ioc_list,list) {1327if (ioc->id == iocid) {1328*iocpp =ioc;1329return iocid;1330}1331}13321333*iocpp = NULL;1334return -1;1335}13361337/**1338* mpt_get_product_name - returns product string1339* @vendor: pci vendor id1340* @device: pci device id1341* @revision: pci revision id1342* @prod_name: string returned1343*1344* Returns product string displayed when driver loads,1345* in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product1346*1347**/1348static void1349mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)1350{1351char *product_str = NULL;13521353if (vendor == PCI_VENDOR_ID_BROCADE) {1354switch (device)1355{1356case MPI_MANUFACTPAGE_DEVICEID_FC949E:1357switch (revision)1358{1359case 0x00:1360product_str = "BRE040 A0";1361break;1362case 0x01:1363product_str = "BRE040 A1";1364break;1365default:1366product_str = "BRE040";1367break;1368}1369break;1370}1371goto out;1372}13731374switch (device)1375{1376case MPI_MANUFACTPAGE_DEVICEID_FC909:1377product_str = "LSIFC909 B1";1378break;1379case MPI_MANUFACTPAGE_DEVICEID_FC919:1380product_str = "LSIFC919 B0";1381break;1382case MPI_MANUFACTPAGE_DEVICEID_FC929:1383product_str = "LSIFC929 B0";1384break;1385case MPI_MANUFACTPAGE_DEVICEID_FC919X:1386if (revision < 0x80)1387product_str = "LSIFC919X A0";1388else1389product_str = "LSIFC919XL A1";1390break;1391case MPI_MANUFACTPAGE_DEVICEID_FC929X:1392if (revision < 0x80)1393product_str = "LSIFC929X A0";1394else1395product_str = "LSIFC929XL A1";1396break;1397case MPI_MANUFACTPAGE_DEVICEID_FC939X:1398product_str = "LSIFC939X A1";1399break;1400case MPI_MANUFACTPAGE_DEVICEID_FC949X:1401product_str = "LSIFC949X A1";1402break;1403case MPI_MANUFACTPAGE_DEVICEID_FC949E:1404switch (revision)1405{1406case 0x00:1407product_str = "LSIFC949E A0";1408break;1409case 0x01:1410product_str = "LSIFC949E A1";1411break;1412default:1413product_str = "LSIFC949E";1414break;1415}1416break;1417case MPI_MANUFACTPAGE_DEVID_53C1030:1418switch (revision)1419{1420case 0x00:1421product_str = "LSI53C1030 A0";1422break;1423case 0x01:1424product_str = "LSI53C1030 B0";1425break;1426case 0x03:1427product_str = "LSI53C1030 B1";1428break;1429case 0x07:1430product_str = "LSI53C1030 B2";1431break;1432case 0x08:1433product_str = "LSI53C1030 C0";1434break;1435case 0x80:1436product_str = "LSI53C1030T A0";1437break;1438case 0x83:1439product_str = "LSI53C1030T A2";1440break;1441case 0x87:1442product_str = "LSI53C1030T A3";1443break;1444case 0xc1:1445product_str = "LSI53C1020A A1";1446break;1447default:1448product_str = "LSI53C1030";1449break;1450}1451break;1452case MPI_MANUFACTPAGE_DEVID_1030_53C1035:1453switch (revision)1454{1455case 0x03:1456product_str = "LSI53C1035 A2";1457break;1458case 0x04:1459product_str = "LSI53C1035 B0";1460break;1461default:1462product_str = "LSI53C1035";1463break;1464}1465break;1466case MPI_MANUFACTPAGE_DEVID_SAS1064:1467switch (revision)1468{1469case 0x00:1470product_str = "LSISAS1064 A1";1471break;1472case 0x01:1473product_str = "LSISAS1064 A2";1474break;1475case 0x02:1476product_str = "LSISAS1064 A3";1477break;1478case 0x03:1479product_str = "LSISAS1064 A4";1480break;1481default:1482product_str = "LSISAS1064";1483break;1484}1485break;1486case MPI_MANUFACTPAGE_DEVID_SAS1064E:1487switch (revision)1488{1489case 0x00:1490product_str = "LSISAS1064E A0";1491break;1492case 0x01:1493product_str = "LSISAS1064E B0";1494break;1495case 0x02:1496product_str = "LSISAS1064E B1";1497break;1498case 0x04:1499product_str = "LSISAS1064E B2";1500break;1501case 0x08:1502product_str = "LSISAS1064E B3";1503break;1504default:1505product_str = "LSISAS1064E";1506break;1507}1508break;1509case MPI_MANUFACTPAGE_DEVID_SAS1068:1510switch (revision)1511{1512case 0x00:1513product_str = "LSISAS1068 A0";1514break;1515case 0x01:1516product_str = "LSISAS1068 B0";1517break;1518case 0x02:1519product_str = "LSISAS1068 B1";1520break;1521default:1522product_str = "LSISAS1068";1523break;1524}1525break;1526case MPI_MANUFACTPAGE_DEVID_SAS1068E:1527switch (revision)1528{1529case 0x00:1530product_str = "LSISAS1068E A0";1531break;1532case 0x01:1533product_str = "LSISAS1068E B0";1534break;1535case 0x02:1536product_str = "LSISAS1068E B1";1537break;1538case 0x04:1539product_str = "LSISAS1068E B2";1540break;1541case 0x08:1542product_str = "LSISAS1068E B3";1543break;1544default:1545product_str = "LSISAS1068E";1546break;1547}1548break;1549case MPI_MANUFACTPAGE_DEVID_SAS1078:1550switch (revision)1551{1552case 0x00:1553product_str = "LSISAS1078 A0";1554break;1555case 0x01:1556product_str = "LSISAS1078 B0";1557break;1558case 0x02:1559product_str = "LSISAS1078 C0";1560break;1561case 0x03:1562product_str = "LSISAS1078 C1";1563break;1564case 0x04:1565product_str = "LSISAS1078 C2";1566break;1567default:1568product_str = "LSISAS1078";1569break;1570}1571break;1572}15731574out:1575if (product_str)1576sprintf(prod_name, "%s", product_str);1577}15781579/**1580* mpt_mapresources - map in memory mapped io1581* @ioc: Pointer to pointer to IOC adapter1582*1583**/1584static int1585mpt_mapresources(MPT_ADAPTER *ioc)1586{1587u8 __iomem *mem;1588int ii;1589resource_size_t mem_phys;1590unsigned long port;1591u32 msize;1592u32 psize;1593u8 revision;1594int r = -ENODEV;1595struct pci_dev *pdev;15961597pdev = ioc->pcidev;1598ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);1599if (pci_enable_device_mem(pdev)) {1600printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "1601"failed\n", ioc->name);1602return r;1603}1604if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {1605printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "1606"MEM failed\n", ioc->name);1607return r;1608}16091610pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);16111612if (sizeof(dma_addr_t) > 4) {1613const uint64_t required_mask = dma_get_required_mask1614(&pdev->dev);1615if (required_mask > DMA_BIT_MASK(32)1616&& !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))1617&& !pci_set_consistent_dma_mask(pdev,1618DMA_BIT_MASK(64))) {1619ioc->dma_mask = DMA_BIT_MASK(64);1620dinitprintk(ioc, printk(MYIOC_s_INFO_FMT1621": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",1622ioc->name));1623} else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))1624&& !pci_set_consistent_dma_mask(pdev,1625DMA_BIT_MASK(32))) {1626ioc->dma_mask = DMA_BIT_MASK(32);1627dinitprintk(ioc, printk(MYIOC_s_INFO_FMT1628": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",1629ioc->name));1630} else {1631printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",1632ioc->name, pci_name(pdev));1633pci_release_selected_regions(pdev, ioc->bars);1634return r;1635}1636} else {1637if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))1638&& !pci_set_consistent_dma_mask(pdev,1639DMA_BIT_MASK(32))) {1640ioc->dma_mask = DMA_BIT_MASK(32);1641dinitprintk(ioc, printk(MYIOC_s_INFO_FMT1642": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",1643ioc->name));1644} else {1645printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",1646ioc->name, pci_name(pdev));1647pci_release_selected_regions(pdev, ioc->bars);1648return r;1649}1650}16511652mem_phys = msize = 0;1653port = psize = 0;1654for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {1655if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {1656if (psize)1657continue;1658/* Get I/O space! */1659port = pci_resource_start(pdev, ii);1660psize = pci_resource_len(pdev, ii);1661} else {1662if (msize)1663continue;1664/* Get memmap */1665mem_phys = pci_resource_start(pdev, ii);1666msize = pci_resource_len(pdev, ii);1667}1668}1669ioc->mem_size = msize;16701671mem = NULL;1672/* Get logical ptr for PciMem0 space */1673/*mem = ioremap(mem_phys, msize);*/1674mem = ioremap(mem_phys, msize);1675if (mem == NULL) {1676printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"1677" memory!\n", ioc->name);1678pci_release_selected_regions(pdev, ioc->bars);1679return -EINVAL;1680}1681ioc->memmap = mem;1682dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %llx\n",1683ioc->name, mem, (unsigned long long)mem_phys));16841685ioc->mem_phys = mem_phys;1686ioc->chip = (SYSIF_REGS __iomem *)mem;16871688/* Save Port IO values in case we need to do downloadboot */1689ioc->pio_mem_phys = port;1690ioc->pio_chip = (SYSIF_REGS __iomem *)port;16911692return 0;1693}16941695/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1696/**1697* mpt_attach - Install a PCI intelligent MPT adapter.1698* @pdev: Pointer to pci_dev structure1699* @id: PCI device ID information1700*1701* This routine performs all the steps necessary to bring the IOC of1702* a MPT adapter to a OPERATIONAL state. This includes registering1703* memory regions, registering the interrupt, and allocating request1704* and reply memory pools.1705*1706* This routine also pre-fetches the LAN MAC address of a Fibre Channel1707* MPT adapter.1708*1709* Returns 0 for success, non-zero for failure.1710*1711* TODO: Add support for polled controllers1712*/1713int1714mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)1715{1716MPT_ADAPTER *ioc;1717u8 cb_idx;1718int r = -ENODEV;1719u8 revision;1720u8 pcixcmd;1721static int mpt_ids = 0;1722#ifdef CONFIG_PROC_FS1723struct proc_dir_entry *dent;1724#endif17251726ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);1727if (ioc == NULL) {1728printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");1729return -ENOMEM;1730}17311732ioc->id = mpt_ids++;1733sprintf(ioc->name, "ioc%d", ioc->id);1734dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));17351736/*1737* set initial debug level1738* (refer to mptdebug.h)1739*1740*/1741ioc->debug_level = mpt_debug_level;1742if (mpt_debug_level)1743printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);17441745dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));17461747ioc->pcidev = pdev;1748if (mpt_mapresources(ioc)) {1749kfree(ioc);1750return r;1751}17521753/*1754* Setting up proper handlers for scatter gather handling1755*/1756if (ioc->dma_mask == DMA_BIT_MASK(64)) {1757if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)1758ioc->add_sge = &mpt_add_sge_64bit_1078;1759else1760ioc->add_sge = &mpt_add_sge_64bit;1761ioc->add_chain = &mpt_add_chain_64bit;1762ioc->sg_addr_size = 8;1763} else {1764ioc->add_sge = &mpt_add_sge;1765ioc->add_chain = &mpt_add_chain;1766ioc->sg_addr_size = 4;1767}1768ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;17691770ioc->alloc_total = sizeof(MPT_ADAPTER);1771ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */1772ioc->reply_sz = MPT_REPLY_FRAME_SIZE;177317741775spin_lock_init(&ioc->taskmgmt_lock);1776mutex_init(&ioc->internal_cmds.mutex);1777init_completion(&ioc->internal_cmds.done);1778mutex_init(&ioc->mptbase_cmds.mutex);1779init_completion(&ioc->mptbase_cmds.done);1780mutex_init(&ioc->taskmgmt_cmds.mutex);1781init_completion(&ioc->taskmgmt_cmds.done);17821783/* Initialize the event logging.1784*/1785ioc->eventTypes = 0; /* None */1786ioc->eventContext = 0;1787ioc->eventLogSize = 0;1788ioc->events = NULL;17891790#ifdef MFCNT1791ioc->mfcnt = 0;1792#endif17931794ioc->sh = NULL;1795ioc->cached_fw = NULL;17961797/* Initialize SCSI Config Data structure1798*/1799memset(&ioc->spi_data, 0, sizeof(SpiCfgData));18001801/* Initialize the fc rport list head.1802*/1803INIT_LIST_HEAD(&ioc->fc_rports);18041805/* Find lookup slot. */1806INIT_LIST_HEAD(&ioc->list);180718081809/* Initialize workqueue */1810INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);18111812snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,1813"mpt_poll_%d", ioc->id);1814ioc->reset_work_q =1815create_singlethread_workqueue(ioc->reset_work_q_name);1816if (!ioc->reset_work_q) {1817printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",1818ioc->name);1819pci_release_selected_regions(pdev, ioc->bars);1820kfree(ioc);1821return -ENOMEM;1822}18231824dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",1825ioc->name, &ioc->facts, &ioc->pfacts[0]));18261827pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);1828mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);18291830switch (pdev->device)1831{1832case MPI_MANUFACTPAGE_DEVICEID_FC939X:1833case MPI_MANUFACTPAGE_DEVICEID_FC949X:1834ioc->errata_flag_1064 = 1;1835case MPI_MANUFACTPAGE_DEVICEID_FC909:1836case MPI_MANUFACTPAGE_DEVICEID_FC929:1837case MPI_MANUFACTPAGE_DEVICEID_FC919:1838case MPI_MANUFACTPAGE_DEVICEID_FC949E:1839ioc->bus_type = FC;1840break;18411842case MPI_MANUFACTPAGE_DEVICEID_FC929X:1843if (revision < XL_929) {1844/* 929X Chip Fix. Set Split transactions level1845* for PCIX. Set MOST bits to zero.1846*/1847pci_read_config_byte(pdev, 0x6a, &pcixcmd);1848pcixcmd &= 0x8F;1849pci_write_config_byte(pdev, 0x6a, pcixcmd);1850} else {1851/* 929XL Chip Fix. Set MMRBC to 0x08.1852*/1853pci_read_config_byte(pdev, 0x6a, &pcixcmd);1854pcixcmd |= 0x08;1855pci_write_config_byte(pdev, 0x6a, pcixcmd);1856}1857ioc->bus_type = FC;1858break;18591860case MPI_MANUFACTPAGE_DEVICEID_FC919X:1861/* 919X Chip Fix. Set Split transactions level1862* for PCIX. Set MOST bits to zero.1863*/1864pci_read_config_byte(pdev, 0x6a, &pcixcmd);1865pcixcmd &= 0x8F;1866pci_write_config_byte(pdev, 0x6a, pcixcmd);1867ioc->bus_type = FC;1868break;18691870case MPI_MANUFACTPAGE_DEVID_53C1030:1871/* 1030 Chip Fix. Disable Split transactions1872* for PCIX. Set MOST bits to zero if Rev < C0( = 8).1873*/1874if (revision < C0_1030) {1875pci_read_config_byte(pdev, 0x6a, &pcixcmd);1876pcixcmd &= 0x8F;1877pci_write_config_byte(pdev, 0x6a, pcixcmd);1878}18791880case MPI_MANUFACTPAGE_DEVID_1030_53C1035:1881ioc->bus_type = SPI;1882break;18831884case MPI_MANUFACTPAGE_DEVID_SAS1064:1885case MPI_MANUFACTPAGE_DEVID_SAS1068:1886ioc->errata_flag_1064 = 1;1887ioc->bus_type = SAS;1888break;18891890case MPI_MANUFACTPAGE_DEVID_SAS1064E:1891case MPI_MANUFACTPAGE_DEVID_SAS1068E:1892case MPI_MANUFACTPAGE_DEVID_SAS1078:1893ioc->bus_type = SAS;1894break;1895}189618971898switch (ioc->bus_type) {18991900case SAS:1901ioc->msi_enable = mpt_msi_enable_sas;1902break;19031904case SPI:1905ioc->msi_enable = mpt_msi_enable_spi;1906break;19071908case FC:1909ioc->msi_enable = mpt_msi_enable_fc;1910break;19111912default:1913ioc->msi_enable = 0;1914break;1915}19161917ioc->fw_events_off = 1;19181919if (ioc->errata_flag_1064)1920pci_disable_io_access(pdev);19211922spin_lock_init(&ioc->FreeQlock);19231924/* Disable all! */1925CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);1926ioc->active = 0;1927CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);19281929/* Set IOC ptr in the pcidev's driver data. */1930pci_set_drvdata(ioc->pcidev, ioc);19311932/* Set lookup ptr. */1933list_add_tail(&ioc->list, &ioc_list);19341935/* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.1936*/1937mpt_detect_bound_ports(ioc, pdev);19381939INIT_LIST_HEAD(&ioc->fw_event_list);1940spin_lock_init(&ioc->fw_event_lock);1941snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);1942ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);19431944if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,1945CAN_SLEEP)) != 0){1946printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",1947ioc->name, r);19481949list_del(&ioc->list);1950if (ioc->alt_ioc)1951ioc->alt_ioc->alt_ioc = NULL;1952iounmap(ioc->memmap);1953if (r != -5)1954pci_release_selected_regions(pdev, ioc->bars);19551956destroy_workqueue(ioc->reset_work_q);1957ioc->reset_work_q = NULL;19581959kfree(ioc);1960pci_set_drvdata(pdev, NULL);1961return r;1962}19631964/* call per device driver probe entry point */1965for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {1966if(MptDeviceDriverHandlers[cb_idx] &&1967MptDeviceDriverHandlers[cb_idx]->probe) {1968MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);1969}1970}19711972#ifdef CONFIG_PROC_FS1973/*1974* Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.1975*/1976dent = proc_mkdir(ioc->name, mpt_proc_root_dir);1977if (dent) {1978proc_create_data("info", S_IRUGO, dent, &mpt_iocinfo_proc_fops, ioc);1979proc_create_data("summary", S_IRUGO, dent, &mpt_summary_proc_fops, ioc);1980}1981#endif19821983if (!ioc->alt_ioc)1984queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,1985msecs_to_jiffies(MPT_POLLING_INTERVAL));19861987return 0;1988}19891990/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/1991/**1992* mpt_detach - Remove a PCI intelligent MPT adapter.1993* @pdev: Pointer to pci_dev structure1994*/19951996void1997mpt_detach(struct pci_dev *pdev)1998{1999MPT_ADAPTER *ioc = pci_get_drvdata(pdev);2000char pname[32];2001u8 cb_idx;2002unsigned long flags;2003struct workqueue_struct *wq;20042005/*2006* Stop polling ioc for fault condition2007*/2008spin_lock_irqsave(&ioc->taskmgmt_lock, flags);2009wq = ioc->reset_work_q;2010ioc->reset_work_q = NULL;2011spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);2012cancel_delayed_work(&ioc->fault_reset_work);2013destroy_workqueue(wq);20142015spin_lock_irqsave(&ioc->fw_event_lock, flags);2016wq = ioc->fw_event_q;2017ioc->fw_event_q = NULL;2018spin_unlock_irqrestore(&ioc->fw_event_lock, flags);2019destroy_workqueue(wq);20202021sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);2022remove_proc_entry(pname, NULL);2023sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);2024remove_proc_entry(pname, NULL);2025sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);2026remove_proc_entry(pname, NULL);20272028/* call per device driver remove entry point */2029for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {2030if(MptDeviceDriverHandlers[cb_idx] &&2031MptDeviceDriverHandlers[cb_idx]->remove) {2032MptDeviceDriverHandlers[cb_idx]->remove(pdev);2033}2034}20352036/* Disable interrupts! */2037CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);20382039ioc->active = 0;2040synchronize_irq(pdev->irq);20412042/* Clear any lingering interrupt */2043CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);20442045CHIPREG_READ32(&ioc->chip->IntStatus);20462047mpt_adapter_dispose(ioc);20482049}20502051/**************************************************************************2052* Power Management2053*/2054#ifdef CONFIG_PM2055/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2056/**2057* mpt_suspend - Fusion MPT base driver suspend routine.2058* @pdev: Pointer to pci_dev structure2059* @state: new state to enter2060*/2061int2062mpt_suspend(struct pci_dev *pdev, pm_message_t state)2063{2064u32 device_state;2065MPT_ADAPTER *ioc = pci_get_drvdata(pdev);20662067device_state = pci_choose_state(pdev, state);2068printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "2069"operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),2070device_state);20712072/* put ioc into READY_STATE */2073if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {2074printk(MYIOC_s_ERR_FMT2075"pci-suspend: IOC msg unit reset failed!\n", ioc->name);2076}20772078/* disable interrupts */2079CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);2080ioc->active = 0;20812082/* Clear any lingering interrupt */2083CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);20842085free_irq(ioc->pci_irq, ioc);2086if (ioc->msi_enable)2087pci_disable_msi(ioc->pcidev);2088ioc->pci_irq = -1;2089pci_save_state(pdev);2090pci_disable_device(pdev);2091pci_release_selected_regions(pdev, ioc->bars);2092pci_set_power_state(pdev, device_state);2093return 0;2094}20952096/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2097/**2098* mpt_resume - Fusion MPT base driver resume routine.2099* @pdev: Pointer to pci_dev structure2100*/2101int2102mpt_resume(struct pci_dev *pdev)2103{2104MPT_ADAPTER *ioc = pci_get_drvdata(pdev);2105u32 device_state = pdev->current_state;2106int recovery_state;2107int err;21082109printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "2110"operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),2111device_state);21122113pci_set_power_state(pdev, PCI_D0);2114pci_enable_wake(pdev, PCI_D0, 0);2115pci_restore_state(pdev);2116ioc->pcidev = pdev;2117err = mpt_mapresources(ioc);2118if (err)2119return err;21202121if (ioc->dma_mask == DMA_BIT_MASK(64)) {2122if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)2123ioc->add_sge = &mpt_add_sge_64bit_1078;2124else2125ioc->add_sge = &mpt_add_sge_64bit;2126ioc->add_chain = &mpt_add_chain_64bit;2127ioc->sg_addr_size = 8;2128} else {21292130ioc->add_sge = &mpt_add_sge;2131ioc->add_chain = &mpt_add_chain;2132ioc->sg_addr_size = 4;2133}2134ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;21352136printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",2137ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),2138CHIPREG_READ32(&ioc->chip->Doorbell));21392140/*2141* Errata workaround for SAS pci express:2142* Upon returning to the D0 state, the contents of the doorbell will be2143* stale data, and this will incorrectly signal to the host driver that2144* the firmware is ready to process mpt commands. The workaround is2145* to issue a diagnostic reset.2146*/2147if (ioc->bus_type == SAS && (pdev->device ==2148MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==2149MPI_MANUFACTPAGE_DEVID_SAS1064E)) {2150if (KickStart(ioc, 1, CAN_SLEEP) < 0) {2151printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",2152ioc->name);2153goto out;2154}2155}21562157/* bring ioc to operational state */2158printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);2159recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,2160CAN_SLEEP);2161if (recovery_state != 0)2162printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "2163"error:[%x]\n", ioc->name, recovery_state);2164else2165printk(MYIOC_s_INFO_FMT2166"pci-resume: success\n", ioc->name);2167out:2168return 0;21692170}2171#endif21722173static int2174mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)2175{2176if ((MptDriverClass[index] == MPTSPI_DRIVER &&2177ioc->bus_type != SPI) ||2178(MptDriverClass[index] == MPTFC_DRIVER &&2179ioc->bus_type != FC) ||2180(MptDriverClass[index] == MPTSAS_DRIVER &&2181ioc->bus_type != SAS))2182/* make sure we only call the relevant reset handler2183* for the bus */2184return 0;2185return (MptResetHandlers[index])(ioc, reset_phase);2186}21872188/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2189/**2190* mpt_do_ioc_recovery - Initialize or recover MPT adapter.2191* @ioc: Pointer to MPT adapter structure2192* @reason: Event word / reason2193* @sleepFlag: Use schedule if CAN_SLEEP else use udelay.2194*2195* This routine performs all the steps necessary to bring the IOC2196* to a OPERATIONAL state.2197*2198* This routine also pre-fetches the LAN MAC address of a Fibre Channel2199* MPT adapter.2200*2201* Returns:2202* 0 for success2203* -1 if failed to get board READY2204* -2 if READY but IOCFacts Failed2205* -3 if READY but PrimeIOCFifos Failed2206* -4 if READY but IOCInit Failed2207* -5 if failed to enable_device and/or request_selected_regions2208* -6 if failed to upload firmware2209*/2210static int2211mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)2212{2213int hard_reset_done = 0;2214int alt_ioc_ready = 0;2215int hard;2216int rc=0;2217int ii;2218int ret = 0;2219int reset_alt_ioc_active = 0;2220int irq_allocated = 0;2221u8 *a;22222223printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,2224reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");22252226/* Disable reply interrupts (also blocks FreeQ) */2227CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);2228ioc->active = 0;22292230if (ioc->alt_ioc) {2231if (ioc->alt_ioc->active ||2232reason == MPT_HOSTEVENT_IOC_RECOVER) {2233reset_alt_ioc_active = 1;2234/* Disable alt-IOC's reply interrupts2235* (and FreeQ) for a bit2236**/2237CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,22380xFFFFFFFF);2239ioc->alt_ioc->active = 0;2240}2241}22422243hard = 1;2244if (reason == MPT_HOSTEVENT_IOC_BRINGUP)2245hard = 0;22462247if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {2248if (hard_reset_done == -4) {2249printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",2250ioc->name);22512252if (reset_alt_ioc_active && ioc->alt_ioc) {2253/* (re)Enable alt-IOC! (reply interrupt, FreeQ) */2254dprintk(ioc, printk(MYIOC_s_INFO_FMT2255"alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));2256CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);2257ioc->alt_ioc->active = 1;2258}22592260} else {2261printk(MYIOC_s_WARN_FMT2262"NOT READY WARNING!\n", ioc->name);2263}2264ret = -1;2265goto out;2266}22672268/* hard_reset_done = 0 if a soft reset was performed2269* and 1 if a hard reset was performed.2270*/2271if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {2272if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)2273alt_ioc_ready = 1;2274else2275printk(MYIOC_s_WARN_FMT2276": alt-ioc Not ready WARNING!\n",2277ioc->alt_ioc->name);2278}22792280for (ii=0; ii<5; ii++) {2281/* Get IOC facts! Allow 5 retries */2282if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)2283break;2284}228522862287if (ii == 5) {2288dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT2289"Retry IocFacts failed rc=%x\n", ioc->name, rc));2290ret = -2;2291} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {2292MptDisplayIocCapabilities(ioc);2293}22942295if (alt_ioc_ready) {2296if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {2297dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT2298"Initial Alt IocFacts failed rc=%x\n",2299ioc->name, rc));2300/* Retry - alt IOC was initialized once2301*/2302rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);2303}2304if (rc) {2305dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT2306"Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));2307alt_ioc_ready = 0;2308reset_alt_ioc_active = 0;2309} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {2310MptDisplayIocCapabilities(ioc->alt_ioc);2311}2312}23132314if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&2315(ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {2316pci_release_selected_regions(ioc->pcidev, ioc->bars);2317ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |2318IORESOURCE_IO);2319if (pci_enable_device(ioc->pcidev))2320return -5;2321if (pci_request_selected_regions(ioc->pcidev, ioc->bars,2322"mpt"))2323return -5;2324}23252326/*2327* Device is reset now. It must have de-asserted the interrupt line2328* (if it was asserted) and it should be safe to register for the2329* interrupt now.2330*/2331if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {2332ioc->pci_irq = -1;2333if (ioc->pcidev->irq) {2334if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))2335printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",2336ioc->name);2337else2338ioc->msi_enable = 0;2339rc = request_irq(ioc->pcidev->irq, mpt_interrupt,2340IRQF_SHARED, ioc->name, ioc);2341if (rc < 0) {2342printk(MYIOC_s_ERR_FMT "Unable to allocate "2343"interrupt %d!\n",2344ioc->name, ioc->pcidev->irq);2345if (ioc->msi_enable)2346pci_disable_msi(ioc->pcidev);2347ret = -EBUSY;2348goto out;2349}2350irq_allocated = 1;2351ioc->pci_irq = ioc->pcidev->irq;2352pci_set_master(ioc->pcidev); /* ?? */2353pci_set_drvdata(ioc->pcidev, ioc);2354dinitprintk(ioc, printk(MYIOC_s_INFO_FMT2355"installed at interrupt %d\n", ioc->name,2356ioc->pcidev->irq));2357}2358}23592360/* Prime reply & request queues!2361* (mucho alloc's) Must be done prior to2362* init as upper addresses are needed for init.2363* If fails, continue with alt-ioc processing2364*/2365dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",2366ioc->name));2367if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))2368ret = -3;23692370/* May need to check/upload firmware & data here!2371* If fails, continue with alt-ioc processing2372*/2373dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",2374ioc->name));2375if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))2376ret = -4;2377// NEW!2378if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {2379printk(MYIOC_s_WARN_FMT2380": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",2381ioc->alt_ioc->name, rc);2382alt_ioc_ready = 0;2383reset_alt_ioc_active = 0;2384}23852386if (alt_ioc_ready) {2387if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {2388alt_ioc_ready = 0;2389reset_alt_ioc_active = 0;2390printk(MYIOC_s_WARN_FMT2391": alt-ioc: (%d) init failure WARNING!\n",2392ioc->alt_ioc->name, rc);2393}2394}23952396if (reason == MPT_HOSTEVENT_IOC_BRINGUP){2397if (ioc->upload_fw) {2398ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT2399"firmware upload required!\n", ioc->name));24002401/* Controller is not operational, cannot do upload2402*/2403if (ret == 0) {2404rc = mpt_do_upload(ioc, sleepFlag);2405if (rc == 0) {2406if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {2407/*2408* Maintain only one pointer to FW memory2409* so there will not be two attempt to2410* downloadboot onboard dual function2411* chips (mpt_adapter_disable,2412* mpt_diag_reset)2413*/2414ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT2415"mpt_upload: alt_%s has cached_fw=%p \n",2416ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));2417ioc->cached_fw = NULL;2418}2419} else {2420printk(MYIOC_s_WARN_FMT2421"firmware upload failure!\n", ioc->name);2422ret = -6;2423}2424}2425}2426}24272428/* Enable MPT base driver management of EventNotification2429* and EventAck handling.2430*/2431if ((ret == 0) && (!ioc->facts.EventState)) {2432dinitprintk(ioc, printk(MYIOC_s_INFO_FMT2433"SendEventNotification\n",2434ioc->name));2435ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */2436}24372438if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)2439rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);24402441if (ret == 0) {2442/* Enable! (reply interrupt) */2443CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);2444ioc->active = 1;2445}2446if (rc == 0) { /* alt ioc */2447if (reset_alt_ioc_active && ioc->alt_ioc) {2448/* (re)Enable alt-IOC! (reply interrupt) */2449dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"2450"reply irq re-enabled\n",2451ioc->alt_ioc->name));2452CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,2453MPI_HIM_DIM);2454ioc->alt_ioc->active = 1;2455}2456}245724582459/* Add additional "reason" check before call to GetLanConfigPages2460* (combined with GetIoUnitPage2 call). This prevents a somewhat2461* recursive scenario; GetLanConfigPages times out, timer expired2462* routine calls HardResetHandler, which calls into here again,2463* and we try GetLanConfigPages again...2464*/2465if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {24662467/*2468* Initialize link list for inactive raid volumes.2469*/2470mutex_init(&ioc->raid_data.inactive_list_mutex);2471INIT_LIST_HEAD(&ioc->raid_data.inactive_list);24722473switch (ioc->bus_type) {24742475case SAS:2476/* clear persistency table */2477if(ioc->facts.IOCExceptions &2478MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {2479ret = mptbase_sas_persist_operation(ioc,2480MPI_SAS_OP_CLEAR_NOT_PRESENT);2481if(ret != 0)2482goto out;2483}24842485/* Find IM volumes2486*/2487mpt_findImVolumes(ioc);24882489/* Check, and possibly reset, the coalescing value2490*/2491mpt_read_ioc_pg_1(ioc);24922493break;24942495case FC:2496if ((ioc->pfacts[0].ProtocolFlags &2497MPI_PORTFACTS_PROTOCOL_LAN) &&2498(ioc->lan_cnfg_page0.Header.PageLength == 0)) {2499/*2500* Pre-fetch the ports LAN MAC address!2501* (LANPage1_t stuff)2502*/2503(void) GetLanConfigPages(ioc);2504a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;2505dprintk(ioc, printk(MYIOC_s_DEBUG_FMT2506"LanAddr = %02X:%02X:%02X"2507":%02X:%02X:%02X\n",2508ioc->name, a[5], a[4],2509a[3], a[2], a[1], a[0]));2510}2511break;25122513case SPI:2514/* Get NVRAM and adapter maximums from SPP 0 and 22515*/2516mpt_GetScsiPortSettings(ioc, 0);25172518/* Get version and length of SDP 12519*/2520mpt_readScsiDevicePageHeaders(ioc, 0);25212522/* Find IM volumes2523*/2524if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)2525mpt_findImVolumes(ioc);25262527/* Check, and possibly reset, the coalescing value2528*/2529mpt_read_ioc_pg_1(ioc);25302531mpt_read_ioc_pg_4(ioc);25322533break;2534}25352536GetIoUnitPage2(ioc);2537mpt_get_manufacturing_pg_0(ioc);2538}25392540out:2541if ((ret != 0) && irq_allocated) {2542free_irq(ioc->pci_irq, ioc);2543if (ioc->msi_enable)2544pci_disable_msi(ioc->pcidev);2545}2546return ret;2547}25482549/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2550/**2551* mpt_detect_bound_ports - Search for matching PCI bus/dev_function2552* @ioc: Pointer to MPT adapter structure2553* @pdev: Pointer to (struct pci_dev) structure2554*2555* Search for PCI bus/dev_function which matches2556* PCI bus/dev_function (+/-1) for newly discovered 929,2557* 929X, 1030 or 1035.2558*2559* If match on PCI dev_function +/-1 is found, bind the two MPT adapters2560* using alt_ioc pointer fields in their %MPT_ADAPTER structures.2561*/2562static void2563mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)2564{2565struct pci_dev *peer=NULL;2566unsigned int slot = PCI_SLOT(pdev->devfn);2567unsigned int func = PCI_FUNC(pdev->devfn);2568MPT_ADAPTER *ioc_srch;25692570dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"2571" searching for devfn match on %x or %x\n",2572ioc->name, pci_name(pdev), pdev->bus->number,2573pdev->devfn, func-1, func+1));25742575peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));2576if (!peer) {2577peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));2578if (!peer)2579return;2580}25812582list_for_each_entry(ioc_srch, &ioc_list, list) {2583struct pci_dev *_pcidev = ioc_srch->pcidev;2584if (_pcidev == peer) {2585/* Paranoia checks */2586if (ioc->alt_ioc != NULL) {2587printk(MYIOC_s_WARN_FMT2588"Oops, already bound (%s <==> %s)!\n",2589ioc->name, ioc->name, ioc->alt_ioc->name);2590break;2591} else if (ioc_srch->alt_ioc != NULL) {2592printk(MYIOC_s_WARN_FMT2593"Oops, already bound (%s <==> %s)!\n",2594ioc_srch->name, ioc_srch->name,2595ioc_srch->alt_ioc->name);2596break;2597}2598dprintk(ioc, printk(MYIOC_s_DEBUG_FMT2599"FOUND! binding %s <==> %s\n",2600ioc->name, ioc->name, ioc_srch->name));2601ioc_srch->alt_ioc = ioc;2602ioc->alt_ioc = ioc_srch;2603}2604}2605pci_dev_put(peer);2606}26072608/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2609/**2610* mpt_adapter_disable - Disable misbehaving MPT adapter.2611* @ioc: Pointer to MPT adapter structure2612*/2613static void2614mpt_adapter_disable(MPT_ADAPTER *ioc)2615{2616int sz;2617int ret;26182619if (ioc->cached_fw != NULL) {2620ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT2621"%s: Pushing FW onto adapter\n", __func__, ioc->name));2622if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)2623ioc->cached_fw, CAN_SLEEP)) < 0) {2624printk(MYIOC_s_WARN_FMT2625": firmware downloadboot failure (%d)!\n",2626ioc->name, ret);2627}2628}26292630/*2631* Put the controller into ready state (if its not already)2632*/2633if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {2634if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,2635CAN_SLEEP)) {2636if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)2637printk(MYIOC_s_ERR_FMT "%s: IOC msg unit "2638"reset failed to put ioc in ready state!\n",2639ioc->name, __func__);2640} else2641printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset "2642"failed!\n", ioc->name, __func__);2643}264426452646/* Disable adapter interrupts! */2647synchronize_irq(ioc->pcidev->irq);2648CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);2649ioc->active = 0;26502651/* Clear any lingering interrupt */2652CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);2653CHIPREG_READ32(&ioc->chip->IntStatus);26542655if (ioc->alloc != NULL) {2656sz = ioc->alloc_sz;2657dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",2658ioc->name, ioc->alloc, ioc->alloc_sz));2659pci_free_consistent(ioc->pcidev, sz,2660ioc->alloc, ioc->alloc_dma);2661ioc->reply_frames = NULL;2662ioc->req_frames = NULL;2663ioc->alloc = NULL;2664ioc->alloc_total -= sz;2665}26662667if (ioc->sense_buf_pool != NULL) {2668sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);2669pci_free_consistent(ioc->pcidev, sz,2670ioc->sense_buf_pool, ioc->sense_buf_pool_dma);2671ioc->sense_buf_pool = NULL;2672ioc->alloc_total -= sz;2673}26742675if (ioc->events != NULL){2676sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);2677kfree(ioc->events);2678ioc->events = NULL;2679ioc->alloc_total -= sz;2680}26812682mpt_free_fw_memory(ioc);26832684kfree(ioc->spi_data.nvram);2685mpt_inactive_raid_list_free(ioc);2686kfree(ioc->raid_data.pIocPg2);2687kfree(ioc->raid_data.pIocPg3);2688ioc->spi_data.nvram = NULL;2689ioc->raid_data.pIocPg3 = NULL;26902691if (ioc->spi_data.pIocPg4 != NULL) {2692sz = ioc->spi_data.IocPg4Sz;2693pci_free_consistent(ioc->pcidev, sz,2694ioc->spi_data.pIocPg4,2695ioc->spi_data.IocPg4_dma);2696ioc->spi_data.pIocPg4 = NULL;2697ioc->alloc_total -= sz;2698}26992700if (ioc->ReqToChain != NULL) {2701kfree(ioc->ReqToChain);2702kfree(ioc->RequestNB);2703ioc->ReqToChain = NULL;2704}27052706kfree(ioc->ChainToChain);2707ioc->ChainToChain = NULL;27082709if (ioc->HostPageBuffer != NULL) {2710if((ret = mpt_host_page_access_control(ioc,2711MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {2712printk(MYIOC_s_ERR_FMT2713": %s: host page buffers free failed (%d)!\n",2714ioc->name, __func__, ret);2715}2716dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT2717"HostPageBuffer free @ %p, sz=%d bytes\n",2718ioc->name, ioc->HostPageBuffer,2719ioc->HostPageBuffer_sz));2720pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,2721ioc->HostPageBuffer, ioc->HostPageBuffer_dma);2722ioc->HostPageBuffer = NULL;2723ioc->HostPageBuffer_sz = 0;2724ioc->alloc_total -= ioc->HostPageBuffer_sz;2725}27262727pci_set_drvdata(ioc->pcidev, NULL);2728}2729/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2730/**2731* mpt_adapter_dispose - Free all resources associated with an MPT adapter2732* @ioc: Pointer to MPT adapter structure2733*2734* This routine unregisters h/w resources and frees all alloc'd memory2735* associated with a MPT adapter structure.2736*/2737static void2738mpt_adapter_dispose(MPT_ADAPTER *ioc)2739{2740int sz_first, sz_last;27412742if (ioc == NULL)2743return;27442745sz_first = ioc->alloc_total;27462747mpt_adapter_disable(ioc);27482749if (ioc->pci_irq != -1) {2750free_irq(ioc->pci_irq, ioc);2751if (ioc->msi_enable)2752pci_disable_msi(ioc->pcidev);2753ioc->pci_irq = -1;2754}27552756if (ioc->memmap != NULL) {2757iounmap(ioc->memmap);2758ioc->memmap = NULL;2759}27602761pci_disable_device(ioc->pcidev);2762pci_release_selected_regions(ioc->pcidev, ioc->bars);27632764#if defined(CONFIG_MTRR) && 02765if (ioc->mtrr_reg > 0) {2766mtrr_del(ioc->mtrr_reg, 0, 0);2767dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));2768}2769#endif27702771/* Zap the adapter lookup ptr! */2772list_del(&ioc->list);27732774sz_last = ioc->alloc_total;2775dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",2776ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));27772778if (ioc->alt_ioc)2779ioc->alt_ioc->alt_ioc = NULL;27802781kfree(ioc);2782}27832784/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2785/**2786* MptDisplayIocCapabilities - Disply IOC's capabilities.2787* @ioc: Pointer to MPT adapter structure2788*/2789static void2790MptDisplayIocCapabilities(MPT_ADAPTER *ioc)2791{2792int i = 0;27932794printk(KERN_INFO "%s: ", ioc->name);2795if (ioc->prod_name)2796printk("%s: ", ioc->prod_name);2797printk("Capabilities={");27982799if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {2800printk("Initiator");2801i++;2802}28032804if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {2805printk("%sTarget", i ? "," : "");2806i++;2807}28082809if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {2810printk("%sLAN", i ? "," : "");2811i++;2812}28132814#if 02815/*2816* This would probably evoke more questions than it's worth2817*/2818if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {2819printk("%sLogBusAddr", i ? "," : "");2820i++;2821}2822#endif28232824printk("}\n");2825}28262827/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2828/**2829* MakeIocReady - Get IOC to a READY state, using KickStart if needed.2830* @ioc: Pointer to MPT_ADAPTER structure2831* @force: Force hard KickStart of IOC2832* @sleepFlag: Specifies whether the process can sleep2833*2834* Returns:2835* 1 - DIAG reset and READY2836* 0 - READY initially OR soft reset and READY2837* -1 - Any failure on KickStart2838* -2 - Msg Unit Reset Failed2839* -3 - IO Unit Reset Failed2840* -4 - IOC owned by a PEER2841*/2842static int2843MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)2844{2845u32 ioc_state;2846int statefault = 0;2847int cntdn;2848int hard_reset_done = 0;2849int r;2850int ii;2851int whoinit;28522853/* Get current [raw] IOC state */2854ioc_state = mpt_GetIocState(ioc, 0);2855dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));28562857/*2858* Check to see if IOC got left/stuck in doorbell handshake2859* grip of death. If so, hard reset the IOC.2860*/2861if (ioc_state & MPI_DOORBELL_ACTIVE) {2862statefault = 1;2863printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",2864ioc->name);2865}28662867/* Is it already READY? */2868if (!statefault &&2869((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {2870dinitprintk(ioc, printk(MYIOC_s_INFO_FMT2871"IOC is in READY state\n", ioc->name));2872return 0;2873}28742875/*2876* Check to see if IOC is in FAULT state.2877*/2878if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {2879statefault = 2;2880printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",2881ioc->name);2882printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",2883ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);2884}28852886/*2887* Hmmm... Did it get left operational?2888*/2889if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {2890dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",2891ioc->name));28922893/* Check WhoInit.2894* If PCI Peer, exit.2895* Else, if no fault conditions are present, issue a MessageUnitReset2896* Else, fall through to KickStart case2897*/2898whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;2899dinitprintk(ioc, printk(MYIOC_s_INFO_FMT2900"whoinit 0x%x statefault %d force %d\n",2901ioc->name, whoinit, statefault, force));2902if (whoinit == MPI_WHOINIT_PCI_PEER)2903return -4;2904else {2905if ((statefault == 0 ) && (force == 0)) {2906if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)2907return 0;2908}2909statefault = 3;2910}2911}29122913hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);2914if (hard_reset_done < 0)2915return -1;29162917/*2918* Loop here waiting for IOC to come READY.2919*/2920ii = 0;2921cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */29222923while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {2924if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {2925/*2926* BIOS or previous driver load left IOC in OP state.2927* Reset messaging FIFOs.2928*/2929if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {2930printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);2931return -2;2932}2933} else if (ioc_state == MPI_IOC_STATE_RESET) {2934/*2935* Something is wrong. Try to get IOC back2936* to a known state.2937*/2938if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {2939printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);2940return -3;2941}2942}29432944ii++; cntdn--;2945if (!cntdn) {2946printk(MYIOC_s_ERR_FMT2947"Wait IOC_READY state (0x%x) timeout(%d)!\n",2948ioc->name, ioc_state, (int)((ii+5)/HZ));2949return -ETIME;2950}29512952if (sleepFlag == CAN_SLEEP) {2953msleep(1);2954} else {2955mdelay (1); /* 1 msec delay */2956}29572958}29592960if (statefault < 3) {2961printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,2962statefault == 1 ? "stuck handshake" : "IOC FAULT");2963}29642965return hard_reset_done;2966}29672968/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2969/**2970* mpt_GetIocState - Get the current state of a MPT adapter.2971* @ioc: Pointer to MPT_ADAPTER structure2972* @cooked: Request raw or cooked IOC state2973*2974* Returns all IOC Doorbell register bits if cooked==0, else just the2975* Doorbell bits in MPI_IOC_STATE_MASK.2976*/2977u322978mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)2979{2980u32 s, sc;29812982/* Get! */2983s = CHIPREG_READ32(&ioc->chip->Doorbell);2984sc = s & MPI_IOC_STATE_MASK;29852986/* Save! */2987ioc->last_state = sc;29882989return cooked ? sc : s;2990}29912992/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/2993/**2994* GetIocFacts - Send IOCFacts request to MPT adapter.2995* @ioc: Pointer to MPT_ADAPTER structure2996* @sleepFlag: Specifies whether the process can sleep2997* @reason: If recovery, only update facts.2998*2999* Returns 0 for success, non-zero for failure.3000*/3001static int3002GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)3003{3004IOCFacts_t get_facts;3005IOCFactsReply_t *facts;3006int r;3007int req_sz;3008int reply_sz;3009int sz;3010u32 status, vv;3011u8 shiftFactor=1;30123013/* IOC *must* NOT be in RESET state! */3014if (ioc->last_state == MPI_IOC_STATE_RESET) {3015printk(KERN_ERR MYNAM3016": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",3017ioc->name, ioc->last_state);3018return -44;3019}30203021facts = &ioc->facts;30223023/* Destination (reply area)... */3024reply_sz = sizeof(*facts);3025memset(facts, 0, reply_sz);30263027/* Request area (get_facts on the stack right now!) */3028req_sz = sizeof(get_facts);3029memset(&get_facts, 0, req_sz);30303031get_facts.Function = MPI_FUNCTION_IOC_FACTS;3032/* Assert: All other get_facts fields are zero! */30333034dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT3035"Sending get IocFacts request req_sz=%d reply_sz=%d\n",3036ioc->name, req_sz, reply_sz));30373038/* No non-zero fields in the get_facts request are greater than3039* 1 byte in size, so we can just fire it off as is.3040*/3041r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,3042reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);3043if (r != 0)3044return r;30453046/*3047* Now byte swap (GRRR) the necessary fields before any further3048* inspection of reply contents.3049*3050* But need to do some sanity checks on MsgLength (byte) field3051* to make sure we don't zero IOC's req_sz!3052*/3053/* Did we get a valid reply? */3054if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {3055if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {3056/*3057* If not been here, done that, save off first WhoInit value3058*/3059if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)3060ioc->FirstWhoInit = facts->WhoInit;3061}30623063facts->MsgVersion = le16_to_cpu(facts->MsgVersion);3064facts->MsgContext = le32_to_cpu(facts->MsgContext);3065facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);3066facts->IOCStatus = le16_to_cpu(facts->IOCStatus);3067facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);3068status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;3069/* CHECKME! IOCStatus, IOCLogInfo */30703071facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);3072facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);30733074/*3075* FC f/w version changed between 1.1 and 1.23076* Old: u16{Major(4),Minor(4),SubMinor(8)}3077* New: u32{Major(8),Minor(8),Unit(8),Dev(8)}3078*/3079if (facts->MsgVersion < MPI_VERSION_01_02) {3080/*3081* Handle old FC f/w style, convert to new...3082*/3083u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);3084facts->FWVersion.Word =3085((oldv<<12) & 0xFF000000) |3086((oldv<<8) & 0x000FFF00);3087} else3088facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);30893090facts->ProductID = le16_to_cpu(facts->ProductID);30913092if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)3093> MPI_FW_HEADER_PID_PROD_TARGET_SCSI)3094ioc->ir_firmware = 1;30953096facts->CurrentHostMfaHighAddr =3097le32_to_cpu(facts->CurrentHostMfaHighAddr);3098facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);3099facts->CurrentSenseBufferHighAddr =3100le32_to_cpu(facts->CurrentSenseBufferHighAddr);3101facts->CurReplyFrameSize =3102le16_to_cpu(facts->CurReplyFrameSize);3103facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);31043105/*3106* Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx3107* Older MPI-1.00.xx struct had 13 dwords, and enlarged3108* to 14 in MPI-1.01.0x.3109*/3110if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&3111facts->MsgVersion > MPI_VERSION_01_00) {3112facts->FWImageSize = le32_to_cpu(facts->FWImageSize);3113}31143115sz = facts->FWImageSize;3116if ( sz & 0x01 )3117sz += 1;3118if ( sz & 0x02 )3119sz += 2;3120facts->FWImageSize = sz;31213122if (!facts->RequestFrameSize) {3123/* Something is wrong! */3124printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",3125ioc->name);3126return -55;3127}31283129r = sz = facts->BlockSize;3130vv = ((63 / (sz * 4)) + 1) & 0x03;3131ioc->NB_for_64_byte_frame = vv;3132while ( sz )3133{3134shiftFactor++;3135sz = sz >> 1;3136}3137ioc->NBShiftFactor = shiftFactor;3138dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT3139"NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",3140ioc->name, vv, shiftFactor, r));31413142if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {3143/*3144* Set values for this IOC's request & reply frame sizes,3145* and request & reply queue depths...3146*/3147ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);3148ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);3149ioc->reply_sz = MPT_REPLY_FRAME_SIZE;3150ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);31513152dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",3153ioc->name, ioc->reply_sz, ioc->reply_depth));3154dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",3155ioc->name, ioc->req_sz, ioc->req_depth));31563157/* Get port facts! */3158if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )3159return r;3160}3161} else {3162printk(MYIOC_s_ERR_FMT3163"Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",3164ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,3165RequestFrameSize)/sizeof(u32)));3166return -66;3167}31683169return 0;3170}31713172/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/3173/**3174* GetPortFacts - Send PortFacts request to MPT adapter.3175* @ioc: Pointer to MPT_ADAPTER structure3176* @portnum: Port number3177* @sleepFlag: Specifies whether the process can sleep3178*3179* Returns 0 for success, non-zero for failure.3180*/3181static int3182GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)3183{3184PortFacts_t get_pfacts;3185PortFactsReply_t *pfacts;3186int ii;3187int req_sz;3188int reply_sz;3189int max_id;31903191/* IOC *must* NOT be in RESET state! */3192if (ioc->last_state == MPI_IOC_STATE_RESET) {3193printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",3194ioc->name, ioc->last_state );3195return -4;3196}31973198pfacts = &ioc->pfacts[portnum];31993200/* Destination (reply area)... */3201reply_sz = sizeof(*pfacts);3202memset(pfacts, 0, reply_sz);32033204/* Request area (get_pfacts on the stack right now!) */3205req_sz = sizeof(get_pfacts);3206memset(&get_pfacts, 0, req_sz);32073208get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;3209get_pfacts.PortNumber = portnum;3210/* Assert: All other get_pfacts fields are zero! */32113212dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",3213ioc->name, portnum));32143215/* No non-zero fields in the get_pfacts request are greater than3216* 1 byte in size, so we can just fire it off as is.3217*/3218ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,3219reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);3220if (ii != 0)3221return ii;32223223/* Did we get a valid reply? */32243225/* Now byte swap the necessary fields in the response. */3226pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);3227pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);3228pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);3229pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);3230pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);3231pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);3232pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);3233pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);3234pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);32353236max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :3237pfacts->MaxDevices;3238ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;3239ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;32403241/*3242* Place all the devices on channels3243*3244* (for debuging)3245*/3246if (mpt_channel_mapping) {3247ioc->devices_per_bus = 1;3248ioc->number_of_buses = (max_id > 255) ? 255 : max_id;3249}32503251return 0;3252}32533254/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/3255/**3256* SendIocInit - Send IOCInit request to MPT adapter.3257* @ioc: Pointer to MPT_ADAPTER structure3258* @sleepFlag: Specifies whether the process can sleep3259*3260* Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.3261*3262* Returns 0 for success, non-zero for failure.3263*/3264static int3265SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)3266{3267IOCInit_t ioc_init;3268MPIDefaultReply_t init_reply;3269u32 state;3270int r;3271int count;3272int cntdn;32733274memset(&ioc_init, 0, sizeof(ioc_init));3275memset(&init_reply, 0, sizeof(init_reply));32763277ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;3278ioc_init.Function = MPI_FUNCTION_IOC_INIT;32793280/* If we are in a recovery mode and we uploaded the FW image,3281* then this pointer is not NULL. Skip the upload a second time.3282* Set this flag if cached_fw set for either IOC.3283*/3284if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)3285ioc->upload_fw = 1;3286else3287ioc->upload_fw = 0;3288ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",3289ioc->name, ioc->upload_fw, ioc->facts.Flags));32903291ioc_init.MaxDevices = (U8)ioc->devices_per_bus;3292ioc_init.MaxBuses = (U8)ioc->number_of_buses;32933294dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",3295ioc->name, ioc->facts.MsgVersion));3296if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {3297// set MsgVersion and HeaderVersion host driver was built with3298ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);3299ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);33003301if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {3302ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;3303} else if(mpt_host_page_alloc(ioc, &ioc_init))3304return -99;3305}3306ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */33073308if (ioc->sg_addr_size == sizeof(u64)) {3309/* Save the upper 32-bits of the request3310* (reply) and sense buffers.3311*/3312ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));3313ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));3314} else {3315/* Force 32-bit addressing */3316ioc_init.HostMfaHighAddr = cpu_to_le32(0);3317ioc_init.SenseBufferHighAddr = cpu_to_le32(0);3318}33193320ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;3321ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;3322ioc->facts.MaxDevices = ioc_init.MaxDevices;3323ioc->facts.MaxBuses = ioc_init.MaxBuses;33243325dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",3326ioc->name, &ioc_init));33273328r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,3329sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);3330if (r != 0) {3331printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);3332return r;3333}33343335/* No need to byte swap the multibyte fields in the reply3336* since we don't even look at its contents.3337*/33383339dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",3340ioc->name, &ioc_init));33413342if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {3343printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);3344return r;3345}33463347/* YIKES! SUPER IMPORTANT!!!3348* Poll IocState until _OPERATIONAL while IOC is doing3349* LoopInit and TargetDiscovery!3350*/3351count = 0;3352cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */3353state = mpt_GetIocState(ioc, 1);3354while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {3355if (sleepFlag == CAN_SLEEP) {3356msleep(1);3357} else {3358mdelay(1);3359}33603361if (!cntdn) {3362printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",3363ioc->name, (int)((count+5)/HZ));3364return -9;3365}33663367state = mpt_GetIocState(ioc, 1);3368count++;3369}3370dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",3371ioc->name, count));33723373ioc->aen_event_read_flag=0;3374return r;3375}33763377/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/3378/**3379* SendPortEnable - Send PortEnable request to MPT adapter port.3380* @ioc: Pointer to MPT_ADAPTER structure3381* @portnum: Port number to enable3382* @sleepFlag: Specifies whether the process can sleep3383*3384* Send PortEnable to bring IOC to OPERATIONAL state.3385*3386* Returns 0 for success, non-zero for failure.3387*/3388static int3389SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)3390{3391PortEnable_t port_enable;3392MPIDefaultReply_t reply_buf;3393int rc;3394int req_sz;3395int reply_sz;33963397/* Destination... */3398reply_sz = sizeof(MPIDefaultReply_t);3399memset(&reply_buf, 0, reply_sz);34003401req_sz = sizeof(PortEnable_t);3402memset(&port_enable, 0, req_sz);34033404port_enable.Function = MPI_FUNCTION_PORT_ENABLE;3405port_enable.PortNumber = portnum;3406/* port_enable.ChainOffset = 0; */3407/* port_enable.MsgFlags = 0; */3408/* port_enable.MsgContext = 0; */34093410dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",3411ioc->name, portnum, &port_enable));34123413/* RAID FW may take a long time to enable3414*/3415if (ioc->ir_firmware || ioc->bus_type == SAS) {3416rc = mpt_handshake_req_reply_wait(ioc, req_sz,3417(u32*)&port_enable, reply_sz, (u16*)&reply_buf,3418300 /*seconds*/, sleepFlag);3419} else {3420rc = mpt_handshake_req_reply_wait(ioc, req_sz,3421(u32*)&port_enable, reply_sz, (u16*)&reply_buf,342230 /*seconds*/, sleepFlag);3423}3424return rc;3425}34263427/**3428* mpt_alloc_fw_memory - allocate firmware memory3429* @ioc: Pointer to MPT_ADAPTER structure3430* @size: total FW bytes3431*3432* If memory has already been allocated, the same (cached) value3433* is returned.3434*3435* Return 0 if successful, or non-zero for failure3436**/3437int3438mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)3439{3440int rc;34413442if (ioc->cached_fw) {3443rc = 0; /* use already allocated memory */3444goto out;3445}3446else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {3447ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */3448ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;3449rc = 0;3450goto out;3451}3452ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);3453if (!ioc->cached_fw) {3454printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",3455ioc->name);3456rc = -1;3457} else {3458dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",3459ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));3460ioc->alloc_total += size;3461rc = 0;3462}3463out:3464return rc;3465}34663467/**3468* mpt_free_fw_memory - free firmware memory3469* @ioc: Pointer to MPT_ADAPTER structure3470*3471* If alt_img is NULL, delete from ioc structure.3472* Else, delete a secondary image in same format.3473**/3474void3475mpt_free_fw_memory(MPT_ADAPTER *ioc)3476{3477int sz;34783479if (!ioc->cached_fw)3480return;34813482sz = ioc->facts.FWImageSize;3483dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",3484ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));3485pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);3486ioc->alloc_total -= sz;3487ioc->cached_fw = NULL;3488}34893490/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/3491/**3492* mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.3493* @ioc: Pointer to MPT_ADAPTER structure3494* @sleepFlag: Specifies whether the process can sleep3495*3496* Returns 0 for success, >0 for handshake failure3497* <0 for fw upload failure.3498*3499* Remark: If bound IOC and a successful FWUpload was performed3500* on the bound IOC, the second image is discarded3501* and memory is free'd. Both channels must upload to prevent3502* IOC from running in degraded mode.3503*/3504static int3505mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)3506{3507u8 reply[sizeof(FWUploadReply_t)];3508FWUpload_t *prequest;3509FWUploadReply_t *preply;3510FWUploadTCSGE_t *ptcsge;3511u32 flagsLength;3512int ii, sz, reply_sz;3513int cmdStatus;3514int request_size;3515/* If the image size is 0, we are done.3516*/3517if ((sz = ioc->facts.FWImageSize) == 0)3518return 0;35193520if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)3521return -ENOMEM;35223523dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",3524ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));35253526prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :3527kzalloc(ioc->req_sz, GFP_KERNEL);3528if (!prequest) {3529dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "3530"while allocating memory \n", ioc->name));3531mpt_free_fw_memory(ioc);3532return -ENOMEM;3533}35343535preply = (FWUploadReply_t *)&reply;35363537reply_sz = sizeof(reply);3538memset(preply, 0, reply_sz);35393540prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;3541prequest->Function = MPI_FUNCTION_FW_UPLOAD;35423543ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;3544ptcsge->DetailsLength = 12;3545ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;3546ptcsge->ImageSize = cpu_to_le32(sz);3547ptcsge++;35483549flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;3550ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);3551request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +3552ioc->SGE_size;3553dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "3554" (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,3555ioc->facts.FWImageSize, request_size));3556DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);35573558ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,3559reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);35603561dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "3562"rc=%x \n", ioc->name, ii));35633564cmdStatus = -EFAULT;3565if (ii == 0) {3566/* Handshake transfer was complete and successful.3567* Check the Reply Frame.3568*/3569int status;3570status = le16_to_cpu(preply->IOCStatus) &3571MPI_IOCSTATUS_MASK;3572if (status == MPI_IOCSTATUS_SUCCESS &&3573ioc->facts.FWImageSize ==3574le32_to_cpu(preply->ActualImageSize))3575cmdStatus = 0;3576}3577dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",3578ioc->name, cmdStatus));357935803581if (cmdStatus) {3582ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "3583"freeing image \n", ioc->name));3584mpt_free_fw_memory(ioc);3585}3586kfree(prequest);35873588return cmdStatus;3589}35903591/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/3592/**3593* mpt_downloadboot - DownloadBoot code3594* @ioc: Pointer to MPT_ADAPTER structure3595* @pFwHeader: Pointer to firmware header info3596* @sleepFlag: Specifies whether the process can sleep3597*3598* FwDownloadBoot requires Programmed IO access.3599*3600* Returns 0 for success3601* -1 FW Image size is 03602* -2 No valid cached_fw Pointer3603* <0 for fw upload failure.3604*/3605static int3606mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)3607{3608MpiExtImageHeader_t *pExtImage;3609u32 fwSize;3610u32 diag0val;3611int count;3612u32 *ptrFw;3613u32 diagRwData;3614u32 nextImage;3615u32 load_addr;3616u32 ioc_state=0;36173618ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",3619ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));36203621CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);3622CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);3623CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);3624CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);3625CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);3626CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);36273628CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));36293630/* wait 1 msec */3631if (sleepFlag == CAN_SLEEP) {3632msleep(1);3633} else {3634mdelay (1);3635}36363637diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);3638CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);36393640for (count = 0; count < 30; count ++) {3641diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);3642if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {3643ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",3644ioc->name, count));3645break;3646}3647/* wait .1 sec */3648if (sleepFlag == CAN_SLEEP) {3649msleep (100);3650} else {3651mdelay (100);3652}3653}36543655if ( count == 30 ) {3656ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "3657"Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",3658ioc->name, diag0val));3659return -3;3660}36613662CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);3663CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);3664CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);3665CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);3666CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);3667CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);36683669/* Set the DiagRwEn and Disable ARM bits */3670CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));36713672fwSize = (pFwHeader->ImageSize + 3)/4;3673ptrFw = (u32 *) pFwHeader;36743675/* Write the LoadStartAddress to the DiagRw Address Register3676* using Programmed IO3677*/3678if (ioc->errata_flag_1064)3679pci_enable_io_access(ioc->pcidev);36803681CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);3682ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",3683ioc->name, pFwHeader->LoadStartAddress));36843685ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",3686ioc->name, fwSize*4, ptrFw));3687while (fwSize--) {3688CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);3689}36903691nextImage = pFwHeader->NextImageHeaderOffset;3692while (nextImage) {3693pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);36943695load_addr = pExtImage->LoadStartAddress;36963697fwSize = (pExtImage->ImageSize + 3) >> 2;3698ptrFw = (u32 *)pExtImage;36993700ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",3701ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));3702CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);37033704while (fwSize--) {3705CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);3706}3707nextImage = pExtImage->NextImageHeaderOffset;3708}37093710/* Write the IopResetVectorRegAddr */3711ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));3712CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);37133714/* Write the IopResetVectorValue */3715ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));3716CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);37173718/* Clear the internal flash bad bit - autoincrementing register,3719* so must do two writes.3720*/3721if (ioc->bus_type == SPI) {3722/*3723* 1030 and 1035 H/W errata, workaround to access3724* the ClearFlashBadSignatureBit3725*/3726CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);3727diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);3728diagRwData |= 0x40000000;3729CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);3730CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);37313732} else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {3733diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);3734CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |3735MPI_DIAG_CLEAR_FLASH_BAD_SIG);37363737/* wait 1 msec */3738if (sleepFlag == CAN_SLEEP) {3739msleep (1);3740} else {3741mdelay (1);3742}3743}37443745if (ioc->errata_flag_1064)3746pci_disable_io_access(ioc->pcidev);37473748diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);3749ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "3750"turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",3751ioc->name, diag0val));3752diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);3753ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",3754ioc->name, diag0val));3755CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);37563757/* Write 0xFF to reset the sequencer */3758CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);37593760if (ioc->bus_type == SAS) {3761ioc_state = mpt_GetIocState(ioc, 0);3762if ( (GetIocFacts(ioc, sleepFlag,3763MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {3764ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",3765ioc->name, ioc_state));3766return -EFAULT;3767}3768}37693770for (count=0; count<HZ*20; count++) {3771if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {3772ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT3773"downloadboot successful! (count=%d) IocState=%x\n",3774ioc->name, count, ioc_state));3775if (ioc->bus_type == SAS) {3776return 0;3777}3778if ((SendIocInit(ioc, sleepFlag)) != 0) {3779ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT3780"downloadboot: SendIocInit failed\n",3781ioc->name));3782return -EFAULT;3783}3784ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT3785"downloadboot: SendIocInit successful\n",3786ioc->name));3787return 0;3788}3789if (sleepFlag == CAN_SLEEP) {3790msleep (10);3791} else {3792mdelay (10);3793}3794}3795ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT3796"downloadboot failed! IocState=%x\n",ioc->name, ioc_state));3797return -EFAULT;3798}37993800/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/3801/**3802* KickStart - Perform hard reset of MPT adapter.3803* @ioc: Pointer to MPT_ADAPTER structure3804* @force: Force hard reset3805* @sleepFlag: Specifies whether the process can sleep3806*3807* This routine places MPT adapter in diagnostic mode via the3808* WriteSequence register, and then performs a hard reset of adapter3809* via the Diagnostic register.3810*3811* Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)3812* or NO_SLEEP (interrupt thread, use mdelay)3813* force - 1 if doorbell active, board fault state3814* board operational, IOC_RECOVERY or3815* IOC_BRINGUP and there is an alt_ioc.3816* 0 else3817*3818* Returns:3819* 1 - hard reset, READY3820* 0 - no reset due to History bit, READY3821* -1 - no reset due to History bit but not READY3822* OR reset but failed to come READY3823* -2 - no reset, could not enter DIAG mode3824* -3 - reset but bad FW bit3825*/3826static int3827KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)3828{3829int hard_reset_done = 0;3830u32 ioc_state=0;3831int cnt,cntdn;38323833dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));3834if (ioc->bus_type == SPI) {3835/* Always issue a Msg Unit Reset first. This will clear some3836* SCSI bus hang conditions.3837*/3838SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);38393840if (sleepFlag == CAN_SLEEP) {3841msleep (1000);3842} else {3843mdelay (1000);3844}3845}38463847hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);3848if (hard_reset_done < 0)3849return hard_reset_done;38503851dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",3852ioc->name));38533854cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */3855for (cnt=0; cnt<cntdn; cnt++) {3856ioc_state = mpt_GetIocState(ioc, 1);3857if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {3858dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",3859ioc->name, cnt));3860return hard_reset_done;3861}3862if (sleepFlag == CAN_SLEEP) {3863msleep (10);3864} else {3865mdelay (10);3866}3867}38683869dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",3870ioc->name, mpt_GetIocState(ioc, 0)));3871return -1;3872}38733874/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/3875/**3876* mpt_diag_reset - Perform hard reset of the adapter.3877* @ioc: Pointer to MPT_ADAPTER structure3878* @ignore: Set if to honor and clear to ignore3879* the reset history bit3880* @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,3881* else set to NO_SLEEP (use mdelay instead)3882*3883* This routine places the adapter in diagnostic mode via the3884* WriteSequence register and then performs a hard reset of adapter3885* via the Diagnostic register. Adapter should be in ready state3886* upon successful completion.3887*3888* Returns: 1 hard reset successful3889* 0 no reset performed because reset history bit set3890* -2 enabling diagnostic mode failed3891* -3 diagnostic reset failed3892*/3893static int3894mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)3895{3896u32 diag0val;3897u32 doorbell;3898int hard_reset_done = 0;3899int count = 0;3900u32 diag1val = 0;3901MpiFwHeader_t *cached_fw; /* Pointer to FW */3902u8 cb_idx;39033904/* Clear any existing interrupts */3905CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);39063907if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {39083909if (!ignore)3910return 0;39113912drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "3913"address=%p\n", ioc->name, __func__,3914&ioc->chip->Doorbell, &ioc->chip->Reset_1078));3915CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);3916if (sleepFlag == CAN_SLEEP)3917msleep(1);3918else3919mdelay(1);39203921/*3922* Call each currently registered protocol IOC reset handler3923* with pre-reset indication.3924* NOTE: If we're doing _IOC_BRINGUP, there can be no3925* MptResetHandlers[] registered yet.3926*/3927for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {3928if (MptResetHandlers[cb_idx])3929(*(MptResetHandlers[cb_idx]))(ioc,3930MPT_IOC_PRE_RESET);3931}39323933for (count = 0; count < 60; count ++) {3934doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);3935doorbell &= MPI_IOC_STATE_MASK;39363937drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT3938"looking for READY STATE: doorbell=%x"3939" count=%d\n",3940ioc->name, doorbell, count));39413942if (doorbell == MPI_IOC_STATE_READY) {3943return 1;3944}39453946/* wait 1 sec */3947if (sleepFlag == CAN_SLEEP)3948msleep(1000);3949else3950mdelay(1000);3951}3952return -1;3953}39543955/* Use "Diagnostic reset" method! (only thing available!) */3956diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);39573958if (ioc->debug_level & MPT_DEBUG) {3959if (ioc->alt_ioc)3960diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);3961dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",3962ioc->name, diag0val, diag1val));3963}39643965/* Do the reset if we are told to ignore the reset history3966* or if the reset history is 03967*/3968if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {3969while ((diag0val & MPI_DIAG_DRWE) == 0) {3970/* Write magic sequence to WriteSequence register3971* Loop until in diagnostic mode3972*/3973CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);3974CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);3975CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);3976CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);3977CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);3978CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);39793980/* wait 100 msec */3981if (sleepFlag == CAN_SLEEP) {3982msleep (100);3983} else {3984mdelay (100);3985}39863987count++;3988if (count > 20) {3989printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",3990ioc->name, diag0val);3991return -2;39923993}39943995diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);39963997dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",3998ioc->name, diag0val));3999}40004001if (ioc->debug_level & MPT_DEBUG) {4002if (ioc->alt_ioc)4003diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);4004dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",4005ioc->name, diag0val, diag1val));4006}4007/*4008* Disable the ARM (Bug fix)4009*4010*/4011CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);4012mdelay(1);40134014/*4015* Now hit the reset bit in the Diagnostic register4016* (THE BIG HAMMER!) (Clears DRWE bit).4017*/4018CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);4019hard_reset_done = 1;4020dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",4021ioc->name));40224023/*4024* Call each currently registered protocol IOC reset handler4025* with pre-reset indication.4026* NOTE: If we're doing _IOC_BRINGUP, there can be no4027* MptResetHandlers[] registered yet.4028*/4029for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {4030if (MptResetHandlers[cb_idx]) {4031mpt_signal_reset(cb_idx,4032ioc, MPT_IOC_PRE_RESET);4033if (ioc->alt_ioc) {4034mpt_signal_reset(cb_idx,4035ioc->alt_ioc, MPT_IOC_PRE_RESET);4036}4037}4038}40394040if (ioc->cached_fw)4041cached_fw = (MpiFwHeader_t *)ioc->cached_fw;4042else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)4043cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;4044else4045cached_fw = NULL;4046if (cached_fw) {4047/* If the DownloadBoot operation fails, the4048* IOC will be left unusable. This is a fatal error4049* case. _diag_reset will return < 04050*/4051for (count = 0; count < 30; count ++) {4052diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);4053if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {4054break;4055}40564057dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",4058ioc->name, diag0val, count));4059/* wait 1 sec */4060if (sleepFlag == CAN_SLEEP) {4061msleep (1000);4062} else {4063mdelay (1000);4064}4065}4066if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {4067printk(MYIOC_s_WARN_FMT4068"firmware downloadboot failure (%d)!\n", ioc->name, count);4069}40704071} else {4072/* Wait for FW to reload and for board4073* to go to the READY state.4074* Maximum wait is 60 seconds.4075* If fail, no error will check again4076* with calling program.4077*/4078for (count = 0; count < 60; count ++) {4079doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);4080doorbell &= MPI_IOC_STATE_MASK;40814082drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT4083"looking for READY STATE: doorbell=%x"4084" count=%d\n", ioc->name, doorbell, count));40854086if (doorbell == MPI_IOC_STATE_READY) {4087break;4088}40894090/* wait 1 sec */4091if (sleepFlag == CAN_SLEEP) {4092msleep (1000);4093} else {4094mdelay (1000);4095}4096}40974098if (doorbell != MPI_IOC_STATE_READY)4099printk(MYIOC_s_ERR_FMT "Failed to come READY "4100"after reset! IocState=%x", ioc->name,4101doorbell);4102}4103}41044105diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);4106if (ioc->debug_level & MPT_DEBUG) {4107if (ioc->alt_ioc)4108diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);4109dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",4110ioc->name, diag0val, diag1val));4111}41124113/* Clear RESET_HISTORY bit! Place board in the4114* diagnostic mode to update the diag register.4115*/4116diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);4117count = 0;4118while ((diag0val & MPI_DIAG_DRWE) == 0) {4119/* Write magic sequence to WriteSequence register4120* Loop until in diagnostic mode4121*/4122CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);4123CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);4124CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);4125CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);4126CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);4127CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);41284129/* wait 100 msec */4130if (sleepFlag == CAN_SLEEP) {4131msleep (100);4132} else {4133mdelay (100);4134}41354136count++;4137if (count > 20) {4138printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",4139ioc->name, diag0val);4140break;4141}4142diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);4143}4144diag0val &= ~MPI_DIAG_RESET_HISTORY;4145CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);4146diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);4147if (diag0val & MPI_DIAG_RESET_HISTORY) {4148printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",4149ioc->name);4150}41514152/* Disable Diagnostic Mode4153*/4154CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);41554156/* Check FW reload status flags.4157*/4158diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);4159if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {4160printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",4161ioc->name, diag0val);4162return -3;4163}41644165if (ioc->debug_level & MPT_DEBUG) {4166if (ioc->alt_ioc)4167diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);4168dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",4169ioc->name, diag0val, diag1val));4170}41714172/*4173* Reset flag that says we've enabled event notification4174*/4175ioc->facts.EventState = 0;41764177if (ioc->alt_ioc)4178ioc->alt_ioc->facts.EventState = 0;41794180return hard_reset_done;4181}41824183/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/4184/**4185* SendIocReset - Send IOCReset request to MPT adapter.4186* @ioc: Pointer to MPT_ADAPTER structure4187* @reset_type: reset type, expected values are4188* %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET4189* @sleepFlag: Specifies whether the process can sleep4190*4191* Send IOCReset request to the MPT adapter.4192*4193* Returns 0 for success, non-zero for failure.4194*/4195static int4196SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)4197{4198int r;4199u32 state;4200int cntdn, count;42014202drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",4203ioc->name, reset_type));4204CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);4205if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)4206return r;42074208/* FW ACK'd request, wait for READY state4209*/4210count = 0;4211cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */42124213while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {4214cntdn--;4215count++;4216if (!cntdn) {4217if (sleepFlag != CAN_SLEEP)4218count *= 10;42194220printk(MYIOC_s_ERR_FMT4221"Wait IOC_READY state (0x%x) timeout(%d)!\n",4222ioc->name, state, (int)((count+5)/HZ));4223return -ETIME;4224}42254226if (sleepFlag == CAN_SLEEP) {4227msleep(1);4228} else {4229mdelay (1); /* 1 msec delay */4230}4231}42324233/* TODO!4234* Cleanup all event stuff for this IOC; re-issue EventNotification4235* request if needed.4236*/4237if (ioc->facts.Function)4238ioc->facts.EventState = 0;42394240return 0;4241}42424243/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/4244/**4245* initChainBuffers - Allocate memory for and initialize chain buffers4246* @ioc: Pointer to MPT_ADAPTER structure4247*4248* Allocates memory for and initializes chain buffers,4249* chain buffer control arrays and spinlock.4250*/4251static int4252initChainBuffers(MPT_ADAPTER *ioc)4253{4254u8 *mem;4255int sz, ii, num_chain;4256int scale, num_sge, numSGE;42574258/* ReqToChain size must equal the req_depth4259* index = req_idx4260*/4261if (ioc->ReqToChain == NULL) {4262sz = ioc->req_depth * sizeof(int);4263mem = kmalloc(sz, GFP_ATOMIC);4264if (mem == NULL)4265return -1;42664267ioc->ReqToChain = (int *) mem;4268dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",4269ioc->name, mem, sz));4270mem = kmalloc(sz, GFP_ATOMIC);4271if (mem == NULL)4272return -1;42734274ioc->RequestNB = (int *) mem;4275dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",4276ioc->name, mem, sz));4277}4278for (ii = 0; ii < ioc->req_depth; ii++) {4279ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;4280}42814282/* ChainToChain size must equal the total number4283* of chain buffers to be allocated.4284* index = chain_idx4285*4286* Calculate the number of chain buffers needed(plus 1) per I/O4287* then multiply the maximum number of simultaneous cmds4288*4289* num_sge = num sge in request frame + last chain buffer4290* scale = num sge per chain buffer if no chain element4291*/4292scale = ioc->req_sz / ioc->SGE_size;4293if (ioc->sg_addr_size == sizeof(u64))4294num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;4295else4296num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;42974298if (ioc->sg_addr_size == sizeof(u64)) {4299numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +4300(ioc->req_sz - 60) / ioc->SGE_size;4301} else {4302numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +4303scale + (ioc->req_sz - 64) / ioc->SGE_size;4304}4305dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",4306ioc->name, num_sge, numSGE));43074308if (ioc->bus_type == FC) {4309if (numSGE > MPT_SCSI_FC_SG_DEPTH)4310numSGE = MPT_SCSI_FC_SG_DEPTH;4311} else {4312if (numSGE > MPT_SCSI_SG_DEPTH)4313numSGE = MPT_SCSI_SG_DEPTH;4314}43154316num_chain = 1;4317while (numSGE - num_sge > 0) {4318num_chain++;4319num_sge += (scale - 1);4320}4321num_chain++;43224323dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",4324ioc->name, numSGE, num_sge, num_chain));43254326if (ioc->bus_type == SPI)4327num_chain *= MPT_SCSI_CAN_QUEUE;4328else if (ioc->bus_type == SAS)4329num_chain *= MPT_SAS_CAN_QUEUE;4330else4331num_chain *= MPT_FC_CAN_QUEUE;43324333ioc->num_chain = num_chain;43344335sz = num_chain * sizeof(int);4336if (ioc->ChainToChain == NULL) {4337mem = kmalloc(sz, GFP_ATOMIC);4338if (mem == NULL)4339return -1;43404341ioc->ChainToChain = (int *) mem;4342dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",4343ioc->name, mem, sz));4344} else {4345mem = (u8 *) ioc->ChainToChain;4346}4347memset(mem, 0xFF, sz);4348return num_chain;4349}43504351/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/4352/**4353* PrimeIocFifos - Initialize IOC request and reply FIFOs.4354* @ioc: Pointer to MPT_ADAPTER structure4355*4356* This routine allocates memory for the MPT reply and request frame4357* pools (if necessary), and primes the IOC reply FIFO with4358* reply frames.4359*4360* Returns 0 for success, non-zero for failure.4361*/4362static int4363PrimeIocFifos(MPT_ADAPTER *ioc)4364{4365MPT_FRAME_HDR *mf;4366unsigned long flags;4367dma_addr_t alloc_dma;4368u8 *mem;4369int i, reply_sz, sz, total_size, num_chain;4370u64 dma_mask;43714372dma_mask = 0;43734374/* Prime reply FIFO... */43754376if (ioc->reply_frames == NULL) {4377if ( (num_chain = initChainBuffers(ioc)) < 0)4378return -1;4379/*4380* 1078 errata workaround for the 36GB limitation4381*/4382if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&4383ioc->dma_mask > DMA_BIT_MASK(35)) {4384if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))4385&& !pci_set_consistent_dma_mask(ioc->pcidev,4386DMA_BIT_MASK(32))) {4387dma_mask = DMA_BIT_MASK(35);4388d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT4389"setting 35 bit addressing for "4390"Request/Reply/Chain and Sense Buffers\n",4391ioc->name));4392} else {4393/*Reseting DMA mask to 64 bit*/4394pci_set_dma_mask(ioc->pcidev,4395DMA_BIT_MASK(64));4396pci_set_consistent_dma_mask(ioc->pcidev,4397DMA_BIT_MASK(64));43984399printk(MYIOC_s_ERR_FMT4400"failed setting 35 bit addressing for "4401"Request/Reply/Chain and Sense Buffers\n",4402ioc->name);4403return -1;4404}4405}44064407total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);4408dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",4409ioc->name, ioc->reply_sz, ioc->reply_depth));4410dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",4411ioc->name, reply_sz, reply_sz));44124413sz = (ioc->req_sz * ioc->req_depth);4414dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",4415ioc->name, ioc->req_sz, ioc->req_depth));4416dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",4417ioc->name, sz, sz));4418total_size += sz;44194420sz = num_chain * ioc->req_sz; /* chain buffer pool size */4421dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",4422ioc->name, ioc->req_sz, num_chain));4423dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",4424ioc->name, sz, sz, num_chain));44254426total_size += sz;4427mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);4428if (mem == NULL) {4429printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",4430ioc->name);4431goto out_fail;4432}44334434dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",4435ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));44364437memset(mem, 0, total_size);4438ioc->alloc_total += total_size;4439ioc->alloc = mem;4440ioc->alloc_dma = alloc_dma;4441ioc->alloc_sz = total_size;4442ioc->reply_frames = (MPT_FRAME_HDR *) mem;4443ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);44444445dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",4446ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));44474448alloc_dma += reply_sz;4449mem += reply_sz;44504451/* Request FIFO - WE manage this! */44524453ioc->req_frames = (MPT_FRAME_HDR *) mem;4454ioc->req_frames_dma = alloc_dma;44554456dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",4457ioc->name, mem, (void *)(ulong)alloc_dma));44584459ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);44604461#if defined(CONFIG_MTRR) && 04462/*4463* Enable Write Combining MTRR for IOC's memory region.4464* (at least as much as we can; "size and base must be4465* multiples of 4 kiB"4466*/4467ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,4468sz,4469MTRR_TYPE_WRCOMB, 1);4470dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",4471ioc->name, ioc->req_frames_dma, sz));4472#endif44734474for (i = 0; i < ioc->req_depth; i++) {4475alloc_dma += ioc->req_sz;4476mem += ioc->req_sz;4477}44784479ioc->ChainBuffer = mem;4480ioc->ChainBufferDMA = alloc_dma;44814482dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",4483ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));44844485/* Initialize the free chain Q.4486*/44874488INIT_LIST_HEAD(&ioc->FreeChainQ);44894490/* Post the chain buffers to the FreeChainQ.4491*/4492mem = (u8 *)ioc->ChainBuffer;4493for (i=0; i < num_chain; i++) {4494mf = (MPT_FRAME_HDR *) mem;4495list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);4496mem += ioc->req_sz;4497}44984499/* Initialize Request frames linked list4500*/4501alloc_dma = ioc->req_frames_dma;4502mem = (u8 *) ioc->req_frames;45034504spin_lock_irqsave(&ioc->FreeQlock, flags);4505INIT_LIST_HEAD(&ioc->FreeQ);4506for (i = 0; i < ioc->req_depth; i++) {4507mf = (MPT_FRAME_HDR *) mem;45084509/* Queue REQUESTs *internally*! */4510list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);45114512mem += ioc->req_sz;4513}4514spin_unlock_irqrestore(&ioc->FreeQlock, flags);45154516sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);4517ioc->sense_buf_pool =4518pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);4519if (ioc->sense_buf_pool == NULL) {4520printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",4521ioc->name);4522goto out_fail;4523}45244525ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);4526ioc->alloc_total += sz;4527dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",4528ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));45294530}45314532/* Post Reply frames to FIFO4533*/4534alloc_dma = ioc->alloc_dma;4535dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",4536ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));45374538for (i = 0; i < ioc->reply_depth; i++) {4539/* Write each address to the IOC! */4540CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);4541alloc_dma += ioc->reply_sz;4542}45434544if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,4545ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,4546ioc->dma_mask))4547d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT4548"restoring 64 bit addressing\n", ioc->name));45494550return 0;45514552out_fail:45534554if (ioc->alloc != NULL) {4555sz = ioc->alloc_sz;4556pci_free_consistent(ioc->pcidev,4557sz,4558ioc->alloc, ioc->alloc_dma);4559ioc->reply_frames = NULL;4560ioc->req_frames = NULL;4561ioc->alloc_total -= sz;4562}4563if (ioc->sense_buf_pool != NULL) {4564sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);4565pci_free_consistent(ioc->pcidev,4566sz,4567ioc->sense_buf_pool, ioc->sense_buf_pool_dma);4568ioc->sense_buf_pool = NULL;4569}45704571if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,4572DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,4573DMA_BIT_MASK(64)))4574d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT4575"restoring 64 bit addressing\n", ioc->name));45764577return -1;4578}45794580/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/4581/**4582* mpt_handshake_req_reply_wait - Send MPT request to and receive reply4583* from IOC via doorbell handshake method.4584* @ioc: Pointer to MPT_ADAPTER structure4585* @reqBytes: Size of the request in bytes4586* @req: Pointer to MPT request frame4587* @replyBytes: Expected size of the reply in bytes4588* @u16reply: Pointer to area where reply should be written4589* @maxwait: Max wait time for a reply (in seconds)4590* @sleepFlag: Specifies whether the process can sleep4591*4592* NOTES: It is the callers responsibility to byte-swap fields in the4593* request which are greater than 1 byte in size. It is also the4594* callers responsibility to byte-swap response fields which are4595* greater than 1 byte in size.4596*4597* Returns 0 for success, non-zero for failure.4598*/4599static int4600mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,4601int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)4602{4603MPIDefaultReply_t *mptReply;4604int failcnt = 0;4605int t;46064607/*4608* Get ready to cache a handshake reply4609*/4610ioc->hs_reply_idx = 0;4611mptReply = (MPIDefaultReply_t *) ioc->hs_reply;4612mptReply->MsgLength = 0;46134614/*4615* Make sure there are no doorbells (WRITE 0 to IntStatus reg),4616* then tell IOC that we want to handshake a request of N words.4617* (WRITE u32val to Doorbell reg).4618*/4619CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);4620CHIPREG_WRITE32(&ioc->chip->Doorbell,4621((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |4622((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));46234624/*4625* Wait for IOC's doorbell handshake int4626*/4627if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)4628failcnt++;46294630dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",4631ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));46324633/* Read doorbell and check for active bit */4634if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))4635return -1;46364637/*4638* Clear doorbell int (WRITE 0 to IntStatus reg),4639* then wait for IOC to ACKnowledge that it's ready for4640* our handshake request.4641*/4642CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);4643if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)4644failcnt++;46454646if (!failcnt) {4647int ii;4648u8 *req_as_bytes = (u8 *) req;46494650/*4651* Stuff request words via doorbell handshake,4652* with ACK from IOC for each.4653*/4654for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {4655u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |4656(req_as_bytes[(ii*4) + 1] << 8) |4657(req_as_bytes[(ii*4) + 2] << 16) |4658(req_as_bytes[(ii*4) + 3] << 24));46594660CHIPREG_WRITE32(&ioc->chip->Doorbell, word);4661if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)4662failcnt++;4663}46644665dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));4666DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);46674668dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",4669ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));46704671/*4672* Wait for completion of doorbell handshake reply from the IOC4673*/4674if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)4675failcnt++;46764677dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",4678ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));46794680/*4681* Copy out the cached reply...4682*/4683for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)4684u16reply[ii] = ioc->hs_reply[ii];4685} else {4686return -99;4687}46884689return -failcnt;4690}46914692/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/4693/**4694* WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge4695* @ioc: Pointer to MPT_ADAPTER structure4696* @howlong: How long to wait (in seconds)4697* @sleepFlag: Specifies whether the process can sleep4698*4699* This routine waits (up to ~2 seconds max) for IOC doorbell4700* handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS4701* bit in its IntStatus register being clear.4702*4703* Returns a negative value on failure, else wait loop count.4704*/4705static int4706WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)4707{4708int cntdn;4709int count = 0;4710u32 intstat=0;47114712cntdn = 1000 * howlong;47134714if (sleepFlag == CAN_SLEEP) {4715while (--cntdn) {4716msleep (1);4717intstat = CHIPREG_READ32(&ioc->chip->IntStatus);4718if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))4719break;4720count++;4721}4722} else {4723while (--cntdn) {4724udelay (1000);4725intstat = CHIPREG_READ32(&ioc->chip->IntStatus);4726if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))4727break;4728count++;4729}4730}47314732if (cntdn) {4733dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",4734ioc->name, count));4735return count;4736}47374738printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",4739ioc->name, count, intstat);4740return -1;4741}47424743/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/4744/**4745* WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit4746* @ioc: Pointer to MPT_ADAPTER structure4747* @howlong: How long to wait (in seconds)4748* @sleepFlag: Specifies whether the process can sleep4749*4750* This routine waits (up to ~2 seconds max) for IOC doorbell interrupt4751* (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.4752*4753* Returns a negative value on failure, else wait loop count.4754*/4755static int4756WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)4757{4758int cntdn;4759int count = 0;4760u32 intstat=0;47614762cntdn = 1000 * howlong;4763if (sleepFlag == CAN_SLEEP) {4764while (--cntdn) {4765intstat = CHIPREG_READ32(&ioc->chip->IntStatus);4766if (intstat & MPI_HIS_DOORBELL_INTERRUPT)4767break;4768msleep(1);4769count++;4770}4771} else {4772while (--cntdn) {4773intstat = CHIPREG_READ32(&ioc->chip->IntStatus);4774if (intstat & MPI_HIS_DOORBELL_INTERRUPT)4775break;4776udelay (1000);4777count++;4778}4779}47804781if (cntdn) {4782dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",4783ioc->name, count, howlong));4784return count;4785}47864787printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",4788ioc->name, count, intstat);4789return -1;4790}47914792/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/4793/**4794* WaitForDoorbellReply - Wait for and capture an IOC handshake reply.4795* @ioc: Pointer to MPT_ADAPTER structure4796* @howlong: How long to wait (in seconds)4797* @sleepFlag: Specifies whether the process can sleep4798*4799* This routine polls the IOC for a handshake reply, 16 bits at a time.4800* Reply is cached to IOC private area large enough to hold a maximum4801* of 128 bytes of reply data.4802*4803* Returns a negative value on failure, else size of reply in WORDS.4804*/4805static int4806WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)4807{4808int u16cnt = 0;4809int failcnt = 0;4810int t;4811u16 *hs_reply = ioc->hs_reply;4812volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;4813u16 hword;48144815hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;48164817/*4818* Get first two u16's so we can look at IOC's intended reply MsgLength4819*/4820u16cnt=0;4821if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {4822failcnt++;4823} else {4824hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);4825CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);4826if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)4827failcnt++;4828else {4829hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);4830CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);4831}4832}48334834dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",4835ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),4836failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));48374838/*4839* If no error (and IOC said MsgLength is > 0), piece together4840* reply 16 bits at a time.4841*/4842for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {4843if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)4844failcnt++;4845hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);4846/* don't overflow our IOC hs_reply[] buffer! */4847if (u16cnt < ARRAY_SIZE(ioc->hs_reply))4848hs_reply[u16cnt] = hword;4849CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);4850}48514852if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)4853failcnt++;4854CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);48554856if (failcnt) {4857printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",4858ioc->name);4859return -failcnt;4860}4861#if 04862else if (u16cnt != (2 * mptReply->MsgLength)) {4863return -101;4864}4865else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {4866return -102;4867}4868#endif48694870dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));4871DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);48724873dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",4874ioc->name, t, u16cnt/2));4875return u16cnt/2;4876}48774878/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/4879/**4880* GetLanConfigPages - Fetch LANConfig pages.4881* @ioc: Pointer to MPT_ADAPTER structure4882*4883* Return: 0 for success4884* -ENOMEM if no memory available4885* -EPERM if not allowed due to ISR context4886* -EAGAIN if no msg frames currently available4887* -EFAULT for non-successful reply or no reply (timeout)4888*/4889static int4890GetLanConfigPages(MPT_ADAPTER *ioc)4891{4892ConfigPageHeader_t hdr;4893CONFIGPARMS cfg;4894LANPage0_t *ppage0_alloc;4895dma_addr_t page0_dma;4896LANPage1_t *ppage1_alloc;4897dma_addr_t page1_dma;4898int rc = 0;4899int data_sz;4900int copy_sz;49014902/* Get LAN Page 0 header */4903hdr.PageVersion = 0;4904hdr.PageLength = 0;4905hdr.PageNumber = 0;4906hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;4907cfg.cfghdr.hdr = &hdr;4908cfg.physAddr = -1;4909cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;4910cfg.dir = 0;4911cfg.pageAddr = 0;4912cfg.timeout = 0;49134914if ((rc = mpt_config(ioc, &cfg)) != 0)4915return rc;49164917if (hdr.PageLength > 0) {4918data_sz = hdr.PageLength * 4;4919ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);4920rc = -ENOMEM;4921if (ppage0_alloc) {4922memset((u8 *)ppage0_alloc, 0, data_sz);4923cfg.physAddr = page0_dma;4924cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;49254926if ((rc = mpt_config(ioc, &cfg)) == 0) {4927/* save the data */4928copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);4929memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);49304931}49324933pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);49344935/* FIXME!4936* Normalize endianness of structure data,4937* by byte-swapping all > 1 byte fields!4938*/49394940}49414942if (rc)4943return rc;4944}49454946/* Get LAN Page 1 header */4947hdr.PageVersion = 0;4948hdr.PageLength = 0;4949hdr.PageNumber = 1;4950hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;4951cfg.cfghdr.hdr = &hdr;4952cfg.physAddr = -1;4953cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;4954cfg.dir = 0;4955cfg.pageAddr = 0;49564957if ((rc = mpt_config(ioc, &cfg)) != 0)4958return rc;49594960if (hdr.PageLength == 0)4961return 0;49624963data_sz = hdr.PageLength * 4;4964rc = -ENOMEM;4965ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);4966if (ppage1_alloc) {4967memset((u8 *)ppage1_alloc, 0, data_sz);4968cfg.physAddr = page1_dma;4969cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;49704971if ((rc = mpt_config(ioc, &cfg)) == 0) {4972/* save the data */4973copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);4974memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);4975}49764977pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);49784979/* FIXME!4980* Normalize endianness of structure data,4981* by byte-swapping all > 1 byte fields!4982*/49834984}49854986return rc;4987}49884989/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/4990/**4991* mptbase_sas_persist_operation - Perform operation on SAS Persistent Table4992* @ioc: Pointer to MPT_ADAPTER structure4993* @persist_opcode: see below4994*4995* MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for4996* devices not currently present.4997* MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings4998*4999* NOTE: Don't use not this function during interrupt time.5000*5001* Returns 0 for success, non-zero error5002*/50035004/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/5005int5006mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)5007{5008SasIoUnitControlRequest_t *sasIoUnitCntrReq;5009SasIoUnitControlReply_t *sasIoUnitCntrReply;5010MPT_FRAME_HDR *mf = NULL;5011MPIHeader_t *mpi_hdr;5012int ret = 0;5013unsigned long timeleft;50145015mutex_lock(&ioc->mptbase_cmds.mutex);50165017/* init the internal cmd struct */5018memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);5019INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)50205021/* insure garbage is not sent to fw */5022switch(persist_opcode) {50235024case MPI_SAS_OP_CLEAR_NOT_PRESENT:5025case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:5026break;50275028default:5029ret = -1;5030goto out;5031}50325033printk(KERN_DEBUG "%s: persist_opcode=%x\n",5034__func__, persist_opcode);50355036/* Get a MF for this command.5037*/5038if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {5039printk(KERN_DEBUG "%s: no msg frames!\n", __func__);5040ret = -1;5041goto out;5042}50435044mpi_hdr = (MPIHeader_t *) mf;5045sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;5046memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));5047sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;5048sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;5049sasIoUnitCntrReq->Operation = persist_opcode;50505051mpt_put_msg_frame(mpt_base_index, ioc, mf);5052timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);5053if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {5054ret = -ETIME;5055printk(KERN_DEBUG "%s: failed\n", __func__);5056if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)5057goto out;5058if (!timeleft) {5059printk(MYIOC_s_WARN_FMT5060"Issuing Reset from %s!!, doorbell=0x%08x\n",5061ioc->name, __func__, mpt_GetIocState(ioc, 0));5062mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);5063mpt_free_msg_frame(ioc, mf);5064}5065goto out;5066}50675068if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {5069ret = -1;5070goto out;5071}50725073sasIoUnitCntrReply =5074(SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;5075if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {5076printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",5077__func__, sasIoUnitCntrReply->IOCStatus,5078sasIoUnitCntrReply->IOCLogInfo);5079printk(KERN_DEBUG "%s: failed\n", __func__);5080ret = -1;5081} else5082printk(KERN_DEBUG "%s: success\n", __func__);5083out:50845085CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)5086mutex_unlock(&ioc->mptbase_cmds.mutex);5087return ret;5088}50895090/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/50915092static void5093mptbase_raid_process_event_data(MPT_ADAPTER *ioc,5094MpiEventDataRaid_t * pRaidEventData)5095{5096int volume;5097int reason;5098int disk;5099int status;5100int flags;5101int state;51025103volume = pRaidEventData->VolumeID;5104reason = pRaidEventData->ReasonCode;5105disk = pRaidEventData->PhysDiskNum;5106status = le32_to_cpu(pRaidEventData->SettingsStatus);5107flags = (status >> 0) & 0xff;5108state = (status >> 8) & 0xff;51095110if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {5111return;5112}51135114if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&5115reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||5116(reason == MPI_EVENT_RAID_RC_SMART_DATA)) {5117printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",5118ioc->name, disk, volume);5119} else {5120printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",5121ioc->name, volume);5122}51235124switch(reason) {5125case MPI_EVENT_RAID_RC_VOLUME_CREATED:5126printk(MYIOC_s_INFO_FMT " volume has been created\n",5127ioc->name);5128break;51295130case MPI_EVENT_RAID_RC_VOLUME_DELETED:51315132printk(MYIOC_s_INFO_FMT " volume has been deleted\n",5133ioc->name);5134break;51355136case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:5137printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",5138ioc->name);5139break;51405141case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:5142printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",5143ioc->name,5144state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL5145? "optimal"5146: state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED5147? "degraded"5148: state == MPI_RAIDVOL0_STATUS_STATE_FAILED5149? "failed"5150: "state unknown",5151flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED5152? ", enabled" : "",5153flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED5154? ", quiesced" : "",5155flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS5156? ", resync in progress" : "" );5157break;51585159case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:5160printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",5161ioc->name, disk);5162break;51635164case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:5165printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",5166ioc->name);5167break;51685169case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:5170printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",5171ioc->name);5172break;51735174case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:5175printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",5176ioc->name);5177break;51785179case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:5180printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",5181ioc->name,5182state == MPI_PHYSDISK0_STATUS_ONLINE5183? "online"5184: state == MPI_PHYSDISK0_STATUS_MISSING5185? "missing"5186: state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE5187? "not compatible"5188: state == MPI_PHYSDISK0_STATUS_FAILED5189? "failed"5190: state == MPI_PHYSDISK0_STATUS_INITIALIZING5191? "initializing"5192: state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED5193? "offline requested"5194: state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED5195? "failed requested"5196: state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE5197? "offline"5198: "state unknown",5199flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC5200? ", out of sync" : "",5201flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED5202? ", quiesced" : "" );5203break;52045205case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:5206printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",5207ioc->name, disk);5208break;52095210case MPI_EVENT_RAID_RC_SMART_DATA:5211printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",5212ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);5213break;52145215case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:5216printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",5217ioc->name, disk);5218break;5219}5220}52215222/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/5223/**5224* GetIoUnitPage2 - Retrieve BIOS version and boot order information.5225* @ioc: Pointer to MPT_ADAPTER structure5226*5227* Returns: 0 for success5228* -ENOMEM if no memory available5229* -EPERM if not allowed due to ISR context5230* -EAGAIN if no msg frames currently available5231* -EFAULT for non-successful reply or no reply (timeout)5232*/5233static int5234GetIoUnitPage2(MPT_ADAPTER *ioc)5235{5236ConfigPageHeader_t hdr;5237CONFIGPARMS cfg;5238IOUnitPage2_t *ppage_alloc;5239dma_addr_t page_dma;5240int data_sz;5241int rc;52425243/* Get the page header */5244hdr.PageVersion = 0;5245hdr.PageLength = 0;5246hdr.PageNumber = 2;5247hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;5248cfg.cfghdr.hdr = &hdr;5249cfg.physAddr = -1;5250cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;5251cfg.dir = 0;5252cfg.pageAddr = 0;5253cfg.timeout = 0;52545255if ((rc = mpt_config(ioc, &cfg)) != 0)5256return rc;52575258if (hdr.PageLength == 0)5259return 0;52605261/* Read the config page */5262data_sz = hdr.PageLength * 4;5263rc = -ENOMEM;5264ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);5265if (ppage_alloc) {5266memset((u8 *)ppage_alloc, 0, data_sz);5267cfg.physAddr = page_dma;5268cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;52695270/* If Good, save data */5271if ((rc = mpt_config(ioc, &cfg)) == 0)5272ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);52735274pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);5275}52765277return rc;5278}52795280/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/5281/**5282* mpt_GetScsiPortSettings - read SCSI Port Page 0 and 25283* @ioc: Pointer to a Adapter Strucutre5284* @portnum: IOC port number5285*5286* Return: -EFAULT if read of config page header fails5287* or if no nvram5288* If read of SCSI Port Page 0 fails,5289* NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)5290* Adapter settings: async, narrow5291* Return 15292* If read of SCSI Port Page 2 fails,5293* Adapter settings valid5294* NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)5295* Return 15296* Else5297* Both valid5298* Return 05299* CHECK - what type of locking mechanisms should be used????5300*/5301static int5302mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)5303{5304u8 *pbuf;5305dma_addr_t buf_dma;5306CONFIGPARMS cfg;5307ConfigPageHeader_t header;5308int ii;5309int data, rc = 0;53105311/* Allocate memory5312*/5313if (!ioc->spi_data.nvram) {5314int sz;5315u8 *mem;5316sz = MPT_MAX_SCSI_DEVICES * sizeof(int);5317mem = kmalloc(sz, GFP_ATOMIC);5318if (mem == NULL)5319return -EFAULT;53205321ioc->spi_data.nvram = (int *) mem;53225323dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",5324ioc->name, ioc->spi_data.nvram, sz));5325}53265327/* Invalidate NVRAM information5328*/5329for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {5330ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;5331}53325333/* Read SPP0 header, allocate memory, then read page.5334*/5335header.PageVersion = 0;5336header.PageLength = 0;5337header.PageNumber = 0;5338header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;5339cfg.cfghdr.hdr = &header;5340cfg.physAddr = -1;5341cfg.pageAddr = portnum;5342cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;5343cfg.dir = 0;5344cfg.timeout = 0; /* use default */5345if (mpt_config(ioc, &cfg) != 0)5346return -EFAULT;53475348if (header.PageLength > 0) {5349pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);5350if (pbuf) {5351cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;5352cfg.physAddr = buf_dma;5353if (mpt_config(ioc, &cfg) != 0) {5354ioc->spi_data.maxBusWidth = MPT_NARROW;5355ioc->spi_data.maxSyncOffset = 0;5356ioc->spi_data.minSyncFactor = MPT_ASYNC;5357ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;5358rc = 1;5359ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT5360"Unable to read PortPage0 minSyncFactor=%x\n",5361ioc->name, ioc->spi_data.minSyncFactor));5362} else {5363/* Save the Port Page 0 data5364*/5365SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;5366pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);5367pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);53685369if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {5370ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;5371ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT5372"noQas due to Capabilities=%x\n",5373ioc->name, pPP0->Capabilities));5374}5375ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;5376data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;5377if (data) {5378ioc->spi_data.maxSyncOffset = (u8) (data >> 16);5379data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;5380ioc->spi_data.minSyncFactor = (u8) (data >> 8);5381ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT5382"PortPage0 minSyncFactor=%x\n",5383ioc->name, ioc->spi_data.minSyncFactor));5384} else {5385ioc->spi_data.maxSyncOffset = 0;5386ioc->spi_data.minSyncFactor = MPT_ASYNC;5387}53885389ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;53905391/* Update the minSyncFactor based on bus type.5392*/5393if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||5394(ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {53955396if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {5397ioc->spi_data.minSyncFactor = MPT_ULTRA;5398ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT5399"HVD or SE detected, minSyncFactor=%x\n",5400ioc->name, ioc->spi_data.minSyncFactor));5401}5402}5403}5404if (pbuf) {5405pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);5406}5407}5408}54095410/* SCSI Port Page 2 - Read the header then the page.5411*/5412header.PageVersion = 0;5413header.PageLength = 0;5414header.PageNumber = 2;5415header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;5416cfg.cfghdr.hdr = &header;5417cfg.physAddr = -1;5418cfg.pageAddr = portnum;5419cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;5420cfg.dir = 0;5421if (mpt_config(ioc, &cfg) != 0)5422return -EFAULT;54235424if (header.PageLength > 0) {5425/* Allocate memory and read SCSI Port Page 25426*/5427pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);5428if (pbuf) {5429cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;5430cfg.physAddr = buf_dma;5431if (mpt_config(ioc, &cfg) != 0) {5432/* Nvram data is left with INVALID mark5433*/5434rc = 1;5435} else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {54365437/* This is an ATTO adapter, read Page2 accordingly5438*/5439ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;5440ATTODeviceInfo_t *pdevice = NULL;5441u16 ATTOFlags;54425443/* Save the Port Page 2 data5444* (reformat into a 32bit quantity)5445*/5446for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {5447pdevice = &pPP2->DeviceSettings[ii];5448ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);5449data = 0;54505451/* Translate ATTO device flags to LSI format5452*/5453if (ATTOFlags & ATTOFLAG_DISC)5454data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);5455if (ATTOFlags & ATTOFLAG_ID_ENB)5456data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);5457if (ATTOFlags & ATTOFLAG_LUN_ENB)5458data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);5459if (ATTOFlags & ATTOFLAG_TAGGED)5460data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);5461if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))5462data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);54635464data = (data << 16) | (pdevice->Period << 8) | 10;5465ioc->spi_data.nvram[ii] = data;5466}5467} else {5468SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;5469MpiDeviceInfo_t *pdevice = NULL;54705471/*5472* Save "Set to Avoid SCSI Bus Resets" flag5473*/5474ioc->spi_data.bus_reset =5475(le32_to_cpu(pPP2->PortFlags) &5476MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?54770 : 1 ;54785479/* Save the Port Page 2 data5480* (reformat into a 32bit quantity)5481*/5482data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;5483ioc->spi_data.PortFlags = data;5484for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {5485pdevice = &pPP2->DeviceSettings[ii];5486data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |5487(pdevice->SyncFactor << 8) | pdevice->Timeout;5488ioc->spi_data.nvram[ii] = data;5489}5490}54915492pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);5493}5494}54955496/* Update Adapter limits with those from NVRAM5497* Comment: Don't need to do this. Target performance5498* parameters will never exceed the adapters limits.5499*/55005501return rc;5502}55035504/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/5505/**5506* mpt_readScsiDevicePageHeaders - save version and length of SDP15507* @ioc: Pointer to a Adapter Strucutre5508* @portnum: IOC port number5509*5510* Return: -EFAULT if read of config page header fails5511* or 0 if success.5512*/5513static int5514mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)5515{5516CONFIGPARMS cfg;5517ConfigPageHeader_t header;55185519/* Read the SCSI Device Page 1 header5520*/5521header.PageVersion = 0;5522header.PageLength = 0;5523header.PageNumber = 1;5524header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;5525cfg.cfghdr.hdr = &header;5526cfg.physAddr = -1;5527cfg.pageAddr = portnum;5528cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;5529cfg.dir = 0;5530cfg.timeout = 0;5531if (mpt_config(ioc, &cfg) != 0)5532return -EFAULT;55335534ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;5535ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;55365537header.PageVersion = 0;5538header.PageLength = 0;5539header.PageNumber = 0;5540header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;5541if (mpt_config(ioc, &cfg) != 0)5542return -EFAULT;55435544ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;5545ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;55465547dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",5548ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));55495550dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",5551ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));5552return 0;5553}55545555/**5556* mpt_inactive_raid_list_free - This clears this link list.5557* @ioc : pointer to per adapter structure5558**/5559static void5560mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)5561{5562struct inactive_raid_component_info *component_info, *pNext;55635564if (list_empty(&ioc->raid_data.inactive_list))5565return;55665567mutex_lock(&ioc->raid_data.inactive_list_mutex);5568list_for_each_entry_safe(component_info, pNext,5569&ioc->raid_data.inactive_list, list) {5570list_del(&component_info->list);5571kfree(component_info);5572}5573mutex_unlock(&ioc->raid_data.inactive_list_mutex);5574}55755576/**5577* mpt_inactive_raid_volumes - sets up link list of phy_disk_nums for devices belonging in an inactive volume5578*5579* @ioc : pointer to per adapter structure5580* @channel : volume channel5581* @id : volume target id5582**/5583static void5584mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)5585{5586CONFIGPARMS cfg;5587ConfigPageHeader_t hdr;5588dma_addr_t dma_handle;5589pRaidVolumePage0_t buffer = NULL;5590int i;5591RaidPhysDiskPage0_t phys_disk;5592struct inactive_raid_component_info *component_info;5593int handle_inactive_volumes;55945595memset(&cfg, 0 , sizeof(CONFIGPARMS));5596memset(&hdr, 0 , sizeof(ConfigPageHeader_t));5597hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;5598cfg.pageAddr = (channel << 8) + id;5599cfg.cfghdr.hdr = &hdr;5600cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;56015602if (mpt_config(ioc, &cfg) != 0)5603goto out;56045605if (!hdr.PageLength)5606goto out;56075608buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,5609&dma_handle);56105611if (!buffer)5612goto out;56135614cfg.physAddr = dma_handle;5615cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;56165617if (mpt_config(ioc, &cfg) != 0)5618goto out;56195620if (!buffer->NumPhysDisks)5621goto out;56225623handle_inactive_volumes =5624(buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||5625(buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||5626buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||5627buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;56285629if (!handle_inactive_volumes)5630goto out;56315632mutex_lock(&ioc->raid_data.inactive_list_mutex);5633for (i = 0; i < buffer->NumPhysDisks; i++) {5634if(mpt_raid_phys_disk_pg0(ioc,5635buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)5636continue;56375638if ((component_info = kmalloc(sizeof (*component_info),5639GFP_KERNEL)) == NULL)5640continue;56415642component_info->volumeID = id;5643component_info->volumeBus = channel;5644component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;5645component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;5646component_info->d.PhysDiskID = phys_disk.PhysDiskID;5647component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;56485649list_add_tail(&component_info->list,5650&ioc->raid_data.inactive_list);5651}5652mutex_unlock(&ioc->raid_data.inactive_list_mutex);56535654out:5655if (buffer)5656pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,5657dma_handle);5658}56595660/**5661* mpt_raid_phys_disk_pg0 - returns phys disk page zero5662* @ioc: Pointer to a Adapter Structure5663* @phys_disk_num: io unit unique phys disk num generated by the ioc5664* @phys_disk: requested payload data returned5665*5666* Return:5667* 0 on success5668* -EFAULT if read of config page header fails or data pointer not NULL5669* -ENOMEM if pci_alloc failed5670**/5671int5672mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,5673RaidPhysDiskPage0_t *phys_disk)5674{5675CONFIGPARMS cfg;5676ConfigPageHeader_t hdr;5677dma_addr_t dma_handle;5678pRaidPhysDiskPage0_t buffer = NULL;5679int rc;56805681memset(&cfg, 0 , sizeof(CONFIGPARMS));5682memset(&hdr, 0 , sizeof(ConfigPageHeader_t));5683memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));56845685hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;5686hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;5687cfg.cfghdr.hdr = &hdr;5688cfg.physAddr = -1;5689cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;56905691if (mpt_config(ioc, &cfg) != 0) {5692rc = -EFAULT;5693goto out;5694}56955696if (!hdr.PageLength) {5697rc = -EFAULT;5698goto out;5699}57005701buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,5702&dma_handle);57035704if (!buffer) {5705rc = -ENOMEM;5706goto out;5707}57085709cfg.physAddr = dma_handle;5710cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;5711cfg.pageAddr = phys_disk_num;57125713if (mpt_config(ioc, &cfg) != 0) {5714rc = -EFAULT;5715goto out;5716}57175718rc = 0;5719memcpy(phys_disk, buffer, sizeof(*buffer));5720phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);57215722out:57235724if (buffer)5725pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,5726dma_handle);57275728return rc;5729}57305731/**5732* mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num5733* @ioc: Pointer to a Adapter Structure5734* @phys_disk_num: io unit unique phys disk num generated by the ioc5735*5736* Return:5737* returns number paths5738**/5739int5740mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)5741{5742CONFIGPARMS cfg;5743ConfigPageHeader_t hdr;5744dma_addr_t dma_handle;5745pRaidPhysDiskPage1_t buffer = NULL;5746int rc;57475748memset(&cfg, 0 , sizeof(CONFIGPARMS));5749memset(&hdr, 0 , sizeof(ConfigPageHeader_t));57505751hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;5752hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;5753hdr.PageNumber = 1;5754cfg.cfghdr.hdr = &hdr;5755cfg.physAddr = -1;5756cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;57575758if (mpt_config(ioc, &cfg) != 0) {5759rc = 0;5760goto out;5761}57625763if (!hdr.PageLength) {5764rc = 0;5765goto out;5766}57675768buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,5769&dma_handle);57705771if (!buffer) {5772rc = 0;5773goto out;5774}57755776cfg.physAddr = dma_handle;5777cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;5778cfg.pageAddr = phys_disk_num;57795780if (mpt_config(ioc, &cfg) != 0) {5781rc = 0;5782goto out;5783}57845785rc = buffer->NumPhysDiskPaths;5786out:57875788if (buffer)5789pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,5790dma_handle);57915792return rc;5793}5794EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);57955796/**5797* mpt_raid_phys_disk_pg1 - returns phys disk page 15798* @ioc: Pointer to a Adapter Structure5799* @phys_disk_num: io unit unique phys disk num generated by the ioc5800* @phys_disk: requested payload data returned5801*5802* Return:5803* 0 on success5804* -EFAULT if read of config page header fails or data pointer not NULL5805* -ENOMEM if pci_alloc failed5806**/5807int5808mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,5809RaidPhysDiskPage1_t *phys_disk)5810{5811CONFIGPARMS cfg;5812ConfigPageHeader_t hdr;5813dma_addr_t dma_handle;5814pRaidPhysDiskPage1_t buffer = NULL;5815int rc;5816int i;5817__le64 sas_address;58185819memset(&cfg, 0 , sizeof(CONFIGPARMS));5820memset(&hdr, 0 , sizeof(ConfigPageHeader_t));5821rc = 0;58225823hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;5824hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;5825hdr.PageNumber = 1;5826cfg.cfghdr.hdr = &hdr;5827cfg.physAddr = -1;5828cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;58295830if (mpt_config(ioc, &cfg) != 0) {5831rc = -EFAULT;5832goto out;5833}58345835if (!hdr.PageLength) {5836rc = -EFAULT;5837goto out;5838}58395840buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,5841&dma_handle);58425843if (!buffer) {5844rc = -ENOMEM;5845goto out;5846}58475848cfg.physAddr = dma_handle;5849cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;5850cfg.pageAddr = phys_disk_num;58515852if (mpt_config(ioc, &cfg) != 0) {5853rc = -EFAULT;5854goto out;5855}58565857phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;5858phys_disk->PhysDiskNum = phys_disk_num;5859for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {5860phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;5861phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;5862phys_disk->Path[i].OwnerIdentifier =5863buffer->Path[i].OwnerIdentifier;5864phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);5865memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));5866sas_address = le64_to_cpu(sas_address);5867memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));5868memcpy(&sas_address,5869&buffer->Path[i].OwnerWWID, sizeof(__le64));5870sas_address = le64_to_cpu(sas_address);5871memcpy(&phys_disk->Path[i].OwnerWWID,5872&sas_address, sizeof(__le64));5873}58745875out:58765877if (buffer)5878pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,5879dma_handle);58805881return rc;5882}5883EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);588458855886/**5887* mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes5888* @ioc: Pointer to a Adapter Strucutre5889*5890* Return:5891* 0 on success5892* -EFAULT if read of config page header fails or data pointer not NULL5893* -ENOMEM if pci_alloc failed5894**/5895int5896mpt_findImVolumes(MPT_ADAPTER *ioc)5897{5898IOCPage2_t *pIoc2;5899u8 *mem;5900dma_addr_t ioc2_dma;5901CONFIGPARMS cfg;5902ConfigPageHeader_t header;5903int rc = 0;5904int iocpage2sz;5905int i;59065907if (!ioc->ir_firmware)5908return 0;59095910/* Free the old page5911*/5912kfree(ioc->raid_data.pIocPg2);5913ioc->raid_data.pIocPg2 = NULL;5914mpt_inactive_raid_list_free(ioc);59155916/* Read IOCP2 header then the page.5917*/5918header.PageVersion = 0;5919header.PageLength = 0;5920header.PageNumber = 2;5921header.PageType = MPI_CONFIG_PAGETYPE_IOC;5922cfg.cfghdr.hdr = &header;5923cfg.physAddr = -1;5924cfg.pageAddr = 0;5925cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;5926cfg.dir = 0;5927cfg.timeout = 0;5928if (mpt_config(ioc, &cfg) != 0)5929return -EFAULT;59305931if (header.PageLength == 0)5932return -EFAULT;59335934iocpage2sz = header.PageLength * 4;5935pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);5936if (!pIoc2)5937return -ENOMEM;59385939cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;5940cfg.physAddr = ioc2_dma;5941if (mpt_config(ioc, &cfg) != 0)5942goto out;59435944mem = kmalloc(iocpage2sz, GFP_KERNEL);5945if (!mem) {5946rc = -ENOMEM;5947goto out;5948}59495950memcpy(mem, (u8 *)pIoc2, iocpage2sz);5951ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;59525953mpt_read_ioc_pg_3(ioc);59545955for (i = 0; i < pIoc2->NumActiveVolumes ; i++)5956mpt_inactive_raid_volumes(ioc,5957pIoc2->RaidVolume[i].VolumeBus,5958pIoc2->RaidVolume[i].VolumeID);59595960out:5961pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);59625963return rc;5964}59655966static int5967mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)5968{5969IOCPage3_t *pIoc3;5970u8 *mem;5971CONFIGPARMS cfg;5972ConfigPageHeader_t header;5973dma_addr_t ioc3_dma;5974int iocpage3sz = 0;59755976/* Free the old page5977*/5978kfree(ioc->raid_data.pIocPg3);5979ioc->raid_data.pIocPg3 = NULL;59805981/* There is at least one physical disk.5982* Read and save IOC Page 35983*/5984header.PageVersion = 0;5985header.PageLength = 0;5986header.PageNumber = 3;5987header.PageType = MPI_CONFIG_PAGETYPE_IOC;5988cfg.cfghdr.hdr = &header;5989cfg.physAddr = -1;5990cfg.pageAddr = 0;5991cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;5992cfg.dir = 0;5993cfg.timeout = 0;5994if (mpt_config(ioc, &cfg) != 0)5995return 0;59965997if (header.PageLength == 0)5998return 0;59996000/* Read Header good, alloc memory6001*/6002iocpage3sz = header.PageLength * 4;6003pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);6004if (!pIoc3)6005return 0;60066007/* Read the Page and save the data6008* into malloc'd memory.6009*/6010cfg.physAddr = ioc3_dma;6011cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;6012if (mpt_config(ioc, &cfg) == 0) {6013mem = kmalloc(iocpage3sz, GFP_KERNEL);6014if (mem) {6015memcpy(mem, (u8 *)pIoc3, iocpage3sz);6016ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;6017}6018}60196020pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);60216022return 0;6023}60246025static void6026mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)6027{6028IOCPage4_t *pIoc4;6029CONFIGPARMS cfg;6030ConfigPageHeader_t header;6031dma_addr_t ioc4_dma;6032int iocpage4sz;60336034/* Read and save IOC Page 46035*/6036header.PageVersion = 0;6037header.PageLength = 0;6038header.PageNumber = 4;6039header.PageType = MPI_CONFIG_PAGETYPE_IOC;6040cfg.cfghdr.hdr = &header;6041cfg.physAddr = -1;6042cfg.pageAddr = 0;6043cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;6044cfg.dir = 0;6045cfg.timeout = 0;6046if (mpt_config(ioc, &cfg) != 0)6047return;60486049if (header.PageLength == 0)6050return;60516052if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {6053iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */6054pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);6055if (!pIoc4)6056return;6057ioc->alloc_total += iocpage4sz;6058} else {6059ioc4_dma = ioc->spi_data.IocPg4_dma;6060iocpage4sz = ioc->spi_data.IocPg4Sz;6061}60626063/* Read the Page into dma memory.6064*/6065cfg.physAddr = ioc4_dma;6066cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;6067if (mpt_config(ioc, &cfg) == 0) {6068ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;6069ioc->spi_data.IocPg4_dma = ioc4_dma;6070ioc->spi_data.IocPg4Sz = iocpage4sz;6071} else {6072pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);6073ioc->spi_data.pIocPg4 = NULL;6074ioc->alloc_total -= iocpage4sz;6075}6076}60776078static void6079mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)6080{6081IOCPage1_t *pIoc1;6082CONFIGPARMS cfg;6083ConfigPageHeader_t header;6084dma_addr_t ioc1_dma;6085int iocpage1sz = 0;6086u32 tmp;60876088/* Check the Coalescing Timeout in IOC Page 16089*/6090header.PageVersion = 0;6091header.PageLength = 0;6092header.PageNumber = 1;6093header.PageType = MPI_CONFIG_PAGETYPE_IOC;6094cfg.cfghdr.hdr = &header;6095cfg.physAddr = -1;6096cfg.pageAddr = 0;6097cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;6098cfg.dir = 0;6099cfg.timeout = 0;6100if (mpt_config(ioc, &cfg) != 0)6101return;61026103if (header.PageLength == 0)6104return;61056106/* Read Header good, alloc memory6107*/6108iocpage1sz = header.PageLength * 4;6109pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);6110if (!pIoc1)6111return;61126113/* Read the Page and check coalescing timeout6114*/6115cfg.physAddr = ioc1_dma;6116cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;6117if (mpt_config(ioc, &cfg) == 0) {61186119tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;6120if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {6121tmp = le32_to_cpu(pIoc1->CoalescingTimeout);61226123dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",6124ioc->name, tmp));61256126if (tmp > MPT_COALESCING_TIMEOUT) {6127pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);61286129/* Write NVRAM and current6130*/6131cfg.dir = 1;6132cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;6133if (mpt_config(ioc, &cfg) == 0) {6134dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",6135ioc->name, MPT_COALESCING_TIMEOUT));61366137cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;6138if (mpt_config(ioc, &cfg) == 0) {6139dprintk(ioc, printk(MYIOC_s_DEBUG_FMT6140"Reset NVRAM Coalescing Timeout to = %d\n",6141ioc->name, MPT_COALESCING_TIMEOUT));6142} else {6143dprintk(ioc, printk(MYIOC_s_DEBUG_FMT6144"Reset NVRAM Coalescing Timeout Failed\n",6145ioc->name));6146}61476148} else {6149dprintk(ioc, printk(MYIOC_s_WARN_FMT6150"Reset of Current Coalescing Timeout Failed!\n",6151ioc->name));6152}6153}61546155} else {6156dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));6157}6158}61596160pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);61616162return;6163}61646165static void6166mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)6167{6168CONFIGPARMS cfg;6169ConfigPageHeader_t hdr;6170dma_addr_t buf_dma;6171ManufacturingPage0_t *pbuf = NULL;61726173memset(&cfg, 0 , sizeof(CONFIGPARMS));6174memset(&hdr, 0 , sizeof(ConfigPageHeader_t));61756176hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;6177cfg.cfghdr.hdr = &hdr;6178cfg.physAddr = -1;6179cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;6180cfg.timeout = 10;61816182if (mpt_config(ioc, &cfg) != 0)6183goto out;61846185if (!cfg.cfghdr.hdr->PageLength)6186goto out;61876188cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;6189pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);6190if (!pbuf)6191goto out;61926193cfg.physAddr = buf_dma;61946195if (mpt_config(ioc, &cfg) != 0)6196goto out;61976198memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));6199memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));6200memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));62016202out:62036204if (pbuf)6205pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);6206}62076208/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/6209/**6210* SendEventNotification - Send EventNotification (on or off) request to adapter6211* @ioc: Pointer to MPT_ADAPTER structure6212* @EvSwitch: Event switch flags6213* @sleepFlag: Specifies whether the process can sleep6214*/6215static int6216SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)6217{6218EventNotification_t evn;6219MPIDefaultReply_t reply_buf;62206221memset(&evn, 0, sizeof(EventNotification_t));6222memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));62236224evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;6225evn.Switch = EvSwitch;6226evn.MsgContext = cpu_to_le32(mpt_base_index << 16);62276228devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT6229"Sending EventNotification (%d) request %p\n",6230ioc->name, EvSwitch, &evn));62316232return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),6233(u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,6234sleepFlag);6235}62366237/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/6238/**6239* SendEventAck - Send EventAck request to MPT adapter.6240* @ioc: Pointer to MPT_ADAPTER structure6241* @evnp: Pointer to original EventNotification request6242*/6243static int6244SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)6245{6246EventAck_t *pAck;62476248if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {6249dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",6250ioc->name, __func__));6251return -1;6252}62536254devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));62556256pAck->Function = MPI_FUNCTION_EVENT_ACK;6257pAck->ChainOffset = 0;6258pAck->Reserved[0] = pAck->Reserved[1] = 0;6259pAck->MsgFlags = 0;6260pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;6261pAck->Event = evnp->Event;6262pAck->EventContext = evnp->EventContext;62636264mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);62656266return 0;6267}62686269/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/6270/**6271* mpt_config - Generic function to issue config message6272* @ioc: Pointer to an adapter structure6273* @pCfg: Pointer to a configuration structure. Struct contains6274* action, page address, direction, physical address6275* and pointer to a configuration page header6276* Page header is updated.6277*6278* Returns 0 for success6279* -EPERM if not allowed due to ISR context6280* -EAGAIN if no msg frames currently available6281* -EFAULT for non-successful reply or no reply (timeout)6282*/6283int6284mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)6285{6286Config_t *pReq;6287ConfigReply_t *pReply;6288ConfigExtendedPageHeader_t *pExtHdr = NULL;6289MPT_FRAME_HDR *mf;6290int ii;6291int flagsLength;6292long timeout;6293int ret;6294u8 page_type = 0, extend_page;6295unsigned long timeleft;6296unsigned long flags;6297int in_isr;6298u8 issue_hard_reset = 0;6299u8 retry_count = 0;63006301/* Prevent calling wait_event() (below), if caller happens6302* to be in ISR context, because that is fatal!6303*/6304in_isr = in_interrupt();6305if (in_isr) {6306dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",6307ioc->name));6308return -EPERM;6309}63106311/* don't send a config page during diag reset */6312spin_lock_irqsave(&ioc->taskmgmt_lock, flags);6313if (ioc->ioc_reset_in_progress) {6314dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT6315"%s: busy with host reset\n", ioc->name, __func__));6316spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);6317return -EBUSY;6318}6319spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);63206321/* don't send if no chance of success */6322if (!ioc->active ||6323mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {6324dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT6325"%s: ioc not operational, %d, %xh\n",6326ioc->name, __func__, ioc->active,6327mpt_GetIocState(ioc, 0)));6328return -EFAULT;6329}63306331retry_config:6332mutex_lock(&ioc->mptbase_cmds.mutex);6333/* init the internal cmd struct */6334memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);6335INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)63366337/* Get and Populate a free Frame6338*/6339if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {6340dcprintk(ioc, printk(MYIOC_s_WARN_FMT6341"mpt_config: no msg frames!\n", ioc->name));6342ret = -EAGAIN;6343goto out;6344}63456346pReq = (Config_t *)mf;6347pReq->Action = pCfg->action;6348pReq->Reserved = 0;6349pReq->ChainOffset = 0;6350pReq->Function = MPI_FUNCTION_CONFIG;63516352/* Assume page type is not extended and clear "reserved" fields. */6353pReq->ExtPageLength = 0;6354pReq->ExtPageType = 0;6355pReq->MsgFlags = 0;63566357for (ii=0; ii < 8; ii++)6358pReq->Reserved2[ii] = 0;63596360pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;6361pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;6362pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;6363pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);63646365if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {6366pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;6367pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);6368pReq->ExtPageType = pExtHdr->ExtPageType;6369pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;63706371/* Page Length must be treated as a reserved field for the6372* extended header.6373*/6374pReq->Header.PageLength = 0;6375}63766377pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);63786379/* Add a SGE to the config request.6380*/6381if (pCfg->dir)6382flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;6383else6384flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;63856386if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==6387MPI_CONFIG_PAGETYPE_EXTENDED) {6388flagsLength |= pExtHdr->ExtPageLength * 4;6389page_type = pReq->ExtPageType;6390extend_page = 1;6391} else {6392flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;6393page_type = pReq->Header.PageType;6394extend_page = 0;6395}63966397dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT6398"Sending Config request type 0x%x, page 0x%x and action %d\n",6399ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));64006401ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);6402timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;6403mpt_put_msg_frame(mpt_base_index, ioc, mf);6404timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,6405timeout);6406if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {6407ret = -ETIME;6408dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT6409"Failed Sending Config request type 0x%x, page 0x%x,"6410" action %d, status %xh, time left %ld\n\n",6411ioc->name, page_type, pReq->Header.PageNumber,6412pReq->Action, ioc->mptbase_cmds.status, timeleft));6413if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)6414goto out;6415if (!timeleft)6416issue_hard_reset = 1;6417goto out;6418}64196420if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {6421ret = -1;6422goto out;6423}6424pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;6425ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;6426if (ret == MPI_IOCSTATUS_SUCCESS) {6427if (extend_page) {6428pCfg->cfghdr.ehdr->ExtPageLength =6429le16_to_cpu(pReply->ExtPageLength);6430pCfg->cfghdr.ehdr->ExtPageType =6431pReply->ExtPageType;6432}6433pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;6434pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;6435pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;6436pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;64376438}64396440if (retry_count)6441printk(MYIOC_s_INFO_FMT "Retry completed "6442"ret=0x%x timeleft=%ld\n",6443ioc->name, ret, timeleft);64446445dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",6446ret, le32_to_cpu(pReply->IOCLogInfo)));64476448out:64496450CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)6451mutex_unlock(&ioc->mptbase_cmds.mutex);6452if (issue_hard_reset) {6453issue_hard_reset = 0;6454printk(MYIOC_s_WARN_FMT6455"Issuing Reset from %s!!, doorbell=0x%08x\n",6456ioc->name, __func__, mpt_GetIocState(ioc, 0));6457if (retry_count == 0) {6458if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)6459retry_count++;6460} else6461mpt_HardResetHandler(ioc, CAN_SLEEP);64626463mpt_free_msg_frame(ioc, mf);6464/* attempt one retry for a timed out command */6465if (retry_count < 2) {6466printk(MYIOC_s_INFO_FMT6467"Attempting Retry Config request"6468" type 0x%x, page 0x%x,"6469" action %d\n", ioc->name, page_type,6470pCfg->cfghdr.hdr->PageNumber, pCfg->action);6471retry_count++;6472goto retry_config;6473}6474}6475return ret;64766477}64786479/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/6480/**6481* mpt_ioc_reset - Base cleanup for hard reset6482* @ioc: Pointer to the adapter structure6483* @reset_phase: Indicates pre- or post-reset functionality6484*6485* Remark: Frees resources with internally generated commands.6486*/6487static int6488mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)6489{6490switch (reset_phase) {6491case MPT_IOC_SETUP_RESET:6492ioc->taskmgmt_quiesce_io = 1;6493dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT6494"%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));6495break;6496case MPT_IOC_PRE_RESET:6497dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT6498"%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));6499break;6500case MPT_IOC_POST_RESET:6501dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT6502"%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));6503/* wake up mptbase_cmds */6504if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {6505ioc->mptbase_cmds.status |=6506MPT_MGMT_STATUS_DID_IOCRESET;6507complete(&ioc->mptbase_cmds.done);6508}6509/* wake up taskmgmt_cmds */6510if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {6511ioc->taskmgmt_cmds.status |=6512MPT_MGMT_STATUS_DID_IOCRESET;6513complete(&ioc->taskmgmt_cmds.done);6514}6515break;6516default:6517break;6518}65196520return 1; /* currently means nothing really */6521}652265236524#ifdef CONFIG_PROC_FS /* { */6525/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/6526/*6527* procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...6528*/6529/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/6530/**6531* procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.6532*6533* Returns 0 for success, non-zero for failure.6534*/6535static int6536procmpt_create(void)6537{6538mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);6539if (mpt_proc_root_dir == NULL)6540return -ENOTDIR;65416542proc_create("summary", S_IRUGO, mpt_proc_root_dir, &mpt_summary_proc_fops);6543proc_create("version", S_IRUGO, mpt_proc_root_dir, &mpt_version_proc_fops);6544return 0;6545}65466547/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/6548/**6549* procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.6550*6551* Returns 0 for success, non-zero for failure.6552*/6553static void6554procmpt_destroy(void)6555{6556remove_proc_entry("version", mpt_proc_root_dir);6557remove_proc_entry("summary", mpt_proc_root_dir);6558remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);6559}65606561/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/6562/*6563* Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.6564*/6565static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan);65666567static int mpt_summary_proc_show(struct seq_file *m, void *v)6568{6569MPT_ADAPTER *ioc = m->private;65706571if (ioc) {6572seq_mpt_print_ioc_summary(ioc, m, 1);6573} else {6574list_for_each_entry(ioc, &ioc_list, list) {6575seq_mpt_print_ioc_summary(ioc, m, 1);6576}6577}65786579return 0;6580}65816582static int mpt_summary_proc_open(struct inode *inode, struct file *file)6583{6584return single_open(file, mpt_summary_proc_show, PDE(inode)->data);6585}65866587static const struct file_operations mpt_summary_proc_fops = {6588.owner = THIS_MODULE,6589.open = mpt_summary_proc_open,6590.read = seq_read,6591.llseek = seq_lseek,6592.release = single_release,6593};65946595static int mpt_version_proc_show(struct seq_file *m, void *v)6596{6597u8 cb_idx;6598int scsi, fc, sas, lan, ctl, targ, dmp;6599char *drvname;66006601seq_printf(m, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);6602seq_printf(m, " Fusion MPT base driver\n");66036604scsi = fc = sas = lan = ctl = targ = dmp = 0;6605for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {6606drvname = NULL;6607if (MptCallbacks[cb_idx]) {6608switch (MptDriverClass[cb_idx]) {6609case MPTSPI_DRIVER:6610if (!scsi++) drvname = "SPI host";6611break;6612case MPTFC_DRIVER:6613if (!fc++) drvname = "FC host";6614break;6615case MPTSAS_DRIVER:6616if (!sas++) drvname = "SAS host";6617break;6618case MPTLAN_DRIVER:6619if (!lan++) drvname = "LAN";6620break;6621case MPTSTM_DRIVER:6622if (!targ++) drvname = "SCSI target";6623break;6624case MPTCTL_DRIVER:6625if (!ctl++) drvname = "ioctl";6626break;6627}66286629if (drvname)6630seq_printf(m, " Fusion MPT %s driver\n", drvname);6631}6632}66336634return 0;6635}66366637static int mpt_version_proc_open(struct inode *inode, struct file *file)6638{6639return single_open(file, mpt_version_proc_show, NULL);6640}66416642static const struct file_operations mpt_version_proc_fops = {6643.owner = THIS_MODULE,6644.open = mpt_version_proc_open,6645.read = seq_read,6646.llseek = seq_lseek,6647.release = single_release,6648};66496650static int mpt_iocinfo_proc_show(struct seq_file *m, void *v)6651{6652MPT_ADAPTER *ioc = m->private;6653char expVer[32];6654int sz;6655int p;66566657mpt_get_fw_exp_ver(expVer, ioc);66586659seq_printf(m, "%s:", ioc->name);6660if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)6661seq_printf(m, " (f/w download boot flag set)");6662// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)6663// seq_printf(m, " CONFIG_CHECKSUM_FAIL!");66646665seq_printf(m, "\n ProductID = 0x%04x (%s)\n",6666ioc->facts.ProductID,6667ioc->prod_name);6668seq_printf(m, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);6669if (ioc->facts.FWImageSize)6670seq_printf(m, " (fw_size=%d)", ioc->facts.FWImageSize);6671seq_printf(m, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);6672seq_printf(m, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);6673seq_printf(m, " EventState = 0x%02x\n", ioc->facts.EventState);66746675seq_printf(m, " CurrentHostMfaHighAddr = 0x%08x\n",6676ioc->facts.CurrentHostMfaHighAddr);6677seq_printf(m, " CurrentSenseBufferHighAddr = 0x%08x\n",6678ioc->facts.CurrentSenseBufferHighAddr);66796680seq_printf(m, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);6681seq_printf(m, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);66826683seq_printf(m, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",6684(void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);6685/*6686* Rounding UP to nearest 4-kB boundary here...6687*/6688sz = (ioc->req_sz * ioc->req_depth) + 128;6689sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;6690seq_printf(m, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",6691ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);6692seq_printf(m, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",66934*ioc->facts.RequestFrameSize,6694ioc->facts.GlobalCredits);66956696seq_printf(m, " Frames @ 0x%p (Dma @ 0x%p)\n",6697(void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);6698sz = (ioc->reply_sz * ioc->reply_depth) + 128;6699seq_printf(m, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",6700ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);6701seq_printf(m, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",6702ioc->facts.CurReplyFrameSize,6703ioc->facts.ReplyQueueDepth);67046705seq_printf(m, " MaxDevices = %d\n",6706(ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);6707seq_printf(m, " MaxBuses = %d\n", ioc->facts.MaxBuses);67086709/* per-port info */6710for (p=0; p < ioc->facts.NumberOfPorts; p++) {6711seq_printf(m, " PortNumber = %d (of %d)\n",6712p+1,6713ioc->facts.NumberOfPorts);6714if (ioc->bus_type == FC) {6715if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {6716u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;6717seq_printf(m, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",6718a[5], a[4], a[3], a[2], a[1], a[0]);6719}6720seq_printf(m, " WWN = %08X%08X:%08X%08X\n",6721ioc->fc_port_page0[p].WWNN.High,6722ioc->fc_port_page0[p].WWNN.Low,6723ioc->fc_port_page0[p].WWPN.High,6724ioc->fc_port_page0[p].WWPN.Low);6725}6726}67276728return 0;6729}67306731static int mpt_iocinfo_proc_open(struct inode *inode, struct file *file)6732{6733return single_open(file, mpt_iocinfo_proc_show, PDE(inode)->data);6734}67356736static const struct file_operations mpt_iocinfo_proc_fops = {6737.owner = THIS_MODULE,6738.open = mpt_iocinfo_proc_open,6739.read = seq_read,6740.llseek = seq_lseek,6741.release = single_release,6742};6743#endif /* CONFIG_PROC_FS } */67446745/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/6746static void6747mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)6748{6749buf[0] ='\0';6750if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {6751sprintf(buf, " (Exp %02d%02d)",6752(ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */6753(ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */67546755/* insider hack! */6756if ((ioc->facts.FWVersion.Word >> 8) & 0x80)6757strcat(buf, " [MDBG]");6758}6759}67606761/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/6762/**6763* mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.6764* @ioc: Pointer to MPT_ADAPTER structure6765* @buffer: Pointer to buffer where IOC summary info should be written6766* @size: Pointer to number of bytes we wrote (set by this routine)6767* @len: Offset at which to start writing in buffer6768* @showlan: Display LAN stuff?6769*6770* This routine writes (english readable) ASCII text, which represents6771* a summary of IOC information, to a buffer.6772*/6773void6774mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)6775{6776char expVer[32];6777int y;67786779mpt_get_fw_exp_ver(expVer, ioc);67806781/*6782* Shorter summary of attached ioc's...6783*/6784y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",6785ioc->name,6786ioc->prod_name,6787MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */6788ioc->facts.FWVersion.Word,6789expVer,6790ioc->facts.NumberOfPorts,6791ioc->req_depth);67926793if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {6794u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;6795y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",6796a[5], a[4], a[3], a[2], a[1], a[0]);6797}67986799y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);68006801if (!ioc->active)6802y += sprintf(buffer+len+y, " (disabled)");68036804y += sprintf(buffer+len+y, "\n");68056806*size = y;6807}68086809static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan)6810{6811char expVer[32];68126813mpt_get_fw_exp_ver(expVer, ioc);68146815/*6816* Shorter summary of attached ioc's...6817*/6818seq_printf(m, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",6819ioc->name,6820ioc->prod_name,6821MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */6822ioc->facts.FWVersion.Word,6823expVer,6824ioc->facts.NumberOfPorts,6825ioc->req_depth);68266827if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {6828u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;6829seq_printf(m, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",6830a[5], a[4], a[3], a[2], a[1], a[0]);6831}68326833seq_printf(m, ", IRQ=%d", ioc->pci_irq);68346835if (!ioc->active)6836seq_printf(m, " (disabled)");68376838seq_putc(m, '\n');6839}68406841/**6842* mpt_set_taskmgmt_in_progress_flag - set flags associated with task management6843* @ioc: Pointer to MPT_ADAPTER structure6844*6845* Returns 0 for SUCCESS or -1 if FAILED.6846*6847* If -1 is return, then it was not possible to set the flags6848**/6849int6850mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)6851{6852unsigned long flags;6853int retval;68546855spin_lock_irqsave(&ioc->taskmgmt_lock, flags);6856if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||6857(ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {6858retval = -1;6859goto out;6860}6861retval = 0;6862ioc->taskmgmt_in_progress = 1;6863ioc->taskmgmt_quiesce_io = 1;6864if (ioc->alt_ioc) {6865ioc->alt_ioc->taskmgmt_in_progress = 1;6866ioc->alt_ioc->taskmgmt_quiesce_io = 1;6867}6868out:6869spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);6870return retval;6871}6872EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);68736874/**6875* mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management6876* @ioc: Pointer to MPT_ADAPTER structure6877*6878**/6879void6880mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)6881{6882unsigned long flags;68836884spin_lock_irqsave(&ioc->taskmgmt_lock, flags);6885ioc->taskmgmt_in_progress = 0;6886ioc->taskmgmt_quiesce_io = 0;6887if (ioc->alt_ioc) {6888ioc->alt_ioc->taskmgmt_in_progress = 0;6889ioc->alt_ioc->taskmgmt_quiesce_io = 0;6890}6891spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);6892}6893EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);689468956896/**6897* mpt_halt_firmware - Halts the firmware if it is operational and panic6898* the kernel6899* @ioc: Pointer to MPT_ADAPTER structure6900*6901**/6902void6903mpt_halt_firmware(MPT_ADAPTER *ioc)6904{6905u32 ioc_raw_state;69066907ioc_raw_state = mpt_GetIocState(ioc, 0);69086909if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {6910printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",6911ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);6912panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,6913ioc_raw_state & MPI_DOORBELL_DATA_MASK);6914} else {6915CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);6916panic("%s: Firmware is halted due to command timeout\n",6917ioc->name);6918}6919}6920EXPORT_SYMBOL(mpt_halt_firmware);69216922/**6923* mpt_SoftResetHandler - Issues a less expensive reset6924* @ioc: Pointer to MPT_ADAPTER structure6925* @sleepFlag: Indicates if sleep or schedule must be called.6926*6927* Returns 0 for SUCCESS or -1 if FAILED.6928*6929* Message Unit Reset - instructs the IOC to reset the Reply Post and6930* Free FIFO's. All the Message Frames on Reply Free FIFO are discarded.6931* All posted buffers are freed, and event notification is turned off.6932* IOC doesn't reply to any outstanding request. This will transfer IOC6933* to READY state.6934**/6935int6936mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)6937{6938int rc;6939int ii;6940u8 cb_idx;6941unsigned long flags;6942u32 ioc_state;6943unsigned long time_count;69446945dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n",6946ioc->name));69476948ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;69496950if (mpt_fwfault_debug)6951mpt_halt_firmware(ioc);69526953if (ioc_state == MPI_IOC_STATE_FAULT ||6954ioc_state == MPI_IOC_STATE_RESET) {6955dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT6956"skipping, either in FAULT or RESET state!\n", ioc->name));6957return -1;6958}69596960if (ioc->bus_type == FC) {6961dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT6962"skipping, because the bus type is FC!\n", ioc->name));6963return -1;6964}69656966spin_lock_irqsave(&ioc->taskmgmt_lock, flags);6967if (ioc->ioc_reset_in_progress) {6968spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);6969return -1;6970}6971ioc->ioc_reset_in_progress = 1;6972spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);69736974rc = -1;69756976for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {6977if (MptResetHandlers[cb_idx])6978mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);6979}69806981spin_lock_irqsave(&ioc->taskmgmt_lock, flags);6982if (ioc->taskmgmt_in_progress) {6983ioc->ioc_reset_in_progress = 0;6984spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);6985return -1;6986}6987spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);6988/* Disable reply interrupts (also blocks FreeQ) */6989CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);6990ioc->active = 0;6991time_count = jiffies;69926993rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);69946995for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {6996if (MptResetHandlers[cb_idx])6997mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);6998}69997000if (rc)7001goto out;70027003ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;7004if (ioc_state != MPI_IOC_STATE_READY)7005goto out;70067007for (ii = 0; ii < 5; ii++) {7008/* Get IOC facts! Allow 5 retries */7009rc = GetIocFacts(ioc, sleepFlag,7010MPT_HOSTEVENT_IOC_RECOVER);7011if (rc == 0)7012break;7013if (sleepFlag == CAN_SLEEP)7014msleep(100);7015else7016mdelay(100);7017}7018if (ii == 5)7019goto out;70207021rc = PrimeIocFifos(ioc);7022if (rc != 0)7023goto out;70247025rc = SendIocInit(ioc, sleepFlag);7026if (rc != 0)7027goto out;70287029rc = SendEventNotification(ioc, 1, sleepFlag);7030if (rc != 0)7031goto out;70327033if (ioc->hard_resets < -1)7034ioc->hard_resets++;70357036/*7037* At this point, we know soft reset succeeded.7038*/70397040ioc->active = 1;7041CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);70427043out:7044spin_lock_irqsave(&ioc->taskmgmt_lock, flags);7045ioc->ioc_reset_in_progress = 0;7046ioc->taskmgmt_quiesce_io = 0;7047ioc->taskmgmt_in_progress = 0;7048spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);70497050if (ioc->active) { /* otherwise, hard reset coming */7051for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {7052if (MptResetHandlers[cb_idx])7053mpt_signal_reset(cb_idx, ioc,7054MPT_IOC_POST_RESET);7055}7056}70577058dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT7059"SoftResetHandler: completed (%d seconds): %s\n",7060ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,7061((rc == 0) ? "SUCCESS" : "FAILED")));70627063return rc;7064}70657066/**7067* mpt_Soft_Hard_ResetHandler - Try less expensive reset7068* @ioc: Pointer to MPT_ADAPTER structure7069* @sleepFlag: Indicates if sleep or schedule must be called.7070*7071* Returns 0 for SUCCESS or -1 if FAILED.7072* Try for softreset first, only if it fails go for expensive7073* HardReset.7074**/7075int7076mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) {7077int ret = -1;70787079ret = mpt_SoftResetHandler(ioc, sleepFlag);7080if (ret == 0)7081return ret;7082ret = mpt_HardResetHandler(ioc, sleepFlag);7083return ret;7084}7085EXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler);70867087/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/7088/*7089* Reset Handling7090*/7091/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/7092/**7093* mpt_HardResetHandler - Generic reset handler7094* @ioc: Pointer to MPT_ADAPTER structure7095* @sleepFlag: Indicates if sleep or schedule must be called.7096*7097* Issues SCSI Task Management call based on input arg values.7098* If TaskMgmt fails, returns associated SCSI request.7099*7100* Remark: _HardResetHandler can be invoked from an interrupt thread (timer)7101* or a non-interrupt thread. In the former, must not call schedule().7102*7103* Note: A return of -1 is a FATAL error case, as it means a7104* FW reload/initialization failed.7105*7106* Returns 0 for SUCCESS or -1 if FAILED.7107*/7108int7109mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)7110{7111int rc;7112u8 cb_idx;7113unsigned long flags;7114unsigned long time_count;71157116dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));7117#ifdef MFCNT7118printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);7119printk("MF count 0x%x !\n", ioc->mfcnt);7120#endif7121if (mpt_fwfault_debug)7122mpt_halt_firmware(ioc);71237124/* Reset the adapter. Prevent more than 1 call to7125* mpt_do_ioc_recovery at any instant in time.7126*/7127spin_lock_irqsave(&ioc->taskmgmt_lock, flags);7128if (ioc->ioc_reset_in_progress) {7129spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);7130return 0;7131}7132ioc->ioc_reset_in_progress = 1;7133if (ioc->alt_ioc)7134ioc->alt_ioc->ioc_reset_in_progress = 1;7135spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);713671377138/* The SCSI driver needs to adjust timeouts on all current7139* commands prior to the diagnostic reset being issued.7140* Prevents timeouts occurring during a diagnostic reset...very bad.7141* For all other protocol drivers, this is a no-op.7142*/7143for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {7144if (MptResetHandlers[cb_idx]) {7145mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);7146if (ioc->alt_ioc)7147mpt_signal_reset(cb_idx, ioc->alt_ioc,7148MPT_IOC_SETUP_RESET);7149}7150}71517152time_count = jiffies;7153rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);7154if (rc != 0) {7155printk(KERN_WARNING MYNAM7156": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n",7157rc, ioc->name, mpt_GetIocState(ioc, 0));7158} else {7159if (ioc->hard_resets < -1)7160ioc->hard_resets++;7161}71627163spin_lock_irqsave(&ioc->taskmgmt_lock, flags);7164ioc->ioc_reset_in_progress = 0;7165ioc->taskmgmt_quiesce_io = 0;7166ioc->taskmgmt_in_progress = 0;7167if (ioc->alt_ioc) {7168ioc->alt_ioc->ioc_reset_in_progress = 0;7169ioc->alt_ioc->taskmgmt_quiesce_io = 0;7170ioc->alt_ioc->taskmgmt_in_progress = 0;7171}7172spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);71737174for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {7175if (MptResetHandlers[cb_idx]) {7176mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);7177if (ioc->alt_ioc)7178mpt_signal_reset(cb_idx,7179ioc->alt_ioc, MPT_IOC_POST_RESET);7180}7181}71827183dtmprintk(ioc,7184printk(MYIOC_s_DEBUG_FMT7185"HardResetHandler: completed (%d seconds): %s\n", ioc->name,7186jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?7187"SUCCESS" : "FAILED")));71887189return rc;7190}71917192#ifdef CONFIG_FUSION_LOGGING7193static void7194mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)7195{7196char *ds = NULL;7197u32 evData0;7198int ii;7199u8 event;7200char *evStr = ioc->evStr;72017202event = le32_to_cpu(pEventReply->Event) & 0xFF;7203evData0 = le32_to_cpu(pEventReply->Data[0]);72047205switch(event) {7206case MPI_EVENT_NONE:7207ds = "None";7208break;7209case MPI_EVENT_LOG_DATA:7210ds = "Log Data";7211break;7212case MPI_EVENT_STATE_CHANGE:7213ds = "State Change";7214break;7215case MPI_EVENT_UNIT_ATTENTION:7216ds = "Unit Attention";7217break;7218case MPI_EVENT_IOC_BUS_RESET:7219ds = "IOC Bus Reset";7220break;7221case MPI_EVENT_EXT_BUS_RESET:7222ds = "External Bus Reset";7223break;7224case MPI_EVENT_RESCAN:7225ds = "Bus Rescan Event";7226break;7227case MPI_EVENT_LINK_STATUS_CHANGE:7228if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)7229ds = "Link Status(FAILURE) Change";7230else7231ds = "Link Status(ACTIVE) Change";7232break;7233case MPI_EVENT_LOOP_STATE_CHANGE:7234if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)7235ds = "Loop State(LIP) Change";7236else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)7237ds = "Loop State(LPE) Change";7238else7239ds = "Loop State(LPB) Change";7240break;7241case MPI_EVENT_LOGOUT:7242ds = "Logout";7243break;7244case MPI_EVENT_EVENT_CHANGE:7245if (evData0)7246ds = "Events ON";7247else7248ds = "Events OFF";7249break;7250case MPI_EVENT_INTEGRATED_RAID:7251{7252u8 ReasonCode = (u8)(evData0 >> 16);7253switch (ReasonCode) {7254case MPI_EVENT_RAID_RC_VOLUME_CREATED :7255ds = "Integrated Raid: Volume Created";7256break;7257case MPI_EVENT_RAID_RC_VOLUME_DELETED :7258ds = "Integrated Raid: Volume Deleted";7259break;7260case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :7261ds = "Integrated Raid: Volume Settings Changed";7262break;7263case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :7264ds = "Integrated Raid: Volume Status Changed";7265break;7266case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :7267ds = "Integrated Raid: Volume Physdisk Changed";7268break;7269case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :7270ds = "Integrated Raid: Physdisk Created";7271break;7272case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :7273ds = "Integrated Raid: Physdisk Deleted";7274break;7275case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :7276ds = "Integrated Raid: Physdisk Settings Changed";7277break;7278case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :7279ds = "Integrated Raid: Physdisk Status Changed";7280break;7281case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :7282ds = "Integrated Raid: Domain Validation Needed";7283break;7284case MPI_EVENT_RAID_RC_SMART_DATA :7285ds = "Integrated Raid; Smart Data";7286break;7287case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :7288ds = "Integrated Raid: Replace Action Started";7289break;7290default:7291ds = "Integrated Raid";7292break;7293}7294break;7295}7296case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:7297ds = "SCSI Device Status Change";7298break;7299case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:7300{7301u8 id = (u8)(evData0);7302u8 channel = (u8)(evData0 >> 8);7303u8 ReasonCode = (u8)(evData0 >> 16);7304switch (ReasonCode) {7305case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:7306snprintf(evStr, EVENT_DESCR_STR_SZ,7307"SAS Device Status Change: Added: "7308"id=%d channel=%d", id, channel);7309break;7310case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:7311snprintf(evStr, EVENT_DESCR_STR_SZ,7312"SAS Device Status Change: Deleted: "7313"id=%d channel=%d", id, channel);7314break;7315case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:7316snprintf(evStr, EVENT_DESCR_STR_SZ,7317"SAS Device Status Change: SMART Data: "7318"id=%d channel=%d", id, channel);7319break;7320case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:7321snprintf(evStr, EVENT_DESCR_STR_SZ,7322"SAS Device Status Change: No Persistancy: "7323"id=%d channel=%d", id, channel);7324break;7325case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:7326snprintf(evStr, EVENT_DESCR_STR_SZ,7327"SAS Device Status Change: Unsupported Device "7328"Discovered : id=%d channel=%d", id, channel);7329break;7330case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:7331snprintf(evStr, EVENT_DESCR_STR_SZ,7332"SAS Device Status Change: Internal Device "7333"Reset : id=%d channel=%d", id, channel);7334break;7335case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:7336snprintf(evStr, EVENT_DESCR_STR_SZ,7337"SAS Device Status Change: Internal Task "7338"Abort : id=%d channel=%d", id, channel);7339break;7340case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:7341snprintf(evStr, EVENT_DESCR_STR_SZ,7342"SAS Device Status Change: Internal Abort "7343"Task Set : id=%d channel=%d", id, channel);7344break;7345case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:7346snprintf(evStr, EVENT_DESCR_STR_SZ,7347"SAS Device Status Change: Internal Clear "7348"Task Set : id=%d channel=%d", id, channel);7349break;7350case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:7351snprintf(evStr, EVENT_DESCR_STR_SZ,7352"SAS Device Status Change: Internal Query "7353"Task : id=%d channel=%d", id, channel);7354break;7355default:7356snprintf(evStr, EVENT_DESCR_STR_SZ,7357"SAS Device Status Change: Unknown: "7358"id=%d channel=%d", id, channel);7359break;7360}7361break;7362}7363case MPI_EVENT_ON_BUS_TIMER_EXPIRED:7364ds = "Bus Timer Expired";7365break;7366case MPI_EVENT_QUEUE_FULL:7367{7368u16 curr_depth = (u16)(evData0 >> 16);7369u8 channel = (u8)(evData0 >> 8);7370u8 id = (u8)(evData0);73717372snprintf(evStr, EVENT_DESCR_STR_SZ,7373"Queue Full: channel=%d id=%d depth=%d",7374channel, id, curr_depth);7375break;7376}7377case MPI_EVENT_SAS_SES:7378ds = "SAS SES Event";7379break;7380case MPI_EVENT_PERSISTENT_TABLE_FULL:7381ds = "Persistent Table Full";7382break;7383case MPI_EVENT_SAS_PHY_LINK_STATUS:7384{7385u8 LinkRates = (u8)(evData0 >> 8);7386u8 PhyNumber = (u8)(evData0);7387LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>7388MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;7389switch (LinkRates) {7390case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:7391snprintf(evStr, EVENT_DESCR_STR_SZ,7392"SAS PHY Link Status: Phy=%d:"7393" Rate Unknown",PhyNumber);7394break;7395case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:7396snprintf(evStr, EVENT_DESCR_STR_SZ,7397"SAS PHY Link Status: Phy=%d:"7398" Phy Disabled",PhyNumber);7399break;7400case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:7401snprintf(evStr, EVENT_DESCR_STR_SZ,7402"SAS PHY Link Status: Phy=%d:"7403" Failed Speed Nego",PhyNumber);7404break;7405case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:7406snprintf(evStr, EVENT_DESCR_STR_SZ,7407"SAS PHY Link Status: Phy=%d:"7408" Sata OOB Completed",PhyNumber);7409break;7410case MPI_EVENT_SAS_PLS_LR_RATE_1_5:7411snprintf(evStr, EVENT_DESCR_STR_SZ,7412"SAS PHY Link Status: Phy=%d:"7413" Rate 1.5 Gbps",PhyNumber);7414break;7415case MPI_EVENT_SAS_PLS_LR_RATE_3_0:7416snprintf(evStr, EVENT_DESCR_STR_SZ,7417"SAS PHY Link Status: Phy=%d:"7418" Rate 3.0 Gbps", PhyNumber);7419break;7420case MPI_EVENT_SAS_PLS_LR_RATE_6_0:7421snprintf(evStr, EVENT_DESCR_STR_SZ,7422"SAS PHY Link Status: Phy=%d:"7423" Rate 6.0 Gbps", PhyNumber);7424break;7425default:7426snprintf(evStr, EVENT_DESCR_STR_SZ,7427"SAS PHY Link Status: Phy=%d", PhyNumber);7428break;7429}7430break;7431}7432case MPI_EVENT_SAS_DISCOVERY_ERROR:7433ds = "SAS Discovery Error";7434break;7435case MPI_EVENT_IR_RESYNC_UPDATE:7436{7437u8 resync_complete = (u8)(evData0 >> 16);7438snprintf(evStr, EVENT_DESCR_STR_SZ,7439"IR Resync Update: Complete = %d:",resync_complete);7440break;7441}7442case MPI_EVENT_IR2:7443{7444u8 id = (u8)(evData0);7445u8 channel = (u8)(evData0 >> 8);7446u8 phys_num = (u8)(evData0 >> 24);7447u8 ReasonCode = (u8)(evData0 >> 16);74487449switch (ReasonCode) {7450case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:7451snprintf(evStr, EVENT_DESCR_STR_SZ,7452"IR2: LD State Changed: "7453"id=%d channel=%d phys_num=%d",7454id, channel, phys_num);7455break;7456case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:7457snprintf(evStr, EVENT_DESCR_STR_SZ,7458"IR2: PD State Changed "7459"id=%d channel=%d phys_num=%d",7460id, channel, phys_num);7461break;7462case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:7463snprintf(evStr, EVENT_DESCR_STR_SZ,7464"IR2: Bad Block Table Full: "7465"id=%d channel=%d phys_num=%d",7466id, channel, phys_num);7467break;7468case MPI_EVENT_IR2_RC_PD_INSERTED:7469snprintf(evStr, EVENT_DESCR_STR_SZ,7470"IR2: PD Inserted: "7471"id=%d channel=%d phys_num=%d",7472id, channel, phys_num);7473break;7474case MPI_EVENT_IR2_RC_PD_REMOVED:7475snprintf(evStr, EVENT_DESCR_STR_SZ,7476"IR2: PD Removed: "7477"id=%d channel=%d phys_num=%d",7478id, channel, phys_num);7479break;7480case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:7481snprintf(evStr, EVENT_DESCR_STR_SZ,7482"IR2: Foreign CFG Detected: "7483"id=%d channel=%d phys_num=%d",7484id, channel, phys_num);7485break;7486case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:7487snprintf(evStr, EVENT_DESCR_STR_SZ,7488"IR2: Rebuild Medium Error: "7489"id=%d channel=%d phys_num=%d",7490id, channel, phys_num);7491break;7492case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:7493snprintf(evStr, EVENT_DESCR_STR_SZ,7494"IR2: Dual Port Added: "7495"id=%d channel=%d phys_num=%d",7496id, channel, phys_num);7497break;7498case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:7499snprintf(evStr, EVENT_DESCR_STR_SZ,7500"IR2: Dual Port Removed: "7501"id=%d channel=%d phys_num=%d",7502id, channel, phys_num);7503break;7504default:7505ds = "IR2";7506break;7507}7508break;7509}7510case MPI_EVENT_SAS_DISCOVERY:7511{7512if (evData0)7513ds = "SAS Discovery: Start";7514else7515ds = "SAS Discovery: Stop";7516break;7517}7518case MPI_EVENT_LOG_ENTRY_ADDED:7519ds = "SAS Log Entry Added";7520break;75217522case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:7523{7524u8 phy_num = (u8)(evData0);7525u8 port_num = (u8)(evData0 >> 8);7526u8 port_width = (u8)(evData0 >> 16);7527u8 primative = (u8)(evData0 >> 24);7528snprintf(evStr, EVENT_DESCR_STR_SZ,7529"SAS Broadcase Primative: phy=%d port=%d "7530"width=%d primative=0x%02x",7531phy_num, port_num, port_width, primative);7532break;7533}75347535case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:7536{7537u8 reason = (u8)(evData0);75387539switch (reason) {7540case MPI_EVENT_SAS_INIT_RC_ADDED:7541ds = "SAS Initiator Status Change: Added";7542break;7543case MPI_EVENT_SAS_INIT_RC_REMOVED:7544ds = "SAS Initiator Status Change: Deleted";7545break;7546default:7547ds = "SAS Initiator Status Change";7548break;7549}7550break;7551}75527553case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:7554{7555u8 max_init = (u8)(evData0);7556u8 current_init = (u8)(evData0 >> 8);75577558snprintf(evStr, EVENT_DESCR_STR_SZ,7559"SAS Initiator Device Table Overflow: max initiators=%02d "7560"current initators=%02d",7561max_init, current_init);7562break;7563}7564case MPI_EVENT_SAS_SMP_ERROR:7565{7566u8 status = (u8)(evData0);7567u8 port_num = (u8)(evData0 >> 8);7568u8 result = (u8)(evData0 >> 16);75697570if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)7571snprintf(evStr, EVENT_DESCR_STR_SZ,7572"SAS SMP Error: port=%d result=0x%02x",7573port_num, result);7574else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)7575snprintf(evStr, EVENT_DESCR_STR_SZ,7576"SAS SMP Error: port=%d : CRC Error",7577port_num);7578else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)7579snprintf(evStr, EVENT_DESCR_STR_SZ,7580"SAS SMP Error: port=%d : Timeout",7581port_num);7582else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)7583snprintf(evStr, EVENT_DESCR_STR_SZ,7584"SAS SMP Error: port=%d : No Destination",7585port_num);7586else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)7587snprintf(evStr, EVENT_DESCR_STR_SZ,7588"SAS SMP Error: port=%d : Bad Destination",7589port_num);7590else7591snprintf(evStr, EVENT_DESCR_STR_SZ,7592"SAS SMP Error: port=%d : status=0x%02x",7593port_num, status);7594break;7595}75967597case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:7598{7599u8 reason = (u8)(evData0);76007601switch (reason) {7602case MPI_EVENT_SAS_EXP_RC_ADDED:7603ds = "Expander Status Change: Added";7604break;7605case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:7606ds = "Expander Status Change: Deleted";7607break;7608default:7609ds = "Expander Status Change";7610break;7611}7612break;7613}76147615/*7616* MPT base "custom" events may be added here...7617*/7618default:7619ds = "Unknown";7620break;7621}7622if (ds)7623strncpy(evStr, ds, EVENT_DESCR_STR_SZ);762476257626devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT7627"MPT event:(%02Xh) : %s\n",7628ioc->name, event, evStr));76297630devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM7631": Event data:\n"));7632for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)7633devtverboseprintk(ioc, printk(" %08x",7634le32_to_cpu(pEventReply->Data[ii])));7635devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));7636}7637#endif7638/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/7639/**7640* ProcessEventNotification - Route EventNotificationReply to all event handlers7641* @ioc: Pointer to MPT_ADAPTER structure7642* @pEventReply: Pointer to EventNotification reply frame7643* @evHandlers: Pointer to integer, number of event handlers7644*7645* Routes a received EventNotificationReply to all currently registered7646* event handlers.7647* Returns sum of event handlers return values.7648*/7649static int7650ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)7651{7652u16 evDataLen;7653u32 evData0 = 0;7654int ii;7655u8 cb_idx;7656int r = 0;7657int handlers = 0;7658u8 event;76597660/*7661* Do platform normalization of values7662*/7663event = le32_to_cpu(pEventReply->Event) & 0xFF;7664evDataLen = le16_to_cpu(pEventReply->EventDataLength);7665if (evDataLen) {7666evData0 = le32_to_cpu(pEventReply->Data[0]);7667}76687669#ifdef CONFIG_FUSION_LOGGING7670if (evDataLen)7671mpt_display_event_info(ioc, pEventReply);7672#endif76737674/*7675* Do general / base driver event processing7676*/7677switch(event) {7678case MPI_EVENT_EVENT_CHANGE: /* 0A */7679if (evDataLen) {7680u8 evState = evData0 & 0xFF;76817682/* CHECKME! What if evState unexpectedly says OFF (0)? */76837684/* Update EventState field in cached IocFacts */7685if (ioc->facts.Function) {7686ioc->facts.EventState = evState;7687}7688}7689break;7690case MPI_EVENT_INTEGRATED_RAID:7691mptbase_raid_process_event_data(ioc,7692(MpiEventDataRaid_t *)pEventReply->Data);7693break;7694default:7695break;7696}76977698/*7699* Should this event be logged? Events are written sequentially.7700* When buffer is full, start again at the top.7701*/7702if (ioc->events && (ioc->eventTypes & ( 1 << event))) {7703int idx;77047705idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;77067707ioc->events[idx].event = event;7708ioc->events[idx].eventContext = ioc->eventContext;77097710for (ii = 0; ii < 2; ii++) {7711if (ii < evDataLen)7712ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);7713else7714ioc->events[idx].data[ii] = 0;7715}77167717ioc->eventContext++;7718}771977207721/*7722* Call each currently registered protocol event handler.7723*/7724for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {7725if (MptEvHandlers[cb_idx]) {7726devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT7727"Routing Event to event handler #%d\n",7728ioc->name, cb_idx));7729r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);7730handlers++;7731}7732}7733/* FIXME? Examine results here? */77347735/*7736* If needed, send (a single) EventAck.7737*/7738if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {7739devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT7740"EventAck required\n",ioc->name));7741if ((ii = SendEventAck(ioc, pEventReply)) != 0) {7742devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",7743ioc->name, ii));7744}7745}77467747*evHandlers = handlers;7748return r;7749}77507751/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/7752/**7753* mpt_fc_log_info - Log information returned from Fibre Channel IOC.7754* @ioc: Pointer to MPT_ADAPTER structure7755* @log_info: U32 LogInfo reply word from the IOC7756*7757* Refer to lsi/mpi_log_fc.h.7758*/7759static void7760mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)7761{7762char *desc = "unknown";77637764switch (log_info & 0xFF000000) {7765case MPI_IOCLOGINFO_FC_INIT_BASE:7766desc = "FCP Initiator";7767break;7768case MPI_IOCLOGINFO_FC_TARGET_BASE:7769desc = "FCP Target";7770break;7771case MPI_IOCLOGINFO_FC_LAN_BASE:7772desc = "LAN";7773break;7774case MPI_IOCLOGINFO_FC_MSG_BASE:7775desc = "MPI Message Layer";7776break;7777case MPI_IOCLOGINFO_FC_LINK_BASE:7778desc = "FC Link";7779break;7780case MPI_IOCLOGINFO_FC_CTX_BASE:7781desc = "Context Manager";7782break;7783case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:7784desc = "Invalid Field Offset";7785break;7786case MPI_IOCLOGINFO_FC_STATE_CHANGE:7787desc = "State Change Info";7788break;7789}77907791printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",7792ioc->name, log_info, desc, (log_info & 0xFFFFFF));7793}77947795/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/7796/**7797* mpt_spi_log_info - Log information returned from SCSI Parallel IOC.7798* @ioc: Pointer to MPT_ADAPTER structure7799* @log_info: U32 LogInfo word from the IOC7800*7801* Refer to lsi/sp_log.h.7802*/7803static void7804mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)7805{7806u32 info = log_info & 0x00FF0000;7807char *desc = "unknown";78087809switch (info) {7810case 0x00010000:7811desc = "bug! MID not found";7812break;78137814case 0x00020000:7815desc = "Parity Error";7816break;78177818case 0x00030000:7819desc = "ASYNC Outbound Overrun";7820break;78217822case 0x00040000:7823desc = "SYNC Offset Error";7824break;78257826case 0x00050000:7827desc = "BM Change";7828break;78297830case 0x00060000:7831desc = "Msg In Overflow";7832break;78337834case 0x00070000:7835desc = "DMA Error";7836break;78377838case 0x00080000:7839desc = "Outbound DMA Overrun";7840break;78417842case 0x00090000:7843desc = "Task Management";7844break;78457846case 0x000A0000:7847desc = "Device Problem";7848break;78497850case 0x000B0000:7851desc = "Invalid Phase Change";7852break;78537854case 0x000C0000:7855desc = "Untagged Table Size";7856break;78577858}78597860printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);7861}78627863/* strings for sas loginfo */7864static char *originator_str[] = {7865"IOP", /* 00h */7866"PL", /* 01h */7867"IR" /* 02h */7868};7869static char *iop_code_str[] = {7870NULL, /* 00h */7871"Invalid SAS Address", /* 01h */7872NULL, /* 02h */7873"Invalid Page", /* 03h */7874"Diag Message Error", /* 04h */7875"Task Terminated", /* 05h */7876"Enclosure Management", /* 06h */7877"Target Mode" /* 07h */7878};7879static char *pl_code_str[] = {7880NULL, /* 00h */7881"Open Failure", /* 01h */7882"Invalid Scatter Gather List", /* 02h */7883"Wrong Relative Offset or Frame Length", /* 03h */7884"Frame Transfer Error", /* 04h */7885"Transmit Frame Connected Low", /* 05h */7886"SATA Non-NCQ RW Error Bit Set", /* 06h */7887"SATA Read Log Receive Data Error", /* 07h */7888"SATA NCQ Fail All Commands After Error", /* 08h */7889"SATA Error in Receive Set Device Bit FIS", /* 09h */7890"Receive Frame Invalid Message", /* 0Ah */7891"Receive Context Message Valid Error", /* 0Bh */7892"Receive Frame Current Frame Error", /* 0Ch */7893"SATA Link Down", /* 0Dh */7894"Discovery SATA Init W IOS", /* 0Eh */7895"Config Invalid Page", /* 0Fh */7896"Discovery SATA Init Timeout", /* 10h */7897"Reset", /* 11h */7898"Abort", /* 12h */7899"IO Not Yet Executed", /* 13h */7900"IO Executed", /* 14h */7901"Persistent Reservation Out Not Affiliation "7902"Owner", /* 15h */7903"Open Transmit DMA Abort", /* 16h */7904"IO Device Missing Delay Retry", /* 17h */7905"IO Cancelled Due to Receive Error", /* 18h */7906NULL, /* 19h */7907NULL, /* 1Ah */7908NULL, /* 1Bh */7909NULL, /* 1Ch */7910NULL, /* 1Dh */7911NULL, /* 1Eh */7912NULL, /* 1Fh */7913"Enclosure Management" /* 20h */7914};7915static char *ir_code_str[] = {7916"Raid Action Error", /* 00h */7917NULL, /* 00h */7918NULL, /* 01h */7919NULL, /* 02h */7920NULL, /* 03h */7921NULL, /* 04h */7922NULL, /* 05h */7923NULL, /* 06h */7924NULL /* 07h */7925};7926static char *raid_sub_code_str[] = {7927NULL, /* 00h */7928"Volume Creation Failed: Data Passed too "7929"Large", /* 01h */7930"Volume Creation Failed: Duplicate Volumes "7931"Attempted", /* 02h */7932"Volume Creation Failed: Max Number "7933"Supported Volumes Exceeded", /* 03h */7934"Volume Creation Failed: DMA Error", /* 04h */7935"Volume Creation Failed: Invalid Volume Type", /* 05h */7936"Volume Creation Failed: Error Reading "7937"MFG Page 4", /* 06h */7938"Volume Creation Failed: Creating Internal "7939"Structures", /* 07h */7940NULL, /* 08h */7941NULL, /* 09h */7942NULL, /* 0Ah */7943NULL, /* 0Bh */7944NULL, /* 0Ch */7945NULL, /* 0Dh */7946NULL, /* 0Eh */7947NULL, /* 0Fh */7948"Activation failed: Already Active Volume", /* 10h */7949"Activation failed: Unsupported Volume Type", /* 11h */7950"Activation failed: Too Many Active Volumes", /* 12h */7951"Activation failed: Volume ID in Use", /* 13h */7952"Activation failed: Reported Failure", /* 14h */7953"Activation failed: Importing a Volume", /* 15h */7954NULL, /* 16h */7955NULL, /* 17h */7956NULL, /* 18h */7957NULL, /* 19h */7958NULL, /* 1Ah */7959NULL, /* 1Bh */7960NULL, /* 1Ch */7961NULL, /* 1Dh */7962NULL, /* 1Eh */7963NULL, /* 1Fh */7964"Phys Disk failed: Too Many Phys Disks", /* 20h */7965"Phys Disk failed: Data Passed too Large", /* 21h */7966"Phys Disk failed: DMA Error", /* 22h */7967"Phys Disk failed: Invalid <channel:id>", /* 23h */7968"Phys Disk failed: Creating Phys Disk Config "7969"Page", /* 24h */7970NULL, /* 25h */7971NULL, /* 26h */7972NULL, /* 27h */7973NULL, /* 28h */7974NULL, /* 29h */7975NULL, /* 2Ah */7976NULL, /* 2Bh */7977NULL, /* 2Ch */7978NULL, /* 2Dh */7979NULL, /* 2Eh */7980NULL, /* 2Fh */7981"Compatibility Error: IR Disabled", /* 30h */7982"Compatibility Error: Inquiry Command Failed", /* 31h */7983"Compatibility Error: Device not Direct Access "7984"Device ", /* 32h */7985"Compatibility Error: Removable Device Found", /* 33h */7986"Compatibility Error: Device SCSI Version not "7987"2 or Higher", /* 34h */7988"Compatibility Error: SATA Device, 48 BIT LBA "7989"not Supported", /* 35h */7990"Compatibility Error: Device doesn't have "7991"512 Byte Block Sizes", /* 36h */7992"Compatibility Error: Volume Type Check Failed", /* 37h */7993"Compatibility Error: Volume Type is "7994"Unsupported by FW", /* 38h */7995"Compatibility Error: Disk Drive too Small for "7996"use in Volume", /* 39h */7997"Compatibility Error: Phys Disk for Create "7998"Volume not Found", /* 3Ah */7999"Compatibility Error: Too Many or too Few "8000"Disks for Volume Type", /* 3Bh */8001"Compatibility Error: Disk stripe Sizes "8002"Must be 64KB", /* 3Ch */8003"Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */8004};80058006/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/8007/**8008* mpt_sas_log_info - Log information returned from SAS IOC.8009* @ioc: Pointer to MPT_ADAPTER structure8010* @log_info: U32 LogInfo reply word from the IOC8011* @cb_idx: callback function's handle8012*8013* Refer to lsi/mpi_log_sas.h.8014**/8015static void8016mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info, u8 cb_idx)8017{8018union loginfo_type {8019u32 loginfo;8020struct {8021u32 subcode:16;8022u32 code:8;8023u32 originator:4;8024u32 bus_type:4;8025}dw;8026};8027union loginfo_type sas_loginfo;8028char *originator_desc = NULL;8029char *code_desc = NULL;8030char *sub_code_desc = NULL;80318032sas_loginfo.loginfo = log_info;8033if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&8034(sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))8035return;80368037originator_desc = originator_str[sas_loginfo.dw.originator];80388039switch (sas_loginfo.dw.originator) {80408041case 0: /* IOP */8042if (sas_loginfo.dw.code <8043ARRAY_SIZE(iop_code_str))8044code_desc = iop_code_str[sas_loginfo.dw.code];8045break;8046case 1: /* PL */8047if (sas_loginfo.dw.code <8048ARRAY_SIZE(pl_code_str))8049code_desc = pl_code_str[sas_loginfo.dw.code];8050break;8051case 2: /* IR */8052if (sas_loginfo.dw.code >=8053ARRAY_SIZE(ir_code_str))8054break;8055code_desc = ir_code_str[sas_loginfo.dw.code];8056if (sas_loginfo.dw.subcode >=8057ARRAY_SIZE(raid_sub_code_str))8058break;8059if (sas_loginfo.dw.code == 0)8060sub_code_desc =8061raid_sub_code_str[sas_loginfo.dw.subcode];8062break;8063default:8064return;8065}80668067if (sub_code_desc != NULL)8068printk(MYIOC_s_INFO_FMT8069"LogInfo(0x%08x): Originator={%s}, Code={%s},"8070" SubCode={%s} cb_idx %s\n",8071ioc->name, log_info, originator_desc, code_desc,8072sub_code_desc, MptCallbacksName[cb_idx]);8073else if (code_desc != NULL)8074printk(MYIOC_s_INFO_FMT8075"LogInfo(0x%08x): Originator={%s}, Code={%s},"8076" SubCode(0x%04x) cb_idx %s\n",8077ioc->name, log_info, originator_desc, code_desc,8078sas_loginfo.dw.subcode, MptCallbacksName[cb_idx]);8079else8080printk(MYIOC_s_INFO_FMT8081"LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"8082" SubCode(0x%04x) cb_idx %s\n",8083ioc->name, log_info, originator_desc,8084sas_loginfo.dw.code, sas_loginfo.dw.subcode,8085MptCallbacksName[cb_idx]);8086}80878088/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/8089/**8090* mpt_iocstatus_info_config - IOCSTATUS information for config pages8091* @ioc: Pointer to MPT_ADAPTER structure8092* @ioc_status: U32 IOCStatus word from IOC8093* @mf: Pointer to MPT request frame8094*8095* Refer to lsi/mpi.h.8096**/8097static void8098mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)8099{8100Config_t *pReq = (Config_t *)mf;8101char extend_desc[EVENT_DESCR_STR_SZ];8102char *desc = NULL;8103u32 form;8104u8 page_type;81058106if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)8107page_type = pReq->ExtPageType;8108else8109page_type = pReq->Header.PageType;81108111/*8112* ignore invalid page messages for GET_NEXT_HANDLE8113*/8114form = le32_to_cpu(pReq->PageAddress);8115if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {8116if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||8117page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||8118page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {8119if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==8120MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)8121return;8122}8123if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)8124if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==8125MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)8126return;8127}81288129snprintf(extend_desc, EVENT_DESCR_STR_SZ,8130"type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",8131page_type, pReq->Header.PageNumber, pReq->Action, form);81328133switch (ioc_status) {81348135case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */8136desc = "Config Page Invalid Action";8137break;81388139case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */8140desc = "Config Page Invalid Type";8141break;81428143case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */8144desc = "Config Page Invalid Page";8145break;81468147case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */8148desc = "Config Page Invalid Data";8149break;81508151case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */8152desc = "Config Page No Defaults";8153break;81548155case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */8156desc = "Config Page Can't Commit";8157break;8158}81598160if (!desc)8161return;81628163dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",8164ioc->name, ioc_status, desc, extend_desc));8165}81668167/**8168* mpt_iocstatus_info - IOCSTATUS information returned from IOC.8169* @ioc: Pointer to MPT_ADAPTER structure8170* @ioc_status: U32 IOCStatus word from IOC8171* @mf: Pointer to MPT request frame8172*8173* Refer to lsi/mpi.h.8174**/8175static void8176mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)8177{8178u32 status = ioc_status & MPI_IOCSTATUS_MASK;8179char *desc = NULL;81808181switch (status) {81828183/****************************************************************************/8184/* Common IOCStatus values for all replies */8185/****************************************************************************/81868187case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */8188desc = "Invalid Function";8189break;81908191case MPI_IOCSTATUS_BUSY: /* 0x0002 */8192desc = "Busy";8193break;81948195case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */8196desc = "Invalid SGL";8197break;81988199case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */8200desc = "Internal Error";8201break;82028203case MPI_IOCSTATUS_RESERVED: /* 0x0005 */8204desc = "Reserved";8205break;82068207case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */8208desc = "Insufficient Resources";8209break;82108211case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */8212desc = "Invalid Field";8213break;82148215case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */8216desc = "Invalid State";8217break;82188219/****************************************************************************/8220/* Config IOCStatus values */8221/****************************************************************************/82228223case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */8224case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */8225case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */8226case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */8227case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */8228case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */8229mpt_iocstatus_info_config(ioc, status, mf);8230break;82318232/****************************************************************************/8233/* SCSIIO Reply (SPI, FCP, SAS) initiator values */8234/* */8235/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */8236/* */8237/****************************************************************************/82388239case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */8240case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */8241case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */8242case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */8243case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */8244case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */8245case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */8246case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */8247case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */8248case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */8249case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */8250case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */8251case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */8252break;82538254/****************************************************************************/8255/* SCSI Target values */8256/****************************************************************************/82578258case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */8259desc = "Target: Priority IO";8260break;82618262case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */8263desc = "Target: Invalid Port";8264break;82658266case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */8267desc = "Target Invalid IO Index:";8268break;82698270case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */8271desc = "Target: Aborted";8272break;82738274case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */8275desc = "Target: No Conn Retryable";8276break;82778278case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */8279desc = "Target: No Connection";8280break;82818282case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */8283desc = "Target: Transfer Count Mismatch";8284break;82858286case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */8287desc = "Target: STS Data not Sent";8288break;82898290case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */8291desc = "Target: Data Offset Error";8292break;82938294case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */8295desc = "Target: Too Much Write Data";8296break;82978298case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */8299desc = "Target: IU Too Short";8300break;83018302case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */8303desc = "Target: ACK NAK Timeout";8304break;83058306case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */8307desc = "Target: Nak Received";8308break;83098310/****************************************************************************/8311/* Fibre Channel Direct Access values */8312/****************************************************************************/83138314case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */8315desc = "FC: Aborted";8316break;83178318case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */8319desc = "FC: RX ID Invalid";8320break;83218322case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */8323desc = "FC: DID Invalid";8324break;83258326case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */8327desc = "FC: Node Logged Out";8328break;83298330case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */8331desc = "FC: Exchange Canceled";8332break;83338334/****************************************************************************/8335/* LAN values */8336/****************************************************************************/83378338case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */8339desc = "LAN: Device not Found";8340break;83418342case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */8343desc = "LAN: Device Failure";8344break;83458346case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */8347desc = "LAN: Transmit Error";8348break;83498350case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */8351desc = "LAN: Transmit Aborted";8352break;83538354case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */8355desc = "LAN: Receive Error";8356break;83578358case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */8359desc = "LAN: Receive Aborted";8360break;83618362case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */8363desc = "LAN: Partial Packet";8364break;83658366case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */8367desc = "LAN: Canceled";8368break;83698370/****************************************************************************/8371/* Serial Attached SCSI values */8372/****************************************************************************/83738374case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */8375desc = "SAS: SMP Request Failed";8376break;83778378case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */8379desc = "SAS: SMP Data Overrun";8380break;83818382default:8383desc = "Others";8384break;8385}83868387if (!desc)8388return;83898390dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",8391ioc->name, status, desc));8392}83938394/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/8395EXPORT_SYMBOL(mpt_attach);8396EXPORT_SYMBOL(mpt_detach);8397#ifdef CONFIG_PM8398EXPORT_SYMBOL(mpt_resume);8399EXPORT_SYMBOL(mpt_suspend);8400#endif8401EXPORT_SYMBOL(ioc_list);8402EXPORT_SYMBOL(mpt_register);8403EXPORT_SYMBOL(mpt_deregister);8404EXPORT_SYMBOL(mpt_event_register);8405EXPORT_SYMBOL(mpt_event_deregister);8406EXPORT_SYMBOL(mpt_reset_register);8407EXPORT_SYMBOL(mpt_reset_deregister);8408EXPORT_SYMBOL(mpt_device_driver_register);8409EXPORT_SYMBOL(mpt_device_driver_deregister);8410EXPORT_SYMBOL(mpt_get_msg_frame);8411EXPORT_SYMBOL(mpt_put_msg_frame);8412EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);8413EXPORT_SYMBOL(mpt_free_msg_frame);8414EXPORT_SYMBOL(mpt_send_handshake_request);8415EXPORT_SYMBOL(mpt_verify_adapter);8416EXPORT_SYMBOL(mpt_GetIocState);8417EXPORT_SYMBOL(mpt_print_ioc_summary);8418EXPORT_SYMBOL(mpt_HardResetHandler);8419EXPORT_SYMBOL(mpt_config);8420EXPORT_SYMBOL(mpt_findImVolumes);8421EXPORT_SYMBOL(mpt_alloc_fw_memory);8422EXPORT_SYMBOL(mpt_free_fw_memory);8423EXPORT_SYMBOL(mptbase_sas_persist_operation);8424EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);84258426/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/8427/**8428* fusion_init - Fusion MPT base driver initialization routine.8429*8430* Returns 0 for success, non-zero for failure.8431*/8432static int __init8433fusion_init(void)8434{8435u8 cb_idx;84368437show_mptmod_ver(my_NAME, my_VERSION);8438printk(KERN_INFO COPYRIGHT "\n");84398440for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {8441MptCallbacks[cb_idx] = NULL;8442MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;8443MptEvHandlers[cb_idx] = NULL;8444MptResetHandlers[cb_idx] = NULL;8445}84468447/* Register ourselves (mptbase) in order to facilitate8448* EventNotification handling.8449*/8450mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER,8451"mptbase_reply");84528453/* Register for hard reset handling callbacks.8454*/8455mpt_reset_register(mpt_base_index, mpt_ioc_reset);84568457#ifdef CONFIG_PROC_FS8458(void) procmpt_create();8459#endif8460return 0;8461}84628463/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/8464/**8465* fusion_exit - Perform driver unload cleanup.8466*8467* This routine frees all resources associated with each MPT adapter8468* and removes all %MPT_PROCFS_MPTBASEDIR entries.8469*/8470static void __exit8471fusion_exit(void)8472{84738474mpt_reset_deregister(mpt_base_index);84758476#ifdef CONFIG_PROC_FS8477procmpt_destroy();8478#endif8479}84808481module_init(fusion_init);8482module_exit(fusion_exit);848384848485