162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * linux/drivers/message/fusion/mptbase.c 362306a36Sopenharmony_ci * This is the Fusion MPT base driver which supports multiple 462306a36Sopenharmony_ci * (SCSI + LAN) specialized protocol drivers. 562306a36Sopenharmony_ci * For use with LSI PCI chip/adapter(s) 662306a36Sopenharmony_ci * running LSI Fusion MPT (Message Passing Technology) firmware. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (c) 1999-2008 LSI Corporation 962306a36Sopenharmony_ci * (mailto:DL-MPTFusionLinux@lsi.com) 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 1362306a36Sopenharmony_ci/* 1462306a36Sopenharmony_ci This program is free software; you can redistribute it and/or modify 1562306a36Sopenharmony_ci it under the terms of the GNU General Public License as published by 1662306a36Sopenharmony_ci the Free Software Foundation; version 2 of the License. 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci This program is distributed in the hope that it will be useful, 1962306a36Sopenharmony_ci but WITHOUT ANY WARRANTY; without even the implied warranty of 2062306a36Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2162306a36Sopenharmony_ci GNU General Public License for more details. 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci NO WARRANTY 2462306a36Sopenharmony_ci THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR 2562306a36Sopenharmony_ci CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT 2662306a36Sopenharmony_ci LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 2762306a36Sopenharmony_ci MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is 2862306a36Sopenharmony_ci solely responsible for determining the appropriateness of using and 2962306a36Sopenharmony_ci distributing the Program and assumes all risks associated with its 3062306a36Sopenharmony_ci exercise of rights under this Agreement, including but not limited to 3162306a36Sopenharmony_ci the risks and costs of program errors, damage to or loss of data, 3262306a36Sopenharmony_ci programs or equipment, and unavailability or interruption of operations. 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci DISCLAIMER OF LIABILITY 3562306a36Sopenharmony_ci NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY 3662306a36Sopenharmony_ci DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3762306a36Sopenharmony_ci DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND 3862306a36Sopenharmony_ci ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 3962306a36Sopenharmony_ci TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 4062306a36Sopenharmony_ci USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 4162306a36Sopenharmony_ci HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci You should have received a copy of the GNU General Public License 4462306a36Sopenharmony_ci along with this program; if not, write to the Free Software 4562306a36Sopenharmony_ci Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 4662306a36Sopenharmony_ci*/ 4762306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#include <linux/kernel.h> 5062306a36Sopenharmony_ci#include <linux/module.h> 5162306a36Sopenharmony_ci#include <linux/errno.h> 5262306a36Sopenharmony_ci#include <linux/init.h> 5362306a36Sopenharmony_ci#include <linux/seq_file.h> 5462306a36Sopenharmony_ci#include <linux/slab.h> 5562306a36Sopenharmony_ci#include <linux/types.h> 5662306a36Sopenharmony_ci#include <linux/pci.h> 5762306a36Sopenharmony_ci#include <linux/kdev_t.h> 5862306a36Sopenharmony_ci#include <linux/blkdev.h> 5962306a36Sopenharmony_ci#include <linux/delay.h> 6062306a36Sopenharmony_ci#include <linux/interrupt.h> 6162306a36Sopenharmony_ci#include <linux/dma-mapping.h> 6262306a36Sopenharmony_ci#include <linux/kthread.h> 6362306a36Sopenharmony_ci#include <scsi/scsi_host.h> 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#include "mptbase.h" 6662306a36Sopenharmony_ci#include "lsi/mpi_log_fc.h" 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 6962306a36Sopenharmony_ci#define my_NAME "Fusion MPT base driver" 7062306a36Sopenharmony_ci#define my_VERSION MPT_LINUX_VERSION_COMMON 7162306a36Sopenharmony_ci#define MYNAM "mptbase" 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciMODULE_AUTHOR(MODULEAUTHOR); 7462306a36Sopenharmony_ciMODULE_DESCRIPTION(my_NAME); 7562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 7662306a36Sopenharmony_ciMODULE_VERSION(my_VERSION); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* 7962306a36Sopenharmony_ci * cmd line parameters 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int mpt_msi_enable_spi; 8362306a36Sopenharmony_cimodule_param(mpt_msi_enable_spi, int, 0); 8462306a36Sopenharmony_ciMODULE_PARM_DESC(mpt_msi_enable_spi, 8562306a36Sopenharmony_ci " Enable MSI Support for SPI controllers (default=0)"); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic int mpt_msi_enable_fc; 8862306a36Sopenharmony_cimodule_param(mpt_msi_enable_fc, int, 0); 8962306a36Sopenharmony_ciMODULE_PARM_DESC(mpt_msi_enable_fc, 9062306a36Sopenharmony_ci " Enable MSI Support for FC controllers (default=0)"); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic int mpt_msi_enable_sas; 9362306a36Sopenharmony_cimodule_param(mpt_msi_enable_sas, int, 0); 9462306a36Sopenharmony_ciMODULE_PARM_DESC(mpt_msi_enable_sas, 9562306a36Sopenharmony_ci " Enable MSI Support for SAS controllers (default=0)"); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int mpt_channel_mapping; 9862306a36Sopenharmony_cimodule_param(mpt_channel_mapping, int, 0); 9962306a36Sopenharmony_ciMODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)"); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int mpt_debug_level; 10262306a36Sopenharmony_cistatic int mpt_set_debug_level(const char *val, const struct kernel_param *kp); 10362306a36Sopenharmony_cimodule_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int, 10462306a36Sopenharmony_ci &mpt_debug_level, 0600); 10562306a36Sopenharmony_ciMODULE_PARM_DESC(mpt_debug_level, 10662306a36Sopenharmony_ci " debug level - refer to mptdebug.h - (default=0)"); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ciint mpt_fwfault_debug; 10962306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_fwfault_debug); 11062306a36Sopenharmony_cimodule_param(mpt_fwfault_debug, int, 0600); 11162306a36Sopenharmony_ciMODULE_PARM_DESC(mpt_fwfault_debug, 11262306a36Sopenharmony_ci "Enable detection of Firmware fault and halt Firmware on fault - (default=0)"); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic char MptCallbacksName[MPT_MAX_PROTOCOL_DRIVERS] 11562306a36Sopenharmony_ci [MPT_MAX_CALLBACKNAME_LEN+1]; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#ifdef MFCNT 11862306a36Sopenharmony_cistatic int mfcounter = 0; 11962306a36Sopenharmony_ci#define PRINT_MF_COUNT 20000 12062306a36Sopenharmony_ci#endif 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 12362306a36Sopenharmony_ci/* 12462306a36Sopenharmony_ci * Public data... 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci#define WHOINIT_UNKNOWN 0xAA 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 13062306a36Sopenharmony_ci/* 13162306a36Sopenharmony_ci * Private data... 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ci /* Adapter link list */ 13462306a36Sopenharmony_ciLIST_HEAD(ioc_list); 13562306a36Sopenharmony_ci /* Callback lookup table */ 13662306a36Sopenharmony_cistatic MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS]; 13762306a36Sopenharmony_ci /* Protocol driver class lookup table */ 13862306a36Sopenharmony_cistatic int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS]; 13962306a36Sopenharmony_ci /* Event handler lookup table */ 14062306a36Sopenharmony_cistatic MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS]; 14162306a36Sopenharmony_ci /* Reset handler lookup table */ 14262306a36Sopenharmony_cistatic MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS]; 14362306a36Sopenharmony_cistatic struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS]; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 14662306a36Sopenharmony_cistatic struct proc_dir_entry *mpt_proc_root_dir; 14762306a36Sopenharmony_ci#endif 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/* 15062306a36Sopenharmony_ci * Driver Callback Index's 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_cistatic u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS; 15362306a36Sopenharmony_cistatic u8 last_drv_idx; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 15662306a36Sopenharmony_ci/* 15762306a36Sopenharmony_ci * Forward protos... 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_cistatic irqreturn_t mpt_interrupt(int irq, void *bus_id); 16062306a36Sopenharmony_cistatic int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, 16162306a36Sopenharmony_ci MPT_FRAME_HDR *reply); 16262306a36Sopenharmony_cistatic int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, 16362306a36Sopenharmony_ci u32 *req, int replyBytes, u16 *u16reply, int maxwait, 16462306a36Sopenharmony_ci int sleepFlag); 16562306a36Sopenharmony_cistatic int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag); 16662306a36Sopenharmony_cistatic void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev); 16762306a36Sopenharmony_cistatic void mpt_adapter_disable(MPT_ADAPTER *ioc); 16862306a36Sopenharmony_cistatic void mpt_adapter_dispose(MPT_ADAPTER *ioc); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic void MptDisplayIocCapabilities(MPT_ADAPTER *ioc); 17162306a36Sopenharmony_cistatic int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag); 17262306a36Sopenharmony_cistatic int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason); 17362306a36Sopenharmony_cistatic int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag); 17462306a36Sopenharmony_cistatic int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag); 17562306a36Sopenharmony_cistatic int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag); 17662306a36Sopenharmony_cistatic int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag); 17762306a36Sopenharmony_cistatic int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag); 17862306a36Sopenharmony_cistatic int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag); 17962306a36Sopenharmony_cistatic int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag); 18062306a36Sopenharmony_cistatic int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag); 18162306a36Sopenharmony_cistatic int PrimeIocFifos(MPT_ADAPTER *ioc); 18262306a36Sopenharmony_cistatic int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag); 18362306a36Sopenharmony_cistatic int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag); 18462306a36Sopenharmony_cistatic int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag); 18562306a36Sopenharmony_cistatic int GetLanConfigPages(MPT_ADAPTER *ioc); 18662306a36Sopenharmony_cistatic int GetIoUnitPage2(MPT_ADAPTER *ioc); 18762306a36Sopenharmony_ciint mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode); 18862306a36Sopenharmony_cistatic int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum); 18962306a36Sopenharmony_cistatic int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum); 19062306a36Sopenharmony_cistatic void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc); 19162306a36Sopenharmony_cistatic void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc); 19262306a36Sopenharmony_cistatic void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc); 19362306a36Sopenharmony_cistatic int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, 19462306a36Sopenharmony_ci int sleepFlag); 19562306a36Sopenharmony_cistatic int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp); 19662306a36Sopenharmony_cistatic int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag); 19762306a36Sopenharmony_cistatic int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 20062306a36Sopenharmony_cistatic int mpt_summary_proc_show(struct seq_file *m, void *v); 20162306a36Sopenharmony_cistatic int mpt_version_proc_show(struct seq_file *m, void *v); 20262306a36Sopenharmony_cistatic int mpt_iocinfo_proc_show(struct seq_file *m, void *v); 20362306a36Sopenharmony_ci#endif 20462306a36Sopenharmony_cistatic void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic int ProcessEventNotification(MPT_ADAPTER *ioc, 20762306a36Sopenharmony_ci EventNotificationReply_t *evReply, int *evHandlers); 20862306a36Sopenharmony_cistatic void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf); 20962306a36Sopenharmony_cistatic void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info); 21062306a36Sopenharmony_cistatic void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info); 21162306a36Sopenharmony_cistatic void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info , u8 cb_idx); 21262306a36Sopenharmony_cistatic int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc); 21362306a36Sopenharmony_cistatic void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci/* module entry point */ 21662306a36Sopenharmony_cistatic int __init fusion_init (void); 21762306a36Sopenharmony_cistatic void __exit fusion_exit (void); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci#define CHIPREG_READ32(addr) readl_relaxed(addr) 22062306a36Sopenharmony_ci#define CHIPREG_READ32_dmasync(addr) readl(addr) 22162306a36Sopenharmony_ci#define CHIPREG_WRITE32(addr,val) writel(val, addr) 22262306a36Sopenharmony_ci#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr) 22362306a36Sopenharmony_ci#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr) 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic void 22662306a36Sopenharmony_cipci_disable_io_access(struct pci_dev *pdev) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci u16 command_reg; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci pci_read_config_word(pdev, PCI_COMMAND, &command_reg); 23162306a36Sopenharmony_ci command_reg &= ~1; 23262306a36Sopenharmony_ci pci_write_config_word(pdev, PCI_COMMAND, command_reg); 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic void 23662306a36Sopenharmony_cipci_enable_io_access(struct pci_dev *pdev) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci u16 command_reg; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci pci_read_config_word(pdev, PCI_COMMAND, &command_reg); 24162306a36Sopenharmony_ci command_reg |= 1; 24262306a36Sopenharmony_ci pci_write_config_word(pdev, PCI_COMMAND, command_reg); 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic int mpt_set_debug_level(const char *val, const struct kernel_param *kp) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci int ret = param_set_int(val, kp); 24862306a36Sopenharmony_ci MPT_ADAPTER *ioc; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (ret) 25162306a36Sopenharmony_ci return ret; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci list_for_each_entry(ioc, &ioc_list, list) 25462306a36Sopenharmony_ci ioc->debug_level = mpt_debug_level; 25562306a36Sopenharmony_ci return 0; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/** 25962306a36Sopenharmony_ci * mpt_get_cb_idx - obtain cb_idx for registered driver 26062306a36Sopenharmony_ci * @dclass: class driver enum 26162306a36Sopenharmony_ci * 26262306a36Sopenharmony_ci * Returns cb_idx, or zero means it wasn't found 26362306a36Sopenharmony_ci **/ 26462306a36Sopenharmony_cistatic u8 26562306a36Sopenharmony_cimpt_get_cb_idx(MPT_DRIVER_CLASS dclass) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci u8 cb_idx; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) 27062306a36Sopenharmony_ci if (MptDriverClass[cb_idx] == dclass) 27162306a36Sopenharmony_ci return cb_idx; 27262306a36Sopenharmony_ci return 0; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci/** 27662306a36Sopenharmony_ci * mpt_is_discovery_complete - determine if discovery has completed 27762306a36Sopenharmony_ci * @ioc: per adatper instance 27862306a36Sopenharmony_ci * 27962306a36Sopenharmony_ci * Returns 1 when discovery completed, else zero. 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_cistatic int 28262306a36Sopenharmony_cimpt_is_discovery_complete(MPT_ADAPTER *ioc) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci ConfigExtendedPageHeader_t hdr; 28562306a36Sopenharmony_ci CONFIGPARMS cfg; 28662306a36Sopenharmony_ci SasIOUnitPage0_t *buffer; 28762306a36Sopenharmony_ci dma_addr_t dma_handle; 28862306a36Sopenharmony_ci int rc = 0; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t)); 29162306a36Sopenharmony_ci memset(&cfg, 0, sizeof(CONFIGPARMS)); 29262306a36Sopenharmony_ci hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; 29362306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 29462306a36Sopenharmony_ci hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; 29562306a36Sopenharmony_ci cfg.cfghdr.ehdr = &hdr; 29662306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if ((mpt_config(ioc, &cfg))) 29962306a36Sopenharmony_ci goto out; 30062306a36Sopenharmony_ci if (!hdr.ExtPageLength) 30162306a36Sopenharmony_ci goto out; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, 30462306a36Sopenharmony_ci &dma_handle, GFP_KERNEL); 30562306a36Sopenharmony_ci if (!buffer) 30662306a36Sopenharmony_ci goto out; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci cfg.physAddr = dma_handle; 30962306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if ((mpt_config(ioc, &cfg))) 31262306a36Sopenharmony_ci goto out_free_consistent; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (!(buffer->PhyData[0].PortFlags & 31562306a36Sopenharmony_ci MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS)) 31662306a36Sopenharmony_ci rc = 1; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci out_free_consistent: 31962306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, buffer, 32062306a36Sopenharmony_ci dma_handle); 32162306a36Sopenharmony_ci out: 32262306a36Sopenharmony_ci return rc; 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci/** 32762306a36Sopenharmony_ci * mpt_remove_dead_ioc_func - kthread context to remove dead ioc 32862306a36Sopenharmony_ci * @arg: input argument, used to derive ioc 32962306a36Sopenharmony_ci * 33062306a36Sopenharmony_ci * Return 0 if controller is removed from pci subsystem. 33162306a36Sopenharmony_ci * Return -1 for other case. 33262306a36Sopenharmony_ci */ 33362306a36Sopenharmony_cistatic int mpt_remove_dead_ioc_func(void *arg) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; 33662306a36Sopenharmony_ci struct pci_dev *pdev; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (!ioc) 33962306a36Sopenharmony_ci return -1; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci pdev = ioc->pcidev; 34262306a36Sopenharmony_ci if (!pdev) 34362306a36Sopenharmony_ci return -1; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci pci_stop_and_remove_bus_device_locked(pdev); 34662306a36Sopenharmony_ci return 0; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci/** 35262306a36Sopenharmony_ci * mpt_fault_reset_work - work performed on workq after ioc fault 35362306a36Sopenharmony_ci * @work: input argument, used to derive ioc 35462306a36Sopenharmony_ci * 35562306a36Sopenharmony_ci**/ 35662306a36Sopenharmony_cistatic void 35762306a36Sopenharmony_cimpt_fault_reset_work(struct work_struct *work) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci MPT_ADAPTER *ioc = 36062306a36Sopenharmony_ci container_of(work, MPT_ADAPTER, fault_reset_work.work); 36162306a36Sopenharmony_ci u32 ioc_raw_state; 36262306a36Sopenharmony_ci int rc; 36362306a36Sopenharmony_ci unsigned long flags; 36462306a36Sopenharmony_ci MPT_SCSI_HOST *hd; 36562306a36Sopenharmony_ci struct task_struct *p; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (ioc->ioc_reset_in_progress || !ioc->active) 36862306a36Sopenharmony_ci goto out; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci ioc_raw_state = mpt_GetIocState(ioc, 0); 37262306a36Sopenharmony_ci if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_MASK) { 37362306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "%s: IOC is non-operational !!!!\n", 37462306a36Sopenharmony_ci ioc->name, __func__); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* 37762306a36Sopenharmony_ci * Call mptscsih_flush_pending_cmds callback so that we 37862306a36Sopenharmony_ci * flush all pending commands back to OS. 37962306a36Sopenharmony_ci * This call is required to aovid deadlock at block layer. 38062306a36Sopenharmony_ci * Dead IOC will fail to do diag reset,and this call is safe 38162306a36Sopenharmony_ci * since dead ioc will never return any command back from HW. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_ci hd = shost_priv(ioc->sh); 38462306a36Sopenharmony_ci ioc->schedule_dead_ioc_flush_running_cmds(hd); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /*Remove the Dead Host */ 38762306a36Sopenharmony_ci p = kthread_run(mpt_remove_dead_ioc_func, ioc, 38862306a36Sopenharmony_ci "mpt_dead_ioc_%d", ioc->id); 38962306a36Sopenharmony_ci if (IS_ERR(p)) { 39062306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT 39162306a36Sopenharmony_ci "%s: Running mpt_dead_ioc thread failed !\n", 39262306a36Sopenharmony_ci ioc->name, __func__); 39362306a36Sopenharmony_ci } else { 39462306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 39562306a36Sopenharmony_ci "%s: Running mpt_dead_ioc thread success !\n", 39662306a36Sopenharmony_ci ioc->name, __func__); 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci return; /* don't rearm timer */ 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if ((ioc_raw_state & MPI_IOC_STATE_MASK) 40262306a36Sopenharmony_ci == MPI_IOC_STATE_FAULT) { 40362306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n", 40462306a36Sopenharmony_ci ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); 40562306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", 40662306a36Sopenharmony_ci ioc->name, __func__); 40762306a36Sopenharmony_ci rc = mpt_HardResetHandler(ioc, CAN_SLEEP); 40862306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name, 40962306a36Sopenharmony_ci __func__, (rc == 0) ? "success" : "failed"); 41062306a36Sopenharmony_ci ioc_raw_state = mpt_GetIocState(ioc, 0); 41162306a36Sopenharmony_ci if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) 41262306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after " 41362306a36Sopenharmony_ci "reset (%04xh)\n", ioc->name, ioc_raw_state & 41462306a36Sopenharmony_ci MPI_DOORBELL_DATA_MASK); 41562306a36Sopenharmony_ci } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) { 41662306a36Sopenharmony_ci if ((mpt_is_discovery_complete(ioc))) { 41762306a36Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing " 41862306a36Sopenharmony_ci "discovery_quiesce_io flag\n", ioc->name)); 41962306a36Sopenharmony_ci ioc->sas_discovery_quiesce_io = 0; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci out: 42462306a36Sopenharmony_ci /* 42562306a36Sopenharmony_ci * Take turns polling alternate controller 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_ci if (ioc->alt_ioc) 42862306a36Sopenharmony_ci ioc = ioc->alt_ioc; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* rearm the timer */ 43162306a36Sopenharmony_ci spin_lock_irqsave(&ioc->taskmgmt_lock, flags); 43262306a36Sopenharmony_ci if (ioc->reset_work_q) 43362306a36Sopenharmony_ci queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work, 43462306a36Sopenharmony_ci msecs_to_jiffies(MPT_POLLING_INTERVAL)); 43562306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci/* 44062306a36Sopenharmony_ci * Process turbo (context) reply... 44162306a36Sopenharmony_ci */ 44262306a36Sopenharmony_cistatic void 44362306a36Sopenharmony_cimpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci MPT_FRAME_HDR *mf = NULL; 44662306a36Sopenharmony_ci MPT_FRAME_HDR *mr = NULL; 44762306a36Sopenharmony_ci u16 req_idx = 0; 44862306a36Sopenharmony_ci u8 cb_idx; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n", 45162306a36Sopenharmony_ci ioc->name, pa)); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) { 45462306a36Sopenharmony_ci case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT: 45562306a36Sopenharmony_ci req_idx = pa & 0x0000FFFF; 45662306a36Sopenharmony_ci cb_idx = (pa & 0x00FF0000) >> 16; 45762306a36Sopenharmony_ci mf = MPT_INDEX_2_MFPTR(ioc, req_idx); 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci case MPI_CONTEXT_REPLY_TYPE_LAN: 46062306a36Sopenharmony_ci cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER); 46162306a36Sopenharmony_ci /* 46262306a36Sopenharmony_ci * Blind set of mf to NULL here was fatal 46362306a36Sopenharmony_ci * after lan_reply says "freeme" 46462306a36Sopenharmony_ci * Fix sort of combined with an optimization here; 46562306a36Sopenharmony_ci * added explicit check for case where lan_reply 46662306a36Sopenharmony_ci * was just returning 1 and doing nothing else. 46762306a36Sopenharmony_ci * For this case skip the callback, but set up 46862306a36Sopenharmony_ci * proper mf value first here:-) 46962306a36Sopenharmony_ci */ 47062306a36Sopenharmony_ci if ((pa & 0x58000000) == 0x58000000) { 47162306a36Sopenharmony_ci req_idx = pa & 0x0000FFFF; 47262306a36Sopenharmony_ci mf = MPT_INDEX_2_MFPTR(ioc, req_idx); 47362306a36Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 47462306a36Sopenharmony_ci mb(); 47562306a36Sopenharmony_ci return; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); 47862306a36Sopenharmony_ci break; 47962306a36Sopenharmony_ci case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET: 48062306a36Sopenharmony_ci cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER); 48162306a36Sopenharmony_ci mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); 48262306a36Sopenharmony_ci break; 48362306a36Sopenharmony_ci default: 48462306a36Sopenharmony_ci cb_idx = 0; 48562306a36Sopenharmony_ci BUG(); 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* Check for (valid) IO callback! */ 48962306a36Sopenharmony_ci if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || 49062306a36Sopenharmony_ci MptCallbacks[cb_idx] == NULL) { 49162306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", 49262306a36Sopenharmony_ci __func__, ioc->name, cb_idx); 49362306a36Sopenharmony_ci goto out; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci if (MptCallbacks[cb_idx](ioc, mf, mr)) 49762306a36Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 49862306a36Sopenharmony_ci out: 49962306a36Sopenharmony_ci mb(); 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic void 50362306a36Sopenharmony_cimpt_reply(MPT_ADAPTER *ioc, u32 pa) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci MPT_FRAME_HDR *mf; 50662306a36Sopenharmony_ci MPT_FRAME_HDR *mr; 50762306a36Sopenharmony_ci u16 req_idx; 50862306a36Sopenharmony_ci u8 cb_idx; 50962306a36Sopenharmony_ci int freeme; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci u32 reply_dma_low; 51262306a36Sopenharmony_ci u16 ioc_stat; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* non-TURBO reply! Hmmm, something may be up... 51562306a36Sopenharmony_ci * Newest turbo reply mechanism; get address 51662306a36Sopenharmony_ci * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)! 51762306a36Sopenharmony_ci */ 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci /* Map DMA address of reply header to cpu address. 52062306a36Sopenharmony_ci * pa is 32 bits - but the dma address may be 32 or 64 bits 52162306a36Sopenharmony_ci * get offset based only only the low addresses 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci reply_dma_low = (pa <<= 1); 52562306a36Sopenharmony_ci mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames + 52662306a36Sopenharmony_ci (reply_dma_low - ioc->reply_frames_low_dma)); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx); 52962306a36Sopenharmony_ci cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx; 53062306a36Sopenharmony_ci mf = MPT_INDEX_2_MFPTR(ioc, req_idx); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n", 53362306a36Sopenharmony_ci ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function)); 53462306a36Sopenharmony_ci DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* Check/log IOC log info 53762306a36Sopenharmony_ci */ 53862306a36Sopenharmony_ci ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus); 53962306a36Sopenharmony_ci if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { 54062306a36Sopenharmony_ci u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo); 54162306a36Sopenharmony_ci if (ioc->bus_type == FC) 54262306a36Sopenharmony_ci mpt_fc_log_info(ioc, log_info); 54362306a36Sopenharmony_ci else if (ioc->bus_type == SPI) 54462306a36Sopenharmony_ci mpt_spi_log_info(ioc, log_info); 54562306a36Sopenharmony_ci else if (ioc->bus_type == SAS) 54662306a36Sopenharmony_ci mpt_sas_log_info(ioc, log_info, cb_idx); 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (ioc_stat & MPI_IOCSTATUS_MASK) 55062306a36Sopenharmony_ci mpt_iocstatus_info(ioc, (u32)ioc_stat, mf); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci /* Check for (valid) IO callback! */ 55362306a36Sopenharmony_ci if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || 55462306a36Sopenharmony_ci MptCallbacks[cb_idx] == NULL) { 55562306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", 55662306a36Sopenharmony_ci __func__, ioc->name, cb_idx); 55762306a36Sopenharmony_ci freeme = 0; 55862306a36Sopenharmony_ci goto out; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci freeme = MptCallbacks[cb_idx](ioc, mf, mr); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci out: 56462306a36Sopenharmony_ci /* Flush (non-TURBO) reply with a WRITE! */ 56562306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (freeme) 56862306a36Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 56962306a36Sopenharmony_ci mb(); 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 57362306a36Sopenharmony_ci/** 57462306a36Sopenharmony_ci * mpt_interrupt - MPT adapter (IOC) specific interrupt handler. 57562306a36Sopenharmony_ci * @irq: irq number (not used) 57662306a36Sopenharmony_ci * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure 57762306a36Sopenharmony_ci * 57862306a36Sopenharmony_ci * This routine is registered via the request_irq() kernel API call, 57962306a36Sopenharmony_ci * and handles all interrupts generated from a specific MPT adapter 58062306a36Sopenharmony_ci * (also referred to as a IO Controller or IOC). 58162306a36Sopenharmony_ci * This routine must clear the interrupt from the adapter and does 58262306a36Sopenharmony_ci * so by reading the reply FIFO. Multiple replies may be processed 58362306a36Sopenharmony_ci * per single call to this routine. 58462306a36Sopenharmony_ci * 58562306a36Sopenharmony_ci * This routine handles register-level access of the adapter but 58662306a36Sopenharmony_ci * dispatches (calls) a protocol-specific callback routine to handle 58762306a36Sopenharmony_ci * the protocol-specific details of the MPT request completion. 58862306a36Sopenharmony_ci */ 58962306a36Sopenharmony_cistatic irqreturn_t 59062306a36Sopenharmony_cimpt_interrupt(int irq, void *bus_id) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci MPT_ADAPTER *ioc = bus_id; 59362306a36Sopenharmony_ci u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (pa == 0xFFFFFFFF) 59662306a36Sopenharmony_ci return IRQ_NONE; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci /* 59962306a36Sopenharmony_ci * Drain the reply FIFO! 60062306a36Sopenharmony_ci */ 60162306a36Sopenharmony_ci do { 60262306a36Sopenharmony_ci if (pa & MPI_ADDRESS_REPLY_A_BIT) 60362306a36Sopenharmony_ci mpt_reply(ioc, pa); 60462306a36Sopenharmony_ci else 60562306a36Sopenharmony_ci mpt_turbo_reply(ioc, pa); 60662306a36Sopenharmony_ci pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); 60762306a36Sopenharmony_ci } while (pa != 0xFFFFFFFF); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci return IRQ_HANDLED; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 61362306a36Sopenharmony_ci/** 61462306a36Sopenharmony_ci * mptbase_reply - MPT base driver's callback routine 61562306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 61662306a36Sopenharmony_ci * @req: Pointer to original MPT request frame 61762306a36Sopenharmony_ci * @reply: Pointer to MPT reply frame (NULL if TurboReply) 61862306a36Sopenharmony_ci * 61962306a36Sopenharmony_ci * MPT base driver's callback routine; all base driver 62062306a36Sopenharmony_ci * "internal" request/reply processing is routed here. 62162306a36Sopenharmony_ci * Currently used for EventNotification and EventAck handling. 62262306a36Sopenharmony_ci * 62362306a36Sopenharmony_ci * Returns 1 indicating original alloc'd request frame ptr 62462306a36Sopenharmony_ci * should be freed, or 0 if it shouldn't. 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_cistatic int 62762306a36Sopenharmony_cimptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci EventNotificationReply_t *pEventReply; 63062306a36Sopenharmony_ci u8 event; 63162306a36Sopenharmony_ci int evHandlers; 63262306a36Sopenharmony_ci int freereq = 1; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci switch (reply->u.hdr.Function) { 63562306a36Sopenharmony_ci case MPI_FUNCTION_EVENT_NOTIFICATION: 63662306a36Sopenharmony_ci pEventReply = (EventNotificationReply_t *)reply; 63762306a36Sopenharmony_ci evHandlers = 0; 63862306a36Sopenharmony_ci ProcessEventNotification(ioc, pEventReply, &evHandlers); 63962306a36Sopenharmony_ci event = le32_to_cpu(pEventReply->Event) & 0xFF; 64062306a36Sopenharmony_ci if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) 64162306a36Sopenharmony_ci freereq = 0; 64262306a36Sopenharmony_ci if (event != MPI_EVENT_EVENT_CHANGE) 64362306a36Sopenharmony_ci break; 64462306a36Sopenharmony_ci fallthrough; 64562306a36Sopenharmony_ci case MPI_FUNCTION_CONFIG: 64662306a36Sopenharmony_ci case MPI_FUNCTION_SAS_IO_UNIT_CONTROL: 64762306a36Sopenharmony_ci ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; 64862306a36Sopenharmony_ci ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID; 64962306a36Sopenharmony_ci memcpy(ioc->mptbase_cmds.reply, reply, 65062306a36Sopenharmony_ci min(MPT_DEFAULT_FRAME_SIZE, 65162306a36Sopenharmony_ci 4 * reply->u.reply.MsgLength)); 65262306a36Sopenharmony_ci if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) { 65362306a36Sopenharmony_ci ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING; 65462306a36Sopenharmony_ci complete(&ioc->mptbase_cmds.done); 65562306a36Sopenharmony_ci } else 65662306a36Sopenharmony_ci freereq = 0; 65762306a36Sopenharmony_ci if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF) 65862306a36Sopenharmony_ci freereq = 1; 65962306a36Sopenharmony_ci break; 66062306a36Sopenharmony_ci case MPI_FUNCTION_EVENT_ACK: 66162306a36Sopenharmony_ci devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT 66262306a36Sopenharmony_ci "EventAck reply received\n", ioc->name)); 66362306a36Sopenharmony_ci break; 66462306a36Sopenharmony_ci default: 66562306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT 66662306a36Sopenharmony_ci "Unexpected msg function (=%02Xh) reply received!\n", 66762306a36Sopenharmony_ci ioc->name, reply->u.hdr.Function); 66862306a36Sopenharmony_ci break; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci /* 67262306a36Sopenharmony_ci * Conditionally tell caller to free the original 67362306a36Sopenharmony_ci * EventNotification/EventAck/unexpected request frame! 67462306a36Sopenharmony_ci */ 67562306a36Sopenharmony_ci return freereq; 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 67962306a36Sopenharmony_ci/** 68062306a36Sopenharmony_ci * mpt_register - Register protocol-specific main callback handler. 68162306a36Sopenharmony_ci * @cbfunc: callback function pointer 68262306a36Sopenharmony_ci * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value) 68362306a36Sopenharmony_ci * @func_name: call function's name 68462306a36Sopenharmony_ci * 68562306a36Sopenharmony_ci * This routine is called by a protocol-specific driver (SCSI host, 68662306a36Sopenharmony_ci * LAN, SCSI target) to register its reply callback routine. Each 68762306a36Sopenharmony_ci * protocol-specific driver must do this before it will be able to 68862306a36Sopenharmony_ci * use any IOC resources, such as obtaining request frames. 68962306a36Sopenharmony_ci * 69062306a36Sopenharmony_ci * NOTES: The SCSI protocol driver currently calls this routine thrice 69162306a36Sopenharmony_ci * in order to register separate callbacks; one for "normal" SCSI IO; 69262306a36Sopenharmony_ci * one for MptScsiTaskMgmt requests; one for Scan/DV requests. 69362306a36Sopenharmony_ci * 69462306a36Sopenharmony_ci * Returns u8 valued "handle" in the range (and S.O.D. order) 69562306a36Sopenharmony_ci * {N,...,7,6,5,...,1} if successful. 69662306a36Sopenharmony_ci * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be 69762306a36Sopenharmony_ci * considered an error by the caller. 69862306a36Sopenharmony_ci */ 69962306a36Sopenharmony_ciu8 70062306a36Sopenharmony_cimpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci u8 cb_idx; 70362306a36Sopenharmony_ci last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* 70662306a36Sopenharmony_ci * Search for empty callback slot in this order: {N,...,7,6,5,...,1} 70762306a36Sopenharmony_ci * (slot/handle 0 is reserved!) 70862306a36Sopenharmony_ci */ 70962306a36Sopenharmony_ci for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { 71062306a36Sopenharmony_ci if (MptCallbacks[cb_idx] == NULL) { 71162306a36Sopenharmony_ci MptCallbacks[cb_idx] = cbfunc; 71262306a36Sopenharmony_ci MptDriverClass[cb_idx] = dclass; 71362306a36Sopenharmony_ci MptEvHandlers[cb_idx] = NULL; 71462306a36Sopenharmony_ci last_drv_idx = cb_idx; 71562306a36Sopenharmony_ci strscpy(MptCallbacksName[cb_idx], func_name, 71662306a36Sopenharmony_ci MPT_MAX_CALLBACKNAME_LEN+1); 71762306a36Sopenharmony_ci break; 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci return last_drv_idx; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 72562306a36Sopenharmony_ci/** 72662306a36Sopenharmony_ci * mpt_deregister - Deregister a protocol drivers resources. 72762306a36Sopenharmony_ci * @cb_idx: previously registered callback handle 72862306a36Sopenharmony_ci * 72962306a36Sopenharmony_ci * Each protocol-specific driver should call this routine when its 73062306a36Sopenharmony_ci * module is unloaded. 73162306a36Sopenharmony_ci */ 73262306a36Sopenharmony_civoid 73362306a36Sopenharmony_cimpt_deregister(u8 cb_idx) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) { 73662306a36Sopenharmony_ci MptCallbacks[cb_idx] = NULL; 73762306a36Sopenharmony_ci MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER; 73862306a36Sopenharmony_ci MptEvHandlers[cb_idx] = NULL; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci last_drv_idx++; 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 74562306a36Sopenharmony_ci/** 74662306a36Sopenharmony_ci * mpt_event_register - Register protocol-specific event callback handler. 74762306a36Sopenharmony_ci * @cb_idx: previously registered (via mpt_register) callback handle 74862306a36Sopenharmony_ci * @ev_cbfunc: callback function 74962306a36Sopenharmony_ci * 75062306a36Sopenharmony_ci * This routine can be called by one or more protocol-specific drivers 75162306a36Sopenharmony_ci * if/when they choose to be notified of MPT events. 75262306a36Sopenharmony_ci * 75362306a36Sopenharmony_ci * Returns 0 for success. 75462306a36Sopenharmony_ci */ 75562306a36Sopenharmony_ciint 75662306a36Sopenharmony_cimpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) 75962306a36Sopenharmony_ci return -1; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci MptEvHandlers[cb_idx] = ev_cbfunc; 76262306a36Sopenharmony_ci return 0; 76362306a36Sopenharmony_ci} 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 76662306a36Sopenharmony_ci/** 76762306a36Sopenharmony_ci * mpt_event_deregister - Deregister protocol-specific event callback handler 76862306a36Sopenharmony_ci * @cb_idx: previously registered callback handle 76962306a36Sopenharmony_ci * 77062306a36Sopenharmony_ci * Each protocol-specific driver should call this routine 77162306a36Sopenharmony_ci * when it does not (or can no longer) handle events, 77262306a36Sopenharmony_ci * or when its module is unloaded. 77362306a36Sopenharmony_ci */ 77462306a36Sopenharmony_civoid 77562306a36Sopenharmony_cimpt_event_deregister(u8 cb_idx) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) 77862306a36Sopenharmony_ci return; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci MptEvHandlers[cb_idx] = NULL; 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 78462306a36Sopenharmony_ci/** 78562306a36Sopenharmony_ci * mpt_reset_register - Register protocol-specific IOC reset handler. 78662306a36Sopenharmony_ci * @cb_idx: previously registered (via mpt_register) callback handle 78762306a36Sopenharmony_ci * @reset_func: reset function 78862306a36Sopenharmony_ci * 78962306a36Sopenharmony_ci * This routine can be called by one or more protocol-specific drivers 79062306a36Sopenharmony_ci * if/when they choose to be notified of IOC resets. 79162306a36Sopenharmony_ci * 79262306a36Sopenharmony_ci * Returns 0 for success. 79362306a36Sopenharmony_ci */ 79462306a36Sopenharmony_ciint 79562306a36Sopenharmony_cimpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) 79862306a36Sopenharmony_ci return -1; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci MptResetHandlers[cb_idx] = reset_func; 80162306a36Sopenharmony_ci return 0; 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 80562306a36Sopenharmony_ci/** 80662306a36Sopenharmony_ci * mpt_reset_deregister - Deregister protocol-specific IOC reset handler. 80762306a36Sopenharmony_ci * @cb_idx: previously registered callback handle 80862306a36Sopenharmony_ci * 80962306a36Sopenharmony_ci * Each protocol-specific driver should call this routine 81062306a36Sopenharmony_ci * when it does not (or can no longer) handle IOC reset handling, 81162306a36Sopenharmony_ci * or when its module is unloaded. 81262306a36Sopenharmony_ci */ 81362306a36Sopenharmony_civoid 81462306a36Sopenharmony_cimpt_reset_deregister(u8 cb_idx) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) 81762306a36Sopenharmony_ci return; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci MptResetHandlers[cb_idx] = NULL; 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 82362306a36Sopenharmony_ci/** 82462306a36Sopenharmony_ci * mpt_device_driver_register - Register device driver hooks 82562306a36Sopenharmony_ci * @dd_cbfunc: driver callbacks struct 82662306a36Sopenharmony_ci * @cb_idx: MPT protocol driver index 82762306a36Sopenharmony_ci */ 82862306a36Sopenharmony_ciint 82962306a36Sopenharmony_cimpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci MPT_ADAPTER *ioc; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) 83462306a36Sopenharmony_ci return -EINVAL; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci MptDeviceDriverHandlers[cb_idx] = dd_cbfunc; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci /* call per pci device probe entry point */ 83962306a36Sopenharmony_ci list_for_each_entry(ioc, &ioc_list, list) { 84062306a36Sopenharmony_ci if (dd_cbfunc->probe) 84162306a36Sopenharmony_ci dd_cbfunc->probe(ioc->pcidev); 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci return 0; 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 84862306a36Sopenharmony_ci/** 84962306a36Sopenharmony_ci * mpt_device_driver_deregister - DeRegister device driver hooks 85062306a36Sopenharmony_ci * @cb_idx: MPT protocol driver index 85162306a36Sopenharmony_ci */ 85262306a36Sopenharmony_civoid 85362306a36Sopenharmony_cimpt_device_driver_deregister(u8 cb_idx) 85462306a36Sopenharmony_ci{ 85562306a36Sopenharmony_ci struct mpt_pci_driver *dd_cbfunc; 85662306a36Sopenharmony_ci MPT_ADAPTER *ioc; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) 85962306a36Sopenharmony_ci return; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci dd_cbfunc = MptDeviceDriverHandlers[cb_idx]; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci list_for_each_entry(ioc, &ioc_list, list) { 86462306a36Sopenharmony_ci if (dd_cbfunc->remove) 86562306a36Sopenharmony_ci dd_cbfunc->remove(ioc->pcidev); 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci MptDeviceDriverHandlers[cb_idx] = NULL; 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 87362306a36Sopenharmony_ci/** 87462306a36Sopenharmony_ci * mpt_get_msg_frame - Obtain an MPT request frame from the pool 87562306a36Sopenharmony_ci * @cb_idx: Handle of registered MPT protocol driver 87662306a36Sopenharmony_ci * @ioc: Pointer to MPT adapter structure 87762306a36Sopenharmony_ci * 87862306a36Sopenharmony_ci * Obtain an MPT request frame from the pool (of 1024) that are 87962306a36Sopenharmony_ci * allocated per MPT adapter. 88062306a36Sopenharmony_ci * 88162306a36Sopenharmony_ci * Returns pointer to a MPT request frame or %NULL if none are available 88262306a36Sopenharmony_ci * or IOC is not active. 88362306a36Sopenharmony_ci */ 88462306a36Sopenharmony_ciMPT_FRAME_HDR* 88562306a36Sopenharmony_cimpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci MPT_FRAME_HDR *mf; 88862306a36Sopenharmony_ci unsigned long flags; 88962306a36Sopenharmony_ci u16 req_idx; /* Request index */ 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci /* validate handle and ioc identifier */ 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci#ifdef MFCNT 89462306a36Sopenharmony_ci if (!ioc->active) 89562306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame " 89662306a36Sopenharmony_ci "returning NULL!\n", ioc->name); 89762306a36Sopenharmony_ci#endif 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci /* If interrupts are not attached, do not return a request frame */ 90062306a36Sopenharmony_ci if (!ioc->active) 90162306a36Sopenharmony_ci return NULL; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci spin_lock_irqsave(&ioc->FreeQlock, flags); 90462306a36Sopenharmony_ci if (!list_empty(&ioc->FreeQ)) { 90562306a36Sopenharmony_ci int req_offset; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR, 90862306a36Sopenharmony_ci u.frame.linkage.list); 90962306a36Sopenharmony_ci list_del(&mf->u.frame.linkage.list); 91062306a36Sopenharmony_ci mf->u.frame.linkage.arg1 = 0; 91162306a36Sopenharmony_ci mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */ 91262306a36Sopenharmony_ci req_offset = (u8 *)mf - (u8 *)ioc->req_frames; 91362306a36Sopenharmony_ci /* u16! */ 91462306a36Sopenharmony_ci req_idx = req_offset / ioc->req_sz; 91562306a36Sopenharmony_ci mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); 91662306a36Sopenharmony_ci mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; 91762306a36Sopenharmony_ci /* Default, will be changed if necessary in SG generation */ 91862306a36Sopenharmony_ci ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; 91962306a36Sopenharmony_ci#ifdef MFCNT 92062306a36Sopenharmony_ci ioc->mfcnt++; 92162306a36Sopenharmony_ci#endif 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci else 92462306a36Sopenharmony_ci mf = NULL; 92562306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->FreeQlock, flags); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci#ifdef MFCNT 92862306a36Sopenharmony_ci if (mf == NULL) 92962306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! " 93062306a36Sopenharmony_ci "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt, 93162306a36Sopenharmony_ci ioc->req_depth); 93262306a36Sopenharmony_ci mfcounter++; 93362306a36Sopenharmony_ci if (mfcounter == PRINT_MF_COUNT) 93462306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name, 93562306a36Sopenharmony_ci ioc->mfcnt, ioc->req_depth); 93662306a36Sopenharmony_ci#endif 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n", 93962306a36Sopenharmony_ci ioc->name, cb_idx, ioc->id, mf)); 94062306a36Sopenharmony_ci return mf; 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 94462306a36Sopenharmony_ci/** 94562306a36Sopenharmony_ci * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC 94662306a36Sopenharmony_ci * @cb_idx: Handle of registered MPT protocol driver 94762306a36Sopenharmony_ci * @ioc: Pointer to MPT adapter structure 94862306a36Sopenharmony_ci * @mf: Pointer to MPT request frame 94962306a36Sopenharmony_ci * 95062306a36Sopenharmony_ci * This routine posts an MPT request frame to the request post FIFO of a 95162306a36Sopenharmony_ci * specific MPT adapter. 95262306a36Sopenharmony_ci */ 95362306a36Sopenharmony_civoid 95462306a36Sopenharmony_cimpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) 95562306a36Sopenharmony_ci{ 95662306a36Sopenharmony_ci u32 mf_dma_addr; 95762306a36Sopenharmony_ci int req_offset; 95862306a36Sopenharmony_ci u16 req_idx; /* Request index */ 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci /* ensure values are reset properly! */ 96162306a36Sopenharmony_ci mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */ 96262306a36Sopenharmony_ci req_offset = (u8 *)mf - (u8 *)ioc->req_frames; 96362306a36Sopenharmony_ci /* u16! */ 96462306a36Sopenharmony_ci req_idx = req_offset / ioc->req_sz; 96562306a36Sopenharmony_ci mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); 96662306a36Sopenharmony_ci mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx]; 97162306a36Sopenharmony_ci dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d " 97262306a36Sopenharmony_ci "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, 97362306a36Sopenharmony_ci ioc->RequestNB[req_idx])); 97462306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr); 97562306a36Sopenharmony_ci} 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci/** 97862306a36Sopenharmony_ci * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame 97962306a36Sopenharmony_ci * @cb_idx: Handle of registered MPT protocol driver 98062306a36Sopenharmony_ci * @ioc: Pointer to MPT adapter structure 98162306a36Sopenharmony_ci * @mf: Pointer to MPT request frame 98262306a36Sopenharmony_ci * 98362306a36Sopenharmony_ci * Send a protocol-specific MPT request frame to an IOC using 98462306a36Sopenharmony_ci * hi-priority request queue. 98562306a36Sopenharmony_ci * 98662306a36Sopenharmony_ci * This routine posts an MPT request frame to the request post FIFO of a 98762306a36Sopenharmony_ci * specific MPT adapter. 98862306a36Sopenharmony_ci **/ 98962306a36Sopenharmony_civoid 99062306a36Sopenharmony_cimpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) 99162306a36Sopenharmony_ci{ 99262306a36Sopenharmony_ci u32 mf_dma_addr; 99362306a36Sopenharmony_ci int req_offset; 99462306a36Sopenharmony_ci u16 req_idx; /* Request index */ 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci /* ensure values are reset properly! */ 99762306a36Sopenharmony_ci mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; 99862306a36Sopenharmony_ci req_offset = (u8 *)mf - (u8 *)ioc->req_frames; 99962306a36Sopenharmony_ci req_idx = req_offset / ioc->req_sz; 100062306a36Sopenharmony_ci mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx); 100162306a36Sopenharmony_ci mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci mf_dma_addr = (ioc->req_frames_low_dma + req_offset); 100662306a36Sopenharmony_ci dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n", 100762306a36Sopenharmony_ci ioc->name, mf_dma_addr, req_idx)); 100862306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr); 100962306a36Sopenharmony_ci} 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 101262306a36Sopenharmony_ci/** 101362306a36Sopenharmony_ci * mpt_free_msg_frame - Place MPT request frame back on FreeQ. 101462306a36Sopenharmony_ci * @ioc: Pointer to MPT adapter structure 101562306a36Sopenharmony_ci * @mf: Pointer to MPT request frame 101662306a36Sopenharmony_ci * 101762306a36Sopenharmony_ci * This routine places a MPT request frame back on the MPT adapter's 101862306a36Sopenharmony_ci * FreeQ. 101962306a36Sopenharmony_ci */ 102062306a36Sopenharmony_civoid 102162306a36Sopenharmony_cimpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) 102262306a36Sopenharmony_ci{ 102362306a36Sopenharmony_ci unsigned long flags; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci /* Put Request back on FreeQ! */ 102662306a36Sopenharmony_ci spin_lock_irqsave(&ioc->FreeQlock, flags); 102762306a36Sopenharmony_ci if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf) 102862306a36Sopenharmony_ci goto out; 102962306a36Sopenharmony_ci /* signature to know if this mf is freed */ 103062306a36Sopenharmony_ci mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf); 103162306a36Sopenharmony_ci list_add(&mf->u.frame.linkage.list, &ioc->FreeQ); 103262306a36Sopenharmony_ci#ifdef MFCNT 103362306a36Sopenharmony_ci ioc->mfcnt--; 103462306a36Sopenharmony_ci#endif 103562306a36Sopenharmony_ci out: 103662306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->FreeQlock, flags); 103762306a36Sopenharmony_ci} 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 104062306a36Sopenharmony_ci/** 104162306a36Sopenharmony_ci * mpt_add_sge - Place a simple 32 bit SGE at address pAddr. 104262306a36Sopenharmony_ci * @pAddr: virtual address for SGE 104362306a36Sopenharmony_ci * @flagslength: SGE flags and data transfer length 104462306a36Sopenharmony_ci * @dma_addr: Physical address 104562306a36Sopenharmony_ci * 104662306a36Sopenharmony_ci * This routine places a MPT request frame back on the MPT adapter's 104762306a36Sopenharmony_ci * FreeQ. 104862306a36Sopenharmony_ci */ 104962306a36Sopenharmony_cistatic void 105062306a36Sopenharmony_cimpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr) 105162306a36Sopenharmony_ci{ 105262306a36Sopenharmony_ci SGESimple32_t *pSge = (SGESimple32_t *) pAddr; 105362306a36Sopenharmony_ci pSge->FlagsLength = cpu_to_le32(flagslength); 105462306a36Sopenharmony_ci pSge->Address = cpu_to_le32(dma_addr); 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci/** 105862306a36Sopenharmony_ci * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr. 105962306a36Sopenharmony_ci * @pAddr: virtual address for SGE 106062306a36Sopenharmony_ci * @flagslength: SGE flags and data transfer length 106162306a36Sopenharmony_ci * @dma_addr: Physical address 106262306a36Sopenharmony_ci * 106362306a36Sopenharmony_ci * This routine places a MPT request frame back on the MPT adapter's 106462306a36Sopenharmony_ci * FreeQ. 106562306a36Sopenharmony_ci **/ 106662306a36Sopenharmony_cistatic void 106762306a36Sopenharmony_cimpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr) 106862306a36Sopenharmony_ci{ 106962306a36Sopenharmony_ci SGESimple64_t *pSge = (SGESimple64_t *) pAddr; 107062306a36Sopenharmony_ci pSge->Address.Low = cpu_to_le32 107162306a36Sopenharmony_ci (lower_32_bits(dma_addr)); 107262306a36Sopenharmony_ci pSge->Address.High = cpu_to_le32 107362306a36Sopenharmony_ci (upper_32_bits(dma_addr)); 107462306a36Sopenharmony_ci pSge->FlagsLength = cpu_to_le32 107562306a36Sopenharmony_ci ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING)); 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci/** 107962306a36Sopenharmony_ci * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround). 108062306a36Sopenharmony_ci * @pAddr: virtual address for SGE 108162306a36Sopenharmony_ci * @flagslength: SGE flags and data transfer length 108262306a36Sopenharmony_ci * @dma_addr: Physical address 108362306a36Sopenharmony_ci * 108462306a36Sopenharmony_ci * This routine places a MPT request frame back on the MPT adapter's 108562306a36Sopenharmony_ci * FreeQ. 108662306a36Sopenharmony_ci **/ 108762306a36Sopenharmony_cistatic void 108862306a36Sopenharmony_cimpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci SGESimple64_t *pSge = (SGESimple64_t *) pAddr; 109162306a36Sopenharmony_ci u32 tmp; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci pSge->Address.Low = cpu_to_le32 109462306a36Sopenharmony_ci (lower_32_bits(dma_addr)); 109562306a36Sopenharmony_ci tmp = (u32)(upper_32_bits(dma_addr)); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci /* 109862306a36Sopenharmony_ci * 1078 errata workaround for the 36GB limitation 109962306a36Sopenharmony_ci */ 110062306a36Sopenharmony_ci if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) { 110162306a36Sopenharmony_ci flagslength |= 110262306a36Sopenharmony_ci MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS); 110362306a36Sopenharmony_ci tmp |= (1<<31); 110462306a36Sopenharmony_ci if (mpt_debug_level & MPT_DEBUG_36GB_MEM) 110562306a36Sopenharmony_ci printk(KERN_DEBUG "1078 P0M2 addressing for " 110662306a36Sopenharmony_ci "addr = 0x%llx len = %d\n", 110762306a36Sopenharmony_ci (unsigned long long)dma_addr, 110862306a36Sopenharmony_ci MPI_SGE_LENGTH(flagslength)); 110962306a36Sopenharmony_ci } 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci pSge->Address.High = cpu_to_le32(tmp); 111262306a36Sopenharmony_ci pSge->FlagsLength = cpu_to_le32( 111362306a36Sopenharmony_ci (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING)); 111462306a36Sopenharmony_ci} 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 111762306a36Sopenharmony_ci/** 111862306a36Sopenharmony_ci * mpt_add_chain - Place a 32 bit chain SGE at address pAddr. 111962306a36Sopenharmony_ci * @pAddr: virtual address for SGE 112062306a36Sopenharmony_ci * @next: nextChainOffset value (u32's) 112162306a36Sopenharmony_ci * @length: length of next SGL segment 112262306a36Sopenharmony_ci * @dma_addr: Physical address 112362306a36Sopenharmony_ci * 112462306a36Sopenharmony_ci */ 112562306a36Sopenharmony_cistatic void 112662306a36Sopenharmony_cimpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr) 112762306a36Sopenharmony_ci{ 112862306a36Sopenharmony_ci SGEChain32_t *pChain = (SGEChain32_t *) pAddr; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci pChain->Length = cpu_to_le16(length); 113162306a36Sopenharmony_ci pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT; 113262306a36Sopenharmony_ci pChain->NextChainOffset = next; 113362306a36Sopenharmony_ci pChain->Address = cpu_to_le32(dma_addr); 113462306a36Sopenharmony_ci} 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 113762306a36Sopenharmony_ci/** 113862306a36Sopenharmony_ci * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr. 113962306a36Sopenharmony_ci * @pAddr: virtual address for SGE 114062306a36Sopenharmony_ci * @next: nextChainOffset value (u32's) 114162306a36Sopenharmony_ci * @length: length of next SGL segment 114262306a36Sopenharmony_ci * @dma_addr: Physical address 114362306a36Sopenharmony_ci * 114462306a36Sopenharmony_ci */ 114562306a36Sopenharmony_cistatic void 114662306a36Sopenharmony_cimpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr) 114762306a36Sopenharmony_ci{ 114862306a36Sopenharmony_ci SGEChain64_t *pChain = (SGEChain64_t *) pAddr; 114962306a36Sopenharmony_ci u32 tmp = dma_addr & 0xFFFFFFFF; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci pChain->Length = cpu_to_le16(length); 115262306a36Sopenharmony_ci pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT | 115362306a36Sopenharmony_ci MPI_SGE_FLAGS_64_BIT_ADDRESSING); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci pChain->NextChainOffset = next; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci pChain->Address.Low = cpu_to_le32(tmp); 115862306a36Sopenharmony_ci tmp = (u32)(upper_32_bits(dma_addr)); 115962306a36Sopenharmony_ci pChain->Address.High = cpu_to_le32(tmp); 116062306a36Sopenharmony_ci} 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 116362306a36Sopenharmony_ci/** 116462306a36Sopenharmony_ci * mpt_send_handshake_request - Send MPT request via doorbell handshake method. 116562306a36Sopenharmony_ci * @cb_idx: Handle of registered MPT protocol driver 116662306a36Sopenharmony_ci * @ioc: Pointer to MPT adapter structure 116762306a36Sopenharmony_ci * @reqBytes: Size of the request in bytes 116862306a36Sopenharmony_ci * @req: Pointer to MPT request frame 116962306a36Sopenharmony_ci * @sleepFlag: Use schedule if CAN_SLEEP else use udelay. 117062306a36Sopenharmony_ci * 117162306a36Sopenharmony_ci * This routine is used exclusively to send MptScsiTaskMgmt 117262306a36Sopenharmony_ci * requests since they are required to be sent via doorbell handshake. 117362306a36Sopenharmony_ci * 117462306a36Sopenharmony_ci * NOTE: It is the callers responsibility to byte-swap fields in the 117562306a36Sopenharmony_ci * request which are greater than 1 byte in size. 117662306a36Sopenharmony_ci * 117762306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure. 117862306a36Sopenharmony_ci */ 117962306a36Sopenharmony_ciint 118062306a36Sopenharmony_cimpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag) 118162306a36Sopenharmony_ci{ 118262306a36Sopenharmony_ci int r = 0; 118362306a36Sopenharmony_ci u8 *req_as_bytes; 118462306a36Sopenharmony_ci int ii; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci /* State is known to be good upon entering 118762306a36Sopenharmony_ci * this function so issue the bus reset 118862306a36Sopenharmony_ci * request. 118962306a36Sopenharmony_ci */ 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci /* 119262306a36Sopenharmony_ci * Emulate what mpt_put_msg_frame() does /wrt to sanity 119362306a36Sopenharmony_ci * setting cb_idx/req_idx. But ONLY if this request 119462306a36Sopenharmony_ci * is in proper (pre-alloc'd) request buffer range... 119562306a36Sopenharmony_ci */ 119662306a36Sopenharmony_ci ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req); 119762306a36Sopenharmony_ci if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) { 119862306a36Sopenharmony_ci MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req; 119962306a36Sopenharmony_ci mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii); 120062306a36Sopenharmony_ci mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci /* Make sure there are no doorbells */ 120462306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->Doorbell, 120762306a36Sopenharmony_ci ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) | 120862306a36Sopenharmony_ci ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT))); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci /* Wait for IOC doorbell int */ 121162306a36Sopenharmony_ci if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) { 121262306a36Sopenharmony_ci return ii; 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci /* Read doorbell and check for active bit */ 121662306a36Sopenharmony_ci if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE)) 121762306a36Sopenharmony_ci return -5; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n", 122062306a36Sopenharmony_ci ioc->name, ii)); 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { 122562306a36Sopenharmony_ci return -2; 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci /* Send request via doorbell handshake */ 122962306a36Sopenharmony_ci req_as_bytes = (u8 *) req; 123062306a36Sopenharmony_ci for (ii = 0; ii < reqBytes/4; ii++) { 123162306a36Sopenharmony_ci u32 word; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci word = ((req_as_bytes[(ii*4) + 0] << 0) | 123462306a36Sopenharmony_ci (req_as_bytes[(ii*4) + 1] << 8) | 123562306a36Sopenharmony_ci (req_as_bytes[(ii*4) + 2] << 16) | 123662306a36Sopenharmony_ci (req_as_bytes[(ii*4) + 3] << 24)); 123762306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->Doorbell, word); 123862306a36Sopenharmony_ci if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { 123962306a36Sopenharmony_ci r = -3; 124062306a36Sopenharmony_ci break; 124162306a36Sopenharmony_ci } 124262306a36Sopenharmony_ci } 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0) 124562306a36Sopenharmony_ci r = 0; 124662306a36Sopenharmony_ci else 124762306a36Sopenharmony_ci r = -4; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci /* Make sure there are no doorbells */ 125062306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci return r; 125362306a36Sopenharmony_ci} 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 125662306a36Sopenharmony_ci/** 125762306a36Sopenharmony_ci * mpt_host_page_access_control - control the IOC's Host Page Buffer access 125862306a36Sopenharmony_ci * @ioc: Pointer to MPT adapter structure 125962306a36Sopenharmony_ci * @access_control_value: define bits below 126062306a36Sopenharmony_ci * @sleepFlag: Specifies whether the process can sleep 126162306a36Sopenharmony_ci * 126262306a36Sopenharmony_ci * Provides mechanism for the host driver to control the IOC's 126362306a36Sopenharmony_ci * Host Page Buffer access. 126462306a36Sopenharmony_ci * 126562306a36Sopenharmony_ci * Access Control Value - bits[15:12] 126662306a36Sopenharmony_ci * 0h Reserved 126762306a36Sopenharmony_ci * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS } 126862306a36Sopenharmony_ci * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS } 126962306a36Sopenharmony_ci * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER } 127062306a36Sopenharmony_ci * 127162306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure. 127262306a36Sopenharmony_ci */ 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_cistatic int 127562306a36Sopenharmony_cimpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag) 127662306a36Sopenharmony_ci{ 127762306a36Sopenharmony_ci /* return if in use */ 127862306a36Sopenharmony_ci if (CHIPREG_READ32(&ioc->chip->Doorbell) 127962306a36Sopenharmony_ci & MPI_DOORBELL_ACTIVE) 128062306a36Sopenharmony_ci return -1; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->Doorbell, 128562306a36Sopenharmony_ci ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL 128662306a36Sopenharmony_ci <<MPI_DOORBELL_FUNCTION_SHIFT) | 128762306a36Sopenharmony_ci (access_control_value<<12))); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci /* Wait for IOC to clear Doorbell Status bit */ 129062306a36Sopenharmony_ci if (WaitForDoorbellAck(ioc, 5, sleepFlag) < 0) 129162306a36Sopenharmony_ci return -2; 129262306a36Sopenharmony_ci else 129362306a36Sopenharmony_ci return 0; 129462306a36Sopenharmony_ci} 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 129762306a36Sopenharmony_ci/** 129862306a36Sopenharmony_ci * mpt_host_page_alloc - allocate system memory for the fw 129962306a36Sopenharmony_ci * @ioc: Pointer to pointer to IOC adapter 130062306a36Sopenharmony_ci * @ioc_init: Pointer to ioc init config page 130162306a36Sopenharmony_ci * 130262306a36Sopenharmony_ci * If we already allocated memory in past, then resend the same pointer. 130362306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure. 130462306a36Sopenharmony_ci */ 130562306a36Sopenharmony_cistatic int 130662306a36Sopenharmony_cimpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init) 130762306a36Sopenharmony_ci{ 130862306a36Sopenharmony_ci char *psge; 130962306a36Sopenharmony_ci int flags_length; 131062306a36Sopenharmony_ci u32 host_page_buffer_sz=0; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci if(!ioc->HostPageBuffer) { 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci host_page_buffer_sz = 131562306a36Sopenharmony_ci le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci if(!host_page_buffer_sz) 131862306a36Sopenharmony_ci return 0; /* fw doesn't need any host buffers */ 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci /* spin till we get enough memory */ 132162306a36Sopenharmony_ci while (host_page_buffer_sz > 0) { 132262306a36Sopenharmony_ci ioc->HostPageBuffer = 132362306a36Sopenharmony_ci dma_alloc_coherent(&ioc->pcidev->dev, 132462306a36Sopenharmony_ci host_page_buffer_sz, 132562306a36Sopenharmony_ci &ioc->HostPageBuffer_dma, 132662306a36Sopenharmony_ci GFP_KERNEL); 132762306a36Sopenharmony_ci if (ioc->HostPageBuffer) { 132862306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT 132962306a36Sopenharmony_ci "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n", 133062306a36Sopenharmony_ci ioc->name, ioc->HostPageBuffer, 133162306a36Sopenharmony_ci (u32)ioc->HostPageBuffer_dma, 133262306a36Sopenharmony_ci host_page_buffer_sz)); 133362306a36Sopenharmony_ci ioc->alloc_total += host_page_buffer_sz; 133462306a36Sopenharmony_ci ioc->HostPageBuffer_sz = host_page_buffer_sz; 133562306a36Sopenharmony_ci break; 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci host_page_buffer_sz -= (4*1024); 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci } 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci if(!ioc->HostPageBuffer) { 134362306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT 134462306a36Sopenharmony_ci "Failed to alloc memory for host_page_buffer!\n", 134562306a36Sopenharmony_ci ioc->name); 134662306a36Sopenharmony_ci return -999; 134762306a36Sopenharmony_ci } 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci psge = (char *)&ioc_init->HostPageBufferSGE; 135062306a36Sopenharmony_ci flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT | 135162306a36Sopenharmony_ci MPI_SGE_FLAGS_SYSTEM_ADDRESS | 135262306a36Sopenharmony_ci MPI_SGE_FLAGS_HOST_TO_IOC | 135362306a36Sopenharmony_ci MPI_SGE_FLAGS_END_OF_BUFFER; 135462306a36Sopenharmony_ci flags_length = flags_length << MPI_SGE_FLAGS_SHIFT; 135562306a36Sopenharmony_ci flags_length |= ioc->HostPageBuffer_sz; 135662306a36Sopenharmony_ci ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma); 135762306a36Sopenharmony_ci ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci return 0; 136062306a36Sopenharmony_ci} 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 136362306a36Sopenharmony_ci/** 136462306a36Sopenharmony_ci * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure. 136562306a36Sopenharmony_ci * @iocid: IOC unique identifier (integer) 136662306a36Sopenharmony_ci * @iocpp: Pointer to pointer to IOC adapter 136762306a36Sopenharmony_ci * 136862306a36Sopenharmony_ci * Given a unique IOC identifier, set pointer to the associated MPT 136962306a36Sopenharmony_ci * adapter structure. 137062306a36Sopenharmony_ci * 137162306a36Sopenharmony_ci * Returns iocid and sets iocpp if iocid is found. 137262306a36Sopenharmony_ci * Returns -1 if iocid is not found. 137362306a36Sopenharmony_ci */ 137462306a36Sopenharmony_ciint 137562306a36Sopenharmony_cimpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp) 137662306a36Sopenharmony_ci{ 137762306a36Sopenharmony_ci MPT_ADAPTER *ioc; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci list_for_each_entry(ioc,&ioc_list,list) { 138062306a36Sopenharmony_ci if (ioc->id == iocid) { 138162306a36Sopenharmony_ci *iocpp =ioc; 138262306a36Sopenharmony_ci return iocid; 138362306a36Sopenharmony_ci } 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci *iocpp = NULL; 138762306a36Sopenharmony_ci return -1; 138862306a36Sopenharmony_ci} 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci/** 139162306a36Sopenharmony_ci * mpt_get_product_name - returns product string 139262306a36Sopenharmony_ci * @vendor: pci vendor id 139362306a36Sopenharmony_ci * @device: pci device id 139462306a36Sopenharmony_ci * @revision: pci revision id 139562306a36Sopenharmony_ci * 139662306a36Sopenharmony_ci * Returns product string displayed when driver loads, 139762306a36Sopenharmony_ci * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product 139862306a36Sopenharmony_ci * 139962306a36Sopenharmony_ci **/ 140062306a36Sopenharmony_cistatic const char* 140162306a36Sopenharmony_cimpt_get_product_name(u16 vendor, u16 device, u8 revision) 140262306a36Sopenharmony_ci{ 140362306a36Sopenharmony_ci char *product_str = NULL; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci if (vendor == PCI_VENDOR_ID_BROCADE) { 140662306a36Sopenharmony_ci switch (device) 140762306a36Sopenharmony_ci { 140862306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVICEID_FC949E: 140962306a36Sopenharmony_ci switch (revision) 141062306a36Sopenharmony_ci { 141162306a36Sopenharmony_ci case 0x00: 141262306a36Sopenharmony_ci product_str = "BRE040 A0"; 141362306a36Sopenharmony_ci break; 141462306a36Sopenharmony_ci case 0x01: 141562306a36Sopenharmony_ci product_str = "BRE040 A1"; 141662306a36Sopenharmony_ci break; 141762306a36Sopenharmony_ci default: 141862306a36Sopenharmony_ci product_str = "BRE040"; 141962306a36Sopenharmony_ci break; 142062306a36Sopenharmony_ci } 142162306a36Sopenharmony_ci break; 142262306a36Sopenharmony_ci } 142362306a36Sopenharmony_ci goto out; 142462306a36Sopenharmony_ci } 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci switch (device) 142762306a36Sopenharmony_ci { 142862306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVICEID_FC909: 142962306a36Sopenharmony_ci product_str = "LSIFC909 B1"; 143062306a36Sopenharmony_ci break; 143162306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVICEID_FC919: 143262306a36Sopenharmony_ci product_str = "LSIFC919 B0"; 143362306a36Sopenharmony_ci break; 143462306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVICEID_FC929: 143562306a36Sopenharmony_ci product_str = "LSIFC929 B0"; 143662306a36Sopenharmony_ci break; 143762306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVICEID_FC919X: 143862306a36Sopenharmony_ci if (revision < 0x80) 143962306a36Sopenharmony_ci product_str = "LSIFC919X A0"; 144062306a36Sopenharmony_ci else 144162306a36Sopenharmony_ci product_str = "LSIFC919XL A1"; 144262306a36Sopenharmony_ci break; 144362306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVICEID_FC929X: 144462306a36Sopenharmony_ci if (revision < 0x80) 144562306a36Sopenharmony_ci product_str = "LSIFC929X A0"; 144662306a36Sopenharmony_ci else 144762306a36Sopenharmony_ci product_str = "LSIFC929XL A1"; 144862306a36Sopenharmony_ci break; 144962306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVICEID_FC939X: 145062306a36Sopenharmony_ci product_str = "LSIFC939X A1"; 145162306a36Sopenharmony_ci break; 145262306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVICEID_FC949X: 145362306a36Sopenharmony_ci product_str = "LSIFC949X A1"; 145462306a36Sopenharmony_ci break; 145562306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVICEID_FC949E: 145662306a36Sopenharmony_ci switch (revision) 145762306a36Sopenharmony_ci { 145862306a36Sopenharmony_ci case 0x00: 145962306a36Sopenharmony_ci product_str = "LSIFC949E A0"; 146062306a36Sopenharmony_ci break; 146162306a36Sopenharmony_ci case 0x01: 146262306a36Sopenharmony_ci product_str = "LSIFC949E A1"; 146362306a36Sopenharmony_ci break; 146462306a36Sopenharmony_ci default: 146562306a36Sopenharmony_ci product_str = "LSIFC949E"; 146662306a36Sopenharmony_ci break; 146762306a36Sopenharmony_ci } 146862306a36Sopenharmony_ci break; 146962306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVID_53C1030: 147062306a36Sopenharmony_ci switch (revision) 147162306a36Sopenharmony_ci { 147262306a36Sopenharmony_ci case 0x00: 147362306a36Sopenharmony_ci product_str = "LSI53C1030 A0"; 147462306a36Sopenharmony_ci break; 147562306a36Sopenharmony_ci case 0x01: 147662306a36Sopenharmony_ci product_str = "LSI53C1030 B0"; 147762306a36Sopenharmony_ci break; 147862306a36Sopenharmony_ci case 0x03: 147962306a36Sopenharmony_ci product_str = "LSI53C1030 B1"; 148062306a36Sopenharmony_ci break; 148162306a36Sopenharmony_ci case 0x07: 148262306a36Sopenharmony_ci product_str = "LSI53C1030 B2"; 148362306a36Sopenharmony_ci break; 148462306a36Sopenharmony_ci case 0x08: 148562306a36Sopenharmony_ci product_str = "LSI53C1030 C0"; 148662306a36Sopenharmony_ci break; 148762306a36Sopenharmony_ci case 0x80: 148862306a36Sopenharmony_ci product_str = "LSI53C1030T A0"; 148962306a36Sopenharmony_ci break; 149062306a36Sopenharmony_ci case 0x83: 149162306a36Sopenharmony_ci product_str = "LSI53C1030T A2"; 149262306a36Sopenharmony_ci break; 149362306a36Sopenharmony_ci case 0x87: 149462306a36Sopenharmony_ci product_str = "LSI53C1030T A3"; 149562306a36Sopenharmony_ci break; 149662306a36Sopenharmony_ci case 0xc1: 149762306a36Sopenharmony_ci product_str = "LSI53C1020A A1"; 149862306a36Sopenharmony_ci break; 149962306a36Sopenharmony_ci default: 150062306a36Sopenharmony_ci product_str = "LSI53C1030"; 150162306a36Sopenharmony_ci break; 150262306a36Sopenharmony_ci } 150362306a36Sopenharmony_ci break; 150462306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVID_1030_53C1035: 150562306a36Sopenharmony_ci switch (revision) 150662306a36Sopenharmony_ci { 150762306a36Sopenharmony_ci case 0x03: 150862306a36Sopenharmony_ci product_str = "LSI53C1035 A2"; 150962306a36Sopenharmony_ci break; 151062306a36Sopenharmony_ci case 0x04: 151162306a36Sopenharmony_ci product_str = "LSI53C1035 B0"; 151262306a36Sopenharmony_ci break; 151362306a36Sopenharmony_ci default: 151462306a36Sopenharmony_ci product_str = "LSI53C1035"; 151562306a36Sopenharmony_ci break; 151662306a36Sopenharmony_ci } 151762306a36Sopenharmony_ci break; 151862306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVID_SAS1064: 151962306a36Sopenharmony_ci switch (revision) 152062306a36Sopenharmony_ci { 152162306a36Sopenharmony_ci case 0x00: 152262306a36Sopenharmony_ci product_str = "LSISAS1064 A1"; 152362306a36Sopenharmony_ci break; 152462306a36Sopenharmony_ci case 0x01: 152562306a36Sopenharmony_ci product_str = "LSISAS1064 A2"; 152662306a36Sopenharmony_ci break; 152762306a36Sopenharmony_ci case 0x02: 152862306a36Sopenharmony_ci product_str = "LSISAS1064 A3"; 152962306a36Sopenharmony_ci break; 153062306a36Sopenharmony_ci case 0x03: 153162306a36Sopenharmony_ci product_str = "LSISAS1064 A4"; 153262306a36Sopenharmony_ci break; 153362306a36Sopenharmony_ci default: 153462306a36Sopenharmony_ci product_str = "LSISAS1064"; 153562306a36Sopenharmony_ci break; 153662306a36Sopenharmony_ci } 153762306a36Sopenharmony_ci break; 153862306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVID_SAS1064E: 153962306a36Sopenharmony_ci switch (revision) 154062306a36Sopenharmony_ci { 154162306a36Sopenharmony_ci case 0x00: 154262306a36Sopenharmony_ci product_str = "LSISAS1064E A0"; 154362306a36Sopenharmony_ci break; 154462306a36Sopenharmony_ci case 0x01: 154562306a36Sopenharmony_ci product_str = "LSISAS1064E B0"; 154662306a36Sopenharmony_ci break; 154762306a36Sopenharmony_ci case 0x02: 154862306a36Sopenharmony_ci product_str = "LSISAS1064E B1"; 154962306a36Sopenharmony_ci break; 155062306a36Sopenharmony_ci case 0x04: 155162306a36Sopenharmony_ci product_str = "LSISAS1064E B2"; 155262306a36Sopenharmony_ci break; 155362306a36Sopenharmony_ci case 0x08: 155462306a36Sopenharmony_ci product_str = "LSISAS1064E B3"; 155562306a36Sopenharmony_ci break; 155662306a36Sopenharmony_ci default: 155762306a36Sopenharmony_ci product_str = "LSISAS1064E"; 155862306a36Sopenharmony_ci break; 155962306a36Sopenharmony_ci } 156062306a36Sopenharmony_ci break; 156162306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVID_SAS1068: 156262306a36Sopenharmony_ci switch (revision) 156362306a36Sopenharmony_ci { 156462306a36Sopenharmony_ci case 0x00: 156562306a36Sopenharmony_ci product_str = "LSISAS1068 A0"; 156662306a36Sopenharmony_ci break; 156762306a36Sopenharmony_ci case 0x01: 156862306a36Sopenharmony_ci product_str = "LSISAS1068 B0"; 156962306a36Sopenharmony_ci break; 157062306a36Sopenharmony_ci case 0x02: 157162306a36Sopenharmony_ci product_str = "LSISAS1068 B1"; 157262306a36Sopenharmony_ci break; 157362306a36Sopenharmony_ci default: 157462306a36Sopenharmony_ci product_str = "LSISAS1068"; 157562306a36Sopenharmony_ci break; 157662306a36Sopenharmony_ci } 157762306a36Sopenharmony_ci break; 157862306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVID_SAS1068E: 157962306a36Sopenharmony_ci switch (revision) 158062306a36Sopenharmony_ci { 158162306a36Sopenharmony_ci case 0x00: 158262306a36Sopenharmony_ci product_str = "LSISAS1068E A0"; 158362306a36Sopenharmony_ci break; 158462306a36Sopenharmony_ci case 0x01: 158562306a36Sopenharmony_ci product_str = "LSISAS1068E B0"; 158662306a36Sopenharmony_ci break; 158762306a36Sopenharmony_ci case 0x02: 158862306a36Sopenharmony_ci product_str = "LSISAS1068E B1"; 158962306a36Sopenharmony_ci break; 159062306a36Sopenharmony_ci case 0x04: 159162306a36Sopenharmony_ci product_str = "LSISAS1068E B2"; 159262306a36Sopenharmony_ci break; 159362306a36Sopenharmony_ci case 0x08: 159462306a36Sopenharmony_ci product_str = "LSISAS1068E B3"; 159562306a36Sopenharmony_ci break; 159662306a36Sopenharmony_ci default: 159762306a36Sopenharmony_ci product_str = "LSISAS1068E"; 159862306a36Sopenharmony_ci break; 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci break; 160162306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVID_SAS1078: 160262306a36Sopenharmony_ci switch (revision) 160362306a36Sopenharmony_ci { 160462306a36Sopenharmony_ci case 0x00: 160562306a36Sopenharmony_ci product_str = "LSISAS1078 A0"; 160662306a36Sopenharmony_ci break; 160762306a36Sopenharmony_ci case 0x01: 160862306a36Sopenharmony_ci product_str = "LSISAS1078 B0"; 160962306a36Sopenharmony_ci break; 161062306a36Sopenharmony_ci case 0x02: 161162306a36Sopenharmony_ci product_str = "LSISAS1078 C0"; 161262306a36Sopenharmony_ci break; 161362306a36Sopenharmony_ci case 0x03: 161462306a36Sopenharmony_ci product_str = "LSISAS1078 C1"; 161562306a36Sopenharmony_ci break; 161662306a36Sopenharmony_ci case 0x04: 161762306a36Sopenharmony_ci product_str = "LSISAS1078 C2"; 161862306a36Sopenharmony_ci break; 161962306a36Sopenharmony_ci default: 162062306a36Sopenharmony_ci product_str = "LSISAS1078"; 162162306a36Sopenharmony_ci break; 162262306a36Sopenharmony_ci } 162362306a36Sopenharmony_ci break; 162462306a36Sopenharmony_ci } 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci out: 162762306a36Sopenharmony_ci return product_str; 162862306a36Sopenharmony_ci} 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci/** 163162306a36Sopenharmony_ci * mpt_mapresources - map in memory mapped io 163262306a36Sopenharmony_ci * @ioc: Pointer to pointer to IOC adapter 163362306a36Sopenharmony_ci * 163462306a36Sopenharmony_ci **/ 163562306a36Sopenharmony_cistatic int 163662306a36Sopenharmony_cimpt_mapresources(MPT_ADAPTER *ioc) 163762306a36Sopenharmony_ci{ 163862306a36Sopenharmony_ci u8 __iomem *mem; 163962306a36Sopenharmony_ci int ii; 164062306a36Sopenharmony_ci resource_size_t mem_phys; 164162306a36Sopenharmony_ci unsigned long port; 164262306a36Sopenharmony_ci u32 msize; 164362306a36Sopenharmony_ci u32 psize; 164462306a36Sopenharmony_ci int r = -ENODEV; 164562306a36Sopenharmony_ci struct pci_dev *pdev; 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci pdev = ioc->pcidev; 164862306a36Sopenharmony_ci ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); 164962306a36Sopenharmony_ci if (pci_enable_device_mem(pdev)) { 165062306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() " 165162306a36Sopenharmony_ci "failed\n", ioc->name); 165262306a36Sopenharmony_ci return r; 165362306a36Sopenharmony_ci } 165462306a36Sopenharmony_ci if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) { 165562306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with " 165662306a36Sopenharmony_ci "MEM failed\n", ioc->name); 165762306a36Sopenharmony_ci goto out_pci_disable_device; 165862306a36Sopenharmony_ci } 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci if (sizeof(dma_addr_t) > 4) { 166162306a36Sopenharmony_ci const uint64_t required_mask = dma_get_required_mask 166262306a36Sopenharmony_ci (&pdev->dev); 166362306a36Sopenharmony_ci if (required_mask > DMA_BIT_MASK(32) 166462306a36Sopenharmony_ci && !dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) 166562306a36Sopenharmony_ci && !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) { 166662306a36Sopenharmony_ci ioc->dma_mask = DMA_BIT_MASK(64); 166762306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_INFO_FMT 166862306a36Sopenharmony_ci ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", 166962306a36Sopenharmony_ci ioc->name)); 167062306a36Sopenharmony_ci } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)) 167162306a36Sopenharmony_ci && !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32))) { 167262306a36Sopenharmony_ci ioc->dma_mask = DMA_BIT_MASK(32); 167362306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_INFO_FMT 167462306a36Sopenharmony_ci ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", 167562306a36Sopenharmony_ci ioc->name)); 167662306a36Sopenharmony_ci } else { 167762306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", 167862306a36Sopenharmony_ci ioc->name, pci_name(pdev)); 167962306a36Sopenharmony_ci goto out_pci_release_region; 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci } else { 168262306a36Sopenharmony_ci if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)) 168362306a36Sopenharmony_ci && !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32))) { 168462306a36Sopenharmony_ci ioc->dma_mask = DMA_BIT_MASK(32); 168562306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_INFO_FMT 168662306a36Sopenharmony_ci ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", 168762306a36Sopenharmony_ci ioc->name)); 168862306a36Sopenharmony_ci } else { 168962306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", 169062306a36Sopenharmony_ci ioc->name, pci_name(pdev)); 169162306a36Sopenharmony_ci goto out_pci_release_region; 169262306a36Sopenharmony_ci } 169362306a36Sopenharmony_ci } 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci mem_phys = msize = 0; 169662306a36Sopenharmony_ci port = psize = 0; 169762306a36Sopenharmony_ci for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) { 169862306a36Sopenharmony_ci if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) { 169962306a36Sopenharmony_ci if (psize) 170062306a36Sopenharmony_ci continue; 170162306a36Sopenharmony_ci /* Get I/O space! */ 170262306a36Sopenharmony_ci port = pci_resource_start(pdev, ii); 170362306a36Sopenharmony_ci psize = pci_resource_len(pdev, ii); 170462306a36Sopenharmony_ci } else { 170562306a36Sopenharmony_ci if (msize) 170662306a36Sopenharmony_ci continue; 170762306a36Sopenharmony_ci /* Get memmap */ 170862306a36Sopenharmony_ci mem_phys = pci_resource_start(pdev, ii); 170962306a36Sopenharmony_ci msize = pci_resource_len(pdev, ii); 171062306a36Sopenharmony_ci } 171162306a36Sopenharmony_ci } 171262306a36Sopenharmony_ci ioc->mem_size = msize; 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci mem = NULL; 171562306a36Sopenharmony_ci /* Get logical ptr for PciMem0 space */ 171662306a36Sopenharmony_ci /*mem = ioremap(mem_phys, msize);*/ 171762306a36Sopenharmony_ci mem = ioremap(mem_phys, msize); 171862306a36Sopenharmony_ci if (mem == NULL) { 171962306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter" 172062306a36Sopenharmony_ci " memory!\n", ioc->name); 172162306a36Sopenharmony_ci r = -EINVAL; 172262306a36Sopenharmony_ci goto out_pci_release_region; 172362306a36Sopenharmony_ci } 172462306a36Sopenharmony_ci ioc->memmap = mem; 172562306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %llx\n", 172662306a36Sopenharmony_ci ioc->name, mem, (unsigned long long)mem_phys)); 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci ioc->mem_phys = mem_phys; 172962306a36Sopenharmony_ci ioc->chip = (SYSIF_REGS __iomem *)mem; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci /* Save Port IO values in case we need to do downloadboot */ 173262306a36Sopenharmony_ci ioc->pio_mem_phys = port; 173362306a36Sopenharmony_ci ioc->pio_chip = (SYSIF_REGS __iomem *)port; 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci return 0; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ciout_pci_release_region: 173862306a36Sopenharmony_ci pci_release_selected_regions(pdev, ioc->bars); 173962306a36Sopenharmony_ciout_pci_disable_device: 174062306a36Sopenharmony_ci pci_disable_device(pdev); 174162306a36Sopenharmony_ci return r; 174262306a36Sopenharmony_ci} 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 174562306a36Sopenharmony_ci/** 174662306a36Sopenharmony_ci * mpt_attach - Install a PCI intelligent MPT adapter. 174762306a36Sopenharmony_ci * @pdev: Pointer to pci_dev structure 174862306a36Sopenharmony_ci * @id: PCI device ID information 174962306a36Sopenharmony_ci * 175062306a36Sopenharmony_ci * This routine performs all the steps necessary to bring the IOC of 175162306a36Sopenharmony_ci * a MPT adapter to a OPERATIONAL state. This includes registering 175262306a36Sopenharmony_ci * memory regions, registering the interrupt, and allocating request 175362306a36Sopenharmony_ci * and reply memory pools. 175462306a36Sopenharmony_ci * 175562306a36Sopenharmony_ci * This routine also pre-fetches the LAN MAC address of a Fibre Channel 175662306a36Sopenharmony_ci * MPT adapter. 175762306a36Sopenharmony_ci * 175862306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure. 175962306a36Sopenharmony_ci * 176062306a36Sopenharmony_ci * TODO: Add support for polled controllers 176162306a36Sopenharmony_ci */ 176262306a36Sopenharmony_ciint 176362306a36Sopenharmony_cimpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) 176462306a36Sopenharmony_ci{ 176562306a36Sopenharmony_ci MPT_ADAPTER *ioc; 176662306a36Sopenharmony_ci u8 cb_idx; 176762306a36Sopenharmony_ci int r = -ENODEV; 176862306a36Sopenharmony_ci u8 pcixcmd; 176962306a36Sopenharmony_ci static int mpt_ids = 0; 177062306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 177162306a36Sopenharmony_ci struct proc_dir_entry *dent; 177262306a36Sopenharmony_ci#endif 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_KERNEL); 177562306a36Sopenharmony_ci if (ioc == NULL) { 177662306a36Sopenharmony_ci printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n"); 177762306a36Sopenharmony_ci return -ENOMEM; 177862306a36Sopenharmony_ci } 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci ioc->id = mpt_ids++; 178162306a36Sopenharmony_ci sprintf(ioc->name, "ioc%d", ioc->id); 178262306a36Sopenharmony_ci dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n")); 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci /* 178562306a36Sopenharmony_ci * set initial debug level 178662306a36Sopenharmony_ci * (refer to mptdebug.h) 178762306a36Sopenharmony_ci * 178862306a36Sopenharmony_ci */ 178962306a36Sopenharmony_ci ioc->debug_level = mpt_debug_level; 179062306a36Sopenharmony_ci if (mpt_debug_level) 179162306a36Sopenharmony_ci printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level); 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name)); 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci ioc->pcidev = pdev; 179662306a36Sopenharmony_ci if (mpt_mapresources(ioc)) { 179762306a36Sopenharmony_ci goto out_free_ioc; 179862306a36Sopenharmony_ci } 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci /* 180162306a36Sopenharmony_ci * Setting up proper handlers for scatter gather handling 180262306a36Sopenharmony_ci */ 180362306a36Sopenharmony_ci if (ioc->dma_mask == DMA_BIT_MASK(64)) { 180462306a36Sopenharmony_ci if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) 180562306a36Sopenharmony_ci ioc->add_sge = &mpt_add_sge_64bit_1078; 180662306a36Sopenharmony_ci else 180762306a36Sopenharmony_ci ioc->add_sge = &mpt_add_sge_64bit; 180862306a36Sopenharmony_ci ioc->add_chain = &mpt_add_chain_64bit; 180962306a36Sopenharmony_ci ioc->sg_addr_size = 8; 181062306a36Sopenharmony_ci } else { 181162306a36Sopenharmony_ci ioc->add_sge = &mpt_add_sge; 181262306a36Sopenharmony_ci ioc->add_chain = &mpt_add_chain; 181362306a36Sopenharmony_ci ioc->sg_addr_size = 4; 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size; 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci ioc->alloc_total = sizeof(MPT_ADAPTER); 181862306a36Sopenharmony_ci ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */ 181962306a36Sopenharmony_ci ioc->reply_sz = MPT_REPLY_FRAME_SIZE; 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci spin_lock_init(&ioc->taskmgmt_lock); 182362306a36Sopenharmony_ci mutex_init(&ioc->internal_cmds.mutex); 182462306a36Sopenharmony_ci init_completion(&ioc->internal_cmds.done); 182562306a36Sopenharmony_ci mutex_init(&ioc->mptbase_cmds.mutex); 182662306a36Sopenharmony_ci init_completion(&ioc->mptbase_cmds.done); 182762306a36Sopenharmony_ci mutex_init(&ioc->taskmgmt_cmds.mutex); 182862306a36Sopenharmony_ci init_completion(&ioc->taskmgmt_cmds.done); 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci /* Initialize the event logging. 183162306a36Sopenharmony_ci */ 183262306a36Sopenharmony_ci ioc->eventTypes = 0; /* None */ 183362306a36Sopenharmony_ci ioc->eventContext = 0; 183462306a36Sopenharmony_ci ioc->eventLogSize = 0; 183562306a36Sopenharmony_ci ioc->events = NULL; 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci#ifdef MFCNT 183862306a36Sopenharmony_ci ioc->mfcnt = 0; 183962306a36Sopenharmony_ci#endif 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci ioc->sh = NULL; 184262306a36Sopenharmony_ci ioc->cached_fw = NULL; 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci /* Initialize SCSI Config Data structure 184562306a36Sopenharmony_ci */ 184662306a36Sopenharmony_ci memset(&ioc->spi_data, 0, sizeof(SpiCfgData)); 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci /* Initialize the fc rport list head. 184962306a36Sopenharmony_ci */ 185062306a36Sopenharmony_ci INIT_LIST_HEAD(&ioc->fc_rports); 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci /* Find lookup slot. */ 185362306a36Sopenharmony_ci INIT_LIST_HEAD(&ioc->list); 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci /* Initialize workqueue */ 185762306a36Sopenharmony_ci INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work); 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN, 186062306a36Sopenharmony_ci "mpt_poll_%d", ioc->id); 186162306a36Sopenharmony_ci ioc->reset_work_q = alloc_workqueue(ioc->reset_work_q_name, 186262306a36Sopenharmony_ci WQ_MEM_RECLAIM, 0); 186362306a36Sopenharmony_ci if (!ioc->reset_work_q) { 186462306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n", 186562306a36Sopenharmony_ci ioc->name); 186662306a36Sopenharmony_ci r = -ENOMEM; 186762306a36Sopenharmony_ci goto out_unmap_resources; 186862306a36Sopenharmony_ci } 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n", 187162306a36Sopenharmony_ci ioc->name, &ioc->facts, &ioc->pfacts[0])); 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci ioc->prod_name = mpt_get_product_name(pdev->vendor, pdev->device, 187462306a36Sopenharmony_ci pdev->revision); 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci switch (pdev->device) 187762306a36Sopenharmony_ci { 187862306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVICEID_FC939X: 187962306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVICEID_FC949X: 188062306a36Sopenharmony_ci ioc->errata_flag_1064 = 1; 188162306a36Sopenharmony_ci fallthrough; 188262306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVICEID_FC909: 188362306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVICEID_FC929: 188462306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVICEID_FC919: 188562306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVICEID_FC949E: 188662306a36Sopenharmony_ci ioc->bus_type = FC; 188762306a36Sopenharmony_ci break; 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVICEID_FC929X: 189062306a36Sopenharmony_ci if (pdev->revision < XL_929) { 189162306a36Sopenharmony_ci /* 929X Chip Fix. Set Split transactions level 189262306a36Sopenharmony_ci * for PCIX. Set MOST bits to zero. 189362306a36Sopenharmony_ci */ 189462306a36Sopenharmony_ci pci_read_config_byte(pdev, 0x6a, &pcixcmd); 189562306a36Sopenharmony_ci pcixcmd &= 0x8F; 189662306a36Sopenharmony_ci pci_write_config_byte(pdev, 0x6a, pcixcmd); 189762306a36Sopenharmony_ci } else { 189862306a36Sopenharmony_ci /* 929XL Chip Fix. Set MMRBC to 0x08. 189962306a36Sopenharmony_ci */ 190062306a36Sopenharmony_ci pci_read_config_byte(pdev, 0x6a, &pcixcmd); 190162306a36Sopenharmony_ci pcixcmd |= 0x08; 190262306a36Sopenharmony_ci pci_write_config_byte(pdev, 0x6a, pcixcmd); 190362306a36Sopenharmony_ci } 190462306a36Sopenharmony_ci ioc->bus_type = FC; 190562306a36Sopenharmony_ci break; 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVICEID_FC919X: 190862306a36Sopenharmony_ci /* 919X Chip Fix. Set Split transactions level 190962306a36Sopenharmony_ci * for PCIX. Set MOST bits to zero. 191062306a36Sopenharmony_ci */ 191162306a36Sopenharmony_ci pci_read_config_byte(pdev, 0x6a, &pcixcmd); 191262306a36Sopenharmony_ci pcixcmd &= 0x8F; 191362306a36Sopenharmony_ci pci_write_config_byte(pdev, 0x6a, pcixcmd); 191462306a36Sopenharmony_ci ioc->bus_type = FC; 191562306a36Sopenharmony_ci break; 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVID_53C1030: 191862306a36Sopenharmony_ci /* 1030 Chip Fix. Disable Split transactions 191962306a36Sopenharmony_ci * for PCIX. Set MOST bits to zero if Rev < C0( = 8). 192062306a36Sopenharmony_ci */ 192162306a36Sopenharmony_ci if (pdev->revision < C0_1030) { 192262306a36Sopenharmony_ci pci_read_config_byte(pdev, 0x6a, &pcixcmd); 192362306a36Sopenharmony_ci pcixcmd &= 0x8F; 192462306a36Sopenharmony_ci pci_write_config_byte(pdev, 0x6a, pcixcmd); 192562306a36Sopenharmony_ci } 192662306a36Sopenharmony_ci fallthrough; 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVID_1030_53C1035: 192962306a36Sopenharmony_ci ioc->bus_type = SPI; 193062306a36Sopenharmony_ci break; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVID_SAS1064: 193362306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVID_SAS1068: 193462306a36Sopenharmony_ci ioc->errata_flag_1064 = 1; 193562306a36Sopenharmony_ci ioc->bus_type = SAS; 193662306a36Sopenharmony_ci break; 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVID_SAS1064E: 193962306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVID_SAS1068E: 194062306a36Sopenharmony_ci case MPI_MANUFACTPAGE_DEVID_SAS1078: 194162306a36Sopenharmony_ci ioc->bus_type = SAS; 194262306a36Sopenharmony_ci break; 194362306a36Sopenharmony_ci } 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci switch (ioc->bus_type) { 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci case SAS: 194962306a36Sopenharmony_ci ioc->msi_enable = mpt_msi_enable_sas; 195062306a36Sopenharmony_ci break; 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci case SPI: 195362306a36Sopenharmony_ci ioc->msi_enable = mpt_msi_enable_spi; 195462306a36Sopenharmony_ci break; 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci case FC: 195762306a36Sopenharmony_ci ioc->msi_enable = mpt_msi_enable_fc; 195862306a36Sopenharmony_ci break; 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci default: 196162306a36Sopenharmony_ci ioc->msi_enable = 0; 196262306a36Sopenharmony_ci break; 196362306a36Sopenharmony_ci } 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci ioc->fw_events_off = 1; 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci if (ioc->errata_flag_1064) 196862306a36Sopenharmony_ci pci_disable_io_access(pdev); 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci spin_lock_init(&ioc->FreeQlock); 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci /* Disable all! */ 197362306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); 197462306a36Sopenharmony_ci ioc->active = 0; 197562306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci /* Set IOC ptr in the pcidev's driver data. */ 197862306a36Sopenharmony_ci pci_set_drvdata(ioc->pcidev, ioc); 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci /* Set lookup ptr. */ 198162306a36Sopenharmony_ci list_add_tail(&ioc->list, &ioc_list); 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets. 198462306a36Sopenharmony_ci */ 198562306a36Sopenharmony_ci mpt_detect_bound_ports(ioc, pdev); 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci INIT_LIST_HEAD(&ioc->fw_event_list); 198862306a36Sopenharmony_ci spin_lock_init(&ioc->fw_event_lock); 198962306a36Sopenharmony_ci snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id); 199062306a36Sopenharmony_ci ioc->fw_event_q = alloc_workqueue(ioc->fw_event_q_name, 199162306a36Sopenharmony_ci WQ_MEM_RECLAIM, 0); 199262306a36Sopenharmony_ci if (!ioc->fw_event_q) { 199362306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n", 199462306a36Sopenharmony_ci ioc->name); 199562306a36Sopenharmony_ci r = -ENOMEM; 199662306a36Sopenharmony_ci goto out_remove_ioc; 199762306a36Sopenharmony_ci } 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, 200062306a36Sopenharmony_ci CAN_SLEEP)) != 0){ 200162306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n", 200262306a36Sopenharmony_ci ioc->name, r); 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci destroy_workqueue(ioc->fw_event_q); 200562306a36Sopenharmony_ci ioc->fw_event_q = NULL; 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci list_del(&ioc->list); 200862306a36Sopenharmony_ci if (ioc->alt_ioc) 200962306a36Sopenharmony_ci ioc->alt_ioc->alt_ioc = NULL; 201062306a36Sopenharmony_ci iounmap(ioc->memmap); 201162306a36Sopenharmony_ci if (pci_is_enabled(pdev)) 201262306a36Sopenharmony_ci pci_disable_device(pdev); 201362306a36Sopenharmony_ci if (r != -5) 201462306a36Sopenharmony_ci pci_release_selected_regions(pdev, ioc->bars); 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ci destroy_workqueue(ioc->reset_work_q); 201762306a36Sopenharmony_ci ioc->reset_work_q = NULL; 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci kfree(ioc); 202062306a36Sopenharmony_ci return r; 202162306a36Sopenharmony_ci } 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci /* call per device driver probe entry point */ 202462306a36Sopenharmony_ci for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) { 202562306a36Sopenharmony_ci if(MptDeviceDriverHandlers[cb_idx] && 202662306a36Sopenharmony_ci MptDeviceDriverHandlers[cb_idx]->probe) { 202762306a36Sopenharmony_ci MptDeviceDriverHandlers[cb_idx]->probe(pdev); 202862306a36Sopenharmony_ci } 202962306a36Sopenharmony_ci } 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 203262306a36Sopenharmony_ci /* 203362306a36Sopenharmony_ci * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter. 203462306a36Sopenharmony_ci */ 203562306a36Sopenharmony_ci dent = proc_mkdir(ioc->name, mpt_proc_root_dir); 203662306a36Sopenharmony_ci if (dent) { 203762306a36Sopenharmony_ci proc_create_single_data("info", S_IRUGO, dent, 203862306a36Sopenharmony_ci mpt_iocinfo_proc_show, ioc); 203962306a36Sopenharmony_ci proc_create_single_data("summary", S_IRUGO, dent, 204062306a36Sopenharmony_ci mpt_summary_proc_show, ioc); 204162306a36Sopenharmony_ci } 204262306a36Sopenharmony_ci#endif 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_ci if (!ioc->alt_ioc) 204562306a36Sopenharmony_ci queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work, 204662306a36Sopenharmony_ci msecs_to_jiffies(MPT_POLLING_INTERVAL)); 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci return 0; 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ciout_remove_ioc: 205162306a36Sopenharmony_ci list_del(&ioc->list); 205262306a36Sopenharmony_ci if (ioc->alt_ioc) 205362306a36Sopenharmony_ci ioc->alt_ioc->alt_ioc = NULL; 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci destroy_workqueue(ioc->reset_work_q); 205662306a36Sopenharmony_ci ioc->reset_work_q = NULL; 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ciout_unmap_resources: 205962306a36Sopenharmony_ci iounmap(ioc->memmap); 206062306a36Sopenharmony_ci pci_disable_device(pdev); 206162306a36Sopenharmony_ci pci_release_selected_regions(pdev, ioc->bars); 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ciout_free_ioc: 206462306a36Sopenharmony_ci kfree(ioc); 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci return r; 206762306a36Sopenharmony_ci} 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 207062306a36Sopenharmony_ci/** 207162306a36Sopenharmony_ci * mpt_detach - Remove a PCI intelligent MPT adapter. 207262306a36Sopenharmony_ci * @pdev: Pointer to pci_dev structure 207362306a36Sopenharmony_ci */ 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_civoid 207662306a36Sopenharmony_cimpt_detach(struct pci_dev *pdev) 207762306a36Sopenharmony_ci{ 207862306a36Sopenharmony_ci MPT_ADAPTER *ioc = pci_get_drvdata(pdev); 207962306a36Sopenharmony_ci char pname[64]; 208062306a36Sopenharmony_ci u8 cb_idx; 208162306a36Sopenharmony_ci unsigned long flags; 208262306a36Sopenharmony_ci struct workqueue_struct *wq; 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci /* 208562306a36Sopenharmony_ci * Stop polling ioc for fault condition 208662306a36Sopenharmony_ci */ 208762306a36Sopenharmony_ci spin_lock_irqsave(&ioc->taskmgmt_lock, flags); 208862306a36Sopenharmony_ci wq = ioc->reset_work_q; 208962306a36Sopenharmony_ci ioc->reset_work_q = NULL; 209062306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 209162306a36Sopenharmony_ci cancel_delayed_work(&ioc->fault_reset_work); 209262306a36Sopenharmony_ci destroy_workqueue(wq); 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci spin_lock_irqsave(&ioc->fw_event_lock, flags); 209562306a36Sopenharmony_ci wq = ioc->fw_event_q; 209662306a36Sopenharmony_ci ioc->fw_event_q = NULL; 209762306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->fw_event_lock, flags); 209862306a36Sopenharmony_ci destroy_workqueue(wq); 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci snprintf(pname, sizeof(pname), MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name); 210162306a36Sopenharmony_ci remove_proc_entry(pname, NULL); 210262306a36Sopenharmony_ci snprintf(pname, sizeof(pname), MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name); 210362306a36Sopenharmony_ci remove_proc_entry(pname, NULL); 210462306a36Sopenharmony_ci snprintf(pname, sizeof(pname), MPT_PROCFS_MPTBASEDIR "/%s", ioc->name); 210562306a36Sopenharmony_ci remove_proc_entry(pname, NULL); 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci /* call per device driver remove entry point */ 210862306a36Sopenharmony_ci for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) { 210962306a36Sopenharmony_ci if(MptDeviceDriverHandlers[cb_idx] && 211062306a36Sopenharmony_ci MptDeviceDriverHandlers[cb_idx]->remove) { 211162306a36Sopenharmony_ci MptDeviceDriverHandlers[cb_idx]->remove(pdev); 211262306a36Sopenharmony_ci } 211362306a36Sopenharmony_ci } 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci /* Disable interrupts! */ 211662306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci ioc->active = 0; 211962306a36Sopenharmony_ci synchronize_irq(pdev->irq); 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci /* Clear any lingering interrupt */ 212262306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci CHIPREG_READ32(&ioc->chip->IntStatus); 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci mpt_adapter_dispose(ioc); 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci} 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci/************************************************************************** 213162306a36Sopenharmony_ci * Power Management 213262306a36Sopenharmony_ci */ 213362306a36Sopenharmony_ci#ifdef CONFIG_PM 213462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 213562306a36Sopenharmony_ci/** 213662306a36Sopenharmony_ci * mpt_suspend - Fusion MPT base driver suspend routine. 213762306a36Sopenharmony_ci * @pdev: Pointer to pci_dev structure 213862306a36Sopenharmony_ci * @state: new state to enter 213962306a36Sopenharmony_ci */ 214062306a36Sopenharmony_ciint 214162306a36Sopenharmony_cimpt_suspend(struct pci_dev *pdev, pm_message_t state) 214262306a36Sopenharmony_ci{ 214362306a36Sopenharmony_ci u32 device_state; 214462306a36Sopenharmony_ci MPT_ADAPTER *ioc = pci_get_drvdata(pdev); 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci device_state = pci_choose_state(pdev, state); 214762306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering " 214862306a36Sopenharmony_ci "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev), 214962306a36Sopenharmony_ci device_state); 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci /* put ioc into READY_STATE */ 215262306a36Sopenharmony_ci if (SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) { 215362306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT 215462306a36Sopenharmony_ci "pci-suspend: IOC msg unit reset failed!\n", ioc->name); 215562306a36Sopenharmony_ci } 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci /* disable interrupts */ 215862306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); 215962306a36Sopenharmony_ci ioc->active = 0; 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci /* Clear any lingering interrupt */ 216262306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci free_irq(ioc->pci_irq, ioc); 216562306a36Sopenharmony_ci if (ioc->msi_enable) 216662306a36Sopenharmony_ci pci_disable_msi(ioc->pcidev); 216762306a36Sopenharmony_ci ioc->pci_irq = -1; 216862306a36Sopenharmony_ci pci_save_state(pdev); 216962306a36Sopenharmony_ci pci_disable_device(pdev); 217062306a36Sopenharmony_ci pci_release_selected_regions(pdev, ioc->bars); 217162306a36Sopenharmony_ci pci_set_power_state(pdev, device_state); 217262306a36Sopenharmony_ci return 0; 217362306a36Sopenharmony_ci} 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 217662306a36Sopenharmony_ci/** 217762306a36Sopenharmony_ci * mpt_resume - Fusion MPT base driver resume routine. 217862306a36Sopenharmony_ci * @pdev: Pointer to pci_dev structure 217962306a36Sopenharmony_ci */ 218062306a36Sopenharmony_ciint 218162306a36Sopenharmony_cimpt_resume(struct pci_dev *pdev) 218262306a36Sopenharmony_ci{ 218362306a36Sopenharmony_ci MPT_ADAPTER *ioc = pci_get_drvdata(pdev); 218462306a36Sopenharmony_ci u32 device_state = pdev->current_state; 218562306a36Sopenharmony_ci int recovery_state; 218662306a36Sopenharmony_ci int err; 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous " 218962306a36Sopenharmony_ci "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev), 219062306a36Sopenharmony_ci device_state); 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci pci_set_power_state(pdev, PCI_D0); 219362306a36Sopenharmony_ci pci_enable_wake(pdev, PCI_D0, 0); 219462306a36Sopenharmony_ci pci_restore_state(pdev); 219562306a36Sopenharmony_ci ioc->pcidev = pdev; 219662306a36Sopenharmony_ci err = mpt_mapresources(ioc); 219762306a36Sopenharmony_ci if (err) 219862306a36Sopenharmony_ci return err; 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci if (ioc->dma_mask == DMA_BIT_MASK(64)) { 220162306a36Sopenharmony_ci if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) 220262306a36Sopenharmony_ci ioc->add_sge = &mpt_add_sge_64bit_1078; 220362306a36Sopenharmony_ci else 220462306a36Sopenharmony_ci ioc->add_sge = &mpt_add_sge_64bit; 220562306a36Sopenharmony_ci ioc->add_chain = &mpt_add_chain_64bit; 220662306a36Sopenharmony_ci ioc->sg_addr_size = 8; 220762306a36Sopenharmony_ci } else { 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci ioc->add_sge = &mpt_add_sge; 221062306a36Sopenharmony_ci ioc->add_chain = &mpt_add_chain; 221162306a36Sopenharmony_ci ioc->sg_addr_size = 4; 221262306a36Sopenharmony_ci } 221362306a36Sopenharmony_ci ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size; 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n", 221662306a36Sopenharmony_ci ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT), 221762306a36Sopenharmony_ci CHIPREG_READ32(&ioc->chip->Doorbell)); 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci /* 222062306a36Sopenharmony_ci * Errata workaround for SAS pci express: 222162306a36Sopenharmony_ci * Upon returning to the D0 state, the contents of the doorbell will be 222262306a36Sopenharmony_ci * stale data, and this will incorrectly signal to the host driver that 222362306a36Sopenharmony_ci * the firmware is ready to process mpt commands. The workaround is 222462306a36Sopenharmony_ci * to issue a diagnostic reset. 222562306a36Sopenharmony_ci */ 222662306a36Sopenharmony_ci if (ioc->bus_type == SAS && (pdev->device == 222762306a36Sopenharmony_ci MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device == 222862306a36Sopenharmony_ci MPI_MANUFACTPAGE_DEVID_SAS1064E)) { 222962306a36Sopenharmony_ci if (KickStart(ioc, 1, CAN_SLEEP) < 0) { 223062306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n", 223162306a36Sopenharmony_ci ioc->name); 223262306a36Sopenharmony_ci goto out; 223362306a36Sopenharmony_ci } 223462306a36Sopenharmony_ci } 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_ci /* bring ioc to operational state */ 223762306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name); 223862306a36Sopenharmony_ci recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, 223962306a36Sopenharmony_ci CAN_SLEEP); 224062306a36Sopenharmony_ci if (recovery_state != 0) 224162306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, " 224262306a36Sopenharmony_ci "error:[%x]\n", ioc->name, recovery_state); 224362306a36Sopenharmony_ci else 224462306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT 224562306a36Sopenharmony_ci "pci-resume: success\n", ioc->name); 224662306a36Sopenharmony_ci out: 224762306a36Sopenharmony_ci return 0; 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci} 225062306a36Sopenharmony_ci#endif 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_cistatic int 225362306a36Sopenharmony_cimpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase) 225462306a36Sopenharmony_ci{ 225562306a36Sopenharmony_ci if ((MptDriverClass[index] == MPTSPI_DRIVER && 225662306a36Sopenharmony_ci ioc->bus_type != SPI) || 225762306a36Sopenharmony_ci (MptDriverClass[index] == MPTFC_DRIVER && 225862306a36Sopenharmony_ci ioc->bus_type != FC) || 225962306a36Sopenharmony_ci (MptDriverClass[index] == MPTSAS_DRIVER && 226062306a36Sopenharmony_ci ioc->bus_type != SAS)) 226162306a36Sopenharmony_ci /* make sure we only call the relevant reset handler 226262306a36Sopenharmony_ci * for the bus */ 226362306a36Sopenharmony_ci return 0; 226462306a36Sopenharmony_ci return (MptResetHandlers[index])(ioc, reset_phase); 226562306a36Sopenharmony_ci} 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 226862306a36Sopenharmony_ci/** 226962306a36Sopenharmony_ci * mpt_do_ioc_recovery - Initialize or recover MPT adapter. 227062306a36Sopenharmony_ci * @ioc: Pointer to MPT adapter structure 227162306a36Sopenharmony_ci * @reason: Event word / reason 227262306a36Sopenharmony_ci * @sleepFlag: Use schedule if CAN_SLEEP else use udelay. 227362306a36Sopenharmony_ci * 227462306a36Sopenharmony_ci * This routine performs all the steps necessary to bring the IOC 227562306a36Sopenharmony_ci * to a OPERATIONAL state. 227662306a36Sopenharmony_ci * 227762306a36Sopenharmony_ci * This routine also pre-fetches the LAN MAC address of a Fibre Channel 227862306a36Sopenharmony_ci * MPT adapter. 227962306a36Sopenharmony_ci * 228062306a36Sopenharmony_ci * Returns: 228162306a36Sopenharmony_ci * 0 for success 228262306a36Sopenharmony_ci * -1 if failed to get board READY 228362306a36Sopenharmony_ci * -2 if READY but IOCFacts Failed 228462306a36Sopenharmony_ci * -3 if READY but PrimeIOCFifos Failed 228562306a36Sopenharmony_ci * -4 if READY but IOCInit Failed 228662306a36Sopenharmony_ci * -5 if failed to enable_device and/or request_selected_regions 228762306a36Sopenharmony_ci * -6 if failed to upload firmware 228862306a36Sopenharmony_ci */ 228962306a36Sopenharmony_cistatic int 229062306a36Sopenharmony_cimpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) 229162306a36Sopenharmony_ci{ 229262306a36Sopenharmony_ci int hard_reset_done = 0; 229362306a36Sopenharmony_ci int alt_ioc_ready = 0; 229462306a36Sopenharmony_ci int hard; 229562306a36Sopenharmony_ci int rc=0; 229662306a36Sopenharmony_ci int ii; 229762306a36Sopenharmony_ci int ret = 0; 229862306a36Sopenharmony_ci int reset_alt_ioc_active = 0; 229962306a36Sopenharmony_ci int irq_allocated = 0; 230062306a36Sopenharmony_ci u8 *a; 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name, 230362306a36Sopenharmony_ci reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery"); 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci /* Disable reply interrupts (also blocks FreeQ) */ 230662306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); 230762306a36Sopenharmony_ci ioc->active = 0; 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci if (ioc->alt_ioc) { 231062306a36Sopenharmony_ci if (ioc->alt_ioc->active || 231162306a36Sopenharmony_ci reason == MPT_HOSTEVENT_IOC_RECOVER) { 231262306a36Sopenharmony_ci reset_alt_ioc_active = 1; 231362306a36Sopenharmony_ci /* Disable alt-IOC's reply interrupts 231462306a36Sopenharmony_ci * (and FreeQ) for a bit 231562306a36Sopenharmony_ci **/ 231662306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 231762306a36Sopenharmony_ci 0xFFFFFFFF); 231862306a36Sopenharmony_ci ioc->alt_ioc->active = 0; 231962306a36Sopenharmony_ci } 232062306a36Sopenharmony_ci } 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci hard = 1; 232362306a36Sopenharmony_ci if (reason == MPT_HOSTEVENT_IOC_BRINGUP) 232462306a36Sopenharmony_ci hard = 0; 232562306a36Sopenharmony_ci 232662306a36Sopenharmony_ci if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) { 232762306a36Sopenharmony_ci if (hard_reset_done == -4) { 232862306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n", 232962306a36Sopenharmony_ci ioc->name); 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci if (reset_alt_ioc_active && ioc->alt_ioc) { 233262306a36Sopenharmony_ci /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */ 233362306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_INFO_FMT 233462306a36Sopenharmony_ci "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name)); 233562306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM); 233662306a36Sopenharmony_ci ioc->alt_ioc->active = 1; 233762306a36Sopenharmony_ci } 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci } else { 234062306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 234162306a36Sopenharmony_ci "NOT READY WARNING!\n", ioc->name); 234262306a36Sopenharmony_ci } 234362306a36Sopenharmony_ci ret = -1; 234462306a36Sopenharmony_ci goto out; 234562306a36Sopenharmony_ci } 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci /* hard_reset_done = 0 if a soft reset was performed 234862306a36Sopenharmony_ci * and 1 if a hard reset was performed. 234962306a36Sopenharmony_ci */ 235062306a36Sopenharmony_ci if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) { 235162306a36Sopenharmony_ci if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) 235262306a36Sopenharmony_ci alt_ioc_ready = 1; 235362306a36Sopenharmony_ci else 235462306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 235562306a36Sopenharmony_ci ": alt-ioc Not ready WARNING!\n", 235662306a36Sopenharmony_ci ioc->alt_ioc->name); 235762306a36Sopenharmony_ci } 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci for (ii=0; ii<5; ii++) { 236062306a36Sopenharmony_ci /* Get IOC facts! Allow 5 retries */ 236162306a36Sopenharmony_ci if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0) 236262306a36Sopenharmony_ci break; 236362306a36Sopenharmony_ci } 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci if (ii == 5) { 236762306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT 236862306a36Sopenharmony_ci "Retry IocFacts failed rc=%x\n", ioc->name, rc)); 236962306a36Sopenharmony_ci ret = -2; 237062306a36Sopenharmony_ci } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { 237162306a36Sopenharmony_ci MptDisplayIocCapabilities(ioc); 237262306a36Sopenharmony_ci } 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci if (alt_ioc_ready) { 237562306a36Sopenharmony_ci if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { 237662306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT 237762306a36Sopenharmony_ci "Initial Alt IocFacts failed rc=%x\n", 237862306a36Sopenharmony_ci ioc->name, rc)); 237962306a36Sopenharmony_ci /* Retry - alt IOC was initialized once 238062306a36Sopenharmony_ci */ 238162306a36Sopenharmony_ci rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason); 238262306a36Sopenharmony_ci } 238362306a36Sopenharmony_ci if (rc) { 238462306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT 238562306a36Sopenharmony_ci "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc)); 238662306a36Sopenharmony_ci alt_ioc_ready = 0; 238762306a36Sopenharmony_ci reset_alt_ioc_active = 0; 238862306a36Sopenharmony_ci } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { 238962306a36Sopenharmony_ci MptDisplayIocCapabilities(ioc->alt_ioc); 239062306a36Sopenharmony_ci } 239162306a36Sopenharmony_ci } 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) && 239462306a36Sopenharmony_ci (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) { 239562306a36Sopenharmony_ci pci_release_selected_regions(ioc->pcidev, ioc->bars); 239662306a36Sopenharmony_ci ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM | 239762306a36Sopenharmony_ci IORESOURCE_IO); 239862306a36Sopenharmony_ci if (pci_enable_device(ioc->pcidev)) 239962306a36Sopenharmony_ci return -5; 240062306a36Sopenharmony_ci if (pci_request_selected_regions(ioc->pcidev, ioc->bars, 240162306a36Sopenharmony_ci "mpt")) 240262306a36Sopenharmony_ci return -5; 240362306a36Sopenharmony_ci } 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci /* 240662306a36Sopenharmony_ci * Device is reset now. It must have de-asserted the interrupt line 240762306a36Sopenharmony_ci * (if it was asserted) and it should be safe to register for the 240862306a36Sopenharmony_ci * interrupt now. 240962306a36Sopenharmony_ci */ 241062306a36Sopenharmony_ci if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { 241162306a36Sopenharmony_ci ioc->pci_irq = -1; 241262306a36Sopenharmony_ci if (ioc->pcidev->irq) { 241362306a36Sopenharmony_ci if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev)) 241462306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n", 241562306a36Sopenharmony_ci ioc->name); 241662306a36Sopenharmony_ci else 241762306a36Sopenharmony_ci ioc->msi_enable = 0; 241862306a36Sopenharmony_ci rc = request_irq(ioc->pcidev->irq, mpt_interrupt, 241962306a36Sopenharmony_ci IRQF_SHARED, ioc->name, ioc); 242062306a36Sopenharmony_ci if (rc < 0) { 242162306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "Unable to allocate " 242262306a36Sopenharmony_ci "interrupt %d!\n", 242362306a36Sopenharmony_ci ioc->name, ioc->pcidev->irq); 242462306a36Sopenharmony_ci if (ioc->msi_enable) 242562306a36Sopenharmony_ci pci_disable_msi(ioc->pcidev); 242662306a36Sopenharmony_ci ret = -EBUSY; 242762306a36Sopenharmony_ci goto out; 242862306a36Sopenharmony_ci } 242962306a36Sopenharmony_ci irq_allocated = 1; 243062306a36Sopenharmony_ci ioc->pci_irq = ioc->pcidev->irq; 243162306a36Sopenharmony_ci pci_set_master(ioc->pcidev); /* ?? */ 243262306a36Sopenharmony_ci pci_set_drvdata(ioc->pcidev, ioc); 243362306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_INFO_FMT 243462306a36Sopenharmony_ci "installed at interrupt %d\n", ioc->name, 243562306a36Sopenharmony_ci ioc->pcidev->irq)); 243662306a36Sopenharmony_ci } 243762306a36Sopenharmony_ci } 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci /* Prime reply & request queues! 244062306a36Sopenharmony_ci * (mucho alloc's) Must be done prior to 244162306a36Sopenharmony_ci * init as upper addresses are needed for init. 244262306a36Sopenharmony_ci * If fails, continue with alt-ioc processing 244362306a36Sopenharmony_ci */ 244462306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n", 244562306a36Sopenharmony_ci ioc->name)); 244662306a36Sopenharmony_ci if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0)) 244762306a36Sopenharmony_ci ret = -3; 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_ci /* May need to check/upload firmware & data here! 245062306a36Sopenharmony_ci * If fails, continue with alt-ioc processing 245162306a36Sopenharmony_ci */ 245262306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n", 245362306a36Sopenharmony_ci ioc->name)); 245462306a36Sopenharmony_ci if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0)) 245562306a36Sopenharmony_ci ret = -4; 245662306a36Sopenharmony_ci// NEW! 245762306a36Sopenharmony_ci if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) { 245862306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 245962306a36Sopenharmony_ci ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n", 246062306a36Sopenharmony_ci ioc->alt_ioc->name, rc); 246162306a36Sopenharmony_ci alt_ioc_ready = 0; 246262306a36Sopenharmony_ci reset_alt_ioc_active = 0; 246362306a36Sopenharmony_ci } 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ci if (alt_ioc_ready) { 246662306a36Sopenharmony_ci if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { 246762306a36Sopenharmony_ci alt_ioc_ready = 0; 246862306a36Sopenharmony_ci reset_alt_ioc_active = 0; 246962306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 247062306a36Sopenharmony_ci ": alt-ioc: (%d) init failure WARNING!\n", 247162306a36Sopenharmony_ci ioc->alt_ioc->name, rc); 247262306a36Sopenharmony_ci } 247362306a36Sopenharmony_ci } 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_ci if (reason == MPT_HOSTEVENT_IOC_BRINGUP){ 247662306a36Sopenharmony_ci if (ioc->upload_fw) { 247762306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT 247862306a36Sopenharmony_ci "firmware upload required!\n", ioc->name)); 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_ci /* Controller is not operational, cannot do upload 248162306a36Sopenharmony_ci */ 248262306a36Sopenharmony_ci if (ret == 0) { 248362306a36Sopenharmony_ci rc = mpt_do_upload(ioc, sleepFlag); 248462306a36Sopenharmony_ci if (rc == 0) { 248562306a36Sopenharmony_ci if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) { 248662306a36Sopenharmony_ci /* 248762306a36Sopenharmony_ci * Maintain only one pointer to FW memory 248862306a36Sopenharmony_ci * so there will not be two attempt to 248962306a36Sopenharmony_ci * downloadboot onboard dual function 249062306a36Sopenharmony_ci * chips (mpt_adapter_disable, 249162306a36Sopenharmony_ci * mpt_diag_reset) 249262306a36Sopenharmony_ci */ 249362306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT 249462306a36Sopenharmony_ci "mpt_upload: alt_%s has cached_fw=%p \n", 249562306a36Sopenharmony_ci ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw)); 249662306a36Sopenharmony_ci ioc->cached_fw = NULL; 249762306a36Sopenharmony_ci } 249862306a36Sopenharmony_ci } else { 249962306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 250062306a36Sopenharmony_ci "firmware upload failure!\n", ioc->name); 250162306a36Sopenharmony_ci ret = -6; 250262306a36Sopenharmony_ci } 250362306a36Sopenharmony_ci } 250462306a36Sopenharmony_ci } 250562306a36Sopenharmony_ci } 250662306a36Sopenharmony_ci 250762306a36Sopenharmony_ci /* Enable MPT base driver management of EventNotification 250862306a36Sopenharmony_ci * and EventAck handling. 250962306a36Sopenharmony_ci */ 251062306a36Sopenharmony_ci if ((ret == 0) && (!ioc->facts.EventState)) { 251162306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_INFO_FMT 251262306a36Sopenharmony_ci "SendEventNotification\n", 251362306a36Sopenharmony_ci ioc->name)); 251462306a36Sopenharmony_ci ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */ 251562306a36Sopenharmony_ci } 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) 251862306a36Sopenharmony_ci rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag); 251962306a36Sopenharmony_ci 252062306a36Sopenharmony_ci if (ret == 0) { 252162306a36Sopenharmony_ci /* Enable! (reply interrupt) */ 252262306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); 252362306a36Sopenharmony_ci ioc->active = 1; 252462306a36Sopenharmony_ci } 252562306a36Sopenharmony_ci if (rc == 0) { /* alt ioc */ 252662306a36Sopenharmony_ci if (reset_alt_ioc_active && ioc->alt_ioc) { 252762306a36Sopenharmony_ci /* (re)Enable alt-IOC! (reply interrupt) */ 252862306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc" 252962306a36Sopenharmony_ci "reply irq re-enabled\n", 253062306a36Sopenharmony_ci ioc->alt_ioc->name)); 253162306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 253262306a36Sopenharmony_ci MPI_HIM_DIM); 253362306a36Sopenharmony_ci ioc->alt_ioc->active = 1; 253462306a36Sopenharmony_ci } 253562306a36Sopenharmony_ci } 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci /* Add additional "reason" check before call to GetLanConfigPages 253962306a36Sopenharmony_ci * (combined with GetIoUnitPage2 call). This prevents a somewhat 254062306a36Sopenharmony_ci * recursive scenario; GetLanConfigPages times out, timer expired 254162306a36Sopenharmony_ci * routine calls HardResetHandler, which calls into here again, 254262306a36Sopenharmony_ci * and we try GetLanConfigPages again... 254362306a36Sopenharmony_ci */ 254462306a36Sopenharmony_ci if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci /* 254762306a36Sopenharmony_ci * Initialize link list for inactive raid volumes. 254862306a36Sopenharmony_ci */ 254962306a36Sopenharmony_ci mutex_init(&ioc->raid_data.inactive_list_mutex); 255062306a36Sopenharmony_ci INIT_LIST_HEAD(&ioc->raid_data.inactive_list); 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_ci switch (ioc->bus_type) { 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_ci case SAS: 255562306a36Sopenharmony_ci /* clear persistency table */ 255662306a36Sopenharmony_ci if(ioc->facts.IOCExceptions & 255762306a36Sopenharmony_ci MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) { 255862306a36Sopenharmony_ci ret = mptbase_sas_persist_operation(ioc, 255962306a36Sopenharmony_ci MPI_SAS_OP_CLEAR_NOT_PRESENT); 256062306a36Sopenharmony_ci if(ret != 0) 256162306a36Sopenharmony_ci goto out; 256262306a36Sopenharmony_ci } 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci /* Find IM volumes 256562306a36Sopenharmony_ci */ 256662306a36Sopenharmony_ci mpt_findImVolumes(ioc); 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci /* Check, and possibly reset, the coalescing value 256962306a36Sopenharmony_ci */ 257062306a36Sopenharmony_ci mpt_read_ioc_pg_1(ioc); 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_ci break; 257362306a36Sopenharmony_ci 257462306a36Sopenharmony_ci case FC: 257562306a36Sopenharmony_ci if ((ioc->pfacts[0].ProtocolFlags & 257662306a36Sopenharmony_ci MPI_PORTFACTS_PROTOCOL_LAN) && 257762306a36Sopenharmony_ci (ioc->lan_cnfg_page0.Header.PageLength == 0)) { 257862306a36Sopenharmony_ci /* 257962306a36Sopenharmony_ci * Pre-fetch the ports LAN MAC address! 258062306a36Sopenharmony_ci * (LANPage1_t stuff) 258162306a36Sopenharmony_ci */ 258262306a36Sopenharmony_ci (void) GetLanConfigPages(ioc); 258362306a36Sopenharmony_ci a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; 258462306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT 258562306a36Sopenharmony_ci "LanAddr = %pMR\n", ioc->name, a)); 258662306a36Sopenharmony_ci } 258762306a36Sopenharmony_ci break; 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_ci case SPI: 259062306a36Sopenharmony_ci /* Get NVRAM and adapter maximums from SPP 0 and 2 259162306a36Sopenharmony_ci */ 259262306a36Sopenharmony_ci mpt_GetScsiPortSettings(ioc, 0); 259362306a36Sopenharmony_ci 259462306a36Sopenharmony_ci /* Get version and length of SDP 1 259562306a36Sopenharmony_ci */ 259662306a36Sopenharmony_ci mpt_readScsiDevicePageHeaders(ioc, 0); 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ci /* Find IM volumes 259962306a36Sopenharmony_ci */ 260062306a36Sopenharmony_ci if (ioc->facts.MsgVersion >= MPI_VERSION_01_02) 260162306a36Sopenharmony_ci mpt_findImVolumes(ioc); 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ci /* Check, and possibly reset, the coalescing value 260462306a36Sopenharmony_ci */ 260562306a36Sopenharmony_ci mpt_read_ioc_pg_1(ioc); 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ci mpt_read_ioc_pg_4(ioc); 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_ci break; 261062306a36Sopenharmony_ci } 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_ci GetIoUnitPage2(ioc); 261362306a36Sopenharmony_ci mpt_get_manufacturing_pg_0(ioc); 261462306a36Sopenharmony_ci } 261562306a36Sopenharmony_ci 261662306a36Sopenharmony_ci out: 261762306a36Sopenharmony_ci if ((ret != 0) && irq_allocated) { 261862306a36Sopenharmony_ci free_irq(ioc->pci_irq, ioc); 261962306a36Sopenharmony_ci if (ioc->msi_enable) 262062306a36Sopenharmony_ci pci_disable_msi(ioc->pcidev); 262162306a36Sopenharmony_ci } 262262306a36Sopenharmony_ci return ret; 262362306a36Sopenharmony_ci} 262462306a36Sopenharmony_ci 262562306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 262662306a36Sopenharmony_ci/** 262762306a36Sopenharmony_ci * mpt_detect_bound_ports - Search for matching PCI bus/dev_function 262862306a36Sopenharmony_ci * @ioc: Pointer to MPT adapter structure 262962306a36Sopenharmony_ci * @pdev: Pointer to (struct pci_dev) structure 263062306a36Sopenharmony_ci * 263162306a36Sopenharmony_ci * Search for PCI bus/dev_function which matches 263262306a36Sopenharmony_ci * PCI bus/dev_function (+/-1) for newly discovered 929, 263362306a36Sopenharmony_ci * 929X, 1030 or 1035. 263462306a36Sopenharmony_ci * 263562306a36Sopenharmony_ci * If match on PCI dev_function +/-1 is found, bind the two MPT adapters 263662306a36Sopenharmony_ci * using alt_ioc pointer fields in their %MPT_ADAPTER structures. 263762306a36Sopenharmony_ci */ 263862306a36Sopenharmony_cistatic void 263962306a36Sopenharmony_cimpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) 264062306a36Sopenharmony_ci{ 264162306a36Sopenharmony_ci struct pci_dev *peer=NULL; 264262306a36Sopenharmony_ci unsigned int slot = PCI_SLOT(pdev->devfn); 264362306a36Sopenharmony_ci unsigned int func = PCI_FUNC(pdev->devfn); 264462306a36Sopenharmony_ci MPT_ADAPTER *ioc_srch; 264562306a36Sopenharmony_ci 264662306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x," 264762306a36Sopenharmony_ci " searching for devfn match on %x or %x\n", 264862306a36Sopenharmony_ci ioc->name, pci_name(pdev), pdev->bus->number, 264962306a36Sopenharmony_ci pdev->devfn, func-1, func+1)); 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1)); 265262306a36Sopenharmony_ci if (!peer) { 265362306a36Sopenharmony_ci peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1)); 265462306a36Sopenharmony_ci if (!peer) 265562306a36Sopenharmony_ci return; 265662306a36Sopenharmony_ci } 265762306a36Sopenharmony_ci 265862306a36Sopenharmony_ci list_for_each_entry(ioc_srch, &ioc_list, list) { 265962306a36Sopenharmony_ci struct pci_dev *_pcidev = ioc_srch->pcidev; 266062306a36Sopenharmony_ci if (_pcidev == peer) { 266162306a36Sopenharmony_ci /* Paranoia checks */ 266262306a36Sopenharmony_ci if (ioc->alt_ioc != NULL) { 266362306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 266462306a36Sopenharmony_ci "Oops, already bound (%s <==> %s)!\n", 266562306a36Sopenharmony_ci ioc->name, ioc->name, ioc->alt_ioc->name); 266662306a36Sopenharmony_ci break; 266762306a36Sopenharmony_ci } else if (ioc_srch->alt_ioc != NULL) { 266862306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 266962306a36Sopenharmony_ci "Oops, already bound (%s <==> %s)!\n", 267062306a36Sopenharmony_ci ioc_srch->name, ioc_srch->name, 267162306a36Sopenharmony_ci ioc_srch->alt_ioc->name); 267262306a36Sopenharmony_ci break; 267362306a36Sopenharmony_ci } 267462306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT 267562306a36Sopenharmony_ci "FOUND! binding %s <==> %s\n", 267662306a36Sopenharmony_ci ioc->name, ioc->name, ioc_srch->name)); 267762306a36Sopenharmony_ci ioc_srch->alt_ioc = ioc; 267862306a36Sopenharmony_ci ioc->alt_ioc = ioc_srch; 267962306a36Sopenharmony_ci } 268062306a36Sopenharmony_ci } 268162306a36Sopenharmony_ci pci_dev_put(peer); 268262306a36Sopenharmony_ci} 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 268562306a36Sopenharmony_ci/** 268662306a36Sopenharmony_ci * mpt_adapter_disable - Disable misbehaving MPT adapter. 268762306a36Sopenharmony_ci * @ioc: Pointer to MPT adapter structure 268862306a36Sopenharmony_ci */ 268962306a36Sopenharmony_cistatic void 269062306a36Sopenharmony_cimpt_adapter_disable(MPT_ADAPTER *ioc) 269162306a36Sopenharmony_ci{ 269262306a36Sopenharmony_ci int sz; 269362306a36Sopenharmony_ci int ret; 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci if (ioc->cached_fw != NULL) { 269662306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT 269762306a36Sopenharmony_ci "%s: Pushing FW onto adapter\n", __func__, ioc->name)); 269862306a36Sopenharmony_ci if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *) 269962306a36Sopenharmony_ci ioc->cached_fw, CAN_SLEEP)) < 0) { 270062306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 270162306a36Sopenharmony_ci ": firmware downloadboot failure (%d)!\n", 270262306a36Sopenharmony_ci ioc->name, ret); 270362306a36Sopenharmony_ci } 270462306a36Sopenharmony_ci } 270562306a36Sopenharmony_ci 270662306a36Sopenharmony_ci /* 270762306a36Sopenharmony_ci * Put the controller into ready state (if its not already) 270862306a36Sopenharmony_ci */ 270962306a36Sopenharmony_ci if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) { 271062306a36Sopenharmony_ci if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, 271162306a36Sopenharmony_ci CAN_SLEEP)) { 271262306a36Sopenharmony_ci if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) 271362306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "%s: IOC msg unit " 271462306a36Sopenharmony_ci "reset failed to put ioc in ready state!\n", 271562306a36Sopenharmony_ci ioc->name, __func__); 271662306a36Sopenharmony_ci } else 271762306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset " 271862306a36Sopenharmony_ci "failed!\n", ioc->name, __func__); 271962306a36Sopenharmony_ci } 272062306a36Sopenharmony_ci 272162306a36Sopenharmony_ci 272262306a36Sopenharmony_ci /* Disable adapter interrupts! */ 272362306a36Sopenharmony_ci synchronize_irq(ioc->pcidev->irq); 272462306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); 272562306a36Sopenharmony_ci ioc->active = 0; 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_ci /* Clear any lingering interrupt */ 272862306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); 272962306a36Sopenharmony_ci CHIPREG_READ32(&ioc->chip->IntStatus); 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci if (ioc->alloc != NULL) { 273262306a36Sopenharmony_ci sz = ioc->alloc_sz; 273362306a36Sopenharmony_ci dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n", 273462306a36Sopenharmony_ci ioc->name, ioc->alloc, ioc->alloc_sz)); 273562306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, sz, ioc->alloc, 273662306a36Sopenharmony_ci ioc->alloc_dma); 273762306a36Sopenharmony_ci ioc->reply_frames = NULL; 273862306a36Sopenharmony_ci ioc->req_frames = NULL; 273962306a36Sopenharmony_ci ioc->alloc = NULL; 274062306a36Sopenharmony_ci ioc->alloc_total -= sz; 274162306a36Sopenharmony_ci } 274262306a36Sopenharmony_ci 274362306a36Sopenharmony_ci if (ioc->sense_buf_pool != NULL) { 274462306a36Sopenharmony_ci sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); 274562306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, sz, ioc->sense_buf_pool, 274662306a36Sopenharmony_ci ioc->sense_buf_pool_dma); 274762306a36Sopenharmony_ci ioc->sense_buf_pool = NULL; 274862306a36Sopenharmony_ci ioc->alloc_total -= sz; 274962306a36Sopenharmony_ci } 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_ci if (ioc->events != NULL){ 275262306a36Sopenharmony_ci sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS); 275362306a36Sopenharmony_ci kfree(ioc->events); 275462306a36Sopenharmony_ci ioc->events = NULL; 275562306a36Sopenharmony_ci ioc->alloc_total -= sz; 275662306a36Sopenharmony_ci } 275762306a36Sopenharmony_ci 275862306a36Sopenharmony_ci mpt_free_fw_memory(ioc); 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_ci kfree(ioc->spi_data.nvram); 276162306a36Sopenharmony_ci mpt_inactive_raid_list_free(ioc); 276262306a36Sopenharmony_ci kfree(ioc->raid_data.pIocPg2); 276362306a36Sopenharmony_ci kfree(ioc->raid_data.pIocPg3); 276462306a36Sopenharmony_ci ioc->spi_data.nvram = NULL; 276562306a36Sopenharmony_ci ioc->raid_data.pIocPg3 = NULL; 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_ci if (ioc->spi_data.pIocPg4 != NULL) { 276862306a36Sopenharmony_ci sz = ioc->spi_data.IocPg4Sz; 276962306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, sz, 277062306a36Sopenharmony_ci ioc->spi_data.pIocPg4, 277162306a36Sopenharmony_ci ioc->spi_data.IocPg4_dma); 277262306a36Sopenharmony_ci ioc->spi_data.pIocPg4 = NULL; 277362306a36Sopenharmony_ci ioc->alloc_total -= sz; 277462306a36Sopenharmony_ci } 277562306a36Sopenharmony_ci 277662306a36Sopenharmony_ci if (ioc->ReqToChain != NULL) { 277762306a36Sopenharmony_ci kfree(ioc->ReqToChain); 277862306a36Sopenharmony_ci kfree(ioc->RequestNB); 277962306a36Sopenharmony_ci ioc->ReqToChain = NULL; 278062306a36Sopenharmony_ci } 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci kfree(ioc->ChainToChain); 278362306a36Sopenharmony_ci ioc->ChainToChain = NULL; 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_ci if (ioc->HostPageBuffer != NULL) { 278662306a36Sopenharmony_ci if((ret = mpt_host_page_access_control(ioc, 278762306a36Sopenharmony_ci MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) { 278862306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT 278962306a36Sopenharmony_ci ": %s: host page buffers free failed (%d)!\n", 279062306a36Sopenharmony_ci ioc->name, __func__, ret); 279162306a36Sopenharmony_ci } 279262306a36Sopenharmony_ci dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT 279362306a36Sopenharmony_ci "HostPageBuffer free @ %p, sz=%d bytes\n", 279462306a36Sopenharmony_ci ioc->name, ioc->HostPageBuffer, 279562306a36Sopenharmony_ci ioc->HostPageBuffer_sz)); 279662306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, ioc->HostPageBuffer_sz, 279762306a36Sopenharmony_ci ioc->HostPageBuffer, ioc->HostPageBuffer_dma); 279862306a36Sopenharmony_ci ioc->HostPageBuffer = NULL; 279962306a36Sopenharmony_ci ioc->HostPageBuffer_sz = 0; 280062306a36Sopenharmony_ci ioc->alloc_total -= ioc->HostPageBuffer_sz; 280162306a36Sopenharmony_ci } 280262306a36Sopenharmony_ci 280362306a36Sopenharmony_ci pci_set_drvdata(ioc->pcidev, NULL); 280462306a36Sopenharmony_ci} 280562306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 280662306a36Sopenharmony_ci/** 280762306a36Sopenharmony_ci * mpt_adapter_dispose - Free all resources associated with an MPT adapter 280862306a36Sopenharmony_ci * @ioc: Pointer to MPT adapter structure 280962306a36Sopenharmony_ci * 281062306a36Sopenharmony_ci * This routine unregisters h/w resources and frees all alloc'd memory 281162306a36Sopenharmony_ci * associated with a MPT adapter structure. 281262306a36Sopenharmony_ci */ 281362306a36Sopenharmony_cistatic void 281462306a36Sopenharmony_cimpt_adapter_dispose(MPT_ADAPTER *ioc) 281562306a36Sopenharmony_ci{ 281662306a36Sopenharmony_ci int sz_first, sz_last; 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ci if (ioc == NULL) 281962306a36Sopenharmony_ci return; 282062306a36Sopenharmony_ci 282162306a36Sopenharmony_ci sz_first = ioc->alloc_total; 282262306a36Sopenharmony_ci 282362306a36Sopenharmony_ci mpt_adapter_disable(ioc); 282462306a36Sopenharmony_ci 282562306a36Sopenharmony_ci if (ioc->pci_irq != -1) { 282662306a36Sopenharmony_ci free_irq(ioc->pci_irq, ioc); 282762306a36Sopenharmony_ci if (ioc->msi_enable) 282862306a36Sopenharmony_ci pci_disable_msi(ioc->pcidev); 282962306a36Sopenharmony_ci ioc->pci_irq = -1; 283062306a36Sopenharmony_ci } 283162306a36Sopenharmony_ci 283262306a36Sopenharmony_ci if (ioc->memmap != NULL) { 283362306a36Sopenharmony_ci iounmap(ioc->memmap); 283462306a36Sopenharmony_ci ioc->memmap = NULL; 283562306a36Sopenharmony_ci } 283662306a36Sopenharmony_ci 283762306a36Sopenharmony_ci pci_disable_device(ioc->pcidev); 283862306a36Sopenharmony_ci pci_release_selected_regions(ioc->pcidev, ioc->bars); 283962306a36Sopenharmony_ci 284062306a36Sopenharmony_ci /* Zap the adapter lookup ptr! */ 284162306a36Sopenharmony_ci list_del(&ioc->list); 284262306a36Sopenharmony_ci 284362306a36Sopenharmony_ci sz_last = ioc->alloc_total; 284462306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n", 284562306a36Sopenharmony_ci ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first)); 284662306a36Sopenharmony_ci 284762306a36Sopenharmony_ci if (ioc->alt_ioc) 284862306a36Sopenharmony_ci ioc->alt_ioc->alt_ioc = NULL; 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_ci kfree(ioc); 285162306a36Sopenharmony_ci} 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 285462306a36Sopenharmony_ci/** 285562306a36Sopenharmony_ci * MptDisplayIocCapabilities - Disply IOC's capabilities. 285662306a36Sopenharmony_ci * @ioc: Pointer to MPT adapter structure 285762306a36Sopenharmony_ci */ 285862306a36Sopenharmony_cistatic void 285962306a36Sopenharmony_ciMptDisplayIocCapabilities(MPT_ADAPTER *ioc) 286062306a36Sopenharmony_ci{ 286162306a36Sopenharmony_ci int i = 0; 286262306a36Sopenharmony_ci 286362306a36Sopenharmony_ci printk(KERN_INFO "%s: ", ioc->name); 286462306a36Sopenharmony_ci if (ioc->prod_name) 286562306a36Sopenharmony_ci pr_cont("%s: ", ioc->prod_name); 286662306a36Sopenharmony_ci pr_cont("Capabilities={"); 286762306a36Sopenharmony_ci 286862306a36Sopenharmony_ci if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) { 286962306a36Sopenharmony_ci pr_cont("Initiator"); 287062306a36Sopenharmony_ci i++; 287162306a36Sopenharmony_ci } 287262306a36Sopenharmony_ci 287362306a36Sopenharmony_ci if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) { 287462306a36Sopenharmony_ci pr_cont("%sTarget", i ? "," : ""); 287562306a36Sopenharmony_ci i++; 287662306a36Sopenharmony_ci } 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_ci if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { 287962306a36Sopenharmony_ci pr_cont("%sLAN", i ? "," : ""); 288062306a36Sopenharmony_ci i++; 288162306a36Sopenharmony_ci } 288262306a36Sopenharmony_ci 288362306a36Sopenharmony_ci#if 0 288462306a36Sopenharmony_ci /* 288562306a36Sopenharmony_ci * This would probably evoke more questions than it's worth 288662306a36Sopenharmony_ci */ 288762306a36Sopenharmony_ci if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) { 288862306a36Sopenharmony_ci pr_cont("%sLogBusAddr", i ? "," : ""); 288962306a36Sopenharmony_ci i++; 289062306a36Sopenharmony_ci } 289162306a36Sopenharmony_ci#endif 289262306a36Sopenharmony_ci 289362306a36Sopenharmony_ci pr_cont("}\n"); 289462306a36Sopenharmony_ci} 289562306a36Sopenharmony_ci 289662306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 289762306a36Sopenharmony_ci/** 289862306a36Sopenharmony_ci * MakeIocReady - Get IOC to a READY state, using KickStart if needed. 289962306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 290062306a36Sopenharmony_ci * @force: Force hard KickStart of IOC 290162306a36Sopenharmony_ci * @sleepFlag: Specifies whether the process can sleep 290262306a36Sopenharmony_ci * 290362306a36Sopenharmony_ci * Returns: 290462306a36Sopenharmony_ci * 1 - DIAG reset and READY 290562306a36Sopenharmony_ci * 0 - READY initially OR soft reset and READY 290662306a36Sopenharmony_ci * -1 - Any failure on KickStart 290762306a36Sopenharmony_ci * -2 - Msg Unit Reset Failed 290862306a36Sopenharmony_ci * -3 - IO Unit Reset Failed 290962306a36Sopenharmony_ci * -4 - IOC owned by a PEER 291062306a36Sopenharmony_ci */ 291162306a36Sopenharmony_cistatic int 291262306a36Sopenharmony_ciMakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) 291362306a36Sopenharmony_ci{ 291462306a36Sopenharmony_ci u32 ioc_state; 291562306a36Sopenharmony_ci int statefault = 0; 291662306a36Sopenharmony_ci int cntdn; 291762306a36Sopenharmony_ci int hard_reset_done = 0; 291862306a36Sopenharmony_ci int r; 291962306a36Sopenharmony_ci int ii; 292062306a36Sopenharmony_ci int whoinit; 292162306a36Sopenharmony_ci 292262306a36Sopenharmony_ci /* Get current [raw] IOC state */ 292362306a36Sopenharmony_ci ioc_state = mpt_GetIocState(ioc, 0); 292462306a36Sopenharmony_ci dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state)); 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci /* 292762306a36Sopenharmony_ci * Check to see if IOC got left/stuck in doorbell handshake 292862306a36Sopenharmony_ci * grip of death. If so, hard reset the IOC. 292962306a36Sopenharmony_ci */ 293062306a36Sopenharmony_ci if (ioc_state & MPI_DOORBELL_ACTIVE) { 293162306a36Sopenharmony_ci statefault = 1; 293262306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n", 293362306a36Sopenharmony_ci ioc->name); 293462306a36Sopenharmony_ci } 293562306a36Sopenharmony_ci 293662306a36Sopenharmony_ci /* Is it already READY? */ 293762306a36Sopenharmony_ci if (!statefault && 293862306a36Sopenharmony_ci ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) { 293962306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_INFO_FMT 294062306a36Sopenharmony_ci "IOC is in READY state\n", ioc->name)); 294162306a36Sopenharmony_ci return 0; 294262306a36Sopenharmony_ci } 294362306a36Sopenharmony_ci 294462306a36Sopenharmony_ci /* 294562306a36Sopenharmony_ci * Check to see if IOC is in FAULT state. 294662306a36Sopenharmony_ci */ 294762306a36Sopenharmony_ci if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { 294862306a36Sopenharmony_ci statefault = 2; 294962306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n", 295062306a36Sopenharmony_ci ioc->name); 295162306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n", 295262306a36Sopenharmony_ci ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK); 295362306a36Sopenharmony_ci } 295462306a36Sopenharmony_ci 295562306a36Sopenharmony_ci /* 295662306a36Sopenharmony_ci * Hmmm... Did it get left operational? 295762306a36Sopenharmony_ci */ 295862306a36Sopenharmony_ci if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) { 295962306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n", 296062306a36Sopenharmony_ci ioc->name)); 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_ci /* Check WhoInit. 296362306a36Sopenharmony_ci * If PCI Peer, exit. 296462306a36Sopenharmony_ci * Else, if no fault conditions are present, issue a MessageUnitReset 296562306a36Sopenharmony_ci * Else, fall through to KickStart case 296662306a36Sopenharmony_ci */ 296762306a36Sopenharmony_ci whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT; 296862306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_INFO_FMT 296962306a36Sopenharmony_ci "whoinit 0x%x statefault %d force %d\n", 297062306a36Sopenharmony_ci ioc->name, whoinit, statefault, force)); 297162306a36Sopenharmony_ci if (whoinit == MPI_WHOINIT_PCI_PEER) 297262306a36Sopenharmony_ci return -4; 297362306a36Sopenharmony_ci else { 297462306a36Sopenharmony_ci if ((statefault == 0 ) && (force == 0)) { 297562306a36Sopenharmony_ci if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0) 297662306a36Sopenharmony_ci return 0; 297762306a36Sopenharmony_ci } 297862306a36Sopenharmony_ci statefault = 3; 297962306a36Sopenharmony_ci } 298062306a36Sopenharmony_ci } 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_ci hard_reset_done = KickStart(ioc, statefault||force, sleepFlag); 298362306a36Sopenharmony_ci if (hard_reset_done < 0) 298462306a36Sopenharmony_ci return -1; 298562306a36Sopenharmony_ci 298662306a36Sopenharmony_ci /* 298762306a36Sopenharmony_ci * Loop here waiting for IOC to come READY. 298862306a36Sopenharmony_ci */ 298962306a36Sopenharmony_ci ii = 0; 299062306a36Sopenharmony_ci cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */ 299162306a36Sopenharmony_ci 299262306a36Sopenharmony_ci while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) { 299362306a36Sopenharmony_ci if (ioc_state == MPI_IOC_STATE_OPERATIONAL) { 299462306a36Sopenharmony_ci /* 299562306a36Sopenharmony_ci * BIOS or previous driver load left IOC in OP state. 299662306a36Sopenharmony_ci * Reset messaging FIFOs. 299762306a36Sopenharmony_ci */ 299862306a36Sopenharmony_ci if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) { 299962306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name); 300062306a36Sopenharmony_ci return -2; 300162306a36Sopenharmony_ci } 300262306a36Sopenharmony_ci } else if (ioc_state == MPI_IOC_STATE_RESET) { 300362306a36Sopenharmony_ci /* 300462306a36Sopenharmony_ci * Something is wrong. Try to get IOC back 300562306a36Sopenharmony_ci * to a known state. 300662306a36Sopenharmony_ci */ 300762306a36Sopenharmony_ci if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) { 300862306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name); 300962306a36Sopenharmony_ci return -3; 301062306a36Sopenharmony_ci } 301162306a36Sopenharmony_ci } 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci ii++; cntdn--; 301462306a36Sopenharmony_ci if (!cntdn) { 301562306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT 301662306a36Sopenharmony_ci "Wait IOC_READY state (0x%x) timeout(%d)!\n", 301762306a36Sopenharmony_ci ioc->name, ioc_state, (int)((ii+5)/HZ)); 301862306a36Sopenharmony_ci return -ETIME; 301962306a36Sopenharmony_ci } 302062306a36Sopenharmony_ci 302162306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) { 302262306a36Sopenharmony_ci msleep(1); 302362306a36Sopenharmony_ci } else { 302462306a36Sopenharmony_ci mdelay (1); /* 1 msec delay */ 302562306a36Sopenharmony_ci } 302662306a36Sopenharmony_ci 302762306a36Sopenharmony_ci } 302862306a36Sopenharmony_ci 302962306a36Sopenharmony_ci if (statefault < 3) { 303062306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name, 303162306a36Sopenharmony_ci statefault == 1 ? "stuck handshake" : "IOC FAULT"); 303262306a36Sopenharmony_ci } 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_ci return hard_reset_done; 303562306a36Sopenharmony_ci} 303662306a36Sopenharmony_ci 303762306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 303862306a36Sopenharmony_ci/** 303962306a36Sopenharmony_ci * mpt_GetIocState - Get the current state of a MPT adapter. 304062306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 304162306a36Sopenharmony_ci * @cooked: Request raw or cooked IOC state 304262306a36Sopenharmony_ci * 304362306a36Sopenharmony_ci * Returns all IOC Doorbell register bits if cooked==0, else just the 304462306a36Sopenharmony_ci * Doorbell bits in MPI_IOC_STATE_MASK. 304562306a36Sopenharmony_ci */ 304662306a36Sopenharmony_ciu32 304762306a36Sopenharmony_cimpt_GetIocState(MPT_ADAPTER *ioc, int cooked) 304862306a36Sopenharmony_ci{ 304962306a36Sopenharmony_ci u32 s, sc; 305062306a36Sopenharmony_ci 305162306a36Sopenharmony_ci /* Get! */ 305262306a36Sopenharmony_ci s = CHIPREG_READ32(&ioc->chip->Doorbell); 305362306a36Sopenharmony_ci sc = s & MPI_IOC_STATE_MASK; 305462306a36Sopenharmony_ci 305562306a36Sopenharmony_ci /* Save! */ 305662306a36Sopenharmony_ci ioc->last_state = sc; 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci return cooked ? sc : s; 305962306a36Sopenharmony_ci} 306062306a36Sopenharmony_ci 306162306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 306262306a36Sopenharmony_ci/** 306362306a36Sopenharmony_ci * GetIocFacts - Send IOCFacts request to MPT adapter. 306462306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 306562306a36Sopenharmony_ci * @sleepFlag: Specifies whether the process can sleep 306662306a36Sopenharmony_ci * @reason: If recovery, only update facts. 306762306a36Sopenharmony_ci * 306862306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure. 306962306a36Sopenharmony_ci */ 307062306a36Sopenharmony_cistatic int 307162306a36Sopenharmony_ciGetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) 307262306a36Sopenharmony_ci{ 307362306a36Sopenharmony_ci IOCFacts_t get_facts; 307462306a36Sopenharmony_ci IOCFactsReply_t *facts; 307562306a36Sopenharmony_ci int r; 307662306a36Sopenharmony_ci int req_sz; 307762306a36Sopenharmony_ci int reply_sz; 307862306a36Sopenharmony_ci int sz; 307962306a36Sopenharmony_ci u32 vv; 308062306a36Sopenharmony_ci u8 shiftFactor=1; 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_ci /* IOC *must* NOT be in RESET state! */ 308362306a36Sopenharmony_ci if (ioc->last_state == MPI_IOC_STATE_RESET) { 308462306a36Sopenharmony_ci printk(KERN_ERR MYNAM 308562306a36Sopenharmony_ci ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n", 308662306a36Sopenharmony_ci ioc->name, ioc->last_state); 308762306a36Sopenharmony_ci return -44; 308862306a36Sopenharmony_ci } 308962306a36Sopenharmony_ci 309062306a36Sopenharmony_ci facts = &ioc->facts; 309162306a36Sopenharmony_ci 309262306a36Sopenharmony_ci /* Destination (reply area)... */ 309362306a36Sopenharmony_ci reply_sz = sizeof(*facts); 309462306a36Sopenharmony_ci memset(facts, 0, reply_sz); 309562306a36Sopenharmony_ci 309662306a36Sopenharmony_ci /* Request area (get_facts on the stack right now!) */ 309762306a36Sopenharmony_ci req_sz = sizeof(get_facts); 309862306a36Sopenharmony_ci memset(&get_facts, 0, req_sz); 309962306a36Sopenharmony_ci 310062306a36Sopenharmony_ci get_facts.Function = MPI_FUNCTION_IOC_FACTS; 310162306a36Sopenharmony_ci /* Assert: All other get_facts fields are zero! */ 310262306a36Sopenharmony_ci 310362306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT 310462306a36Sopenharmony_ci "Sending get IocFacts request req_sz=%d reply_sz=%d\n", 310562306a36Sopenharmony_ci ioc->name, req_sz, reply_sz)); 310662306a36Sopenharmony_ci 310762306a36Sopenharmony_ci /* No non-zero fields in the get_facts request are greater than 310862306a36Sopenharmony_ci * 1 byte in size, so we can just fire it off as is. 310962306a36Sopenharmony_ci */ 311062306a36Sopenharmony_ci r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts, 311162306a36Sopenharmony_ci reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag); 311262306a36Sopenharmony_ci if (r != 0) 311362306a36Sopenharmony_ci return r; 311462306a36Sopenharmony_ci 311562306a36Sopenharmony_ci /* 311662306a36Sopenharmony_ci * Now byte swap (GRRR) the necessary fields before any further 311762306a36Sopenharmony_ci * inspection of reply contents. 311862306a36Sopenharmony_ci * 311962306a36Sopenharmony_ci * But need to do some sanity checks on MsgLength (byte) field 312062306a36Sopenharmony_ci * to make sure we don't zero IOC's req_sz! 312162306a36Sopenharmony_ci */ 312262306a36Sopenharmony_ci /* Did we get a valid reply? */ 312362306a36Sopenharmony_ci if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) { 312462306a36Sopenharmony_ci if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { 312562306a36Sopenharmony_ci /* 312662306a36Sopenharmony_ci * If not been here, done that, save off first WhoInit value 312762306a36Sopenharmony_ci */ 312862306a36Sopenharmony_ci if (ioc->FirstWhoInit == WHOINIT_UNKNOWN) 312962306a36Sopenharmony_ci ioc->FirstWhoInit = facts->WhoInit; 313062306a36Sopenharmony_ci } 313162306a36Sopenharmony_ci 313262306a36Sopenharmony_ci facts->MsgVersion = le16_to_cpu(facts->MsgVersion); 313362306a36Sopenharmony_ci facts->MsgContext = le32_to_cpu(facts->MsgContext); 313462306a36Sopenharmony_ci facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions); 313562306a36Sopenharmony_ci facts->IOCStatus = le16_to_cpu(facts->IOCStatus); 313662306a36Sopenharmony_ci facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo); 313762306a36Sopenharmony_ci /* CHECKME! IOCStatus, IOCLogInfo */ 313862306a36Sopenharmony_ci 313962306a36Sopenharmony_ci facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth); 314062306a36Sopenharmony_ci facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize); 314162306a36Sopenharmony_ci 314262306a36Sopenharmony_ci /* 314362306a36Sopenharmony_ci * FC f/w version changed between 1.1 and 1.2 314462306a36Sopenharmony_ci * Old: u16{Major(4),Minor(4),SubMinor(8)} 314562306a36Sopenharmony_ci * New: u32{Major(8),Minor(8),Unit(8),Dev(8)} 314662306a36Sopenharmony_ci */ 314762306a36Sopenharmony_ci if (facts->MsgVersion < MPI_VERSION_01_02) { 314862306a36Sopenharmony_ci /* 314962306a36Sopenharmony_ci * Handle old FC f/w style, convert to new... 315062306a36Sopenharmony_ci */ 315162306a36Sopenharmony_ci u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion); 315262306a36Sopenharmony_ci facts->FWVersion.Word = 315362306a36Sopenharmony_ci ((oldv<<12) & 0xFF000000) | 315462306a36Sopenharmony_ci ((oldv<<8) & 0x000FFF00); 315562306a36Sopenharmony_ci } else 315662306a36Sopenharmony_ci facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word); 315762306a36Sopenharmony_ci 315862306a36Sopenharmony_ci facts->ProductID = le16_to_cpu(facts->ProductID); 315962306a36Sopenharmony_ci 316062306a36Sopenharmony_ci if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK) 316162306a36Sopenharmony_ci > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) 316262306a36Sopenharmony_ci ioc->ir_firmware = 1; 316362306a36Sopenharmony_ci 316462306a36Sopenharmony_ci facts->CurrentHostMfaHighAddr = 316562306a36Sopenharmony_ci le32_to_cpu(facts->CurrentHostMfaHighAddr); 316662306a36Sopenharmony_ci facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits); 316762306a36Sopenharmony_ci facts->CurrentSenseBufferHighAddr = 316862306a36Sopenharmony_ci le32_to_cpu(facts->CurrentSenseBufferHighAddr); 316962306a36Sopenharmony_ci facts->CurReplyFrameSize = 317062306a36Sopenharmony_ci le16_to_cpu(facts->CurReplyFrameSize); 317162306a36Sopenharmony_ci facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities); 317262306a36Sopenharmony_ci 317362306a36Sopenharmony_ci /* 317462306a36Sopenharmony_ci * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx 317562306a36Sopenharmony_ci * Older MPI-1.00.xx struct had 13 dwords, and enlarged 317662306a36Sopenharmony_ci * to 14 in MPI-1.01.0x. 317762306a36Sopenharmony_ci */ 317862306a36Sopenharmony_ci if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 && 317962306a36Sopenharmony_ci facts->MsgVersion > MPI_VERSION_01_00) { 318062306a36Sopenharmony_ci facts->FWImageSize = le32_to_cpu(facts->FWImageSize); 318162306a36Sopenharmony_ci } 318262306a36Sopenharmony_ci 318362306a36Sopenharmony_ci facts->FWImageSize = ALIGN(facts->FWImageSize, 4); 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_ci if (!facts->RequestFrameSize) { 318662306a36Sopenharmony_ci /* Something is wrong! */ 318762306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n", 318862306a36Sopenharmony_ci ioc->name); 318962306a36Sopenharmony_ci return -55; 319062306a36Sopenharmony_ci } 319162306a36Sopenharmony_ci 319262306a36Sopenharmony_ci r = sz = facts->BlockSize; 319362306a36Sopenharmony_ci vv = ((63 / (sz * 4)) + 1) & 0x03; 319462306a36Sopenharmony_ci ioc->NB_for_64_byte_frame = vv; 319562306a36Sopenharmony_ci while ( sz ) 319662306a36Sopenharmony_ci { 319762306a36Sopenharmony_ci shiftFactor++; 319862306a36Sopenharmony_ci sz = sz >> 1; 319962306a36Sopenharmony_ci } 320062306a36Sopenharmony_ci ioc->NBShiftFactor = shiftFactor; 320162306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT 320262306a36Sopenharmony_ci "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n", 320362306a36Sopenharmony_ci ioc->name, vv, shiftFactor, r)); 320462306a36Sopenharmony_ci 320562306a36Sopenharmony_ci if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { 320662306a36Sopenharmony_ci /* 320762306a36Sopenharmony_ci * Set values for this IOC's request & reply frame sizes, 320862306a36Sopenharmony_ci * and request & reply queue depths... 320962306a36Sopenharmony_ci */ 321062306a36Sopenharmony_ci ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4); 321162306a36Sopenharmony_ci ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits); 321262306a36Sopenharmony_ci ioc->reply_sz = MPT_REPLY_FRAME_SIZE; 321362306a36Sopenharmony_ci ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth); 321462306a36Sopenharmony_ci 321562306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n", 321662306a36Sopenharmony_ci ioc->name, ioc->reply_sz, ioc->reply_depth)); 321762306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n", 321862306a36Sopenharmony_ci ioc->name, ioc->req_sz, ioc->req_depth)); 321962306a36Sopenharmony_ci 322062306a36Sopenharmony_ci /* Get port facts! */ 322162306a36Sopenharmony_ci if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 ) 322262306a36Sopenharmony_ci return r; 322362306a36Sopenharmony_ci } 322462306a36Sopenharmony_ci } else { 322562306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT 322662306a36Sopenharmony_ci "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n", 322762306a36Sopenharmony_ci ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t, 322862306a36Sopenharmony_ci RequestFrameSize)/sizeof(u32))); 322962306a36Sopenharmony_ci return -66; 323062306a36Sopenharmony_ci } 323162306a36Sopenharmony_ci 323262306a36Sopenharmony_ci return 0; 323362306a36Sopenharmony_ci} 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 323662306a36Sopenharmony_ci/** 323762306a36Sopenharmony_ci * GetPortFacts - Send PortFacts request to MPT adapter. 323862306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 323962306a36Sopenharmony_ci * @portnum: Port number 324062306a36Sopenharmony_ci * @sleepFlag: Specifies whether the process can sleep 324162306a36Sopenharmony_ci * 324262306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure. 324362306a36Sopenharmony_ci */ 324462306a36Sopenharmony_cistatic int 324562306a36Sopenharmony_ciGetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag) 324662306a36Sopenharmony_ci{ 324762306a36Sopenharmony_ci PortFacts_t get_pfacts; 324862306a36Sopenharmony_ci PortFactsReply_t *pfacts; 324962306a36Sopenharmony_ci int ii; 325062306a36Sopenharmony_ci int req_sz; 325162306a36Sopenharmony_ci int reply_sz; 325262306a36Sopenharmony_ci int max_id; 325362306a36Sopenharmony_ci 325462306a36Sopenharmony_ci /* IOC *must* NOT be in RESET state! */ 325562306a36Sopenharmony_ci if (ioc->last_state == MPI_IOC_STATE_RESET) { 325662306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n", 325762306a36Sopenharmony_ci ioc->name, ioc->last_state ); 325862306a36Sopenharmony_ci return -4; 325962306a36Sopenharmony_ci } 326062306a36Sopenharmony_ci 326162306a36Sopenharmony_ci pfacts = &ioc->pfacts[portnum]; 326262306a36Sopenharmony_ci 326362306a36Sopenharmony_ci /* Destination (reply area)... */ 326462306a36Sopenharmony_ci reply_sz = sizeof(*pfacts); 326562306a36Sopenharmony_ci memset(pfacts, 0, reply_sz); 326662306a36Sopenharmony_ci 326762306a36Sopenharmony_ci /* Request area (get_pfacts on the stack right now!) */ 326862306a36Sopenharmony_ci req_sz = sizeof(get_pfacts); 326962306a36Sopenharmony_ci memset(&get_pfacts, 0, req_sz); 327062306a36Sopenharmony_ci 327162306a36Sopenharmony_ci get_pfacts.Function = MPI_FUNCTION_PORT_FACTS; 327262306a36Sopenharmony_ci get_pfacts.PortNumber = portnum; 327362306a36Sopenharmony_ci /* Assert: All other get_pfacts fields are zero! */ 327462306a36Sopenharmony_ci 327562306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n", 327662306a36Sopenharmony_ci ioc->name, portnum)); 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_ci /* No non-zero fields in the get_pfacts request are greater than 327962306a36Sopenharmony_ci * 1 byte in size, so we can just fire it off as is. 328062306a36Sopenharmony_ci */ 328162306a36Sopenharmony_ci ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts, 328262306a36Sopenharmony_ci reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag); 328362306a36Sopenharmony_ci if (ii != 0) 328462306a36Sopenharmony_ci return ii; 328562306a36Sopenharmony_ci 328662306a36Sopenharmony_ci /* Did we get a valid reply? */ 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_ci /* Now byte swap the necessary fields in the response. */ 328962306a36Sopenharmony_ci pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext); 329062306a36Sopenharmony_ci pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus); 329162306a36Sopenharmony_ci pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo); 329262306a36Sopenharmony_ci pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices); 329362306a36Sopenharmony_ci pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID); 329462306a36Sopenharmony_ci pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags); 329562306a36Sopenharmony_ci pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers); 329662306a36Sopenharmony_ci pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs); 329762306a36Sopenharmony_ci pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets); 329862306a36Sopenharmony_ci 329962306a36Sopenharmony_ci max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID : 330062306a36Sopenharmony_ci pfacts->MaxDevices; 330162306a36Sopenharmony_ci ioc->devices_per_bus = (max_id > 255) ? 256 : max_id; 330262306a36Sopenharmony_ci ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256; 330362306a36Sopenharmony_ci 330462306a36Sopenharmony_ci /* 330562306a36Sopenharmony_ci * Place all the devices on channels 330662306a36Sopenharmony_ci * 330762306a36Sopenharmony_ci * (for debuging) 330862306a36Sopenharmony_ci */ 330962306a36Sopenharmony_ci if (mpt_channel_mapping) { 331062306a36Sopenharmony_ci ioc->devices_per_bus = 1; 331162306a36Sopenharmony_ci ioc->number_of_buses = (max_id > 255) ? 255 : max_id; 331262306a36Sopenharmony_ci } 331362306a36Sopenharmony_ci 331462306a36Sopenharmony_ci return 0; 331562306a36Sopenharmony_ci} 331662306a36Sopenharmony_ci 331762306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 331862306a36Sopenharmony_ci/** 331962306a36Sopenharmony_ci * SendIocInit - Send IOCInit request to MPT adapter. 332062306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 332162306a36Sopenharmony_ci * @sleepFlag: Specifies whether the process can sleep 332262306a36Sopenharmony_ci * 332362306a36Sopenharmony_ci * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state. 332462306a36Sopenharmony_ci * 332562306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure. 332662306a36Sopenharmony_ci */ 332762306a36Sopenharmony_cistatic int 332862306a36Sopenharmony_ciSendIocInit(MPT_ADAPTER *ioc, int sleepFlag) 332962306a36Sopenharmony_ci{ 333062306a36Sopenharmony_ci IOCInit_t ioc_init; 333162306a36Sopenharmony_ci MPIDefaultReply_t init_reply; 333262306a36Sopenharmony_ci u32 state; 333362306a36Sopenharmony_ci int r; 333462306a36Sopenharmony_ci int count; 333562306a36Sopenharmony_ci int cntdn; 333662306a36Sopenharmony_ci 333762306a36Sopenharmony_ci memset(&ioc_init, 0, sizeof(ioc_init)); 333862306a36Sopenharmony_ci memset(&init_reply, 0, sizeof(init_reply)); 333962306a36Sopenharmony_ci 334062306a36Sopenharmony_ci ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER; 334162306a36Sopenharmony_ci ioc_init.Function = MPI_FUNCTION_IOC_INIT; 334262306a36Sopenharmony_ci 334362306a36Sopenharmony_ci /* If we are in a recovery mode and we uploaded the FW image, 334462306a36Sopenharmony_ci * then this pointer is not NULL. Skip the upload a second time. 334562306a36Sopenharmony_ci * Set this flag if cached_fw set for either IOC. 334662306a36Sopenharmony_ci */ 334762306a36Sopenharmony_ci if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) 334862306a36Sopenharmony_ci ioc->upload_fw = 1; 334962306a36Sopenharmony_ci else 335062306a36Sopenharmony_ci ioc->upload_fw = 0; 335162306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n", 335262306a36Sopenharmony_ci ioc->name, ioc->upload_fw, ioc->facts.Flags)); 335362306a36Sopenharmony_ci 335462306a36Sopenharmony_ci ioc_init.MaxDevices = (U8)ioc->devices_per_bus; 335562306a36Sopenharmony_ci ioc_init.MaxBuses = (U8)ioc->number_of_buses; 335662306a36Sopenharmony_ci 335762306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n", 335862306a36Sopenharmony_ci ioc->name, ioc->facts.MsgVersion)); 335962306a36Sopenharmony_ci if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) { 336062306a36Sopenharmony_ci // set MsgVersion and HeaderVersion host driver was built with 336162306a36Sopenharmony_ci ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION); 336262306a36Sopenharmony_ci ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION); 336362306a36Sopenharmony_ci 336462306a36Sopenharmony_ci if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) { 336562306a36Sopenharmony_ci ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE; 336662306a36Sopenharmony_ci } else if(mpt_host_page_alloc(ioc, &ioc_init)) 336762306a36Sopenharmony_ci return -99; 336862306a36Sopenharmony_ci } 336962306a36Sopenharmony_ci ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */ 337062306a36Sopenharmony_ci 337162306a36Sopenharmony_ci if (ioc->sg_addr_size == sizeof(u64)) { 337262306a36Sopenharmony_ci /* Save the upper 32-bits of the request 337362306a36Sopenharmony_ci * (reply) and sense buffers. 337462306a36Sopenharmony_ci */ 337562306a36Sopenharmony_ci ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32)); 337662306a36Sopenharmony_ci ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32)); 337762306a36Sopenharmony_ci } else { 337862306a36Sopenharmony_ci /* Force 32-bit addressing */ 337962306a36Sopenharmony_ci ioc_init.HostMfaHighAddr = cpu_to_le32(0); 338062306a36Sopenharmony_ci ioc_init.SenseBufferHighAddr = cpu_to_le32(0); 338162306a36Sopenharmony_ci } 338262306a36Sopenharmony_ci 338362306a36Sopenharmony_ci ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr; 338462306a36Sopenharmony_ci ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr; 338562306a36Sopenharmony_ci ioc->facts.MaxDevices = ioc_init.MaxDevices; 338662306a36Sopenharmony_ci ioc->facts.MaxBuses = ioc_init.MaxBuses; 338762306a36Sopenharmony_ci 338862306a36Sopenharmony_ci dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n", 338962306a36Sopenharmony_ci ioc->name, &ioc_init)); 339062306a36Sopenharmony_ci 339162306a36Sopenharmony_ci r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init, 339262306a36Sopenharmony_ci sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag); 339362306a36Sopenharmony_ci if (r != 0) { 339462306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r); 339562306a36Sopenharmony_ci return r; 339662306a36Sopenharmony_ci } 339762306a36Sopenharmony_ci 339862306a36Sopenharmony_ci /* No need to byte swap the multibyte fields in the reply 339962306a36Sopenharmony_ci * since we don't even look at its contents. 340062306a36Sopenharmony_ci */ 340162306a36Sopenharmony_ci 340262306a36Sopenharmony_ci dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n", 340362306a36Sopenharmony_ci ioc->name, &ioc_init)); 340462306a36Sopenharmony_ci 340562306a36Sopenharmony_ci if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) { 340662306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r); 340762306a36Sopenharmony_ci return r; 340862306a36Sopenharmony_ci } 340962306a36Sopenharmony_ci 341062306a36Sopenharmony_ci /* YIKES! SUPER IMPORTANT!!! 341162306a36Sopenharmony_ci * Poll IocState until _OPERATIONAL while IOC is doing 341262306a36Sopenharmony_ci * LoopInit and TargetDiscovery! 341362306a36Sopenharmony_ci */ 341462306a36Sopenharmony_ci count = 0; 341562306a36Sopenharmony_ci cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */ 341662306a36Sopenharmony_ci state = mpt_GetIocState(ioc, 1); 341762306a36Sopenharmony_ci while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) { 341862306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) { 341962306a36Sopenharmony_ci msleep(1); 342062306a36Sopenharmony_ci } else { 342162306a36Sopenharmony_ci mdelay(1); 342262306a36Sopenharmony_ci } 342362306a36Sopenharmony_ci 342462306a36Sopenharmony_ci if (!cntdn) { 342562306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n", 342662306a36Sopenharmony_ci ioc->name, (int)((count+5)/HZ)); 342762306a36Sopenharmony_ci return -9; 342862306a36Sopenharmony_ci } 342962306a36Sopenharmony_ci 343062306a36Sopenharmony_ci state = mpt_GetIocState(ioc, 1); 343162306a36Sopenharmony_ci count++; 343262306a36Sopenharmony_ci } 343362306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n", 343462306a36Sopenharmony_ci ioc->name, count)); 343562306a36Sopenharmony_ci 343662306a36Sopenharmony_ci ioc->aen_event_read_flag=0; 343762306a36Sopenharmony_ci return r; 343862306a36Sopenharmony_ci} 343962306a36Sopenharmony_ci 344062306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 344162306a36Sopenharmony_ci/** 344262306a36Sopenharmony_ci * SendPortEnable - Send PortEnable request to MPT adapter port. 344362306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 344462306a36Sopenharmony_ci * @portnum: Port number to enable 344562306a36Sopenharmony_ci * @sleepFlag: Specifies whether the process can sleep 344662306a36Sopenharmony_ci * 344762306a36Sopenharmony_ci * Send PortEnable to bring IOC to OPERATIONAL state. 344862306a36Sopenharmony_ci * 344962306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure. 345062306a36Sopenharmony_ci */ 345162306a36Sopenharmony_cistatic int 345262306a36Sopenharmony_ciSendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) 345362306a36Sopenharmony_ci{ 345462306a36Sopenharmony_ci PortEnable_t port_enable; 345562306a36Sopenharmony_ci MPIDefaultReply_t reply_buf; 345662306a36Sopenharmony_ci int rc; 345762306a36Sopenharmony_ci int req_sz; 345862306a36Sopenharmony_ci int reply_sz; 345962306a36Sopenharmony_ci 346062306a36Sopenharmony_ci /* Destination... */ 346162306a36Sopenharmony_ci reply_sz = sizeof(MPIDefaultReply_t); 346262306a36Sopenharmony_ci memset(&reply_buf, 0, reply_sz); 346362306a36Sopenharmony_ci 346462306a36Sopenharmony_ci req_sz = sizeof(PortEnable_t); 346562306a36Sopenharmony_ci memset(&port_enable, 0, req_sz); 346662306a36Sopenharmony_ci 346762306a36Sopenharmony_ci port_enable.Function = MPI_FUNCTION_PORT_ENABLE; 346862306a36Sopenharmony_ci port_enable.PortNumber = portnum; 346962306a36Sopenharmony_ci/* port_enable.ChainOffset = 0; */ 347062306a36Sopenharmony_ci/* port_enable.MsgFlags = 0; */ 347162306a36Sopenharmony_ci/* port_enable.MsgContext = 0; */ 347262306a36Sopenharmony_ci 347362306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n", 347462306a36Sopenharmony_ci ioc->name, portnum, &port_enable)); 347562306a36Sopenharmony_ci 347662306a36Sopenharmony_ci /* RAID FW may take a long time to enable 347762306a36Sopenharmony_ci */ 347862306a36Sopenharmony_ci if (ioc->ir_firmware || ioc->bus_type == SAS) { 347962306a36Sopenharmony_ci rc = mpt_handshake_req_reply_wait(ioc, req_sz, 348062306a36Sopenharmony_ci (u32*)&port_enable, reply_sz, (u16*)&reply_buf, 348162306a36Sopenharmony_ci 300 /*seconds*/, sleepFlag); 348262306a36Sopenharmony_ci } else { 348362306a36Sopenharmony_ci rc = mpt_handshake_req_reply_wait(ioc, req_sz, 348462306a36Sopenharmony_ci (u32*)&port_enable, reply_sz, (u16*)&reply_buf, 348562306a36Sopenharmony_ci 30 /*seconds*/, sleepFlag); 348662306a36Sopenharmony_ci } 348762306a36Sopenharmony_ci return rc; 348862306a36Sopenharmony_ci} 348962306a36Sopenharmony_ci 349062306a36Sopenharmony_ci/** 349162306a36Sopenharmony_ci * mpt_alloc_fw_memory - allocate firmware memory 349262306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 349362306a36Sopenharmony_ci * @size: total FW bytes 349462306a36Sopenharmony_ci * 349562306a36Sopenharmony_ci * If memory has already been allocated, the same (cached) value 349662306a36Sopenharmony_ci * is returned. 349762306a36Sopenharmony_ci * 349862306a36Sopenharmony_ci * Return 0 if successful, or non-zero for failure 349962306a36Sopenharmony_ci **/ 350062306a36Sopenharmony_ciint 350162306a36Sopenharmony_cimpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size) 350262306a36Sopenharmony_ci{ 350362306a36Sopenharmony_ci int rc; 350462306a36Sopenharmony_ci 350562306a36Sopenharmony_ci if (ioc->cached_fw) { 350662306a36Sopenharmony_ci rc = 0; /* use already allocated memory */ 350762306a36Sopenharmony_ci goto out; 350862306a36Sopenharmony_ci } 350962306a36Sopenharmony_ci else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) { 351062306a36Sopenharmony_ci ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */ 351162306a36Sopenharmony_ci ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma; 351262306a36Sopenharmony_ci rc = 0; 351362306a36Sopenharmony_ci goto out; 351462306a36Sopenharmony_ci } 351562306a36Sopenharmony_ci ioc->cached_fw = dma_alloc_coherent(&ioc->pcidev->dev, size, 351662306a36Sopenharmony_ci &ioc->cached_fw_dma, GFP_ATOMIC); 351762306a36Sopenharmony_ci if (!ioc->cached_fw) { 351862306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n", 351962306a36Sopenharmony_ci ioc->name); 352062306a36Sopenharmony_ci rc = -1; 352162306a36Sopenharmony_ci } else { 352262306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n", 352362306a36Sopenharmony_ci ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size)); 352462306a36Sopenharmony_ci ioc->alloc_total += size; 352562306a36Sopenharmony_ci rc = 0; 352662306a36Sopenharmony_ci } 352762306a36Sopenharmony_ci out: 352862306a36Sopenharmony_ci return rc; 352962306a36Sopenharmony_ci} 353062306a36Sopenharmony_ci 353162306a36Sopenharmony_ci/** 353262306a36Sopenharmony_ci * mpt_free_fw_memory - free firmware memory 353362306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 353462306a36Sopenharmony_ci * 353562306a36Sopenharmony_ci * If alt_img is NULL, delete from ioc structure. 353662306a36Sopenharmony_ci * Else, delete a secondary image in same format. 353762306a36Sopenharmony_ci **/ 353862306a36Sopenharmony_civoid 353962306a36Sopenharmony_cimpt_free_fw_memory(MPT_ADAPTER *ioc) 354062306a36Sopenharmony_ci{ 354162306a36Sopenharmony_ci int sz; 354262306a36Sopenharmony_ci 354362306a36Sopenharmony_ci if (!ioc->cached_fw) 354462306a36Sopenharmony_ci return; 354562306a36Sopenharmony_ci 354662306a36Sopenharmony_ci sz = ioc->facts.FWImageSize; 354762306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n", 354862306a36Sopenharmony_ci ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); 354962306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, sz, ioc->cached_fw, 355062306a36Sopenharmony_ci ioc->cached_fw_dma); 355162306a36Sopenharmony_ci ioc->alloc_total -= sz; 355262306a36Sopenharmony_ci ioc->cached_fw = NULL; 355362306a36Sopenharmony_ci} 355462306a36Sopenharmony_ci 355562306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 355662306a36Sopenharmony_ci/** 355762306a36Sopenharmony_ci * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port. 355862306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 355962306a36Sopenharmony_ci * @sleepFlag: Specifies whether the process can sleep 356062306a36Sopenharmony_ci * 356162306a36Sopenharmony_ci * Returns 0 for success, >0 for handshake failure 356262306a36Sopenharmony_ci * <0 for fw upload failure. 356362306a36Sopenharmony_ci * 356462306a36Sopenharmony_ci * Remark: If bound IOC and a successful FWUpload was performed 356562306a36Sopenharmony_ci * on the bound IOC, the second image is discarded 356662306a36Sopenharmony_ci * and memory is free'd. Both channels must upload to prevent 356762306a36Sopenharmony_ci * IOC from running in degraded mode. 356862306a36Sopenharmony_ci */ 356962306a36Sopenharmony_cistatic int 357062306a36Sopenharmony_cimpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) 357162306a36Sopenharmony_ci{ 357262306a36Sopenharmony_ci u8 reply[sizeof(FWUploadReply_t)]; 357362306a36Sopenharmony_ci FWUpload_t *prequest; 357462306a36Sopenharmony_ci FWUploadReply_t *preply; 357562306a36Sopenharmony_ci FWUploadTCSGE_t *ptcsge; 357662306a36Sopenharmony_ci u32 flagsLength; 357762306a36Sopenharmony_ci int ii, sz, reply_sz; 357862306a36Sopenharmony_ci int cmdStatus; 357962306a36Sopenharmony_ci int request_size; 358062306a36Sopenharmony_ci /* If the image size is 0, we are done. 358162306a36Sopenharmony_ci */ 358262306a36Sopenharmony_ci if ((sz = ioc->facts.FWImageSize) == 0) 358362306a36Sopenharmony_ci return 0; 358462306a36Sopenharmony_ci 358562306a36Sopenharmony_ci if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0) 358662306a36Sopenharmony_ci return -ENOMEM; 358762306a36Sopenharmony_ci 358862306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n", 358962306a36Sopenharmony_ci ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); 359062306a36Sopenharmony_ci 359162306a36Sopenharmony_ci prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) : 359262306a36Sopenharmony_ci kzalloc(ioc->req_sz, GFP_KERNEL); 359362306a36Sopenharmony_ci if (!prequest) { 359462306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed " 359562306a36Sopenharmony_ci "while allocating memory \n", ioc->name)); 359662306a36Sopenharmony_ci mpt_free_fw_memory(ioc); 359762306a36Sopenharmony_ci return -ENOMEM; 359862306a36Sopenharmony_ci } 359962306a36Sopenharmony_ci 360062306a36Sopenharmony_ci preply = (FWUploadReply_t *)&reply; 360162306a36Sopenharmony_ci 360262306a36Sopenharmony_ci reply_sz = sizeof(reply); 360362306a36Sopenharmony_ci memset(preply, 0, reply_sz); 360462306a36Sopenharmony_ci 360562306a36Sopenharmony_ci prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM; 360662306a36Sopenharmony_ci prequest->Function = MPI_FUNCTION_FW_UPLOAD; 360762306a36Sopenharmony_ci 360862306a36Sopenharmony_ci ptcsge = (FWUploadTCSGE_t *) &prequest->SGL; 360962306a36Sopenharmony_ci ptcsge->DetailsLength = 12; 361062306a36Sopenharmony_ci ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT; 361162306a36Sopenharmony_ci ptcsge->ImageSize = cpu_to_le32(sz); 361262306a36Sopenharmony_ci ptcsge++; 361362306a36Sopenharmony_ci 361462306a36Sopenharmony_ci flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz; 361562306a36Sopenharmony_ci ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma); 361662306a36Sopenharmony_ci request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) + 361762306a36Sopenharmony_ci ioc->SGE_size; 361862306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload " 361962306a36Sopenharmony_ci " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest, 362062306a36Sopenharmony_ci ioc->facts.FWImageSize, request_size)); 362162306a36Sopenharmony_ci DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest); 362262306a36Sopenharmony_ci 362362306a36Sopenharmony_ci ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest, 362462306a36Sopenharmony_ci reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag); 362562306a36Sopenharmony_ci 362662306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed " 362762306a36Sopenharmony_ci "rc=%x \n", ioc->name, ii)); 362862306a36Sopenharmony_ci 362962306a36Sopenharmony_ci cmdStatus = -EFAULT; 363062306a36Sopenharmony_ci if (ii == 0) { 363162306a36Sopenharmony_ci /* Handshake transfer was complete and successful. 363262306a36Sopenharmony_ci * Check the Reply Frame. 363362306a36Sopenharmony_ci */ 363462306a36Sopenharmony_ci int status; 363562306a36Sopenharmony_ci status = le16_to_cpu(preply->IOCStatus) & 363662306a36Sopenharmony_ci MPI_IOCSTATUS_MASK; 363762306a36Sopenharmony_ci if (status == MPI_IOCSTATUS_SUCCESS && 363862306a36Sopenharmony_ci ioc->facts.FWImageSize == 363962306a36Sopenharmony_ci le32_to_cpu(preply->ActualImageSize)) 364062306a36Sopenharmony_ci cmdStatus = 0; 364162306a36Sopenharmony_ci } 364262306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n", 364362306a36Sopenharmony_ci ioc->name, cmdStatus)); 364462306a36Sopenharmony_ci 364562306a36Sopenharmony_ci 364662306a36Sopenharmony_ci if (cmdStatus) { 364762306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, " 364862306a36Sopenharmony_ci "freeing image \n", ioc->name)); 364962306a36Sopenharmony_ci mpt_free_fw_memory(ioc); 365062306a36Sopenharmony_ci } 365162306a36Sopenharmony_ci kfree(prequest); 365262306a36Sopenharmony_ci 365362306a36Sopenharmony_ci return cmdStatus; 365462306a36Sopenharmony_ci} 365562306a36Sopenharmony_ci 365662306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 365762306a36Sopenharmony_ci/** 365862306a36Sopenharmony_ci * mpt_downloadboot - DownloadBoot code 365962306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 366062306a36Sopenharmony_ci * @pFwHeader: Pointer to firmware header info 366162306a36Sopenharmony_ci * @sleepFlag: Specifies whether the process can sleep 366262306a36Sopenharmony_ci * 366362306a36Sopenharmony_ci * FwDownloadBoot requires Programmed IO access. 366462306a36Sopenharmony_ci * 366562306a36Sopenharmony_ci * Returns 0 for success 366662306a36Sopenharmony_ci * -1 FW Image size is 0 366762306a36Sopenharmony_ci * -2 No valid cached_fw Pointer 366862306a36Sopenharmony_ci * <0 for fw upload failure. 366962306a36Sopenharmony_ci */ 367062306a36Sopenharmony_cistatic int 367162306a36Sopenharmony_cimpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag) 367262306a36Sopenharmony_ci{ 367362306a36Sopenharmony_ci MpiExtImageHeader_t *pExtImage; 367462306a36Sopenharmony_ci u32 fwSize; 367562306a36Sopenharmony_ci u32 diag0val; 367662306a36Sopenharmony_ci int count; 367762306a36Sopenharmony_ci u32 *ptrFw; 367862306a36Sopenharmony_ci u32 diagRwData; 367962306a36Sopenharmony_ci u32 nextImage; 368062306a36Sopenharmony_ci u32 load_addr; 368162306a36Sopenharmony_ci u32 ioc_state=0; 368262306a36Sopenharmony_ci 368362306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n", 368462306a36Sopenharmony_ci ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader)); 368562306a36Sopenharmony_ci 368662306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); 368762306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); 368862306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); 368962306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); 369062306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); 369162306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); 369262306a36Sopenharmony_ci 369362306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM)); 369462306a36Sopenharmony_ci 369562306a36Sopenharmony_ci /* wait 1 msec */ 369662306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) { 369762306a36Sopenharmony_ci msleep(1); 369862306a36Sopenharmony_ci } else { 369962306a36Sopenharmony_ci mdelay (1); 370062306a36Sopenharmony_ci } 370162306a36Sopenharmony_ci 370262306a36Sopenharmony_ci diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); 370362306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER); 370462306a36Sopenharmony_ci 370562306a36Sopenharmony_ci for (count = 0; count < 30; count ++) { 370662306a36Sopenharmony_ci diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); 370762306a36Sopenharmony_ci if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) { 370862306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n", 370962306a36Sopenharmony_ci ioc->name, count)); 371062306a36Sopenharmony_ci break; 371162306a36Sopenharmony_ci } 371262306a36Sopenharmony_ci /* wait .1 sec */ 371362306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) { 371462306a36Sopenharmony_ci msleep (100); 371562306a36Sopenharmony_ci } else { 371662306a36Sopenharmony_ci mdelay (100); 371762306a36Sopenharmony_ci } 371862306a36Sopenharmony_ci } 371962306a36Sopenharmony_ci 372062306a36Sopenharmony_ci if ( count == 30 ) { 372162306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! " 372262306a36Sopenharmony_ci "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n", 372362306a36Sopenharmony_ci ioc->name, diag0val)); 372462306a36Sopenharmony_ci return -3; 372562306a36Sopenharmony_ci } 372662306a36Sopenharmony_ci 372762306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); 372862306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); 372962306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); 373062306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); 373162306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); 373262306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); 373362306a36Sopenharmony_ci 373462306a36Sopenharmony_ci /* Set the DiagRwEn and Disable ARM bits */ 373562306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM)); 373662306a36Sopenharmony_ci 373762306a36Sopenharmony_ci fwSize = (pFwHeader->ImageSize + 3)/4; 373862306a36Sopenharmony_ci ptrFw = (u32 *) pFwHeader; 373962306a36Sopenharmony_ci 374062306a36Sopenharmony_ci /* Write the LoadStartAddress to the DiagRw Address Register 374162306a36Sopenharmony_ci * using Programmed IO 374262306a36Sopenharmony_ci */ 374362306a36Sopenharmony_ci if (ioc->errata_flag_1064) 374462306a36Sopenharmony_ci pci_enable_io_access(ioc->pcidev); 374562306a36Sopenharmony_ci 374662306a36Sopenharmony_ci CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress); 374762306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n", 374862306a36Sopenharmony_ci ioc->name, pFwHeader->LoadStartAddress)); 374962306a36Sopenharmony_ci 375062306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n", 375162306a36Sopenharmony_ci ioc->name, fwSize*4, ptrFw)); 375262306a36Sopenharmony_ci while (fwSize--) { 375362306a36Sopenharmony_ci CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++); 375462306a36Sopenharmony_ci } 375562306a36Sopenharmony_ci 375662306a36Sopenharmony_ci nextImage = pFwHeader->NextImageHeaderOffset; 375762306a36Sopenharmony_ci while (nextImage) { 375862306a36Sopenharmony_ci pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage); 375962306a36Sopenharmony_ci 376062306a36Sopenharmony_ci load_addr = pExtImage->LoadStartAddress; 376162306a36Sopenharmony_ci 376262306a36Sopenharmony_ci fwSize = (pExtImage->ImageSize + 3) >> 2; 376362306a36Sopenharmony_ci ptrFw = (u32 *)pExtImage; 376462306a36Sopenharmony_ci 376562306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n", 376662306a36Sopenharmony_ci ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr)); 376762306a36Sopenharmony_ci CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr); 376862306a36Sopenharmony_ci 376962306a36Sopenharmony_ci while (fwSize--) { 377062306a36Sopenharmony_ci CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++); 377162306a36Sopenharmony_ci } 377262306a36Sopenharmony_ci nextImage = pExtImage->NextImageHeaderOffset; 377362306a36Sopenharmony_ci } 377462306a36Sopenharmony_ci 377562306a36Sopenharmony_ci /* Write the IopResetVectorRegAddr */ 377662306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr)); 377762306a36Sopenharmony_ci CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr); 377862306a36Sopenharmony_ci 377962306a36Sopenharmony_ci /* Write the IopResetVectorValue */ 378062306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue)); 378162306a36Sopenharmony_ci CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue); 378262306a36Sopenharmony_ci 378362306a36Sopenharmony_ci /* Clear the internal flash bad bit - autoincrementing register, 378462306a36Sopenharmony_ci * so must do two writes. 378562306a36Sopenharmony_ci */ 378662306a36Sopenharmony_ci if (ioc->bus_type == SPI) { 378762306a36Sopenharmony_ci /* 378862306a36Sopenharmony_ci * 1030 and 1035 H/W errata, workaround to access 378962306a36Sopenharmony_ci * the ClearFlashBadSignatureBit 379062306a36Sopenharmony_ci */ 379162306a36Sopenharmony_ci CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); 379262306a36Sopenharmony_ci diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData); 379362306a36Sopenharmony_ci diagRwData |= 0x40000000; 379462306a36Sopenharmony_ci CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); 379562306a36Sopenharmony_ci CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData); 379662306a36Sopenharmony_ci 379762306a36Sopenharmony_ci } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ { 379862306a36Sopenharmony_ci diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); 379962306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | 380062306a36Sopenharmony_ci MPI_DIAG_CLEAR_FLASH_BAD_SIG); 380162306a36Sopenharmony_ci 380262306a36Sopenharmony_ci /* wait 1 msec */ 380362306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) { 380462306a36Sopenharmony_ci msleep (1); 380562306a36Sopenharmony_ci } else { 380662306a36Sopenharmony_ci mdelay (1); 380762306a36Sopenharmony_ci } 380862306a36Sopenharmony_ci } 380962306a36Sopenharmony_ci 381062306a36Sopenharmony_ci if (ioc->errata_flag_1064) 381162306a36Sopenharmony_ci pci_disable_io_access(ioc->pcidev); 381262306a36Sopenharmony_ci 381362306a36Sopenharmony_ci diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); 381462306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, " 381562306a36Sopenharmony_ci "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n", 381662306a36Sopenharmony_ci ioc->name, diag0val)); 381762306a36Sopenharmony_ci diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE); 381862306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n", 381962306a36Sopenharmony_ci ioc->name, diag0val)); 382062306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); 382162306a36Sopenharmony_ci 382262306a36Sopenharmony_ci /* Write 0xFF to reset the sequencer */ 382362306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); 382462306a36Sopenharmony_ci 382562306a36Sopenharmony_ci if (ioc->bus_type == SAS) { 382662306a36Sopenharmony_ci ioc_state = mpt_GetIocState(ioc, 0); 382762306a36Sopenharmony_ci if ( (GetIocFacts(ioc, sleepFlag, 382862306a36Sopenharmony_ci MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) { 382962306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n", 383062306a36Sopenharmony_ci ioc->name, ioc_state)); 383162306a36Sopenharmony_ci return -EFAULT; 383262306a36Sopenharmony_ci } 383362306a36Sopenharmony_ci } 383462306a36Sopenharmony_ci 383562306a36Sopenharmony_ci for (count=0; count<HZ*20; count++) { 383662306a36Sopenharmony_ci if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) { 383762306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT 383862306a36Sopenharmony_ci "downloadboot successful! (count=%d) IocState=%x\n", 383962306a36Sopenharmony_ci ioc->name, count, ioc_state)); 384062306a36Sopenharmony_ci if (ioc->bus_type == SAS) { 384162306a36Sopenharmony_ci return 0; 384262306a36Sopenharmony_ci } 384362306a36Sopenharmony_ci if ((SendIocInit(ioc, sleepFlag)) != 0) { 384462306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT 384562306a36Sopenharmony_ci "downloadboot: SendIocInit failed\n", 384662306a36Sopenharmony_ci ioc->name)); 384762306a36Sopenharmony_ci return -EFAULT; 384862306a36Sopenharmony_ci } 384962306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT 385062306a36Sopenharmony_ci "downloadboot: SendIocInit successful\n", 385162306a36Sopenharmony_ci ioc->name)); 385262306a36Sopenharmony_ci return 0; 385362306a36Sopenharmony_ci } 385462306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) { 385562306a36Sopenharmony_ci msleep (10); 385662306a36Sopenharmony_ci } else { 385762306a36Sopenharmony_ci mdelay (10); 385862306a36Sopenharmony_ci } 385962306a36Sopenharmony_ci } 386062306a36Sopenharmony_ci ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT 386162306a36Sopenharmony_ci "downloadboot failed! IocState=%x\n",ioc->name, ioc_state)); 386262306a36Sopenharmony_ci return -EFAULT; 386362306a36Sopenharmony_ci} 386462306a36Sopenharmony_ci 386562306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 386662306a36Sopenharmony_ci/** 386762306a36Sopenharmony_ci * KickStart - Perform hard reset of MPT adapter. 386862306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 386962306a36Sopenharmony_ci * @force: Force hard reset 387062306a36Sopenharmony_ci * @sleepFlag: Specifies whether the process can sleep 387162306a36Sopenharmony_ci * 387262306a36Sopenharmony_ci * This routine places MPT adapter in diagnostic mode via the 387362306a36Sopenharmony_ci * WriteSequence register, and then performs a hard reset of adapter 387462306a36Sopenharmony_ci * via the Diagnostic register. 387562306a36Sopenharmony_ci * 387662306a36Sopenharmony_ci * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread) 387762306a36Sopenharmony_ci * or NO_SLEEP (interrupt thread, use mdelay) 387862306a36Sopenharmony_ci * force - 1 if doorbell active, board fault state 387962306a36Sopenharmony_ci * board operational, IOC_RECOVERY or 388062306a36Sopenharmony_ci * IOC_BRINGUP and there is an alt_ioc. 388162306a36Sopenharmony_ci * 0 else 388262306a36Sopenharmony_ci * 388362306a36Sopenharmony_ci * Returns: 388462306a36Sopenharmony_ci * 1 - hard reset, READY 388562306a36Sopenharmony_ci * 0 - no reset due to History bit, READY 388662306a36Sopenharmony_ci * -1 - no reset due to History bit but not READY 388762306a36Sopenharmony_ci * OR reset but failed to come READY 388862306a36Sopenharmony_ci * -2 - no reset, could not enter DIAG mode 388962306a36Sopenharmony_ci * -3 - reset but bad FW bit 389062306a36Sopenharmony_ci */ 389162306a36Sopenharmony_cistatic int 389262306a36Sopenharmony_ciKickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) 389362306a36Sopenharmony_ci{ 389462306a36Sopenharmony_ci int hard_reset_done = 0; 389562306a36Sopenharmony_ci u32 ioc_state=0; 389662306a36Sopenharmony_ci int cnt,cntdn; 389762306a36Sopenharmony_ci 389862306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name)); 389962306a36Sopenharmony_ci if (ioc->bus_type == SPI) { 390062306a36Sopenharmony_ci /* Always issue a Msg Unit Reset first. This will clear some 390162306a36Sopenharmony_ci * SCSI bus hang conditions. 390262306a36Sopenharmony_ci */ 390362306a36Sopenharmony_ci SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag); 390462306a36Sopenharmony_ci 390562306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) { 390662306a36Sopenharmony_ci msleep (1000); 390762306a36Sopenharmony_ci } else { 390862306a36Sopenharmony_ci mdelay (1000); 390962306a36Sopenharmony_ci } 391062306a36Sopenharmony_ci } 391162306a36Sopenharmony_ci 391262306a36Sopenharmony_ci hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag); 391362306a36Sopenharmony_ci if (hard_reset_done < 0) 391462306a36Sopenharmony_ci return hard_reset_done; 391562306a36Sopenharmony_ci 391662306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n", 391762306a36Sopenharmony_ci ioc->name)); 391862306a36Sopenharmony_ci 391962306a36Sopenharmony_ci cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */ 392062306a36Sopenharmony_ci for (cnt=0; cnt<cntdn; cnt++) { 392162306a36Sopenharmony_ci ioc_state = mpt_GetIocState(ioc, 1); 392262306a36Sopenharmony_ci if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) { 392362306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n", 392462306a36Sopenharmony_ci ioc->name, cnt)); 392562306a36Sopenharmony_ci return hard_reset_done; 392662306a36Sopenharmony_ci } 392762306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) { 392862306a36Sopenharmony_ci msleep (10); 392962306a36Sopenharmony_ci } else { 393062306a36Sopenharmony_ci mdelay (10); 393162306a36Sopenharmony_ci } 393262306a36Sopenharmony_ci } 393362306a36Sopenharmony_ci 393462306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n", 393562306a36Sopenharmony_ci ioc->name, mpt_GetIocState(ioc, 0))); 393662306a36Sopenharmony_ci return -1; 393762306a36Sopenharmony_ci} 393862306a36Sopenharmony_ci 393962306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 394062306a36Sopenharmony_ci/** 394162306a36Sopenharmony_ci * mpt_diag_reset - Perform hard reset of the adapter. 394262306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 394362306a36Sopenharmony_ci * @ignore: Set if to honor and clear to ignore 394462306a36Sopenharmony_ci * the reset history bit 394562306a36Sopenharmony_ci * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread, 394662306a36Sopenharmony_ci * else set to NO_SLEEP (use mdelay instead) 394762306a36Sopenharmony_ci * 394862306a36Sopenharmony_ci * This routine places the adapter in diagnostic mode via the 394962306a36Sopenharmony_ci * WriteSequence register and then performs a hard reset of adapter 395062306a36Sopenharmony_ci * via the Diagnostic register. Adapter should be in ready state 395162306a36Sopenharmony_ci * upon successful completion. 395262306a36Sopenharmony_ci * 395362306a36Sopenharmony_ci * Returns: 1 hard reset successful 395462306a36Sopenharmony_ci * 0 no reset performed because reset history bit set 395562306a36Sopenharmony_ci * -2 enabling diagnostic mode failed 395662306a36Sopenharmony_ci * -3 diagnostic reset failed 395762306a36Sopenharmony_ci */ 395862306a36Sopenharmony_cistatic int 395962306a36Sopenharmony_cimpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) 396062306a36Sopenharmony_ci{ 396162306a36Sopenharmony_ci u32 diag0val; 396262306a36Sopenharmony_ci u32 doorbell; 396362306a36Sopenharmony_ci int hard_reset_done = 0; 396462306a36Sopenharmony_ci int count = 0; 396562306a36Sopenharmony_ci u32 diag1val = 0; 396662306a36Sopenharmony_ci MpiFwHeader_t *cached_fw; /* Pointer to FW */ 396762306a36Sopenharmony_ci u8 cb_idx; 396862306a36Sopenharmony_ci 396962306a36Sopenharmony_ci /* Clear any existing interrupts */ 397062306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); 397162306a36Sopenharmony_ci 397262306a36Sopenharmony_ci if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) { 397362306a36Sopenharmony_ci 397462306a36Sopenharmony_ci if (!ignore) 397562306a36Sopenharmony_ci return 0; 397662306a36Sopenharmony_ci 397762306a36Sopenharmony_ci drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset " 397862306a36Sopenharmony_ci "address=%p\n", ioc->name, __func__, 397962306a36Sopenharmony_ci &ioc->chip->Doorbell, &ioc->chip->Reset_1078)); 398062306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07); 398162306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) 398262306a36Sopenharmony_ci msleep(1); 398362306a36Sopenharmony_ci else 398462306a36Sopenharmony_ci mdelay(1); 398562306a36Sopenharmony_ci 398662306a36Sopenharmony_ci /* 398762306a36Sopenharmony_ci * Call each currently registered protocol IOC reset handler 398862306a36Sopenharmony_ci * with pre-reset indication. 398962306a36Sopenharmony_ci * NOTE: If we're doing _IOC_BRINGUP, there can be no 399062306a36Sopenharmony_ci * MptResetHandlers[] registered yet. 399162306a36Sopenharmony_ci */ 399262306a36Sopenharmony_ci for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { 399362306a36Sopenharmony_ci if (MptResetHandlers[cb_idx]) 399462306a36Sopenharmony_ci (*(MptResetHandlers[cb_idx]))(ioc, 399562306a36Sopenharmony_ci MPT_IOC_PRE_RESET); 399662306a36Sopenharmony_ci } 399762306a36Sopenharmony_ci 399862306a36Sopenharmony_ci for (count = 0; count < 60; count ++) { 399962306a36Sopenharmony_ci doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); 400062306a36Sopenharmony_ci doorbell &= MPI_IOC_STATE_MASK; 400162306a36Sopenharmony_ci 400262306a36Sopenharmony_ci drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT 400362306a36Sopenharmony_ci "looking for READY STATE: doorbell=%x" 400462306a36Sopenharmony_ci " count=%d\n", 400562306a36Sopenharmony_ci ioc->name, doorbell, count)); 400662306a36Sopenharmony_ci 400762306a36Sopenharmony_ci if (doorbell == MPI_IOC_STATE_READY) { 400862306a36Sopenharmony_ci return 1; 400962306a36Sopenharmony_ci } 401062306a36Sopenharmony_ci 401162306a36Sopenharmony_ci /* wait 1 sec */ 401262306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) 401362306a36Sopenharmony_ci msleep(1000); 401462306a36Sopenharmony_ci else 401562306a36Sopenharmony_ci mdelay(1000); 401662306a36Sopenharmony_ci } 401762306a36Sopenharmony_ci return -1; 401862306a36Sopenharmony_ci } 401962306a36Sopenharmony_ci 402062306a36Sopenharmony_ci /* Use "Diagnostic reset" method! (only thing available!) */ 402162306a36Sopenharmony_ci diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); 402262306a36Sopenharmony_ci 402362306a36Sopenharmony_ci if (ioc->debug_level & MPT_DEBUG) { 402462306a36Sopenharmony_ci if (ioc->alt_ioc) 402562306a36Sopenharmony_ci diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); 402662306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n", 402762306a36Sopenharmony_ci ioc->name, diag0val, diag1val)); 402862306a36Sopenharmony_ci } 402962306a36Sopenharmony_ci 403062306a36Sopenharmony_ci /* Do the reset if we are told to ignore the reset history 403162306a36Sopenharmony_ci * or if the reset history is 0 403262306a36Sopenharmony_ci */ 403362306a36Sopenharmony_ci if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) { 403462306a36Sopenharmony_ci while ((diag0val & MPI_DIAG_DRWE) == 0) { 403562306a36Sopenharmony_ci /* Write magic sequence to WriteSequence register 403662306a36Sopenharmony_ci * Loop until in diagnostic mode 403762306a36Sopenharmony_ci */ 403862306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); 403962306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); 404062306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); 404162306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); 404262306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); 404362306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); 404462306a36Sopenharmony_ci 404562306a36Sopenharmony_ci /* wait 100 msec */ 404662306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) { 404762306a36Sopenharmony_ci msleep (100); 404862306a36Sopenharmony_ci } else { 404962306a36Sopenharmony_ci mdelay (100); 405062306a36Sopenharmony_ci } 405162306a36Sopenharmony_ci 405262306a36Sopenharmony_ci count++; 405362306a36Sopenharmony_ci if (count > 20) { 405462306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n", 405562306a36Sopenharmony_ci ioc->name, diag0val); 405662306a36Sopenharmony_ci return -2; 405762306a36Sopenharmony_ci 405862306a36Sopenharmony_ci } 405962306a36Sopenharmony_ci 406062306a36Sopenharmony_ci diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); 406162306a36Sopenharmony_ci 406262306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n", 406362306a36Sopenharmony_ci ioc->name, diag0val)); 406462306a36Sopenharmony_ci } 406562306a36Sopenharmony_ci 406662306a36Sopenharmony_ci if (ioc->debug_level & MPT_DEBUG) { 406762306a36Sopenharmony_ci if (ioc->alt_ioc) 406862306a36Sopenharmony_ci diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); 406962306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n", 407062306a36Sopenharmony_ci ioc->name, diag0val, diag1val)); 407162306a36Sopenharmony_ci } 407262306a36Sopenharmony_ci /* 407362306a36Sopenharmony_ci * Disable the ARM (Bug fix) 407462306a36Sopenharmony_ci * 407562306a36Sopenharmony_ci */ 407662306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM); 407762306a36Sopenharmony_ci mdelay(1); 407862306a36Sopenharmony_ci 407962306a36Sopenharmony_ci /* 408062306a36Sopenharmony_ci * Now hit the reset bit in the Diagnostic register 408162306a36Sopenharmony_ci * (THE BIG HAMMER!) (Clears DRWE bit). 408262306a36Sopenharmony_ci */ 408362306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER); 408462306a36Sopenharmony_ci hard_reset_done = 1; 408562306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n", 408662306a36Sopenharmony_ci ioc->name)); 408762306a36Sopenharmony_ci 408862306a36Sopenharmony_ci /* 408962306a36Sopenharmony_ci * Call each currently registered protocol IOC reset handler 409062306a36Sopenharmony_ci * with pre-reset indication. 409162306a36Sopenharmony_ci * NOTE: If we're doing _IOC_BRINGUP, there can be no 409262306a36Sopenharmony_ci * MptResetHandlers[] registered yet. 409362306a36Sopenharmony_ci */ 409462306a36Sopenharmony_ci for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { 409562306a36Sopenharmony_ci if (MptResetHandlers[cb_idx]) { 409662306a36Sopenharmony_ci mpt_signal_reset(cb_idx, 409762306a36Sopenharmony_ci ioc, MPT_IOC_PRE_RESET); 409862306a36Sopenharmony_ci if (ioc->alt_ioc) { 409962306a36Sopenharmony_ci mpt_signal_reset(cb_idx, 410062306a36Sopenharmony_ci ioc->alt_ioc, MPT_IOC_PRE_RESET); 410162306a36Sopenharmony_ci } 410262306a36Sopenharmony_ci } 410362306a36Sopenharmony_ci } 410462306a36Sopenharmony_ci 410562306a36Sopenharmony_ci if (ioc->cached_fw) 410662306a36Sopenharmony_ci cached_fw = (MpiFwHeader_t *)ioc->cached_fw; 410762306a36Sopenharmony_ci else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) 410862306a36Sopenharmony_ci cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw; 410962306a36Sopenharmony_ci else 411062306a36Sopenharmony_ci cached_fw = NULL; 411162306a36Sopenharmony_ci if (cached_fw) { 411262306a36Sopenharmony_ci /* If the DownloadBoot operation fails, the 411362306a36Sopenharmony_ci * IOC will be left unusable. This is a fatal error 411462306a36Sopenharmony_ci * case. _diag_reset will return < 0 411562306a36Sopenharmony_ci */ 411662306a36Sopenharmony_ci for (count = 0; count < 30; count ++) { 411762306a36Sopenharmony_ci diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); 411862306a36Sopenharmony_ci if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) { 411962306a36Sopenharmony_ci break; 412062306a36Sopenharmony_ci } 412162306a36Sopenharmony_ci 412262306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n", 412362306a36Sopenharmony_ci ioc->name, diag0val, count)); 412462306a36Sopenharmony_ci /* wait 1 sec */ 412562306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) { 412662306a36Sopenharmony_ci msleep (1000); 412762306a36Sopenharmony_ci } else { 412862306a36Sopenharmony_ci mdelay (1000); 412962306a36Sopenharmony_ci } 413062306a36Sopenharmony_ci } 413162306a36Sopenharmony_ci if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) { 413262306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 413362306a36Sopenharmony_ci "firmware downloadboot failure (%d)!\n", ioc->name, count); 413462306a36Sopenharmony_ci } 413562306a36Sopenharmony_ci 413662306a36Sopenharmony_ci } else { 413762306a36Sopenharmony_ci /* Wait for FW to reload and for board 413862306a36Sopenharmony_ci * to go to the READY state. 413962306a36Sopenharmony_ci * Maximum wait is 60 seconds. 414062306a36Sopenharmony_ci * If fail, no error will check again 414162306a36Sopenharmony_ci * with calling program. 414262306a36Sopenharmony_ci */ 414362306a36Sopenharmony_ci for (count = 0; count < 60; count ++) { 414462306a36Sopenharmony_ci doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); 414562306a36Sopenharmony_ci doorbell &= MPI_IOC_STATE_MASK; 414662306a36Sopenharmony_ci 414762306a36Sopenharmony_ci drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT 414862306a36Sopenharmony_ci "looking for READY STATE: doorbell=%x" 414962306a36Sopenharmony_ci " count=%d\n", ioc->name, doorbell, count)); 415062306a36Sopenharmony_ci 415162306a36Sopenharmony_ci if (doorbell == MPI_IOC_STATE_READY) { 415262306a36Sopenharmony_ci break; 415362306a36Sopenharmony_ci } 415462306a36Sopenharmony_ci 415562306a36Sopenharmony_ci /* wait 1 sec */ 415662306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) { 415762306a36Sopenharmony_ci msleep (1000); 415862306a36Sopenharmony_ci } else { 415962306a36Sopenharmony_ci mdelay (1000); 416062306a36Sopenharmony_ci } 416162306a36Sopenharmony_ci } 416262306a36Sopenharmony_ci 416362306a36Sopenharmony_ci if (doorbell != MPI_IOC_STATE_READY) 416462306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "Failed to come READY " 416562306a36Sopenharmony_ci "after reset! IocState=%x", ioc->name, 416662306a36Sopenharmony_ci doorbell); 416762306a36Sopenharmony_ci } 416862306a36Sopenharmony_ci } 416962306a36Sopenharmony_ci 417062306a36Sopenharmony_ci diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); 417162306a36Sopenharmony_ci if (ioc->debug_level & MPT_DEBUG) { 417262306a36Sopenharmony_ci if (ioc->alt_ioc) 417362306a36Sopenharmony_ci diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); 417462306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n", 417562306a36Sopenharmony_ci ioc->name, diag0val, diag1val)); 417662306a36Sopenharmony_ci } 417762306a36Sopenharmony_ci 417862306a36Sopenharmony_ci /* Clear RESET_HISTORY bit! Place board in the 417962306a36Sopenharmony_ci * diagnostic mode to update the diag register. 418062306a36Sopenharmony_ci */ 418162306a36Sopenharmony_ci diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); 418262306a36Sopenharmony_ci count = 0; 418362306a36Sopenharmony_ci while ((diag0val & MPI_DIAG_DRWE) == 0) { 418462306a36Sopenharmony_ci /* Write magic sequence to WriteSequence register 418562306a36Sopenharmony_ci * Loop until in diagnostic mode 418662306a36Sopenharmony_ci */ 418762306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); 418862306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); 418962306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); 419062306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); 419162306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); 419262306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); 419362306a36Sopenharmony_ci 419462306a36Sopenharmony_ci /* wait 100 msec */ 419562306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) { 419662306a36Sopenharmony_ci msleep (100); 419762306a36Sopenharmony_ci } else { 419862306a36Sopenharmony_ci mdelay (100); 419962306a36Sopenharmony_ci } 420062306a36Sopenharmony_ci 420162306a36Sopenharmony_ci count++; 420262306a36Sopenharmony_ci if (count > 20) { 420362306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n", 420462306a36Sopenharmony_ci ioc->name, diag0val); 420562306a36Sopenharmony_ci break; 420662306a36Sopenharmony_ci } 420762306a36Sopenharmony_ci diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); 420862306a36Sopenharmony_ci } 420962306a36Sopenharmony_ci diag0val &= ~MPI_DIAG_RESET_HISTORY; 421062306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); 421162306a36Sopenharmony_ci diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); 421262306a36Sopenharmony_ci if (diag0val & MPI_DIAG_RESET_HISTORY) { 421362306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n", 421462306a36Sopenharmony_ci ioc->name); 421562306a36Sopenharmony_ci } 421662306a36Sopenharmony_ci 421762306a36Sopenharmony_ci /* Disable Diagnostic Mode 421862306a36Sopenharmony_ci */ 421962306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF); 422062306a36Sopenharmony_ci 422162306a36Sopenharmony_ci /* Check FW reload status flags. 422262306a36Sopenharmony_ci */ 422362306a36Sopenharmony_ci diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); 422462306a36Sopenharmony_ci if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) { 422562306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n", 422662306a36Sopenharmony_ci ioc->name, diag0val); 422762306a36Sopenharmony_ci return -3; 422862306a36Sopenharmony_ci } 422962306a36Sopenharmony_ci 423062306a36Sopenharmony_ci if (ioc->debug_level & MPT_DEBUG) { 423162306a36Sopenharmony_ci if (ioc->alt_ioc) 423262306a36Sopenharmony_ci diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); 423362306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n", 423462306a36Sopenharmony_ci ioc->name, diag0val, diag1val)); 423562306a36Sopenharmony_ci } 423662306a36Sopenharmony_ci 423762306a36Sopenharmony_ci /* 423862306a36Sopenharmony_ci * Reset flag that says we've enabled event notification 423962306a36Sopenharmony_ci */ 424062306a36Sopenharmony_ci ioc->facts.EventState = 0; 424162306a36Sopenharmony_ci 424262306a36Sopenharmony_ci if (ioc->alt_ioc) 424362306a36Sopenharmony_ci ioc->alt_ioc->facts.EventState = 0; 424462306a36Sopenharmony_ci 424562306a36Sopenharmony_ci return hard_reset_done; 424662306a36Sopenharmony_ci} 424762306a36Sopenharmony_ci 424862306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 424962306a36Sopenharmony_ci/** 425062306a36Sopenharmony_ci * SendIocReset - Send IOCReset request to MPT adapter. 425162306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 425262306a36Sopenharmony_ci * @reset_type: reset type, expected values are 425362306a36Sopenharmony_ci * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET 425462306a36Sopenharmony_ci * @sleepFlag: Specifies whether the process can sleep 425562306a36Sopenharmony_ci * 425662306a36Sopenharmony_ci * Send IOCReset request to the MPT adapter. 425762306a36Sopenharmony_ci * 425862306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure. 425962306a36Sopenharmony_ci */ 426062306a36Sopenharmony_cistatic int 426162306a36Sopenharmony_ciSendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag) 426262306a36Sopenharmony_ci{ 426362306a36Sopenharmony_ci int r; 426462306a36Sopenharmony_ci u32 state; 426562306a36Sopenharmony_ci int cntdn, count; 426662306a36Sopenharmony_ci 426762306a36Sopenharmony_ci drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n", 426862306a36Sopenharmony_ci ioc->name, reset_type)); 426962306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT); 427062306a36Sopenharmony_ci if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) 427162306a36Sopenharmony_ci return r; 427262306a36Sopenharmony_ci 427362306a36Sopenharmony_ci /* FW ACK'd request, wait for READY state 427462306a36Sopenharmony_ci */ 427562306a36Sopenharmony_ci count = 0; 427662306a36Sopenharmony_ci cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */ 427762306a36Sopenharmony_ci 427862306a36Sopenharmony_ci while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) { 427962306a36Sopenharmony_ci cntdn--; 428062306a36Sopenharmony_ci count++; 428162306a36Sopenharmony_ci if (!cntdn) { 428262306a36Sopenharmony_ci if (sleepFlag != CAN_SLEEP) 428362306a36Sopenharmony_ci count *= 10; 428462306a36Sopenharmony_ci 428562306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT 428662306a36Sopenharmony_ci "Wait IOC_READY state (0x%x) timeout(%d)!\n", 428762306a36Sopenharmony_ci ioc->name, state, (int)((count+5)/HZ)); 428862306a36Sopenharmony_ci return -ETIME; 428962306a36Sopenharmony_ci } 429062306a36Sopenharmony_ci 429162306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) { 429262306a36Sopenharmony_ci msleep(1); 429362306a36Sopenharmony_ci } else { 429462306a36Sopenharmony_ci mdelay (1); /* 1 msec delay */ 429562306a36Sopenharmony_ci } 429662306a36Sopenharmony_ci } 429762306a36Sopenharmony_ci 429862306a36Sopenharmony_ci /* TODO! 429962306a36Sopenharmony_ci * Cleanup all event stuff for this IOC; re-issue EventNotification 430062306a36Sopenharmony_ci * request if needed. 430162306a36Sopenharmony_ci */ 430262306a36Sopenharmony_ci if (ioc->facts.Function) 430362306a36Sopenharmony_ci ioc->facts.EventState = 0; 430462306a36Sopenharmony_ci 430562306a36Sopenharmony_ci return 0; 430662306a36Sopenharmony_ci} 430762306a36Sopenharmony_ci 430862306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 430962306a36Sopenharmony_ci/** 431062306a36Sopenharmony_ci * initChainBuffers - Allocate memory for and initialize chain buffers 431162306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 431262306a36Sopenharmony_ci * 431362306a36Sopenharmony_ci * Allocates memory for and initializes chain buffers, 431462306a36Sopenharmony_ci * chain buffer control arrays and spinlock. 431562306a36Sopenharmony_ci */ 431662306a36Sopenharmony_cistatic int 431762306a36Sopenharmony_ciinitChainBuffers(MPT_ADAPTER *ioc) 431862306a36Sopenharmony_ci{ 431962306a36Sopenharmony_ci u8 *mem; 432062306a36Sopenharmony_ci int sz, ii, num_chain; 432162306a36Sopenharmony_ci int scale, num_sge, numSGE; 432262306a36Sopenharmony_ci 432362306a36Sopenharmony_ci /* ReqToChain size must equal the req_depth 432462306a36Sopenharmony_ci * index = req_idx 432562306a36Sopenharmony_ci */ 432662306a36Sopenharmony_ci if (ioc->ReqToChain == NULL) { 432762306a36Sopenharmony_ci sz = ioc->req_depth * sizeof(int); 432862306a36Sopenharmony_ci mem = kmalloc(sz, GFP_ATOMIC); 432962306a36Sopenharmony_ci if (mem == NULL) 433062306a36Sopenharmony_ci return -1; 433162306a36Sopenharmony_ci 433262306a36Sopenharmony_ci ioc->ReqToChain = (int *) mem; 433362306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n", 433462306a36Sopenharmony_ci ioc->name, mem, sz)); 433562306a36Sopenharmony_ci mem = kmalloc(sz, GFP_ATOMIC); 433662306a36Sopenharmony_ci if (mem == NULL) 433762306a36Sopenharmony_ci return -1; 433862306a36Sopenharmony_ci 433962306a36Sopenharmony_ci ioc->RequestNB = (int *) mem; 434062306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n", 434162306a36Sopenharmony_ci ioc->name, mem, sz)); 434262306a36Sopenharmony_ci } 434362306a36Sopenharmony_ci for (ii = 0; ii < ioc->req_depth; ii++) { 434462306a36Sopenharmony_ci ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN; 434562306a36Sopenharmony_ci } 434662306a36Sopenharmony_ci 434762306a36Sopenharmony_ci /* ChainToChain size must equal the total number 434862306a36Sopenharmony_ci * of chain buffers to be allocated. 434962306a36Sopenharmony_ci * index = chain_idx 435062306a36Sopenharmony_ci * 435162306a36Sopenharmony_ci * Calculate the number of chain buffers needed(plus 1) per I/O 435262306a36Sopenharmony_ci * then multiply the maximum number of simultaneous cmds 435362306a36Sopenharmony_ci * 435462306a36Sopenharmony_ci * num_sge = num sge in request frame + last chain buffer 435562306a36Sopenharmony_ci * scale = num sge per chain buffer if no chain element 435662306a36Sopenharmony_ci */ 435762306a36Sopenharmony_ci scale = ioc->req_sz / ioc->SGE_size; 435862306a36Sopenharmony_ci if (ioc->sg_addr_size == sizeof(u64)) 435962306a36Sopenharmony_ci num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size; 436062306a36Sopenharmony_ci else 436162306a36Sopenharmony_ci num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size; 436262306a36Sopenharmony_ci 436362306a36Sopenharmony_ci if (ioc->sg_addr_size == sizeof(u64)) { 436462306a36Sopenharmony_ci numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale + 436562306a36Sopenharmony_ci (ioc->req_sz - 60) / ioc->SGE_size; 436662306a36Sopenharmony_ci } else { 436762306a36Sopenharmony_ci numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + 436862306a36Sopenharmony_ci scale + (ioc->req_sz - 64) / ioc->SGE_size; 436962306a36Sopenharmony_ci } 437062306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n", 437162306a36Sopenharmony_ci ioc->name, num_sge, numSGE)); 437262306a36Sopenharmony_ci 437362306a36Sopenharmony_ci if (ioc->bus_type == FC) { 437462306a36Sopenharmony_ci if (numSGE > MPT_SCSI_FC_SG_DEPTH) 437562306a36Sopenharmony_ci numSGE = MPT_SCSI_FC_SG_DEPTH; 437662306a36Sopenharmony_ci } else { 437762306a36Sopenharmony_ci if (numSGE > MPT_SCSI_SG_DEPTH) 437862306a36Sopenharmony_ci numSGE = MPT_SCSI_SG_DEPTH; 437962306a36Sopenharmony_ci } 438062306a36Sopenharmony_ci 438162306a36Sopenharmony_ci num_chain = 1; 438262306a36Sopenharmony_ci while (numSGE - num_sge > 0) { 438362306a36Sopenharmony_ci num_chain++; 438462306a36Sopenharmony_ci num_sge += (scale - 1); 438562306a36Sopenharmony_ci } 438662306a36Sopenharmony_ci num_chain++; 438762306a36Sopenharmony_ci 438862306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n", 438962306a36Sopenharmony_ci ioc->name, numSGE, num_sge, num_chain)); 439062306a36Sopenharmony_ci 439162306a36Sopenharmony_ci if (ioc->bus_type == SPI) 439262306a36Sopenharmony_ci num_chain *= MPT_SCSI_CAN_QUEUE; 439362306a36Sopenharmony_ci else if (ioc->bus_type == SAS) 439462306a36Sopenharmony_ci num_chain *= MPT_SAS_CAN_QUEUE; 439562306a36Sopenharmony_ci else 439662306a36Sopenharmony_ci num_chain *= MPT_FC_CAN_QUEUE; 439762306a36Sopenharmony_ci 439862306a36Sopenharmony_ci ioc->num_chain = num_chain; 439962306a36Sopenharmony_ci 440062306a36Sopenharmony_ci sz = num_chain * sizeof(int); 440162306a36Sopenharmony_ci if (ioc->ChainToChain == NULL) { 440262306a36Sopenharmony_ci mem = kmalloc(sz, GFP_ATOMIC); 440362306a36Sopenharmony_ci if (mem == NULL) 440462306a36Sopenharmony_ci return -1; 440562306a36Sopenharmony_ci 440662306a36Sopenharmony_ci ioc->ChainToChain = (int *) mem; 440762306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n", 440862306a36Sopenharmony_ci ioc->name, mem, sz)); 440962306a36Sopenharmony_ci } else { 441062306a36Sopenharmony_ci mem = (u8 *) ioc->ChainToChain; 441162306a36Sopenharmony_ci } 441262306a36Sopenharmony_ci memset(mem, 0xFF, sz); 441362306a36Sopenharmony_ci return num_chain; 441462306a36Sopenharmony_ci} 441562306a36Sopenharmony_ci 441662306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 441762306a36Sopenharmony_ci/** 441862306a36Sopenharmony_ci * PrimeIocFifos - Initialize IOC request and reply FIFOs. 441962306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 442062306a36Sopenharmony_ci * 442162306a36Sopenharmony_ci * This routine allocates memory for the MPT reply and request frame 442262306a36Sopenharmony_ci * pools (if necessary), and primes the IOC reply FIFO with 442362306a36Sopenharmony_ci * reply frames. 442462306a36Sopenharmony_ci * 442562306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure. 442662306a36Sopenharmony_ci */ 442762306a36Sopenharmony_cistatic int 442862306a36Sopenharmony_ciPrimeIocFifos(MPT_ADAPTER *ioc) 442962306a36Sopenharmony_ci{ 443062306a36Sopenharmony_ci MPT_FRAME_HDR *mf; 443162306a36Sopenharmony_ci unsigned long flags; 443262306a36Sopenharmony_ci dma_addr_t alloc_dma; 443362306a36Sopenharmony_ci u8 *mem; 443462306a36Sopenharmony_ci int i, reply_sz, sz, total_size, num_chain; 443562306a36Sopenharmony_ci u64 dma_mask; 443662306a36Sopenharmony_ci 443762306a36Sopenharmony_ci dma_mask = 0; 443862306a36Sopenharmony_ci 443962306a36Sopenharmony_ci /* Prime reply FIFO... */ 444062306a36Sopenharmony_ci 444162306a36Sopenharmony_ci if (ioc->reply_frames == NULL) { 444262306a36Sopenharmony_ci if ( (num_chain = initChainBuffers(ioc)) < 0) 444362306a36Sopenharmony_ci return -1; 444462306a36Sopenharmony_ci /* 444562306a36Sopenharmony_ci * 1078 errata workaround for the 36GB limitation 444662306a36Sopenharmony_ci */ 444762306a36Sopenharmony_ci if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 && 444862306a36Sopenharmony_ci ioc->dma_mask > DMA_BIT_MASK(35)) { 444962306a36Sopenharmony_ci if (!dma_set_mask(&ioc->pcidev->dev, DMA_BIT_MASK(32)) 445062306a36Sopenharmony_ci && !dma_set_coherent_mask(&ioc->pcidev->dev, DMA_BIT_MASK(32))) { 445162306a36Sopenharmony_ci dma_mask = DMA_BIT_MASK(35); 445262306a36Sopenharmony_ci d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT 445362306a36Sopenharmony_ci "setting 35 bit addressing for " 445462306a36Sopenharmony_ci "Request/Reply/Chain and Sense Buffers\n", 445562306a36Sopenharmony_ci ioc->name)); 445662306a36Sopenharmony_ci } else { 445762306a36Sopenharmony_ci /*Reseting DMA mask to 64 bit*/ 445862306a36Sopenharmony_ci dma_set_mask(&ioc->pcidev->dev, 445962306a36Sopenharmony_ci DMA_BIT_MASK(64)); 446062306a36Sopenharmony_ci dma_set_coherent_mask(&ioc->pcidev->dev, 446162306a36Sopenharmony_ci DMA_BIT_MASK(64)); 446262306a36Sopenharmony_ci 446362306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT 446462306a36Sopenharmony_ci "failed setting 35 bit addressing for " 446562306a36Sopenharmony_ci "Request/Reply/Chain and Sense Buffers\n", 446662306a36Sopenharmony_ci ioc->name); 446762306a36Sopenharmony_ci return -1; 446862306a36Sopenharmony_ci } 446962306a36Sopenharmony_ci } 447062306a36Sopenharmony_ci 447162306a36Sopenharmony_ci total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth); 447262306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n", 447362306a36Sopenharmony_ci ioc->name, ioc->reply_sz, ioc->reply_depth)); 447462306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n", 447562306a36Sopenharmony_ci ioc->name, reply_sz, reply_sz)); 447662306a36Sopenharmony_ci 447762306a36Sopenharmony_ci sz = (ioc->req_sz * ioc->req_depth); 447862306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n", 447962306a36Sopenharmony_ci ioc->name, ioc->req_sz, ioc->req_depth)); 448062306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n", 448162306a36Sopenharmony_ci ioc->name, sz, sz)); 448262306a36Sopenharmony_ci total_size += sz; 448362306a36Sopenharmony_ci 448462306a36Sopenharmony_ci sz = num_chain * ioc->req_sz; /* chain buffer pool size */ 448562306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n", 448662306a36Sopenharmony_ci ioc->name, ioc->req_sz, num_chain)); 448762306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n", 448862306a36Sopenharmony_ci ioc->name, sz, sz, num_chain)); 448962306a36Sopenharmony_ci 449062306a36Sopenharmony_ci total_size += sz; 449162306a36Sopenharmony_ci mem = dma_alloc_coherent(&ioc->pcidev->dev, total_size, 449262306a36Sopenharmony_ci &alloc_dma, GFP_KERNEL); 449362306a36Sopenharmony_ci if (mem == NULL) { 449462306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n", 449562306a36Sopenharmony_ci ioc->name); 449662306a36Sopenharmony_ci goto out_fail; 449762306a36Sopenharmony_ci } 449862306a36Sopenharmony_ci 449962306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n", 450062306a36Sopenharmony_ci ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size)); 450162306a36Sopenharmony_ci 450262306a36Sopenharmony_ci memset(mem, 0, total_size); 450362306a36Sopenharmony_ci ioc->alloc_total += total_size; 450462306a36Sopenharmony_ci ioc->alloc = mem; 450562306a36Sopenharmony_ci ioc->alloc_dma = alloc_dma; 450662306a36Sopenharmony_ci ioc->alloc_sz = total_size; 450762306a36Sopenharmony_ci ioc->reply_frames = (MPT_FRAME_HDR *) mem; 450862306a36Sopenharmony_ci ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); 450962306a36Sopenharmony_ci 451062306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n", 451162306a36Sopenharmony_ci ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma)); 451262306a36Sopenharmony_ci 451362306a36Sopenharmony_ci alloc_dma += reply_sz; 451462306a36Sopenharmony_ci mem += reply_sz; 451562306a36Sopenharmony_ci 451662306a36Sopenharmony_ci /* Request FIFO - WE manage this! */ 451762306a36Sopenharmony_ci 451862306a36Sopenharmony_ci ioc->req_frames = (MPT_FRAME_HDR *) mem; 451962306a36Sopenharmony_ci ioc->req_frames_dma = alloc_dma; 452062306a36Sopenharmony_ci 452162306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n", 452262306a36Sopenharmony_ci ioc->name, mem, (void *)(ulong)alloc_dma)); 452362306a36Sopenharmony_ci 452462306a36Sopenharmony_ci ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); 452562306a36Sopenharmony_ci 452662306a36Sopenharmony_ci for (i = 0; i < ioc->req_depth; i++) { 452762306a36Sopenharmony_ci alloc_dma += ioc->req_sz; 452862306a36Sopenharmony_ci mem += ioc->req_sz; 452962306a36Sopenharmony_ci } 453062306a36Sopenharmony_ci 453162306a36Sopenharmony_ci ioc->ChainBuffer = mem; 453262306a36Sopenharmony_ci ioc->ChainBufferDMA = alloc_dma; 453362306a36Sopenharmony_ci 453462306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n", 453562306a36Sopenharmony_ci ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA)); 453662306a36Sopenharmony_ci 453762306a36Sopenharmony_ci /* Initialize the free chain Q. 453862306a36Sopenharmony_ci */ 453962306a36Sopenharmony_ci 454062306a36Sopenharmony_ci INIT_LIST_HEAD(&ioc->FreeChainQ); 454162306a36Sopenharmony_ci 454262306a36Sopenharmony_ci /* Post the chain buffers to the FreeChainQ. 454362306a36Sopenharmony_ci */ 454462306a36Sopenharmony_ci mem = (u8 *)ioc->ChainBuffer; 454562306a36Sopenharmony_ci for (i=0; i < num_chain; i++) { 454662306a36Sopenharmony_ci mf = (MPT_FRAME_HDR *) mem; 454762306a36Sopenharmony_ci list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ); 454862306a36Sopenharmony_ci mem += ioc->req_sz; 454962306a36Sopenharmony_ci } 455062306a36Sopenharmony_ci 455162306a36Sopenharmony_ci /* Initialize Request frames linked list 455262306a36Sopenharmony_ci */ 455362306a36Sopenharmony_ci alloc_dma = ioc->req_frames_dma; 455462306a36Sopenharmony_ci mem = (u8 *) ioc->req_frames; 455562306a36Sopenharmony_ci 455662306a36Sopenharmony_ci spin_lock_irqsave(&ioc->FreeQlock, flags); 455762306a36Sopenharmony_ci INIT_LIST_HEAD(&ioc->FreeQ); 455862306a36Sopenharmony_ci for (i = 0; i < ioc->req_depth; i++) { 455962306a36Sopenharmony_ci mf = (MPT_FRAME_HDR *) mem; 456062306a36Sopenharmony_ci 456162306a36Sopenharmony_ci /* Queue REQUESTs *internally*! */ 456262306a36Sopenharmony_ci list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ); 456362306a36Sopenharmony_ci 456462306a36Sopenharmony_ci mem += ioc->req_sz; 456562306a36Sopenharmony_ci } 456662306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->FreeQlock, flags); 456762306a36Sopenharmony_ci 456862306a36Sopenharmony_ci sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); 456962306a36Sopenharmony_ci ioc->sense_buf_pool = dma_alloc_coherent(&ioc->pcidev->dev, sz, 457062306a36Sopenharmony_ci &ioc->sense_buf_pool_dma, GFP_KERNEL); 457162306a36Sopenharmony_ci if (ioc->sense_buf_pool == NULL) { 457262306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n", 457362306a36Sopenharmony_ci ioc->name); 457462306a36Sopenharmony_ci goto out_fail; 457562306a36Sopenharmony_ci } 457662306a36Sopenharmony_ci 457762306a36Sopenharmony_ci ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF); 457862306a36Sopenharmony_ci ioc->alloc_total += sz; 457962306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n", 458062306a36Sopenharmony_ci ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma)); 458162306a36Sopenharmony_ci 458262306a36Sopenharmony_ci } 458362306a36Sopenharmony_ci 458462306a36Sopenharmony_ci /* Post Reply frames to FIFO 458562306a36Sopenharmony_ci */ 458662306a36Sopenharmony_ci alloc_dma = ioc->alloc_dma; 458762306a36Sopenharmony_ci dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n", 458862306a36Sopenharmony_ci ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma)); 458962306a36Sopenharmony_ci 459062306a36Sopenharmony_ci for (i = 0; i < ioc->reply_depth; i++) { 459162306a36Sopenharmony_ci /* Write each address to the IOC! */ 459262306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma); 459362306a36Sopenharmony_ci alloc_dma += ioc->reply_sz; 459462306a36Sopenharmony_ci } 459562306a36Sopenharmony_ci 459662306a36Sopenharmony_ci if (dma_mask == DMA_BIT_MASK(35) && !dma_set_mask(&ioc->pcidev->dev, 459762306a36Sopenharmony_ci ioc->dma_mask) && !dma_set_coherent_mask(&ioc->pcidev->dev, 459862306a36Sopenharmony_ci ioc->dma_mask)) 459962306a36Sopenharmony_ci d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT 460062306a36Sopenharmony_ci "restoring 64 bit addressing\n", ioc->name)); 460162306a36Sopenharmony_ci 460262306a36Sopenharmony_ci return 0; 460362306a36Sopenharmony_ci 460462306a36Sopenharmony_ciout_fail: 460562306a36Sopenharmony_ci 460662306a36Sopenharmony_ci if (ioc->alloc != NULL) { 460762306a36Sopenharmony_ci sz = ioc->alloc_sz; 460862306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, sz, ioc->alloc, 460962306a36Sopenharmony_ci ioc->alloc_dma); 461062306a36Sopenharmony_ci ioc->reply_frames = NULL; 461162306a36Sopenharmony_ci ioc->req_frames = NULL; 461262306a36Sopenharmony_ci ioc->alloc_total -= sz; 461362306a36Sopenharmony_ci } 461462306a36Sopenharmony_ci if (ioc->sense_buf_pool != NULL) { 461562306a36Sopenharmony_ci sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC); 461662306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, sz, ioc->sense_buf_pool, 461762306a36Sopenharmony_ci ioc->sense_buf_pool_dma); 461862306a36Sopenharmony_ci ioc->sense_buf_pool = NULL; 461962306a36Sopenharmony_ci } 462062306a36Sopenharmony_ci 462162306a36Sopenharmony_ci if (dma_mask == DMA_BIT_MASK(35) && !dma_set_mask(&ioc->pcidev->dev, 462262306a36Sopenharmony_ci DMA_BIT_MASK(64)) && !dma_set_coherent_mask(&ioc->pcidev->dev, 462362306a36Sopenharmony_ci DMA_BIT_MASK(64))) 462462306a36Sopenharmony_ci d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT 462562306a36Sopenharmony_ci "restoring 64 bit addressing\n", ioc->name)); 462662306a36Sopenharmony_ci 462762306a36Sopenharmony_ci return -1; 462862306a36Sopenharmony_ci} 462962306a36Sopenharmony_ci 463062306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 463162306a36Sopenharmony_ci/** 463262306a36Sopenharmony_ci * mpt_handshake_req_reply_wait - Send MPT request to and receive reply 463362306a36Sopenharmony_ci * from IOC via doorbell handshake method. 463462306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 463562306a36Sopenharmony_ci * @reqBytes: Size of the request in bytes 463662306a36Sopenharmony_ci * @req: Pointer to MPT request frame 463762306a36Sopenharmony_ci * @replyBytes: Expected size of the reply in bytes 463862306a36Sopenharmony_ci * @u16reply: Pointer to area where reply should be written 463962306a36Sopenharmony_ci * @maxwait: Max wait time for a reply (in seconds) 464062306a36Sopenharmony_ci * @sleepFlag: Specifies whether the process can sleep 464162306a36Sopenharmony_ci * 464262306a36Sopenharmony_ci * NOTES: It is the callers responsibility to byte-swap fields in the 464362306a36Sopenharmony_ci * request which are greater than 1 byte in size. It is also the 464462306a36Sopenharmony_ci * callers responsibility to byte-swap response fields which are 464562306a36Sopenharmony_ci * greater than 1 byte in size. 464662306a36Sopenharmony_ci * 464762306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure. 464862306a36Sopenharmony_ci */ 464962306a36Sopenharmony_cistatic int 465062306a36Sopenharmony_cimpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, 465162306a36Sopenharmony_ci int replyBytes, u16 *u16reply, int maxwait, int sleepFlag) 465262306a36Sopenharmony_ci{ 465362306a36Sopenharmony_ci MPIDefaultReply_t *mptReply; 465462306a36Sopenharmony_ci int failcnt = 0; 465562306a36Sopenharmony_ci int t; 465662306a36Sopenharmony_ci 465762306a36Sopenharmony_ci /* 465862306a36Sopenharmony_ci * Get ready to cache a handshake reply 465962306a36Sopenharmony_ci */ 466062306a36Sopenharmony_ci ioc->hs_reply_idx = 0; 466162306a36Sopenharmony_ci mptReply = (MPIDefaultReply_t *) ioc->hs_reply; 466262306a36Sopenharmony_ci mptReply->MsgLength = 0; 466362306a36Sopenharmony_ci 466462306a36Sopenharmony_ci /* 466562306a36Sopenharmony_ci * Make sure there are no doorbells (WRITE 0 to IntStatus reg), 466662306a36Sopenharmony_ci * then tell IOC that we want to handshake a request of N words. 466762306a36Sopenharmony_ci * (WRITE u32val to Doorbell reg). 466862306a36Sopenharmony_ci */ 466962306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); 467062306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->Doorbell, 467162306a36Sopenharmony_ci ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) | 467262306a36Sopenharmony_ci ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT))); 467362306a36Sopenharmony_ci 467462306a36Sopenharmony_ci /* 467562306a36Sopenharmony_ci * Wait for IOC's doorbell handshake int 467662306a36Sopenharmony_ci */ 467762306a36Sopenharmony_ci if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) 467862306a36Sopenharmony_ci failcnt++; 467962306a36Sopenharmony_ci 468062306a36Sopenharmony_ci dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n", 468162306a36Sopenharmony_ci ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); 468262306a36Sopenharmony_ci 468362306a36Sopenharmony_ci /* Read doorbell and check for active bit */ 468462306a36Sopenharmony_ci if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE)) 468562306a36Sopenharmony_ci return -1; 468662306a36Sopenharmony_ci 468762306a36Sopenharmony_ci /* 468862306a36Sopenharmony_ci * Clear doorbell int (WRITE 0 to IntStatus reg), 468962306a36Sopenharmony_ci * then wait for IOC to ACKnowledge that it's ready for 469062306a36Sopenharmony_ci * our handshake request. 469162306a36Sopenharmony_ci */ 469262306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); 469362306a36Sopenharmony_ci if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) 469462306a36Sopenharmony_ci failcnt++; 469562306a36Sopenharmony_ci 469662306a36Sopenharmony_ci if (!failcnt) { 469762306a36Sopenharmony_ci int ii; 469862306a36Sopenharmony_ci u8 *req_as_bytes = (u8 *) req; 469962306a36Sopenharmony_ci 470062306a36Sopenharmony_ci /* 470162306a36Sopenharmony_ci * Stuff request words via doorbell handshake, 470262306a36Sopenharmony_ci * with ACK from IOC for each. 470362306a36Sopenharmony_ci */ 470462306a36Sopenharmony_ci for (ii = 0; !failcnt && ii < reqBytes/4; ii++) { 470562306a36Sopenharmony_ci u32 word = ((req_as_bytes[(ii*4) + 0] << 0) | 470662306a36Sopenharmony_ci (req_as_bytes[(ii*4) + 1] << 8) | 470762306a36Sopenharmony_ci (req_as_bytes[(ii*4) + 2] << 16) | 470862306a36Sopenharmony_ci (req_as_bytes[(ii*4) + 3] << 24)); 470962306a36Sopenharmony_ci 471062306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->Doorbell, word); 471162306a36Sopenharmony_ci if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) 471262306a36Sopenharmony_ci failcnt++; 471362306a36Sopenharmony_ci } 471462306a36Sopenharmony_ci 471562306a36Sopenharmony_ci dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req)); 471662306a36Sopenharmony_ci DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req); 471762306a36Sopenharmony_ci 471862306a36Sopenharmony_ci dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n", 471962306a36Sopenharmony_ci ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : "")); 472062306a36Sopenharmony_ci 472162306a36Sopenharmony_ci /* 472262306a36Sopenharmony_ci * Wait for completion of doorbell handshake reply from the IOC 472362306a36Sopenharmony_ci */ 472462306a36Sopenharmony_ci if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0) 472562306a36Sopenharmony_ci failcnt++; 472662306a36Sopenharmony_ci 472762306a36Sopenharmony_ci dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n", 472862306a36Sopenharmony_ci ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : "")); 472962306a36Sopenharmony_ci 473062306a36Sopenharmony_ci /* 473162306a36Sopenharmony_ci * Copy out the cached reply... 473262306a36Sopenharmony_ci */ 473362306a36Sopenharmony_ci for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++) 473462306a36Sopenharmony_ci u16reply[ii] = ioc->hs_reply[ii]; 473562306a36Sopenharmony_ci } else { 473662306a36Sopenharmony_ci return -99; 473762306a36Sopenharmony_ci } 473862306a36Sopenharmony_ci 473962306a36Sopenharmony_ci return -failcnt; 474062306a36Sopenharmony_ci} 474162306a36Sopenharmony_ci 474262306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 474362306a36Sopenharmony_ci/** 474462306a36Sopenharmony_ci * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge 474562306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 474662306a36Sopenharmony_ci * @howlong: How long to wait (in seconds) 474762306a36Sopenharmony_ci * @sleepFlag: Specifies whether the process can sleep 474862306a36Sopenharmony_ci * 474962306a36Sopenharmony_ci * This routine waits (up to ~2 seconds max) for IOC doorbell 475062306a36Sopenharmony_ci * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS 475162306a36Sopenharmony_ci * bit in its IntStatus register being clear. 475262306a36Sopenharmony_ci * 475362306a36Sopenharmony_ci * Returns a negative value on failure, else wait loop count. 475462306a36Sopenharmony_ci */ 475562306a36Sopenharmony_cistatic int 475662306a36Sopenharmony_ciWaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag) 475762306a36Sopenharmony_ci{ 475862306a36Sopenharmony_ci int cntdn; 475962306a36Sopenharmony_ci int count = 0; 476062306a36Sopenharmony_ci u32 intstat=0; 476162306a36Sopenharmony_ci 476262306a36Sopenharmony_ci cntdn = 1000 * howlong; 476362306a36Sopenharmony_ci 476462306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) { 476562306a36Sopenharmony_ci while (--cntdn) { 476662306a36Sopenharmony_ci msleep (1); 476762306a36Sopenharmony_ci intstat = CHIPREG_READ32(&ioc->chip->IntStatus); 476862306a36Sopenharmony_ci if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS)) 476962306a36Sopenharmony_ci break; 477062306a36Sopenharmony_ci count++; 477162306a36Sopenharmony_ci } 477262306a36Sopenharmony_ci } else { 477362306a36Sopenharmony_ci while (--cntdn) { 477462306a36Sopenharmony_ci udelay (1000); 477562306a36Sopenharmony_ci intstat = CHIPREG_READ32(&ioc->chip->IntStatus); 477662306a36Sopenharmony_ci if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS)) 477762306a36Sopenharmony_ci break; 477862306a36Sopenharmony_ci count++; 477962306a36Sopenharmony_ci } 478062306a36Sopenharmony_ci } 478162306a36Sopenharmony_ci 478262306a36Sopenharmony_ci if (cntdn) { 478362306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n", 478462306a36Sopenharmony_ci ioc->name, count)); 478562306a36Sopenharmony_ci return count; 478662306a36Sopenharmony_ci } 478762306a36Sopenharmony_ci 478862306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n", 478962306a36Sopenharmony_ci ioc->name, count, intstat); 479062306a36Sopenharmony_ci return -1; 479162306a36Sopenharmony_ci} 479262306a36Sopenharmony_ci 479362306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 479462306a36Sopenharmony_ci/** 479562306a36Sopenharmony_ci * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit 479662306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 479762306a36Sopenharmony_ci * @howlong: How long to wait (in seconds) 479862306a36Sopenharmony_ci * @sleepFlag: Specifies whether the process can sleep 479962306a36Sopenharmony_ci * 480062306a36Sopenharmony_ci * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt 480162306a36Sopenharmony_ci * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register. 480262306a36Sopenharmony_ci * 480362306a36Sopenharmony_ci * Returns a negative value on failure, else wait loop count. 480462306a36Sopenharmony_ci */ 480562306a36Sopenharmony_cistatic int 480662306a36Sopenharmony_ciWaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag) 480762306a36Sopenharmony_ci{ 480862306a36Sopenharmony_ci int cntdn; 480962306a36Sopenharmony_ci int count = 0; 481062306a36Sopenharmony_ci u32 intstat=0; 481162306a36Sopenharmony_ci 481262306a36Sopenharmony_ci cntdn = 1000 * howlong; 481362306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) { 481462306a36Sopenharmony_ci while (--cntdn) { 481562306a36Sopenharmony_ci intstat = CHIPREG_READ32(&ioc->chip->IntStatus); 481662306a36Sopenharmony_ci if (intstat & MPI_HIS_DOORBELL_INTERRUPT) 481762306a36Sopenharmony_ci break; 481862306a36Sopenharmony_ci msleep(1); 481962306a36Sopenharmony_ci count++; 482062306a36Sopenharmony_ci } 482162306a36Sopenharmony_ci } else { 482262306a36Sopenharmony_ci while (--cntdn) { 482362306a36Sopenharmony_ci intstat = CHIPREG_READ32(&ioc->chip->IntStatus); 482462306a36Sopenharmony_ci if (intstat & MPI_HIS_DOORBELL_INTERRUPT) 482562306a36Sopenharmony_ci break; 482662306a36Sopenharmony_ci udelay (1000); 482762306a36Sopenharmony_ci count++; 482862306a36Sopenharmony_ci } 482962306a36Sopenharmony_ci } 483062306a36Sopenharmony_ci 483162306a36Sopenharmony_ci if (cntdn) { 483262306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n", 483362306a36Sopenharmony_ci ioc->name, count, howlong)); 483462306a36Sopenharmony_ci return count; 483562306a36Sopenharmony_ci } 483662306a36Sopenharmony_ci 483762306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n", 483862306a36Sopenharmony_ci ioc->name, count, intstat); 483962306a36Sopenharmony_ci return -1; 484062306a36Sopenharmony_ci} 484162306a36Sopenharmony_ci 484262306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 484362306a36Sopenharmony_ci/** 484462306a36Sopenharmony_ci * WaitForDoorbellReply - Wait for and capture an IOC handshake reply. 484562306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 484662306a36Sopenharmony_ci * @howlong: How long to wait (in seconds) 484762306a36Sopenharmony_ci * @sleepFlag: Specifies whether the process can sleep 484862306a36Sopenharmony_ci * 484962306a36Sopenharmony_ci * This routine polls the IOC for a handshake reply, 16 bits at a time. 485062306a36Sopenharmony_ci * Reply is cached to IOC private area large enough to hold a maximum 485162306a36Sopenharmony_ci * of 128 bytes of reply data. 485262306a36Sopenharmony_ci * 485362306a36Sopenharmony_ci * Returns a negative value on failure, else size of reply in WORDS. 485462306a36Sopenharmony_ci */ 485562306a36Sopenharmony_cistatic int 485662306a36Sopenharmony_ciWaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag) 485762306a36Sopenharmony_ci{ 485862306a36Sopenharmony_ci int u16cnt = 0; 485962306a36Sopenharmony_ci int failcnt = 0; 486062306a36Sopenharmony_ci int t; 486162306a36Sopenharmony_ci u16 *hs_reply = ioc->hs_reply; 486262306a36Sopenharmony_ci volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply; 486362306a36Sopenharmony_ci u16 hword; 486462306a36Sopenharmony_ci 486562306a36Sopenharmony_ci hs_reply[0] = hs_reply[1] = hs_reply[7] = 0; 486662306a36Sopenharmony_ci 486762306a36Sopenharmony_ci /* 486862306a36Sopenharmony_ci * Get first two u16's so we can look at IOC's intended reply MsgLength 486962306a36Sopenharmony_ci */ 487062306a36Sopenharmony_ci u16cnt=0; 487162306a36Sopenharmony_ci if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) { 487262306a36Sopenharmony_ci failcnt++; 487362306a36Sopenharmony_ci } else { 487462306a36Sopenharmony_ci hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); 487562306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); 487662306a36Sopenharmony_ci if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) 487762306a36Sopenharmony_ci failcnt++; 487862306a36Sopenharmony_ci else { 487962306a36Sopenharmony_ci hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); 488062306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); 488162306a36Sopenharmony_ci } 488262306a36Sopenharmony_ci } 488362306a36Sopenharmony_ci 488462306a36Sopenharmony_ci dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n", 488562306a36Sopenharmony_ci ioc->name, t, le32_to_cpu(*(u32 *)hs_reply), 488662306a36Sopenharmony_ci failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); 488762306a36Sopenharmony_ci 488862306a36Sopenharmony_ci /* 488962306a36Sopenharmony_ci * If no error (and IOC said MsgLength is > 0), piece together 489062306a36Sopenharmony_ci * reply 16 bits at a time. 489162306a36Sopenharmony_ci */ 489262306a36Sopenharmony_ci for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) { 489362306a36Sopenharmony_ci if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) 489462306a36Sopenharmony_ci failcnt++; 489562306a36Sopenharmony_ci hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); 489662306a36Sopenharmony_ci /* don't overflow our IOC hs_reply[] buffer! */ 489762306a36Sopenharmony_ci if (u16cnt < ARRAY_SIZE(ioc->hs_reply)) 489862306a36Sopenharmony_ci hs_reply[u16cnt] = hword; 489962306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); 490062306a36Sopenharmony_ci } 490162306a36Sopenharmony_ci 490262306a36Sopenharmony_ci if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) 490362306a36Sopenharmony_ci failcnt++; 490462306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); 490562306a36Sopenharmony_ci 490662306a36Sopenharmony_ci if (failcnt) { 490762306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n", 490862306a36Sopenharmony_ci ioc->name); 490962306a36Sopenharmony_ci return -failcnt; 491062306a36Sopenharmony_ci } 491162306a36Sopenharmony_ci#if 0 491262306a36Sopenharmony_ci else if (u16cnt != (2 * mptReply->MsgLength)) { 491362306a36Sopenharmony_ci return -101; 491462306a36Sopenharmony_ci } 491562306a36Sopenharmony_ci else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 491662306a36Sopenharmony_ci return -102; 491762306a36Sopenharmony_ci } 491862306a36Sopenharmony_ci#endif 491962306a36Sopenharmony_ci 492062306a36Sopenharmony_ci dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name)); 492162306a36Sopenharmony_ci DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply); 492262306a36Sopenharmony_ci 492362306a36Sopenharmony_ci dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n", 492462306a36Sopenharmony_ci ioc->name, t, u16cnt/2)); 492562306a36Sopenharmony_ci return u16cnt/2; 492662306a36Sopenharmony_ci} 492762306a36Sopenharmony_ci 492862306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 492962306a36Sopenharmony_ci/** 493062306a36Sopenharmony_ci * GetLanConfigPages - Fetch LANConfig pages. 493162306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 493262306a36Sopenharmony_ci * 493362306a36Sopenharmony_ci * Return: 0 for success 493462306a36Sopenharmony_ci * -ENOMEM if no memory available 493562306a36Sopenharmony_ci * -EPERM if not allowed due to ISR context 493662306a36Sopenharmony_ci * -EAGAIN if no msg frames currently available 493762306a36Sopenharmony_ci * -EFAULT for non-successful reply or no reply (timeout) 493862306a36Sopenharmony_ci */ 493962306a36Sopenharmony_cistatic int 494062306a36Sopenharmony_ciGetLanConfigPages(MPT_ADAPTER *ioc) 494162306a36Sopenharmony_ci{ 494262306a36Sopenharmony_ci ConfigPageHeader_t hdr; 494362306a36Sopenharmony_ci CONFIGPARMS cfg; 494462306a36Sopenharmony_ci LANPage0_t *ppage0_alloc; 494562306a36Sopenharmony_ci dma_addr_t page0_dma; 494662306a36Sopenharmony_ci LANPage1_t *ppage1_alloc; 494762306a36Sopenharmony_ci dma_addr_t page1_dma; 494862306a36Sopenharmony_ci int rc = 0; 494962306a36Sopenharmony_ci int data_sz; 495062306a36Sopenharmony_ci int copy_sz; 495162306a36Sopenharmony_ci 495262306a36Sopenharmony_ci /* Get LAN Page 0 header */ 495362306a36Sopenharmony_ci hdr.PageVersion = 0; 495462306a36Sopenharmony_ci hdr.PageLength = 0; 495562306a36Sopenharmony_ci hdr.PageNumber = 0; 495662306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_LAN; 495762306a36Sopenharmony_ci cfg.cfghdr.hdr = &hdr; 495862306a36Sopenharmony_ci cfg.physAddr = -1; 495962306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 496062306a36Sopenharmony_ci cfg.dir = 0; 496162306a36Sopenharmony_ci cfg.pageAddr = 0; 496262306a36Sopenharmony_ci cfg.timeout = 0; 496362306a36Sopenharmony_ci 496462306a36Sopenharmony_ci if ((rc = mpt_config(ioc, &cfg)) != 0) 496562306a36Sopenharmony_ci return rc; 496662306a36Sopenharmony_ci 496762306a36Sopenharmony_ci if (hdr.PageLength > 0) { 496862306a36Sopenharmony_ci data_sz = hdr.PageLength * 4; 496962306a36Sopenharmony_ci ppage0_alloc = dma_alloc_coherent(&ioc->pcidev->dev, data_sz, 497062306a36Sopenharmony_ci &page0_dma, GFP_KERNEL); 497162306a36Sopenharmony_ci rc = -ENOMEM; 497262306a36Sopenharmony_ci if (ppage0_alloc) { 497362306a36Sopenharmony_ci memset((u8 *)ppage0_alloc, 0, data_sz); 497462306a36Sopenharmony_ci cfg.physAddr = page0_dma; 497562306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 497662306a36Sopenharmony_ci 497762306a36Sopenharmony_ci if ((rc = mpt_config(ioc, &cfg)) == 0) { 497862306a36Sopenharmony_ci /* save the data */ 497962306a36Sopenharmony_ci copy_sz = min_t(int, sizeof(LANPage0_t), data_sz); 498062306a36Sopenharmony_ci memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz); 498162306a36Sopenharmony_ci 498262306a36Sopenharmony_ci } 498362306a36Sopenharmony_ci 498462306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, data_sz, 498562306a36Sopenharmony_ci (u8 *)ppage0_alloc, page0_dma); 498662306a36Sopenharmony_ci 498762306a36Sopenharmony_ci /* FIXME! 498862306a36Sopenharmony_ci * Normalize endianness of structure data, 498962306a36Sopenharmony_ci * by byte-swapping all > 1 byte fields! 499062306a36Sopenharmony_ci */ 499162306a36Sopenharmony_ci 499262306a36Sopenharmony_ci } 499362306a36Sopenharmony_ci 499462306a36Sopenharmony_ci if (rc) 499562306a36Sopenharmony_ci return rc; 499662306a36Sopenharmony_ci } 499762306a36Sopenharmony_ci 499862306a36Sopenharmony_ci /* Get LAN Page 1 header */ 499962306a36Sopenharmony_ci hdr.PageVersion = 0; 500062306a36Sopenharmony_ci hdr.PageLength = 0; 500162306a36Sopenharmony_ci hdr.PageNumber = 1; 500262306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_LAN; 500362306a36Sopenharmony_ci cfg.cfghdr.hdr = &hdr; 500462306a36Sopenharmony_ci cfg.physAddr = -1; 500562306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 500662306a36Sopenharmony_ci cfg.dir = 0; 500762306a36Sopenharmony_ci cfg.pageAddr = 0; 500862306a36Sopenharmony_ci 500962306a36Sopenharmony_ci if ((rc = mpt_config(ioc, &cfg)) != 0) 501062306a36Sopenharmony_ci return rc; 501162306a36Sopenharmony_ci 501262306a36Sopenharmony_ci if (hdr.PageLength == 0) 501362306a36Sopenharmony_ci return 0; 501462306a36Sopenharmony_ci 501562306a36Sopenharmony_ci data_sz = hdr.PageLength * 4; 501662306a36Sopenharmony_ci rc = -ENOMEM; 501762306a36Sopenharmony_ci ppage1_alloc = dma_alloc_coherent(&ioc->pcidev->dev, data_sz, 501862306a36Sopenharmony_ci &page1_dma, GFP_KERNEL); 501962306a36Sopenharmony_ci if (ppage1_alloc) { 502062306a36Sopenharmony_ci memset((u8 *)ppage1_alloc, 0, data_sz); 502162306a36Sopenharmony_ci cfg.physAddr = page1_dma; 502262306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 502362306a36Sopenharmony_ci 502462306a36Sopenharmony_ci if ((rc = mpt_config(ioc, &cfg)) == 0) { 502562306a36Sopenharmony_ci /* save the data */ 502662306a36Sopenharmony_ci copy_sz = min_t(int, sizeof(LANPage1_t), data_sz); 502762306a36Sopenharmony_ci memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz); 502862306a36Sopenharmony_ci } 502962306a36Sopenharmony_ci 503062306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, data_sz, 503162306a36Sopenharmony_ci (u8 *)ppage1_alloc, page1_dma); 503262306a36Sopenharmony_ci 503362306a36Sopenharmony_ci /* FIXME! 503462306a36Sopenharmony_ci * Normalize endianness of structure data, 503562306a36Sopenharmony_ci * by byte-swapping all > 1 byte fields! 503662306a36Sopenharmony_ci */ 503762306a36Sopenharmony_ci 503862306a36Sopenharmony_ci } 503962306a36Sopenharmony_ci 504062306a36Sopenharmony_ci return rc; 504162306a36Sopenharmony_ci} 504262306a36Sopenharmony_ci 504362306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 504462306a36Sopenharmony_ci/** 504562306a36Sopenharmony_ci * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table 504662306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 504762306a36Sopenharmony_ci * @persist_opcode: see below 504862306a36Sopenharmony_ci * 504962306a36Sopenharmony_ci * =============================== ====================================== 505062306a36Sopenharmony_ci * MPI_SAS_OP_CLEAR_NOT_PRESENT Free all persist TargetID mappings for 505162306a36Sopenharmony_ci * devices not currently present. 505262306a36Sopenharmony_ci * MPI_SAS_OP_CLEAR_ALL_PERSISTENT Clear al persist TargetID mappings 505362306a36Sopenharmony_ci * =============================== ====================================== 505462306a36Sopenharmony_ci * 505562306a36Sopenharmony_ci * NOTE: Don't use not this function during interrupt time. 505662306a36Sopenharmony_ci * 505762306a36Sopenharmony_ci * Returns 0 for success, non-zero error 505862306a36Sopenharmony_ci */ 505962306a36Sopenharmony_ci 506062306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 506162306a36Sopenharmony_ciint 506262306a36Sopenharmony_cimptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode) 506362306a36Sopenharmony_ci{ 506462306a36Sopenharmony_ci SasIoUnitControlRequest_t *sasIoUnitCntrReq; 506562306a36Sopenharmony_ci SasIoUnitControlReply_t *sasIoUnitCntrReply; 506662306a36Sopenharmony_ci MPT_FRAME_HDR *mf = NULL; 506762306a36Sopenharmony_ci MPIHeader_t *mpi_hdr; 506862306a36Sopenharmony_ci int ret = 0; 506962306a36Sopenharmony_ci unsigned long timeleft; 507062306a36Sopenharmony_ci 507162306a36Sopenharmony_ci mutex_lock(&ioc->mptbase_cmds.mutex); 507262306a36Sopenharmony_ci 507362306a36Sopenharmony_ci /* init the internal cmd struct */ 507462306a36Sopenharmony_ci memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE); 507562306a36Sopenharmony_ci INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status) 507662306a36Sopenharmony_ci 507762306a36Sopenharmony_ci /* insure garbage is not sent to fw */ 507862306a36Sopenharmony_ci switch(persist_opcode) { 507962306a36Sopenharmony_ci 508062306a36Sopenharmony_ci case MPI_SAS_OP_CLEAR_NOT_PRESENT: 508162306a36Sopenharmony_ci case MPI_SAS_OP_CLEAR_ALL_PERSISTENT: 508262306a36Sopenharmony_ci break; 508362306a36Sopenharmony_ci 508462306a36Sopenharmony_ci default: 508562306a36Sopenharmony_ci ret = -1; 508662306a36Sopenharmony_ci goto out; 508762306a36Sopenharmony_ci } 508862306a36Sopenharmony_ci 508962306a36Sopenharmony_ci printk(KERN_DEBUG "%s: persist_opcode=%x\n", 509062306a36Sopenharmony_ci __func__, persist_opcode); 509162306a36Sopenharmony_ci 509262306a36Sopenharmony_ci /* Get a MF for this command. 509362306a36Sopenharmony_ci */ 509462306a36Sopenharmony_ci if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { 509562306a36Sopenharmony_ci printk(KERN_DEBUG "%s: no msg frames!\n", __func__); 509662306a36Sopenharmony_ci ret = -1; 509762306a36Sopenharmony_ci goto out; 509862306a36Sopenharmony_ci } 509962306a36Sopenharmony_ci 510062306a36Sopenharmony_ci mpi_hdr = (MPIHeader_t *) mf; 510162306a36Sopenharmony_ci sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf; 510262306a36Sopenharmony_ci memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t)); 510362306a36Sopenharmony_ci sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; 510462306a36Sopenharmony_ci sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext; 510562306a36Sopenharmony_ci sasIoUnitCntrReq->Operation = persist_opcode; 510662306a36Sopenharmony_ci 510762306a36Sopenharmony_ci mpt_put_msg_frame(mpt_base_index, ioc, mf); 510862306a36Sopenharmony_ci timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ); 510962306a36Sopenharmony_ci if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { 511062306a36Sopenharmony_ci ret = -ETIME; 511162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: failed\n", __func__); 511262306a36Sopenharmony_ci if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) 511362306a36Sopenharmony_ci goto out; 511462306a36Sopenharmony_ci if (!timeleft) { 511562306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 511662306a36Sopenharmony_ci "Issuing Reset from %s!!, doorbell=0x%08x\n", 511762306a36Sopenharmony_ci ioc->name, __func__, mpt_GetIocState(ioc, 0)); 511862306a36Sopenharmony_ci mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); 511962306a36Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 512062306a36Sopenharmony_ci } 512162306a36Sopenharmony_ci goto out; 512262306a36Sopenharmony_ci } 512362306a36Sopenharmony_ci 512462306a36Sopenharmony_ci if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { 512562306a36Sopenharmony_ci ret = -1; 512662306a36Sopenharmony_ci goto out; 512762306a36Sopenharmony_ci } 512862306a36Sopenharmony_ci 512962306a36Sopenharmony_ci sasIoUnitCntrReply = 513062306a36Sopenharmony_ci (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply; 513162306a36Sopenharmony_ci if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) { 513262306a36Sopenharmony_ci printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", 513362306a36Sopenharmony_ci __func__, sasIoUnitCntrReply->IOCStatus, 513462306a36Sopenharmony_ci sasIoUnitCntrReply->IOCLogInfo); 513562306a36Sopenharmony_ci printk(KERN_DEBUG "%s: failed\n", __func__); 513662306a36Sopenharmony_ci ret = -1; 513762306a36Sopenharmony_ci } else 513862306a36Sopenharmony_ci printk(KERN_DEBUG "%s: success\n", __func__); 513962306a36Sopenharmony_ci out: 514062306a36Sopenharmony_ci 514162306a36Sopenharmony_ci CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status) 514262306a36Sopenharmony_ci mutex_unlock(&ioc->mptbase_cmds.mutex); 514362306a36Sopenharmony_ci return ret; 514462306a36Sopenharmony_ci} 514562306a36Sopenharmony_ci 514662306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 514762306a36Sopenharmony_ci 514862306a36Sopenharmony_cistatic void 514962306a36Sopenharmony_cimptbase_raid_process_event_data(MPT_ADAPTER *ioc, 515062306a36Sopenharmony_ci MpiEventDataRaid_t * pRaidEventData) 515162306a36Sopenharmony_ci{ 515262306a36Sopenharmony_ci int volume; 515362306a36Sopenharmony_ci int reason; 515462306a36Sopenharmony_ci int disk; 515562306a36Sopenharmony_ci int status; 515662306a36Sopenharmony_ci int flags; 515762306a36Sopenharmony_ci int state; 515862306a36Sopenharmony_ci 515962306a36Sopenharmony_ci volume = pRaidEventData->VolumeID; 516062306a36Sopenharmony_ci reason = pRaidEventData->ReasonCode; 516162306a36Sopenharmony_ci disk = pRaidEventData->PhysDiskNum; 516262306a36Sopenharmony_ci status = le32_to_cpu(pRaidEventData->SettingsStatus); 516362306a36Sopenharmony_ci flags = (status >> 0) & 0xff; 516462306a36Sopenharmony_ci state = (status >> 8) & 0xff; 516562306a36Sopenharmony_ci 516662306a36Sopenharmony_ci if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) { 516762306a36Sopenharmony_ci return; 516862306a36Sopenharmony_ci } 516962306a36Sopenharmony_ci 517062306a36Sopenharmony_ci if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED && 517162306a36Sopenharmony_ci reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) || 517262306a36Sopenharmony_ci (reason == MPI_EVENT_RAID_RC_SMART_DATA)) { 517362306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n", 517462306a36Sopenharmony_ci ioc->name, disk, volume); 517562306a36Sopenharmony_ci } else { 517662306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n", 517762306a36Sopenharmony_ci ioc->name, volume); 517862306a36Sopenharmony_ci } 517962306a36Sopenharmony_ci 518062306a36Sopenharmony_ci switch(reason) { 518162306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_VOLUME_CREATED: 518262306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT " volume has been created\n", 518362306a36Sopenharmony_ci ioc->name); 518462306a36Sopenharmony_ci break; 518562306a36Sopenharmony_ci 518662306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_VOLUME_DELETED: 518762306a36Sopenharmony_ci 518862306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT " volume has been deleted\n", 518962306a36Sopenharmony_ci ioc->name); 519062306a36Sopenharmony_ci break; 519162306a36Sopenharmony_ci 519262306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED: 519362306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT " volume settings have been changed\n", 519462306a36Sopenharmony_ci ioc->name); 519562306a36Sopenharmony_ci break; 519662306a36Sopenharmony_ci 519762306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: 519862306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n", 519962306a36Sopenharmony_ci ioc->name, 520062306a36Sopenharmony_ci state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL 520162306a36Sopenharmony_ci ? "optimal" 520262306a36Sopenharmony_ci : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED 520362306a36Sopenharmony_ci ? "degraded" 520462306a36Sopenharmony_ci : state == MPI_RAIDVOL0_STATUS_STATE_FAILED 520562306a36Sopenharmony_ci ? "failed" 520662306a36Sopenharmony_ci : "state unknown", 520762306a36Sopenharmony_ci flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED 520862306a36Sopenharmony_ci ? ", enabled" : "", 520962306a36Sopenharmony_ci flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED 521062306a36Sopenharmony_ci ? ", quiesced" : "", 521162306a36Sopenharmony_ci flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS 521262306a36Sopenharmony_ci ? ", resync in progress" : "" ); 521362306a36Sopenharmony_ci break; 521462306a36Sopenharmony_ci 521562306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED: 521662306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n", 521762306a36Sopenharmony_ci ioc->name, disk); 521862306a36Sopenharmony_ci break; 521962306a36Sopenharmony_ci 522062306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: 522162306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n", 522262306a36Sopenharmony_ci ioc->name); 522362306a36Sopenharmony_ci break; 522462306a36Sopenharmony_ci 522562306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: 522662306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n", 522762306a36Sopenharmony_ci ioc->name); 522862306a36Sopenharmony_ci break; 522962306a36Sopenharmony_ci 523062306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED: 523162306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n", 523262306a36Sopenharmony_ci ioc->name); 523362306a36Sopenharmony_ci break; 523462306a36Sopenharmony_ci 523562306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: 523662306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n", 523762306a36Sopenharmony_ci ioc->name, 523862306a36Sopenharmony_ci state == MPI_PHYSDISK0_STATUS_ONLINE 523962306a36Sopenharmony_ci ? "online" 524062306a36Sopenharmony_ci : state == MPI_PHYSDISK0_STATUS_MISSING 524162306a36Sopenharmony_ci ? "missing" 524262306a36Sopenharmony_ci : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE 524362306a36Sopenharmony_ci ? "not compatible" 524462306a36Sopenharmony_ci : state == MPI_PHYSDISK0_STATUS_FAILED 524562306a36Sopenharmony_ci ? "failed" 524662306a36Sopenharmony_ci : state == MPI_PHYSDISK0_STATUS_INITIALIZING 524762306a36Sopenharmony_ci ? "initializing" 524862306a36Sopenharmony_ci : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED 524962306a36Sopenharmony_ci ? "offline requested" 525062306a36Sopenharmony_ci : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED 525162306a36Sopenharmony_ci ? "failed requested" 525262306a36Sopenharmony_ci : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE 525362306a36Sopenharmony_ci ? "offline" 525462306a36Sopenharmony_ci : "state unknown", 525562306a36Sopenharmony_ci flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC 525662306a36Sopenharmony_ci ? ", out of sync" : "", 525762306a36Sopenharmony_ci flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED 525862306a36Sopenharmony_ci ? ", quiesced" : "" ); 525962306a36Sopenharmony_ci break; 526062306a36Sopenharmony_ci 526162306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED: 526262306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n", 526362306a36Sopenharmony_ci ioc->name, disk); 526462306a36Sopenharmony_ci break; 526562306a36Sopenharmony_ci 526662306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_SMART_DATA: 526762306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n", 526862306a36Sopenharmony_ci ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ); 526962306a36Sopenharmony_ci break; 527062306a36Sopenharmony_ci 527162306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED: 527262306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n", 527362306a36Sopenharmony_ci ioc->name, disk); 527462306a36Sopenharmony_ci break; 527562306a36Sopenharmony_ci } 527662306a36Sopenharmony_ci} 527762306a36Sopenharmony_ci 527862306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 527962306a36Sopenharmony_ci/** 528062306a36Sopenharmony_ci * GetIoUnitPage2 - Retrieve BIOS version and boot order information. 528162306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 528262306a36Sopenharmony_ci * 528362306a36Sopenharmony_ci * Returns: 0 for success 528462306a36Sopenharmony_ci * -ENOMEM if no memory available 528562306a36Sopenharmony_ci * -EPERM if not allowed due to ISR context 528662306a36Sopenharmony_ci * -EAGAIN if no msg frames currently available 528762306a36Sopenharmony_ci * -EFAULT for non-successful reply or no reply (timeout) 528862306a36Sopenharmony_ci */ 528962306a36Sopenharmony_cistatic int 529062306a36Sopenharmony_ciGetIoUnitPage2(MPT_ADAPTER *ioc) 529162306a36Sopenharmony_ci{ 529262306a36Sopenharmony_ci ConfigPageHeader_t hdr; 529362306a36Sopenharmony_ci CONFIGPARMS cfg; 529462306a36Sopenharmony_ci IOUnitPage2_t *ppage_alloc; 529562306a36Sopenharmony_ci dma_addr_t page_dma; 529662306a36Sopenharmony_ci int data_sz; 529762306a36Sopenharmony_ci int rc; 529862306a36Sopenharmony_ci 529962306a36Sopenharmony_ci /* Get the page header */ 530062306a36Sopenharmony_ci hdr.PageVersion = 0; 530162306a36Sopenharmony_ci hdr.PageLength = 0; 530262306a36Sopenharmony_ci hdr.PageNumber = 2; 530362306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT; 530462306a36Sopenharmony_ci cfg.cfghdr.hdr = &hdr; 530562306a36Sopenharmony_ci cfg.physAddr = -1; 530662306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 530762306a36Sopenharmony_ci cfg.dir = 0; 530862306a36Sopenharmony_ci cfg.pageAddr = 0; 530962306a36Sopenharmony_ci cfg.timeout = 0; 531062306a36Sopenharmony_ci 531162306a36Sopenharmony_ci if ((rc = mpt_config(ioc, &cfg)) != 0) 531262306a36Sopenharmony_ci return rc; 531362306a36Sopenharmony_ci 531462306a36Sopenharmony_ci if (hdr.PageLength == 0) 531562306a36Sopenharmony_ci return 0; 531662306a36Sopenharmony_ci 531762306a36Sopenharmony_ci /* Read the config page */ 531862306a36Sopenharmony_ci data_sz = hdr.PageLength * 4; 531962306a36Sopenharmony_ci rc = -ENOMEM; 532062306a36Sopenharmony_ci ppage_alloc = dma_alloc_coherent(&ioc->pcidev->dev, data_sz, 532162306a36Sopenharmony_ci &page_dma, GFP_KERNEL); 532262306a36Sopenharmony_ci if (ppage_alloc) { 532362306a36Sopenharmony_ci memset((u8 *)ppage_alloc, 0, data_sz); 532462306a36Sopenharmony_ci cfg.physAddr = page_dma; 532562306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 532662306a36Sopenharmony_ci 532762306a36Sopenharmony_ci /* If Good, save data */ 532862306a36Sopenharmony_ci if ((rc = mpt_config(ioc, &cfg)) == 0) 532962306a36Sopenharmony_ci ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion); 533062306a36Sopenharmony_ci 533162306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, data_sz, 533262306a36Sopenharmony_ci (u8 *)ppage_alloc, page_dma); 533362306a36Sopenharmony_ci } 533462306a36Sopenharmony_ci 533562306a36Sopenharmony_ci return rc; 533662306a36Sopenharmony_ci} 533762306a36Sopenharmony_ci 533862306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 533962306a36Sopenharmony_ci/** 534062306a36Sopenharmony_ci * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2 534162306a36Sopenharmony_ci * @ioc: Pointer to a Adapter Strucutre 534262306a36Sopenharmony_ci * @portnum: IOC port number 534362306a36Sopenharmony_ci * 534462306a36Sopenharmony_ci * Return: -EFAULT if read of config page header fails 534562306a36Sopenharmony_ci * or if no nvram 534662306a36Sopenharmony_ci * If read of SCSI Port Page 0 fails, 534762306a36Sopenharmony_ci * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF) 534862306a36Sopenharmony_ci * Adapter settings: async, narrow 534962306a36Sopenharmony_ci * Return 1 535062306a36Sopenharmony_ci * If read of SCSI Port Page 2 fails, 535162306a36Sopenharmony_ci * Adapter settings valid 535262306a36Sopenharmony_ci * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF) 535362306a36Sopenharmony_ci * Return 1 535462306a36Sopenharmony_ci * Else 535562306a36Sopenharmony_ci * Both valid 535662306a36Sopenharmony_ci * Return 0 535762306a36Sopenharmony_ci * CHECK - what type of locking mechanisms should be used???? 535862306a36Sopenharmony_ci */ 535962306a36Sopenharmony_cistatic int 536062306a36Sopenharmony_cimpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) 536162306a36Sopenharmony_ci{ 536262306a36Sopenharmony_ci u8 *pbuf; 536362306a36Sopenharmony_ci dma_addr_t buf_dma; 536462306a36Sopenharmony_ci CONFIGPARMS cfg; 536562306a36Sopenharmony_ci ConfigPageHeader_t header; 536662306a36Sopenharmony_ci int ii; 536762306a36Sopenharmony_ci int data, rc = 0; 536862306a36Sopenharmony_ci 536962306a36Sopenharmony_ci /* Allocate memory 537062306a36Sopenharmony_ci */ 537162306a36Sopenharmony_ci if (!ioc->spi_data.nvram) { 537262306a36Sopenharmony_ci int sz; 537362306a36Sopenharmony_ci u8 *mem; 537462306a36Sopenharmony_ci sz = MPT_MAX_SCSI_DEVICES * sizeof(int); 537562306a36Sopenharmony_ci mem = kmalloc(sz, GFP_ATOMIC); 537662306a36Sopenharmony_ci if (mem == NULL) 537762306a36Sopenharmony_ci return -EFAULT; 537862306a36Sopenharmony_ci 537962306a36Sopenharmony_ci ioc->spi_data.nvram = (int *) mem; 538062306a36Sopenharmony_ci 538162306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n", 538262306a36Sopenharmony_ci ioc->name, ioc->spi_data.nvram, sz)); 538362306a36Sopenharmony_ci } 538462306a36Sopenharmony_ci 538562306a36Sopenharmony_ci /* Invalidate NVRAM information 538662306a36Sopenharmony_ci */ 538762306a36Sopenharmony_ci for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { 538862306a36Sopenharmony_ci ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID; 538962306a36Sopenharmony_ci } 539062306a36Sopenharmony_ci 539162306a36Sopenharmony_ci /* Read SPP0 header, allocate memory, then read page. 539262306a36Sopenharmony_ci */ 539362306a36Sopenharmony_ci header.PageVersion = 0; 539462306a36Sopenharmony_ci header.PageLength = 0; 539562306a36Sopenharmony_ci header.PageNumber = 0; 539662306a36Sopenharmony_ci header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT; 539762306a36Sopenharmony_ci cfg.cfghdr.hdr = &header; 539862306a36Sopenharmony_ci cfg.physAddr = -1; 539962306a36Sopenharmony_ci cfg.pageAddr = portnum; 540062306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 540162306a36Sopenharmony_ci cfg.dir = 0; 540262306a36Sopenharmony_ci cfg.timeout = 0; /* use default */ 540362306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 540462306a36Sopenharmony_ci return -EFAULT; 540562306a36Sopenharmony_ci 540662306a36Sopenharmony_ci if (header.PageLength > 0) { 540762306a36Sopenharmony_ci pbuf = dma_alloc_coherent(&ioc->pcidev->dev, 540862306a36Sopenharmony_ci header.PageLength * 4, &buf_dma, 540962306a36Sopenharmony_ci GFP_KERNEL); 541062306a36Sopenharmony_ci if (pbuf) { 541162306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 541262306a36Sopenharmony_ci cfg.physAddr = buf_dma; 541362306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) { 541462306a36Sopenharmony_ci ioc->spi_data.maxBusWidth = MPT_NARROW; 541562306a36Sopenharmony_ci ioc->spi_data.maxSyncOffset = 0; 541662306a36Sopenharmony_ci ioc->spi_data.minSyncFactor = MPT_ASYNC; 541762306a36Sopenharmony_ci ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN; 541862306a36Sopenharmony_ci rc = 1; 541962306a36Sopenharmony_ci ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT 542062306a36Sopenharmony_ci "Unable to read PortPage0 minSyncFactor=%x\n", 542162306a36Sopenharmony_ci ioc->name, ioc->spi_data.minSyncFactor)); 542262306a36Sopenharmony_ci } else { 542362306a36Sopenharmony_ci /* Save the Port Page 0 data 542462306a36Sopenharmony_ci */ 542562306a36Sopenharmony_ci SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf; 542662306a36Sopenharmony_ci pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities); 542762306a36Sopenharmony_ci pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface); 542862306a36Sopenharmony_ci 542962306a36Sopenharmony_ci if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) { 543062306a36Sopenharmony_ci ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS; 543162306a36Sopenharmony_ci ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT 543262306a36Sopenharmony_ci "noQas due to Capabilities=%x\n", 543362306a36Sopenharmony_ci ioc->name, pPP0->Capabilities)); 543462306a36Sopenharmony_ci } 543562306a36Sopenharmony_ci ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0; 543662306a36Sopenharmony_ci data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK; 543762306a36Sopenharmony_ci if (data) { 543862306a36Sopenharmony_ci ioc->spi_data.maxSyncOffset = (u8) (data >> 16); 543962306a36Sopenharmony_ci data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK; 544062306a36Sopenharmony_ci ioc->spi_data.minSyncFactor = (u8) (data >> 8); 544162306a36Sopenharmony_ci ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT 544262306a36Sopenharmony_ci "PortPage0 minSyncFactor=%x\n", 544362306a36Sopenharmony_ci ioc->name, ioc->spi_data.minSyncFactor)); 544462306a36Sopenharmony_ci } else { 544562306a36Sopenharmony_ci ioc->spi_data.maxSyncOffset = 0; 544662306a36Sopenharmony_ci ioc->spi_data.minSyncFactor = MPT_ASYNC; 544762306a36Sopenharmony_ci } 544862306a36Sopenharmony_ci 544962306a36Sopenharmony_ci ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK; 545062306a36Sopenharmony_ci 545162306a36Sopenharmony_ci /* Update the minSyncFactor based on bus type. 545262306a36Sopenharmony_ci */ 545362306a36Sopenharmony_ci if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) || 545462306a36Sopenharmony_ci (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) { 545562306a36Sopenharmony_ci 545662306a36Sopenharmony_ci if (ioc->spi_data.minSyncFactor < MPT_ULTRA) { 545762306a36Sopenharmony_ci ioc->spi_data.minSyncFactor = MPT_ULTRA; 545862306a36Sopenharmony_ci ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT 545962306a36Sopenharmony_ci "HVD or SE detected, minSyncFactor=%x\n", 546062306a36Sopenharmony_ci ioc->name, ioc->spi_data.minSyncFactor)); 546162306a36Sopenharmony_ci } 546262306a36Sopenharmony_ci } 546362306a36Sopenharmony_ci } 546462306a36Sopenharmony_ci if (pbuf) { 546562306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, 546662306a36Sopenharmony_ci header.PageLength * 4, pbuf, 546762306a36Sopenharmony_ci buf_dma); 546862306a36Sopenharmony_ci } 546962306a36Sopenharmony_ci } 547062306a36Sopenharmony_ci } 547162306a36Sopenharmony_ci 547262306a36Sopenharmony_ci /* SCSI Port Page 2 - Read the header then the page. 547362306a36Sopenharmony_ci */ 547462306a36Sopenharmony_ci header.PageVersion = 0; 547562306a36Sopenharmony_ci header.PageLength = 0; 547662306a36Sopenharmony_ci header.PageNumber = 2; 547762306a36Sopenharmony_ci header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT; 547862306a36Sopenharmony_ci cfg.cfghdr.hdr = &header; 547962306a36Sopenharmony_ci cfg.physAddr = -1; 548062306a36Sopenharmony_ci cfg.pageAddr = portnum; 548162306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 548262306a36Sopenharmony_ci cfg.dir = 0; 548362306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 548462306a36Sopenharmony_ci return -EFAULT; 548562306a36Sopenharmony_ci 548662306a36Sopenharmony_ci if (header.PageLength > 0) { 548762306a36Sopenharmony_ci /* Allocate memory and read SCSI Port Page 2 548862306a36Sopenharmony_ci */ 548962306a36Sopenharmony_ci pbuf = dma_alloc_coherent(&ioc->pcidev->dev, 549062306a36Sopenharmony_ci header.PageLength * 4, &buf_dma, 549162306a36Sopenharmony_ci GFP_KERNEL); 549262306a36Sopenharmony_ci if (pbuf) { 549362306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM; 549462306a36Sopenharmony_ci cfg.physAddr = buf_dma; 549562306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) { 549662306a36Sopenharmony_ci /* Nvram data is left with INVALID mark 549762306a36Sopenharmony_ci */ 549862306a36Sopenharmony_ci rc = 1; 549962306a36Sopenharmony_ci } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) { 550062306a36Sopenharmony_ci 550162306a36Sopenharmony_ci /* This is an ATTO adapter, read Page2 accordingly 550262306a36Sopenharmony_ci */ 550362306a36Sopenharmony_ci ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf; 550462306a36Sopenharmony_ci ATTODeviceInfo_t *pdevice = NULL; 550562306a36Sopenharmony_ci u16 ATTOFlags; 550662306a36Sopenharmony_ci 550762306a36Sopenharmony_ci /* Save the Port Page 2 data 550862306a36Sopenharmony_ci * (reformat into a 32bit quantity) 550962306a36Sopenharmony_ci */ 551062306a36Sopenharmony_ci for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { 551162306a36Sopenharmony_ci pdevice = &pPP2->DeviceSettings[ii]; 551262306a36Sopenharmony_ci ATTOFlags = le16_to_cpu(pdevice->ATTOFlags); 551362306a36Sopenharmony_ci data = 0; 551462306a36Sopenharmony_ci 551562306a36Sopenharmony_ci /* Translate ATTO device flags to LSI format 551662306a36Sopenharmony_ci */ 551762306a36Sopenharmony_ci if (ATTOFlags & ATTOFLAG_DISC) 551862306a36Sopenharmony_ci data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE); 551962306a36Sopenharmony_ci if (ATTOFlags & ATTOFLAG_ID_ENB) 552062306a36Sopenharmony_ci data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE); 552162306a36Sopenharmony_ci if (ATTOFlags & ATTOFLAG_LUN_ENB) 552262306a36Sopenharmony_ci data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE); 552362306a36Sopenharmony_ci if (ATTOFlags & ATTOFLAG_TAGGED) 552462306a36Sopenharmony_ci data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE); 552562306a36Sopenharmony_ci if (!(ATTOFlags & ATTOFLAG_WIDE_ENB)) 552662306a36Sopenharmony_ci data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE); 552762306a36Sopenharmony_ci 552862306a36Sopenharmony_ci data = (data << 16) | (pdevice->Period << 8) | 10; 552962306a36Sopenharmony_ci ioc->spi_data.nvram[ii] = data; 553062306a36Sopenharmony_ci } 553162306a36Sopenharmony_ci } else { 553262306a36Sopenharmony_ci SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf; 553362306a36Sopenharmony_ci MpiDeviceInfo_t *pdevice = NULL; 553462306a36Sopenharmony_ci 553562306a36Sopenharmony_ci /* 553662306a36Sopenharmony_ci * Save "Set to Avoid SCSI Bus Resets" flag 553762306a36Sopenharmony_ci */ 553862306a36Sopenharmony_ci ioc->spi_data.bus_reset = 553962306a36Sopenharmony_ci (le32_to_cpu(pPP2->PortFlags) & 554062306a36Sopenharmony_ci MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ? 554162306a36Sopenharmony_ci 0 : 1 ; 554262306a36Sopenharmony_ci 554362306a36Sopenharmony_ci /* Save the Port Page 2 data 554462306a36Sopenharmony_ci * (reformat into a 32bit quantity) 554562306a36Sopenharmony_ci */ 554662306a36Sopenharmony_ci data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK; 554762306a36Sopenharmony_ci ioc->spi_data.PortFlags = data; 554862306a36Sopenharmony_ci for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { 554962306a36Sopenharmony_ci pdevice = &pPP2->DeviceSettings[ii]; 555062306a36Sopenharmony_ci data = (le16_to_cpu(pdevice->DeviceFlags) << 16) | 555162306a36Sopenharmony_ci (pdevice->SyncFactor << 8) | pdevice->Timeout; 555262306a36Sopenharmony_ci ioc->spi_data.nvram[ii] = data; 555362306a36Sopenharmony_ci } 555462306a36Sopenharmony_ci } 555562306a36Sopenharmony_ci 555662306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, 555762306a36Sopenharmony_ci header.PageLength * 4, pbuf, 555862306a36Sopenharmony_ci buf_dma); 555962306a36Sopenharmony_ci } 556062306a36Sopenharmony_ci } 556162306a36Sopenharmony_ci 556262306a36Sopenharmony_ci /* Update Adapter limits with those from NVRAM 556362306a36Sopenharmony_ci * Comment: Don't need to do this. Target performance 556462306a36Sopenharmony_ci * parameters will never exceed the adapters limits. 556562306a36Sopenharmony_ci */ 556662306a36Sopenharmony_ci 556762306a36Sopenharmony_ci return rc; 556862306a36Sopenharmony_ci} 556962306a36Sopenharmony_ci 557062306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 557162306a36Sopenharmony_ci/** 557262306a36Sopenharmony_ci * mpt_readScsiDevicePageHeaders - save version and length of SDP1 557362306a36Sopenharmony_ci * @ioc: Pointer to a Adapter Strucutre 557462306a36Sopenharmony_ci * @portnum: IOC port number 557562306a36Sopenharmony_ci * 557662306a36Sopenharmony_ci * Return: -EFAULT if read of config page header fails 557762306a36Sopenharmony_ci * or 0 if success. 557862306a36Sopenharmony_ci */ 557962306a36Sopenharmony_cistatic int 558062306a36Sopenharmony_cimpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum) 558162306a36Sopenharmony_ci{ 558262306a36Sopenharmony_ci CONFIGPARMS cfg; 558362306a36Sopenharmony_ci ConfigPageHeader_t header; 558462306a36Sopenharmony_ci 558562306a36Sopenharmony_ci /* Read the SCSI Device Page 1 header 558662306a36Sopenharmony_ci */ 558762306a36Sopenharmony_ci header.PageVersion = 0; 558862306a36Sopenharmony_ci header.PageLength = 0; 558962306a36Sopenharmony_ci header.PageNumber = 1; 559062306a36Sopenharmony_ci header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; 559162306a36Sopenharmony_ci cfg.cfghdr.hdr = &header; 559262306a36Sopenharmony_ci cfg.physAddr = -1; 559362306a36Sopenharmony_ci cfg.pageAddr = portnum; 559462306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 559562306a36Sopenharmony_ci cfg.dir = 0; 559662306a36Sopenharmony_ci cfg.timeout = 0; 559762306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 559862306a36Sopenharmony_ci return -EFAULT; 559962306a36Sopenharmony_ci 560062306a36Sopenharmony_ci ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion; 560162306a36Sopenharmony_ci ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength; 560262306a36Sopenharmony_ci 560362306a36Sopenharmony_ci header.PageVersion = 0; 560462306a36Sopenharmony_ci header.PageLength = 0; 560562306a36Sopenharmony_ci header.PageNumber = 0; 560662306a36Sopenharmony_ci header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; 560762306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 560862306a36Sopenharmony_ci return -EFAULT; 560962306a36Sopenharmony_ci 561062306a36Sopenharmony_ci ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion; 561162306a36Sopenharmony_ci ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength; 561262306a36Sopenharmony_ci 561362306a36Sopenharmony_ci dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n", 561462306a36Sopenharmony_ci ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length)); 561562306a36Sopenharmony_ci 561662306a36Sopenharmony_ci dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n", 561762306a36Sopenharmony_ci ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length)); 561862306a36Sopenharmony_ci return 0; 561962306a36Sopenharmony_ci} 562062306a36Sopenharmony_ci 562162306a36Sopenharmony_ci/** 562262306a36Sopenharmony_ci * mpt_inactive_raid_list_free - This clears this link list. 562362306a36Sopenharmony_ci * @ioc : pointer to per adapter structure 562462306a36Sopenharmony_ci **/ 562562306a36Sopenharmony_cistatic void 562662306a36Sopenharmony_cimpt_inactive_raid_list_free(MPT_ADAPTER *ioc) 562762306a36Sopenharmony_ci{ 562862306a36Sopenharmony_ci struct inactive_raid_component_info *component_info, *pNext; 562962306a36Sopenharmony_ci 563062306a36Sopenharmony_ci if (list_empty(&ioc->raid_data.inactive_list)) 563162306a36Sopenharmony_ci return; 563262306a36Sopenharmony_ci 563362306a36Sopenharmony_ci mutex_lock(&ioc->raid_data.inactive_list_mutex); 563462306a36Sopenharmony_ci list_for_each_entry_safe(component_info, pNext, 563562306a36Sopenharmony_ci &ioc->raid_data.inactive_list, list) { 563662306a36Sopenharmony_ci list_del(&component_info->list); 563762306a36Sopenharmony_ci kfree(component_info); 563862306a36Sopenharmony_ci } 563962306a36Sopenharmony_ci mutex_unlock(&ioc->raid_data.inactive_list_mutex); 564062306a36Sopenharmony_ci} 564162306a36Sopenharmony_ci 564262306a36Sopenharmony_ci/** 564362306a36Sopenharmony_ci * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums for devices belonging in an inactive volume 564462306a36Sopenharmony_ci * 564562306a36Sopenharmony_ci * @ioc : pointer to per adapter structure 564662306a36Sopenharmony_ci * @channel : volume channel 564762306a36Sopenharmony_ci * @id : volume target id 564862306a36Sopenharmony_ci **/ 564962306a36Sopenharmony_cistatic void 565062306a36Sopenharmony_cimpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id) 565162306a36Sopenharmony_ci{ 565262306a36Sopenharmony_ci CONFIGPARMS cfg; 565362306a36Sopenharmony_ci ConfigPageHeader_t hdr; 565462306a36Sopenharmony_ci dma_addr_t dma_handle; 565562306a36Sopenharmony_ci pRaidVolumePage0_t buffer = NULL; 565662306a36Sopenharmony_ci int i; 565762306a36Sopenharmony_ci RaidPhysDiskPage0_t phys_disk; 565862306a36Sopenharmony_ci struct inactive_raid_component_info *component_info; 565962306a36Sopenharmony_ci int handle_inactive_volumes; 566062306a36Sopenharmony_ci 566162306a36Sopenharmony_ci memset(&cfg, 0 , sizeof(CONFIGPARMS)); 566262306a36Sopenharmony_ci memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); 566362306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; 566462306a36Sopenharmony_ci cfg.pageAddr = (channel << 8) + id; 566562306a36Sopenharmony_ci cfg.cfghdr.hdr = &hdr; 566662306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 566762306a36Sopenharmony_ci 566862306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 566962306a36Sopenharmony_ci goto out; 567062306a36Sopenharmony_ci 567162306a36Sopenharmony_ci if (!hdr.PageLength) 567262306a36Sopenharmony_ci goto out; 567362306a36Sopenharmony_ci 567462306a36Sopenharmony_ci buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.PageLength * 4, 567562306a36Sopenharmony_ci &dma_handle, GFP_KERNEL); 567662306a36Sopenharmony_ci 567762306a36Sopenharmony_ci if (!buffer) 567862306a36Sopenharmony_ci goto out; 567962306a36Sopenharmony_ci 568062306a36Sopenharmony_ci cfg.physAddr = dma_handle; 568162306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 568262306a36Sopenharmony_ci 568362306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 568462306a36Sopenharmony_ci goto out; 568562306a36Sopenharmony_ci 568662306a36Sopenharmony_ci if (!buffer->NumPhysDisks) 568762306a36Sopenharmony_ci goto out; 568862306a36Sopenharmony_ci 568962306a36Sopenharmony_ci handle_inactive_volumes = 569062306a36Sopenharmony_ci (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE || 569162306a36Sopenharmony_ci (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 || 569262306a36Sopenharmony_ci buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED || 569362306a36Sopenharmony_ci buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0; 569462306a36Sopenharmony_ci 569562306a36Sopenharmony_ci if (!handle_inactive_volumes) 569662306a36Sopenharmony_ci goto out; 569762306a36Sopenharmony_ci 569862306a36Sopenharmony_ci mutex_lock(&ioc->raid_data.inactive_list_mutex); 569962306a36Sopenharmony_ci for (i = 0; i < buffer->NumPhysDisks; i++) { 570062306a36Sopenharmony_ci if(mpt_raid_phys_disk_pg0(ioc, 570162306a36Sopenharmony_ci buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) 570262306a36Sopenharmony_ci continue; 570362306a36Sopenharmony_ci 570462306a36Sopenharmony_ci if ((component_info = kmalloc(sizeof (*component_info), 570562306a36Sopenharmony_ci GFP_KERNEL)) == NULL) 570662306a36Sopenharmony_ci continue; 570762306a36Sopenharmony_ci 570862306a36Sopenharmony_ci component_info->volumeID = id; 570962306a36Sopenharmony_ci component_info->volumeBus = channel; 571062306a36Sopenharmony_ci component_info->d.PhysDiskNum = phys_disk.PhysDiskNum; 571162306a36Sopenharmony_ci component_info->d.PhysDiskBus = phys_disk.PhysDiskBus; 571262306a36Sopenharmony_ci component_info->d.PhysDiskID = phys_disk.PhysDiskID; 571362306a36Sopenharmony_ci component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC; 571462306a36Sopenharmony_ci 571562306a36Sopenharmony_ci list_add_tail(&component_info->list, 571662306a36Sopenharmony_ci &ioc->raid_data.inactive_list); 571762306a36Sopenharmony_ci } 571862306a36Sopenharmony_ci mutex_unlock(&ioc->raid_data.inactive_list_mutex); 571962306a36Sopenharmony_ci 572062306a36Sopenharmony_ci out: 572162306a36Sopenharmony_ci if (buffer) 572262306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, hdr.PageLength * 4, 572362306a36Sopenharmony_ci buffer, dma_handle); 572462306a36Sopenharmony_ci} 572562306a36Sopenharmony_ci 572662306a36Sopenharmony_ci/** 572762306a36Sopenharmony_ci * mpt_raid_phys_disk_pg0 - returns phys disk page zero 572862306a36Sopenharmony_ci * @ioc: Pointer to a Adapter Structure 572962306a36Sopenharmony_ci * @phys_disk_num: io unit unique phys disk num generated by the ioc 573062306a36Sopenharmony_ci * @phys_disk: requested payload data returned 573162306a36Sopenharmony_ci * 573262306a36Sopenharmony_ci * Return: 573362306a36Sopenharmony_ci * 0 on success 573462306a36Sopenharmony_ci * -EFAULT if read of config page header fails or data pointer not NULL 573562306a36Sopenharmony_ci * -ENOMEM if pci_alloc failed 573662306a36Sopenharmony_ci **/ 573762306a36Sopenharmony_ciint 573862306a36Sopenharmony_cimpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, 573962306a36Sopenharmony_ci RaidPhysDiskPage0_t *phys_disk) 574062306a36Sopenharmony_ci{ 574162306a36Sopenharmony_ci CONFIGPARMS cfg; 574262306a36Sopenharmony_ci ConfigPageHeader_t hdr; 574362306a36Sopenharmony_ci dma_addr_t dma_handle; 574462306a36Sopenharmony_ci pRaidPhysDiskPage0_t buffer = NULL; 574562306a36Sopenharmony_ci int rc; 574662306a36Sopenharmony_ci 574762306a36Sopenharmony_ci memset(&cfg, 0 , sizeof(CONFIGPARMS)); 574862306a36Sopenharmony_ci memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); 574962306a36Sopenharmony_ci memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t)); 575062306a36Sopenharmony_ci 575162306a36Sopenharmony_ci hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION; 575262306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; 575362306a36Sopenharmony_ci cfg.cfghdr.hdr = &hdr; 575462306a36Sopenharmony_ci cfg.physAddr = -1; 575562306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 575662306a36Sopenharmony_ci 575762306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) { 575862306a36Sopenharmony_ci rc = -EFAULT; 575962306a36Sopenharmony_ci goto out; 576062306a36Sopenharmony_ci } 576162306a36Sopenharmony_ci 576262306a36Sopenharmony_ci if (!hdr.PageLength) { 576362306a36Sopenharmony_ci rc = -EFAULT; 576462306a36Sopenharmony_ci goto out; 576562306a36Sopenharmony_ci } 576662306a36Sopenharmony_ci 576762306a36Sopenharmony_ci buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.PageLength * 4, 576862306a36Sopenharmony_ci &dma_handle, GFP_KERNEL); 576962306a36Sopenharmony_ci 577062306a36Sopenharmony_ci if (!buffer) { 577162306a36Sopenharmony_ci rc = -ENOMEM; 577262306a36Sopenharmony_ci goto out; 577362306a36Sopenharmony_ci } 577462306a36Sopenharmony_ci 577562306a36Sopenharmony_ci cfg.physAddr = dma_handle; 577662306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 577762306a36Sopenharmony_ci cfg.pageAddr = phys_disk_num; 577862306a36Sopenharmony_ci 577962306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) { 578062306a36Sopenharmony_ci rc = -EFAULT; 578162306a36Sopenharmony_ci goto out; 578262306a36Sopenharmony_ci } 578362306a36Sopenharmony_ci 578462306a36Sopenharmony_ci rc = 0; 578562306a36Sopenharmony_ci memcpy(phys_disk, buffer, sizeof(*buffer)); 578662306a36Sopenharmony_ci phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA); 578762306a36Sopenharmony_ci 578862306a36Sopenharmony_ci out: 578962306a36Sopenharmony_ci 579062306a36Sopenharmony_ci if (buffer) 579162306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, hdr.PageLength * 4, 579262306a36Sopenharmony_ci buffer, dma_handle); 579362306a36Sopenharmony_ci 579462306a36Sopenharmony_ci return rc; 579562306a36Sopenharmony_ci} 579662306a36Sopenharmony_ci 579762306a36Sopenharmony_ci/** 579862306a36Sopenharmony_ci * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num 579962306a36Sopenharmony_ci * @ioc: Pointer to a Adapter Structure 580062306a36Sopenharmony_ci * @phys_disk_num: io unit unique phys disk num generated by the ioc 580162306a36Sopenharmony_ci * 580262306a36Sopenharmony_ci * Return: 580362306a36Sopenharmony_ci * returns number paths 580462306a36Sopenharmony_ci **/ 580562306a36Sopenharmony_ciint 580662306a36Sopenharmony_cimpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num) 580762306a36Sopenharmony_ci{ 580862306a36Sopenharmony_ci CONFIGPARMS cfg; 580962306a36Sopenharmony_ci ConfigPageHeader_t hdr; 581062306a36Sopenharmony_ci dma_addr_t dma_handle; 581162306a36Sopenharmony_ci pRaidPhysDiskPage1_t buffer = NULL; 581262306a36Sopenharmony_ci int rc; 581362306a36Sopenharmony_ci 581462306a36Sopenharmony_ci memset(&cfg, 0 , sizeof(CONFIGPARMS)); 581562306a36Sopenharmony_ci memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); 581662306a36Sopenharmony_ci 581762306a36Sopenharmony_ci hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION; 581862306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; 581962306a36Sopenharmony_ci hdr.PageNumber = 1; 582062306a36Sopenharmony_ci cfg.cfghdr.hdr = &hdr; 582162306a36Sopenharmony_ci cfg.physAddr = -1; 582262306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 582362306a36Sopenharmony_ci 582462306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) { 582562306a36Sopenharmony_ci rc = 0; 582662306a36Sopenharmony_ci goto out; 582762306a36Sopenharmony_ci } 582862306a36Sopenharmony_ci 582962306a36Sopenharmony_ci if (!hdr.PageLength) { 583062306a36Sopenharmony_ci rc = 0; 583162306a36Sopenharmony_ci goto out; 583262306a36Sopenharmony_ci } 583362306a36Sopenharmony_ci 583462306a36Sopenharmony_ci buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.PageLength * 4, 583562306a36Sopenharmony_ci &dma_handle, GFP_KERNEL); 583662306a36Sopenharmony_ci 583762306a36Sopenharmony_ci if (!buffer) { 583862306a36Sopenharmony_ci rc = 0; 583962306a36Sopenharmony_ci goto out; 584062306a36Sopenharmony_ci } 584162306a36Sopenharmony_ci 584262306a36Sopenharmony_ci cfg.physAddr = dma_handle; 584362306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 584462306a36Sopenharmony_ci cfg.pageAddr = phys_disk_num; 584562306a36Sopenharmony_ci 584662306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) { 584762306a36Sopenharmony_ci rc = 0; 584862306a36Sopenharmony_ci goto out; 584962306a36Sopenharmony_ci } 585062306a36Sopenharmony_ci 585162306a36Sopenharmony_ci rc = buffer->NumPhysDiskPaths; 585262306a36Sopenharmony_ci out: 585362306a36Sopenharmony_ci 585462306a36Sopenharmony_ci if (buffer) 585562306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, hdr.PageLength * 4, 585662306a36Sopenharmony_ci buffer, dma_handle); 585762306a36Sopenharmony_ci 585862306a36Sopenharmony_ci return rc; 585962306a36Sopenharmony_ci} 586062306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths); 586162306a36Sopenharmony_ci 586262306a36Sopenharmony_ci/** 586362306a36Sopenharmony_ci * mpt_raid_phys_disk_pg1 - returns phys disk page 1 586462306a36Sopenharmony_ci * @ioc: Pointer to a Adapter Structure 586562306a36Sopenharmony_ci * @phys_disk_num: io unit unique phys disk num generated by the ioc 586662306a36Sopenharmony_ci * @phys_disk: requested payload data returned 586762306a36Sopenharmony_ci * 586862306a36Sopenharmony_ci * Return: 586962306a36Sopenharmony_ci * 0 on success 587062306a36Sopenharmony_ci * -EFAULT if read of config page header fails or data pointer not NULL 587162306a36Sopenharmony_ci * -ENOMEM if pci_alloc failed 587262306a36Sopenharmony_ci **/ 587362306a36Sopenharmony_ciint 587462306a36Sopenharmony_cimpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num, 587562306a36Sopenharmony_ci RaidPhysDiskPage1_t *phys_disk) 587662306a36Sopenharmony_ci{ 587762306a36Sopenharmony_ci CONFIGPARMS cfg; 587862306a36Sopenharmony_ci ConfigPageHeader_t hdr; 587962306a36Sopenharmony_ci dma_addr_t dma_handle; 588062306a36Sopenharmony_ci pRaidPhysDiskPage1_t buffer = NULL; 588162306a36Sopenharmony_ci int rc; 588262306a36Sopenharmony_ci int i; 588362306a36Sopenharmony_ci __le64 sas_address; 588462306a36Sopenharmony_ci 588562306a36Sopenharmony_ci memset(&cfg, 0 , sizeof(CONFIGPARMS)); 588662306a36Sopenharmony_ci memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); 588762306a36Sopenharmony_ci rc = 0; 588862306a36Sopenharmony_ci 588962306a36Sopenharmony_ci hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION; 589062306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK; 589162306a36Sopenharmony_ci hdr.PageNumber = 1; 589262306a36Sopenharmony_ci cfg.cfghdr.hdr = &hdr; 589362306a36Sopenharmony_ci cfg.physAddr = -1; 589462306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 589562306a36Sopenharmony_ci 589662306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) { 589762306a36Sopenharmony_ci rc = -EFAULT; 589862306a36Sopenharmony_ci goto out; 589962306a36Sopenharmony_ci } 590062306a36Sopenharmony_ci 590162306a36Sopenharmony_ci if (!hdr.PageLength) { 590262306a36Sopenharmony_ci rc = -EFAULT; 590362306a36Sopenharmony_ci goto out; 590462306a36Sopenharmony_ci } 590562306a36Sopenharmony_ci 590662306a36Sopenharmony_ci buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.PageLength * 4, 590762306a36Sopenharmony_ci &dma_handle, GFP_KERNEL); 590862306a36Sopenharmony_ci 590962306a36Sopenharmony_ci if (!buffer) { 591062306a36Sopenharmony_ci rc = -ENOMEM; 591162306a36Sopenharmony_ci goto out; 591262306a36Sopenharmony_ci } 591362306a36Sopenharmony_ci 591462306a36Sopenharmony_ci cfg.physAddr = dma_handle; 591562306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 591662306a36Sopenharmony_ci cfg.pageAddr = phys_disk_num; 591762306a36Sopenharmony_ci 591862306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) { 591962306a36Sopenharmony_ci rc = -EFAULT; 592062306a36Sopenharmony_ci goto out; 592162306a36Sopenharmony_ci } 592262306a36Sopenharmony_ci 592362306a36Sopenharmony_ci phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths; 592462306a36Sopenharmony_ci phys_disk->PhysDiskNum = phys_disk_num; 592562306a36Sopenharmony_ci for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) { 592662306a36Sopenharmony_ci phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID; 592762306a36Sopenharmony_ci phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus; 592862306a36Sopenharmony_ci phys_disk->Path[i].OwnerIdentifier = 592962306a36Sopenharmony_ci buffer->Path[i].OwnerIdentifier; 593062306a36Sopenharmony_ci phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags); 593162306a36Sopenharmony_ci memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64)); 593262306a36Sopenharmony_ci sas_address = le64_to_cpu(sas_address); 593362306a36Sopenharmony_ci memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64)); 593462306a36Sopenharmony_ci memcpy(&sas_address, 593562306a36Sopenharmony_ci &buffer->Path[i].OwnerWWID, sizeof(__le64)); 593662306a36Sopenharmony_ci sas_address = le64_to_cpu(sas_address); 593762306a36Sopenharmony_ci memcpy(&phys_disk->Path[i].OwnerWWID, 593862306a36Sopenharmony_ci &sas_address, sizeof(__le64)); 593962306a36Sopenharmony_ci } 594062306a36Sopenharmony_ci 594162306a36Sopenharmony_ci out: 594262306a36Sopenharmony_ci 594362306a36Sopenharmony_ci if (buffer) 594462306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, hdr.PageLength * 4, 594562306a36Sopenharmony_ci buffer, dma_handle); 594662306a36Sopenharmony_ci 594762306a36Sopenharmony_ci return rc; 594862306a36Sopenharmony_ci} 594962306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_raid_phys_disk_pg1); 595062306a36Sopenharmony_ci 595162306a36Sopenharmony_ci 595262306a36Sopenharmony_ci/** 595362306a36Sopenharmony_ci * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes 595462306a36Sopenharmony_ci * @ioc: Pointer to a Adapter Strucutre 595562306a36Sopenharmony_ci * 595662306a36Sopenharmony_ci * Return: 595762306a36Sopenharmony_ci * 0 on success 595862306a36Sopenharmony_ci * -EFAULT if read of config page header fails or data pointer not NULL 595962306a36Sopenharmony_ci * -ENOMEM if pci_alloc failed 596062306a36Sopenharmony_ci **/ 596162306a36Sopenharmony_ciint 596262306a36Sopenharmony_cimpt_findImVolumes(MPT_ADAPTER *ioc) 596362306a36Sopenharmony_ci{ 596462306a36Sopenharmony_ci IOCPage2_t *pIoc2; 596562306a36Sopenharmony_ci u8 *mem; 596662306a36Sopenharmony_ci dma_addr_t ioc2_dma; 596762306a36Sopenharmony_ci CONFIGPARMS cfg; 596862306a36Sopenharmony_ci ConfigPageHeader_t header; 596962306a36Sopenharmony_ci int rc = 0; 597062306a36Sopenharmony_ci int iocpage2sz; 597162306a36Sopenharmony_ci int i; 597262306a36Sopenharmony_ci 597362306a36Sopenharmony_ci if (!ioc->ir_firmware) 597462306a36Sopenharmony_ci return 0; 597562306a36Sopenharmony_ci 597662306a36Sopenharmony_ci /* Free the old page 597762306a36Sopenharmony_ci */ 597862306a36Sopenharmony_ci kfree(ioc->raid_data.pIocPg2); 597962306a36Sopenharmony_ci ioc->raid_data.pIocPg2 = NULL; 598062306a36Sopenharmony_ci mpt_inactive_raid_list_free(ioc); 598162306a36Sopenharmony_ci 598262306a36Sopenharmony_ci /* Read IOCP2 header then the page. 598362306a36Sopenharmony_ci */ 598462306a36Sopenharmony_ci header.PageVersion = 0; 598562306a36Sopenharmony_ci header.PageLength = 0; 598662306a36Sopenharmony_ci header.PageNumber = 2; 598762306a36Sopenharmony_ci header.PageType = MPI_CONFIG_PAGETYPE_IOC; 598862306a36Sopenharmony_ci cfg.cfghdr.hdr = &header; 598962306a36Sopenharmony_ci cfg.physAddr = -1; 599062306a36Sopenharmony_ci cfg.pageAddr = 0; 599162306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 599262306a36Sopenharmony_ci cfg.dir = 0; 599362306a36Sopenharmony_ci cfg.timeout = 0; 599462306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 599562306a36Sopenharmony_ci return -EFAULT; 599662306a36Sopenharmony_ci 599762306a36Sopenharmony_ci if (header.PageLength == 0) 599862306a36Sopenharmony_ci return -EFAULT; 599962306a36Sopenharmony_ci 600062306a36Sopenharmony_ci iocpage2sz = header.PageLength * 4; 600162306a36Sopenharmony_ci pIoc2 = dma_alloc_coherent(&ioc->pcidev->dev, iocpage2sz, &ioc2_dma, 600262306a36Sopenharmony_ci GFP_KERNEL); 600362306a36Sopenharmony_ci if (!pIoc2) 600462306a36Sopenharmony_ci return -ENOMEM; 600562306a36Sopenharmony_ci 600662306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 600762306a36Sopenharmony_ci cfg.physAddr = ioc2_dma; 600862306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 600962306a36Sopenharmony_ci goto out; 601062306a36Sopenharmony_ci 601162306a36Sopenharmony_ci mem = kmemdup(pIoc2, iocpage2sz, GFP_KERNEL); 601262306a36Sopenharmony_ci if (!mem) { 601362306a36Sopenharmony_ci rc = -ENOMEM; 601462306a36Sopenharmony_ci goto out; 601562306a36Sopenharmony_ci } 601662306a36Sopenharmony_ci 601762306a36Sopenharmony_ci ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem; 601862306a36Sopenharmony_ci 601962306a36Sopenharmony_ci mpt_read_ioc_pg_3(ioc); 602062306a36Sopenharmony_ci 602162306a36Sopenharmony_ci for (i = 0; i < pIoc2->NumActiveVolumes ; i++) 602262306a36Sopenharmony_ci mpt_inactive_raid_volumes(ioc, 602362306a36Sopenharmony_ci pIoc2->RaidVolume[i].VolumeBus, 602462306a36Sopenharmony_ci pIoc2->RaidVolume[i].VolumeID); 602562306a36Sopenharmony_ci 602662306a36Sopenharmony_ci out: 602762306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, iocpage2sz, pIoc2, ioc2_dma); 602862306a36Sopenharmony_ci 602962306a36Sopenharmony_ci return rc; 603062306a36Sopenharmony_ci} 603162306a36Sopenharmony_ci 603262306a36Sopenharmony_cistatic int 603362306a36Sopenharmony_cimpt_read_ioc_pg_3(MPT_ADAPTER *ioc) 603462306a36Sopenharmony_ci{ 603562306a36Sopenharmony_ci IOCPage3_t *pIoc3; 603662306a36Sopenharmony_ci u8 *mem; 603762306a36Sopenharmony_ci CONFIGPARMS cfg; 603862306a36Sopenharmony_ci ConfigPageHeader_t header; 603962306a36Sopenharmony_ci dma_addr_t ioc3_dma; 604062306a36Sopenharmony_ci int iocpage3sz = 0; 604162306a36Sopenharmony_ci 604262306a36Sopenharmony_ci /* Free the old page 604362306a36Sopenharmony_ci */ 604462306a36Sopenharmony_ci kfree(ioc->raid_data.pIocPg3); 604562306a36Sopenharmony_ci ioc->raid_data.pIocPg3 = NULL; 604662306a36Sopenharmony_ci 604762306a36Sopenharmony_ci /* There is at least one physical disk. 604862306a36Sopenharmony_ci * Read and save IOC Page 3 604962306a36Sopenharmony_ci */ 605062306a36Sopenharmony_ci header.PageVersion = 0; 605162306a36Sopenharmony_ci header.PageLength = 0; 605262306a36Sopenharmony_ci header.PageNumber = 3; 605362306a36Sopenharmony_ci header.PageType = MPI_CONFIG_PAGETYPE_IOC; 605462306a36Sopenharmony_ci cfg.cfghdr.hdr = &header; 605562306a36Sopenharmony_ci cfg.physAddr = -1; 605662306a36Sopenharmony_ci cfg.pageAddr = 0; 605762306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 605862306a36Sopenharmony_ci cfg.dir = 0; 605962306a36Sopenharmony_ci cfg.timeout = 0; 606062306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 606162306a36Sopenharmony_ci return 0; 606262306a36Sopenharmony_ci 606362306a36Sopenharmony_ci if (header.PageLength == 0) 606462306a36Sopenharmony_ci return 0; 606562306a36Sopenharmony_ci 606662306a36Sopenharmony_ci /* Read Header good, alloc memory 606762306a36Sopenharmony_ci */ 606862306a36Sopenharmony_ci iocpage3sz = header.PageLength * 4; 606962306a36Sopenharmony_ci pIoc3 = dma_alloc_coherent(&ioc->pcidev->dev, iocpage3sz, &ioc3_dma, 607062306a36Sopenharmony_ci GFP_KERNEL); 607162306a36Sopenharmony_ci if (!pIoc3) 607262306a36Sopenharmony_ci return 0; 607362306a36Sopenharmony_ci 607462306a36Sopenharmony_ci /* Read the Page and save the data 607562306a36Sopenharmony_ci * into malloc'd memory. 607662306a36Sopenharmony_ci */ 607762306a36Sopenharmony_ci cfg.physAddr = ioc3_dma; 607862306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 607962306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) == 0) { 608062306a36Sopenharmony_ci mem = kmalloc(iocpage3sz, GFP_KERNEL); 608162306a36Sopenharmony_ci if (mem) { 608262306a36Sopenharmony_ci memcpy(mem, (u8 *)pIoc3, iocpage3sz); 608362306a36Sopenharmony_ci ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem; 608462306a36Sopenharmony_ci } 608562306a36Sopenharmony_ci } 608662306a36Sopenharmony_ci 608762306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, iocpage3sz, pIoc3, ioc3_dma); 608862306a36Sopenharmony_ci 608962306a36Sopenharmony_ci return 0; 609062306a36Sopenharmony_ci} 609162306a36Sopenharmony_ci 609262306a36Sopenharmony_cistatic void 609362306a36Sopenharmony_cimpt_read_ioc_pg_4(MPT_ADAPTER *ioc) 609462306a36Sopenharmony_ci{ 609562306a36Sopenharmony_ci IOCPage4_t *pIoc4; 609662306a36Sopenharmony_ci CONFIGPARMS cfg; 609762306a36Sopenharmony_ci ConfigPageHeader_t header; 609862306a36Sopenharmony_ci dma_addr_t ioc4_dma; 609962306a36Sopenharmony_ci int iocpage4sz; 610062306a36Sopenharmony_ci 610162306a36Sopenharmony_ci /* Read and save IOC Page 4 610262306a36Sopenharmony_ci */ 610362306a36Sopenharmony_ci header.PageVersion = 0; 610462306a36Sopenharmony_ci header.PageLength = 0; 610562306a36Sopenharmony_ci header.PageNumber = 4; 610662306a36Sopenharmony_ci header.PageType = MPI_CONFIG_PAGETYPE_IOC; 610762306a36Sopenharmony_ci cfg.cfghdr.hdr = &header; 610862306a36Sopenharmony_ci cfg.physAddr = -1; 610962306a36Sopenharmony_ci cfg.pageAddr = 0; 611062306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 611162306a36Sopenharmony_ci cfg.dir = 0; 611262306a36Sopenharmony_ci cfg.timeout = 0; 611362306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 611462306a36Sopenharmony_ci return; 611562306a36Sopenharmony_ci 611662306a36Sopenharmony_ci if (header.PageLength == 0) 611762306a36Sopenharmony_ci return; 611862306a36Sopenharmony_ci 611962306a36Sopenharmony_ci if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) { 612062306a36Sopenharmony_ci iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */ 612162306a36Sopenharmony_ci pIoc4 = dma_alloc_coherent(&ioc->pcidev->dev, iocpage4sz, 612262306a36Sopenharmony_ci &ioc4_dma, GFP_KERNEL); 612362306a36Sopenharmony_ci if (!pIoc4) 612462306a36Sopenharmony_ci return; 612562306a36Sopenharmony_ci ioc->alloc_total += iocpage4sz; 612662306a36Sopenharmony_ci } else { 612762306a36Sopenharmony_ci ioc4_dma = ioc->spi_data.IocPg4_dma; 612862306a36Sopenharmony_ci iocpage4sz = ioc->spi_data.IocPg4Sz; 612962306a36Sopenharmony_ci } 613062306a36Sopenharmony_ci 613162306a36Sopenharmony_ci /* Read the Page into dma memory. 613262306a36Sopenharmony_ci */ 613362306a36Sopenharmony_ci cfg.physAddr = ioc4_dma; 613462306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 613562306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) == 0) { 613662306a36Sopenharmony_ci ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4; 613762306a36Sopenharmony_ci ioc->spi_data.IocPg4_dma = ioc4_dma; 613862306a36Sopenharmony_ci ioc->spi_data.IocPg4Sz = iocpage4sz; 613962306a36Sopenharmony_ci } else { 614062306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, iocpage4sz, pIoc4, 614162306a36Sopenharmony_ci ioc4_dma); 614262306a36Sopenharmony_ci ioc->spi_data.pIocPg4 = NULL; 614362306a36Sopenharmony_ci ioc->alloc_total -= iocpage4sz; 614462306a36Sopenharmony_ci } 614562306a36Sopenharmony_ci} 614662306a36Sopenharmony_ci 614762306a36Sopenharmony_cistatic void 614862306a36Sopenharmony_cimpt_read_ioc_pg_1(MPT_ADAPTER *ioc) 614962306a36Sopenharmony_ci{ 615062306a36Sopenharmony_ci IOCPage1_t *pIoc1; 615162306a36Sopenharmony_ci CONFIGPARMS cfg; 615262306a36Sopenharmony_ci ConfigPageHeader_t header; 615362306a36Sopenharmony_ci dma_addr_t ioc1_dma; 615462306a36Sopenharmony_ci int iocpage1sz = 0; 615562306a36Sopenharmony_ci u32 tmp; 615662306a36Sopenharmony_ci 615762306a36Sopenharmony_ci /* Check the Coalescing Timeout in IOC Page 1 615862306a36Sopenharmony_ci */ 615962306a36Sopenharmony_ci header.PageVersion = 0; 616062306a36Sopenharmony_ci header.PageLength = 0; 616162306a36Sopenharmony_ci header.PageNumber = 1; 616262306a36Sopenharmony_ci header.PageType = MPI_CONFIG_PAGETYPE_IOC; 616362306a36Sopenharmony_ci cfg.cfghdr.hdr = &header; 616462306a36Sopenharmony_ci cfg.physAddr = -1; 616562306a36Sopenharmony_ci cfg.pageAddr = 0; 616662306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 616762306a36Sopenharmony_ci cfg.dir = 0; 616862306a36Sopenharmony_ci cfg.timeout = 0; 616962306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 617062306a36Sopenharmony_ci return; 617162306a36Sopenharmony_ci 617262306a36Sopenharmony_ci if (header.PageLength == 0) 617362306a36Sopenharmony_ci return; 617462306a36Sopenharmony_ci 617562306a36Sopenharmony_ci /* Read Header good, alloc memory 617662306a36Sopenharmony_ci */ 617762306a36Sopenharmony_ci iocpage1sz = header.PageLength * 4; 617862306a36Sopenharmony_ci pIoc1 = dma_alloc_coherent(&ioc->pcidev->dev, iocpage1sz, &ioc1_dma, 617962306a36Sopenharmony_ci GFP_KERNEL); 618062306a36Sopenharmony_ci if (!pIoc1) 618162306a36Sopenharmony_ci return; 618262306a36Sopenharmony_ci 618362306a36Sopenharmony_ci /* Read the Page and check coalescing timeout 618462306a36Sopenharmony_ci */ 618562306a36Sopenharmony_ci cfg.physAddr = ioc1_dma; 618662306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 618762306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) == 0) { 618862306a36Sopenharmony_ci 618962306a36Sopenharmony_ci tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING; 619062306a36Sopenharmony_ci if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) { 619162306a36Sopenharmony_ci tmp = le32_to_cpu(pIoc1->CoalescingTimeout); 619262306a36Sopenharmony_ci 619362306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n", 619462306a36Sopenharmony_ci ioc->name, tmp)); 619562306a36Sopenharmony_ci 619662306a36Sopenharmony_ci if (tmp > MPT_COALESCING_TIMEOUT) { 619762306a36Sopenharmony_ci pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT); 619862306a36Sopenharmony_ci 619962306a36Sopenharmony_ci /* Write NVRAM and current 620062306a36Sopenharmony_ci */ 620162306a36Sopenharmony_ci cfg.dir = 1; 620262306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; 620362306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) == 0) { 620462306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n", 620562306a36Sopenharmony_ci ioc->name, MPT_COALESCING_TIMEOUT)); 620662306a36Sopenharmony_ci 620762306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM; 620862306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) == 0) { 620962306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT 621062306a36Sopenharmony_ci "Reset NVRAM Coalescing Timeout to = %d\n", 621162306a36Sopenharmony_ci ioc->name, MPT_COALESCING_TIMEOUT)); 621262306a36Sopenharmony_ci } else { 621362306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_DEBUG_FMT 621462306a36Sopenharmony_ci "Reset NVRAM Coalescing Timeout Failed\n", 621562306a36Sopenharmony_ci ioc->name)); 621662306a36Sopenharmony_ci } 621762306a36Sopenharmony_ci 621862306a36Sopenharmony_ci } else { 621962306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_WARN_FMT 622062306a36Sopenharmony_ci "Reset of Current Coalescing Timeout Failed!\n", 622162306a36Sopenharmony_ci ioc->name)); 622262306a36Sopenharmony_ci } 622362306a36Sopenharmony_ci } 622462306a36Sopenharmony_ci 622562306a36Sopenharmony_ci } else { 622662306a36Sopenharmony_ci dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name)); 622762306a36Sopenharmony_ci } 622862306a36Sopenharmony_ci } 622962306a36Sopenharmony_ci 623062306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, iocpage1sz, pIoc1, ioc1_dma); 623162306a36Sopenharmony_ci 623262306a36Sopenharmony_ci return; 623362306a36Sopenharmony_ci} 623462306a36Sopenharmony_ci 623562306a36Sopenharmony_cistatic void 623662306a36Sopenharmony_cimpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc) 623762306a36Sopenharmony_ci{ 623862306a36Sopenharmony_ci CONFIGPARMS cfg; 623962306a36Sopenharmony_ci ConfigPageHeader_t hdr; 624062306a36Sopenharmony_ci dma_addr_t buf_dma; 624162306a36Sopenharmony_ci ManufacturingPage0_t *pbuf = NULL; 624262306a36Sopenharmony_ci 624362306a36Sopenharmony_ci memset(&cfg, 0 , sizeof(CONFIGPARMS)); 624462306a36Sopenharmony_ci memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); 624562306a36Sopenharmony_ci 624662306a36Sopenharmony_ci hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING; 624762306a36Sopenharmony_ci cfg.cfghdr.hdr = &hdr; 624862306a36Sopenharmony_ci cfg.physAddr = -1; 624962306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; 625062306a36Sopenharmony_ci cfg.timeout = 10; 625162306a36Sopenharmony_ci 625262306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 625362306a36Sopenharmony_ci goto out; 625462306a36Sopenharmony_ci 625562306a36Sopenharmony_ci if (!cfg.cfghdr.hdr->PageLength) 625662306a36Sopenharmony_ci goto out; 625762306a36Sopenharmony_ci 625862306a36Sopenharmony_ci cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 625962306a36Sopenharmony_ci pbuf = dma_alloc_coherent(&ioc->pcidev->dev, hdr.PageLength * 4, 626062306a36Sopenharmony_ci &buf_dma, GFP_KERNEL); 626162306a36Sopenharmony_ci if (!pbuf) 626262306a36Sopenharmony_ci goto out; 626362306a36Sopenharmony_ci 626462306a36Sopenharmony_ci cfg.physAddr = buf_dma; 626562306a36Sopenharmony_ci 626662306a36Sopenharmony_ci if (mpt_config(ioc, &cfg) != 0) 626762306a36Sopenharmony_ci goto out; 626862306a36Sopenharmony_ci 626962306a36Sopenharmony_ci memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name)); 627062306a36Sopenharmony_ci memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly)); 627162306a36Sopenharmony_ci memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer)); 627262306a36Sopenharmony_ci 627362306a36Sopenharmony_ciout: 627462306a36Sopenharmony_ci 627562306a36Sopenharmony_ci if (pbuf) 627662306a36Sopenharmony_ci dma_free_coherent(&ioc->pcidev->dev, hdr.PageLength * 4, pbuf, 627762306a36Sopenharmony_ci buf_dma); 627862306a36Sopenharmony_ci} 627962306a36Sopenharmony_ci 628062306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 628162306a36Sopenharmony_ci/** 628262306a36Sopenharmony_ci * SendEventNotification - Send EventNotification (on or off) request to adapter 628362306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 628462306a36Sopenharmony_ci * @EvSwitch: Event switch flags 628562306a36Sopenharmony_ci * @sleepFlag: Specifies whether the process can sleep 628662306a36Sopenharmony_ci */ 628762306a36Sopenharmony_cistatic int 628862306a36Sopenharmony_ciSendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag) 628962306a36Sopenharmony_ci{ 629062306a36Sopenharmony_ci EventNotification_t evn; 629162306a36Sopenharmony_ci MPIDefaultReply_t reply_buf; 629262306a36Sopenharmony_ci 629362306a36Sopenharmony_ci memset(&evn, 0, sizeof(EventNotification_t)); 629462306a36Sopenharmony_ci memset(&reply_buf, 0, sizeof(MPIDefaultReply_t)); 629562306a36Sopenharmony_ci 629662306a36Sopenharmony_ci evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION; 629762306a36Sopenharmony_ci evn.Switch = EvSwitch; 629862306a36Sopenharmony_ci evn.MsgContext = cpu_to_le32(mpt_base_index << 16); 629962306a36Sopenharmony_ci 630062306a36Sopenharmony_ci devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT 630162306a36Sopenharmony_ci "Sending EventNotification (%d) request %p\n", 630262306a36Sopenharmony_ci ioc->name, EvSwitch, &evn)); 630362306a36Sopenharmony_ci 630462306a36Sopenharmony_ci return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t), 630562306a36Sopenharmony_ci (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30, 630662306a36Sopenharmony_ci sleepFlag); 630762306a36Sopenharmony_ci} 630862306a36Sopenharmony_ci 630962306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 631062306a36Sopenharmony_ci/** 631162306a36Sopenharmony_ci * SendEventAck - Send EventAck request to MPT adapter. 631262306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 631362306a36Sopenharmony_ci * @evnp: Pointer to original EventNotification request 631462306a36Sopenharmony_ci */ 631562306a36Sopenharmony_cistatic int 631662306a36Sopenharmony_ciSendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp) 631762306a36Sopenharmony_ci{ 631862306a36Sopenharmony_ci EventAck_t *pAck; 631962306a36Sopenharmony_ci 632062306a36Sopenharmony_ci if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { 632162306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n", 632262306a36Sopenharmony_ci ioc->name, __func__)); 632362306a36Sopenharmony_ci return -1; 632462306a36Sopenharmony_ci } 632562306a36Sopenharmony_ci 632662306a36Sopenharmony_ci devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name)); 632762306a36Sopenharmony_ci 632862306a36Sopenharmony_ci pAck->Function = MPI_FUNCTION_EVENT_ACK; 632962306a36Sopenharmony_ci pAck->ChainOffset = 0; 633062306a36Sopenharmony_ci pAck->Reserved[0] = pAck->Reserved[1] = 0; 633162306a36Sopenharmony_ci pAck->MsgFlags = 0; 633262306a36Sopenharmony_ci pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0; 633362306a36Sopenharmony_ci pAck->Event = evnp->Event; 633462306a36Sopenharmony_ci pAck->EventContext = evnp->EventContext; 633562306a36Sopenharmony_ci 633662306a36Sopenharmony_ci mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck); 633762306a36Sopenharmony_ci 633862306a36Sopenharmony_ci return 0; 633962306a36Sopenharmony_ci} 634062306a36Sopenharmony_ci 634162306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 634262306a36Sopenharmony_ci/** 634362306a36Sopenharmony_ci * mpt_config - Generic function to issue config message 634462306a36Sopenharmony_ci * @ioc: Pointer to an adapter structure 634562306a36Sopenharmony_ci * @pCfg: Pointer to a configuration structure. Struct contains 634662306a36Sopenharmony_ci * action, page address, direction, physical address 634762306a36Sopenharmony_ci * and pointer to a configuration page header 634862306a36Sopenharmony_ci * Page header is updated. 634962306a36Sopenharmony_ci * 635062306a36Sopenharmony_ci * Returns 0 for success 635162306a36Sopenharmony_ci * -EAGAIN if no msg frames currently available 635262306a36Sopenharmony_ci * -EFAULT for non-successful reply or no reply (timeout) 635362306a36Sopenharmony_ci */ 635462306a36Sopenharmony_ciint 635562306a36Sopenharmony_cimpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) 635662306a36Sopenharmony_ci{ 635762306a36Sopenharmony_ci Config_t *pReq; 635862306a36Sopenharmony_ci ConfigReply_t *pReply; 635962306a36Sopenharmony_ci ConfigExtendedPageHeader_t *pExtHdr = NULL; 636062306a36Sopenharmony_ci MPT_FRAME_HDR *mf; 636162306a36Sopenharmony_ci int ii; 636262306a36Sopenharmony_ci int flagsLength; 636362306a36Sopenharmony_ci long timeout; 636462306a36Sopenharmony_ci int ret; 636562306a36Sopenharmony_ci u8 page_type = 0, extend_page; 636662306a36Sopenharmony_ci unsigned long timeleft; 636762306a36Sopenharmony_ci unsigned long flags; 636862306a36Sopenharmony_ci u8 issue_hard_reset = 0; 636962306a36Sopenharmony_ci u8 retry_count = 0; 637062306a36Sopenharmony_ci 637162306a36Sopenharmony_ci might_sleep(); 637262306a36Sopenharmony_ci 637362306a36Sopenharmony_ci /* don't send a config page during diag reset */ 637462306a36Sopenharmony_ci spin_lock_irqsave(&ioc->taskmgmt_lock, flags); 637562306a36Sopenharmony_ci if (ioc->ioc_reset_in_progress) { 637662306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT 637762306a36Sopenharmony_ci "%s: busy with host reset\n", ioc->name, __func__)); 637862306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 637962306a36Sopenharmony_ci return -EBUSY; 638062306a36Sopenharmony_ci } 638162306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 638262306a36Sopenharmony_ci 638362306a36Sopenharmony_ci /* don't send if no chance of success */ 638462306a36Sopenharmony_ci if (!ioc->active || 638562306a36Sopenharmony_ci mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) { 638662306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT 638762306a36Sopenharmony_ci "%s: ioc not operational, %d, %xh\n", 638862306a36Sopenharmony_ci ioc->name, __func__, ioc->active, 638962306a36Sopenharmony_ci mpt_GetIocState(ioc, 0))); 639062306a36Sopenharmony_ci return -EFAULT; 639162306a36Sopenharmony_ci } 639262306a36Sopenharmony_ci 639362306a36Sopenharmony_ci retry_config: 639462306a36Sopenharmony_ci mutex_lock(&ioc->mptbase_cmds.mutex); 639562306a36Sopenharmony_ci /* init the internal cmd struct */ 639662306a36Sopenharmony_ci memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE); 639762306a36Sopenharmony_ci INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status) 639862306a36Sopenharmony_ci 639962306a36Sopenharmony_ci /* Get and Populate a free Frame 640062306a36Sopenharmony_ci */ 640162306a36Sopenharmony_ci if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { 640262306a36Sopenharmony_ci dcprintk(ioc, printk(MYIOC_s_WARN_FMT 640362306a36Sopenharmony_ci "mpt_config: no msg frames!\n", ioc->name)); 640462306a36Sopenharmony_ci ret = -EAGAIN; 640562306a36Sopenharmony_ci goto out; 640662306a36Sopenharmony_ci } 640762306a36Sopenharmony_ci 640862306a36Sopenharmony_ci pReq = (Config_t *)mf; 640962306a36Sopenharmony_ci pReq->Action = pCfg->action; 641062306a36Sopenharmony_ci pReq->Reserved = 0; 641162306a36Sopenharmony_ci pReq->ChainOffset = 0; 641262306a36Sopenharmony_ci pReq->Function = MPI_FUNCTION_CONFIG; 641362306a36Sopenharmony_ci 641462306a36Sopenharmony_ci /* Assume page type is not extended and clear "reserved" fields. */ 641562306a36Sopenharmony_ci pReq->ExtPageLength = 0; 641662306a36Sopenharmony_ci pReq->ExtPageType = 0; 641762306a36Sopenharmony_ci pReq->MsgFlags = 0; 641862306a36Sopenharmony_ci 641962306a36Sopenharmony_ci for (ii=0; ii < 8; ii++) 642062306a36Sopenharmony_ci pReq->Reserved2[ii] = 0; 642162306a36Sopenharmony_ci 642262306a36Sopenharmony_ci pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion; 642362306a36Sopenharmony_ci pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength; 642462306a36Sopenharmony_ci pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber; 642562306a36Sopenharmony_ci pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK); 642662306a36Sopenharmony_ci 642762306a36Sopenharmony_ci if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) { 642862306a36Sopenharmony_ci pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr; 642962306a36Sopenharmony_ci pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength); 643062306a36Sopenharmony_ci pReq->ExtPageType = pExtHdr->ExtPageType; 643162306a36Sopenharmony_ci pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 643262306a36Sopenharmony_ci 643362306a36Sopenharmony_ci /* Page Length must be treated as a reserved field for the 643462306a36Sopenharmony_ci * extended header. 643562306a36Sopenharmony_ci */ 643662306a36Sopenharmony_ci pReq->Header.PageLength = 0; 643762306a36Sopenharmony_ci } 643862306a36Sopenharmony_ci 643962306a36Sopenharmony_ci pReq->PageAddress = cpu_to_le32(pCfg->pageAddr); 644062306a36Sopenharmony_ci 644162306a36Sopenharmony_ci /* Add a SGE to the config request. 644262306a36Sopenharmony_ci */ 644362306a36Sopenharmony_ci if (pCfg->dir) 644462306a36Sopenharmony_ci flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; 644562306a36Sopenharmony_ci else 644662306a36Sopenharmony_ci flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; 644762306a36Sopenharmony_ci 644862306a36Sopenharmony_ci if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == 644962306a36Sopenharmony_ci MPI_CONFIG_PAGETYPE_EXTENDED) { 645062306a36Sopenharmony_ci flagsLength |= pExtHdr->ExtPageLength * 4; 645162306a36Sopenharmony_ci page_type = pReq->ExtPageType; 645262306a36Sopenharmony_ci extend_page = 1; 645362306a36Sopenharmony_ci } else { 645462306a36Sopenharmony_ci flagsLength |= pCfg->cfghdr.hdr->PageLength * 4; 645562306a36Sopenharmony_ci page_type = pReq->Header.PageType; 645662306a36Sopenharmony_ci extend_page = 0; 645762306a36Sopenharmony_ci } 645862306a36Sopenharmony_ci 645962306a36Sopenharmony_ci dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT 646062306a36Sopenharmony_ci "Sending Config request type 0x%x, page 0x%x and action %d\n", 646162306a36Sopenharmony_ci ioc->name, page_type, pReq->Header.PageNumber, pReq->Action)); 646262306a36Sopenharmony_ci 646362306a36Sopenharmony_ci ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr); 646462306a36Sopenharmony_ci timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout; 646562306a36Sopenharmony_ci mpt_put_msg_frame(mpt_base_index, ioc, mf); 646662306a36Sopenharmony_ci timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 646762306a36Sopenharmony_ci timeout); 646862306a36Sopenharmony_ci if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { 646962306a36Sopenharmony_ci ret = -ETIME; 647062306a36Sopenharmony_ci dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT 647162306a36Sopenharmony_ci "Failed Sending Config request type 0x%x, page 0x%x," 647262306a36Sopenharmony_ci " action %d, status %xh, time left %ld\n\n", 647362306a36Sopenharmony_ci ioc->name, page_type, pReq->Header.PageNumber, 647462306a36Sopenharmony_ci pReq->Action, ioc->mptbase_cmds.status, timeleft)); 647562306a36Sopenharmony_ci if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) 647662306a36Sopenharmony_ci goto out; 647762306a36Sopenharmony_ci if (!timeleft) { 647862306a36Sopenharmony_ci spin_lock_irqsave(&ioc->taskmgmt_lock, flags); 647962306a36Sopenharmony_ci if (ioc->ioc_reset_in_progress) { 648062306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, 648162306a36Sopenharmony_ci flags); 648262306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "%s: host reset in" 648362306a36Sopenharmony_ci " progress mpt_config timed out.!!\n", 648462306a36Sopenharmony_ci __func__, ioc->name); 648562306a36Sopenharmony_ci mutex_unlock(&ioc->mptbase_cmds.mutex); 648662306a36Sopenharmony_ci return -EFAULT; 648762306a36Sopenharmony_ci } 648862306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 648962306a36Sopenharmony_ci issue_hard_reset = 1; 649062306a36Sopenharmony_ci } 649162306a36Sopenharmony_ci goto out; 649262306a36Sopenharmony_ci } 649362306a36Sopenharmony_ci 649462306a36Sopenharmony_ci if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { 649562306a36Sopenharmony_ci ret = -1; 649662306a36Sopenharmony_ci goto out; 649762306a36Sopenharmony_ci } 649862306a36Sopenharmony_ci pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply; 649962306a36Sopenharmony_ci ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK; 650062306a36Sopenharmony_ci if (ret == MPI_IOCSTATUS_SUCCESS) { 650162306a36Sopenharmony_ci if (extend_page) { 650262306a36Sopenharmony_ci pCfg->cfghdr.ehdr->ExtPageLength = 650362306a36Sopenharmony_ci le16_to_cpu(pReply->ExtPageLength); 650462306a36Sopenharmony_ci pCfg->cfghdr.ehdr->ExtPageType = 650562306a36Sopenharmony_ci pReply->ExtPageType; 650662306a36Sopenharmony_ci } 650762306a36Sopenharmony_ci pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion; 650862306a36Sopenharmony_ci pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength; 650962306a36Sopenharmony_ci pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber; 651062306a36Sopenharmony_ci pCfg->cfghdr.hdr->PageType = pReply->Header.PageType; 651162306a36Sopenharmony_ci 651262306a36Sopenharmony_ci } 651362306a36Sopenharmony_ci 651462306a36Sopenharmony_ci if (retry_count) 651562306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "Retry completed " 651662306a36Sopenharmony_ci "ret=0x%x timeleft=%ld\n", 651762306a36Sopenharmony_ci ioc->name, ret, timeleft); 651862306a36Sopenharmony_ci 651962306a36Sopenharmony_ci dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n", 652062306a36Sopenharmony_ci ret, le32_to_cpu(pReply->IOCLogInfo))); 652162306a36Sopenharmony_ci 652262306a36Sopenharmony_ciout: 652362306a36Sopenharmony_ci 652462306a36Sopenharmony_ci CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status) 652562306a36Sopenharmony_ci mutex_unlock(&ioc->mptbase_cmds.mutex); 652662306a36Sopenharmony_ci if (issue_hard_reset) { 652762306a36Sopenharmony_ci issue_hard_reset = 0; 652862306a36Sopenharmony_ci printk(MYIOC_s_WARN_FMT 652962306a36Sopenharmony_ci "Issuing Reset from %s!!, doorbell=0x%08x\n", 653062306a36Sopenharmony_ci ioc->name, __func__, mpt_GetIocState(ioc, 0)); 653162306a36Sopenharmony_ci if (retry_count == 0) { 653262306a36Sopenharmony_ci if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0) 653362306a36Sopenharmony_ci retry_count++; 653462306a36Sopenharmony_ci } else 653562306a36Sopenharmony_ci mpt_HardResetHandler(ioc, CAN_SLEEP); 653662306a36Sopenharmony_ci 653762306a36Sopenharmony_ci mpt_free_msg_frame(ioc, mf); 653862306a36Sopenharmony_ci /* attempt one retry for a timed out command */ 653962306a36Sopenharmony_ci if (retry_count < 2) { 654062306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT 654162306a36Sopenharmony_ci "Attempting Retry Config request" 654262306a36Sopenharmony_ci " type 0x%x, page 0x%x," 654362306a36Sopenharmony_ci " action %d\n", ioc->name, page_type, 654462306a36Sopenharmony_ci pCfg->cfghdr.hdr->PageNumber, pCfg->action); 654562306a36Sopenharmony_ci retry_count++; 654662306a36Sopenharmony_ci goto retry_config; 654762306a36Sopenharmony_ci } 654862306a36Sopenharmony_ci } 654962306a36Sopenharmony_ci return ret; 655062306a36Sopenharmony_ci 655162306a36Sopenharmony_ci} 655262306a36Sopenharmony_ci 655362306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 655462306a36Sopenharmony_ci/** 655562306a36Sopenharmony_ci * mpt_ioc_reset - Base cleanup for hard reset 655662306a36Sopenharmony_ci * @ioc: Pointer to the adapter structure 655762306a36Sopenharmony_ci * @reset_phase: Indicates pre- or post-reset functionality 655862306a36Sopenharmony_ci * 655962306a36Sopenharmony_ci * Remark: Frees resources with internally generated commands. 656062306a36Sopenharmony_ci */ 656162306a36Sopenharmony_cistatic int 656262306a36Sopenharmony_cimpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) 656362306a36Sopenharmony_ci{ 656462306a36Sopenharmony_ci switch (reset_phase) { 656562306a36Sopenharmony_ci case MPT_IOC_SETUP_RESET: 656662306a36Sopenharmony_ci ioc->taskmgmt_quiesce_io = 1; 656762306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 656862306a36Sopenharmony_ci "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__)); 656962306a36Sopenharmony_ci break; 657062306a36Sopenharmony_ci case MPT_IOC_PRE_RESET: 657162306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 657262306a36Sopenharmony_ci "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__)); 657362306a36Sopenharmony_ci break; 657462306a36Sopenharmony_ci case MPT_IOC_POST_RESET: 657562306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 657662306a36Sopenharmony_ci "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__)); 657762306a36Sopenharmony_ci/* wake up mptbase_cmds */ 657862306a36Sopenharmony_ci if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) { 657962306a36Sopenharmony_ci ioc->mptbase_cmds.status |= 658062306a36Sopenharmony_ci MPT_MGMT_STATUS_DID_IOCRESET; 658162306a36Sopenharmony_ci complete(&ioc->mptbase_cmds.done); 658262306a36Sopenharmony_ci } 658362306a36Sopenharmony_ci/* wake up taskmgmt_cmds */ 658462306a36Sopenharmony_ci if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { 658562306a36Sopenharmony_ci ioc->taskmgmt_cmds.status |= 658662306a36Sopenharmony_ci MPT_MGMT_STATUS_DID_IOCRESET; 658762306a36Sopenharmony_ci complete(&ioc->taskmgmt_cmds.done); 658862306a36Sopenharmony_ci } 658962306a36Sopenharmony_ci break; 659062306a36Sopenharmony_ci default: 659162306a36Sopenharmony_ci break; 659262306a36Sopenharmony_ci } 659362306a36Sopenharmony_ci 659462306a36Sopenharmony_ci return 1; /* currently means nothing really */ 659562306a36Sopenharmony_ci} 659662306a36Sopenharmony_ci 659762306a36Sopenharmony_ci 659862306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS /* { */ 659962306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 660062306a36Sopenharmony_ci/* 660162306a36Sopenharmony_ci * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff... 660262306a36Sopenharmony_ci */ 660362306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 660462306a36Sopenharmony_ci/** 660562306a36Sopenharmony_ci * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries. 660662306a36Sopenharmony_ci * 660762306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure. 660862306a36Sopenharmony_ci */ 660962306a36Sopenharmony_cistatic int 661062306a36Sopenharmony_ciprocmpt_create(void) 661162306a36Sopenharmony_ci{ 661262306a36Sopenharmony_ci mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL); 661362306a36Sopenharmony_ci if (mpt_proc_root_dir == NULL) 661462306a36Sopenharmony_ci return -ENOTDIR; 661562306a36Sopenharmony_ci 661662306a36Sopenharmony_ci proc_create_single("summary", S_IRUGO, mpt_proc_root_dir, 661762306a36Sopenharmony_ci mpt_summary_proc_show); 661862306a36Sopenharmony_ci proc_create_single("version", S_IRUGO, mpt_proc_root_dir, 661962306a36Sopenharmony_ci mpt_version_proc_show); 662062306a36Sopenharmony_ci return 0; 662162306a36Sopenharmony_ci} 662262306a36Sopenharmony_ci 662362306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 662462306a36Sopenharmony_ci/** 662562306a36Sopenharmony_ci * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries. 662662306a36Sopenharmony_ci * 662762306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure. 662862306a36Sopenharmony_ci */ 662962306a36Sopenharmony_cistatic void 663062306a36Sopenharmony_ciprocmpt_destroy(void) 663162306a36Sopenharmony_ci{ 663262306a36Sopenharmony_ci remove_proc_entry("version", mpt_proc_root_dir); 663362306a36Sopenharmony_ci remove_proc_entry("summary", mpt_proc_root_dir); 663462306a36Sopenharmony_ci remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL); 663562306a36Sopenharmony_ci} 663662306a36Sopenharmony_ci 663762306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 663862306a36Sopenharmony_ci/* 663962306a36Sopenharmony_ci * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary. 664062306a36Sopenharmony_ci */ 664162306a36Sopenharmony_cistatic void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan); 664262306a36Sopenharmony_ci 664362306a36Sopenharmony_cistatic int mpt_summary_proc_show(struct seq_file *m, void *v) 664462306a36Sopenharmony_ci{ 664562306a36Sopenharmony_ci MPT_ADAPTER *ioc = m->private; 664662306a36Sopenharmony_ci 664762306a36Sopenharmony_ci if (ioc) { 664862306a36Sopenharmony_ci seq_mpt_print_ioc_summary(ioc, m, 1); 664962306a36Sopenharmony_ci } else { 665062306a36Sopenharmony_ci list_for_each_entry(ioc, &ioc_list, list) { 665162306a36Sopenharmony_ci seq_mpt_print_ioc_summary(ioc, m, 1); 665262306a36Sopenharmony_ci } 665362306a36Sopenharmony_ci } 665462306a36Sopenharmony_ci 665562306a36Sopenharmony_ci return 0; 665662306a36Sopenharmony_ci} 665762306a36Sopenharmony_ci 665862306a36Sopenharmony_cistatic int mpt_version_proc_show(struct seq_file *m, void *v) 665962306a36Sopenharmony_ci{ 666062306a36Sopenharmony_ci u8 cb_idx; 666162306a36Sopenharmony_ci int scsi, fc, sas, lan, ctl, targ; 666262306a36Sopenharmony_ci char *drvname; 666362306a36Sopenharmony_ci 666462306a36Sopenharmony_ci seq_printf(m, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON); 666562306a36Sopenharmony_ci seq_printf(m, " Fusion MPT base driver\n"); 666662306a36Sopenharmony_ci 666762306a36Sopenharmony_ci scsi = fc = sas = lan = ctl = targ = 0; 666862306a36Sopenharmony_ci for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { 666962306a36Sopenharmony_ci drvname = NULL; 667062306a36Sopenharmony_ci if (MptCallbacks[cb_idx]) { 667162306a36Sopenharmony_ci switch (MptDriverClass[cb_idx]) { 667262306a36Sopenharmony_ci case MPTSPI_DRIVER: 667362306a36Sopenharmony_ci if (!scsi++) drvname = "SPI host"; 667462306a36Sopenharmony_ci break; 667562306a36Sopenharmony_ci case MPTFC_DRIVER: 667662306a36Sopenharmony_ci if (!fc++) drvname = "FC host"; 667762306a36Sopenharmony_ci break; 667862306a36Sopenharmony_ci case MPTSAS_DRIVER: 667962306a36Sopenharmony_ci if (!sas++) drvname = "SAS host"; 668062306a36Sopenharmony_ci break; 668162306a36Sopenharmony_ci case MPTLAN_DRIVER: 668262306a36Sopenharmony_ci if (!lan++) drvname = "LAN"; 668362306a36Sopenharmony_ci break; 668462306a36Sopenharmony_ci case MPTSTM_DRIVER: 668562306a36Sopenharmony_ci if (!targ++) drvname = "SCSI target"; 668662306a36Sopenharmony_ci break; 668762306a36Sopenharmony_ci case MPTCTL_DRIVER: 668862306a36Sopenharmony_ci if (!ctl++) drvname = "ioctl"; 668962306a36Sopenharmony_ci break; 669062306a36Sopenharmony_ci } 669162306a36Sopenharmony_ci 669262306a36Sopenharmony_ci if (drvname) 669362306a36Sopenharmony_ci seq_printf(m, " Fusion MPT %s driver\n", drvname); 669462306a36Sopenharmony_ci } 669562306a36Sopenharmony_ci } 669662306a36Sopenharmony_ci 669762306a36Sopenharmony_ci return 0; 669862306a36Sopenharmony_ci} 669962306a36Sopenharmony_ci 670062306a36Sopenharmony_cistatic int mpt_iocinfo_proc_show(struct seq_file *m, void *v) 670162306a36Sopenharmony_ci{ 670262306a36Sopenharmony_ci MPT_ADAPTER *ioc = m->private; 670362306a36Sopenharmony_ci char expVer[32]; 670462306a36Sopenharmony_ci int sz; 670562306a36Sopenharmony_ci int p; 670662306a36Sopenharmony_ci 670762306a36Sopenharmony_ci mpt_get_fw_exp_ver(expVer, ioc); 670862306a36Sopenharmony_ci 670962306a36Sopenharmony_ci seq_printf(m, "%s:", ioc->name); 671062306a36Sopenharmony_ci if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) 671162306a36Sopenharmony_ci seq_printf(m, " (f/w download boot flag set)"); 671262306a36Sopenharmony_ci// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL) 671362306a36Sopenharmony_ci// seq_printf(m, " CONFIG_CHECKSUM_FAIL!"); 671462306a36Sopenharmony_ci 671562306a36Sopenharmony_ci seq_printf(m, "\n ProductID = 0x%04x (%s)\n", 671662306a36Sopenharmony_ci ioc->facts.ProductID, 671762306a36Sopenharmony_ci ioc->prod_name); 671862306a36Sopenharmony_ci seq_printf(m, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer); 671962306a36Sopenharmony_ci if (ioc->facts.FWImageSize) 672062306a36Sopenharmony_ci seq_printf(m, " (fw_size=%d)", ioc->facts.FWImageSize); 672162306a36Sopenharmony_ci seq_printf(m, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion); 672262306a36Sopenharmony_ci seq_printf(m, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit); 672362306a36Sopenharmony_ci seq_printf(m, " EventState = 0x%02x\n", ioc->facts.EventState); 672462306a36Sopenharmony_ci 672562306a36Sopenharmony_ci seq_printf(m, " CurrentHostMfaHighAddr = 0x%08x\n", 672662306a36Sopenharmony_ci ioc->facts.CurrentHostMfaHighAddr); 672762306a36Sopenharmony_ci seq_printf(m, " CurrentSenseBufferHighAddr = 0x%08x\n", 672862306a36Sopenharmony_ci ioc->facts.CurrentSenseBufferHighAddr); 672962306a36Sopenharmony_ci 673062306a36Sopenharmony_ci seq_printf(m, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth); 673162306a36Sopenharmony_ci seq_printf(m, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize); 673262306a36Sopenharmony_ci 673362306a36Sopenharmony_ci seq_printf(m, " RequestFrames @ 0x%p (Dma @ 0x%p)\n", 673462306a36Sopenharmony_ci (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma); 673562306a36Sopenharmony_ci /* 673662306a36Sopenharmony_ci * Rounding UP to nearest 4-kB boundary here... 673762306a36Sopenharmony_ci */ 673862306a36Sopenharmony_ci sz = (ioc->req_sz * ioc->req_depth) + 128; 673962306a36Sopenharmony_ci sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; 674062306a36Sopenharmony_ci seq_printf(m, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n", 674162306a36Sopenharmony_ci ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz); 674262306a36Sopenharmony_ci seq_printf(m, " {MaxReqSz=%d} {MaxReqDepth=%d}\n", 674362306a36Sopenharmony_ci 4*ioc->facts.RequestFrameSize, 674462306a36Sopenharmony_ci ioc->facts.GlobalCredits); 674562306a36Sopenharmony_ci 674662306a36Sopenharmony_ci seq_printf(m, " Frames @ 0x%p (Dma @ 0x%p)\n", 674762306a36Sopenharmony_ci (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma); 674862306a36Sopenharmony_ci sz = (ioc->reply_sz * ioc->reply_depth) + 128; 674962306a36Sopenharmony_ci seq_printf(m, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n", 675062306a36Sopenharmony_ci ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz); 675162306a36Sopenharmony_ci seq_printf(m, " {MaxRepSz=%d} {MaxRepDepth=%d}\n", 675262306a36Sopenharmony_ci ioc->facts.CurReplyFrameSize, 675362306a36Sopenharmony_ci ioc->facts.ReplyQueueDepth); 675462306a36Sopenharmony_ci 675562306a36Sopenharmony_ci seq_printf(m, " MaxDevices = %d\n", 675662306a36Sopenharmony_ci (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices); 675762306a36Sopenharmony_ci seq_printf(m, " MaxBuses = %d\n", ioc->facts.MaxBuses); 675862306a36Sopenharmony_ci 675962306a36Sopenharmony_ci /* per-port info */ 676062306a36Sopenharmony_ci for (p=0; p < ioc->facts.NumberOfPorts; p++) { 676162306a36Sopenharmony_ci seq_printf(m, " PortNumber = %d (of %d)\n", 676262306a36Sopenharmony_ci p+1, 676362306a36Sopenharmony_ci ioc->facts.NumberOfPorts); 676462306a36Sopenharmony_ci if (ioc->bus_type == FC) { 676562306a36Sopenharmony_ci if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { 676662306a36Sopenharmony_ci u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; 676762306a36Sopenharmony_ci seq_printf(m, " LanAddr = %pMR\n", a); 676862306a36Sopenharmony_ci } 676962306a36Sopenharmony_ci seq_printf(m, " WWN = %08X%08X:%08X%08X\n", 677062306a36Sopenharmony_ci ioc->fc_port_page0[p].WWNN.High, 677162306a36Sopenharmony_ci ioc->fc_port_page0[p].WWNN.Low, 677262306a36Sopenharmony_ci ioc->fc_port_page0[p].WWPN.High, 677362306a36Sopenharmony_ci ioc->fc_port_page0[p].WWPN.Low); 677462306a36Sopenharmony_ci } 677562306a36Sopenharmony_ci } 677662306a36Sopenharmony_ci 677762306a36Sopenharmony_ci return 0; 677862306a36Sopenharmony_ci} 677962306a36Sopenharmony_ci#endif /* CONFIG_PROC_FS } */ 678062306a36Sopenharmony_ci 678162306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 678262306a36Sopenharmony_cistatic void 678362306a36Sopenharmony_cimpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc) 678462306a36Sopenharmony_ci{ 678562306a36Sopenharmony_ci buf[0] ='\0'; 678662306a36Sopenharmony_ci if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) { 678762306a36Sopenharmony_ci sprintf(buf, " (Exp %02d%02d)", 678862306a36Sopenharmony_ci (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */ 678962306a36Sopenharmony_ci (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */ 679062306a36Sopenharmony_ci 679162306a36Sopenharmony_ci /* insider hack! */ 679262306a36Sopenharmony_ci if ((ioc->facts.FWVersion.Word >> 8) & 0x80) 679362306a36Sopenharmony_ci strcat(buf, " [MDBG]"); 679462306a36Sopenharmony_ci } 679562306a36Sopenharmony_ci} 679662306a36Sopenharmony_ci 679762306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 679862306a36Sopenharmony_ci/** 679962306a36Sopenharmony_ci * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer. 680062306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 680162306a36Sopenharmony_ci * @buffer: Pointer to buffer where IOC summary info should be written 680262306a36Sopenharmony_ci * @size: Pointer to number of bytes we wrote (set by this routine) 680362306a36Sopenharmony_ci * @len: Offset at which to start writing in buffer 680462306a36Sopenharmony_ci * @showlan: Display LAN stuff? 680562306a36Sopenharmony_ci * 680662306a36Sopenharmony_ci * This routine writes (english readable) ASCII text, which represents 680762306a36Sopenharmony_ci * a summary of IOC information, to a buffer. 680862306a36Sopenharmony_ci */ 680962306a36Sopenharmony_civoid 681062306a36Sopenharmony_cimpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan) 681162306a36Sopenharmony_ci{ 681262306a36Sopenharmony_ci char expVer[32]; 681362306a36Sopenharmony_ci int y; 681462306a36Sopenharmony_ci 681562306a36Sopenharmony_ci mpt_get_fw_exp_ver(expVer, ioc); 681662306a36Sopenharmony_ci 681762306a36Sopenharmony_ci /* 681862306a36Sopenharmony_ci * Shorter summary of attached ioc's... 681962306a36Sopenharmony_ci */ 682062306a36Sopenharmony_ci y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d", 682162306a36Sopenharmony_ci ioc->name, 682262306a36Sopenharmony_ci ioc->prod_name, 682362306a36Sopenharmony_ci MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */ 682462306a36Sopenharmony_ci ioc->facts.FWVersion.Word, 682562306a36Sopenharmony_ci expVer, 682662306a36Sopenharmony_ci ioc->facts.NumberOfPorts, 682762306a36Sopenharmony_ci ioc->req_depth); 682862306a36Sopenharmony_ci 682962306a36Sopenharmony_ci if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) { 683062306a36Sopenharmony_ci u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; 683162306a36Sopenharmony_ci y += sprintf(buffer+len+y, ", LanAddr=%pMR", a); 683262306a36Sopenharmony_ci } 683362306a36Sopenharmony_ci 683462306a36Sopenharmony_ci y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq); 683562306a36Sopenharmony_ci 683662306a36Sopenharmony_ci if (!ioc->active) 683762306a36Sopenharmony_ci y += sprintf(buffer+len+y, " (disabled)"); 683862306a36Sopenharmony_ci 683962306a36Sopenharmony_ci y += sprintf(buffer+len+y, "\n"); 684062306a36Sopenharmony_ci 684162306a36Sopenharmony_ci *size = y; 684262306a36Sopenharmony_ci} 684362306a36Sopenharmony_ci 684462306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 684562306a36Sopenharmony_cistatic void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan) 684662306a36Sopenharmony_ci{ 684762306a36Sopenharmony_ci char expVer[32]; 684862306a36Sopenharmony_ci 684962306a36Sopenharmony_ci mpt_get_fw_exp_ver(expVer, ioc); 685062306a36Sopenharmony_ci 685162306a36Sopenharmony_ci /* 685262306a36Sopenharmony_ci * Shorter summary of attached ioc's... 685362306a36Sopenharmony_ci */ 685462306a36Sopenharmony_ci seq_printf(m, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d", 685562306a36Sopenharmony_ci ioc->name, 685662306a36Sopenharmony_ci ioc->prod_name, 685762306a36Sopenharmony_ci MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */ 685862306a36Sopenharmony_ci ioc->facts.FWVersion.Word, 685962306a36Sopenharmony_ci expVer, 686062306a36Sopenharmony_ci ioc->facts.NumberOfPorts, 686162306a36Sopenharmony_ci ioc->req_depth); 686262306a36Sopenharmony_ci 686362306a36Sopenharmony_ci if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) { 686462306a36Sopenharmony_ci u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; 686562306a36Sopenharmony_ci seq_printf(m, ", LanAddr=%pMR", a); 686662306a36Sopenharmony_ci } 686762306a36Sopenharmony_ci 686862306a36Sopenharmony_ci seq_printf(m, ", IRQ=%d", ioc->pci_irq); 686962306a36Sopenharmony_ci 687062306a36Sopenharmony_ci if (!ioc->active) 687162306a36Sopenharmony_ci seq_printf(m, " (disabled)"); 687262306a36Sopenharmony_ci 687362306a36Sopenharmony_ci seq_putc(m, '\n'); 687462306a36Sopenharmony_ci} 687562306a36Sopenharmony_ci#endif 687662306a36Sopenharmony_ci 687762306a36Sopenharmony_ci/** 687862306a36Sopenharmony_ci * mpt_set_taskmgmt_in_progress_flag - set flags associated with task management 687962306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 688062306a36Sopenharmony_ci * 688162306a36Sopenharmony_ci * Returns 0 for SUCCESS or -1 if FAILED. 688262306a36Sopenharmony_ci * 688362306a36Sopenharmony_ci * If -1 is return, then it was not possible to set the flags 688462306a36Sopenharmony_ci **/ 688562306a36Sopenharmony_ciint 688662306a36Sopenharmony_cimpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc) 688762306a36Sopenharmony_ci{ 688862306a36Sopenharmony_ci unsigned long flags; 688962306a36Sopenharmony_ci int retval; 689062306a36Sopenharmony_ci 689162306a36Sopenharmony_ci spin_lock_irqsave(&ioc->taskmgmt_lock, flags); 689262306a36Sopenharmony_ci if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress || 689362306a36Sopenharmony_ci (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) { 689462306a36Sopenharmony_ci retval = -1; 689562306a36Sopenharmony_ci goto out; 689662306a36Sopenharmony_ci } 689762306a36Sopenharmony_ci retval = 0; 689862306a36Sopenharmony_ci ioc->taskmgmt_in_progress = 1; 689962306a36Sopenharmony_ci ioc->taskmgmt_quiesce_io = 1; 690062306a36Sopenharmony_ci if (ioc->alt_ioc) { 690162306a36Sopenharmony_ci ioc->alt_ioc->taskmgmt_in_progress = 1; 690262306a36Sopenharmony_ci ioc->alt_ioc->taskmgmt_quiesce_io = 1; 690362306a36Sopenharmony_ci } 690462306a36Sopenharmony_ci out: 690562306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 690662306a36Sopenharmony_ci return retval; 690762306a36Sopenharmony_ci} 690862306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag); 690962306a36Sopenharmony_ci 691062306a36Sopenharmony_ci/** 691162306a36Sopenharmony_ci * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management 691262306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 691362306a36Sopenharmony_ci * 691462306a36Sopenharmony_ci **/ 691562306a36Sopenharmony_civoid 691662306a36Sopenharmony_cimpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc) 691762306a36Sopenharmony_ci{ 691862306a36Sopenharmony_ci unsigned long flags; 691962306a36Sopenharmony_ci 692062306a36Sopenharmony_ci spin_lock_irqsave(&ioc->taskmgmt_lock, flags); 692162306a36Sopenharmony_ci ioc->taskmgmt_in_progress = 0; 692262306a36Sopenharmony_ci ioc->taskmgmt_quiesce_io = 0; 692362306a36Sopenharmony_ci if (ioc->alt_ioc) { 692462306a36Sopenharmony_ci ioc->alt_ioc->taskmgmt_in_progress = 0; 692562306a36Sopenharmony_ci ioc->alt_ioc->taskmgmt_quiesce_io = 0; 692662306a36Sopenharmony_ci } 692762306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 692862306a36Sopenharmony_ci} 692962306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag); 693062306a36Sopenharmony_ci 693162306a36Sopenharmony_ci 693262306a36Sopenharmony_ci/** 693362306a36Sopenharmony_ci * mpt_halt_firmware - Halts the firmware if it is operational and panic 693462306a36Sopenharmony_ci * the kernel 693562306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 693662306a36Sopenharmony_ci * 693762306a36Sopenharmony_ci **/ 693862306a36Sopenharmony_civoid __noreturn 693962306a36Sopenharmony_cimpt_halt_firmware(MPT_ADAPTER *ioc) 694062306a36Sopenharmony_ci{ 694162306a36Sopenharmony_ci u32 ioc_raw_state; 694262306a36Sopenharmony_ci 694362306a36Sopenharmony_ci ioc_raw_state = mpt_GetIocState(ioc, 0); 694462306a36Sopenharmony_ci 694562306a36Sopenharmony_ci if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { 694662306a36Sopenharmony_ci printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n", 694762306a36Sopenharmony_ci ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); 694862306a36Sopenharmony_ci panic("%s: IOC Fault (%04xh)!!!\n", ioc->name, 694962306a36Sopenharmony_ci ioc_raw_state & MPI_DOORBELL_DATA_MASK); 695062306a36Sopenharmony_ci } else { 695162306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00); 695262306a36Sopenharmony_ci panic("%s: Firmware is halted due to command timeout\n", 695362306a36Sopenharmony_ci ioc->name); 695462306a36Sopenharmony_ci } 695562306a36Sopenharmony_ci} 695662306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_halt_firmware); 695762306a36Sopenharmony_ci 695862306a36Sopenharmony_ci/** 695962306a36Sopenharmony_ci * mpt_SoftResetHandler - Issues a less expensive reset 696062306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 696162306a36Sopenharmony_ci * @sleepFlag: Indicates if sleep or schedule must be called. 696262306a36Sopenharmony_ci * 696362306a36Sopenharmony_ci * Returns 0 for SUCCESS or -1 if FAILED. 696462306a36Sopenharmony_ci * 696562306a36Sopenharmony_ci * Message Unit Reset - instructs the IOC to reset the Reply Post and 696662306a36Sopenharmony_ci * Free FIFO's. All the Message Frames on Reply Free FIFO are discarded. 696762306a36Sopenharmony_ci * All posted buffers are freed, and event notification is turned off. 696862306a36Sopenharmony_ci * IOC doesn't reply to any outstanding request. This will transfer IOC 696962306a36Sopenharmony_ci * to READY state. 697062306a36Sopenharmony_ci **/ 697162306a36Sopenharmony_cistatic int 697262306a36Sopenharmony_cimpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag) 697362306a36Sopenharmony_ci{ 697462306a36Sopenharmony_ci int rc; 697562306a36Sopenharmony_ci int ii; 697662306a36Sopenharmony_ci u8 cb_idx; 697762306a36Sopenharmony_ci unsigned long flags; 697862306a36Sopenharmony_ci u32 ioc_state; 697962306a36Sopenharmony_ci unsigned long time_count; 698062306a36Sopenharmony_ci 698162306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n", 698262306a36Sopenharmony_ci ioc->name)); 698362306a36Sopenharmony_ci 698462306a36Sopenharmony_ci ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK; 698562306a36Sopenharmony_ci 698662306a36Sopenharmony_ci if (mpt_fwfault_debug) 698762306a36Sopenharmony_ci mpt_halt_firmware(ioc); 698862306a36Sopenharmony_ci 698962306a36Sopenharmony_ci if (ioc_state == MPI_IOC_STATE_FAULT || 699062306a36Sopenharmony_ci ioc_state == MPI_IOC_STATE_RESET) { 699162306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 699262306a36Sopenharmony_ci "skipping, either in FAULT or RESET state!\n", ioc->name)); 699362306a36Sopenharmony_ci return -1; 699462306a36Sopenharmony_ci } 699562306a36Sopenharmony_ci 699662306a36Sopenharmony_ci if (ioc->bus_type == FC) { 699762306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 699862306a36Sopenharmony_ci "skipping, because the bus type is FC!\n", ioc->name)); 699962306a36Sopenharmony_ci return -1; 700062306a36Sopenharmony_ci } 700162306a36Sopenharmony_ci 700262306a36Sopenharmony_ci spin_lock_irqsave(&ioc->taskmgmt_lock, flags); 700362306a36Sopenharmony_ci if (ioc->ioc_reset_in_progress) { 700462306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 700562306a36Sopenharmony_ci return -1; 700662306a36Sopenharmony_ci } 700762306a36Sopenharmony_ci ioc->ioc_reset_in_progress = 1; 700862306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 700962306a36Sopenharmony_ci 701062306a36Sopenharmony_ci for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { 701162306a36Sopenharmony_ci if (MptResetHandlers[cb_idx]) 701262306a36Sopenharmony_ci mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET); 701362306a36Sopenharmony_ci } 701462306a36Sopenharmony_ci 701562306a36Sopenharmony_ci spin_lock_irqsave(&ioc->taskmgmt_lock, flags); 701662306a36Sopenharmony_ci if (ioc->taskmgmt_in_progress) { 701762306a36Sopenharmony_ci ioc->ioc_reset_in_progress = 0; 701862306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 701962306a36Sopenharmony_ci return -1; 702062306a36Sopenharmony_ci } 702162306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 702262306a36Sopenharmony_ci /* Disable reply interrupts (also blocks FreeQ) */ 702362306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); 702462306a36Sopenharmony_ci ioc->active = 0; 702562306a36Sopenharmony_ci time_count = jiffies; 702662306a36Sopenharmony_ci 702762306a36Sopenharmony_ci rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag); 702862306a36Sopenharmony_ci 702962306a36Sopenharmony_ci for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { 703062306a36Sopenharmony_ci if (MptResetHandlers[cb_idx]) 703162306a36Sopenharmony_ci mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET); 703262306a36Sopenharmony_ci } 703362306a36Sopenharmony_ci 703462306a36Sopenharmony_ci if (rc) 703562306a36Sopenharmony_ci goto out; 703662306a36Sopenharmony_ci 703762306a36Sopenharmony_ci ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK; 703862306a36Sopenharmony_ci if (ioc_state != MPI_IOC_STATE_READY) 703962306a36Sopenharmony_ci goto out; 704062306a36Sopenharmony_ci 704162306a36Sopenharmony_ci for (ii = 0; ii < 5; ii++) { 704262306a36Sopenharmony_ci /* Get IOC facts! Allow 5 retries */ 704362306a36Sopenharmony_ci rc = GetIocFacts(ioc, sleepFlag, 704462306a36Sopenharmony_ci MPT_HOSTEVENT_IOC_RECOVER); 704562306a36Sopenharmony_ci if (rc == 0) 704662306a36Sopenharmony_ci break; 704762306a36Sopenharmony_ci if (sleepFlag == CAN_SLEEP) 704862306a36Sopenharmony_ci msleep(100); 704962306a36Sopenharmony_ci else 705062306a36Sopenharmony_ci mdelay(100); 705162306a36Sopenharmony_ci } 705262306a36Sopenharmony_ci if (ii == 5) 705362306a36Sopenharmony_ci goto out; 705462306a36Sopenharmony_ci 705562306a36Sopenharmony_ci rc = PrimeIocFifos(ioc); 705662306a36Sopenharmony_ci if (rc != 0) 705762306a36Sopenharmony_ci goto out; 705862306a36Sopenharmony_ci 705962306a36Sopenharmony_ci rc = SendIocInit(ioc, sleepFlag); 706062306a36Sopenharmony_ci if (rc != 0) 706162306a36Sopenharmony_ci goto out; 706262306a36Sopenharmony_ci 706362306a36Sopenharmony_ci rc = SendEventNotification(ioc, 1, sleepFlag); 706462306a36Sopenharmony_ci if (rc != 0) 706562306a36Sopenharmony_ci goto out; 706662306a36Sopenharmony_ci 706762306a36Sopenharmony_ci if (ioc->hard_resets < -1) 706862306a36Sopenharmony_ci ioc->hard_resets++; 706962306a36Sopenharmony_ci 707062306a36Sopenharmony_ci /* 707162306a36Sopenharmony_ci * At this point, we know soft reset succeeded. 707262306a36Sopenharmony_ci */ 707362306a36Sopenharmony_ci 707462306a36Sopenharmony_ci ioc->active = 1; 707562306a36Sopenharmony_ci CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); 707662306a36Sopenharmony_ci 707762306a36Sopenharmony_ci out: 707862306a36Sopenharmony_ci spin_lock_irqsave(&ioc->taskmgmt_lock, flags); 707962306a36Sopenharmony_ci ioc->ioc_reset_in_progress = 0; 708062306a36Sopenharmony_ci ioc->taskmgmt_quiesce_io = 0; 708162306a36Sopenharmony_ci ioc->taskmgmt_in_progress = 0; 708262306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 708362306a36Sopenharmony_ci 708462306a36Sopenharmony_ci if (ioc->active) { /* otherwise, hard reset coming */ 708562306a36Sopenharmony_ci for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { 708662306a36Sopenharmony_ci if (MptResetHandlers[cb_idx]) 708762306a36Sopenharmony_ci mpt_signal_reset(cb_idx, ioc, 708862306a36Sopenharmony_ci MPT_IOC_POST_RESET); 708962306a36Sopenharmony_ci } 709062306a36Sopenharmony_ci } 709162306a36Sopenharmony_ci 709262306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT 709362306a36Sopenharmony_ci "SoftResetHandler: completed (%d seconds): %s\n", 709462306a36Sopenharmony_ci ioc->name, jiffies_to_msecs(jiffies - time_count)/1000, 709562306a36Sopenharmony_ci ((rc == 0) ? "SUCCESS" : "FAILED"))); 709662306a36Sopenharmony_ci 709762306a36Sopenharmony_ci return rc; 709862306a36Sopenharmony_ci} 709962306a36Sopenharmony_ci 710062306a36Sopenharmony_ci/** 710162306a36Sopenharmony_ci * mpt_Soft_Hard_ResetHandler - Try less expensive reset 710262306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 710362306a36Sopenharmony_ci * @sleepFlag: Indicates if sleep or schedule must be called. 710462306a36Sopenharmony_ci * 710562306a36Sopenharmony_ci * Returns 0 for SUCCESS or -1 if FAILED. 710662306a36Sopenharmony_ci * Try for softreset first, only if it fails go for expensive 710762306a36Sopenharmony_ci * HardReset. 710862306a36Sopenharmony_ci **/ 710962306a36Sopenharmony_ciint 711062306a36Sopenharmony_cimpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) { 711162306a36Sopenharmony_ci int ret = -1; 711262306a36Sopenharmony_ci 711362306a36Sopenharmony_ci ret = mpt_SoftResetHandler(ioc, sleepFlag); 711462306a36Sopenharmony_ci if (ret == 0) 711562306a36Sopenharmony_ci return ret; 711662306a36Sopenharmony_ci ret = mpt_HardResetHandler(ioc, sleepFlag); 711762306a36Sopenharmony_ci return ret; 711862306a36Sopenharmony_ci} 711962306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler); 712062306a36Sopenharmony_ci 712162306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 712262306a36Sopenharmony_ci/* 712362306a36Sopenharmony_ci * Reset Handling 712462306a36Sopenharmony_ci */ 712562306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 712662306a36Sopenharmony_ci/** 712762306a36Sopenharmony_ci * mpt_HardResetHandler - Generic reset handler 712862306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 712962306a36Sopenharmony_ci * @sleepFlag: Indicates if sleep or schedule must be called. 713062306a36Sopenharmony_ci * 713162306a36Sopenharmony_ci * Issues SCSI Task Management call based on input arg values. 713262306a36Sopenharmony_ci * If TaskMgmt fails, returns associated SCSI request. 713362306a36Sopenharmony_ci * 713462306a36Sopenharmony_ci * Remark: _HardResetHandler can be invoked from an interrupt thread (timer) 713562306a36Sopenharmony_ci * or a non-interrupt thread. In the former, must not call schedule(). 713662306a36Sopenharmony_ci * 713762306a36Sopenharmony_ci * Note: A return of -1 is a FATAL error case, as it means a 713862306a36Sopenharmony_ci * FW reload/initialization failed. 713962306a36Sopenharmony_ci * 714062306a36Sopenharmony_ci * Returns 0 for SUCCESS or -1 if FAILED. 714162306a36Sopenharmony_ci */ 714262306a36Sopenharmony_ciint 714362306a36Sopenharmony_cimpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) 714462306a36Sopenharmony_ci{ 714562306a36Sopenharmony_ci int rc; 714662306a36Sopenharmony_ci u8 cb_idx; 714762306a36Sopenharmony_ci unsigned long flags; 714862306a36Sopenharmony_ci unsigned long time_count; 714962306a36Sopenharmony_ci 715062306a36Sopenharmony_ci dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name)); 715162306a36Sopenharmony_ci#ifdef MFCNT 715262306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name); 715362306a36Sopenharmony_ci printk("MF count 0x%x !\n", ioc->mfcnt); 715462306a36Sopenharmony_ci#endif 715562306a36Sopenharmony_ci if (mpt_fwfault_debug) 715662306a36Sopenharmony_ci mpt_halt_firmware(ioc); 715762306a36Sopenharmony_ci 715862306a36Sopenharmony_ci /* Reset the adapter. Prevent more than 1 call to 715962306a36Sopenharmony_ci * mpt_do_ioc_recovery at any instant in time. 716062306a36Sopenharmony_ci */ 716162306a36Sopenharmony_ci spin_lock_irqsave(&ioc->taskmgmt_lock, flags); 716262306a36Sopenharmony_ci if (ioc->ioc_reset_in_progress) { 716362306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 716462306a36Sopenharmony_ci ioc->wait_on_reset_completion = 1; 716562306a36Sopenharmony_ci do { 716662306a36Sopenharmony_ci ssleep(1); 716762306a36Sopenharmony_ci } while (ioc->ioc_reset_in_progress == 1); 716862306a36Sopenharmony_ci ioc->wait_on_reset_completion = 0; 716962306a36Sopenharmony_ci return ioc->reset_status; 717062306a36Sopenharmony_ci } 717162306a36Sopenharmony_ci if (ioc->wait_on_reset_completion) { 717262306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 717362306a36Sopenharmony_ci rc = 0; 717462306a36Sopenharmony_ci time_count = jiffies; 717562306a36Sopenharmony_ci goto exit; 717662306a36Sopenharmony_ci } 717762306a36Sopenharmony_ci ioc->ioc_reset_in_progress = 1; 717862306a36Sopenharmony_ci if (ioc->alt_ioc) 717962306a36Sopenharmony_ci ioc->alt_ioc->ioc_reset_in_progress = 1; 718062306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 718162306a36Sopenharmony_ci 718262306a36Sopenharmony_ci 718362306a36Sopenharmony_ci /* The SCSI driver needs to adjust timeouts on all current 718462306a36Sopenharmony_ci * commands prior to the diagnostic reset being issued. 718562306a36Sopenharmony_ci * Prevents timeouts occurring during a diagnostic reset...very bad. 718662306a36Sopenharmony_ci * For all other protocol drivers, this is a no-op. 718762306a36Sopenharmony_ci */ 718862306a36Sopenharmony_ci for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { 718962306a36Sopenharmony_ci if (MptResetHandlers[cb_idx]) { 719062306a36Sopenharmony_ci mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET); 719162306a36Sopenharmony_ci if (ioc->alt_ioc) 719262306a36Sopenharmony_ci mpt_signal_reset(cb_idx, ioc->alt_ioc, 719362306a36Sopenharmony_ci MPT_IOC_SETUP_RESET); 719462306a36Sopenharmony_ci } 719562306a36Sopenharmony_ci } 719662306a36Sopenharmony_ci 719762306a36Sopenharmony_ci time_count = jiffies; 719862306a36Sopenharmony_ci rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag); 719962306a36Sopenharmony_ci if (rc != 0) { 720062306a36Sopenharmony_ci printk(KERN_WARNING MYNAM 720162306a36Sopenharmony_ci ": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n", 720262306a36Sopenharmony_ci rc, ioc->name, mpt_GetIocState(ioc, 0)); 720362306a36Sopenharmony_ci } else { 720462306a36Sopenharmony_ci if (ioc->hard_resets < -1) 720562306a36Sopenharmony_ci ioc->hard_resets++; 720662306a36Sopenharmony_ci } 720762306a36Sopenharmony_ci 720862306a36Sopenharmony_ci spin_lock_irqsave(&ioc->taskmgmt_lock, flags); 720962306a36Sopenharmony_ci ioc->ioc_reset_in_progress = 0; 721062306a36Sopenharmony_ci ioc->taskmgmt_quiesce_io = 0; 721162306a36Sopenharmony_ci ioc->taskmgmt_in_progress = 0; 721262306a36Sopenharmony_ci ioc->reset_status = rc; 721362306a36Sopenharmony_ci if (ioc->alt_ioc) { 721462306a36Sopenharmony_ci ioc->alt_ioc->ioc_reset_in_progress = 0; 721562306a36Sopenharmony_ci ioc->alt_ioc->taskmgmt_quiesce_io = 0; 721662306a36Sopenharmony_ci ioc->alt_ioc->taskmgmt_in_progress = 0; 721762306a36Sopenharmony_ci } 721862306a36Sopenharmony_ci spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); 721962306a36Sopenharmony_ci 722062306a36Sopenharmony_ci for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { 722162306a36Sopenharmony_ci if (MptResetHandlers[cb_idx]) { 722262306a36Sopenharmony_ci mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET); 722362306a36Sopenharmony_ci if (ioc->alt_ioc) 722462306a36Sopenharmony_ci mpt_signal_reset(cb_idx, 722562306a36Sopenharmony_ci ioc->alt_ioc, MPT_IOC_POST_RESET); 722662306a36Sopenharmony_ci } 722762306a36Sopenharmony_ci } 722862306a36Sopenharmony_ciexit: 722962306a36Sopenharmony_ci dtmprintk(ioc, 723062306a36Sopenharmony_ci printk(MYIOC_s_DEBUG_FMT 723162306a36Sopenharmony_ci "HardResetHandler: completed (%d seconds): %s\n", ioc->name, 723262306a36Sopenharmony_ci jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ? 723362306a36Sopenharmony_ci "SUCCESS" : "FAILED"))); 723462306a36Sopenharmony_ci 723562306a36Sopenharmony_ci return rc; 723662306a36Sopenharmony_ci} 723762306a36Sopenharmony_ci 723862306a36Sopenharmony_ci#ifdef CONFIG_FUSION_LOGGING 723962306a36Sopenharmony_cistatic void 724062306a36Sopenharmony_cimpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply) 724162306a36Sopenharmony_ci{ 724262306a36Sopenharmony_ci char *ds = NULL; 724362306a36Sopenharmony_ci u32 evData0; 724462306a36Sopenharmony_ci int ii; 724562306a36Sopenharmony_ci u8 event; 724662306a36Sopenharmony_ci char *evStr = ioc->evStr; 724762306a36Sopenharmony_ci 724862306a36Sopenharmony_ci event = le32_to_cpu(pEventReply->Event) & 0xFF; 724962306a36Sopenharmony_ci evData0 = le32_to_cpu(pEventReply->Data[0]); 725062306a36Sopenharmony_ci 725162306a36Sopenharmony_ci switch(event) { 725262306a36Sopenharmony_ci case MPI_EVENT_NONE: 725362306a36Sopenharmony_ci ds = "None"; 725462306a36Sopenharmony_ci break; 725562306a36Sopenharmony_ci case MPI_EVENT_LOG_DATA: 725662306a36Sopenharmony_ci ds = "Log Data"; 725762306a36Sopenharmony_ci break; 725862306a36Sopenharmony_ci case MPI_EVENT_STATE_CHANGE: 725962306a36Sopenharmony_ci ds = "State Change"; 726062306a36Sopenharmony_ci break; 726162306a36Sopenharmony_ci case MPI_EVENT_UNIT_ATTENTION: 726262306a36Sopenharmony_ci ds = "Unit Attention"; 726362306a36Sopenharmony_ci break; 726462306a36Sopenharmony_ci case MPI_EVENT_IOC_BUS_RESET: 726562306a36Sopenharmony_ci ds = "IOC Bus Reset"; 726662306a36Sopenharmony_ci break; 726762306a36Sopenharmony_ci case MPI_EVENT_EXT_BUS_RESET: 726862306a36Sopenharmony_ci ds = "External Bus Reset"; 726962306a36Sopenharmony_ci break; 727062306a36Sopenharmony_ci case MPI_EVENT_RESCAN: 727162306a36Sopenharmony_ci ds = "Bus Rescan Event"; 727262306a36Sopenharmony_ci break; 727362306a36Sopenharmony_ci case MPI_EVENT_LINK_STATUS_CHANGE: 727462306a36Sopenharmony_ci if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE) 727562306a36Sopenharmony_ci ds = "Link Status(FAILURE) Change"; 727662306a36Sopenharmony_ci else 727762306a36Sopenharmony_ci ds = "Link Status(ACTIVE) Change"; 727862306a36Sopenharmony_ci break; 727962306a36Sopenharmony_ci case MPI_EVENT_LOOP_STATE_CHANGE: 728062306a36Sopenharmony_ci if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP) 728162306a36Sopenharmony_ci ds = "Loop State(LIP) Change"; 728262306a36Sopenharmony_ci else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE) 728362306a36Sopenharmony_ci ds = "Loop State(LPE) Change"; 728462306a36Sopenharmony_ci else 728562306a36Sopenharmony_ci ds = "Loop State(LPB) Change"; 728662306a36Sopenharmony_ci break; 728762306a36Sopenharmony_ci case MPI_EVENT_LOGOUT: 728862306a36Sopenharmony_ci ds = "Logout"; 728962306a36Sopenharmony_ci break; 729062306a36Sopenharmony_ci case MPI_EVENT_EVENT_CHANGE: 729162306a36Sopenharmony_ci if (evData0) 729262306a36Sopenharmony_ci ds = "Events ON"; 729362306a36Sopenharmony_ci else 729462306a36Sopenharmony_ci ds = "Events OFF"; 729562306a36Sopenharmony_ci break; 729662306a36Sopenharmony_ci case MPI_EVENT_INTEGRATED_RAID: 729762306a36Sopenharmony_ci { 729862306a36Sopenharmony_ci u8 ReasonCode = (u8)(evData0 >> 16); 729962306a36Sopenharmony_ci switch (ReasonCode) { 730062306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_VOLUME_CREATED : 730162306a36Sopenharmony_ci ds = "Integrated Raid: Volume Created"; 730262306a36Sopenharmony_ci break; 730362306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_VOLUME_DELETED : 730462306a36Sopenharmony_ci ds = "Integrated Raid: Volume Deleted"; 730562306a36Sopenharmony_ci break; 730662306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED : 730762306a36Sopenharmony_ci ds = "Integrated Raid: Volume Settings Changed"; 730862306a36Sopenharmony_ci break; 730962306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED : 731062306a36Sopenharmony_ci ds = "Integrated Raid: Volume Status Changed"; 731162306a36Sopenharmony_ci break; 731262306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED : 731362306a36Sopenharmony_ci ds = "Integrated Raid: Volume Physdisk Changed"; 731462306a36Sopenharmony_ci break; 731562306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_PHYSDISK_CREATED : 731662306a36Sopenharmony_ci ds = "Integrated Raid: Physdisk Created"; 731762306a36Sopenharmony_ci break; 731862306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_PHYSDISK_DELETED : 731962306a36Sopenharmony_ci ds = "Integrated Raid: Physdisk Deleted"; 732062306a36Sopenharmony_ci break; 732162306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED : 732262306a36Sopenharmony_ci ds = "Integrated Raid: Physdisk Settings Changed"; 732362306a36Sopenharmony_ci break; 732462306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED : 732562306a36Sopenharmony_ci ds = "Integrated Raid: Physdisk Status Changed"; 732662306a36Sopenharmony_ci break; 732762306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED : 732862306a36Sopenharmony_ci ds = "Integrated Raid: Domain Validation Needed"; 732962306a36Sopenharmony_ci break; 733062306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_SMART_DATA : 733162306a36Sopenharmony_ci ds = "Integrated Raid; Smart Data"; 733262306a36Sopenharmony_ci break; 733362306a36Sopenharmony_ci case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED : 733462306a36Sopenharmony_ci ds = "Integrated Raid: Replace Action Started"; 733562306a36Sopenharmony_ci break; 733662306a36Sopenharmony_ci default: 733762306a36Sopenharmony_ci ds = "Integrated Raid"; 733862306a36Sopenharmony_ci break; 733962306a36Sopenharmony_ci } 734062306a36Sopenharmony_ci break; 734162306a36Sopenharmony_ci } 734262306a36Sopenharmony_ci case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE: 734362306a36Sopenharmony_ci ds = "SCSI Device Status Change"; 734462306a36Sopenharmony_ci break; 734562306a36Sopenharmony_ci case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: 734662306a36Sopenharmony_ci { 734762306a36Sopenharmony_ci u8 id = (u8)(evData0); 734862306a36Sopenharmony_ci u8 channel = (u8)(evData0 >> 8); 734962306a36Sopenharmony_ci u8 ReasonCode = (u8)(evData0 >> 16); 735062306a36Sopenharmony_ci switch (ReasonCode) { 735162306a36Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: 735262306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 735362306a36Sopenharmony_ci "SAS Device Status Change: Added: " 735462306a36Sopenharmony_ci "id=%d channel=%d", id, channel); 735562306a36Sopenharmony_ci break; 735662306a36Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: 735762306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 735862306a36Sopenharmony_ci "SAS Device Status Change: Deleted: " 735962306a36Sopenharmony_ci "id=%d channel=%d", id, channel); 736062306a36Sopenharmony_ci break; 736162306a36Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: 736262306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 736362306a36Sopenharmony_ci "SAS Device Status Change: SMART Data: " 736462306a36Sopenharmony_ci "id=%d channel=%d", id, channel); 736562306a36Sopenharmony_ci break; 736662306a36Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: 736762306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 736862306a36Sopenharmony_ci "SAS Device Status Change: No Persistency: " 736962306a36Sopenharmony_ci "id=%d channel=%d", id, channel); 737062306a36Sopenharmony_ci break; 737162306a36Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: 737262306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 737362306a36Sopenharmony_ci "SAS Device Status Change: Unsupported Device " 737462306a36Sopenharmony_ci "Discovered : id=%d channel=%d", id, channel); 737562306a36Sopenharmony_ci break; 737662306a36Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: 737762306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 737862306a36Sopenharmony_ci "SAS Device Status Change: Internal Device " 737962306a36Sopenharmony_ci "Reset : id=%d channel=%d", id, channel); 738062306a36Sopenharmony_ci break; 738162306a36Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: 738262306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 738362306a36Sopenharmony_ci "SAS Device Status Change: Internal Task " 738462306a36Sopenharmony_ci "Abort : id=%d channel=%d", id, channel); 738562306a36Sopenharmony_ci break; 738662306a36Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL: 738762306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 738862306a36Sopenharmony_ci "SAS Device Status Change: Internal Abort " 738962306a36Sopenharmony_ci "Task Set : id=%d channel=%d", id, channel); 739062306a36Sopenharmony_ci break; 739162306a36Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: 739262306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 739362306a36Sopenharmony_ci "SAS Device Status Change: Internal Clear " 739462306a36Sopenharmony_ci "Task Set : id=%d channel=%d", id, channel); 739562306a36Sopenharmony_ci break; 739662306a36Sopenharmony_ci case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL: 739762306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 739862306a36Sopenharmony_ci "SAS Device Status Change: Internal Query " 739962306a36Sopenharmony_ci "Task : id=%d channel=%d", id, channel); 740062306a36Sopenharmony_ci break; 740162306a36Sopenharmony_ci default: 740262306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 740362306a36Sopenharmony_ci "SAS Device Status Change: Unknown: " 740462306a36Sopenharmony_ci "id=%d channel=%d", id, channel); 740562306a36Sopenharmony_ci break; 740662306a36Sopenharmony_ci } 740762306a36Sopenharmony_ci break; 740862306a36Sopenharmony_ci } 740962306a36Sopenharmony_ci case MPI_EVENT_ON_BUS_TIMER_EXPIRED: 741062306a36Sopenharmony_ci ds = "Bus Timer Expired"; 741162306a36Sopenharmony_ci break; 741262306a36Sopenharmony_ci case MPI_EVENT_QUEUE_FULL: 741362306a36Sopenharmony_ci { 741462306a36Sopenharmony_ci u16 curr_depth = (u16)(evData0 >> 16); 741562306a36Sopenharmony_ci u8 channel = (u8)(evData0 >> 8); 741662306a36Sopenharmony_ci u8 id = (u8)(evData0); 741762306a36Sopenharmony_ci 741862306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 741962306a36Sopenharmony_ci "Queue Full: channel=%d id=%d depth=%d", 742062306a36Sopenharmony_ci channel, id, curr_depth); 742162306a36Sopenharmony_ci break; 742262306a36Sopenharmony_ci } 742362306a36Sopenharmony_ci case MPI_EVENT_SAS_SES: 742462306a36Sopenharmony_ci ds = "SAS SES Event"; 742562306a36Sopenharmony_ci break; 742662306a36Sopenharmony_ci case MPI_EVENT_PERSISTENT_TABLE_FULL: 742762306a36Sopenharmony_ci ds = "Persistent Table Full"; 742862306a36Sopenharmony_ci break; 742962306a36Sopenharmony_ci case MPI_EVENT_SAS_PHY_LINK_STATUS: 743062306a36Sopenharmony_ci { 743162306a36Sopenharmony_ci u8 LinkRates = (u8)(evData0 >> 8); 743262306a36Sopenharmony_ci u8 PhyNumber = (u8)(evData0); 743362306a36Sopenharmony_ci LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >> 743462306a36Sopenharmony_ci MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT; 743562306a36Sopenharmony_ci switch (LinkRates) { 743662306a36Sopenharmony_ci case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN: 743762306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 743862306a36Sopenharmony_ci "SAS PHY Link Status: Phy=%d:" 743962306a36Sopenharmony_ci " Rate Unknown",PhyNumber); 744062306a36Sopenharmony_ci break; 744162306a36Sopenharmony_ci case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED: 744262306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 744362306a36Sopenharmony_ci "SAS PHY Link Status: Phy=%d:" 744462306a36Sopenharmony_ci " Phy Disabled",PhyNumber); 744562306a36Sopenharmony_ci break; 744662306a36Sopenharmony_ci case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION: 744762306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 744862306a36Sopenharmony_ci "SAS PHY Link Status: Phy=%d:" 744962306a36Sopenharmony_ci " Failed Speed Nego",PhyNumber); 745062306a36Sopenharmony_ci break; 745162306a36Sopenharmony_ci case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE: 745262306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 745362306a36Sopenharmony_ci "SAS PHY Link Status: Phy=%d:" 745462306a36Sopenharmony_ci " Sata OOB Completed",PhyNumber); 745562306a36Sopenharmony_ci break; 745662306a36Sopenharmony_ci case MPI_EVENT_SAS_PLS_LR_RATE_1_5: 745762306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 745862306a36Sopenharmony_ci "SAS PHY Link Status: Phy=%d:" 745962306a36Sopenharmony_ci " Rate 1.5 Gbps",PhyNumber); 746062306a36Sopenharmony_ci break; 746162306a36Sopenharmony_ci case MPI_EVENT_SAS_PLS_LR_RATE_3_0: 746262306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 746362306a36Sopenharmony_ci "SAS PHY Link Status: Phy=%d:" 746462306a36Sopenharmony_ci " Rate 3.0 Gbps", PhyNumber); 746562306a36Sopenharmony_ci break; 746662306a36Sopenharmony_ci case MPI_EVENT_SAS_PLS_LR_RATE_6_0: 746762306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 746862306a36Sopenharmony_ci "SAS PHY Link Status: Phy=%d:" 746962306a36Sopenharmony_ci " Rate 6.0 Gbps", PhyNumber); 747062306a36Sopenharmony_ci break; 747162306a36Sopenharmony_ci default: 747262306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 747362306a36Sopenharmony_ci "SAS PHY Link Status: Phy=%d", PhyNumber); 747462306a36Sopenharmony_ci break; 747562306a36Sopenharmony_ci } 747662306a36Sopenharmony_ci break; 747762306a36Sopenharmony_ci } 747862306a36Sopenharmony_ci case MPI_EVENT_SAS_DISCOVERY_ERROR: 747962306a36Sopenharmony_ci ds = "SAS Discovery Error"; 748062306a36Sopenharmony_ci break; 748162306a36Sopenharmony_ci case MPI_EVENT_IR_RESYNC_UPDATE: 748262306a36Sopenharmony_ci { 748362306a36Sopenharmony_ci u8 resync_complete = (u8)(evData0 >> 16); 748462306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 748562306a36Sopenharmony_ci "IR Resync Update: Complete = %d:",resync_complete); 748662306a36Sopenharmony_ci break; 748762306a36Sopenharmony_ci } 748862306a36Sopenharmony_ci case MPI_EVENT_IR2: 748962306a36Sopenharmony_ci { 749062306a36Sopenharmony_ci u8 id = (u8)(evData0); 749162306a36Sopenharmony_ci u8 channel = (u8)(evData0 >> 8); 749262306a36Sopenharmony_ci u8 phys_num = (u8)(evData0 >> 24); 749362306a36Sopenharmony_ci u8 ReasonCode = (u8)(evData0 >> 16); 749462306a36Sopenharmony_ci 749562306a36Sopenharmony_ci switch (ReasonCode) { 749662306a36Sopenharmony_ci case MPI_EVENT_IR2_RC_LD_STATE_CHANGED: 749762306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 749862306a36Sopenharmony_ci "IR2: LD State Changed: " 749962306a36Sopenharmony_ci "id=%d channel=%d phys_num=%d", 750062306a36Sopenharmony_ci id, channel, phys_num); 750162306a36Sopenharmony_ci break; 750262306a36Sopenharmony_ci case MPI_EVENT_IR2_RC_PD_STATE_CHANGED: 750362306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 750462306a36Sopenharmony_ci "IR2: PD State Changed " 750562306a36Sopenharmony_ci "id=%d channel=%d phys_num=%d", 750662306a36Sopenharmony_ci id, channel, phys_num); 750762306a36Sopenharmony_ci break; 750862306a36Sopenharmony_ci case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL: 750962306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 751062306a36Sopenharmony_ci "IR2: Bad Block Table Full: " 751162306a36Sopenharmony_ci "id=%d channel=%d phys_num=%d", 751262306a36Sopenharmony_ci id, channel, phys_num); 751362306a36Sopenharmony_ci break; 751462306a36Sopenharmony_ci case MPI_EVENT_IR2_RC_PD_INSERTED: 751562306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 751662306a36Sopenharmony_ci "IR2: PD Inserted: " 751762306a36Sopenharmony_ci "id=%d channel=%d phys_num=%d", 751862306a36Sopenharmony_ci id, channel, phys_num); 751962306a36Sopenharmony_ci break; 752062306a36Sopenharmony_ci case MPI_EVENT_IR2_RC_PD_REMOVED: 752162306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 752262306a36Sopenharmony_ci "IR2: PD Removed: " 752362306a36Sopenharmony_ci "id=%d channel=%d phys_num=%d", 752462306a36Sopenharmony_ci id, channel, phys_num); 752562306a36Sopenharmony_ci break; 752662306a36Sopenharmony_ci case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: 752762306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 752862306a36Sopenharmony_ci "IR2: Foreign CFG Detected: " 752962306a36Sopenharmony_ci "id=%d channel=%d phys_num=%d", 753062306a36Sopenharmony_ci id, channel, phys_num); 753162306a36Sopenharmony_ci break; 753262306a36Sopenharmony_ci case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR: 753362306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 753462306a36Sopenharmony_ci "IR2: Rebuild Medium Error: " 753562306a36Sopenharmony_ci "id=%d channel=%d phys_num=%d", 753662306a36Sopenharmony_ci id, channel, phys_num); 753762306a36Sopenharmony_ci break; 753862306a36Sopenharmony_ci case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED: 753962306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 754062306a36Sopenharmony_ci "IR2: Dual Port Added: " 754162306a36Sopenharmony_ci "id=%d channel=%d phys_num=%d", 754262306a36Sopenharmony_ci id, channel, phys_num); 754362306a36Sopenharmony_ci break; 754462306a36Sopenharmony_ci case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED: 754562306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 754662306a36Sopenharmony_ci "IR2: Dual Port Removed: " 754762306a36Sopenharmony_ci "id=%d channel=%d phys_num=%d", 754862306a36Sopenharmony_ci id, channel, phys_num); 754962306a36Sopenharmony_ci break; 755062306a36Sopenharmony_ci default: 755162306a36Sopenharmony_ci ds = "IR2"; 755262306a36Sopenharmony_ci break; 755362306a36Sopenharmony_ci } 755462306a36Sopenharmony_ci break; 755562306a36Sopenharmony_ci } 755662306a36Sopenharmony_ci case MPI_EVENT_SAS_DISCOVERY: 755762306a36Sopenharmony_ci { 755862306a36Sopenharmony_ci if (evData0) 755962306a36Sopenharmony_ci ds = "SAS Discovery: Start"; 756062306a36Sopenharmony_ci else 756162306a36Sopenharmony_ci ds = "SAS Discovery: Stop"; 756262306a36Sopenharmony_ci break; 756362306a36Sopenharmony_ci } 756462306a36Sopenharmony_ci case MPI_EVENT_LOG_ENTRY_ADDED: 756562306a36Sopenharmony_ci ds = "SAS Log Entry Added"; 756662306a36Sopenharmony_ci break; 756762306a36Sopenharmony_ci 756862306a36Sopenharmony_ci case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: 756962306a36Sopenharmony_ci { 757062306a36Sopenharmony_ci u8 phy_num = (u8)(evData0); 757162306a36Sopenharmony_ci u8 port_num = (u8)(evData0 >> 8); 757262306a36Sopenharmony_ci u8 port_width = (u8)(evData0 >> 16); 757362306a36Sopenharmony_ci u8 primitive = (u8)(evData0 >> 24); 757462306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 757562306a36Sopenharmony_ci "SAS Broadcast Primitive: phy=%d port=%d " 757662306a36Sopenharmony_ci "width=%d primitive=0x%02x", 757762306a36Sopenharmony_ci phy_num, port_num, port_width, primitive); 757862306a36Sopenharmony_ci break; 757962306a36Sopenharmony_ci } 758062306a36Sopenharmony_ci 758162306a36Sopenharmony_ci case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: 758262306a36Sopenharmony_ci { 758362306a36Sopenharmony_ci u8 reason = (u8)(evData0); 758462306a36Sopenharmony_ci 758562306a36Sopenharmony_ci switch (reason) { 758662306a36Sopenharmony_ci case MPI_EVENT_SAS_INIT_RC_ADDED: 758762306a36Sopenharmony_ci ds = "SAS Initiator Status Change: Added"; 758862306a36Sopenharmony_ci break; 758962306a36Sopenharmony_ci case MPI_EVENT_SAS_INIT_RC_REMOVED: 759062306a36Sopenharmony_ci ds = "SAS Initiator Status Change: Deleted"; 759162306a36Sopenharmony_ci break; 759262306a36Sopenharmony_ci default: 759362306a36Sopenharmony_ci ds = "SAS Initiator Status Change"; 759462306a36Sopenharmony_ci break; 759562306a36Sopenharmony_ci } 759662306a36Sopenharmony_ci break; 759762306a36Sopenharmony_ci } 759862306a36Sopenharmony_ci 759962306a36Sopenharmony_ci case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW: 760062306a36Sopenharmony_ci { 760162306a36Sopenharmony_ci u8 max_init = (u8)(evData0); 760262306a36Sopenharmony_ci u8 current_init = (u8)(evData0 >> 8); 760362306a36Sopenharmony_ci 760462306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 760562306a36Sopenharmony_ci "SAS Initiator Device Table Overflow: max initiators=%02d " 760662306a36Sopenharmony_ci "current initiators=%02d", 760762306a36Sopenharmony_ci max_init, current_init); 760862306a36Sopenharmony_ci break; 760962306a36Sopenharmony_ci } 761062306a36Sopenharmony_ci case MPI_EVENT_SAS_SMP_ERROR: 761162306a36Sopenharmony_ci { 761262306a36Sopenharmony_ci u8 status = (u8)(evData0); 761362306a36Sopenharmony_ci u8 port_num = (u8)(evData0 >> 8); 761462306a36Sopenharmony_ci u8 result = (u8)(evData0 >> 16); 761562306a36Sopenharmony_ci 761662306a36Sopenharmony_ci if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID) 761762306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 761862306a36Sopenharmony_ci "SAS SMP Error: port=%d result=0x%02x", 761962306a36Sopenharmony_ci port_num, result); 762062306a36Sopenharmony_ci else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR) 762162306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 762262306a36Sopenharmony_ci "SAS SMP Error: port=%d : CRC Error", 762362306a36Sopenharmony_ci port_num); 762462306a36Sopenharmony_ci else if (status == MPI_EVENT_SAS_SMP_TIMEOUT) 762562306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 762662306a36Sopenharmony_ci "SAS SMP Error: port=%d : Timeout", 762762306a36Sopenharmony_ci port_num); 762862306a36Sopenharmony_ci else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION) 762962306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 763062306a36Sopenharmony_ci "SAS SMP Error: port=%d : No Destination", 763162306a36Sopenharmony_ci port_num); 763262306a36Sopenharmony_ci else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION) 763362306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 763462306a36Sopenharmony_ci "SAS SMP Error: port=%d : Bad Destination", 763562306a36Sopenharmony_ci port_num); 763662306a36Sopenharmony_ci else 763762306a36Sopenharmony_ci snprintf(evStr, EVENT_DESCR_STR_SZ, 763862306a36Sopenharmony_ci "SAS SMP Error: port=%d : status=0x%02x", 763962306a36Sopenharmony_ci port_num, status); 764062306a36Sopenharmony_ci break; 764162306a36Sopenharmony_ci } 764262306a36Sopenharmony_ci 764362306a36Sopenharmony_ci case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: 764462306a36Sopenharmony_ci { 764562306a36Sopenharmony_ci u8 reason = (u8)(evData0); 764662306a36Sopenharmony_ci 764762306a36Sopenharmony_ci switch (reason) { 764862306a36Sopenharmony_ci case MPI_EVENT_SAS_EXP_RC_ADDED: 764962306a36Sopenharmony_ci ds = "Expander Status Change: Added"; 765062306a36Sopenharmony_ci break; 765162306a36Sopenharmony_ci case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING: 765262306a36Sopenharmony_ci ds = "Expander Status Change: Deleted"; 765362306a36Sopenharmony_ci break; 765462306a36Sopenharmony_ci default: 765562306a36Sopenharmony_ci ds = "Expander Status Change"; 765662306a36Sopenharmony_ci break; 765762306a36Sopenharmony_ci } 765862306a36Sopenharmony_ci break; 765962306a36Sopenharmony_ci } 766062306a36Sopenharmony_ci 766162306a36Sopenharmony_ci /* 766262306a36Sopenharmony_ci * MPT base "custom" events may be added here... 766362306a36Sopenharmony_ci */ 766462306a36Sopenharmony_ci default: 766562306a36Sopenharmony_ci ds = "Unknown"; 766662306a36Sopenharmony_ci break; 766762306a36Sopenharmony_ci } 766862306a36Sopenharmony_ci if (ds) 766962306a36Sopenharmony_ci strscpy(evStr, ds, EVENT_DESCR_STR_SZ); 767062306a36Sopenharmony_ci 767162306a36Sopenharmony_ci 767262306a36Sopenharmony_ci devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT 767362306a36Sopenharmony_ci "MPT event:(%02Xh) : %s\n", 767462306a36Sopenharmony_ci ioc->name, event, evStr)); 767562306a36Sopenharmony_ci 767662306a36Sopenharmony_ci devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM 767762306a36Sopenharmony_ci ": Event data:\n")); 767862306a36Sopenharmony_ci for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++) 767962306a36Sopenharmony_ci devtverboseprintk(ioc, printk(" %08x", 768062306a36Sopenharmony_ci le32_to_cpu(pEventReply->Data[ii]))); 768162306a36Sopenharmony_ci devtverboseprintk(ioc, printk(KERN_DEBUG "\n")); 768262306a36Sopenharmony_ci} 768362306a36Sopenharmony_ci#endif 768462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 768562306a36Sopenharmony_ci/** 768662306a36Sopenharmony_ci * ProcessEventNotification - Route EventNotificationReply to all event handlers 768762306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 768862306a36Sopenharmony_ci * @pEventReply: Pointer to EventNotification reply frame 768962306a36Sopenharmony_ci * @evHandlers: Pointer to integer, number of event handlers 769062306a36Sopenharmony_ci * 769162306a36Sopenharmony_ci * Routes a received EventNotificationReply to all currently registered 769262306a36Sopenharmony_ci * event handlers. 769362306a36Sopenharmony_ci * Returns sum of event handlers return values. 769462306a36Sopenharmony_ci */ 769562306a36Sopenharmony_cistatic int 769662306a36Sopenharmony_ciProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers) 769762306a36Sopenharmony_ci{ 769862306a36Sopenharmony_ci u16 evDataLen; 769962306a36Sopenharmony_ci u32 evData0 = 0; 770062306a36Sopenharmony_ci int ii; 770162306a36Sopenharmony_ci u8 cb_idx; 770262306a36Sopenharmony_ci int r = 0; 770362306a36Sopenharmony_ci int handlers = 0; 770462306a36Sopenharmony_ci u8 event; 770562306a36Sopenharmony_ci 770662306a36Sopenharmony_ci /* 770762306a36Sopenharmony_ci * Do platform normalization of values 770862306a36Sopenharmony_ci */ 770962306a36Sopenharmony_ci event = le32_to_cpu(pEventReply->Event) & 0xFF; 771062306a36Sopenharmony_ci evDataLen = le16_to_cpu(pEventReply->EventDataLength); 771162306a36Sopenharmony_ci if (evDataLen) { 771262306a36Sopenharmony_ci evData0 = le32_to_cpu(pEventReply->Data[0]); 771362306a36Sopenharmony_ci } 771462306a36Sopenharmony_ci 771562306a36Sopenharmony_ci#ifdef CONFIG_FUSION_LOGGING 771662306a36Sopenharmony_ci if (evDataLen) 771762306a36Sopenharmony_ci mpt_display_event_info(ioc, pEventReply); 771862306a36Sopenharmony_ci#endif 771962306a36Sopenharmony_ci 772062306a36Sopenharmony_ci /* 772162306a36Sopenharmony_ci * Do general / base driver event processing 772262306a36Sopenharmony_ci */ 772362306a36Sopenharmony_ci switch(event) { 772462306a36Sopenharmony_ci case MPI_EVENT_EVENT_CHANGE: /* 0A */ 772562306a36Sopenharmony_ci if (evDataLen) { 772662306a36Sopenharmony_ci u8 evState = evData0 & 0xFF; 772762306a36Sopenharmony_ci 772862306a36Sopenharmony_ci /* CHECKME! What if evState unexpectedly says OFF (0)? */ 772962306a36Sopenharmony_ci 773062306a36Sopenharmony_ci /* Update EventState field in cached IocFacts */ 773162306a36Sopenharmony_ci if (ioc->facts.Function) { 773262306a36Sopenharmony_ci ioc->facts.EventState = evState; 773362306a36Sopenharmony_ci } 773462306a36Sopenharmony_ci } 773562306a36Sopenharmony_ci break; 773662306a36Sopenharmony_ci case MPI_EVENT_INTEGRATED_RAID: 773762306a36Sopenharmony_ci mptbase_raid_process_event_data(ioc, 773862306a36Sopenharmony_ci (MpiEventDataRaid_t *)pEventReply->Data); 773962306a36Sopenharmony_ci break; 774062306a36Sopenharmony_ci default: 774162306a36Sopenharmony_ci break; 774262306a36Sopenharmony_ci } 774362306a36Sopenharmony_ci 774462306a36Sopenharmony_ci /* 774562306a36Sopenharmony_ci * Should this event be logged? Events are written sequentially. 774662306a36Sopenharmony_ci * When buffer is full, start again at the top. 774762306a36Sopenharmony_ci */ 774862306a36Sopenharmony_ci if (ioc->events && (ioc->eventTypes & ( 1 << event))) { 774962306a36Sopenharmony_ci int idx; 775062306a36Sopenharmony_ci 775162306a36Sopenharmony_ci idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE; 775262306a36Sopenharmony_ci 775362306a36Sopenharmony_ci ioc->events[idx].event = event; 775462306a36Sopenharmony_ci ioc->events[idx].eventContext = ioc->eventContext; 775562306a36Sopenharmony_ci 775662306a36Sopenharmony_ci for (ii = 0; ii < 2; ii++) { 775762306a36Sopenharmony_ci if (ii < evDataLen) 775862306a36Sopenharmony_ci ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]); 775962306a36Sopenharmony_ci else 776062306a36Sopenharmony_ci ioc->events[idx].data[ii] = 0; 776162306a36Sopenharmony_ci } 776262306a36Sopenharmony_ci 776362306a36Sopenharmony_ci ioc->eventContext++; 776462306a36Sopenharmony_ci } 776562306a36Sopenharmony_ci 776662306a36Sopenharmony_ci 776762306a36Sopenharmony_ci /* 776862306a36Sopenharmony_ci * Call each currently registered protocol event handler. 776962306a36Sopenharmony_ci */ 777062306a36Sopenharmony_ci for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) { 777162306a36Sopenharmony_ci if (MptEvHandlers[cb_idx]) { 777262306a36Sopenharmony_ci devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT 777362306a36Sopenharmony_ci "Routing Event to event handler #%d\n", 777462306a36Sopenharmony_ci ioc->name, cb_idx)); 777562306a36Sopenharmony_ci r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply); 777662306a36Sopenharmony_ci handlers++; 777762306a36Sopenharmony_ci } 777862306a36Sopenharmony_ci } 777962306a36Sopenharmony_ci /* FIXME? Examine results here? */ 778062306a36Sopenharmony_ci 778162306a36Sopenharmony_ci /* 778262306a36Sopenharmony_ci * If needed, send (a single) EventAck. 778362306a36Sopenharmony_ci */ 778462306a36Sopenharmony_ci if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) { 778562306a36Sopenharmony_ci devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT 778662306a36Sopenharmony_ci "EventAck required\n",ioc->name)); 778762306a36Sopenharmony_ci if ((ii = SendEventAck(ioc, pEventReply)) != 0) { 778862306a36Sopenharmony_ci devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n", 778962306a36Sopenharmony_ci ioc->name, ii)); 779062306a36Sopenharmony_ci } 779162306a36Sopenharmony_ci } 779262306a36Sopenharmony_ci 779362306a36Sopenharmony_ci *evHandlers = handlers; 779462306a36Sopenharmony_ci return r; 779562306a36Sopenharmony_ci} 779662306a36Sopenharmony_ci 779762306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 779862306a36Sopenharmony_ci/** 779962306a36Sopenharmony_ci * mpt_fc_log_info - Log information returned from Fibre Channel IOC. 780062306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 780162306a36Sopenharmony_ci * @log_info: U32 LogInfo reply word from the IOC 780262306a36Sopenharmony_ci * 780362306a36Sopenharmony_ci * Refer to lsi/mpi_log_fc.h. 780462306a36Sopenharmony_ci */ 780562306a36Sopenharmony_cistatic void 780662306a36Sopenharmony_cimpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info) 780762306a36Sopenharmony_ci{ 780862306a36Sopenharmony_ci char *desc = "unknown"; 780962306a36Sopenharmony_ci 781062306a36Sopenharmony_ci switch (log_info & 0xFF000000) { 781162306a36Sopenharmony_ci case MPI_IOCLOGINFO_FC_INIT_BASE: 781262306a36Sopenharmony_ci desc = "FCP Initiator"; 781362306a36Sopenharmony_ci break; 781462306a36Sopenharmony_ci case MPI_IOCLOGINFO_FC_TARGET_BASE: 781562306a36Sopenharmony_ci desc = "FCP Target"; 781662306a36Sopenharmony_ci break; 781762306a36Sopenharmony_ci case MPI_IOCLOGINFO_FC_LAN_BASE: 781862306a36Sopenharmony_ci desc = "LAN"; 781962306a36Sopenharmony_ci break; 782062306a36Sopenharmony_ci case MPI_IOCLOGINFO_FC_MSG_BASE: 782162306a36Sopenharmony_ci desc = "MPI Message Layer"; 782262306a36Sopenharmony_ci break; 782362306a36Sopenharmony_ci case MPI_IOCLOGINFO_FC_LINK_BASE: 782462306a36Sopenharmony_ci desc = "FC Link"; 782562306a36Sopenharmony_ci break; 782662306a36Sopenharmony_ci case MPI_IOCLOGINFO_FC_CTX_BASE: 782762306a36Sopenharmony_ci desc = "Context Manager"; 782862306a36Sopenharmony_ci break; 782962306a36Sopenharmony_ci case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET: 783062306a36Sopenharmony_ci desc = "Invalid Field Offset"; 783162306a36Sopenharmony_ci break; 783262306a36Sopenharmony_ci case MPI_IOCLOGINFO_FC_STATE_CHANGE: 783362306a36Sopenharmony_ci desc = "State Change Info"; 783462306a36Sopenharmony_ci break; 783562306a36Sopenharmony_ci } 783662306a36Sopenharmony_ci 783762306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n", 783862306a36Sopenharmony_ci ioc->name, log_info, desc, (log_info & 0xFFFFFF)); 783962306a36Sopenharmony_ci} 784062306a36Sopenharmony_ci 784162306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 784262306a36Sopenharmony_ci/** 784362306a36Sopenharmony_ci * mpt_spi_log_info - Log information returned from SCSI Parallel IOC. 784462306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 784562306a36Sopenharmony_ci * @log_info: U32 LogInfo word from the IOC 784662306a36Sopenharmony_ci * 784762306a36Sopenharmony_ci * Refer to lsi/sp_log.h. 784862306a36Sopenharmony_ci */ 784962306a36Sopenharmony_cistatic void 785062306a36Sopenharmony_cimpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) 785162306a36Sopenharmony_ci{ 785262306a36Sopenharmony_ci u32 info = log_info & 0x00FF0000; 785362306a36Sopenharmony_ci char *desc = "unknown"; 785462306a36Sopenharmony_ci 785562306a36Sopenharmony_ci switch (info) { 785662306a36Sopenharmony_ci case 0x00010000: 785762306a36Sopenharmony_ci desc = "bug! MID not found"; 785862306a36Sopenharmony_ci break; 785962306a36Sopenharmony_ci 786062306a36Sopenharmony_ci case 0x00020000: 786162306a36Sopenharmony_ci desc = "Parity Error"; 786262306a36Sopenharmony_ci break; 786362306a36Sopenharmony_ci 786462306a36Sopenharmony_ci case 0x00030000: 786562306a36Sopenharmony_ci desc = "ASYNC Outbound Overrun"; 786662306a36Sopenharmony_ci break; 786762306a36Sopenharmony_ci 786862306a36Sopenharmony_ci case 0x00040000: 786962306a36Sopenharmony_ci desc = "SYNC Offset Error"; 787062306a36Sopenharmony_ci break; 787162306a36Sopenharmony_ci 787262306a36Sopenharmony_ci case 0x00050000: 787362306a36Sopenharmony_ci desc = "BM Change"; 787462306a36Sopenharmony_ci break; 787562306a36Sopenharmony_ci 787662306a36Sopenharmony_ci case 0x00060000: 787762306a36Sopenharmony_ci desc = "Msg In Overflow"; 787862306a36Sopenharmony_ci break; 787962306a36Sopenharmony_ci 788062306a36Sopenharmony_ci case 0x00070000: 788162306a36Sopenharmony_ci desc = "DMA Error"; 788262306a36Sopenharmony_ci break; 788362306a36Sopenharmony_ci 788462306a36Sopenharmony_ci case 0x00080000: 788562306a36Sopenharmony_ci desc = "Outbound DMA Overrun"; 788662306a36Sopenharmony_ci break; 788762306a36Sopenharmony_ci 788862306a36Sopenharmony_ci case 0x00090000: 788962306a36Sopenharmony_ci desc = "Task Management"; 789062306a36Sopenharmony_ci break; 789162306a36Sopenharmony_ci 789262306a36Sopenharmony_ci case 0x000A0000: 789362306a36Sopenharmony_ci desc = "Device Problem"; 789462306a36Sopenharmony_ci break; 789562306a36Sopenharmony_ci 789662306a36Sopenharmony_ci case 0x000B0000: 789762306a36Sopenharmony_ci desc = "Invalid Phase Change"; 789862306a36Sopenharmony_ci break; 789962306a36Sopenharmony_ci 790062306a36Sopenharmony_ci case 0x000C0000: 790162306a36Sopenharmony_ci desc = "Untagged Table Size"; 790262306a36Sopenharmony_ci break; 790362306a36Sopenharmony_ci 790462306a36Sopenharmony_ci } 790562306a36Sopenharmony_ci 790662306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc); 790762306a36Sopenharmony_ci} 790862306a36Sopenharmony_ci 790962306a36Sopenharmony_ci/* strings for sas loginfo */ 791062306a36Sopenharmony_ci static char *originator_str[] = { 791162306a36Sopenharmony_ci "IOP", /* 00h */ 791262306a36Sopenharmony_ci "PL", /* 01h */ 791362306a36Sopenharmony_ci "IR" /* 02h */ 791462306a36Sopenharmony_ci }; 791562306a36Sopenharmony_ci static char *iop_code_str[] = { 791662306a36Sopenharmony_ci NULL, /* 00h */ 791762306a36Sopenharmony_ci "Invalid SAS Address", /* 01h */ 791862306a36Sopenharmony_ci NULL, /* 02h */ 791962306a36Sopenharmony_ci "Invalid Page", /* 03h */ 792062306a36Sopenharmony_ci "Diag Message Error", /* 04h */ 792162306a36Sopenharmony_ci "Task Terminated", /* 05h */ 792262306a36Sopenharmony_ci "Enclosure Management", /* 06h */ 792362306a36Sopenharmony_ci "Target Mode" /* 07h */ 792462306a36Sopenharmony_ci }; 792562306a36Sopenharmony_ci static char *pl_code_str[] = { 792662306a36Sopenharmony_ci NULL, /* 00h */ 792762306a36Sopenharmony_ci "Open Failure", /* 01h */ 792862306a36Sopenharmony_ci "Invalid Scatter Gather List", /* 02h */ 792962306a36Sopenharmony_ci "Wrong Relative Offset or Frame Length", /* 03h */ 793062306a36Sopenharmony_ci "Frame Transfer Error", /* 04h */ 793162306a36Sopenharmony_ci "Transmit Frame Connected Low", /* 05h */ 793262306a36Sopenharmony_ci "SATA Non-NCQ RW Error Bit Set", /* 06h */ 793362306a36Sopenharmony_ci "SATA Read Log Receive Data Error", /* 07h */ 793462306a36Sopenharmony_ci "SATA NCQ Fail All Commands After Error", /* 08h */ 793562306a36Sopenharmony_ci "SATA Error in Receive Set Device Bit FIS", /* 09h */ 793662306a36Sopenharmony_ci "Receive Frame Invalid Message", /* 0Ah */ 793762306a36Sopenharmony_ci "Receive Context Message Valid Error", /* 0Bh */ 793862306a36Sopenharmony_ci "Receive Frame Current Frame Error", /* 0Ch */ 793962306a36Sopenharmony_ci "SATA Link Down", /* 0Dh */ 794062306a36Sopenharmony_ci "Discovery SATA Init W IOS", /* 0Eh */ 794162306a36Sopenharmony_ci "Config Invalid Page", /* 0Fh */ 794262306a36Sopenharmony_ci "Discovery SATA Init Timeout", /* 10h */ 794362306a36Sopenharmony_ci "Reset", /* 11h */ 794462306a36Sopenharmony_ci "Abort", /* 12h */ 794562306a36Sopenharmony_ci "IO Not Yet Executed", /* 13h */ 794662306a36Sopenharmony_ci "IO Executed", /* 14h */ 794762306a36Sopenharmony_ci "Persistent Reservation Out Not Affiliation " 794862306a36Sopenharmony_ci "Owner", /* 15h */ 794962306a36Sopenharmony_ci "Open Transmit DMA Abort", /* 16h */ 795062306a36Sopenharmony_ci "IO Device Missing Delay Retry", /* 17h */ 795162306a36Sopenharmony_ci "IO Cancelled Due to Receive Error", /* 18h */ 795262306a36Sopenharmony_ci NULL, /* 19h */ 795362306a36Sopenharmony_ci NULL, /* 1Ah */ 795462306a36Sopenharmony_ci NULL, /* 1Bh */ 795562306a36Sopenharmony_ci NULL, /* 1Ch */ 795662306a36Sopenharmony_ci NULL, /* 1Dh */ 795762306a36Sopenharmony_ci NULL, /* 1Eh */ 795862306a36Sopenharmony_ci NULL, /* 1Fh */ 795962306a36Sopenharmony_ci "Enclosure Management" /* 20h */ 796062306a36Sopenharmony_ci }; 796162306a36Sopenharmony_ci static char *ir_code_str[] = { 796262306a36Sopenharmony_ci "Raid Action Error", /* 00h */ 796362306a36Sopenharmony_ci NULL, /* 00h */ 796462306a36Sopenharmony_ci NULL, /* 01h */ 796562306a36Sopenharmony_ci NULL, /* 02h */ 796662306a36Sopenharmony_ci NULL, /* 03h */ 796762306a36Sopenharmony_ci NULL, /* 04h */ 796862306a36Sopenharmony_ci NULL, /* 05h */ 796962306a36Sopenharmony_ci NULL, /* 06h */ 797062306a36Sopenharmony_ci NULL /* 07h */ 797162306a36Sopenharmony_ci }; 797262306a36Sopenharmony_ci static char *raid_sub_code_str[] = { 797362306a36Sopenharmony_ci NULL, /* 00h */ 797462306a36Sopenharmony_ci "Volume Creation Failed: Data Passed too " 797562306a36Sopenharmony_ci "Large", /* 01h */ 797662306a36Sopenharmony_ci "Volume Creation Failed: Duplicate Volumes " 797762306a36Sopenharmony_ci "Attempted", /* 02h */ 797862306a36Sopenharmony_ci "Volume Creation Failed: Max Number " 797962306a36Sopenharmony_ci "Supported Volumes Exceeded", /* 03h */ 798062306a36Sopenharmony_ci "Volume Creation Failed: DMA Error", /* 04h */ 798162306a36Sopenharmony_ci "Volume Creation Failed: Invalid Volume Type", /* 05h */ 798262306a36Sopenharmony_ci "Volume Creation Failed: Error Reading " 798362306a36Sopenharmony_ci "MFG Page 4", /* 06h */ 798462306a36Sopenharmony_ci "Volume Creation Failed: Creating Internal " 798562306a36Sopenharmony_ci "Structures", /* 07h */ 798662306a36Sopenharmony_ci NULL, /* 08h */ 798762306a36Sopenharmony_ci NULL, /* 09h */ 798862306a36Sopenharmony_ci NULL, /* 0Ah */ 798962306a36Sopenharmony_ci NULL, /* 0Bh */ 799062306a36Sopenharmony_ci NULL, /* 0Ch */ 799162306a36Sopenharmony_ci NULL, /* 0Dh */ 799262306a36Sopenharmony_ci NULL, /* 0Eh */ 799362306a36Sopenharmony_ci NULL, /* 0Fh */ 799462306a36Sopenharmony_ci "Activation failed: Already Active Volume", /* 10h */ 799562306a36Sopenharmony_ci "Activation failed: Unsupported Volume Type", /* 11h */ 799662306a36Sopenharmony_ci "Activation failed: Too Many Active Volumes", /* 12h */ 799762306a36Sopenharmony_ci "Activation failed: Volume ID in Use", /* 13h */ 799862306a36Sopenharmony_ci "Activation failed: Reported Failure", /* 14h */ 799962306a36Sopenharmony_ci "Activation failed: Importing a Volume", /* 15h */ 800062306a36Sopenharmony_ci NULL, /* 16h */ 800162306a36Sopenharmony_ci NULL, /* 17h */ 800262306a36Sopenharmony_ci NULL, /* 18h */ 800362306a36Sopenharmony_ci NULL, /* 19h */ 800462306a36Sopenharmony_ci NULL, /* 1Ah */ 800562306a36Sopenharmony_ci NULL, /* 1Bh */ 800662306a36Sopenharmony_ci NULL, /* 1Ch */ 800762306a36Sopenharmony_ci NULL, /* 1Dh */ 800862306a36Sopenharmony_ci NULL, /* 1Eh */ 800962306a36Sopenharmony_ci NULL, /* 1Fh */ 801062306a36Sopenharmony_ci "Phys Disk failed: Too Many Phys Disks", /* 20h */ 801162306a36Sopenharmony_ci "Phys Disk failed: Data Passed too Large", /* 21h */ 801262306a36Sopenharmony_ci "Phys Disk failed: DMA Error", /* 22h */ 801362306a36Sopenharmony_ci "Phys Disk failed: Invalid <channel:id>", /* 23h */ 801462306a36Sopenharmony_ci "Phys Disk failed: Creating Phys Disk Config " 801562306a36Sopenharmony_ci "Page", /* 24h */ 801662306a36Sopenharmony_ci NULL, /* 25h */ 801762306a36Sopenharmony_ci NULL, /* 26h */ 801862306a36Sopenharmony_ci NULL, /* 27h */ 801962306a36Sopenharmony_ci NULL, /* 28h */ 802062306a36Sopenharmony_ci NULL, /* 29h */ 802162306a36Sopenharmony_ci NULL, /* 2Ah */ 802262306a36Sopenharmony_ci NULL, /* 2Bh */ 802362306a36Sopenharmony_ci NULL, /* 2Ch */ 802462306a36Sopenharmony_ci NULL, /* 2Dh */ 802562306a36Sopenharmony_ci NULL, /* 2Eh */ 802662306a36Sopenharmony_ci NULL, /* 2Fh */ 802762306a36Sopenharmony_ci "Compatibility Error: IR Disabled", /* 30h */ 802862306a36Sopenharmony_ci "Compatibility Error: Inquiry Command Failed", /* 31h */ 802962306a36Sopenharmony_ci "Compatibility Error: Device not Direct Access " 803062306a36Sopenharmony_ci "Device ", /* 32h */ 803162306a36Sopenharmony_ci "Compatibility Error: Removable Device Found", /* 33h */ 803262306a36Sopenharmony_ci "Compatibility Error: Device SCSI Version not " 803362306a36Sopenharmony_ci "2 or Higher", /* 34h */ 803462306a36Sopenharmony_ci "Compatibility Error: SATA Device, 48 BIT LBA " 803562306a36Sopenharmony_ci "not Supported", /* 35h */ 803662306a36Sopenharmony_ci "Compatibility Error: Device doesn't have " 803762306a36Sopenharmony_ci "512 Byte Block Sizes", /* 36h */ 803862306a36Sopenharmony_ci "Compatibility Error: Volume Type Check Failed", /* 37h */ 803962306a36Sopenharmony_ci "Compatibility Error: Volume Type is " 804062306a36Sopenharmony_ci "Unsupported by FW", /* 38h */ 804162306a36Sopenharmony_ci "Compatibility Error: Disk Drive too Small for " 804262306a36Sopenharmony_ci "use in Volume", /* 39h */ 804362306a36Sopenharmony_ci "Compatibility Error: Phys Disk for Create " 804462306a36Sopenharmony_ci "Volume not Found", /* 3Ah */ 804562306a36Sopenharmony_ci "Compatibility Error: Too Many or too Few " 804662306a36Sopenharmony_ci "Disks for Volume Type", /* 3Bh */ 804762306a36Sopenharmony_ci "Compatibility Error: Disk stripe Sizes " 804862306a36Sopenharmony_ci "Must be 64KB", /* 3Ch */ 804962306a36Sopenharmony_ci "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */ 805062306a36Sopenharmony_ci }; 805162306a36Sopenharmony_ci 805262306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 805362306a36Sopenharmony_ci/** 805462306a36Sopenharmony_ci * mpt_sas_log_info - Log information returned from SAS IOC. 805562306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 805662306a36Sopenharmony_ci * @log_info: U32 LogInfo reply word from the IOC 805762306a36Sopenharmony_ci * @cb_idx: callback function's handle 805862306a36Sopenharmony_ci * 805962306a36Sopenharmony_ci * Refer to lsi/mpi_log_sas.h. 806062306a36Sopenharmony_ci **/ 806162306a36Sopenharmony_cistatic void 806262306a36Sopenharmony_cimpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info, u8 cb_idx) 806362306a36Sopenharmony_ci{ 806462306a36Sopenharmony_ci union loginfo_type { 806562306a36Sopenharmony_ci u32 loginfo; 806662306a36Sopenharmony_ci struct { 806762306a36Sopenharmony_ci u32 subcode:16; 806862306a36Sopenharmony_ci u32 code:8; 806962306a36Sopenharmony_ci u32 originator:4; 807062306a36Sopenharmony_ci u32 bus_type:4; 807162306a36Sopenharmony_ci } dw; 807262306a36Sopenharmony_ci }; 807362306a36Sopenharmony_ci union loginfo_type sas_loginfo; 807462306a36Sopenharmony_ci char *originator_desc = NULL; 807562306a36Sopenharmony_ci char *code_desc = NULL; 807662306a36Sopenharmony_ci char *sub_code_desc = NULL; 807762306a36Sopenharmony_ci 807862306a36Sopenharmony_ci sas_loginfo.loginfo = log_info; 807962306a36Sopenharmony_ci if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) && 808062306a36Sopenharmony_ci (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str))) 808162306a36Sopenharmony_ci return; 808262306a36Sopenharmony_ci 808362306a36Sopenharmony_ci originator_desc = originator_str[sas_loginfo.dw.originator]; 808462306a36Sopenharmony_ci 808562306a36Sopenharmony_ci switch (sas_loginfo.dw.originator) { 808662306a36Sopenharmony_ci 808762306a36Sopenharmony_ci case 0: /* IOP */ 808862306a36Sopenharmony_ci if (sas_loginfo.dw.code < 808962306a36Sopenharmony_ci ARRAY_SIZE(iop_code_str)) 809062306a36Sopenharmony_ci code_desc = iop_code_str[sas_loginfo.dw.code]; 809162306a36Sopenharmony_ci break; 809262306a36Sopenharmony_ci case 1: /* PL */ 809362306a36Sopenharmony_ci if (sas_loginfo.dw.code < 809462306a36Sopenharmony_ci ARRAY_SIZE(pl_code_str)) 809562306a36Sopenharmony_ci code_desc = pl_code_str[sas_loginfo.dw.code]; 809662306a36Sopenharmony_ci break; 809762306a36Sopenharmony_ci case 2: /* IR */ 809862306a36Sopenharmony_ci if (sas_loginfo.dw.code >= 809962306a36Sopenharmony_ci ARRAY_SIZE(ir_code_str)) 810062306a36Sopenharmony_ci break; 810162306a36Sopenharmony_ci code_desc = ir_code_str[sas_loginfo.dw.code]; 810262306a36Sopenharmony_ci if (sas_loginfo.dw.subcode >= 810362306a36Sopenharmony_ci ARRAY_SIZE(raid_sub_code_str)) 810462306a36Sopenharmony_ci break; 810562306a36Sopenharmony_ci if (sas_loginfo.dw.code == 0) 810662306a36Sopenharmony_ci sub_code_desc = 810762306a36Sopenharmony_ci raid_sub_code_str[sas_loginfo.dw.subcode]; 810862306a36Sopenharmony_ci break; 810962306a36Sopenharmony_ci default: 811062306a36Sopenharmony_ci return; 811162306a36Sopenharmony_ci } 811262306a36Sopenharmony_ci 811362306a36Sopenharmony_ci if (sub_code_desc != NULL) 811462306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT 811562306a36Sopenharmony_ci "LogInfo(0x%08x): Originator={%s}, Code={%s}," 811662306a36Sopenharmony_ci " SubCode={%s} cb_idx %s\n", 811762306a36Sopenharmony_ci ioc->name, log_info, originator_desc, code_desc, 811862306a36Sopenharmony_ci sub_code_desc, MptCallbacksName[cb_idx]); 811962306a36Sopenharmony_ci else if (code_desc != NULL) 812062306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT 812162306a36Sopenharmony_ci "LogInfo(0x%08x): Originator={%s}, Code={%s}," 812262306a36Sopenharmony_ci " SubCode(0x%04x) cb_idx %s\n", 812362306a36Sopenharmony_ci ioc->name, log_info, originator_desc, code_desc, 812462306a36Sopenharmony_ci sas_loginfo.dw.subcode, MptCallbacksName[cb_idx]); 812562306a36Sopenharmony_ci else 812662306a36Sopenharmony_ci printk(MYIOC_s_INFO_FMT 812762306a36Sopenharmony_ci "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x)," 812862306a36Sopenharmony_ci " SubCode(0x%04x) cb_idx %s\n", 812962306a36Sopenharmony_ci ioc->name, log_info, originator_desc, 813062306a36Sopenharmony_ci sas_loginfo.dw.code, sas_loginfo.dw.subcode, 813162306a36Sopenharmony_ci MptCallbacksName[cb_idx]); 813262306a36Sopenharmony_ci} 813362306a36Sopenharmony_ci 813462306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 813562306a36Sopenharmony_ci/** 813662306a36Sopenharmony_ci * mpt_iocstatus_info_config - IOCSTATUS information for config pages 813762306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 813862306a36Sopenharmony_ci * @ioc_status: U32 IOCStatus word from IOC 813962306a36Sopenharmony_ci * @mf: Pointer to MPT request frame 814062306a36Sopenharmony_ci * 814162306a36Sopenharmony_ci * Refer to lsi/mpi.h. 814262306a36Sopenharmony_ci **/ 814362306a36Sopenharmony_cistatic void 814462306a36Sopenharmony_cimpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf) 814562306a36Sopenharmony_ci{ 814662306a36Sopenharmony_ci Config_t *pReq = (Config_t *)mf; 814762306a36Sopenharmony_ci char extend_desc[EVENT_DESCR_STR_SZ]; 814862306a36Sopenharmony_ci char *desc = NULL; 814962306a36Sopenharmony_ci u32 form; 815062306a36Sopenharmony_ci u8 page_type; 815162306a36Sopenharmony_ci 815262306a36Sopenharmony_ci if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED) 815362306a36Sopenharmony_ci page_type = pReq->ExtPageType; 815462306a36Sopenharmony_ci else 815562306a36Sopenharmony_ci page_type = pReq->Header.PageType; 815662306a36Sopenharmony_ci 815762306a36Sopenharmony_ci /* 815862306a36Sopenharmony_ci * ignore invalid page messages for GET_NEXT_HANDLE 815962306a36Sopenharmony_ci */ 816062306a36Sopenharmony_ci form = le32_to_cpu(pReq->PageAddress); 816162306a36Sopenharmony_ci if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { 816262306a36Sopenharmony_ci if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE || 816362306a36Sopenharmony_ci page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER || 816462306a36Sopenharmony_ci page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) { 816562306a36Sopenharmony_ci if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) == 816662306a36Sopenharmony_ci MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) 816762306a36Sopenharmony_ci return; 816862306a36Sopenharmony_ci } 816962306a36Sopenharmony_ci if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE) 817062306a36Sopenharmony_ci if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) == 817162306a36Sopenharmony_ci MPI_FC_DEVICE_PGAD_FORM_NEXT_DID) 817262306a36Sopenharmony_ci return; 817362306a36Sopenharmony_ci } 817462306a36Sopenharmony_ci 817562306a36Sopenharmony_ci snprintf(extend_desc, EVENT_DESCR_STR_SZ, 817662306a36Sopenharmony_ci "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh", 817762306a36Sopenharmony_ci page_type, pReq->Header.PageNumber, pReq->Action, form); 817862306a36Sopenharmony_ci 817962306a36Sopenharmony_ci switch (ioc_status) { 818062306a36Sopenharmony_ci 818162306a36Sopenharmony_ci case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */ 818262306a36Sopenharmony_ci desc = "Config Page Invalid Action"; 818362306a36Sopenharmony_ci break; 818462306a36Sopenharmony_ci 818562306a36Sopenharmony_ci case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */ 818662306a36Sopenharmony_ci desc = "Config Page Invalid Type"; 818762306a36Sopenharmony_ci break; 818862306a36Sopenharmony_ci 818962306a36Sopenharmony_ci case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */ 819062306a36Sopenharmony_ci desc = "Config Page Invalid Page"; 819162306a36Sopenharmony_ci break; 819262306a36Sopenharmony_ci 819362306a36Sopenharmony_ci case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */ 819462306a36Sopenharmony_ci desc = "Config Page Invalid Data"; 819562306a36Sopenharmony_ci break; 819662306a36Sopenharmony_ci 819762306a36Sopenharmony_ci case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */ 819862306a36Sopenharmony_ci desc = "Config Page No Defaults"; 819962306a36Sopenharmony_ci break; 820062306a36Sopenharmony_ci 820162306a36Sopenharmony_ci case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */ 820262306a36Sopenharmony_ci desc = "Config Page Can't Commit"; 820362306a36Sopenharmony_ci break; 820462306a36Sopenharmony_ci } 820562306a36Sopenharmony_ci 820662306a36Sopenharmony_ci if (!desc) 820762306a36Sopenharmony_ci return; 820862306a36Sopenharmony_ci 820962306a36Sopenharmony_ci dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n", 821062306a36Sopenharmony_ci ioc->name, ioc_status, desc, extend_desc)); 821162306a36Sopenharmony_ci} 821262306a36Sopenharmony_ci 821362306a36Sopenharmony_ci/** 821462306a36Sopenharmony_ci * mpt_iocstatus_info - IOCSTATUS information returned from IOC. 821562306a36Sopenharmony_ci * @ioc: Pointer to MPT_ADAPTER structure 821662306a36Sopenharmony_ci * @ioc_status: U32 IOCStatus word from IOC 821762306a36Sopenharmony_ci * @mf: Pointer to MPT request frame 821862306a36Sopenharmony_ci * 821962306a36Sopenharmony_ci * Refer to lsi/mpi.h. 822062306a36Sopenharmony_ci **/ 822162306a36Sopenharmony_cistatic void 822262306a36Sopenharmony_cimpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf) 822362306a36Sopenharmony_ci{ 822462306a36Sopenharmony_ci u32 status = ioc_status & MPI_IOCSTATUS_MASK; 822562306a36Sopenharmony_ci char *desc = NULL; 822662306a36Sopenharmony_ci 822762306a36Sopenharmony_ci switch (status) { 822862306a36Sopenharmony_ci 822962306a36Sopenharmony_ci/****************************************************************************/ 823062306a36Sopenharmony_ci/* Common IOCStatus values for all replies */ 823162306a36Sopenharmony_ci/****************************************************************************/ 823262306a36Sopenharmony_ci 823362306a36Sopenharmony_ci case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */ 823462306a36Sopenharmony_ci desc = "Invalid Function"; 823562306a36Sopenharmony_ci break; 823662306a36Sopenharmony_ci 823762306a36Sopenharmony_ci case MPI_IOCSTATUS_BUSY: /* 0x0002 */ 823862306a36Sopenharmony_ci desc = "Busy"; 823962306a36Sopenharmony_ci break; 824062306a36Sopenharmony_ci 824162306a36Sopenharmony_ci case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */ 824262306a36Sopenharmony_ci desc = "Invalid SGL"; 824362306a36Sopenharmony_ci break; 824462306a36Sopenharmony_ci 824562306a36Sopenharmony_ci case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */ 824662306a36Sopenharmony_ci desc = "Internal Error"; 824762306a36Sopenharmony_ci break; 824862306a36Sopenharmony_ci 824962306a36Sopenharmony_ci case MPI_IOCSTATUS_RESERVED: /* 0x0005 */ 825062306a36Sopenharmony_ci desc = "Reserved"; 825162306a36Sopenharmony_ci break; 825262306a36Sopenharmony_ci 825362306a36Sopenharmony_ci case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */ 825462306a36Sopenharmony_ci desc = "Insufficient Resources"; 825562306a36Sopenharmony_ci break; 825662306a36Sopenharmony_ci 825762306a36Sopenharmony_ci case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */ 825862306a36Sopenharmony_ci desc = "Invalid Field"; 825962306a36Sopenharmony_ci break; 826062306a36Sopenharmony_ci 826162306a36Sopenharmony_ci case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */ 826262306a36Sopenharmony_ci desc = "Invalid State"; 826362306a36Sopenharmony_ci break; 826462306a36Sopenharmony_ci 826562306a36Sopenharmony_ci/****************************************************************************/ 826662306a36Sopenharmony_ci/* Config IOCStatus values */ 826762306a36Sopenharmony_ci/****************************************************************************/ 826862306a36Sopenharmony_ci 826962306a36Sopenharmony_ci case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */ 827062306a36Sopenharmony_ci case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */ 827162306a36Sopenharmony_ci case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */ 827262306a36Sopenharmony_ci case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */ 827362306a36Sopenharmony_ci case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */ 827462306a36Sopenharmony_ci case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */ 827562306a36Sopenharmony_ci mpt_iocstatus_info_config(ioc, status, mf); 827662306a36Sopenharmony_ci break; 827762306a36Sopenharmony_ci 827862306a36Sopenharmony_ci/****************************************************************************/ 827962306a36Sopenharmony_ci/* SCSIIO Reply (SPI, FCP, SAS) initiator values */ 828062306a36Sopenharmony_ci/* */ 828162306a36Sopenharmony_ci/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */ 828262306a36Sopenharmony_ci/* */ 828362306a36Sopenharmony_ci/****************************************************************************/ 828462306a36Sopenharmony_ci 828562306a36Sopenharmony_ci case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ 828662306a36Sopenharmony_ci case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ 828762306a36Sopenharmony_ci case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */ 828862306a36Sopenharmony_ci case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */ 828962306a36Sopenharmony_ci case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ 829062306a36Sopenharmony_ci case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */ 829162306a36Sopenharmony_ci case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ 829262306a36Sopenharmony_ci case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ 829362306a36Sopenharmony_ci case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ 829462306a36Sopenharmony_ci case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ 829562306a36Sopenharmony_ci case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */ 829662306a36Sopenharmony_ci case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ 829762306a36Sopenharmony_ci case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ 829862306a36Sopenharmony_ci break; 829962306a36Sopenharmony_ci 830062306a36Sopenharmony_ci/****************************************************************************/ 830162306a36Sopenharmony_ci/* SCSI Target values */ 830262306a36Sopenharmony_ci/****************************************************************************/ 830362306a36Sopenharmony_ci 830462306a36Sopenharmony_ci case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */ 830562306a36Sopenharmony_ci desc = "Target: Priority IO"; 830662306a36Sopenharmony_ci break; 830762306a36Sopenharmony_ci 830862306a36Sopenharmony_ci case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */ 830962306a36Sopenharmony_ci desc = "Target: Invalid Port"; 831062306a36Sopenharmony_ci break; 831162306a36Sopenharmony_ci 831262306a36Sopenharmony_ci case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */ 831362306a36Sopenharmony_ci desc = "Target Invalid IO Index:"; 831462306a36Sopenharmony_ci break; 831562306a36Sopenharmony_ci 831662306a36Sopenharmony_ci case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */ 831762306a36Sopenharmony_ci desc = "Target: Aborted"; 831862306a36Sopenharmony_ci break; 831962306a36Sopenharmony_ci 832062306a36Sopenharmony_ci case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */ 832162306a36Sopenharmony_ci desc = "Target: No Conn Retryable"; 832262306a36Sopenharmony_ci break; 832362306a36Sopenharmony_ci 832462306a36Sopenharmony_ci case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */ 832562306a36Sopenharmony_ci desc = "Target: No Connection"; 832662306a36Sopenharmony_ci break; 832762306a36Sopenharmony_ci 832862306a36Sopenharmony_ci case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */ 832962306a36Sopenharmony_ci desc = "Target: Transfer Count Mismatch"; 833062306a36Sopenharmony_ci break; 833162306a36Sopenharmony_ci 833262306a36Sopenharmony_ci case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */ 833362306a36Sopenharmony_ci desc = "Target: STS Data not Sent"; 833462306a36Sopenharmony_ci break; 833562306a36Sopenharmony_ci 833662306a36Sopenharmony_ci case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */ 833762306a36Sopenharmony_ci desc = "Target: Data Offset Error"; 833862306a36Sopenharmony_ci break; 833962306a36Sopenharmony_ci 834062306a36Sopenharmony_ci case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */ 834162306a36Sopenharmony_ci desc = "Target: Too Much Write Data"; 834262306a36Sopenharmony_ci break; 834362306a36Sopenharmony_ci 834462306a36Sopenharmony_ci case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */ 834562306a36Sopenharmony_ci desc = "Target: IU Too Short"; 834662306a36Sopenharmony_ci break; 834762306a36Sopenharmony_ci 834862306a36Sopenharmony_ci case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */ 834962306a36Sopenharmony_ci desc = "Target: ACK NAK Timeout"; 835062306a36Sopenharmony_ci break; 835162306a36Sopenharmony_ci 835262306a36Sopenharmony_ci case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */ 835362306a36Sopenharmony_ci desc = "Target: Nak Received"; 835462306a36Sopenharmony_ci break; 835562306a36Sopenharmony_ci 835662306a36Sopenharmony_ci/****************************************************************************/ 835762306a36Sopenharmony_ci/* Fibre Channel Direct Access values */ 835862306a36Sopenharmony_ci/****************************************************************************/ 835962306a36Sopenharmony_ci 836062306a36Sopenharmony_ci case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */ 836162306a36Sopenharmony_ci desc = "FC: Aborted"; 836262306a36Sopenharmony_ci break; 836362306a36Sopenharmony_ci 836462306a36Sopenharmony_ci case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */ 836562306a36Sopenharmony_ci desc = "FC: RX ID Invalid"; 836662306a36Sopenharmony_ci break; 836762306a36Sopenharmony_ci 836862306a36Sopenharmony_ci case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */ 836962306a36Sopenharmony_ci desc = "FC: DID Invalid"; 837062306a36Sopenharmony_ci break; 837162306a36Sopenharmony_ci 837262306a36Sopenharmony_ci case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */ 837362306a36Sopenharmony_ci desc = "FC: Node Logged Out"; 837462306a36Sopenharmony_ci break; 837562306a36Sopenharmony_ci 837662306a36Sopenharmony_ci case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */ 837762306a36Sopenharmony_ci desc = "FC: Exchange Canceled"; 837862306a36Sopenharmony_ci break; 837962306a36Sopenharmony_ci 838062306a36Sopenharmony_ci/****************************************************************************/ 838162306a36Sopenharmony_ci/* LAN values */ 838262306a36Sopenharmony_ci/****************************************************************************/ 838362306a36Sopenharmony_ci 838462306a36Sopenharmony_ci case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */ 838562306a36Sopenharmony_ci desc = "LAN: Device not Found"; 838662306a36Sopenharmony_ci break; 838762306a36Sopenharmony_ci 838862306a36Sopenharmony_ci case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */ 838962306a36Sopenharmony_ci desc = "LAN: Device Failure"; 839062306a36Sopenharmony_ci break; 839162306a36Sopenharmony_ci 839262306a36Sopenharmony_ci case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */ 839362306a36Sopenharmony_ci desc = "LAN: Transmit Error"; 839462306a36Sopenharmony_ci break; 839562306a36Sopenharmony_ci 839662306a36Sopenharmony_ci case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */ 839762306a36Sopenharmony_ci desc = "LAN: Transmit Aborted"; 839862306a36Sopenharmony_ci break; 839962306a36Sopenharmony_ci 840062306a36Sopenharmony_ci case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */ 840162306a36Sopenharmony_ci desc = "LAN: Receive Error"; 840262306a36Sopenharmony_ci break; 840362306a36Sopenharmony_ci 840462306a36Sopenharmony_ci case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */ 840562306a36Sopenharmony_ci desc = "LAN: Receive Aborted"; 840662306a36Sopenharmony_ci break; 840762306a36Sopenharmony_ci 840862306a36Sopenharmony_ci case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */ 840962306a36Sopenharmony_ci desc = "LAN: Partial Packet"; 841062306a36Sopenharmony_ci break; 841162306a36Sopenharmony_ci 841262306a36Sopenharmony_ci case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */ 841362306a36Sopenharmony_ci desc = "LAN: Canceled"; 841462306a36Sopenharmony_ci break; 841562306a36Sopenharmony_ci 841662306a36Sopenharmony_ci/****************************************************************************/ 841762306a36Sopenharmony_ci/* Serial Attached SCSI values */ 841862306a36Sopenharmony_ci/****************************************************************************/ 841962306a36Sopenharmony_ci 842062306a36Sopenharmony_ci case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */ 842162306a36Sopenharmony_ci desc = "SAS: SMP Request Failed"; 842262306a36Sopenharmony_ci break; 842362306a36Sopenharmony_ci 842462306a36Sopenharmony_ci case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */ 842562306a36Sopenharmony_ci desc = "SAS: SMP Data Overrun"; 842662306a36Sopenharmony_ci break; 842762306a36Sopenharmony_ci 842862306a36Sopenharmony_ci default: 842962306a36Sopenharmony_ci desc = "Others"; 843062306a36Sopenharmony_ci break; 843162306a36Sopenharmony_ci } 843262306a36Sopenharmony_ci 843362306a36Sopenharmony_ci if (!desc) 843462306a36Sopenharmony_ci return; 843562306a36Sopenharmony_ci 843662306a36Sopenharmony_ci dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n", 843762306a36Sopenharmony_ci ioc->name, status, desc)); 843862306a36Sopenharmony_ci} 843962306a36Sopenharmony_ci 844062306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 844162306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_attach); 844262306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_detach); 844362306a36Sopenharmony_ci#ifdef CONFIG_PM 844462306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_resume); 844562306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_suspend); 844662306a36Sopenharmony_ci#endif 844762306a36Sopenharmony_ciEXPORT_SYMBOL(ioc_list); 844862306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_register); 844962306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_deregister); 845062306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_event_register); 845162306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_event_deregister); 845262306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_reset_register); 845362306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_reset_deregister); 845462306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_device_driver_register); 845562306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_device_driver_deregister); 845662306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_get_msg_frame); 845762306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_put_msg_frame); 845862306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_put_msg_frame_hi_pri); 845962306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_free_msg_frame); 846062306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_send_handshake_request); 846162306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_verify_adapter); 846262306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_GetIocState); 846362306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_print_ioc_summary); 846462306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_HardResetHandler); 846562306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_config); 846662306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_findImVolumes); 846762306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_alloc_fw_memory); 846862306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_free_fw_memory); 846962306a36Sopenharmony_ciEXPORT_SYMBOL(mptbase_sas_persist_operation); 847062306a36Sopenharmony_ciEXPORT_SYMBOL(mpt_raid_phys_disk_pg0); 847162306a36Sopenharmony_ci 847262306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 847362306a36Sopenharmony_ci/** 847462306a36Sopenharmony_ci * fusion_init - Fusion MPT base driver initialization routine. 847562306a36Sopenharmony_ci * 847662306a36Sopenharmony_ci * Returns 0 for success, non-zero for failure. 847762306a36Sopenharmony_ci */ 847862306a36Sopenharmony_cistatic int __init 847962306a36Sopenharmony_cifusion_init(void) 848062306a36Sopenharmony_ci{ 848162306a36Sopenharmony_ci u8 cb_idx; 848262306a36Sopenharmony_ci 848362306a36Sopenharmony_ci show_mptmod_ver(my_NAME, my_VERSION); 848462306a36Sopenharmony_ci printk(KERN_INFO COPYRIGHT "\n"); 848562306a36Sopenharmony_ci 848662306a36Sopenharmony_ci for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) { 848762306a36Sopenharmony_ci MptCallbacks[cb_idx] = NULL; 848862306a36Sopenharmony_ci MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER; 848962306a36Sopenharmony_ci MptEvHandlers[cb_idx] = NULL; 849062306a36Sopenharmony_ci MptResetHandlers[cb_idx] = NULL; 849162306a36Sopenharmony_ci } 849262306a36Sopenharmony_ci 849362306a36Sopenharmony_ci /* Register ourselves (mptbase) in order to facilitate 849462306a36Sopenharmony_ci * EventNotification handling. 849562306a36Sopenharmony_ci */ 849662306a36Sopenharmony_ci mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER, 849762306a36Sopenharmony_ci "mptbase_reply"); 849862306a36Sopenharmony_ci 849962306a36Sopenharmony_ci /* Register for hard reset handling callbacks. 850062306a36Sopenharmony_ci */ 850162306a36Sopenharmony_ci mpt_reset_register(mpt_base_index, mpt_ioc_reset); 850262306a36Sopenharmony_ci 850362306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 850462306a36Sopenharmony_ci (void) procmpt_create(); 850562306a36Sopenharmony_ci#endif 850662306a36Sopenharmony_ci return 0; 850762306a36Sopenharmony_ci} 850862306a36Sopenharmony_ci 850962306a36Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ 851062306a36Sopenharmony_ci/** 851162306a36Sopenharmony_ci * fusion_exit - Perform driver unload cleanup. 851262306a36Sopenharmony_ci * 851362306a36Sopenharmony_ci * This routine frees all resources associated with each MPT adapter 851462306a36Sopenharmony_ci * and removes all %MPT_PROCFS_MPTBASEDIR entries. 851562306a36Sopenharmony_ci */ 851662306a36Sopenharmony_cistatic void __exit 851762306a36Sopenharmony_cifusion_exit(void) 851862306a36Sopenharmony_ci{ 851962306a36Sopenharmony_ci 852062306a36Sopenharmony_ci mpt_reset_deregister(mpt_base_index); 852162306a36Sopenharmony_ci 852262306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 852362306a36Sopenharmony_ci procmpt_destroy(); 852462306a36Sopenharmony_ci#endif 852562306a36Sopenharmony_ci} 852662306a36Sopenharmony_ci 852762306a36Sopenharmony_cimodule_init(fusion_init); 852862306a36Sopenharmony_cimodule_exit(fusion_exit); 8529