18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci *  linux/drivers/message/fusion/mptbase.c
38c2ecf20Sopenharmony_ci *      This is the Fusion MPT base driver which supports multiple
48c2ecf20Sopenharmony_ci *      (SCSI + LAN) specialized protocol drivers.
58c2ecf20Sopenharmony_ci *      For use with LSI PCI chip/adapter(s)
68c2ecf20Sopenharmony_ci *      running LSI Fusion MPT (Message Passing Technology) firmware.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci *  Copyright (c) 1999-2008 LSI Corporation
98c2ecf20Sopenharmony_ci *  (mailto:DL-MPTFusionLinux@lsi.com)
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
138c2ecf20Sopenharmony_ci/*
148c2ecf20Sopenharmony_ci    This program is free software; you can redistribute it and/or modify
158c2ecf20Sopenharmony_ci    it under the terms of the GNU General Public License as published by
168c2ecf20Sopenharmony_ci    the Free Software Foundation; version 2 of the License.
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci    This program is distributed in the hope that it will be useful,
198c2ecf20Sopenharmony_ci    but WITHOUT ANY WARRANTY; without even the implied warranty of
208c2ecf20Sopenharmony_ci    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
218c2ecf20Sopenharmony_ci    GNU General Public License for more details.
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci    NO WARRANTY
248c2ecf20Sopenharmony_ci    THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
258c2ecf20Sopenharmony_ci    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
268c2ecf20Sopenharmony_ci    LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
278c2ecf20Sopenharmony_ci    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
288c2ecf20Sopenharmony_ci    solely responsible for determining the appropriateness of using and
298c2ecf20Sopenharmony_ci    distributing the Program and assumes all risks associated with its
308c2ecf20Sopenharmony_ci    exercise of rights under this Agreement, including but not limited to
318c2ecf20Sopenharmony_ci    the risks and costs of program errors, damage to or loss of data,
328c2ecf20Sopenharmony_ci    programs or equipment, and unavailability or interruption of operations.
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci    DISCLAIMER OF LIABILITY
358c2ecf20Sopenharmony_ci    NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
368c2ecf20Sopenharmony_ci    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
378c2ecf20Sopenharmony_ci    DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
388c2ecf20Sopenharmony_ci    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
398c2ecf20Sopenharmony_ci    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
408c2ecf20Sopenharmony_ci    USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
418c2ecf20Sopenharmony_ci    HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci    You should have received a copy of the GNU General Public License
448c2ecf20Sopenharmony_ci    along with this program; if not, write to the Free Software
458c2ecf20Sopenharmony_ci    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
468c2ecf20Sopenharmony_ci*/
478c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#include <linux/kernel.h>
508c2ecf20Sopenharmony_ci#include <linux/module.h>
518c2ecf20Sopenharmony_ci#include <linux/errno.h>
528c2ecf20Sopenharmony_ci#include <linux/init.h>
538c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
548c2ecf20Sopenharmony_ci#include <linux/slab.h>
558c2ecf20Sopenharmony_ci#include <linux/types.h>
568c2ecf20Sopenharmony_ci#include <linux/pci.h>
578c2ecf20Sopenharmony_ci#include <linux/kdev_t.h>
588c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
598c2ecf20Sopenharmony_ci#include <linux/delay.h>
608c2ecf20Sopenharmony_ci#include <linux/interrupt.h>		/* needed for in_interrupt() proto */
618c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
628c2ecf20Sopenharmony_ci#include <linux/kthread.h>
638c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci#include "mptbase.h"
668c2ecf20Sopenharmony_ci#include "lsi/mpi_log_fc.h"
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
698c2ecf20Sopenharmony_ci#define my_NAME		"Fusion MPT base driver"
708c2ecf20Sopenharmony_ci#define my_VERSION	MPT_LINUX_VERSION_COMMON
718c2ecf20Sopenharmony_ci#define MYNAM		"mptbase"
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ciMODULE_AUTHOR(MODULEAUTHOR);
748c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(my_NAME);
758c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
768c2ecf20Sopenharmony_ciMODULE_VERSION(my_VERSION);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/*
798c2ecf20Sopenharmony_ci *  cmd line parameters
808c2ecf20Sopenharmony_ci */
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic int mpt_msi_enable_spi;
838c2ecf20Sopenharmony_cimodule_param(mpt_msi_enable_spi, int, 0);
848c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpt_msi_enable_spi,
858c2ecf20Sopenharmony_ci		 " Enable MSI Support for SPI controllers (default=0)");
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic int mpt_msi_enable_fc;
888c2ecf20Sopenharmony_cimodule_param(mpt_msi_enable_fc, int, 0);
898c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpt_msi_enable_fc,
908c2ecf20Sopenharmony_ci		 " Enable MSI Support for FC controllers (default=0)");
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic int mpt_msi_enable_sas;
938c2ecf20Sopenharmony_cimodule_param(mpt_msi_enable_sas, int, 0);
948c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpt_msi_enable_sas,
958c2ecf20Sopenharmony_ci		 " Enable MSI Support for SAS controllers (default=0)");
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic int mpt_channel_mapping;
988c2ecf20Sopenharmony_cimodule_param(mpt_channel_mapping, int, 0);
998c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic int mpt_debug_level;
1028c2ecf20Sopenharmony_cistatic int mpt_set_debug_level(const char *val, const struct kernel_param *kp);
1038c2ecf20Sopenharmony_cimodule_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
1048c2ecf20Sopenharmony_ci		  &mpt_debug_level, 0600);
1058c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpt_debug_level,
1068c2ecf20Sopenharmony_ci		 " debug level - refer to mptdebug.h - (default=0)");
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ciint mpt_fwfault_debug;
1098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_fwfault_debug);
1108c2ecf20Sopenharmony_cimodule_param(mpt_fwfault_debug, int, 0600);
1118c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mpt_fwfault_debug,
1128c2ecf20Sopenharmony_ci		 "Enable detection of Firmware fault and halt Firmware on fault - (default=0)");
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic char	MptCallbacksName[MPT_MAX_PROTOCOL_DRIVERS]
1158c2ecf20Sopenharmony_ci				[MPT_MAX_CALLBACKNAME_LEN+1];
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#ifdef MFCNT
1188c2ecf20Sopenharmony_cistatic int mfcounter = 0;
1198c2ecf20Sopenharmony_ci#define PRINT_MF_COUNT 20000
1208c2ecf20Sopenharmony_ci#endif
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1238c2ecf20Sopenharmony_ci/*
1248c2ecf20Sopenharmony_ci *  Public data...
1258c2ecf20Sopenharmony_ci */
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci#define WHOINIT_UNKNOWN		0xAA
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1308c2ecf20Sopenharmony_ci/*
1318c2ecf20Sopenharmony_ci *  Private data...
1328c2ecf20Sopenharmony_ci */
1338c2ecf20Sopenharmony_ci					/* Adapter link list */
1348c2ecf20Sopenharmony_ciLIST_HEAD(ioc_list);
1358c2ecf20Sopenharmony_ci					/* Callback lookup table */
1368c2ecf20Sopenharmony_cistatic MPT_CALLBACK		 MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
1378c2ecf20Sopenharmony_ci					/* Protocol driver class lookup table */
1388c2ecf20Sopenharmony_cistatic int			 MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
1398c2ecf20Sopenharmony_ci					/* Event handler lookup table */
1408c2ecf20Sopenharmony_cistatic MPT_EVHANDLER		 MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
1418c2ecf20Sopenharmony_ci					/* Reset handler lookup table */
1428c2ecf20Sopenharmony_cistatic MPT_RESETHANDLER		 MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
1438c2ecf20Sopenharmony_cistatic struct mpt_pci_driver 	*MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
1468c2ecf20Sopenharmony_cistatic struct proc_dir_entry 	*mpt_proc_root_dir;
1478c2ecf20Sopenharmony_ci#endif
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci/*
1508c2ecf20Sopenharmony_ci *  Driver Callback Index's
1518c2ecf20Sopenharmony_ci */
1528c2ecf20Sopenharmony_cistatic u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
1538c2ecf20Sopenharmony_cistatic u8 last_drv_idx;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1568c2ecf20Sopenharmony_ci/*
1578c2ecf20Sopenharmony_ci *  Forward protos...
1588c2ecf20Sopenharmony_ci */
1598c2ecf20Sopenharmony_cistatic irqreturn_t mpt_interrupt(int irq, void *bus_id);
1608c2ecf20Sopenharmony_cistatic int	mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1618c2ecf20Sopenharmony_ci		MPT_FRAME_HDR *reply);
1628c2ecf20Sopenharmony_cistatic int	mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
1638c2ecf20Sopenharmony_ci			u32 *req, int replyBytes, u16 *u16reply, int maxwait,
1648c2ecf20Sopenharmony_ci			int sleepFlag);
1658c2ecf20Sopenharmony_cistatic int	mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
1668c2ecf20Sopenharmony_cistatic void	mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
1678c2ecf20Sopenharmony_cistatic void	mpt_adapter_disable(MPT_ADAPTER *ioc);
1688c2ecf20Sopenharmony_cistatic void	mpt_adapter_dispose(MPT_ADAPTER *ioc);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic void	MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
1718c2ecf20Sopenharmony_cistatic int	MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
1728c2ecf20Sopenharmony_cistatic int	GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
1738c2ecf20Sopenharmony_cistatic int	GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
1748c2ecf20Sopenharmony_cistatic int	SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
1758c2ecf20Sopenharmony_cistatic int	SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
1768c2ecf20Sopenharmony_cistatic int	mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
1778c2ecf20Sopenharmony_cistatic int	mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
1788c2ecf20Sopenharmony_cistatic int	mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
1798c2ecf20Sopenharmony_cistatic int	KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
1808c2ecf20Sopenharmony_cistatic int	SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
1818c2ecf20Sopenharmony_cistatic int	PrimeIocFifos(MPT_ADAPTER *ioc);
1828c2ecf20Sopenharmony_cistatic int	WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
1838c2ecf20Sopenharmony_cistatic int	WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
1848c2ecf20Sopenharmony_cistatic int	WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
1858c2ecf20Sopenharmony_cistatic int	GetLanConfigPages(MPT_ADAPTER *ioc);
1868c2ecf20Sopenharmony_cistatic int	GetIoUnitPage2(MPT_ADAPTER *ioc);
1878c2ecf20Sopenharmony_ciint		mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
1888c2ecf20Sopenharmony_cistatic int	mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
1898c2ecf20Sopenharmony_cistatic int	mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
1908c2ecf20Sopenharmony_cistatic void 	mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
1918c2ecf20Sopenharmony_cistatic void 	mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
1928c2ecf20Sopenharmony_cistatic void	mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
1938c2ecf20Sopenharmony_cistatic int	SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,
1948c2ecf20Sopenharmony_ci	int sleepFlag);
1958c2ecf20Sopenharmony_cistatic int	SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
1968c2ecf20Sopenharmony_cistatic int	mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
1978c2ecf20Sopenharmony_cistatic int	mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
2008c2ecf20Sopenharmony_cistatic int mpt_summary_proc_show(struct seq_file *m, void *v);
2018c2ecf20Sopenharmony_cistatic int mpt_version_proc_show(struct seq_file *m, void *v);
2028c2ecf20Sopenharmony_cistatic int mpt_iocinfo_proc_show(struct seq_file *m, void *v);
2038c2ecf20Sopenharmony_ci#endif
2048c2ecf20Sopenharmony_cistatic void	mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic int	ProcessEventNotification(MPT_ADAPTER *ioc,
2078c2ecf20Sopenharmony_ci		EventNotificationReply_t *evReply, int *evHandlers);
2088c2ecf20Sopenharmony_cistatic void	mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
2098c2ecf20Sopenharmony_cistatic void	mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
2108c2ecf20Sopenharmony_cistatic void	mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
2118c2ecf20Sopenharmony_cistatic void	mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info , u8 cb_idx);
2128c2ecf20Sopenharmony_cistatic int	mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
2138c2ecf20Sopenharmony_cistatic void	mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci/* module entry point */
2168c2ecf20Sopenharmony_cistatic int  __init    fusion_init  (void);
2178c2ecf20Sopenharmony_cistatic void __exit    fusion_exit  (void);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci#define CHIPREG_READ32(addr) 		readl_relaxed(addr)
2208c2ecf20Sopenharmony_ci#define CHIPREG_READ32_dmasync(addr)	readl(addr)
2218c2ecf20Sopenharmony_ci#define CHIPREG_WRITE32(addr,val) 	writel(val, addr)
2228c2ecf20Sopenharmony_ci#define CHIPREG_PIO_WRITE32(addr,val)	outl(val, (unsigned long)addr)
2238c2ecf20Sopenharmony_ci#define CHIPREG_PIO_READ32(addr) 	inl((unsigned long)addr)
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic void
2268c2ecf20Sopenharmony_cipci_disable_io_access(struct pci_dev *pdev)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	u16 command_reg;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
2318c2ecf20Sopenharmony_ci	command_reg &= ~1;
2328c2ecf20Sopenharmony_ci	pci_write_config_word(pdev, PCI_COMMAND, command_reg);
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic void
2368c2ecf20Sopenharmony_cipci_enable_io_access(struct pci_dev *pdev)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	u16 command_reg;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
2418c2ecf20Sopenharmony_ci	command_reg |= 1;
2428c2ecf20Sopenharmony_ci	pci_write_config_word(pdev, PCI_COMMAND, command_reg);
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic int mpt_set_debug_level(const char *val, const struct kernel_param *kp)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	int ret = param_set_int(val, kp);
2488c2ecf20Sopenharmony_ci	MPT_ADAPTER *ioc;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (ret)
2518c2ecf20Sopenharmony_ci		return ret;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	list_for_each_entry(ioc, &ioc_list, list)
2548c2ecf20Sopenharmony_ci		ioc->debug_level = mpt_debug_level;
2558c2ecf20Sopenharmony_ci	return 0;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci/**
2598c2ecf20Sopenharmony_ci *	mpt_get_cb_idx - obtain cb_idx for registered driver
2608c2ecf20Sopenharmony_ci *	@dclass: class driver enum
2618c2ecf20Sopenharmony_ci *
2628c2ecf20Sopenharmony_ci *	Returns cb_idx, or zero means it wasn't found
2638c2ecf20Sopenharmony_ci **/
2648c2ecf20Sopenharmony_cistatic u8
2658c2ecf20Sopenharmony_cimpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	u8 cb_idx;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
2708c2ecf20Sopenharmony_ci		if (MptDriverClass[cb_idx] == dclass)
2718c2ecf20Sopenharmony_ci			return cb_idx;
2728c2ecf20Sopenharmony_ci	return 0;
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci/**
2768c2ecf20Sopenharmony_ci * mpt_is_discovery_complete - determine if discovery has completed
2778c2ecf20Sopenharmony_ci * @ioc: per adatper instance
2788c2ecf20Sopenharmony_ci *
2798c2ecf20Sopenharmony_ci * Returns 1 when discovery completed, else zero.
2808c2ecf20Sopenharmony_ci */
2818c2ecf20Sopenharmony_cistatic int
2828c2ecf20Sopenharmony_cimpt_is_discovery_complete(MPT_ADAPTER *ioc)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	ConfigExtendedPageHeader_t hdr;
2858c2ecf20Sopenharmony_ci	CONFIGPARMS cfg;
2868c2ecf20Sopenharmony_ci	SasIOUnitPage0_t *buffer;
2878c2ecf20Sopenharmony_ci	dma_addr_t dma_handle;
2888c2ecf20Sopenharmony_ci	int rc = 0;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2918c2ecf20Sopenharmony_ci	memset(&cfg, 0, sizeof(CONFIGPARMS));
2928c2ecf20Sopenharmony_ci	hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2938c2ecf20Sopenharmony_ci	hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2948c2ecf20Sopenharmony_ci	hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2958c2ecf20Sopenharmony_ci	cfg.cfghdr.ehdr = &hdr;
2968c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if ((mpt_config(ioc, &cfg)))
2998c2ecf20Sopenharmony_ci		goto out;
3008c2ecf20Sopenharmony_ci	if (!hdr.ExtPageLength)
3018c2ecf20Sopenharmony_ci		goto out;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
3048c2ecf20Sopenharmony_ci	    &dma_handle);
3058c2ecf20Sopenharmony_ci	if (!buffer)
3068c2ecf20Sopenharmony_ci		goto out;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	cfg.physAddr = dma_handle;
3098c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	if ((mpt_config(ioc, &cfg)))
3128c2ecf20Sopenharmony_ci		goto out_free_consistent;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (!(buffer->PhyData[0].PortFlags &
3158c2ecf20Sopenharmony_ci	    MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
3168c2ecf20Sopenharmony_ci		rc = 1;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci out_free_consistent:
3198c2ecf20Sopenharmony_ci	pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
3208c2ecf20Sopenharmony_ci	    buffer, dma_handle);
3218c2ecf20Sopenharmony_ci out:
3228c2ecf20Sopenharmony_ci	return rc;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci/**
3278c2ecf20Sopenharmony_ci *  mpt_remove_dead_ioc_func - kthread context to remove dead ioc
3288c2ecf20Sopenharmony_ci * @arg: input argument, used to derive ioc
3298c2ecf20Sopenharmony_ci *
3308c2ecf20Sopenharmony_ci * Return 0 if controller is removed from pci subsystem.
3318c2ecf20Sopenharmony_ci * Return -1 for other case.
3328c2ecf20Sopenharmony_ci */
3338c2ecf20Sopenharmony_cistatic int mpt_remove_dead_ioc_func(void *arg)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
3368c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	if (!ioc)
3398c2ecf20Sopenharmony_ci		return -1;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	pdev = ioc->pcidev;
3428c2ecf20Sopenharmony_ci	if (!pdev)
3438c2ecf20Sopenharmony_ci		return -1;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	pci_stop_and_remove_bus_device_locked(pdev);
3468c2ecf20Sopenharmony_ci	return 0;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci/**
3528c2ecf20Sopenharmony_ci *	mpt_fault_reset_work - work performed on workq after ioc fault
3538c2ecf20Sopenharmony_ci *	@work: input argument, used to derive ioc
3548c2ecf20Sopenharmony_ci *
3558c2ecf20Sopenharmony_ci**/
3568c2ecf20Sopenharmony_cistatic void
3578c2ecf20Sopenharmony_cimpt_fault_reset_work(struct work_struct *work)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	MPT_ADAPTER	*ioc =
3608c2ecf20Sopenharmony_ci	    container_of(work, MPT_ADAPTER, fault_reset_work.work);
3618c2ecf20Sopenharmony_ci	u32		 ioc_raw_state;
3628c2ecf20Sopenharmony_ci	int		 rc;
3638c2ecf20Sopenharmony_ci	unsigned long	 flags;
3648c2ecf20Sopenharmony_ci	MPT_SCSI_HOST	*hd;
3658c2ecf20Sopenharmony_ci	struct task_struct *p;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	if (ioc->ioc_reset_in_progress || !ioc->active)
3688c2ecf20Sopenharmony_ci		goto out;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	ioc_raw_state = mpt_GetIocState(ioc, 0);
3728c2ecf20Sopenharmony_ci	if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_MASK) {
3738c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "%s: IOC is non-operational !!!!\n",
3748c2ecf20Sopenharmony_ci		    ioc->name, __func__);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci		/*
3778c2ecf20Sopenharmony_ci		 * Call mptscsih_flush_pending_cmds callback so that we
3788c2ecf20Sopenharmony_ci		 * flush all pending commands back to OS.
3798c2ecf20Sopenharmony_ci		 * This call is required to aovid deadlock at block layer.
3808c2ecf20Sopenharmony_ci		 * Dead IOC will fail to do diag reset,and this call is safe
3818c2ecf20Sopenharmony_ci		 * since dead ioc will never return any command back from HW.
3828c2ecf20Sopenharmony_ci		 */
3838c2ecf20Sopenharmony_ci		hd = shost_priv(ioc->sh);
3848c2ecf20Sopenharmony_ci		ioc->schedule_dead_ioc_flush_running_cmds(hd);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci		/*Remove the Dead Host */
3878c2ecf20Sopenharmony_ci		p = kthread_run(mpt_remove_dead_ioc_func, ioc,
3888c2ecf20Sopenharmony_ci				"mpt_dead_ioc_%d", ioc->id);
3898c2ecf20Sopenharmony_ci		if (IS_ERR(p))	{
3908c2ecf20Sopenharmony_ci			printk(MYIOC_s_ERR_FMT
3918c2ecf20Sopenharmony_ci				"%s: Running mpt_dead_ioc thread failed !\n",
3928c2ecf20Sopenharmony_ci				ioc->name, __func__);
3938c2ecf20Sopenharmony_ci		} else {
3948c2ecf20Sopenharmony_ci			printk(MYIOC_s_WARN_FMT
3958c2ecf20Sopenharmony_ci				"%s: Running mpt_dead_ioc thread success !\n",
3968c2ecf20Sopenharmony_ci				ioc->name, __func__);
3978c2ecf20Sopenharmony_ci		}
3988c2ecf20Sopenharmony_ci		return; /* don't rearm timer */
3998c2ecf20Sopenharmony_ci	}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	if ((ioc_raw_state & MPI_IOC_STATE_MASK)
4028c2ecf20Sopenharmony_ci			== MPI_IOC_STATE_FAULT) {
4038c2ecf20Sopenharmony_ci		printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
4048c2ecf20Sopenharmony_ci		       ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
4058c2ecf20Sopenharmony_ci		printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
4068c2ecf20Sopenharmony_ci		       ioc->name, __func__);
4078c2ecf20Sopenharmony_ci		rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
4088c2ecf20Sopenharmony_ci		printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
4098c2ecf20Sopenharmony_ci		       __func__, (rc == 0) ? "success" : "failed");
4108c2ecf20Sopenharmony_ci		ioc_raw_state = mpt_GetIocState(ioc, 0);
4118c2ecf20Sopenharmony_ci		if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
4128c2ecf20Sopenharmony_ci			printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
4138c2ecf20Sopenharmony_ci			    "reset (%04xh)\n", ioc->name, ioc_raw_state &
4148c2ecf20Sopenharmony_ci			    MPI_DOORBELL_DATA_MASK);
4158c2ecf20Sopenharmony_ci	} else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
4168c2ecf20Sopenharmony_ci		if ((mpt_is_discovery_complete(ioc))) {
4178c2ecf20Sopenharmony_ci			devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
4188c2ecf20Sopenharmony_ci			    "discovery_quiesce_io flag\n", ioc->name));
4198c2ecf20Sopenharmony_ci			ioc->sas_discovery_quiesce_io = 0;
4208c2ecf20Sopenharmony_ci		}
4218c2ecf20Sopenharmony_ci	}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci out:
4248c2ecf20Sopenharmony_ci	/*
4258c2ecf20Sopenharmony_ci	 * Take turns polling alternate controller
4268c2ecf20Sopenharmony_ci	 */
4278c2ecf20Sopenharmony_ci	if (ioc->alt_ioc)
4288c2ecf20Sopenharmony_ci		ioc = ioc->alt_ioc;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	/* rearm the timer */
4318c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
4328c2ecf20Sopenharmony_ci	if (ioc->reset_work_q)
4338c2ecf20Sopenharmony_ci		queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
4348c2ecf20Sopenharmony_ci			msecs_to_jiffies(MPT_POLLING_INTERVAL));
4358c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci/*
4408c2ecf20Sopenharmony_ci *  Process turbo (context) reply...
4418c2ecf20Sopenharmony_ci */
4428c2ecf20Sopenharmony_cistatic void
4438c2ecf20Sopenharmony_cimpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	MPT_FRAME_HDR *mf = NULL;
4468c2ecf20Sopenharmony_ci	MPT_FRAME_HDR *mr = NULL;
4478c2ecf20Sopenharmony_ci	u16 req_idx = 0;
4488c2ecf20Sopenharmony_ci	u8 cb_idx;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
4518c2ecf20Sopenharmony_ci				ioc->name, pa));
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
4548c2ecf20Sopenharmony_ci	case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
4558c2ecf20Sopenharmony_ci		req_idx = pa & 0x0000FFFF;
4568c2ecf20Sopenharmony_ci		cb_idx = (pa & 0x00FF0000) >> 16;
4578c2ecf20Sopenharmony_ci		mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
4588c2ecf20Sopenharmony_ci		break;
4598c2ecf20Sopenharmony_ci	case MPI_CONTEXT_REPLY_TYPE_LAN:
4608c2ecf20Sopenharmony_ci		cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
4618c2ecf20Sopenharmony_ci		/*
4628c2ecf20Sopenharmony_ci		 *  Blind set of mf to NULL here was fatal
4638c2ecf20Sopenharmony_ci		 *  after lan_reply says "freeme"
4648c2ecf20Sopenharmony_ci		 *  Fix sort of combined with an optimization here;
4658c2ecf20Sopenharmony_ci		 *  added explicit check for case where lan_reply
4668c2ecf20Sopenharmony_ci		 *  was just returning 1 and doing nothing else.
4678c2ecf20Sopenharmony_ci		 *  For this case skip the callback, but set up
4688c2ecf20Sopenharmony_ci		 *  proper mf value first here:-)
4698c2ecf20Sopenharmony_ci		 */
4708c2ecf20Sopenharmony_ci		if ((pa & 0x58000000) == 0x58000000) {
4718c2ecf20Sopenharmony_ci			req_idx = pa & 0x0000FFFF;
4728c2ecf20Sopenharmony_ci			mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
4738c2ecf20Sopenharmony_ci			mpt_free_msg_frame(ioc, mf);
4748c2ecf20Sopenharmony_ci			mb();
4758c2ecf20Sopenharmony_ci			return;
4768c2ecf20Sopenharmony_ci			break;
4778c2ecf20Sopenharmony_ci		}
4788c2ecf20Sopenharmony_ci		mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
4798c2ecf20Sopenharmony_ci		break;
4808c2ecf20Sopenharmony_ci	case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
4818c2ecf20Sopenharmony_ci		cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
4828c2ecf20Sopenharmony_ci		mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
4838c2ecf20Sopenharmony_ci		break;
4848c2ecf20Sopenharmony_ci	default:
4858c2ecf20Sopenharmony_ci		cb_idx = 0;
4868c2ecf20Sopenharmony_ci		BUG();
4878c2ecf20Sopenharmony_ci	}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/*  Check for (valid) IO callback!  */
4908c2ecf20Sopenharmony_ci	if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
4918c2ecf20Sopenharmony_ci		MptCallbacks[cb_idx] == NULL) {
4928c2ecf20Sopenharmony_ci		printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
4938c2ecf20Sopenharmony_ci				__func__, ioc->name, cb_idx);
4948c2ecf20Sopenharmony_ci		goto out;
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	if (MptCallbacks[cb_idx](ioc, mf, mr))
4988c2ecf20Sopenharmony_ci		mpt_free_msg_frame(ioc, mf);
4998c2ecf20Sopenharmony_ci out:
5008c2ecf20Sopenharmony_ci	mb();
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_cistatic void
5048c2ecf20Sopenharmony_cimpt_reply(MPT_ADAPTER *ioc, u32 pa)
5058c2ecf20Sopenharmony_ci{
5068c2ecf20Sopenharmony_ci	MPT_FRAME_HDR	*mf;
5078c2ecf20Sopenharmony_ci	MPT_FRAME_HDR	*mr;
5088c2ecf20Sopenharmony_ci	u16		 req_idx;
5098c2ecf20Sopenharmony_ci	u8		 cb_idx;
5108c2ecf20Sopenharmony_ci	int		 freeme;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	u32 reply_dma_low;
5138c2ecf20Sopenharmony_ci	u16 ioc_stat;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	/* non-TURBO reply!  Hmmm, something may be up...
5168c2ecf20Sopenharmony_ci	 *  Newest turbo reply mechanism; get address
5178c2ecf20Sopenharmony_ci	 *  via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
5188c2ecf20Sopenharmony_ci	 */
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	/* Map DMA address of reply header to cpu address.
5218c2ecf20Sopenharmony_ci	 * pa is 32 bits - but the dma address may be 32 or 64 bits
5228c2ecf20Sopenharmony_ci	 * get offset based only only the low addresses
5238c2ecf20Sopenharmony_ci	 */
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	reply_dma_low = (pa <<= 1);
5268c2ecf20Sopenharmony_ci	mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
5278c2ecf20Sopenharmony_ci			 (reply_dma_low - ioc->reply_frames_low_dma));
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
5308c2ecf20Sopenharmony_ci	cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
5318c2ecf20Sopenharmony_ci	mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
5348c2ecf20Sopenharmony_ci			ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
5358c2ecf20Sopenharmony_ci	DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	 /*  Check/log IOC log info
5388c2ecf20Sopenharmony_ci	 */
5398c2ecf20Sopenharmony_ci	ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
5408c2ecf20Sopenharmony_ci	if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
5418c2ecf20Sopenharmony_ci		u32	 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
5428c2ecf20Sopenharmony_ci		if (ioc->bus_type == FC)
5438c2ecf20Sopenharmony_ci			mpt_fc_log_info(ioc, log_info);
5448c2ecf20Sopenharmony_ci		else if (ioc->bus_type == SPI)
5458c2ecf20Sopenharmony_ci			mpt_spi_log_info(ioc, log_info);
5468c2ecf20Sopenharmony_ci		else if (ioc->bus_type == SAS)
5478c2ecf20Sopenharmony_ci			mpt_sas_log_info(ioc, log_info, cb_idx);
5488c2ecf20Sopenharmony_ci	}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	if (ioc_stat & MPI_IOCSTATUS_MASK)
5518c2ecf20Sopenharmony_ci		mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	/*  Check for (valid) IO callback!  */
5548c2ecf20Sopenharmony_ci	if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
5558c2ecf20Sopenharmony_ci		MptCallbacks[cb_idx] == NULL) {
5568c2ecf20Sopenharmony_ci		printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
5578c2ecf20Sopenharmony_ci				__func__, ioc->name, cb_idx);
5588c2ecf20Sopenharmony_ci		freeme = 0;
5598c2ecf20Sopenharmony_ci		goto out;
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	freeme = MptCallbacks[cb_idx](ioc, mf, mr);
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci out:
5658c2ecf20Sopenharmony_ci	/*  Flush (non-TURBO) reply with a WRITE!  */
5668c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	if (freeme)
5698c2ecf20Sopenharmony_ci		mpt_free_msg_frame(ioc, mf);
5708c2ecf20Sopenharmony_ci	mb();
5718c2ecf20Sopenharmony_ci}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5748c2ecf20Sopenharmony_ci/**
5758c2ecf20Sopenharmony_ci *	mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
5768c2ecf20Sopenharmony_ci *	@irq: irq number (not used)
5778c2ecf20Sopenharmony_ci *	@bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
5788c2ecf20Sopenharmony_ci *
5798c2ecf20Sopenharmony_ci *	This routine is registered via the request_irq() kernel API call,
5808c2ecf20Sopenharmony_ci *	and handles all interrupts generated from a specific MPT adapter
5818c2ecf20Sopenharmony_ci *	(also referred to as a IO Controller or IOC).
5828c2ecf20Sopenharmony_ci *	This routine must clear the interrupt from the adapter and does
5838c2ecf20Sopenharmony_ci *	so by reading the reply FIFO.  Multiple replies may be processed
5848c2ecf20Sopenharmony_ci *	per single call to this routine.
5858c2ecf20Sopenharmony_ci *
5868c2ecf20Sopenharmony_ci *	This routine handles register-level access of the adapter but
5878c2ecf20Sopenharmony_ci *	dispatches (calls) a protocol-specific callback routine to handle
5888c2ecf20Sopenharmony_ci *	the protocol-specific details of the MPT request completion.
5898c2ecf20Sopenharmony_ci */
5908c2ecf20Sopenharmony_cistatic irqreturn_t
5918c2ecf20Sopenharmony_cimpt_interrupt(int irq, void *bus_id)
5928c2ecf20Sopenharmony_ci{
5938c2ecf20Sopenharmony_ci	MPT_ADAPTER *ioc = bus_id;
5948c2ecf20Sopenharmony_ci	u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	if (pa == 0xFFFFFFFF)
5978c2ecf20Sopenharmony_ci		return IRQ_NONE;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	/*
6008c2ecf20Sopenharmony_ci	 *  Drain the reply FIFO!
6018c2ecf20Sopenharmony_ci	 */
6028c2ecf20Sopenharmony_ci	do {
6038c2ecf20Sopenharmony_ci		if (pa & MPI_ADDRESS_REPLY_A_BIT)
6048c2ecf20Sopenharmony_ci			mpt_reply(ioc, pa);
6058c2ecf20Sopenharmony_ci		else
6068c2ecf20Sopenharmony_ci			mpt_turbo_reply(ioc, pa);
6078c2ecf20Sopenharmony_ci		pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
6088c2ecf20Sopenharmony_ci	} while (pa != 0xFFFFFFFF);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6148c2ecf20Sopenharmony_ci/**
6158c2ecf20Sopenharmony_ci *	mptbase_reply - MPT base driver's callback routine
6168c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
6178c2ecf20Sopenharmony_ci *	@req: Pointer to original MPT request frame
6188c2ecf20Sopenharmony_ci *	@reply: Pointer to MPT reply frame (NULL if TurboReply)
6198c2ecf20Sopenharmony_ci *
6208c2ecf20Sopenharmony_ci *	MPT base driver's callback routine; all base driver
6218c2ecf20Sopenharmony_ci *	"internal" request/reply processing is routed here.
6228c2ecf20Sopenharmony_ci *	Currently used for EventNotification and EventAck handling.
6238c2ecf20Sopenharmony_ci *
6248c2ecf20Sopenharmony_ci *	Returns 1 indicating original alloc'd request frame ptr
6258c2ecf20Sopenharmony_ci *	should be freed, or 0 if it shouldn't.
6268c2ecf20Sopenharmony_ci */
6278c2ecf20Sopenharmony_cistatic int
6288c2ecf20Sopenharmony_cimptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	EventNotificationReply_t *pEventReply;
6318c2ecf20Sopenharmony_ci	u8 event;
6328c2ecf20Sopenharmony_ci	int evHandlers;
6338c2ecf20Sopenharmony_ci	int freereq = 1;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	switch (reply->u.hdr.Function) {
6368c2ecf20Sopenharmony_ci	case MPI_FUNCTION_EVENT_NOTIFICATION:
6378c2ecf20Sopenharmony_ci		pEventReply = (EventNotificationReply_t *)reply;
6388c2ecf20Sopenharmony_ci		evHandlers = 0;
6398c2ecf20Sopenharmony_ci		ProcessEventNotification(ioc, pEventReply, &evHandlers);
6408c2ecf20Sopenharmony_ci		event = le32_to_cpu(pEventReply->Event) & 0xFF;
6418c2ecf20Sopenharmony_ci		if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
6428c2ecf20Sopenharmony_ci			freereq = 0;
6438c2ecf20Sopenharmony_ci		if (event != MPI_EVENT_EVENT_CHANGE)
6448c2ecf20Sopenharmony_ci			break;
6458c2ecf20Sopenharmony_ci		fallthrough;
6468c2ecf20Sopenharmony_ci	case MPI_FUNCTION_CONFIG:
6478c2ecf20Sopenharmony_ci	case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
6488c2ecf20Sopenharmony_ci		ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
6498c2ecf20Sopenharmony_ci		ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
6508c2ecf20Sopenharmony_ci		memcpy(ioc->mptbase_cmds.reply, reply,
6518c2ecf20Sopenharmony_ci		    min(MPT_DEFAULT_FRAME_SIZE,
6528c2ecf20Sopenharmony_ci			4 * reply->u.reply.MsgLength));
6538c2ecf20Sopenharmony_ci		if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6548c2ecf20Sopenharmony_ci			ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
6558c2ecf20Sopenharmony_ci			complete(&ioc->mptbase_cmds.done);
6568c2ecf20Sopenharmony_ci		} else
6578c2ecf20Sopenharmony_ci			freereq = 0;
6588c2ecf20Sopenharmony_ci		if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)
6598c2ecf20Sopenharmony_ci			freereq = 1;
6608c2ecf20Sopenharmony_ci		break;
6618c2ecf20Sopenharmony_ci	case MPI_FUNCTION_EVENT_ACK:
6628c2ecf20Sopenharmony_ci		devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6638c2ecf20Sopenharmony_ci		    "EventAck reply received\n", ioc->name));
6648c2ecf20Sopenharmony_ci		break;
6658c2ecf20Sopenharmony_ci	default:
6668c2ecf20Sopenharmony_ci		printk(MYIOC_s_ERR_FMT
6678c2ecf20Sopenharmony_ci		    "Unexpected msg function (=%02Xh) reply received!\n",
6688c2ecf20Sopenharmony_ci		    ioc->name, reply->u.hdr.Function);
6698c2ecf20Sopenharmony_ci		break;
6708c2ecf20Sopenharmony_ci	}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	/*
6738c2ecf20Sopenharmony_ci	 *	Conditionally tell caller to free the original
6748c2ecf20Sopenharmony_ci	 *	EventNotification/EventAck/unexpected request frame!
6758c2ecf20Sopenharmony_ci	 */
6768c2ecf20Sopenharmony_ci	return freereq;
6778c2ecf20Sopenharmony_ci}
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6808c2ecf20Sopenharmony_ci/**
6818c2ecf20Sopenharmony_ci *	mpt_register - Register protocol-specific main callback handler.
6828c2ecf20Sopenharmony_ci *	@cbfunc: callback function pointer
6838c2ecf20Sopenharmony_ci *	@dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
6848c2ecf20Sopenharmony_ci *	@func_name: call function's name
6858c2ecf20Sopenharmony_ci *
6868c2ecf20Sopenharmony_ci *	This routine is called by a protocol-specific driver (SCSI host,
6878c2ecf20Sopenharmony_ci *	LAN, SCSI target) to register its reply callback routine.  Each
6888c2ecf20Sopenharmony_ci *	protocol-specific driver must do this before it will be able to
6898c2ecf20Sopenharmony_ci *	use any IOC resources, such as obtaining request frames.
6908c2ecf20Sopenharmony_ci *
6918c2ecf20Sopenharmony_ci *	NOTES: The SCSI protocol driver currently calls this routine thrice
6928c2ecf20Sopenharmony_ci *	in order to register separate callbacks; one for "normal" SCSI IO;
6938c2ecf20Sopenharmony_ci *	one for MptScsiTaskMgmt requests; one for Scan/DV requests.
6948c2ecf20Sopenharmony_ci *
6958c2ecf20Sopenharmony_ci *	Returns u8 valued "handle" in the range (and S.O.D. order)
6968c2ecf20Sopenharmony_ci *	{N,...,7,6,5,...,1} if successful.
6978c2ecf20Sopenharmony_ci *	A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
6988c2ecf20Sopenharmony_ci *	considered an error by the caller.
6998c2ecf20Sopenharmony_ci */
7008c2ecf20Sopenharmony_ciu8
7018c2ecf20Sopenharmony_cimpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name)
7028c2ecf20Sopenharmony_ci{
7038c2ecf20Sopenharmony_ci	u8 cb_idx;
7048c2ecf20Sopenharmony_ci	last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	/*
7078c2ecf20Sopenharmony_ci	 *  Search for empty callback slot in this order: {N,...,7,6,5,...,1}
7088c2ecf20Sopenharmony_ci	 *  (slot/handle 0 is reserved!)
7098c2ecf20Sopenharmony_ci	 */
7108c2ecf20Sopenharmony_ci	for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7118c2ecf20Sopenharmony_ci		if (MptCallbacks[cb_idx] == NULL) {
7128c2ecf20Sopenharmony_ci			MptCallbacks[cb_idx] = cbfunc;
7138c2ecf20Sopenharmony_ci			MptDriverClass[cb_idx] = dclass;
7148c2ecf20Sopenharmony_ci			MptEvHandlers[cb_idx] = NULL;
7158c2ecf20Sopenharmony_ci			last_drv_idx = cb_idx;
7168c2ecf20Sopenharmony_ci			strlcpy(MptCallbacksName[cb_idx], func_name,
7178c2ecf20Sopenharmony_ci				MPT_MAX_CALLBACKNAME_LEN+1);
7188c2ecf20Sopenharmony_ci			break;
7198c2ecf20Sopenharmony_ci		}
7208c2ecf20Sopenharmony_ci	}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	return last_drv_idx;
7238c2ecf20Sopenharmony_ci}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7268c2ecf20Sopenharmony_ci/**
7278c2ecf20Sopenharmony_ci *	mpt_deregister - Deregister a protocol drivers resources.
7288c2ecf20Sopenharmony_ci *	@cb_idx: previously registered callback handle
7298c2ecf20Sopenharmony_ci *
7308c2ecf20Sopenharmony_ci *	Each protocol-specific driver should call this routine when its
7318c2ecf20Sopenharmony_ci *	module is unloaded.
7328c2ecf20Sopenharmony_ci */
7338c2ecf20Sopenharmony_civoid
7348c2ecf20Sopenharmony_cimpt_deregister(u8 cb_idx)
7358c2ecf20Sopenharmony_ci{
7368c2ecf20Sopenharmony_ci	if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
7378c2ecf20Sopenharmony_ci		MptCallbacks[cb_idx] = NULL;
7388c2ecf20Sopenharmony_ci		MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7398c2ecf20Sopenharmony_ci		MptEvHandlers[cb_idx] = NULL;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci		last_drv_idx++;
7428c2ecf20Sopenharmony_ci	}
7438c2ecf20Sopenharmony_ci}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7468c2ecf20Sopenharmony_ci/**
7478c2ecf20Sopenharmony_ci *	mpt_event_register - Register protocol-specific event callback handler.
7488c2ecf20Sopenharmony_ci *	@cb_idx: previously registered (via mpt_register) callback handle
7498c2ecf20Sopenharmony_ci *	@ev_cbfunc: callback function
7508c2ecf20Sopenharmony_ci *
7518c2ecf20Sopenharmony_ci *	This routine can be called by one or more protocol-specific drivers
7528c2ecf20Sopenharmony_ci *	if/when they choose to be notified of MPT events.
7538c2ecf20Sopenharmony_ci *
7548c2ecf20Sopenharmony_ci *	Returns 0 for success.
7558c2ecf20Sopenharmony_ci */
7568c2ecf20Sopenharmony_ciint
7578c2ecf20Sopenharmony_cimpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
7588c2ecf20Sopenharmony_ci{
7598c2ecf20Sopenharmony_ci	if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
7608c2ecf20Sopenharmony_ci		return -1;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	MptEvHandlers[cb_idx] = ev_cbfunc;
7638c2ecf20Sopenharmony_ci	return 0;
7648c2ecf20Sopenharmony_ci}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7678c2ecf20Sopenharmony_ci/**
7688c2ecf20Sopenharmony_ci *	mpt_event_deregister - Deregister protocol-specific event callback handler
7698c2ecf20Sopenharmony_ci *	@cb_idx: previously registered callback handle
7708c2ecf20Sopenharmony_ci *
7718c2ecf20Sopenharmony_ci *	Each protocol-specific driver should call this routine
7728c2ecf20Sopenharmony_ci *	when it does not (or can no longer) handle events,
7738c2ecf20Sopenharmony_ci *	or when its module is unloaded.
7748c2ecf20Sopenharmony_ci */
7758c2ecf20Sopenharmony_civoid
7768c2ecf20Sopenharmony_cimpt_event_deregister(u8 cb_idx)
7778c2ecf20Sopenharmony_ci{
7788c2ecf20Sopenharmony_ci	if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
7798c2ecf20Sopenharmony_ci		return;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	MptEvHandlers[cb_idx] = NULL;
7828c2ecf20Sopenharmony_ci}
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7858c2ecf20Sopenharmony_ci/**
7868c2ecf20Sopenharmony_ci *	mpt_reset_register - Register protocol-specific IOC reset handler.
7878c2ecf20Sopenharmony_ci *	@cb_idx: previously registered (via mpt_register) callback handle
7888c2ecf20Sopenharmony_ci *	@reset_func: reset function
7898c2ecf20Sopenharmony_ci *
7908c2ecf20Sopenharmony_ci *	This routine can be called by one or more protocol-specific drivers
7918c2ecf20Sopenharmony_ci *	if/when they choose to be notified of IOC resets.
7928c2ecf20Sopenharmony_ci *
7938c2ecf20Sopenharmony_ci *	Returns 0 for success.
7948c2ecf20Sopenharmony_ci */
7958c2ecf20Sopenharmony_ciint
7968c2ecf20Sopenharmony_cimpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
7978c2ecf20Sopenharmony_ci{
7988c2ecf20Sopenharmony_ci	if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
7998c2ecf20Sopenharmony_ci		return -1;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	MptResetHandlers[cb_idx] = reset_func;
8028c2ecf20Sopenharmony_ci	return 0;
8038c2ecf20Sopenharmony_ci}
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
8068c2ecf20Sopenharmony_ci/**
8078c2ecf20Sopenharmony_ci *	mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
8088c2ecf20Sopenharmony_ci *	@cb_idx: previously registered callback handle
8098c2ecf20Sopenharmony_ci *
8108c2ecf20Sopenharmony_ci *	Each protocol-specific driver should call this routine
8118c2ecf20Sopenharmony_ci *	when it does not (or can no longer) handle IOC reset handling,
8128c2ecf20Sopenharmony_ci *	or when its module is unloaded.
8138c2ecf20Sopenharmony_ci */
8148c2ecf20Sopenharmony_civoid
8158c2ecf20Sopenharmony_cimpt_reset_deregister(u8 cb_idx)
8168c2ecf20Sopenharmony_ci{
8178c2ecf20Sopenharmony_ci	if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
8188c2ecf20Sopenharmony_ci		return;
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	MptResetHandlers[cb_idx] = NULL;
8218c2ecf20Sopenharmony_ci}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
8248c2ecf20Sopenharmony_ci/**
8258c2ecf20Sopenharmony_ci *	mpt_device_driver_register - Register device driver hooks
8268c2ecf20Sopenharmony_ci *	@dd_cbfunc: driver callbacks struct
8278c2ecf20Sopenharmony_ci *	@cb_idx: MPT protocol driver index
8288c2ecf20Sopenharmony_ci */
8298c2ecf20Sopenharmony_ciint
8308c2ecf20Sopenharmony_cimpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
8318c2ecf20Sopenharmony_ci{
8328c2ecf20Sopenharmony_ci	MPT_ADAPTER	*ioc;
8338c2ecf20Sopenharmony_ci	const struct pci_device_id *id;
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
8368c2ecf20Sopenharmony_ci		return -EINVAL;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	/* call per pci device probe entry point */
8418c2ecf20Sopenharmony_ci	list_for_each_entry(ioc, &ioc_list, list) {
8428c2ecf20Sopenharmony_ci		id = ioc->pcidev->driver ?
8438c2ecf20Sopenharmony_ci		    ioc->pcidev->driver->id_table : NULL;
8448c2ecf20Sopenharmony_ci		if (dd_cbfunc->probe)
8458c2ecf20Sopenharmony_ci			dd_cbfunc->probe(ioc->pcidev, id);
8468c2ecf20Sopenharmony_ci	 }
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	return 0;
8498c2ecf20Sopenharmony_ci}
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
8528c2ecf20Sopenharmony_ci/**
8538c2ecf20Sopenharmony_ci *	mpt_device_driver_deregister - DeRegister device driver hooks
8548c2ecf20Sopenharmony_ci *	@cb_idx: MPT protocol driver index
8558c2ecf20Sopenharmony_ci */
8568c2ecf20Sopenharmony_civoid
8578c2ecf20Sopenharmony_cimpt_device_driver_deregister(u8 cb_idx)
8588c2ecf20Sopenharmony_ci{
8598c2ecf20Sopenharmony_ci	struct mpt_pci_driver *dd_cbfunc;
8608c2ecf20Sopenharmony_ci	MPT_ADAPTER	*ioc;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
8638c2ecf20Sopenharmony_ci		return;
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	list_for_each_entry(ioc, &ioc_list, list) {
8688c2ecf20Sopenharmony_ci		if (dd_cbfunc->remove)
8698c2ecf20Sopenharmony_ci			dd_cbfunc->remove(ioc->pcidev);
8708c2ecf20Sopenharmony_ci	}
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	MptDeviceDriverHandlers[cb_idx] = NULL;
8738c2ecf20Sopenharmony_ci}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
8778c2ecf20Sopenharmony_ci/**
8788c2ecf20Sopenharmony_ci *	mpt_get_msg_frame - Obtain an MPT request frame from the pool
8798c2ecf20Sopenharmony_ci *	@cb_idx: Handle of registered MPT protocol driver
8808c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT adapter structure
8818c2ecf20Sopenharmony_ci *
8828c2ecf20Sopenharmony_ci *	Obtain an MPT request frame from the pool (of 1024) that are
8838c2ecf20Sopenharmony_ci *	allocated per MPT adapter.
8848c2ecf20Sopenharmony_ci *
8858c2ecf20Sopenharmony_ci *	Returns pointer to a MPT request frame or %NULL if none are available
8868c2ecf20Sopenharmony_ci *	or IOC is not active.
8878c2ecf20Sopenharmony_ci */
8888c2ecf20Sopenharmony_ciMPT_FRAME_HDR*
8898c2ecf20Sopenharmony_cimpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
8908c2ecf20Sopenharmony_ci{
8918c2ecf20Sopenharmony_ci	MPT_FRAME_HDR *mf;
8928c2ecf20Sopenharmony_ci	unsigned long flags;
8938c2ecf20Sopenharmony_ci	u16	 req_idx;	/* Request index */
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	/* validate handle and ioc identifier */
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci#ifdef MFCNT
8988c2ecf20Sopenharmony_ci	if (!ioc->active)
8998c2ecf20Sopenharmony_ci		printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
9008c2ecf20Sopenharmony_ci		    "returning NULL!\n", ioc->name);
9018c2ecf20Sopenharmony_ci#endif
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	/* If interrupts are not attached, do not return a request frame */
9048c2ecf20Sopenharmony_ci	if (!ioc->active)
9058c2ecf20Sopenharmony_ci		return NULL;
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->FreeQlock, flags);
9088c2ecf20Sopenharmony_ci	if (!list_empty(&ioc->FreeQ)) {
9098c2ecf20Sopenharmony_ci		int req_offset;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci		mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
9128c2ecf20Sopenharmony_ci				u.frame.linkage.list);
9138c2ecf20Sopenharmony_ci		list_del(&mf->u.frame.linkage.list);
9148c2ecf20Sopenharmony_ci		mf->u.frame.linkage.arg1 = 0;
9158c2ecf20Sopenharmony_ci		mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;	/* byte */
9168c2ecf20Sopenharmony_ci		req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
9178c2ecf20Sopenharmony_ci								/* u16! */
9188c2ecf20Sopenharmony_ci		req_idx = req_offset / ioc->req_sz;
9198c2ecf20Sopenharmony_ci		mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
9208c2ecf20Sopenharmony_ci		mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
9218c2ecf20Sopenharmony_ci		/* Default, will be changed if necessary in SG generation */
9228c2ecf20Sopenharmony_ci		ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
9238c2ecf20Sopenharmony_ci#ifdef MFCNT
9248c2ecf20Sopenharmony_ci		ioc->mfcnt++;
9258c2ecf20Sopenharmony_ci#endif
9268c2ecf20Sopenharmony_ci	}
9278c2ecf20Sopenharmony_ci	else
9288c2ecf20Sopenharmony_ci		mf = NULL;
9298c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci#ifdef MFCNT
9328c2ecf20Sopenharmony_ci	if (mf == NULL)
9338c2ecf20Sopenharmony_ci		printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
9348c2ecf20Sopenharmony_ci		    "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
9358c2ecf20Sopenharmony_ci		    ioc->req_depth);
9368c2ecf20Sopenharmony_ci	mfcounter++;
9378c2ecf20Sopenharmony_ci	if (mfcounter == PRINT_MF_COUNT)
9388c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
9398c2ecf20Sopenharmony_ci		    ioc->mfcnt, ioc->req_depth);
9408c2ecf20Sopenharmony_ci#endif
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
9438c2ecf20Sopenharmony_ci	    ioc->name, cb_idx, ioc->id, mf));
9448c2ecf20Sopenharmony_ci	return mf;
9458c2ecf20Sopenharmony_ci}
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
9488c2ecf20Sopenharmony_ci/**
9498c2ecf20Sopenharmony_ci *	mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
9508c2ecf20Sopenharmony_ci *	@cb_idx: Handle of registered MPT protocol driver
9518c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT adapter structure
9528c2ecf20Sopenharmony_ci *	@mf: Pointer to MPT request frame
9538c2ecf20Sopenharmony_ci *
9548c2ecf20Sopenharmony_ci *	This routine posts an MPT request frame to the request post FIFO of a
9558c2ecf20Sopenharmony_ci *	specific MPT adapter.
9568c2ecf20Sopenharmony_ci */
9578c2ecf20Sopenharmony_civoid
9588c2ecf20Sopenharmony_cimpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
9598c2ecf20Sopenharmony_ci{
9608c2ecf20Sopenharmony_ci	u32 mf_dma_addr;
9618c2ecf20Sopenharmony_ci	int req_offset;
9628c2ecf20Sopenharmony_ci	u16 req_idx;	/* Request index */
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	/* ensure values are reset properly! */
9658c2ecf20Sopenharmony_ci	mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;		/* byte */
9668c2ecf20Sopenharmony_ci	req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
9678c2ecf20Sopenharmony_ci								/* u16! */
9688c2ecf20Sopenharmony_ci	req_idx = req_offset / ioc->req_sz;
9698c2ecf20Sopenharmony_ci	mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
9708c2ecf20Sopenharmony_ci	mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
9758c2ecf20Sopenharmony_ci	dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
9768c2ecf20Sopenharmony_ci	    "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
9778c2ecf20Sopenharmony_ci	    ioc->RequestNB[req_idx]));
9788c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
9798c2ecf20Sopenharmony_ci}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci/**
9828c2ecf20Sopenharmony_ci *	mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
9838c2ecf20Sopenharmony_ci *	@cb_idx: Handle of registered MPT protocol driver
9848c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT adapter structure
9858c2ecf20Sopenharmony_ci *	@mf: Pointer to MPT request frame
9868c2ecf20Sopenharmony_ci *
9878c2ecf20Sopenharmony_ci *	Send a protocol-specific MPT request frame to an IOC using
9888c2ecf20Sopenharmony_ci *	hi-priority request queue.
9898c2ecf20Sopenharmony_ci *
9908c2ecf20Sopenharmony_ci *	This routine posts an MPT request frame to the request post FIFO of a
9918c2ecf20Sopenharmony_ci *	specific MPT adapter.
9928c2ecf20Sopenharmony_ci **/
9938c2ecf20Sopenharmony_civoid
9948c2ecf20Sopenharmony_cimpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
9958c2ecf20Sopenharmony_ci{
9968c2ecf20Sopenharmony_ci	u32 mf_dma_addr;
9978c2ecf20Sopenharmony_ci	int req_offset;
9988c2ecf20Sopenharmony_ci	u16 req_idx;	/* Request index */
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	/* ensure values are reset properly! */
10018c2ecf20Sopenharmony_ci	mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
10028c2ecf20Sopenharmony_ci	req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
10038c2ecf20Sopenharmony_ci	req_idx = req_offset / ioc->req_sz;
10048c2ecf20Sopenharmony_ci	mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
10058c2ecf20Sopenharmony_ci	mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
10108c2ecf20Sopenharmony_ci	dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
10118c2ecf20Sopenharmony_ci		ioc->name, mf_dma_addr, req_idx));
10128c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
10138c2ecf20Sopenharmony_ci}
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
10168c2ecf20Sopenharmony_ci/**
10178c2ecf20Sopenharmony_ci *	mpt_free_msg_frame - Place MPT request frame back on FreeQ.
10188c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT adapter structure
10198c2ecf20Sopenharmony_ci *	@mf: Pointer to MPT request frame
10208c2ecf20Sopenharmony_ci *
10218c2ecf20Sopenharmony_ci *	This routine places a MPT request frame back on the MPT adapter's
10228c2ecf20Sopenharmony_ci *	FreeQ.
10238c2ecf20Sopenharmony_ci */
10248c2ecf20Sopenharmony_civoid
10258c2ecf20Sopenharmony_cimpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
10268c2ecf20Sopenharmony_ci{
10278c2ecf20Sopenharmony_ci	unsigned long flags;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	/*  Put Request back on FreeQ!  */
10308c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->FreeQlock, flags);
10318c2ecf20Sopenharmony_ci	if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf)
10328c2ecf20Sopenharmony_ci		goto out;
10338c2ecf20Sopenharmony_ci	/* signature to know if this mf is freed */
10348c2ecf20Sopenharmony_ci	mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf);
10358c2ecf20Sopenharmony_ci	list_add(&mf->u.frame.linkage.list, &ioc->FreeQ);
10368c2ecf20Sopenharmony_ci#ifdef MFCNT
10378c2ecf20Sopenharmony_ci	ioc->mfcnt--;
10388c2ecf20Sopenharmony_ci#endif
10398c2ecf20Sopenharmony_ci out:
10408c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
10418c2ecf20Sopenharmony_ci}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
10448c2ecf20Sopenharmony_ci/**
10458c2ecf20Sopenharmony_ci *	mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
10468c2ecf20Sopenharmony_ci *	@pAddr: virtual address for SGE
10478c2ecf20Sopenharmony_ci *	@flagslength: SGE flags and data transfer length
10488c2ecf20Sopenharmony_ci *	@dma_addr: Physical address
10498c2ecf20Sopenharmony_ci *
10508c2ecf20Sopenharmony_ci *	This routine places a MPT request frame back on the MPT adapter's
10518c2ecf20Sopenharmony_ci *	FreeQ.
10528c2ecf20Sopenharmony_ci */
10538c2ecf20Sopenharmony_cistatic void
10548c2ecf20Sopenharmony_cimpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
10558c2ecf20Sopenharmony_ci{
10568c2ecf20Sopenharmony_ci	SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
10578c2ecf20Sopenharmony_ci	pSge->FlagsLength = cpu_to_le32(flagslength);
10588c2ecf20Sopenharmony_ci	pSge->Address = cpu_to_le32(dma_addr);
10598c2ecf20Sopenharmony_ci}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci/**
10628c2ecf20Sopenharmony_ci *	mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
10638c2ecf20Sopenharmony_ci *	@pAddr: virtual address for SGE
10648c2ecf20Sopenharmony_ci *	@flagslength: SGE flags and data transfer length
10658c2ecf20Sopenharmony_ci *	@dma_addr: Physical address
10668c2ecf20Sopenharmony_ci *
10678c2ecf20Sopenharmony_ci *	This routine places a MPT request frame back on the MPT adapter's
10688c2ecf20Sopenharmony_ci *	FreeQ.
10698c2ecf20Sopenharmony_ci **/
10708c2ecf20Sopenharmony_cistatic void
10718c2ecf20Sopenharmony_cimpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
10728c2ecf20Sopenharmony_ci{
10738c2ecf20Sopenharmony_ci	SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
10748c2ecf20Sopenharmony_ci	pSge->Address.Low = cpu_to_le32
10758c2ecf20Sopenharmony_ci			(lower_32_bits(dma_addr));
10768c2ecf20Sopenharmony_ci	pSge->Address.High = cpu_to_le32
10778c2ecf20Sopenharmony_ci			(upper_32_bits(dma_addr));
10788c2ecf20Sopenharmony_ci	pSge->FlagsLength = cpu_to_le32
10798c2ecf20Sopenharmony_ci			((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
10808c2ecf20Sopenharmony_ci}
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci/**
10838c2ecf20Sopenharmony_ci *	mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround).
10848c2ecf20Sopenharmony_ci *	@pAddr: virtual address for SGE
10858c2ecf20Sopenharmony_ci *	@flagslength: SGE flags and data transfer length
10868c2ecf20Sopenharmony_ci *	@dma_addr: Physical address
10878c2ecf20Sopenharmony_ci *
10888c2ecf20Sopenharmony_ci *	This routine places a MPT request frame back on the MPT adapter's
10898c2ecf20Sopenharmony_ci *	FreeQ.
10908c2ecf20Sopenharmony_ci **/
10918c2ecf20Sopenharmony_cistatic void
10928c2ecf20Sopenharmony_cimpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
10938c2ecf20Sopenharmony_ci{
10948c2ecf20Sopenharmony_ci	SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
10958c2ecf20Sopenharmony_ci	u32 tmp;
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	pSge->Address.Low = cpu_to_le32
10988c2ecf20Sopenharmony_ci			(lower_32_bits(dma_addr));
10998c2ecf20Sopenharmony_ci	tmp = (u32)(upper_32_bits(dma_addr));
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	/*
11028c2ecf20Sopenharmony_ci	 * 1078 errata workaround for the 36GB limitation
11038c2ecf20Sopenharmony_ci	 */
11048c2ecf20Sopenharmony_ci	if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32)  == 9) {
11058c2ecf20Sopenharmony_ci		flagslength |=
11068c2ecf20Sopenharmony_ci		    MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
11078c2ecf20Sopenharmony_ci		tmp |= (1<<31);
11088c2ecf20Sopenharmony_ci		if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
11098c2ecf20Sopenharmony_ci			printk(KERN_DEBUG "1078 P0M2 addressing for "
11108c2ecf20Sopenharmony_ci			    "addr = 0x%llx len = %d\n",
11118c2ecf20Sopenharmony_ci			    (unsigned long long)dma_addr,
11128c2ecf20Sopenharmony_ci			    MPI_SGE_LENGTH(flagslength));
11138c2ecf20Sopenharmony_ci	}
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	pSge->Address.High = cpu_to_le32(tmp);
11168c2ecf20Sopenharmony_ci	pSge->FlagsLength = cpu_to_le32(
11178c2ecf20Sopenharmony_ci		(flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
11188c2ecf20Sopenharmony_ci}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11218c2ecf20Sopenharmony_ci/**
11228c2ecf20Sopenharmony_ci *	mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
11238c2ecf20Sopenharmony_ci *	@pAddr: virtual address for SGE
11248c2ecf20Sopenharmony_ci *	@next: nextChainOffset value (u32's)
11258c2ecf20Sopenharmony_ci *	@length: length of next SGL segment
11268c2ecf20Sopenharmony_ci *	@dma_addr: Physical address
11278c2ecf20Sopenharmony_ci *
11288c2ecf20Sopenharmony_ci */
11298c2ecf20Sopenharmony_cistatic void
11308c2ecf20Sopenharmony_cimpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
11318c2ecf20Sopenharmony_ci{
11328c2ecf20Sopenharmony_ci	SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	pChain->Length = cpu_to_le16(length);
11358c2ecf20Sopenharmony_ci	pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
11368c2ecf20Sopenharmony_ci	pChain->NextChainOffset = next;
11378c2ecf20Sopenharmony_ci	pChain->Address = cpu_to_le32(dma_addr);
11388c2ecf20Sopenharmony_ci}
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11418c2ecf20Sopenharmony_ci/**
11428c2ecf20Sopenharmony_ci *	mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
11438c2ecf20Sopenharmony_ci *	@pAddr: virtual address for SGE
11448c2ecf20Sopenharmony_ci *	@next: nextChainOffset value (u32's)
11458c2ecf20Sopenharmony_ci *	@length: length of next SGL segment
11468c2ecf20Sopenharmony_ci *	@dma_addr: Physical address
11478c2ecf20Sopenharmony_ci *
11488c2ecf20Sopenharmony_ci */
11498c2ecf20Sopenharmony_cistatic void
11508c2ecf20Sopenharmony_cimpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
11518c2ecf20Sopenharmony_ci{
11528c2ecf20Sopenharmony_ci	SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
11538c2ecf20Sopenharmony_ci	u32 tmp = dma_addr & 0xFFFFFFFF;
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci	pChain->Length = cpu_to_le16(length);
11568c2ecf20Sopenharmony_ci	pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
11578c2ecf20Sopenharmony_ci			 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	pChain->NextChainOffset = next;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	pChain->Address.Low = cpu_to_le32(tmp);
11628c2ecf20Sopenharmony_ci	tmp = (u32)(upper_32_bits(dma_addr));
11638c2ecf20Sopenharmony_ci	pChain->Address.High = cpu_to_le32(tmp);
11648c2ecf20Sopenharmony_ci}
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11678c2ecf20Sopenharmony_ci/**
11688c2ecf20Sopenharmony_ci *	mpt_send_handshake_request - Send MPT request via doorbell handshake method.
11698c2ecf20Sopenharmony_ci *	@cb_idx: Handle of registered MPT protocol driver
11708c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT adapter structure
11718c2ecf20Sopenharmony_ci *	@reqBytes: Size of the request in bytes
11728c2ecf20Sopenharmony_ci *	@req: Pointer to MPT request frame
11738c2ecf20Sopenharmony_ci *	@sleepFlag: Use schedule if CAN_SLEEP else use udelay.
11748c2ecf20Sopenharmony_ci *
11758c2ecf20Sopenharmony_ci *	This routine is used exclusively to send MptScsiTaskMgmt
11768c2ecf20Sopenharmony_ci *	requests since they are required to be sent via doorbell handshake.
11778c2ecf20Sopenharmony_ci *
11788c2ecf20Sopenharmony_ci *	NOTE: It is the callers responsibility to byte-swap fields in the
11798c2ecf20Sopenharmony_ci *	request which are greater than 1 byte in size.
11808c2ecf20Sopenharmony_ci *
11818c2ecf20Sopenharmony_ci *	Returns 0 for success, non-zero for failure.
11828c2ecf20Sopenharmony_ci */
11838c2ecf20Sopenharmony_ciint
11848c2ecf20Sopenharmony_cimpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
11858c2ecf20Sopenharmony_ci{
11868c2ecf20Sopenharmony_ci	int	r = 0;
11878c2ecf20Sopenharmony_ci	u8	*req_as_bytes;
11888c2ecf20Sopenharmony_ci	int	 ii;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	/* State is known to be good upon entering
11918c2ecf20Sopenharmony_ci	 * this function so issue the bus reset
11928c2ecf20Sopenharmony_ci	 * request.
11938c2ecf20Sopenharmony_ci	 */
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	/*
11968c2ecf20Sopenharmony_ci	 * Emulate what mpt_put_msg_frame() does /wrt to sanity
11978c2ecf20Sopenharmony_ci	 * setting cb_idx/req_idx.  But ONLY if this request
11988c2ecf20Sopenharmony_ci	 * is in proper (pre-alloc'd) request buffer range...
11998c2ecf20Sopenharmony_ci	 */
12008c2ecf20Sopenharmony_ci	ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
12018c2ecf20Sopenharmony_ci	if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
12028c2ecf20Sopenharmony_ci		MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
12038c2ecf20Sopenharmony_ci		mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
12048c2ecf20Sopenharmony_ci		mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
12058c2ecf20Sopenharmony_ci	}
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	/* Make sure there are no doorbells */
12088c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->Doorbell,
12118c2ecf20Sopenharmony_ci			((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
12128c2ecf20Sopenharmony_ci			 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	/* Wait for IOC doorbell int */
12158c2ecf20Sopenharmony_ci	if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
12168c2ecf20Sopenharmony_ci		return ii;
12178c2ecf20Sopenharmony_ci	}
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	/* Read doorbell and check for active bit */
12208c2ecf20Sopenharmony_ci	if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
12218c2ecf20Sopenharmony_ci		return -5;
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
12248c2ecf20Sopenharmony_ci		ioc->name, ii));
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
12298c2ecf20Sopenharmony_ci		return -2;
12308c2ecf20Sopenharmony_ci	}
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	/* Send request via doorbell handshake */
12338c2ecf20Sopenharmony_ci	req_as_bytes = (u8 *) req;
12348c2ecf20Sopenharmony_ci	for (ii = 0; ii < reqBytes/4; ii++) {
12358c2ecf20Sopenharmony_ci		u32 word;
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci		word = ((req_as_bytes[(ii*4) + 0] <<  0) |
12388c2ecf20Sopenharmony_ci			(req_as_bytes[(ii*4) + 1] <<  8) |
12398c2ecf20Sopenharmony_ci			(req_as_bytes[(ii*4) + 2] << 16) |
12408c2ecf20Sopenharmony_ci			(req_as_bytes[(ii*4) + 3] << 24));
12418c2ecf20Sopenharmony_ci		CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
12428c2ecf20Sopenharmony_ci		if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
12438c2ecf20Sopenharmony_ci			r = -3;
12448c2ecf20Sopenharmony_ci			break;
12458c2ecf20Sopenharmony_ci		}
12468c2ecf20Sopenharmony_ci	}
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
12498c2ecf20Sopenharmony_ci		r = 0;
12508c2ecf20Sopenharmony_ci	else
12518c2ecf20Sopenharmony_ci		r = -4;
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	/* Make sure there are no doorbells */
12548c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	return r;
12578c2ecf20Sopenharmony_ci}
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
12608c2ecf20Sopenharmony_ci/**
12618c2ecf20Sopenharmony_ci * mpt_host_page_access_control - control the IOC's Host Page Buffer access
12628c2ecf20Sopenharmony_ci * @ioc: Pointer to MPT adapter structure
12638c2ecf20Sopenharmony_ci * @access_control_value: define bits below
12648c2ecf20Sopenharmony_ci * @sleepFlag: Specifies whether the process can sleep
12658c2ecf20Sopenharmony_ci *
12668c2ecf20Sopenharmony_ci * Provides mechanism for the host driver to control the IOC's
12678c2ecf20Sopenharmony_ci * Host Page Buffer access.
12688c2ecf20Sopenharmony_ci *
12698c2ecf20Sopenharmony_ci * Access Control Value - bits[15:12]
12708c2ecf20Sopenharmony_ci * 0h Reserved
12718c2ecf20Sopenharmony_ci * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
12728c2ecf20Sopenharmony_ci * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
12738c2ecf20Sopenharmony_ci * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
12748c2ecf20Sopenharmony_ci *
12758c2ecf20Sopenharmony_ci * Returns 0 for success, non-zero for failure.
12768c2ecf20Sopenharmony_ci */
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_cistatic int
12798c2ecf20Sopenharmony_cimpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
12808c2ecf20Sopenharmony_ci{
12818c2ecf20Sopenharmony_ci	int	 r = 0;
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	/* return if in use */
12848c2ecf20Sopenharmony_ci	if (CHIPREG_READ32(&ioc->chip->Doorbell)
12858c2ecf20Sopenharmony_ci	    & MPI_DOORBELL_ACTIVE)
12868c2ecf20Sopenharmony_ci	    return -1;
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->Doorbell,
12918c2ecf20Sopenharmony_ci		((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
12928c2ecf20Sopenharmony_ci		 <<MPI_DOORBELL_FUNCTION_SHIFT) |
12938c2ecf20Sopenharmony_ci		 (access_control_value<<12)));
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	/* Wait for IOC to clear Doorbell Status bit */
12968c2ecf20Sopenharmony_ci	if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
12978c2ecf20Sopenharmony_ci		return -2;
12988c2ecf20Sopenharmony_ci	}else
12998c2ecf20Sopenharmony_ci		return 0;
13008c2ecf20Sopenharmony_ci}
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13038c2ecf20Sopenharmony_ci/**
13048c2ecf20Sopenharmony_ci *	mpt_host_page_alloc - allocate system memory for the fw
13058c2ecf20Sopenharmony_ci *	@ioc: Pointer to pointer to IOC adapter
13068c2ecf20Sopenharmony_ci *	@ioc_init: Pointer to ioc init config page
13078c2ecf20Sopenharmony_ci *
13088c2ecf20Sopenharmony_ci *	If we already allocated memory in past, then resend the same pointer.
13098c2ecf20Sopenharmony_ci *	Returns 0 for success, non-zero for failure.
13108c2ecf20Sopenharmony_ci */
13118c2ecf20Sopenharmony_cistatic int
13128c2ecf20Sopenharmony_cimpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
13138c2ecf20Sopenharmony_ci{
13148c2ecf20Sopenharmony_ci	char	*psge;
13158c2ecf20Sopenharmony_ci	int	flags_length;
13168c2ecf20Sopenharmony_ci	u32	host_page_buffer_sz=0;
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci	if(!ioc->HostPageBuffer) {
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci		host_page_buffer_sz =
13218c2ecf20Sopenharmony_ci		    le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci		if(!host_page_buffer_sz)
13248c2ecf20Sopenharmony_ci			return 0; /* fw doesn't need any host buffers */
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci		/* spin till we get enough memory */
13278c2ecf20Sopenharmony_ci		while (host_page_buffer_sz > 0) {
13288c2ecf20Sopenharmony_ci			ioc->HostPageBuffer =
13298c2ecf20Sopenharmony_ci				dma_alloc_coherent(&ioc->pcidev->dev,
13308c2ecf20Sopenharmony_ci						host_page_buffer_sz,
13318c2ecf20Sopenharmony_ci						&ioc->HostPageBuffer_dma,
13328c2ecf20Sopenharmony_ci						GFP_KERNEL);
13338c2ecf20Sopenharmony_ci			if (ioc->HostPageBuffer) {
13348c2ecf20Sopenharmony_ci				dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
13358c2ecf20Sopenharmony_ci				    "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
13368c2ecf20Sopenharmony_ci				    ioc->name, ioc->HostPageBuffer,
13378c2ecf20Sopenharmony_ci				    (u32)ioc->HostPageBuffer_dma,
13388c2ecf20Sopenharmony_ci				    host_page_buffer_sz));
13398c2ecf20Sopenharmony_ci				ioc->alloc_total += host_page_buffer_sz;
13408c2ecf20Sopenharmony_ci				ioc->HostPageBuffer_sz = host_page_buffer_sz;
13418c2ecf20Sopenharmony_ci				break;
13428c2ecf20Sopenharmony_ci			}
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci			host_page_buffer_sz -= (4*1024);
13458c2ecf20Sopenharmony_ci		}
13468c2ecf20Sopenharmony_ci	}
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	if(!ioc->HostPageBuffer) {
13498c2ecf20Sopenharmony_ci		printk(MYIOC_s_ERR_FMT
13508c2ecf20Sopenharmony_ci		    "Failed to alloc memory for host_page_buffer!\n",
13518c2ecf20Sopenharmony_ci		    ioc->name);
13528c2ecf20Sopenharmony_ci		return -999;
13538c2ecf20Sopenharmony_ci	}
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	psge = (char *)&ioc_init->HostPageBufferSGE;
13568c2ecf20Sopenharmony_ci	flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
13578c2ecf20Sopenharmony_ci	    MPI_SGE_FLAGS_SYSTEM_ADDRESS |
13588c2ecf20Sopenharmony_ci	    MPI_SGE_FLAGS_HOST_TO_IOC |
13598c2ecf20Sopenharmony_ci	    MPI_SGE_FLAGS_END_OF_BUFFER;
13608c2ecf20Sopenharmony_ci	flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
13618c2ecf20Sopenharmony_ci	flags_length |= ioc->HostPageBuffer_sz;
13628c2ecf20Sopenharmony_ci	ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
13638c2ecf20Sopenharmony_ci	ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	return 0;
13668c2ecf20Sopenharmony_ci}
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13698c2ecf20Sopenharmony_ci/**
13708c2ecf20Sopenharmony_ci *	mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
13718c2ecf20Sopenharmony_ci *	@iocid: IOC unique identifier (integer)
13728c2ecf20Sopenharmony_ci *	@iocpp: Pointer to pointer to IOC adapter
13738c2ecf20Sopenharmony_ci *
13748c2ecf20Sopenharmony_ci *	Given a unique IOC identifier, set pointer to the associated MPT
13758c2ecf20Sopenharmony_ci *	adapter structure.
13768c2ecf20Sopenharmony_ci *
13778c2ecf20Sopenharmony_ci *	Returns iocid and sets iocpp if iocid is found.
13788c2ecf20Sopenharmony_ci *	Returns -1 if iocid is not found.
13798c2ecf20Sopenharmony_ci */
13808c2ecf20Sopenharmony_ciint
13818c2ecf20Sopenharmony_cimpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
13828c2ecf20Sopenharmony_ci{
13838c2ecf20Sopenharmony_ci	MPT_ADAPTER *ioc;
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	list_for_each_entry(ioc,&ioc_list,list) {
13868c2ecf20Sopenharmony_ci		if (ioc->id == iocid) {
13878c2ecf20Sopenharmony_ci			*iocpp =ioc;
13888c2ecf20Sopenharmony_ci			return iocid;
13898c2ecf20Sopenharmony_ci		}
13908c2ecf20Sopenharmony_ci	}
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	*iocpp = NULL;
13938c2ecf20Sopenharmony_ci	return -1;
13948c2ecf20Sopenharmony_ci}
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci/**
13978c2ecf20Sopenharmony_ci *	mpt_get_product_name - returns product string
13988c2ecf20Sopenharmony_ci *	@vendor: pci vendor id
13998c2ecf20Sopenharmony_ci *	@device: pci device id
14008c2ecf20Sopenharmony_ci *	@revision: pci revision id
14018c2ecf20Sopenharmony_ci *
14028c2ecf20Sopenharmony_ci *	Returns product string displayed when driver loads,
14038c2ecf20Sopenharmony_ci *	in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
14048c2ecf20Sopenharmony_ci *
14058c2ecf20Sopenharmony_ci **/
14068c2ecf20Sopenharmony_cistatic const char*
14078c2ecf20Sopenharmony_cimpt_get_product_name(u16 vendor, u16 device, u8 revision)
14088c2ecf20Sopenharmony_ci{
14098c2ecf20Sopenharmony_ci	char *product_str = NULL;
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	if (vendor == PCI_VENDOR_ID_BROCADE) {
14128c2ecf20Sopenharmony_ci		switch (device)
14138c2ecf20Sopenharmony_ci		{
14148c2ecf20Sopenharmony_ci		case MPI_MANUFACTPAGE_DEVICEID_FC949E:
14158c2ecf20Sopenharmony_ci			switch (revision)
14168c2ecf20Sopenharmony_ci			{
14178c2ecf20Sopenharmony_ci			case 0x00:
14188c2ecf20Sopenharmony_ci				product_str = "BRE040 A0";
14198c2ecf20Sopenharmony_ci				break;
14208c2ecf20Sopenharmony_ci			case 0x01:
14218c2ecf20Sopenharmony_ci				product_str = "BRE040 A1";
14228c2ecf20Sopenharmony_ci				break;
14238c2ecf20Sopenharmony_ci			default:
14248c2ecf20Sopenharmony_ci				product_str = "BRE040";
14258c2ecf20Sopenharmony_ci				break;
14268c2ecf20Sopenharmony_ci			}
14278c2ecf20Sopenharmony_ci			break;
14288c2ecf20Sopenharmony_ci		}
14298c2ecf20Sopenharmony_ci		goto out;
14308c2ecf20Sopenharmony_ci	}
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	switch (device)
14338c2ecf20Sopenharmony_ci	{
14348c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVICEID_FC909:
14358c2ecf20Sopenharmony_ci		product_str = "LSIFC909 B1";
14368c2ecf20Sopenharmony_ci		break;
14378c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVICEID_FC919:
14388c2ecf20Sopenharmony_ci		product_str = "LSIFC919 B0";
14398c2ecf20Sopenharmony_ci		break;
14408c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVICEID_FC929:
14418c2ecf20Sopenharmony_ci		product_str = "LSIFC929 B0";
14428c2ecf20Sopenharmony_ci		break;
14438c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVICEID_FC919X:
14448c2ecf20Sopenharmony_ci		if (revision < 0x80)
14458c2ecf20Sopenharmony_ci			product_str = "LSIFC919X A0";
14468c2ecf20Sopenharmony_ci		else
14478c2ecf20Sopenharmony_ci			product_str = "LSIFC919XL A1";
14488c2ecf20Sopenharmony_ci		break;
14498c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVICEID_FC929X:
14508c2ecf20Sopenharmony_ci		if (revision < 0x80)
14518c2ecf20Sopenharmony_ci			product_str = "LSIFC929X A0";
14528c2ecf20Sopenharmony_ci		else
14538c2ecf20Sopenharmony_ci			product_str = "LSIFC929XL A1";
14548c2ecf20Sopenharmony_ci		break;
14558c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVICEID_FC939X:
14568c2ecf20Sopenharmony_ci		product_str = "LSIFC939X A1";
14578c2ecf20Sopenharmony_ci		break;
14588c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVICEID_FC949X:
14598c2ecf20Sopenharmony_ci		product_str = "LSIFC949X A1";
14608c2ecf20Sopenharmony_ci		break;
14618c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVICEID_FC949E:
14628c2ecf20Sopenharmony_ci		switch (revision)
14638c2ecf20Sopenharmony_ci		{
14648c2ecf20Sopenharmony_ci		case 0x00:
14658c2ecf20Sopenharmony_ci			product_str = "LSIFC949E A0";
14668c2ecf20Sopenharmony_ci			break;
14678c2ecf20Sopenharmony_ci		case 0x01:
14688c2ecf20Sopenharmony_ci			product_str = "LSIFC949E A1";
14698c2ecf20Sopenharmony_ci			break;
14708c2ecf20Sopenharmony_ci		default:
14718c2ecf20Sopenharmony_ci			product_str = "LSIFC949E";
14728c2ecf20Sopenharmony_ci			break;
14738c2ecf20Sopenharmony_ci		}
14748c2ecf20Sopenharmony_ci		break;
14758c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVID_53C1030:
14768c2ecf20Sopenharmony_ci		switch (revision)
14778c2ecf20Sopenharmony_ci		{
14788c2ecf20Sopenharmony_ci		case 0x00:
14798c2ecf20Sopenharmony_ci			product_str = "LSI53C1030 A0";
14808c2ecf20Sopenharmony_ci			break;
14818c2ecf20Sopenharmony_ci		case 0x01:
14828c2ecf20Sopenharmony_ci			product_str = "LSI53C1030 B0";
14838c2ecf20Sopenharmony_ci			break;
14848c2ecf20Sopenharmony_ci		case 0x03:
14858c2ecf20Sopenharmony_ci			product_str = "LSI53C1030 B1";
14868c2ecf20Sopenharmony_ci			break;
14878c2ecf20Sopenharmony_ci		case 0x07:
14888c2ecf20Sopenharmony_ci			product_str = "LSI53C1030 B2";
14898c2ecf20Sopenharmony_ci			break;
14908c2ecf20Sopenharmony_ci		case 0x08:
14918c2ecf20Sopenharmony_ci			product_str = "LSI53C1030 C0";
14928c2ecf20Sopenharmony_ci			break;
14938c2ecf20Sopenharmony_ci		case 0x80:
14948c2ecf20Sopenharmony_ci			product_str = "LSI53C1030T A0";
14958c2ecf20Sopenharmony_ci			break;
14968c2ecf20Sopenharmony_ci		case 0x83:
14978c2ecf20Sopenharmony_ci			product_str = "LSI53C1030T A2";
14988c2ecf20Sopenharmony_ci			break;
14998c2ecf20Sopenharmony_ci		case 0x87:
15008c2ecf20Sopenharmony_ci			product_str = "LSI53C1030T A3";
15018c2ecf20Sopenharmony_ci			break;
15028c2ecf20Sopenharmony_ci		case 0xc1:
15038c2ecf20Sopenharmony_ci			product_str = "LSI53C1020A A1";
15048c2ecf20Sopenharmony_ci			break;
15058c2ecf20Sopenharmony_ci		default:
15068c2ecf20Sopenharmony_ci			product_str = "LSI53C1030";
15078c2ecf20Sopenharmony_ci			break;
15088c2ecf20Sopenharmony_ci		}
15098c2ecf20Sopenharmony_ci		break;
15108c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
15118c2ecf20Sopenharmony_ci		switch (revision)
15128c2ecf20Sopenharmony_ci		{
15138c2ecf20Sopenharmony_ci		case 0x03:
15148c2ecf20Sopenharmony_ci			product_str = "LSI53C1035 A2";
15158c2ecf20Sopenharmony_ci			break;
15168c2ecf20Sopenharmony_ci		case 0x04:
15178c2ecf20Sopenharmony_ci			product_str = "LSI53C1035 B0";
15188c2ecf20Sopenharmony_ci			break;
15198c2ecf20Sopenharmony_ci		default:
15208c2ecf20Sopenharmony_ci			product_str = "LSI53C1035";
15218c2ecf20Sopenharmony_ci			break;
15228c2ecf20Sopenharmony_ci		}
15238c2ecf20Sopenharmony_ci		break;
15248c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVID_SAS1064:
15258c2ecf20Sopenharmony_ci		switch (revision)
15268c2ecf20Sopenharmony_ci		{
15278c2ecf20Sopenharmony_ci		case 0x00:
15288c2ecf20Sopenharmony_ci			product_str = "LSISAS1064 A1";
15298c2ecf20Sopenharmony_ci			break;
15308c2ecf20Sopenharmony_ci		case 0x01:
15318c2ecf20Sopenharmony_ci			product_str = "LSISAS1064 A2";
15328c2ecf20Sopenharmony_ci			break;
15338c2ecf20Sopenharmony_ci		case 0x02:
15348c2ecf20Sopenharmony_ci			product_str = "LSISAS1064 A3";
15358c2ecf20Sopenharmony_ci			break;
15368c2ecf20Sopenharmony_ci		case 0x03:
15378c2ecf20Sopenharmony_ci			product_str = "LSISAS1064 A4";
15388c2ecf20Sopenharmony_ci			break;
15398c2ecf20Sopenharmony_ci		default:
15408c2ecf20Sopenharmony_ci			product_str = "LSISAS1064";
15418c2ecf20Sopenharmony_ci			break;
15428c2ecf20Sopenharmony_ci		}
15438c2ecf20Sopenharmony_ci		break;
15448c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVID_SAS1064E:
15458c2ecf20Sopenharmony_ci		switch (revision)
15468c2ecf20Sopenharmony_ci		{
15478c2ecf20Sopenharmony_ci		case 0x00:
15488c2ecf20Sopenharmony_ci			product_str = "LSISAS1064E A0";
15498c2ecf20Sopenharmony_ci			break;
15508c2ecf20Sopenharmony_ci		case 0x01:
15518c2ecf20Sopenharmony_ci			product_str = "LSISAS1064E B0";
15528c2ecf20Sopenharmony_ci			break;
15538c2ecf20Sopenharmony_ci		case 0x02:
15548c2ecf20Sopenharmony_ci			product_str = "LSISAS1064E B1";
15558c2ecf20Sopenharmony_ci			break;
15568c2ecf20Sopenharmony_ci		case 0x04:
15578c2ecf20Sopenharmony_ci			product_str = "LSISAS1064E B2";
15588c2ecf20Sopenharmony_ci			break;
15598c2ecf20Sopenharmony_ci		case 0x08:
15608c2ecf20Sopenharmony_ci			product_str = "LSISAS1064E B3";
15618c2ecf20Sopenharmony_ci			break;
15628c2ecf20Sopenharmony_ci		default:
15638c2ecf20Sopenharmony_ci			product_str = "LSISAS1064E";
15648c2ecf20Sopenharmony_ci			break;
15658c2ecf20Sopenharmony_ci		}
15668c2ecf20Sopenharmony_ci		break;
15678c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVID_SAS1068:
15688c2ecf20Sopenharmony_ci		switch (revision)
15698c2ecf20Sopenharmony_ci		{
15708c2ecf20Sopenharmony_ci		case 0x00:
15718c2ecf20Sopenharmony_ci			product_str = "LSISAS1068 A0";
15728c2ecf20Sopenharmony_ci			break;
15738c2ecf20Sopenharmony_ci		case 0x01:
15748c2ecf20Sopenharmony_ci			product_str = "LSISAS1068 B0";
15758c2ecf20Sopenharmony_ci			break;
15768c2ecf20Sopenharmony_ci		case 0x02:
15778c2ecf20Sopenharmony_ci			product_str = "LSISAS1068 B1";
15788c2ecf20Sopenharmony_ci			break;
15798c2ecf20Sopenharmony_ci		default:
15808c2ecf20Sopenharmony_ci			product_str = "LSISAS1068";
15818c2ecf20Sopenharmony_ci			break;
15828c2ecf20Sopenharmony_ci		}
15838c2ecf20Sopenharmony_ci		break;
15848c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVID_SAS1068E:
15858c2ecf20Sopenharmony_ci		switch (revision)
15868c2ecf20Sopenharmony_ci		{
15878c2ecf20Sopenharmony_ci		case 0x00:
15888c2ecf20Sopenharmony_ci			product_str = "LSISAS1068E A0";
15898c2ecf20Sopenharmony_ci			break;
15908c2ecf20Sopenharmony_ci		case 0x01:
15918c2ecf20Sopenharmony_ci			product_str = "LSISAS1068E B0";
15928c2ecf20Sopenharmony_ci			break;
15938c2ecf20Sopenharmony_ci		case 0x02:
15948c2ecf20Sopenharmony_ci			product_str = "LSISAS1068E B1";
15958c2ecf20Sopenharmony_ci			break;
15968c2ecf20Sopenharmony_ci		case 0x04:
15978c2ecf20Sopenharmony_ci			product_str = "LSISAS1068E B2";
15988c2ecf20Sopenharmony_ci			break;
15998c2ecf20Sopenharmony_ci		case 0x08:
16008c2ecf20Sopenharmony_ci			product_str = "LSISAS1068E B3";
16018c2ecf20Sopenharmony_ci			break;
16028c2ecf20Sopenharmony_ci		default:
16038c2ecf20Sopenharmony_ci			product_str = "LSISAS1068E";
16048c2ecf20Sopenharmony_ci			break;
16058c2ecf20Sopenharmony_ci		}
16068c2ecf20Sopenharmony_ci		break;
16078c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVID_SAS1078:
16088c2ecf20Sopenharmony_ci		switch (revision)
16098c2ecf20Sopenharmony_ci		{
16108c2ecf20Sopenharmony_ci		case 0x00:
16118c2ecf20Sopenharmony_ci			product_str = "LSISAS1078 A0";
16128c2ecf20Sopenharmony_ci			break;
16138c2ecf20Sopenharmony_ci		case 0x01:
16148c2ecf20Sopenharmony_ci			product_str = "LSISAS1078 B0";
16158c2ecf20Sopenharmony_ci			break;
16168c2ecf20Sopenharmony_ci		case 0x02:
16178c2ecf20Sopenharmony_ci			product_str = "LSISAS1078 C0";
16188c2ecf20Sopenharmony_ci			break;
16198c2ecf20Sopenharmony_ci		case 0x03:
16208c2ecf20Sopenharmony_ci			product_str = "LSISAS1078 C1";
16218c2ecf20Sopenharmony_ci			break;
16228c2ecf20Sopenharmony_ci		case 0x04:
16238c2ecf20Sopenharmony_ci			product_str = "LSISAS1078 C2";
16248c2ecf20Sopenharmony_ci			break;
16258c2ecf20Sopenharmony_ci		default:
16268c2ecf20Sopenharmony_ci			product_str = "LSISAS1078";
16278c2ecf20Sopenharmony_ci			break;
16288c2ecf20Sopenharmony_ci		}
16298c2ecf20Sopenharmony_ci		break;
16308c2ecf20Sopenharmony_ci	}
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci out:
16338c2ecf20Sopenharmony_ci	return product_str;
16348c2ecf20Sopenharmony_ci}
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci/**
16378c2ecf20Sopenharmony_ci *	mpt_mapresources - map in memory mapped io
16388c2ecf20Sopenharmony_ci *	@ioc: Pointer to pointer to IOC adapter
16398c2ecf20Sopenharmony_ci *
16408c2ecf20Sopenharmony_ci **/
16418c2ecf20Sopenharmony_cistatic int
16428c2ecf20Sopenharmony_cimpt_mapresources(MPT_ADAPTER *ioc)
16438c2ecf20Sopenharmony_ci{
16448c2ecf20Sopenharmony_ci	u8		__iomem *mem;
16458c2ecf20Sopenharmony_ci	int		 ii;
16468c2ecf20Sopenharmony_ci	resource_size_t	 mem_phys;
16478c2ecf20Sopenharmony_ci	unsigned long	 port;
16488c2ecf20Sopenharmony_ci	u32		 msize;
16498c2ecf20Sopenharmony_ci	u32		 psize;
16508c2ecf20Sopenharmony_ci	int		 r = -ENODEV;
16518c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci	pdev = ioc->pcidev;
16548c2ecf20Sopenharmony_ci	ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
16558c2ecf20Sopenharmony_ci	if (pci_enable_device_mem(pdev)) {
16568c2ecf20Sopenharmony_ci		printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
16578c2ecf20Sopenharmony_ci		    "failed\n", ioc->name);
16588c2ecf20Sopenharmony_ci		return r;
16598c2ecf20Sopenharmony_ci	}
16608c2ecf20Sopenharmony_ci	if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
16618c2ecf20Sopenharmony_ci		printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
16628c2ecf20Sopenharmony_ci		    "MEM failed\n", ioc->name);
16638c2ecf20Sopenharmony_ci		goto out_pci_disable_device;
16648c2ecf20Sopenharmony_ci	}
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	if (sizeof(dma_addr_t) > 4) {
16678c2ecf20Sopenharmony_ci		const uint64_t required_mask = dma_get_required_mask
16688c2ecf20Sopenharmony_ci		    (&pdev->dev);
16698c2ecf20Sopenharmony_ci		if (required_mask > DMA_BIT_MASK(32)
16708c2ecf20Sopenharmony_ci			&& !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
16718c2ecf20Sopenharmony_ci			&& !pci_set_consistent_dma_mask(pdev,
16728c2ecf20Sopenharmony_ci						 DMA_BIT_MASK(64))) {
16738c2ecf20Sopenharmony_ci			ioc->dma_mask = DMA_BIT_MASK(64);
16748c2ecf20Sopenharmony_ci			dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
16758c2ecf20Sopenharmony_ci				": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
16768c2ecf20Sopenharmony_ci				ioc->name));
16778c2ecf20Sopenharmony_ci		} else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
16788c2ecf20Sopenharmony_ci			&& !pci_set_consistent_dma_mask(pdev,
16798c2ecf20Sopenharmony_ci						DMA_BIT_MASK(32))) {
16808c2ecf20Sopenharmony_ci			ioc->dma_mask = DMA_BIT_MASK(32);
16818c2ecf20Sopenharmony_ci			dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
16828c2ecf20Sopenharmony_ci				": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
16838c2ecf20Sopenharmony_ci				ioc->name));
16848c2ecf20Sopenharmony_ci		} else {
16858c2ecf20Sopenharmony_ci			printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
16868c2ecf20Sopenharmony_ci			    ioc->name, pci_name(pdev));
16878c2ecf20Sopenharmony_ci			goto out_pci_release_region;
16888c2ecf20Sopenharmony_ci		}
16898c2ecf20Sopenharmony_ci	} else {
16908c2ecf20Sopenharmony_ci		if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
16918c2ecf20Sopenharmony_ci			&& !pci_set_consistent_dma_mask(pdev,
16928c2ecf20Sopenharmony_ci						DMA_BIT_MASK(32))) {
16938c2ecf20Sopenharmony_ci			ioc->dma_mask = DMA_BIT_MASK(32);
16948c2ecf20Sopenharmony_ci			dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
16958c2ecf20Sopenharmony_ci				": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
16968c2ecf20Sopenharmony_ci				ioc->name));
16978c2ecf20Sopenharmony_ci		} else {
16988c2ecf20Sopenharmony_ci			printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
16998c2ecf20Sopenharmony_ci			    ioc->name, pci_name(pdev));
17008c2ecf20Sopenharmony_ci			goto out_pci_release_region;
17018c2ecf20Sopenharmony_ci		}
17028c2ecf20Sopenharmony_ci	}
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	mem_phys = msize = 0;
17058c2ecf20Sopenharmony_ci	port = psize = 0;
17068c2ecf20Sopenharmony_ci	for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
17078c2ecf20Sopenharmony_ci		if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
17088c2ecf20Sopenharmony_ci			if (psize)
17098c2ecf20Sopenharmony_ci				continue;
17108c2ecf20Sopenharmony_ci			/* Get I/O space! */
17118c2ecf20Sopenharmony_ci			port = pci_resource_start(pdev, ii);
17128c2ecf20Sopenharmony_ci			psize = pci_resource_len(pdev, ii);
17138c2ecf20Sopenharmony_ci		} else {
17148c2ecf20Sopenharmony_ci			if (msize)
17158c2ecf20Sopenharmony_ci				continue;
17168c2ecf20Sopenharmony_ci			/* Get memmap */
17178c2ecf20Sopenharmony_ci			mem_phys = pci_resource_start(pdev, ii);
17188c2ecf20Sopenharmony_ci			msize = pci_resource_len(pdev, ii);
17198c2ecf20Sopenharmony_ci		}
17208c2ecf20Sopenharmony_ci	}
17218c2ecf20Sopenharmony_ci	ioc->mem_size = msize;
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	mem = NULL;
17248c2ecf20Sopenharmony_ci	/* Get logical ptr for PciMem0 space */
17258c2ecf20Sopenharmony_ci	/*mem = ioremap(mem_phys, msize);*/
17268c2ecf20Sopenharmony_ci	mem = ioremap(mem_phys, msize);
17278c2ecf20Sopenharmony_ci	if (mem == NULL) {
17288c2ecf20Sopenharmony_ci		printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
17298c2ecf20Sopenharmony_ci			" memory!\n", ioc->name);
17308c2ecf20Sopenharmony_ci		r = -EINVAL;
17318c2ecf20Sopenharmony_ci		goto out_pci_release_region;
17328c2ecf20Sopenharmony_ci	}
17338c2ecf20Sopenharmony_ci	ioc->memmap = mem;
17348c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %llx\n",
17358c2ecf20Sopenharmony_ci	    ioc->name, mem, (unsigned long long)mem_phys));
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci	ioc->mem_phys = mem_phys;
17388c2ecf20Sopenharmony_ci	ioc->chip = (SYSIF_REGS __iomem *)mem;
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci	/* Save Port IO values in case we need to do downloadboot */
17418c2ecf20Sopenharmony_ci	ioc->pio_mem_phys = port;
17428c2ecf20Sopenharmony_ci	ioc->pio_chip = (SYSIF_REGS __iomem *)port;
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci	return 0;
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ciout_pci_release_region:
17478c2ecf20Sopenharmony_ci	pci_release_selected_regions(pdev, ioc->bars);
17488c2ecf20Sopenharmony_ciout_pci_disable_device:
17498c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
17508c2ecf20Sopenharmony_ci	return r;
17518c2ecf20Sopenharmony_ci}
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
17548c2ecf20Sopenharmony_ci/**
17558c2ecf20Sopenharmony_ci *	mpt_attach - Install a PCI intelligent MPT adapter.
17568c2ecf20Sopenharmony_ci *	@pdev: Pointer to pci_dev structure
17578c2ecf20Sopenharmony_ci *	@id: PCI device ID information
17588c2ecf20Sopenharmony_ci *
17598c2ecf20Sopenharmony_ci *	This routine performs all the steps necessary to bring the IOC of
17608c2ecf20Sopenharmony_ci *	a MPT adapter to a OPERATIONAL state.  This includes registering
17618c2ecf20Sopenharmony_ci *	memory regions, registering the interrupt, and allocating request
17628c2ecf20Sopenharmony_ci *	and reply memory pools.
17638c2ecf20Sopenharmony_ci *
17648c2ecf20Sopenharmony_ci *	This routine also pre-fetches the LAN MAC address of a Fibre Channel
17658c2ecf20Sopenharmony_ci *	MPT adapter.
17668c2ecf20Sopenharmony_ci *
17678c2ecf20Sopenharmony_ci *	Returns 0 for success, non-zero for failure.
17688c2ecf20Sopenharmony_ci *
17698c2ecf20Sopenharmony_ci *	TODO: Add support for polled controllers
17708c2ecf20Sopenharmony_ci */
17718c2ecf20Sopenharmony_ciint
17728c2ecf20Sopenharmony_cimpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
17738c2ecf20Sopenharmony_ci{
17748c2ecf20Sopenharmony_ci	MPT_ADAPTER	*ioc;
17758c2ecf20Sopenharmony_ci	u8		 cb_idx;
17768c2ecf20Sopenharmony_ci	int		 r = -ENODEV;
17778c2ecf20Sopenharmony_ci	u8		 pcixcmd;
17788c2ecf20Sopenharmony_ci	static int	 mpt_ids = 0;
17798c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
17808c2ecf20Sopenharmony_ci	struct proc_dir_entry *dent;
17818c2ecf20Sopenharmony_ci#endif
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci	ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_KERNEL);
17848c2ecf20Sopenharmony_ci	if (ioc == NULL) {
17858c2ecf20Sopenharmony_ci		printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
17868c2ecf20Sopenharmony_ci		return -ENOMEM;
17878c2ecf20Sopenharmony_ci	}
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_ci	ioc->id = mpt_ids++;
17908c2ecf20Sopenharmony_ci	sprintf(ioc->name, "ioc%d", ioc->id);
17918c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci	/*
17948c2ecf20Sopenharmony_ci	 * set initial debug level
17958c2ecf20Sopenharmony_ci	 * (refer to mptdebug.h)
17968c2ecf20Sopenharmony_ci	 *
17978c2ecf20Sopenharmony_ci	 */
17988c2ecf20Sopenharmony_ci	ioc->debug_level = mpt_debug_level;
17998c2ecf20Sopenharmony_ci	if (mpt_debug_level)
18008c2ecf20Sopenharmony_ci		printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci	ioc->pcidev = pdev;
18058c2ecf20Sopenharmony_ci	if (mpt_mapresources(ioc)) {
18068c2ecf20Sopenharmony_ci		goto out_free_ioc;
18078c2ecf20Sopenharmony_ci	}
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_ci	/*
18108c2ecf20Sopenharmony_ci	 * Setting up proper handlers for scatter gather handling
18118c2ecf20Sopenharmony_ci	 */
18128c2ecf20Sopenharmony_ci	if (ioc->dma_mask == DMA_BIT_MASK(64)) {
18138c2ecf20Sopenharmony_ci		if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
18148c2ecf20Sopenharmony_ci			ioc->add_sge = &mpt_add_sge_64bit_1078;
18158c2ecf20Sopenharmony_ci		else
18168c2ecf20Sopenharmony_ci			ioc->add_sge = &mpt_add_sge_64bit;
18178c2ecf20Sopenharmony_ci		ioc->add_chain = &mpt_add_chain_64bit;
18188c2ecf20Sopenharmony_ci		ioc->sg_addr_size = 8;
18198c2ecf20Sopenharmony_ci	} else {
18208c2ecf20Sopenharmony_ci		ioc->add_sge = &mpt_add_sge;
18218c2ecf20Sopenharmony_ci		ioc->add_chain = &mpt_add_chain;
18228c2ecf20Sopenharmony_ci		ioc->sg_addr_size = 4;
18238c2ecf20Sopenharmony_ci	}
18248c2ecf20Sopenharmony_ci	ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ci	ioc->alloc_total = sizeof(MPT_ADAPTER);
18278c2ecf20Sopenharmony_ci	ioc->req_sz = MPT_DEFAULT_FRAME_SIZE;		/* avoid div by zero! */
18288c2ecf20Sopenharmony_ci	ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_ci	spin_lock_init(&ioc->taskmgmt_lock);
18328c2ecf20Sopenharmony_ci	mutex_init(&ioc->internal_cmds.mutex);
18338c2ecf20Sopenharmony_ci	init_completion(&ioc->internal_cmds.done);
18348c2ecf20Sopenharmony_ci	mutex_init(&ioc->mptbase_cmds.mutex);
18358c2ecf20Sopenharmony_ci	init_completion(&ioc->mptbase_cmds.done);
18368c2ecf20Sopenharmony_ci	mutex_init(&ioc->taskmgmt_cmds.mutex);
18378c2ecf20Sopenharmony_ci	init_completion(&ioc->taskmgmt_cmds.done);
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	/* Initialize the event logging.
18408c2ecf20Sopenharmony_ci	 */
18418c2ecf20Sopenharmony_ci	ioc->eventTypes = 0;	/* None */
18428c2ecf20Sopenharmony_ci	ioc->eventContext = 0;
18438c2ecf20Sopenharmony_ci	ioc->eventLogSize = 0;
18448c2ecf20Sopenharmony_ci	ioc->events = NULL;
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci#ifdef MFCNT
18478c2ecf20Sopenharmony_ci	ioc->mfcnt = 0;
18488c2ecf20Sopenharmony_ci#endif
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci	ioc->sh = NULL;
18518c2ecf20Sopenharmony_ci	ioc->cached_fw = NULL;
18528c2ecf20Sopenharmony_ci
18538c2ecf20Sopenharmony_ci	/* Initialize SCSI Config Data structure
18548c2ecf20Sopenharmony_ci	 */
18558c2ecf20Sopenharmony_ci	memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci	/* Initialize the fc rport list head.
18588c2ecf20Sopenharmony_ci	 */
18598c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ioc->fc_rports);
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	/* Find lookup slot. */
18628c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ioc->list);
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	/* Initialize workqueue */
18668c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci	snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
18698c2ecf20Sopenharmony_ci		 "mpt_poll_%d", ioc->id);
18708c2ecf20Sopenharmony_ci	ioc->reset_work_q = alloc_workqueue(ioc->reset_work_q_name,
18718c2ecf20Sopenharmony_ci					    WQ_MEM_RECLAIM, 0);
18728c2ecf20Sopenharmony_ci	if (!ioc->reset_work_q) {
18738c2ecf20Sopenharmony_ci		printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
18748c2ecf20Sopenharmony_ci		    ioc->name);
18758c2ecf20Sopenharmony_ci		r = -ENOMEM;
18768c2ecf20Sopenharmony_ci		goto out_unmap_resources;
18778c2ecf20Sopenharmony_ci	}
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
18808c2ecf20Sopenharmony_ci	    ioc->name, &ioc->facts, &ioc->pfacts[0]));
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci	ioc->prod_name = mpt_get_product_name(pdev->vendor, pdev->device,
18838c2ecf20Sopenharmony_ci					      pdev->revision);
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci	switch (pdev->device)
18868c2ecf20Sopenharmony_ci	{
18878c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVICEID_FC939X:
18888c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVICEID_FC949X:
18898c2ecf20Sopenharmony_ci		ioc->errata_flag_1064 = 1;
18908c2ecf20Sopenharmony_ci		fallthrough;
18918c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVICEID_FC909:
18928c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVICEID_FC929:
18938c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVICEID_FC919:
18948c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVICEID_FC949E:
18958c2ecf20Sopenharmony_ci		ioc->bus_type = FC;
18968c2ecf20Sopenharmony_ci		break;
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVICEID_FC929X:
18998c2ecf20Sopenharmony_ci		if (pdev->revision < XL_929) {
19008c2ecf20Sopenharmony_ci			/* 929X Chip Fix. Set Split transactions level
19018c2ecf20Sopenharmony_ci		 	* for PCIX. Set MOST bits to zero.
19028c2ecf20Sopenharmony_ci		 	*/
19038c2ecf20Sopenharmony_ci			pci_read_config_byte(pdev, 0x6a, &pcixcmd);
19048c2ecf20Sopenharmony_ci			pcixcmd &= 0x8F;
19058c2ecf20Sopenharmony_ci			pci_write_config_byte(pdev, 0x6a, pcixcmd);
19068c2ecf20Sopenharmony_ci		} else {
19078c2ecf20Sopenharmony_ci			/* 929XL Chip Fix. Set MMRBC to 0x08.
19088c2ecf20Sopenharmony_ci		 	*/
19098c2ecf20Sopenharmony_ci			pci_read_config_byte(pdev, 0x6a, &pcixcmd);
19108c2ecf20Sopenharmony_ci			pcixcmd |= 0x08;
19118c2ecf20Sopenharmony_ci			pci_write_config_byte(pdev, 0x6a, pcixcmd);
19128c2ecf20Sopenharmony_ci		}
19138c2ecf20Sopenharmony_ci		ioc->bus_type = FC;
19148c2ecf20Sopenharmony_ci		break;
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVICEID_FC919X:
19178c2ecf20Sopenharmony_ci		/* 919X Chip Fix. Set Split transactions level
19188c2ecf20Sopenharmony_ci		 * for PCIX. Set MOST bits to zero.
19198c2ecf20Sopenharmony_ci		 */
19208c2ecf20Sopenharmony_ci		pci_read_config_byte(pdev, 0x6a, &pcixcmd);
19218c2ecf20Sopenharmony_ci		pcixcmd &= 0x8F;
19228c2ecf20Sopenharmony_ci		pci_write_config_byte(pdev, 0x6a, pcixcmd);
19238c2ecf20Sopenharmony_ci		ioc->bus_type = FC;
19248c2ecf20Sopenharmony_ci		break;
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVID_53C1030:
19278c2ecf20Sopenharmony_ci		/* 1030 Chip Fix. Disable Split transactions
19288c2ecf20Sopenharmony_ci		 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
19298c2ecf20Sopenharmony_ci		 */
19308c2ecf20Sopenharmony_ci		if (pdev->revision < C0_1030) {
19318c2ecf20Sopenharmony_ci			pci_read_config_byte(pdev, 0x6a, &pcixcmd);
19328c2ecf20Sopenharmony_ci			pcixcmd &= 0x8F;
19338c2ecf20Sopenharmony_ci			pci_write_config_byte(pdev, 0x6a, pcixcmd);
19348c2ecf20Sopenharmony_ci		}
19358c2ecf20Sopenharmony_ci		fallthrough;
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
19388c2ecf20Sopenharmony_ci		ioc->bus_type = SPI;
19398c2ecf20Sopenharmony_ci		break;
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVID_SAS1064:
19428c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVID_SAS1068:
19438c2ecf20Sopenharmony_ci		ioc->errata_flag_1064 = 1;
19448c2ecf20Sopenharmony_ci		ioc->bus_type = SAS;
19458c2ecf20Sopenharmony_ci		break;
19468c2ecf20Sopenharmony_ci
19478c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVID_SAS1064E:
19488c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVID_SAS1068E:
19498c2ecf20Sopenharmony_ci	case MPI_MANUFACTPAGE_DEVID_SAS1078:
19508c2ecf20Sopenharmony_ci		ioc->bus_type = SAS;
19518c2ecf20Sopenharmony_ci		break;
19528c2ecf20Sopenharmony_ci	}
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci	switch (ioc->bus_type) {
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_ci	case SAS:
19588c2ecf20Sopenharmony_ci		ioc->msi_enable = mpt_msi_enable_sas;
19598c2ecf20Sopenharmony_ci		break;
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci	case SPI:
19628c2ecf20Sopenharmony_ci		ioc->msi_enable = mpt_msi_enable_spi;
19638c2ecf20Sopenharmony_ci		break;
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	case FC:
19668c2ecf20Sopenharmony_ci		ioc->msi_enable = mpt_msi_enable_fc;
19678c2ecf20Sopenharmony_ci		break;
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_ci	default:
19708c2ecf20Sopenharmony_ci		ioc->msi_enable = 0;
19718c2ecf20Sopenharmony_ci		break;
19728c2ecf20Sopenharmony_ci	}
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci	ioc->fw_events_off = 1;
19758c2ecf20Sopenharmony_ci
19768c2ecf20Sopenharmony_ci	if (ioc->errata_flag_1064)
19778c2ecf20Sopenharmony_ci		pci_disable_io_access(pdev);
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci	spin_lock_init(&ioc->FreeQlock);
19808c2ecf20Sopenharmony_ci
19818c2ecf20Sopenharmony_ci	/* Disable all! */
19828c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
19838c2ecf20Sopenharmony_ci	ioc->active = 0;
19848c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_ci	/* Set IOC ptr in the pcidev's driver data. */
19878c2ecf20Sopenharmony_ci	pci_set_drvdata(ioc->pcidev, ioc);
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_ci	/* Set lookup ptr. */
19908c2ecf20Sopenharmony_ci	list_add_tail(&ioc->list, &ioc_list);
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_ci	/* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
19938c2ecf20Sopenharmony_ci	 */
19948c2ecf20Sopenharmony_ci	mpt_detect_bound_ports(ioc, pdev);
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ioc->fw_event_list);
19978c2ecf20Sopenharmony_ci	spin_lock_init(&ioc->fw_event_lock);
19988c2ecf20Sopenharmony_ci	snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
19998c2ecf20Sopenharmony_ci	ioc->fw_event_q = alloc_workqueue(ioc->fw_event_q_name,
20008c2ecf20Sopenharmony_ci					  WQ_MEM_RECLAIM, 0);
20018c2ecf20Sopenharmony_ci	if (!ioc->fw_event_q) {
20028c2ecf20Sopenharmony_ci		printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
20038c2ecf20Sopenharmony_ci		    ioc->name);
20048c2ecf20Sopenharmony_ci		r = -ENOMEM;
20058c2ecf20Sopenharmony_ci		goto out_remove_ioc;
20068c2ecf20Sopenharmony_ci	}
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
20098c2ecf20Sopenharmony_ci	    CAN_SLEEP)) != 0){
20108c2ecf20Sopenharmony_ci		printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
20118c2ecf20Sopenharmony_ci		    ioc->name, r);
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci		destroy_workqueue(ioc->fw_event_q);
20148c2ecf20Sopenharmony_ci		ioc->fw_event_q = NULL;
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci		list_del(&ioc->list);
20178c2ecf20Sopenharmony_ci		if (ioc->alt_ioc)
20188c2ecf20Sopenharmony_ci			ioc->alt_ioc->alt_ioc = NULL;
20198c2ecf20Sopenharmony_ci		iounmap(ioc->memmap);
20208c2ecf20Sopenharmony_ci		if (pci_is_enabled(pdev))
20218c2ecf20Sopenharmony_ci			pci_disable_device(pdev);
20228c2ecf20Sopenharmony_ci		if (r != -5)
20238c2ecf20Sopenharmony_ci			pci_release_selected_regions(pdev, ioc->bars);
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ci		destroy_workqueue(ioc->reset_work_q);
20268c2ecf20Sopenharmony_ci		ioc->reset_work_q = NULL;
20278c2ecf20Sopenharmony_ci
20288c2ecf20Sopenharmony_ci		kfree(ioc);
20298c2ecf20Sopenharmony_ci		return r;
20308c2ecf20Sopenharmony_ci	}
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	/* call per device driver probe entry point */
20338c2ecf20Sopenharmony_ci	for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
20348c2ecf20Sopenharmony_ci		if(MptDeviceDriverHandlers[cb_idx] &&
20358c2ecf20Sopenharmony_ci		  MptDeviceDriverHandlers[cb_idx]->probe) {
20368c2ecf20Sopenharmony_ci			MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
20378c2ecf20Sopenharmony_ci		}
20388c2ecf20Sopenharmony_ci	}
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
20418c2ecf20Sopenharmony_ci	/*
20428c2ecf20Sopenharmony_ci	 *  Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
20438c2ecf20Sopenharmony_ci	 */
20448c2ecf20Sopenharmony_ci	dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
20458c2ecf20Sopenharmony_ci	if (dent) {
20468c2ecf20Sopenharmony_ci		proc_create_single_data("info", S_IRUGO, dent,
20478c2ecf20Sopenharmony_ci				mpt_iocinfo_proc_show, ioc);
20488c2ecf20Sopenharmony_ci		proc_create_single_data("summary", S_IRUGO, dent,
20498c2ecf20Sopenharmony_ci				mpt_summary_proc_show, ioc);
20508c2ecf20Sopenharmony_ci	}
20518c2ecf20Sopenharmony_ci#endif
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_ci	if (!ioc->alt_ioc)
20548c2ecf20Sopenharmony_ci		queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
20558c2ecf20Sopenharmony_ci			msecs_to_jiffies(MPT_POLLING_INTERVAL));
20568c2ecf20Sopenharmony_ci
20578c2ecf20Sopenharmony_ci	return 0;
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ciout_remove_ioc:
20608c2ecf20Sopenharmony_ci	list_del(&ioc->list);
20618c2ecf20Sopenharmony_ci	if (ioc->alt_ioc)
20628c2ecf20Sopenharmony_ci		ioc->alt_ioc->alt_ioc = NULL;
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci	destroy_workqueue(ioc->reset_work_q);
20658c2ecf20Sopenharmony_ci	ioc->reset_work_q = NULL;
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_ciout_unmap_resources:
20688c2ecf20Sopenharmony_ci	iounmap(ioc->memmap);
20698c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
20708c2ecf20Sopenharmony_ci	pci_release_selected_regions(pdev, ioc->bars);
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ciout_free_ioc:
20738c2ecf20Sopenharmony_ci	kfree(ioc);
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ci	return r;
20768c2ecf20Sopenharmony_ci}
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
20798c2ecf20Sopenharmony_ci/**
20808c2ecf20Sopenharmony_ci *	mpt_detach - Remove a PCI intelligent MPT adapter.
20818c2ecf20Sopenharmony_ci *	@pdev: Pointer to pci_dev structure
20828c2ecf20Sopenharmony_ci */
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_civoid
20858c2ecf20Sopenharmony_cimpt_detach(struct pci_dev *pdev)
20868c2ecf20Sopenharmony_ci{
20878c2ecf20Sopenharmony_ci	MPT_ADAPTER 	*ioc = pci_get_drvdata(pdev);
20888c2ecf20Sopenharmony_ci	char pname[64];
20898c2ecf20Sopenharmony_ci	u8 cb_idx;
20908c2ecf20Sopenharmony_ci	unsigned long flags;
20918c2ecf20Sopenharmony_ci	struct workqueue_struct *wq;
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci	/*
20948c2ecf20Sopenharmony_ci	 * Stop polling ioc for fault condition
20958c2ecf20Sopenharmony_ci	 */
20968c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
20978c2ecf20Sopenharmony_ci	wq = ioc->reset_work_q;
20988c2ecf20Sopenharmony_ci	ioc->reset_work_q = NULL;
20998c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
21008c2ecf20Sopenharmony_ci	cancel_delayed_work(&ioc->fault_reset_work);
21018c2ecf20Sopenharmony_ci	destroy_workqueue(wq);
21028c2ecf20Sopenharmony_ci
21038c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->fw_event_lock, flags);
21048c2ecf20Sopenharmony_ci	wq = ioc->fw_event_q;
21058c2ecf20Sopenharmony_ci	ioc->fw_event_q = NULL;
21068c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
21078c2ecf20Sopenharmony_ci	destroy_workqueue(wq);
21088c2ecf20Sopenharmony_ci
21098c2ecf20Sopenharmony_ci	snprintf(pname, sizeof(pname), MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
21108c2ecf20Sopenharmony_ci	remove_proc_entry(pname, NULL);
21118c2ecf20Sopenharmony_ci	snprintf(pname, sizeof(pname), MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
21128c2ecf20Sopenharmony_ci	remove_proc_entry(pname, NULL);
21138c2ecf20Sopenharmony_ci	snprintf(pname, sizeof(pname), MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
21148c2ecf20Sopenharmony_ci	remove_proc_entry(pname, NULL);
21158c2ecf20Sopenharmony_ci
21168c2ecf20Sopenharmony_ci	/* call per device driver remove entry point */
21178c2ecf20Sopenharmony_ci	for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
21188c2ecf20Sopenharmony_ci		if(MptDeviceDriverHandlers[cb_idx] &&
21198c2ecf20Sopenharmony_ci		  MptDeviceDriverHandlers[cb_idx]->remove) {
21208c2ecf20Sopenharmony_ci			MptDeviceDriverHandlers[cb_idx]->remove(pdev);
21218c2ecf20Sopenharmony_ci		}
21228c2ecf20Sopenharmony_ci	}
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_ci	/* Disable interrupts! */
21258c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci	ioc->active = 0;
21288c2ecf20Sopenharmony_ci	synchronize_irq(pdev->irq);
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_ci	/* Clear any lingering interrupt */
21318c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
21328c2ecf20Sopenharmony_ci
21338c2ecf20Sopenharmony_ci	CHIPREG_READ32(&ioc->chip->IntStatus);
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_ci	mpt_adapter_dispose(ioc);
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci}
21388c2ecf20Sopenharmony_ci
21398c2ecf20Sopenharmony_ci/**************************************************************************
21408c2ecf20Sopenharmony_ci * Power Management
21418c2ecf20Sopenharmony_ci */
21428c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
21438c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
21448c2ecf20Sopenharmony_ci/**
21458c2ecf20Sopenharmony_ci *	mpt_suspend - Fusion MPT base driver suspend routine.
21468c2ecf20Sopenharmony_ci *	@pdev: Pointer to pci_dev structure
21478c2ecf20Sopenharmony_ci *	@state: new state to enter
21488c2ecf20Sopenharmony_ci */
21498c2ecf20Sopenharmony_ciint
21508c2ecf20Sopenharmony_cimpt_suspend(struct pci_dev *pdev, pm_message_t state)
21518c2ecf20Sopenharmony_ci{
21528c2ecf20Sopenharmony_ci	u32 device_state;
21538c2ecf20Sopenharmony_ci	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci	device_state = pci_choose_state(pdev, state);
21568c2ecf20Sopenharmony_ci	printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
21578c2ecf20Sopenharmony_ci	    "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
21588c2ecf20Sopenharmony_ci	    device_state);
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci	/* put ioc into READY_STATE */
21618c2ecf20Sopenharmony_ci	if (SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
21628c2ecf20Sopenharmony_ci		printk(MYIOC_s_ERR_FMT
21638c2ecf20Sopenharmony_ci		"pci-suspend:  IOC msg unit reset failed!\n", ioc->name);
21648c2ecf20Sopenharmony_ci	}
21658c2ecf20Sopenharmony_ci
21668c2ecf20Sopenharmony_ci	/* disable interrupts */
21678c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
21688c2ecf20Sopenharmony_ci	ioc->active = 0;
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_ci	/* Clear any lingering interrupt */
21718c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci	free_irq(ioc->pci_irq, ioc);
21748c2ecf20Sopenharmony_ci	if (ioc->msi_enable)
21758c2ecf20Sopenharmony_ci		pci_disable_msi(ioc->pcidev);
21768c2ecf20Sopenharmony_ci	ioc->pci_irq = -1;
21778c2ecf20Sopenharmony_ci	pci_save_state(pdev);
21788c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
21798c2ecf20Sopenharmony_ci	pci_release_selected_regions(pdev, ioc->bars);
21808c2ecf20Sopenharmony_ci	pci_set_power_state(pdev, device_state);
21818c2ecf20Sopenharmony_ci	return 0;
21828c2ecf20Sopenharmony_ci}
21838c2ecf20Sopenharmony_ci
21848c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
21858c2ecf20Sopenharmony_ci/**
21868c2ecf20Sopenharmony_ci *	mpt_resume - Fusion MPT base driver resume routine.
21878c2ecf20Sopenharmony_ci *	@pdev: Pointer to pci_dev structure
21888c2ecf20Sopenharmony_ci */
21898c2ecf20Sopenharmony_ciint
21908c2ecf20Sopenharmony_cimpt_resume(struct pci_dev *pdev)
21918c2ecf20Sopenharmony_ci{
21928c2ecf20Sopenharmony_ci	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
21938c2ecf20Sopenharmony_ci	u32 device_state = pdev->current_state;
21948c2ecf20Sopenharmony_ci	int recovery_state;
21958c2ecf20Sopenharmony_ci	int err;
21968c2ecf20Sopenharmony_ci
21978c2ecf20Sopenharmony_ci	printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
21988c2ecf20Sopenharmony_ci	    "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
21998c2ecf20Sopenharmony_ci	    device_state);
22008c2ecf20Sopenharmony_ci
22018c2ecf20Sopenharmony_ci	pci_set_power_state(pdev, PCI_D0);
22028c2ecf20Sopenharmony_ci	pci_enable_wake(pdev, PCI_D0, 0);
22038c2ecf20Sopenharmony_ci	pci_restore_state(pdev);
22048c2ecf20Sopenharmony_ci	ioc->pcidev = pdev;
22058c2ecf20Sopenharmony_ci	err = mpt_mapresources(ioc);
22068c2ecf20Sopenharmony_ci	if (err)
22078c2ecf20Sopenharmony_ci		return err;
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci	if (ioc->dma_mask == DMA_BIT_MASK(64)) {
22108c2ecf20Sopenharmony_ci		if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
22118c2ecf20Sopenharmony_ci			ioc->add_sge = &mpt_add_sge_64bit_1078;
22128c2ecf20Sopenharmony_ci		else
22138c2ecf20Sopenharmony_ci			ioc->add_sge = &mpt_add_sge_64bit;
22148c2ecf20Sopenharmony_ci		ioc->add_chain = &mpt_add_chain_64bit;
22158c2ecf20Sopenharmony_ci		ioc->sg_addr_size = 8;
22168c2ecf20Sopenharmony_ci	} else {
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_ci		ioc->add_sge = &mpt_add_sge;
22198c2ecf20Sopenharmony_ci		ioc->add_chain = &mpt_add_chain;
22208c2ecf20Sopenharmony_ci		ioc->sg_addr_size = 4;
22218c2ecf20Sopenharmony_ci	}
22228c2ecf20Sopenharmony_ci	ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_ci	printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
22258c2ecf20Sopenharmony_ci	    ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
22268c2ecf20Sopenharmony_ci	    CHIPREG_READ32(&ioc->chip->Doorbell));
22278c2ecf20Sopenharmony_ci
22288c2ecf20Sopenharmony_ci	/*
22298c2ecf20Sopenharmony_ci	 * Errata workaround for SAS pci express:
22308c2ecf20Sopenharmony_ci	 * Upon returning to the D0 state, the contents of the doorbell will be
22318c2ecf20Sopenharmony_ci	 * stale data, and this will incorrectly signal to the host driver that
22328c2ecf20Sopenharmony_ci	 * the firmware is ready to process mpt commands.   The workaround is
22338c2ecf20Sopenharmony_ci	 * to issue a diagnostic reset.
22348c2ecf20Sopenharmony_ci	 */
22358c2ecf20Sopenharmony_ci	if (ioc->bus_type == SAS && (pdev->device ==
22368c2ecf20Sopenharmony_ci	    MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
22378c2ecf20Sopenharmony_ci	    MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
22388c2ecf20Sopenharmony_ci		if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
22398c2ecf20Sopenharmony_ci			printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
22408c2ecf20Sopenharmony_ci			    ioc->name);
22418c2ecf20Sopenharmony_ci			goto out;
22428c2ecf20Sopenharmony_ci		}
22438c2ecf20Sopenharmony_ci	}
22448c2ecf20Sopenharmony_ci
22458c2ecf20Sopenharmony_ci	/* bring ioc to operational state */
22468c2ecf20Sopenharmony_ci	printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
22478c2ecf20Sopenharmony_ci	recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
22488c2ecf20Sopenharmony_ci						 CAN_SLEEP);
22498c2ecf20Sopenharmony_ci	if (recovery_state != 0)
22508c2ecf20Sopenharmony_ci		printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
22518c2ecf20Sopenharmony_ci		    "error:[%x]\n", ioc->name, recovery_state);
22528c2ecf20Sopenharmony_ci	else
22538c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT
22548c2ecf20Sopenharmony_ci		    "pci-resume: success\n", ioc->name);
22558c2ecf20Sopenharmony_ci out:
22568c2ecf20Sopenharmony_ci	return 0;
22578c2ecf20Sopenharmony_ci
22588c2ecf20Sopenharmony_ci}
22598c2ecf20Sopenharmony_ci#endif
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_cistatic int
22628c2ecf20Sopenharmony_cimpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
22638c2ecf20Sopenharmony_ci{
22648c2ecf20Sopenharmony_ci	if ((MptDriverClass[index] == MPTSPI_DRIVER &&
22658c2ecf20Sopenharmony_ci	     ioc->bus_type != SPI) ||
22668c2ecf20Sopenharmony_ci	    (MptDriverClass[index] == MPTFC_DRIVER &&
22678c2ecf20Sopenharmony_ci	     ioc->bus_type != FC) ||
22688c2ecf20Sopenharmony_ci	    (MptDriverClass[index] == MPTSAS_DRIVER &&
22698c2ecf20Sopenharmony_ci	     ioc->bus_type != SAS))
22708c2ecf20Sopenharmony_ci		/* make sure we only call the relevant reset handler
22718c2ecf20Sopenharmony_ci		 * for the bus */
22728c2ecf20Sopenharmony_ci		return 0;
22738c2ecf20Sopenharmony_ci	return (MptResetHandlers[index])(ioc, reset_phase);
22748c2ecf20Sopenharmony_ci}
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
22778c2ecf20Sopenharmony_ci/**
22788c2ecf20Sopenharmony_ci *	mpt_do_ioc_recovery - Initialize or recover MPT adapter.
22798c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT adapter structure
22808c2ecf20Sopenharmony_ci *	@reason: Event word / reason
22818c2ecf20Sopenharmony_ci *	@sleepFlag: Use schedule if CAN_SLEEP else use udelay.
22828c2ecf20Sopenharmony_ci *
22838c2ecf20Sopenharmony_ci *	This routine performs all the steps necessary to bring the IOC
22848c2ecf20Sopenharmony_ci *	to a OPERATIONAL state.
22858c2ecf20Sopenharmony_ci *
22868c2ecf20Sopenharmony_ci *	This routine also pre-fetches the LAN MAC address of a Fibre Channel
22878c2ecf20Sopenharmony_ci *	MPT adapter.
22888c2ecf20Sopenharmony_ci *
22898c2ecf20Sopenharmony_ci *	Returns:
22908c2ecf20Sopenharmony_ci *		 0 for success
22918c2ecf20Sopenharmony_ci *		-1 if failed to get board READY
22928c2ecf20Sopenharmony_ci *		-2 if READY but IOCFacts Failed
22938c2ecf20Sopenharmony_ci *		-3 if READY but PrimeIOCFifos Failed
22948c2ecf20Sopenharmony_ci *		-4 if READY but IOCInit Failed
22958c2ecf20Sopenharmony_ci *		-5 if failed to enable_device and/or request_selected_regions
22968c2ecf20Sopenharmony_ci *		-6 if failed to upload firmware
22978c2ecf20Sopenharmony_ci */
22988c2ecf20Sopenharmony_cistatic int
22998c2ecf20Sopenharmony_cimpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
23008c2ecf20Sopenharmony_ci{
23018c2ecf20Sopenharmony_ci	int	 hard_reset_done = 0;
23028c2ecf20Sopenharmony_ci	int	 alt_ioc_ready = 0;
23038c2ecf20Sopenharmony_ci	int	 hard;
23048c2ecf20Sopenharmony_ci	int	 rc=0;
23058c2ecf20Sopenharmony_ci	int	 ii;
23068c2ecf20Sopenharmony_ci	int	 ret = 0;
23078c2ecf20Sopenharmony_ci	int	 reset_alt_ioc_active = 0;
23088c2ecf20Sopenharmony_ci	int	 irq_allocated = 0;
23098c2ecf20Sopenharmony_ci	u8	*a;
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci	printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
23128c2ecf20Sopenharmony_ci	    reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_ci	/* Disable reply interrupts (also blocks FreeQ) */
23158c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
23168c2ecf20Sopenharmony_ci	ioc->active = 0;
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_ci	if (ioc->alt_ioc) {
23198c2ecf20Sopenharmony_ci		if (ioc->alt_ioc->active ||
23208c2ecf20Sopenharmony_ci		    reason == MPT_HOSTEVENT_IOC_RECOVER) {
23218c2ecf20Sopenharmony_ci			reset_alt_ioc_active = 1;
23228c2ecf20Sopenharmony_ci			/* Disable alt-IOC's reply interrupts
23238c2ecf20Sopenharmony_ci			 *  (and FreeQ) for a bit
23248c2ecf20Sopenharmony_ci			 **/
23258c2ecf20Sopenharmony_ci			CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
23268c2ecf20Sopenharmony_ci				0xFFFFFFFF);
23278c2ecf20Sopenharmony_ci			ioc->alt_ioc->active = 0;
23288c2ecf20Sopenharmony_ci		}
23298c2ecf20Sopenharmony_ci	}
23308c2ecf20Sopenharmony_ci
23318c2ecf20Sopenharmony_ci	hard = 1;
23328c2ecf20Sopenharmony_ci	if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
23338c2ecf20Sopenharmony_ci		hard = 0;
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_ci	if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
23368c2ecf20Sopenharmony_ci		if (hard_reset_done == -4) {
23378c2ecf20Sopenharmony_ci			printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
23388c2ecf20Sopenharmony_ci			    ioc->name);
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_ci			if (reset_alt_ioc_active && ioc->alt_ioc) {
23418c2ecf20Sopenharmony_ci				/* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
23428c2ecf20Sopenharmony_ci				dprintk(ioc, printk(MYIOC_s_INFO_FMT
23438c2ecf20Sopenharmony_ci				    "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
23448c2ecf20Sopenharmony_ci				CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
23458c2ecf20Sopenharmony_ci				ioc->alt_ioc->active = 1;
23468c2ecf20Sopenharmony_ci			}
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_ci		} else {
23498c2ecf20Sopenharmony_ci			printk(MYIOC_s_WARN_FMT
23508c2ecf20Sopenharmony_ci			    "NOT READY WARNING!\n", ioc->name);
23518c2ecf20Sopenharmony_ci		}
23528c2ecf20Sopenharmony_ci		ret = -1;
23538c2ecf20Sopenharmony_ci		goto out;
23548c2ecf20Sopenharmony_ci	}
23558c2ecf20Sopenharmony_ci
23568c2ecf20Sopenharmony_ci	/* hard_reset_done = 0 if a soft reset was performed
23578c2ecf20Sopenharmony_ci	 * and 1 if a hard reset was performed.
23588c2ecf20Sopenharmony_ci	 */
23598c2ecf20Sopenharmony_ci	if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
23608c2ecf20Sopenharmony_ci		if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
23618c2ecf20Sopenharmony_ci			alt_ioc_ready = 1;
23628c2ecf20Sopenharmony_ci		else
23638c2ecf20Sopenharmony_ci			printk(MYIOC_s_WARN_FMT
23648c2ecf20Sopenharmony_ci			    ": alt-ioc Not ready WARNING!\n",
23658c2ecf20Sopenharmony_ci			    ioc->alt_ioc->name);
23668c2ecf20Sopenharmony_ci	}
23678c2ecf20Sopenharmony_ci
23688c2ecf20Sopenharmony_ci	for (ii=0; ii<5; ii++) {
23698c2ecf20Sopenharmony_ci		/* Get IOC facts! Allow 5 retries */
23708c2ecf20Sopenharmony_ci		if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
23718c2ecf20Sopenharmony_ci			break;
23728c2ecf20Sopenharmony_ci	}
23738c2ecf20Sopenharmony_ci
23748c2ecf20Sopenharmony_ci
23758c2ecf20Sopenharmony_ci	if (ii == 5) {
23768c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
23778c2ecf20Sopenharmony_ci		    "Retry IocFacts failed rc=%x\n", ioc->name, rc));
23788c2ecf20Sopenharmony_ci		ret = -2;
23798c2ecf20Sopenharmony_ci	} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
23808c2ecf20Sopenharmony_ci		MptDisplayIocCapabilities(ioc);
23818c2ecf20Sopenharmony_ci	}
23828c2ecf20Sopenharmony_ci
23838c2ecf20Sopenharmony_ci	if (alt_ioc_ready) {
23848c2ecf20Sopenharmony_ci		if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
23858c2ecf20Sopenharmony_ci			dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
23868c2ecf20Sopenharmony_ci			    "Initial Alt IocFacts failed rc=%x\n",
23878c2ecf20Sopenharmony_ci			    ioc->name, rc));
23888c2ecf20Sopenharmony_ci			/* Retry - alt IOC was initialized once
23898c2ecf20Sopenharmony_ci			 */
23908c2ecf20Sopenharmony_ci			rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
23918c2ecf20Sopenharmony_ci		}
23928c2ecf20Sopenharmony_ci		if (rc) {
23938c2ecf20Sopenharmony_ci			dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
23948c2ecf20Sopenharmony_ci			    "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
23958c2ecf20Sopenharmony_ci			alt_ioc_ready = 0;
23968c2ecf20Sopenharmony_ci			reset_alt_ioc_active = 0;
23978c2ecf20Sopenharmony_ci		} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
23988c2ecf20Sopenharmony_ci			MptDisplayIocCapabilities(ioc->alt_ioc);
23998c2ecf20Sopenharmony_ci		}
24008c2ecf20Sopenharmony_ci	}
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci	if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
24038c2ecf20Sopenharmony_ci	    (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
24048c2ecf20Sopenharmony_ci		pci_release_selected_regions(ioc->pcidev, ioc->bars);
24058c2ecf20Sopenharmony_ci		ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
24068c2ecf20Sopenharmony_ci		    IORESOURCE_IO);
24078c2ecf20Sopenharmony_ci		if (pci_enable_device(ioc->pcidev))
24088c2ecf20Sopenharmony_ci			return -5;
24098c2ecf20Sopenharmony_ci		if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
24108c2ecf20Sopenharmony_ci			"mpt"))
24118c2ecf20Sopenharmony_ci			return -5;
24128c2ecf20Sopenharmony_ci	}
24138c2ecf20Sopenharmony_ci
24148c2ecf20Sopenharmony_ci	/*
24158c2ecf20Sopenharmony_ci	 * Device is reset now. It must have de-asserted the interrupt line
24168c2ecf20Sopenharmony_ci	 * (if it was asserted) and it should be safe to register for the
24178c2ecf20Sopenharmony_ci	 * interrupt now.
24188c2ecf20Sopenharmony_ci	 */
24198c2ecf20Sopenharmony_ci	if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
24208c2ecf20Sopenharmony_ci		ioc->pci_irq = -1;
24218c2ecf20Sopenharmony_ci		if (ioc->pcidev->irq) {
24228c2ecf20Sopenharmony_ci			if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
24238c2ecf20Sopenharmony_ci				printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
24248c2ecf20Sopenharmony_ci				    ioc->name);
24258c2ecf20Sopenharmony_ci			else
24268c2ecf20Sopenharmony_ci				ioc->msi_enable = 0;
24278c2ecf20Sopenharmony_ci			rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
24288c2ecf20Sopenharmony_ci			    IRQF_SHARED, ioc->name, ioc);
24298c2ecf20Sopenharmony_ci			if (rc < 0) {
24308c2ecf20Sopenharmony_ci				printk(MYIOC_s_ERR_FMT "Unable to allocate "
24318c2ecf20Sopenharmony_ci				    "interrupt %d!\n",
24328c2ecf20Sopenharmony_ci				    ioc->name, ioc->pcidev->irq);
24338c2ecf20Sopenharmony_ci				if (ioc->msi_enable)
24348c2ecf20Sopenharmony_ci					pci_disable_msi(ioc->pcidev);
24358c2ecf20Sopenharmony_ci				ret = -EBUSY;
24368c2ecf20Sopenharmony_ci				goto out;
24378c2ecf20Sopenharmony_ci			}
24388c2ecf20Sopenharmony_ci			irq_allocated = 1;
24398c2ecf20Sopenharmony_ci			ioc->pci_irq = ioc->pcidev->irq;
24408c2ecf20Sopenharmony_ci			pci_set_master(ioc->pcidev);		/* ?? */
24418c2ecf20Sopenharmony_ci			pci_set_drvdata(ioc->pcidev, ioc);
24428c2ecf20Sopenharmony_ci			dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
24438c2ecf20Sopenharmony_ci			    "installed at interrupt %d\n", ioc->name,
24448c2ecf20Sopenharmony_ci			    ioc->pcidev->irq));
24458c2ecf20Sopenharmony_ci		}
24468c2ecf20Sopenharmony_ci	}
24478c2ecf20Sopenharmony_ci
24488c2ecf20Sopenharmony_ci	/* Prime reply & request queues!
24498c2ecf20Sopenharmony_ci	 * (mucho alloc's) Must be done prior to
24508c2ecf20Sopenharmony_ci	 * init as upper addresses are needed for init.
24518c2ecf20Sopenharmony_ci	 * If fails, continue with alt-ioc processing
24528c2ecf20Sopenharmony_ci	 */
24538c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
24548c2ecf20Sopenharmony_ci	    ioc->name));
24558c2ecf20Sopenharmony_ci	if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
24568c2ecf20Sopenharmony_ci		ret = -3;
24578c2ecf20Sopenharmony_ci
24588c2ecf20Sopenharmony_ci	/* May need to check/upload firmware & data here!
24598c2ecf20Sopenharmony_ci	 * If fails, continue with alt-ioc processing
24608c2ecf20Sopenharmony_ci	 */
24618c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
24628c2ecf20Sopenharmony_ci	    ioc->name));
24638c2ecf20Sopenharmony_ci	if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
24648c2ecf20Sopenharmony_ci		ret = -4;
24658c2ecf20Sopenharmony_ci// NEW!
24668c2ecf20Sopenharmony_ci	if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
24678c2ecf20Sopenharmony_ci		printk(MYIOC_s_WARN_FMT
24688c2ecf20Sopenharmony_ci		    ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
24698c2ecf20Sopenharmony_ci		    ioc->alt_ioc->name, rc);
24708c2ecf20Sopenharmony_ci		alt_ioc_ready = 0;
24718c2ecf20Sopenharmony_ci		reset_alt_ioc_active = 0;
24728c2ecf20Sopenharmony_ci	}
24738c2ecf20Sopenharmony_ci
24748c2ecf20Sopenharmony_ci	if (alt_ioc_ready) {
24758c2ecf20Sopenharmony_ci		if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
24768c2ecf20Sopenharmony_ci			alt_ioc_ready = 0;
24778c2ecf20Sopenharmony_ci			reset_alt_ioc_active = 0;
24788c2ecf20Sopenharmony_ci			printk(MYIOC_s_WARN_FMT
24798c2ecf20Sopenharmony_ci				": alt-ioc: (%d) init failure WARNING!\n",
24808c2ecf20Sopenharmony_ci					ioc->alt_ioc->name, rc);
24818c2ecf20Sopenharmony_ci		}
24828c2ecf20Sopenharmony_ci	}
24838c2ecf20Sopenharmony_ci
24848c2ecf20Sopenharmony_ci	if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
24858c2ecf20Sopenharmony_ci		if (ioc->upload_fw) {
24868c2ecf20Sopenharmony_ci			ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
24878c2ecf20Sopenharmony_ci			    "firmware upload required!\n", ioc->name));
24888c2ecf20Sopenharmony_ci
24898c2ecf20Sopenharmony_ci			/* Controller is not operational, cannot do upload
24908c2ecf20Sopenharmony_ci			 */
24918c2ecf20Sopenharmony_ci			if (ret == 0) {
24928c2ecf20Sopenharmony_ci				rc = mpt_do_upload(ioc, sleepFlag);
24938c2ecf20Sopenharmony_ci				if (rc == 0) {
24948c2ecf20Sopenharmony_ci					if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
24958c2ecf20Sopenharmony_ci						/*
24968c2ecf20Sopenharmony_ci						 * Maintain only one pointer to FW memory
24978c2ecf20Sopenharmony_ci						 * so there will not be two attempt to
24988c2ecf20Sopenharmony_ci						 * downloadboot onboard dual function
24998c2ecf20Sopenharmony_ci						 * chips (mpt_adapter_disable,
25008c2ecf20Sopenharmony_ci						 * mpt_diag_reset)
25018c2ecf20Sopenharmony_ci						 */
25028c2ecf20Sopenharmony_ci						ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
25038c2ecf20Sopenharmony_ci						    "mpt_upload:  alt_%s has cached_fw=%p \n",
25048c2ecf20Sopenharmony_ci						    ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
25058c2ecf20Sopenharmony_ci						ioc->cached_fw = NULL;
25068c2ecf20Sopenharmony_ci					}
25078c2ecf20Sopenharmony_ci				} else {
25088c2ecf20Sopenharmony_ci					printk(MYIOC_s_WARN_FMT
25098c2ecf20Sopenharmony_ci					    "firmware upload failure!\n", ioc->name);
25108c2ecf20Sopenharmony_ci					ret = -6;
25118c2ecf20Sopenharmony_ci				}
25128c2ecf20Sopenharmony_ci			}
25138c2ecf20Sopenharmony_ci		}
25148c2ecf20Sopenharmony_ci	}
25158c2ecf20Sopenharmony_ci
25168c2ecf20Sopenharmony_ci	/*  Enable MPT base driver management of EventNotification
25178c2ecf20Sopenharmony_ci	 *  and EventAck handling.
25188c2ecf20Sopenharmony_ci	 */
25198c2ecf20Sopenharmony_ci	if ((ret == 0) && (!ioc->facts.EventState)) {
25208c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
25218c2ecf20Sopenharmony_ci			"SendEventNotification\n",
25228c2ecf20Sopenharmony_ci		    ioc->name));
25238c2ecf20Sopenharmony_ci		ret = SendEventNotification(ioc, 1, sleepFlag);	/* 1=Enable */
25248c2ecf20Sopenharmony_ci	}
25258c2ecf20Sopenharmony_ci
25268c2ecf20Sopenharmony_ci	if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
25278c2ecf20Sopenharmony_ci		rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_ci	if (ret == 0) {
25308c2ecf20Sopenharmony_ci		/* Enable! (reply interrupt) */
25318c2ecf20Sopenharmony_ci		CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
25328c2ecf20Sopenharmony_ci		ioc->active = 1;
25338c2ecf20Sopenharmony_ci	}
25348c2ecf20Sopenharmony_ci	if (rc == 0) {	/* alt ioc */
25358c2ecf20Sopenharmony_ci		if (reset_alt_ioc_active && ioc->alt_ioc) {
25368c2ecf20Sopenharmony_ci			/* (re)Enable alt-IOC! (reply interrupt) */
25378c2ecf20Sopenharmony_ci			dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
25388c2ecf20Sopenharmony_ci				"reply irq re-enabled\n",
25398c2ecf20Sopenharmony_ci				ioc->alt_ioc->name));
25408c2ecf20Sopenharmony_ci			CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
25418c2ecf20Sopenharmony_ci				MPI_HIM_DIM);
25428c2ecf20Sopenharmony_ci			ioc->alt_ioc->active = 1;
25438c2ecf20Sopenharmony_ci		}
25448c2ecf20Sopenharmony_ci	}
25458c2ecf20Sopenharmony_ci
25468c2ecf20Sopenharmony_ci
25478c2ecf20Sopenharmony_ci	/*	Add additional "reason" check before call to GetLanConfigPages
25488c2ecf20Sopenharmony_ci	 *	(combined with GetIoUnitPage2 call).  This prevents a somewhat
25498c2ecf20Sopenharmony_ci	 *	recursive scenario; GetLanConfigPages times out, timer expired
25508c2ecf20Sopenharmony_ci	 *	routine calls HardResetHandler, which calls into here again,
25518c2ecf20Sopenharmony_ci	 *	and we try GetLanConfigPages again...
25528c2ecf20Sopenharmony_ci	 */
25538c2ecf20Sopenharmony_ci	if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_ci		/*
25568c2ecf20Sopenharmony_ci		 * Initialize link list for inactive raid volumes.
25578c2ecf20Sopenharmony_ci		 */
25588c2ecf20Sopenharmony_ci		mutex_init(&ioc->raid_data.inactive_list_mutex);
25598c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
25608c2ecf20Sopenharmony_ci
25618c2ecf20Sopenharmony_ci		switch (ioc->bus_type) {
25628c2ecf20Sopenharmony_ci
25638c2ecf20Sopenharmony_ci		case SAS:
25648c2ecf20Sopenharmony_ci			/* clear persistency table */
25658c2ecf20Sopenharmony_ci			if(ioc->facts.IOCExceptions &
25668c2ecf20Sopenharmony_ci			    MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
25678c2ecf20Sopenharmony_ci				ret = mptbase_sas_persist_operation(ioc,
25688c2ecf20Sopenharmony_ci				    MPI_SAS_OP_CLEAR_NOT_PRESENT);
25698c2ecf20Sopenharmony_ci				if(ret != 0)
25708c2ecf20Sopenharmony_ci					goto out;
25718c2ecf20Sopenharmony_ci			}
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci			/* Find IM volumes
25748c2ecf20Sopenharmony_ci			 */
25758c2ecf20Sopenharmony_ci			mpt_findImVolumes(ioc);
25768c2ecf20Sopenharmony_ci
25778c2ecf20Sopenharmony_ci			/* Check, and possibly reset, the coalescing value
25788c2ecf20Sopenharmony_ci			 */
25798c2ecf20Sopenharmony_ci			mpt_read_ioc_pg_1(ioc);
25808c2ecf20Sopenharmony_ci
25818c2ecf20Sopenharmony_ci			break;
25828c2ecf20Sopenharmony_ci
25838c2ecf20Sopenharmony_ci		case FC:
25848c2ecf20Sopenharmony_ci			if ((ioc->pfacts[0].ProtocolFlags &
25858c2ecf20Sopenharmony_ci				MPI_PORTFACTS_PROTOCOL_LAN) &&
25868c2ecf20Sopenharmony_ci			    (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
25878c2ecf20Sopenharmony_ci				/*
25888c2ecf20Sopenharmony_ci				 *  Pre-fetch the ports LAN MAC address!
25898c2ecf20Sopenharmony_ci				 *  (LANPage1_t stuff)
25908c2ecf20Sopenharmony_ci				 */
25918c2ecf20Sopenharmony_ci				(void) GetLanConfigPages(ioc);
25928c2ecf20Sopenharmony_ci				a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
25938c2ecf20Sopenharmony_ci				dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
25948c2ecf20Sopenharmony_ci					"LanAddr = %pMR\n", ioc->name, a));
25958c2ecf20Sopenharmony_ci			}
25968c2ecf20Sopenharmony_ci			break;
25978c2ecf20Sopenharmony_ci
25988c2ecf20Sopenharmony_ci		case SPI:
25998c2ecf20Sopenharmony_ci			/* Get NVRAM and adapter maximums from SPP 0 and 2
26008c2ecf20Sopenharmony_ci			 */
26018c2ecf20Sopenharmony_ci			mpt_GetScsiPortSettings(ioc, 0);
26028c2ecf20Sopenharmony_ci
26038c2ecf20Sopenharmony_ci			/* Get version and length of SDP 1
26048c2ecf20Sopenharmony_ci			 */
26058c2ecf20Sopenharmony_ci			mpt_readScsiDevicePageHeaders(ioc, 0);
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_ci			/* Find IM volumes
26088c2ecf20Sopenharmony_ci			 */
26098c2ecf20Sopenharmony_ci			if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
26108c2ecf20Sopenharmony_ci				mpt_findImVolumes(ioc);
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ci			/* Check, and possibly reset, the coalescing value
26138c2ecf20Sopenharmony_ci			 */
26148c2ecf20Sopenharmony_ci			mpt_read_ioc_pg_1(ioc);
26158c2ecf20Sopenharmony_ci
26168c2ecf20Sopenharmony_ci			mpt_read_ioc_pg_4(ioc);
26178c2ecf20Sopenharmony_ci
26188c2ecf20Sopenharmony_ci			break;
26198c2ecf20Sopenharmony_ci		}
26208c2ecf20Sopenharmony_ci
26218c2ecf20Sopenharmony_ci		GetIoUnitPage2(ioc);
26228c2ecf20Sopenharmony_ci		mpt_get_manufacturing_pg_0(ioc);
26238c2ecf20Sopenharmony_ci	}
26248c2ecf20Sopenharmony_ci
26258c2ecf20Sopenharmony_ci out:
26268c2ecf20Sopenharmony_ci	if ((ret != 0) && irq_allocated) {
26278c2ecf20Sopenharmony_ci		free_irq(ioc->pci_irq, ioc);
26288c2ecf20Sopenharmony_ci		if (ioc->msi_enable)
26298c2ecf20Sopenharmony_ci			pci_disable_msi(ioc->pcidev);
26308c2ecf20Sopenharmony_ci	}
26318c2ecf20Sopenharmony_ci	return ret;
26328c2ecf20Sopenharmony_ci}
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
26358c2ecf20Sopenharmony_ci/**
26368c2ecf20Sopenharmony_ci *	mpt_detect_bound_ports - Search for matching PCI bus/dev_function
26378c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT adapter structure
26388c2ecf20Sopenharmony_ci *	@pdev: Pointer to (struct pci_dev) structure
26398c2ecf20Sopenharmony_ci *
26408c2ecf20Sopenharmony_ci *	Search for PCI bus/dev_function which matches
26418c2ecf20Sopenharmony_ci *	PCI bus/dev_function (+/-1) for newly discovered 929,
26428c2ecf20Sopenharmony_ci *	929X, 1030 or 1035.
26438c2ecf20Sopenharmony_ci *
26448c2ecf20Sopenharmony_ci *	If match on PCI dev_function +/-1 is found, bind the two MPT adapters
26458c2ecf20Sopenharmony_ci *	using alt_ioc pointer fields in their %MPT_ADAPTER structures.
26468c2ecf20Sopenharmony_ci */
26478c2ecf20Sopenharmony_cistatic void
26488c2ecf20Sopenharmony_cimpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
26498c2ecf20Sopenharmony_ci{
26508c2ecf20Sopenharmony_ci	struct pci_dev *peer=NULL;
26518c2ecf20Sopenharmony_ci	unsigned int slot = PCI_SLOT(pdev->devfn);
26528c2ecf20Sopenharmony_ci	unsigned int func = PCI_FUNC(pdev->devfn);
26538c2ecf20Sopenharmony_ci	MPT_ADAPTER *ioc_srch;
26548c2ecf20Sopenharmony_ci
26558c2ecf20Sopenharmony_ci	dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
26568c2ecf20Sopenharmony_ci	    " searching for devfn match on %x or %x\n",
26578c2ecf20Sopenharmony_ci	    ioc->name, pci_name(pdev), pdev->bus->number,
26588c2ecf20Sopenharmony_ci	    pdev->devfn, func-1, func+1));
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_ci	peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
26618c2ecf20Sopenharmony_ci	if (!peer) {
26628c2ecf20Sopenharmony_ci		peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
26638c2ecf20Sopenharmony_ci		if (!peer)
26648c2ecf20Sopenharmony_ci			return;
26658c2ecf20Sopenharmony_ci	}
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_ci	list_for_each_entry(ioc_srch, &ioc_list, list) {
26688c2ecf20Sopenharmony_ci		struct pci_dev *_pcidev = ioc_srch->pcidev;
26698c2ecf20Sopenharmony_ci		if (_pcidev == peer) {
26708c2ecf20Sopenharmony_ci			/* Paranoia checks */
26718c2ecf20Sopenharmony_ci			if (ioc->alt_ioc != NULL) {
26728c2ecf20Sopenharmony_ci				printk(MYIOC_s_WARN_FMT
26738c2ecf20Sopenharmony_ci				    "Oops, already bound (%s <==> %s)!\n",
26748c2ecf20Sopenharmony_ci				    ioc->name, ioc->name, ioc->alt_ioc->name);
26758c2ecf20Sopenharmony_ci				break;
26768c2ecf20Sopenharmony_ci			} else if (ioc_srch->alt_ioc != NULL) {
26778c2ecf20Sopenharmony_ci				printk(MYIOC_s_WARN_FMT
26788c2ecf20Sopenharmony_ci				    "Oops, already bound (%s <==> %s)!\n",
26798c2ecf20Sopenharmony_ci				    ioc_srch->name, ioc_srch->name,
26808c2ecf20Sopenharmony_ci				    ioc_srch->alt_ioc->name);
26818c2ecf20Sopenharmony_ci				break;
26828c2ecf20Sopenharmony_ci			}
26838c2ecf20Sopenharmony_ci			dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
26848c2ecf20Sopenharmony_ci				"FOUND! binding %s <==> %s\n",
26858c2ecf20Sopenharmony_ci				ioc->name, ioc->name, ioc_srch->name));
26868c2ecf20Sopenharmony_ci			ioc_srch->alt_ioc = ioc;
26878c2ecf20Sopenharmony_ci			ioc->alt_ioc = ioc_srch;
26888c2ecf20Sopenharmony_ci		}
26898c2ecf20Sopenharmony_ci	}
26908c2ecf20Sopenharmony_ci	pci_dev_put(peer);
26918c2ecf20Sopenharmony_ci}
26928c2ecf20Sopenharmony_ci
26938c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
26948c2ecf20Sopenharmony_ci/**
26958c2ecf20Sopenharmony_ci *	mpt_adapter_disable - Disable misbehaving MPT adapter.
26968c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT adapter structure
26978c2ecf20Sopenharmony_ci */
26988c2ecf20Sopenharmony_cistatic void
26998c2ecf20Sopenharmony_cimpt_adapter_disable(MPT_ADAPTER *ioc)
27008c2ecf20Sopenharmony_ci{
27018c2ecf20Sopenharmony_ci	int sz;
27028c2ecf20Sopenharmony_ci	int ret;
27038c2ecf20Sopenharmony_ci
27048c2ecf20Sopenharmony_ci	if (ioc->cached_fw != NULL) {
27058c2ecf20Sopenharmony_ci		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
27068c2ecf20Sopenharmony_ci			"%s: Pushing FW onto adapter\n", __func__, ioc->name));
27078c2ecf20Sopenharmony_ci		if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
27088c2ecf20Sopenharmony_ci		    ioc->cached_fw, CAN_SLEEP)) < 0) {
27098c2ecf20Sopenharmony_ci			printk(MYIOC_s_WARN_FMT
27108c2ecf20Sopenharmony_ci			    ": firmware downloadboot failure (%d)!\n",
27118c2ecf20Sopenharmony_ci			    ioc->name, ret);
27128c2ecf20Sopenharmony_ci		}
27138c2ecf20Sopenharmony_ci	}
27148c2ecf20Sopenharmony_ci
27158c2ecf20Sopenharmony_ci	/*
27168c2ecf20Sopenharmony_ci	 * Put the controller into ready state (if its not already)
27178c2ecf20Sopenharmony_ci	 */
27188c2ecf20Sopenharmony_ci	if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
27198c2ecf20Sopenharmony_ci		if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
27208c2ecf20Sopenharmony_ci		    CAN_SLEEP)) {
27218c2ecf20Sopenharmony_ci			if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
27228c2ecf20Sopenharmony_ci				printk(MYIOC_s_ERR_FMT "%s:  IOC msg unit "
27238c2ecf20Sopenharmony_ci				    "reset failed to put ioc in ready state!\n",
27248c2ecf20Sopenharmony_ci				    ioc->name, __func__);
27258c2ecf20Sopenharmony_ci		} else
27268c2ecf20Sopenharmony_ci			printk(MYIOC_s_ERR_FMT "%s:  IOC msg unit reset "
27278c2ecf20Sopenharmony_ci			    "failed!\n", ioc->name, __func__);
27288c2ecf20Sopenharmony_ci	}
27298c2ecf20Sopenharmony_ci
27308c2ecf20Sopenharmony_ci
27318c2ecf20Sopenharmony_ci	/* Disable adapter interrupts! */
27328c2ecf20Sopenharmony_ci	synchronize_irq(ioc->pcidev->irq);
27338c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
27348c2ecf20Sopenharmony_ci	ioc->active = 0;
27358c2ecf20Sopenharmony_ci
27368c2ecf20Sopenharmony_ci	/* Clear any lingering interrupt */
27378c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
27388c2ecf20Sopenharmony_ci	CHIPREG_READ32(&ioc->chip->IntStatus);
27398c2ecf20Sopenharmony_ci
27408c2ecf20Sopenharmony_ci	if (ioc->alloc != NULL) {
27418c2ecf20Sopenharmony_ci		sz = ioc->alloc_sz;
27428c2ecf20Sopenharmony_ci		dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free  @ %p, sz=%d bytes\n",
27438c2ecf20Sopenharmony_ci		    ioc->name, ioc->alloc, ioc->alloc_sz));
27448c2ecf20Sopenharmony_ci		dma_free_coherent(&ioc->pcidev->dev, sz, ioc->alloc,
27458c2ecf20Sopenharmony_ci				ioc->alloc_dma);
27468c2ecf20Sopenharmony_ci		ioc->reply_frames = NULL;
27478c2ecf20Sopenharmony_ci		ioc->req_frames = NULL;
27488c2ecf20Sopenharmony_ci		ioc->alloc = NULL;
27498c2ecf20Sopenharmony_ci		ioc->alloc_total -= sz;
27508c2ecf20Sopenharmony_ci	}
27518c2ecf20Sopenharmony_ci
27528c2ecf20Sopenharmony_ci	if (ioc->sense_buf_pool != NULL) {
27538c2ecf20Sopenharmony_ci		sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
27548c2ecf20Sopenharmony_ci		dma_free_coherent(&ioc->pcidev->dev, sz, ioc->sense_buf_pool,
27558c2ecf20Sopenharmony_ci				ioc->sense_buf_pool_dma);
27568c2ecf20Sopenharmony_ci		ioc->sense_buf_pool = NULL;
27578c2ecf20Sopenharmony_ci		ioc->alloc_total -= sz;
27588c2ecf20Sopenharmony_ci	}
27598c2ecf20Sopenharmony_ci
27608c2ecf20Sopenharmony_ci	if (ioc->events != NULL){
27618c2ecf20Sopenharmony_ci		sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
27628c2ecf20Sopenharmony_ci		kfree(ioc->events);
27638c2ecf20Sopenharmony_ci		ioc->events = NULL;
27648c2ecf20Sopenharmony_ci		ioc->alloc_total -= sz;
27658c2ecf20Sopenharmony_ci	}
27668c2ecf20Sopenharmony_ci
27678c2ecf20Sopenharmony_ci	mpt_free_fw_memory(ioc);
27688c2ecf20Sopenharmony_ci
27698c2ecf20Sopenharmony_ci	kfree(ioc->spi_data.nvram);
27708c2ecf20Sopenharmony_ci	mpt_inactive_raid_list_free(ioc);
27718c2ecf20Sopenharmony_ci	kfree(ioc->raid_data.pIocPg2);
27728c2ecf20Sopenharmony_ci	kfree(ioc->raid_data.pIocPg3);
27738c2ecf20Sopenharmony_ci	ioc->spi_data.nvram = NULL;
27748c2ecf20Sopenharmony_ci	ioc->raid_data.pIocPg3 = NULL;
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_ci	if (ioc->spi_data.pIocPg4 != NULL) {
27778c2ecf20Sopenharmony_ci		sz = ioc->spi_data.IocPg4Sz;
27788c2ecf20Sopenharmony_ci		pci_free_consistent(ioc->pcidev, sz,
27798c2ecf20Sopenharmony_ci			ioc->spi_data.pIocPg4,
27808c2ecf20Sopenharmony_ci			ioc->spi_data.IocPg4_dma);
27818c2ecf20Sopenharmony_ci		ioc->spi_data.pIocPg4 = NULL;
27828c2ecf20Sopenharmony_ci		ioc->alloc_total -= sz;
27838c2ecf20Sopenharmony_ci	}
27848c2ecf20Sopenharmony_ci
27858c2ecf20Sopenharmony_ci	if (ioc->ReqToChain != NULL) {
27868c2ecf20Sopenharmony_ci		kfree(ioc->ReqToChain);
27878c2ecf20Sopenharmony_ci		kfree(ioc->RequestNB);
27888c2ecf20Sopenharmony_ci		ioc->ReqToChain = NULL;
27898c2ecf20Sopenharmony_ci	}
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	kfree(ioc->ChainToChain);
27928c2ecf20Sopenharmony_ci	ioc->ChainToChain = NULL;
27938c2ecf20Sopenharmony_ci
27948c2ecf20Sopenharmony_ci	if (ioc->HostPageBuffer != NULL) {
27958c2ecf20Sopenharmony_ci		if((ret = mpt_host_page_access_control(ioc,
27968c2ecf20Sopenharmony_ci		    MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
27978c2ecf20Sopenharmony_ci			printk(MYIOC_s_ERR_FMT
27988c2ecf20Sopenharmony_ci			   ": %s: host page buffers free failed (%d)!\n",
27998c2ecf20Sopenharmony_ci			    ioc->name, __func__, ret);
28008c2ecf20Sopenharmony_ci		}
28018c2ecf20Sopenharmony_ci		dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
28028c2ecf20Sopenharmony_ci			"HostPageBuffer free  @ %p, sz=%d bytes\n",
28038c2ecf20Sopenharmony_ci			ioc->name, ioc->HostPageBuffer,
28048c2ecf20Sopenharmony_ci			ioc->HostPageBuffer_sz));
28058c2ecf20Sopenharmony_ci		dma_free_coherent(&ioc->pcidev->dev, ioc->HostPageBuffer_sz,
28068c2ecf20Sopenharmony_ci		    ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
28078c2ecf20Sopenharmony_ci		ioc->HostPageBuffer = NULL;
28088c2ecf20Sopenharmony_ci		ioc->HostPageBuffer_sz = 0;
28098c2ecf20Sopenharmony_ci		ioc->alloc_total -= ioc->HostPageBuffer_sz;
28108c2ecf20Sopenharmony_ci	}
28118c2ecf20Sopenharmony_ci
28128c2ecf20Sopenharmony_ci	pci_set_drvdata(ioc->pcidev, NULL);
28138c2ecf20Sopenharmony_ci}
28148c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
28158c2ecf20Sopenharmony_ci/**
28168c2ecf20Sopenharmony_ci *	mpt_adapter_dispose - Free all resources associated with an MPT adapter
28178c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT adapter structure
28188c2ecf20Sopenharmony_ci *
28198c2ecf20Sopenharmony_ci *	This routine unregisters h/w resources and frees all alloc'd memory
28208c2ecf20Sopenharmony_ci *	associated with a MPT adapter structure.
28218c2ecf20Sopenharmony_ci */
28228c2ecf20Sopenharmony_cistatic void
28238c2ecf20Sopenharmony_cimpt_adapter_dispose(MPT_ADAPTER *ioc)
28248c2ecf20Sopenharmony_ci{
28258c2ecf20Sopenharmony_ci	int sz_first, sz_last;
28268c2ecf20Sopenharmony_ci
28278c2ecf20Sopenharmony_ci	if (ioc == NULL)
28288c2ecf20Sopenharmony_ci		return;
28298c2ecf20Sopenharmony_ci
28308c2ecf20Sopenharmony_ci	sz_first = ioc->alloc_total;
28318c2ecf20Sopenharmony_ci
28328c2ecf20Sopenharmony_ci	mpt_adapter_disable(ioc);
28338c2ecf20Sopenharmony_ci
28348c2ecf20Sopenharmony_ci	if (ioc->pci_irq != -1) {
28358c2ecf20Sopenharmony_ci		free_irq(ioc->pci_irq, ioc);
28368c2ecf20Sopenharmony_ci		if (ioc->msi_enable)
28378c2ecf20Sopenharmony_ci			pci_disable_msi(ioc->pcidev);
28388c2ecf20Sopenharmony_ci		ioc->pci_irq = -1;
28398c2ecf20Sopenharmony_ci	}
28408c2ecf20Sopenharmony_ci
28418c2ecf20Sopenharmony_ci	if (ioc->memmap != NULL) {
28428c2ecf20Sopenharmony_ci		iounmap(ioc->memmap);
28438c2ecf20Sopenharmony_ci		ioc->memmap = NULL;
28448c2ecf20Sopenharmony_ci	}
28458c2ecf20Sopenharmony_ci
28468c2ecf20Sopenharmony_ci	pci_disable_device(ioc->pcidev);
28478c2ecf20Sopenharmony_ci	pci_release_selected_regions(ioc->pcidev, ioc->bars);
28488c2ecf20Sopenharmony_ci
28498c2ecf20Sopenharmony_ci	/*  Zap the adapter lookup ptr!  */
28508c2ecf20Sopenharmony_ci	list_del(&ioc->list);
28518c2ecf20Sopenharmony_ci
28528c2ecf20Sopenharmony_ci	sz_last = ioc->alloc_total;
28538c2ecf20Sopenharmony_ci	dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
28548c2ecf20Sopenharmony_ci	    ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
28558c2ecf20Sopenharmony_ci
28568c2ecf20Sopenharmony_ci	if (ioc->alt_ioc)
28578c2ecf20Sopenharmony_ci		ioc->alt_ioc->alt_ioc = NULL;
28588c2ecf20Sopenharmony_ci
28598c2ecf20Sopenharmony_ci	kfree(ioc);
28608c2ecf20Sopenharmony_ci}
28618c2ecf20Sopenharmony_ci
28628c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
28638c2ecf20Sopenharmony_ci/**
28648c2ecf20Sopenharmony_ci *	MptDisplayIocCapabilities - Disply IOC's capabilities.
28658c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT adapter structure
28668c2ecf20Sopenharmony_ci */
28678c2ecf20Sopenharmony_cistatic void
28688c2ecf20Sopenharmony_ciMptDisplayIocCapabilities(MPT_ADAPTER *ioc)
28698c2ecf20Sopenharmony_ci{
28708c2ecf20Sopenharmony_ci	int i = 0;
28718c2ecf20Sopenharmony_ci
28728c2ecf20Sopenharmony_ci	printk(KERN_INFO "%s: ", ioc->name);
28738c2ecf20Sopenharmony_ci	if (ioc->prod_name)
28748c2ecf20Sopenharmony_ci		pr_cont("%s: ", ioc->prod_name);
28758c2ecf20Sopenharmony_ci	pr_cont("Capabilities={");
28768c2ecf20Sopenharmony_ci
28778c2ecf20Sopenharmony_ci	if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
28788c2ecf20Sopenharmony_ci		pr_cont("Initiator");
28798c2ecf20Sopenharmony_ci		i++;
28808c2ecf20Sopenharmony_ci	}
28818c2ecf20Sopenharmony_ci
28828c2ecf20Sopenharmony_ci	if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
28838c2ecf20Sopenharmony_ci		pr_cont("%sTarget", i ? "," : "");
28848c2ecf20Sopenharmony_ci		i++;
28858c2ecf20Sopenharmony_ci	}
28868c2ecf20Sopenharmony_ci
28878c2ecf20Sopenharmony_ci	if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
28888c2ecf20Sopenharmony_ci		pr_cont("%sLAN", i ? "," : "");
28898c2ecf20Sopenharmony_ci		i++;
28908c2ecf20Sopenharmony_ci	}
28918c2ecf20Sopenharmony_ci
28928c2ecf20Sopenharmony_ci#if 0
28938c2ecf20Sopenharmony_ci	/*
28948c2ecf20Sopenharmony_ci	 *  This would probably evoke more questions than it's worth
28958c2ecf20Sopenharmony_ci	 */
28968c2ecf20Sopenharmony_ci	if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
28978c2ecf20Sopenharmony_ci		pr_cont("%sLogBusAddr", i ? "," : "");
28988c2ecf20Sopenharmony_ci		i++;
28998c2ecf20Sopenharmony_ci	}
29008c2ecf20Sopenharmony_ci#endif
29018c2ecf20Sopenharmony_ci
29028c2ecf20Sopenharmony_ci	pr_cont("}\n");
29038c2ecf20Sopenharmony_ci}
29048c2ecf20Sopenharmony_ci
29058c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
29068c2ecf20Sopenharmony_ci/**
29078c2ecf20Sopenharmony_ci *	MakeIocReady - Get IOC to a READY state, using KickStart if needed.
29088c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
29098c2ecf20Sopenharmony_ci *	@force: Force hard KickStart of IOC
29108c2ecf20Sopenharmony_ci *	@sleepFlag: Specifies whether the process can sleep
29118c2ecf20Sopenharmony_ci *
29128c2ecf20Sopenharmony_ci *	Returns:
29138c2ecf20Sopenharmony_ci *		 1 - DIAG reset and READY
29148c2ecf20Sopenharmony_ci *		 0 - READY initially OR soft reset and READY
29158c2ecf20Sopenharmony_ci *		-1 - Any failure on KickStart
29168c2ecf20Sopenharmony_ci *		-2 - Msg Unit Reset Failed
29178c2ecf20Sopenharmony_ci *		-3 - IO Unit Reset Failed
29188c2ecf20Sopenharmony_ci *		-4 - IOC owned by a PEER
29198c2ecf20Sopenharmony_ci */
29208c2ecf20Sopenharmony_cistatic int
29218c2ecf20Sopenharmony_ciMakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
29228c2ecf20Sopenharmony_ci{
29238c2ecf20Sopenharmony_ci	u32	 ioc_state;
29248c2ecf20Sopenharmony_ci	int	 statefault = 0;
29258c2ecf20Sopenharmony_ci	int	 cntdn;
29268c2ecf20Sopenharmony_ci	int	 hard_reset_done = 0;
29278c2ecf20Sopenharmony_ci	int	 r;
29288c2ecf20Sopenharmony_ci	int	 ii;
29298c2ecf20Sopenharmony_ci	int	 whoinit;
29308c2ecf20Sopenharmony_ci
29318c2ecf20Sopenharmony_ci	/* Get current [raw] IOC state  */
29328c2ecf20Sopenharmony_ci	ioc_state = mpt_GetIocState(ioc, 0);
29338c2ecf20Sopenharmony_ci	dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
29348c2ecf20Sopenharmony_ci
29358c2ecf20Sopenharmony_ci	/*
29368c2ecf20Sopenharmony_ci	 *	Check to see if IOC got left/stuck in doorbell handshake
29378c2ecf20Sopenharmony_ci	 *	grip of death.  If so, hard reset the IOC.
29388c2ecf20Sopenharmony_ci	 */
29398c2ecf20Sopenharmony_ci	if (ioc_state & MPI_DOORBELL_ACTIVE) {
29408c2ecf20Sopenharmony_ci		statefault = 1;
29418c2ecf20Sopenharmony_ci		printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
29428c2ecf20Sopenharmony_ci				ioc->name);
29438c2ecf20Sopenharmony_ci	}
29448c2ecf20Sopenharmony_ci
29458c2ecf20Sopenharmony_ci	/* Is it already READY? */
29468c2ecf20Sopenharmony_ci	if (!statefault &&
29478c2ecf20Sopenharmony_ci	    ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
29488c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
29498c2ecf20Sopenharmony_ci		    "IOC is in READY state\n", ioc->name));
29508c2ecf20Sopenharmony_ci		return 0;
29518c2ecf20Sopenharmony_ci	}
29528c2ecf20Sopenharmony_ci
29538c2ecf20Sopenharmony_ci	/*
29548c2ecf20Sopenharmony_ci	 *	Check to see if IOC is in FAULT state.
29558c2ecf20Sopenharmony_ci	 */
29568c2ecf20Sopenharmony_ci	if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
29578c2ecf20Sopenharmony_ci		statefault = 2;
29588c2ecf20Sopenharmony_ci		printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
29598c2ecf20Sopenharmony_ci		    ioc->name);
29608c2ecf20Sopenharmony_ci		printk(MYIOC_s_WARN_FMT "           FAULT code = %04xh\n",
29618c2ecf20Sopenharmony_ci		    ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
29628c2ecf20Sopenharmony_ci	}
29638c2ecf20Sopenharmony_ci
29648c2ecf20Sopenharmony_ci	/*
29658c2ecf20Sopenharmony_ci	 *	Hmmm...  Did it get left operational?
29668c2ecf20Sopenharmony_ci	 */
29678c2ecf20Sopenharmony_ci	if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
29688c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
29698c2ecf20Sopenharmony_ci				ioc->name));
29708c2ecf20Sopenharmony_ci
29718c2ecf20Sopenharmony_ci		/* Check WhoInit.
29728c2ecf20Sopenharmony_ci		 * If PCI Peer, exit.
29738c2ecf20Sopenharmony_ci		 * Else, if no fault conditions are present, issue a MessageUnitReset
29748c2ecf20Sopenharmony_ci		 * Else, fall through to KickStart case
29758c2ecf20Sopenharmony_ci		 */
29768c2ecf20Sopenharmony_ci		whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
29778c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
29788c2ecf20Sopenharmony_ci			"whoinit 0x%x statefault %d force %d\n",
29798c2ecf20Sopenharmony_ci			ioc->name, whoinit, statefault, force));
29808c2ecf20Sopenharmony_ci		if (whoinit == MPI_WHOINIT_PCI_PEER)
29818c2ecf20Sopenharmony_ci			return -4;
29828c2ecf20Sopenharmony_ci		else {
29838c2ecf20Sopenharmony_ci			if ((statefault == 0 ) && (force == 0)) {
29848c2ecf20Sopenharmony_ci				if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
29858c2ecf20Sopenharmony_ci					return 0;
29868c2ecf20Sopenharmony_ci			}
29878c2ecf20Sopenharmony_ci			statefault = 3;
29888c2ecf20Sopenharmony_ci		}
29898c2ecf20Sopenharmony_ci	}
29908c2ecf20Sopenharmony_ci
29918c2ecf20Sopenharmony_ci	hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
29928c2ecf20Sopenharmony_ci	if (hard_reset_done < 0)
29938c2ecf20Sopenharmony_ci		return -1;
29948c2ecf20Sopenharmony_ci
29958c2ecf20Sopenharmony_ci	/*
29968c2ecf20Sopenharmony_ci	 *  Loop here waiting for IOC to come READY.
29978c2ecf20Sopenharmony_ci	 */
29988c2ecf20Sopenharmony_ci	ii = 0;
29998c2ecf20Sopenharmony_ci	cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5;	/* 5 seconds */
30008c2ecf20Sopenharmony_ci
30018c2ecf20Sopenharmony_ci	while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
30028c2ecf20Sopenharmony_ci		if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
30038c2ecf20Sopenharmony_ci			/*
30048c2ecf20Sopenharmony_ci			 *  BIOS or previous driver load left IOC in OP state.
30058c2ecf20Sopenharmony_ci			 *  Reset messaging FIFOs.
30068c2ecf20Sopenharmony_ci			 */
30078c2ecf20Sopenharmony_ci			if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
30088c2ecf20Sopenharmony_ci				printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
30098c2ecf20Sopenharmony_ci				return -2;
30108c2ecf20Sopenharmony_ci			}
30118c2ecf20Sopenharmony_ci		} else if (ioc_state == MPI_IOC_STATE_RESET) {
30128c2ecf20Sopenharmony_ci			/*
30138c2ecf20Sopenharmony_ci			 *  Something is wrong.  Try to get IOC back
30148c2ecf20Sopenharmony_ci			 *  to a known state.
30158c2ecf20Sopenharmony_ci			 */
30168c2ecf20Sopenharmony_ci			if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
30178c2ecf20Sopenharmony_ci				printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
30188c2ecf20Sopenharmony_ci				return -3;
30198c2ecf20Sopenharmony_ci			}
30208c2ecf20Sopenharmony_ci		}
30218c2ecf20Sopenharmony_ci
30228c2ecf20Sopenharmony_ci		ii++; cntdn--;
30238c2ecf20Sopenharmony_ci		if (!cntdn) {
30248c2ecf20Sopenharmony_ci			printk(MYIOC_s_ERR_FMT
30258c2ecf20Sopenharmony_ci				"Wait IOC_READY state (0x%x) timeout(%d)!\n",
30268c2ecf20Sopenharmony_ci				ioc->name, ioc_state, (int)((ii+5)/HZ));
30278c2ecf20Sopenharmony_ci			return -ETIME;
30288c2ecf20Sopenharmony_ci		}
30298c2ecf20Sopenharmony_ci
30308c2ecf20Sopenharmony_ci		if (sleepFlag == CAN_SLEEP) {
30318c2ecf20Sopenharmony_ci			msleep(1);
30328c2ecf20Sopenharmony_ci		} else {
30338c2ecf20Sopenharmony_ci			mdelay (1);	/* 1 msec delay */
30348c2ecf20Sopenharmony_ci		}
30358c2ecf20Sopenharmony_ci
30368c2ecf20Sopenharmony_ci	}
30378c2ecf20Sopenharmony_ci
30388c2ecf20Sopenharmony_ci	if (statefault < 3) {
30398c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
30408c2ecf20Sopenharmony_ci			statefault == 1 ? "stuck handshake" : "IOC FAULT");
30418c2ecf20Sopenharmony_ci	}
30428c2ecf20Sopenharmony_ci
30438c2ecf20Sopenharmony_ci	return hard_reset_done;
30448c2ecf20Sopenharmony_ci}
30458c2ecf20Sopenharmony_ci
30468c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
30478c2ecf20Sopenharmony_ci/**
30488c2ecf20Sopenharmony_ci *	mpt_GetIocState - Get the current state of a MPT adapter.
30498c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
30508c2ecf20Sopenharmony_ci *	@cooked: Request raw or cooked IOC state
30518c2ecf20Sopenharmony_ci *
30528c2ecf20Sopenharmony_ci *	Returns all IOC Doorbell register bits if cooked==0, else just the
30538c2ecf20Sopenharmony_ci *	Doorbell bits in MPI_IOC_STATE_MASK.
30548c2ecf20Sopenharmony_ci */
30558c2ecf20Sopenharmony_ciu32
30568c2ecf20Sopenharmony_cimpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
30578c2ecf20Sopenharmony_ci{
30588c2ecf20Sopenharmony_ci	u32 s, sc;
30598c2ecf20Sopenharmony_ci
30608c2ecf20Sopenharmony_ci	/*  Get!  */
30618c2ecf20Sopenharmony_ci	s = CHIPREG_READ32(&ioc->chip->Doorbell);
30628c2ecf20Sopenharmony_ci	sc = s & MPI_IOC_STATE_MASK;
30638c2ecf20Sopenharmony_ci
30648c2ecf20Sopenharmony_ci	/*  Save!  */
30658c2ecf20Sopenharmony_ci	ioc->last_state = sc;
30668c2ecf20Sopenharmony_ci
30678c2ecf20Sopenharmony_ci	return cooked ? sc : s;
30688c2ecf20Sopenharmony_ci}
30698c2ecf20Sopenharmony_ci
30708c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
30718c2ecf20Sopenharmony_ci/**
30728c2ecf20Sopenharmony_ci *	GetIocFacts - Send IOCFacts request to MPT adapter.
30738c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
30748c2ecf20Sopenharmony_ci *	@sleepFlag: Specifies whether the process can sleep
30758c2ecf20Sopenharmony_ci *	@reason: If recovery, only update facts.
30768c2ecf20Sopenharmony_ci *
30778c2ecf20Sopenharmony_ci *	Returns 0 for success, non-zero for failure.
30788c2ecf20Sopenharmony_ci */
30798c2ecf20Sopenharmony_cistatic int
30808c2ecf20Sopenharmony_ciGetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
30818c2ecf20Sopenharmony_ci{
30828c2ecf20Sopenharmony_ci	IOCFacts_t		 get_facts;
30838c2ecf20Sopenharmony_ci	IOCFactsReply_t		*facts;
30848c2ecf20Sopenharmony_ci	int			 r;
30858c2ecf20Sopenharmony_ci	int			 req_sz;
30868c2ecf20Sopenharmony_ci	int			 reply_sz;
30878c2ecf20Sopenharmony_ci	int			 sz;
30888c2ecf20Sopenharmony_ci	u32			 status, vv;
30898c2ecf20Sopenharmony_ci	u8			 shiftFactor=1;
30908c2ecf20Sopenharmony_ci
30918c2ecf20Sopenharmony_ci	/* IOC *must* NOT be in RESET state! */
30928c2ecf20Sopenharmony_ci	if (ioc->last_state == MPI_IOC_STATE_RESET) {
30938c2ecf20Sopenharmony_ci		printk(KERN_ERR MYNAM
30948c2ecf20Sopenharmony_ci		    ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
30958c2ecf20Sopenharmony_ci		    ioc->name, ioc->last_state);
30968c2ecf20Sopenharmony_ci		return -44;
30978c2ecf20Sopenharmony_ci	}
30988c2ecf20Sopenharmony_ci
30998c2ecf20Sopenharmony_ci	facts = &ioc->facts;
31008c2ecf20Sopenharmony_ci
31018c2ecf20Sopenharmony_ci	/* Destination (reply area)... */
31028c2ecf20Sopenharmony_ci	reply_sz = sizeof(*facts);
31038c2ecf20Sopenharmony_ci	memset(facts, 0, reply_sz);
31048c2ecf20Sopenharmony_ci
31058c2ecf20Sopenharmony_ci	/* Request area (get_facts on the stack right now!) */
31068c2ecf20Sopenharmony_ci	req_sz = sizeof(get_facts);
31078c2ecf20Sopenharmony_ci	memset(&get_facts, 0, req_sz);
31088c2ecf20Sopenharmony_ci
31098c2ecf20Sopenharmony_ci	get_facts.Function = MPI_FUNCTION_IOC_FACTS;
31108c2ecf20Sopenharmony_ci	/* Assert: All other get_facts fields are zero! */
31118c2ecf20Sopenharmony_ci
31128c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
31138c2ecf20Sopenharmony_ci	    "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
31148c2ecf20Sopenharmony_ci	    ioc->name, req_sz, reply_sz));
31158c2ecf20Sopenharmony_ci
31168c2ecf20Sopenharmony_ci	/* No non-zero fields in the get_facts request are greater than
31178c2ecf20Sopenharmony_ci	 * 1 byte in size, so we can just fire it off as is.
31188c2ecf20Sopenharmony_ci	 */
31198c2ecf20Sopenharmony_ci	r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
31208c2ecf20Sopenharmony_ci			reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
31218c2ecf20Sopenharmony_ci	if (r != 0)
31228c2ecf20Sopenharmony_ci		return r;
31238c2ecf20Sopenharmony_ci
31248c2ecf20Sopenharmony_ci	/*
31258c2ecf20Sopenharmony_ci	 * Now byte swap (GRRR) the necessary fields before any further
31268c2ecf20Sopenharmony_ci	 * inspection of reply contents.
31278c2ecf20Sopenharmony_ci	 *
31288c2ecf20Sopenharmony_ci	 * But need to do some sanity checks on MsgLength (byte) field
31298c2ecf20Sopenharmony_ci	 * to make sure we don't zero IOC's req_sz!
31308c2ecf20Sopenharmony_ci	 */
31318c2ecf20Sopenharmony_ci	/* Did we get a valid reply? */
31328c2ecf20Sopenharmony_ci	if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
31338c2ecf20Sopenharmony_ci		if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
31348c2ecf20Sopenharmony_ci			/*
31358c2ecf20Sopenharmony_ci			 * If not been here, done that, save off first WhoInit value
31368c2ecf20Sopenharmony_ci			 */
31378c2ecf20Sopenharmony_ci			if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
31388c2ecf20Sopenharmony_ci				ioc->FirstWhoInit = facts->WhoInit;
31398c2ecf20Sopenharmony_ci		}
31408c2ecf20Sopenharmony_ci
31418c2ecf20Sopenharmony_ci		facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
31428c2ecf20Sopenharmony_ci		facts->MsgContext = le32_to_cpu(facts->MsgContext);
31438c2ecf20Sopenharmony_ci		facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
31448c2ecf20Sopenharmony_ci		facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
31458c2ecf20Sopenharmony_ci		facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
31468c2ecf20Sopenharmony_ci		status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
31478c2ecf20Sopenharmony_ci		/* CHECKME! IOCStatus, IOCLogInfo */
31488c2ecf20Sopenharmony_ci
31498c2ecf20Sopenharmony_ci		facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
31508c2ecf20Sopenharmony_ci		facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
31518c2ecf20Sopenharmony_ci
31528c2ecf20Sopenharmony_ci		/*
31538c2ecf20Sopenharmony_ci		 * FC f/w version changed between 1.1 and 1.2
31548c2ecf20Sopenharmony_ci		 *	Old: u16{Major(4),Minor(4),SubMinor(8)}
31558c2ecf20Sopenharmony_ci		 *	New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
31568c2ecf20Sopenharmony_ci		 */
31578c2ecf20Sopenharmony_ci		if (facts->MsgVersion < MPI_VERSION_01_02) {
31588c2ecf20Sopenharmony_ci			/*
31598c2ecf20Sopenharmony_ci			 *	Handle old FC f/w style, convert to new...
31608c2ecf20Sopenharmony_ci			 */
31618c2ecf20Sopenharmony_ci			u16	 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
31628c2ecf20Sopenharmony_ci			facts->FWVersion.Word =
31638c2ecf20Sopenharmony_ci					((oldv<<12) & 0xFF000000) |
31648c2ecf20Sopenharmony_ci					((oldv<<8)  & 0x000FFF00);
31658c2ecf20Sopenharmony_ci		} else
31668c2ecf20Sopenharmony_ci			facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
31678c2ecf20Sopenharmony_ci
31688c2ecf20Sopenharmony_ci		facts->ProductID = le16_to_cpu(facts->ProductID);
31698c2ecf20Sopenharmony_ci
31708c2ecf20Sopenharmony_ci		if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
31718c2ecf20Sopenharmony_ci		    > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
31728c2ecf20Sopenharmony_ci			ioc->ir_firmware = 1;
31738c2ecf20Sopenharmony_ci
31748c2ecf20Sopenharmony_ci		facts->CurrentHostMfaHighAddr =
31758c2ecf20Sopenharmony_ci				le32_to_cpu(facts->CurrentHostMfaHighAddr);
31768c2ecf20Sopenharmony_ci		facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
31778c2ecf20Sopenharmony_ci		facts->CurrentSenseBufferHighAddr =
31788c2ecf20Sopenharmony_ci				le32_to_cpu(facts->CurrentSenseBufferHighAddr);
31798c2ecf20Sopenharmony_ci		facts->CurReplyFrameSize =
31808c2ecf20Sopenharmony_ci				le16_to_cpu(facts->CurReplyFrameSize);
31818c2ecf20Sopenharmony_ci		facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
31828c2ecf20Sopenharmony_ci
31838c2ecf20Sopenharmony_ci		/*
31848c2ecf20Sopenharmony_ci		 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
31858c2ecf20Sopenharmony_ci		 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
31868c2ecf20Sopenharmony_ci		 * to 14 in MPI-1.01.0x.
31878c2ecf20Sopenharmony_ci		 */
31888c2ecf20Sopenharmony_ci		if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
31898c2ecf20Sopenharmony_ci		    facts->MsgVersion > MPI_VERSION_01_00) {
31908c2ecf20Sopenharmony_ci			facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
31918c2ecf20Sopenharmony_ci		}
31928c2ecf20Sopenharmony_ci
31938c2ecf20Sopenharmony_ci		facts->FWImageSize = ALIGN(facts->FWImageSize, 4);
31948c2ecf20Sopenharmony_ci
31958c2ecf20Sopenharmony_ci		if (!facts->RequestFrameSize) {
31968c2ecf20Sopenharmony_ci			/*  Something is wrong!  */
31978c2ecf20Sopenharmony_ci			printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
31988c2ecf20Sopenharmony_ci					ioc->name);
31998c2ecf20Sopenharmony_ci			return -55;
32008c2ecf20Sopenharmony_ci		}
32018c2ecf20Sopenharmony_ci
32028c2ecf20Sopenharmony_ci		r = sz = facts->BlockSize;
32038c2ecf20Sopenharmony_ci		vv = ((63 / (sz * 4)) + 1) & 0x03;
32048c2ecf20Sopenharmony_ci		ioc->NB_for_64_byte_frame = vv;
32058c2ecf20Sopenharmony_ci		while ( sz )
32068c2ecf20Sopenharmony_ci		{
32078c2ecf20Sopenharmony_ci			shiftFactor++;
32088c2ecf20Sopenharmony_ci			sz = sz >> 1;
32098c2ecf20Sopenharmony_ci		}
32108c2ecf20Sopenharmony_ci		ioc->NBShiftFactor  = shiftFactor;
32118c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
32128c2ecf20Sopenharmony_ci		    "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
32138c2ecf20Sopenharmony_ci		    ioc->name, vv, shiftFactor, r));
32148c2ecf20Sopenharmony_ci
32158c2ecf20Sopenharmony_ci		if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
32168c2ecf20Sopenharmony_ci			/*
32178c2ecf20Sopenharmony_ci			 * Set values for this IOC's request & reply frame sizes,
32188c2ecf20Sopenharmony_ci			 * and request & reply queue depths...
32198c2ecf20Sopenharmony_ci			 */
32208c2ecf20Sopenharmony_ci			ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
32218c2ecf20Sopenharmony_ci			ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
32228c2ecf20Sopenharmony_ci			ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
32238c2ecf20Sopenharmony_ci			ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
32248c2ecf20Sopenharmony_ci
32258c2ecf20Sopenharmony_ci			dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
32268c2ecf20Sopenharmony_ci				ioc->name, ioc->reply_sz, ioc->reply_depth));
32278c2ecf20Sopenharmony_ci			dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz  =%3d, req_depth  =%4d\n",
32288c2ecf20Sopenharmony_ci				ioc->name, ioc->req_sz, ioc->req_depth));
32298c2ecf20Sopenharmony_ci
32308c2ecf20Sopenharmony_ci			/* Get port facts! */
32318c2ecf20Sopenharmony_ci			if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
32328c2ecf20Sopenharmony_ci				return r;
32338c2ecf20Sopenharmony_ci		}
32348c2ecf20Sopenharmony_ci	} else {
32358c2ecf20Sopenharmony_ci		printk(MYIOC_s_ERR_FMT
32368c2ecf20Sopenharmony_ci		     "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
32378c2ecf20Sopenharmony_ci		     ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
32388c2ecf20Sopenharmony_ci		     RequestFrameSize)/sizeof(u32)));
32398c2ecf20Sopenharmony_ci		return -66;
32408c2ecf20Sopenharmony_ci	}
32418c2ecf20Sopenharmony_ci
32428c2ecf20Sopenharmony_ci	return 0;
32438c2ecf20Sopenharmony_ci}
32448c2ecf20Sopenharmony_ci
32458c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
32468c2ecf20Sopenharmony_ci/**
32478c2ecf20Sopenharmony_ci *	GetPortFacts - Send PortFacts request to MPT adapter.
32488c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
32498c2ecf20Sopenharmony_ci *	@portnum: Port number
32508c2ecf20Sopenharmony_ci *	@sleepFlag: Specifies whether the process can sleep
32518c2ecf20Sopenharmony_ci *
32528c2ecf20Sopenharmony_ci *	Returns 0 for success, non-zero for failure.
32538c2ecf20Sopenharmony_ci */
32548c2ecf20Sopenharmony_cistatic int
32558c2ecf20Sopenharmony_ciGetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
32568c2ecf20Sopenharmony_ci{
32578c2ecf20Sopenharmony_ci	PortFacts_t		 get_pfacts;
32588c2ecf20Sopenharmony_ci	PortFactsReply_t	*pfacts;
32598c2ecf20Sopenharmony_ci	int			 ii;
32608c2ecf20Sopenharmony_ci	int			 req_sz;
32618c2ecf20Sopenharmony_ci	int			 reply_sz;
32628c2ecf20Sopenharmony_ci	int			 max_id;
32638c2ecf20Sopenharmony_ci
32648c2ecf20Sopenharmony_ci	/* IOC *must* NOT be in RESET state! */
32658c2ecf20Sopenharmony_ci	if (ioc->last_state == MPI_IOC_STATE_RESET) {
32668c2ecf20Sopenharmony_ci		printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
32678c2ecf20Sopenharmony_ci		    ioc->name, ioc->last_state );
32688c2ecf20Sopenharmony_ci		return -4;
32698c2ecf20Sopenharmony_ci	}
32708c2ecf20Sopenharmony_ci
32718c2ecf20Sopenharmony_ci	pfacts = &ioc->pfacts[portnum];
32728c2ecf20Sopenharmony_ci
32738c2ecf20Sopenharmony_ci	/* Destination (reply area)...  */
32748c2ecf20Sopenharmony_ci	reply_sz = sizeof(*pfacts);
32758c2ecf20Sopenharmony_ci	memset(pfacts, 0, reply_sz);
32768c2ecf20Sopenharmony_ci
32778c2ecf20Sopenharmony_ci	/* Request area (get_pfacts on the stack right now!) */
32788c2ecf20Sopenharmony_ci	req_sz = sizeof(get_pfacts);
32798c2ecf20Sopenharmony_ci	memset(&get_pfacts, 0, req_sz);
32808c2ecf20Sopenharmony_ci
32818c2ecf20Sopenharmony_ci	get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
32828c2ecf20Sopenharmony_ci	get_pfacts.PortNumber = portnum;
32838c2ecf20Sopenharmony_ci	/* Assert: All other get_pfacts fields are zero! */
32848c2ecf20Sopenharmony_ci
32858c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
32868c2ecf20Sopenharmony_ci			ioc->name, portnum));
32878c2ecf20Sopenharmony_ci
32888c2ecf20Sopenharmony_ci	/* No non-zero fields in the get_pfacts request are greater than
32898c2ecf20Sopenharmony_ci	 * 1 byte in size, so we can just fire it off as is.
32908c2ecf20Sopenharmony_ci	 */
32918c2ecf20Sopenharmony_ci	ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
32928c2ecf20Sopenharmony_ci				reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
32938c2ecf20Sopenharmony_ci	if (ii != 0)
32948c2ecf20Sopenharmony_ci		return ii;
32958c2ecf20Sopenharmony_ci
32968c2ecf20Sopenharmony_ci	/* Did we get a valid reply? */
32978c2ecf20Sopenharmony_ci
32988c2ecf20Sopenharmony_ci	/* Now byte swap the necessary fields in the response. */
32998c2ecf20Sopenharmony_ci	pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
33008c2ecf20Sopenharmony_ci	pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
33018c2ecf20Sopenharmony_ci	pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
33028c2ecf20Sopenharmony_ci	pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
33038c2ecf20Sopenharmony_ci	pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
33048c2ecf20Sopenharmony_ci	pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
33058c2ecf20Sopenharmony_ci	pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
33068c2ecf20Sopenharmony_ci	pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
33078c2ecf20Sopenharmony_ci	pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
33088c2ecf20Sopenharmony_ci
33098c2ecf20Sopenharmony_ci	max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
33108c2ecf20Sopenharmony_ci	    pfacts->MaxDevices;
33118c2ecf20Sopenharmony_ci	ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
33128c2ecf20Sopenharmony_ci	ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
33138c2ecf20Sopenharmony_ci
33148c2ecf20Sopenharmony_ci	/*
33158c2ecf20Sopenharmony_ci	 * Place all the devices on channels
33168c2ecf20Sopenharmony_ci	 *
33178c2ecf20Sopenharmony_ci	 * (for debuging)
33188c2ecf20Sopenharmony_ci	 */
33198c2ecf20Sopenharmony_ci	if (mpt_channel_mapping) {
33208c2ecf20Sopenharmony_ci		ioc->devices_per_bus = 1;
33218c2ecf20Sopenharmony_ci		ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
33228c2ecf20Sopenharmony_ci	}
33238c2ecf20Sopenharmony_ci
33248c2ecf20Sopenharmony_ci	return 0;
33258c2ecf20Sopenharmony_ci}
33268c2ecf20Sopenharmony_ci
33278c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
33288c2ecf20Sopenharmony_ci/**
33298c2ecf20Sopenharmony_ci *	SendIocInit - Send IOCInit request to MPT adapter.
33308c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
33318c2ecf20Sopenharmony_ci *	@sleepFlag: Specifies whether the process can sleep
33328c2ecf20Sopenharmony_ci *
33338c2ecf20Sopenharmony_ci *	Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
33348c2ecf20Sopenharmony_ci *
33358c2ecf20Sopenharmony_ci *	Returns 0 for success, non-zero for failure.
33368c2ecf20Sopenharmony_ci */
33378c2ecf20Sopenharmony_cistatic int
33388c2ecf20Sopenharmony_ciSendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
33398c2ecf20Sopenharmony_ci{
33408c2ecf20Sopenharmony_ci	IOCInit_t		 ioc_init;
33418c2ecf20Sopenharmony_ci	MPIDefaultReply_t	 init_reply;
33428c2ecf20Sopenharmony_ci	u32			 state;
33438c2ecf20Sopenharmony_ci	int			 r;
33448c2ecf20Sopenharmony_ci	int			 count;
33458c2ecf20Sopenharmony_ci	int			 cntdn;
33468c2ecf20Sopenharmony_ci
33478c2ecf20Sopenharmony_ci	memset(&ioc_init, 0, sizeof(ioc_init));
33488c2ecf20Sopenharmony_ci	memset(&init_reply, 0, sizeof(init_reply));
33498c2ecf20Sopenharmony_ci
33508c2ecf20Sopenharmony_ci	ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
33518c2ecf20Sopenharmony_ci	ioc_init.Function = MPI_FUNCTION_IOC_INIT;
33528c2ecf20Sopenharmony_ci
33538c2ecf20Sopenharmony_ci	/* If we are in a recovery mode and we uploaded the FW image,
33548c2ecf20Sopenharmony_ci	 * then this pointer is not NULL. Skip the upload a second time.
33558c2ecf20Sopenharmony_ci	 * Set this flag if cached_fw set for either IOC.
33568c2ecf20Sopenharmony_ci	 */
33578c2ecf20Sopenharmony_ci	if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
33588c2ecf20Sopenharmony_ci		ioc->upload_fw = 1;
33598c2ecf20Sopenharmony_ci	else
33608c2ecf20Sopenharmony_ci		ioc->upload_fw = 0;
33618c2ecf20Sopenharmony_ci	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
33628c2ecf20Sopenharmony_ci		   ioc->name, ioc->upload_fw, ioc->facts.Flags));
33638c2ecf20Sopenharmony_ci
33648c2ecf20Sopenharmony_ci	ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
33658c2ecf20Sopenharmony_ci	ioc_init.MaxBuses = (U8)ioc->number_of_buses;
33668c2ecf20Sopenharmony_ci
33678c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
33688c2ecf20Sopenharmony_ci		   ioc->name, ioc->facts.MsgVersion));
33698c2ecf20Sopenharmony_ci	if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
33708c2ecf20Sopenharmony_ci		// set MsgVersion and HeaderVersion host driver was built with
33718c2ecf20Sopenharmony_ci		ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
33728c2ecf20Sopenharmony_ci	        ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
33738c2ecf20Sopenharmony_ci
33748c2ecf20Sopenharmony_ci		if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
33758c2ecf20Sopenharmony_ci			ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
33768c2ecf20Sopenharmony_ci		} else if(mpt_host_page_alloc(ioc, &ioc_init))
33778c2ecf20Sopenharmony_ci			return -99;
33788c2ecf20Sopenharmony_ci	}
33798c2ecf20Sopenharmony_ci	ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz);	/* in BYTES */
33808c2ecf20Sopenharmony_ci
33818c2ecf20Sopenharmony_ci	if (ioc->sg_addr_size == sizeof(u64)) {
33828c2ecf20Sopenharmony_ci		/* Save the upper 32-bits of the request
33838c2ecf20Sopenharmony_ci		 * (reply) and sense buffers.
33848c2ecf20Sopenharmony_ci		 */
33858c2ecf20Sopenharmony_ci		ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
33868c2ecf20Sopenharmony_ci		ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
33878c2ecf20Sopenharmony_ci	} else {
33888c2ecf20Sopenharmony_ci		/* Force 32-bit addressing */
33898c2ecf20Sopenharmony_ci		ioc_init.HostMfaHighAddr = cpu_to_le32(0);
33908c2ecf20Sopenharmony_ci		ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
33918c2ecf20Sopenharmony_ci	}
33928c2ecf20Sopenharmony_ci
33938c2ecf20Sopenharmony_ci	ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
33948c2ecf20Sopenharmony_ci	ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
33958c2ecf20Sopenharmony_ci	ioc->facts.MaxDevices = ioc_init.MaxDevices;
33968c2ecf20Sopenharmony_ci	ioc->facts.MaxBuses = ioc_init.MaxBuses;
33978c2ecf20Sopenharmony_ci
33988c2ecf20Sopenharmony_ci	dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
33998c2ecf20Sopenharmony_ci			ioc->name, &ioc_init));
34008c2ecf20Sopenharmony_ci
34018c2ecf20Sopenharmony_ci	r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
34028c2ecf20Sopenharmony_ci				sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
34038c2ecf20Sopenharmony_ci	if (r != 0) {
34048c2ecf20Sopenharmony_ci		printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
34058c2ecf20Sopenharmony_ci		return r;
34068c2ecf20Sopenharmony_ci	}
34078c2ecf20Sopenharmony_ci
34088c2ecf20Sopenharmony_ci	/* No need to byte swap the multibyte fields in the reply
34098c2ecf20Sopenharmony_ci	 * since we don't even look at its contents.
34108c2ecf20Sopenharmony_ci	 */
34118c2ecf20Sopenharmony_ci
34128c2ecf20Sopenharmony_ci	dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
34138c2ecf20Sopenharmony_ci			ioc->name, &ioc_init));
34148c2ecf20Sopenharmony_ci
34158c2ecf20Sopenharmony_ci	if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
34168c2ecf20Sopenharmony_ci		printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
34178c2ecf20Sopenharmony_ci		return r;
34188c2ecf20Sopenharmony_ci	}
34198c2ecf20Sopenharmony_ci
34208c2ecf20Sopenharmony_ci	/* YIKES!  SUPER IMPORTANT!!!
34218c2ecf20Sopenharmony_ci	 *  Poll IocState until _OPERATIONAL while IOC is doing
34228c2ecf20Sopenharmony_ci	 *  LoopInit and TargetDiscovery!
34238c2ecf20Sopenharmony_ci	 */
34248c2ecf20Sopenharmony_ci	count = 0;
34258c2ecf20Sopenharmony_ci	cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60;	/* 60 seconds */
34268c2ecf20Sopenharmony_ci	state = mpt_GetIocState(ioc, 1);
34278c2ecf20Sopenharmony_ci	while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
34288c2ecf20Sopenharmony_ci		if (sleepFlag == CAN_SLEEP) {
34298c2ecf20Sopenharmony_ci			msleep(1);
34308c2ecf20Sopenharmony_ci		} else {
34318c2ecf20Sopenharmony_ci			mdelay(1);
34328c2ecf20Sopenharmony_ci		}
34338c2ecf20Sopenharmony_ci
34348c2ecf20Sopenharmony_ci		if (!cntdn) {
34358c2ecf20Sopenharmony_ci			printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
34368c2ecf20Sopenharmony_ci					ioc->name, (int)((count+5)/HZ));
34378c2ecf20Sopenharmony_ci			return -9;
34388c2ecf20Sopenharmony_ci		}
34398c2ecf20Sopenharmony_ci
34408c2ecf20Sopenharmony_ci		state = mpt_GetIocState(ioc, 1);
34418c2ecf20Sopenharmony_ci		count++;
34428c2ecf20Sopenharmony_ci	}
34438c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
34448c2ecf20Sopenharmony_ci			ioc->name, count));
34458c2ecf20Sopenharmony_ci
34468c2ecf20Sopenharmony_ci	ioc->aen_event_read_flag=0;
34478c2ecf20Sopenharmony_ci	return r;
34488c2ecf20Sopenharmony_ci}
34498c2ecf20Sopenharmony_ci
34508c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
34518c2ecf20Sopenharmony_ci/**
34528c2ecf20Sopenharmony_ci *	SendPortEnable - Send PortEnable request to MPT adapter port.
34538c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
34548c2ecf20Sopenharmony_ci *	@portnum: Port number to enable
34558c2ecf20Sopenharmony_ci *	@sleepFlag: Specifies whether the process can sleep
34568c2ecf20Sopenharmony_ci *
34578c2ecf20Sopenharmony_ci *	Send PortEnable to bring IOC to OPERATIONAL state.
34588c2ecf20Sopenharmony_ci *
34598c2ecf20Sopenharmony_ci *	Returns 0 for success, non-zero for failure.
34608c2ecf20Sopenharmony_ci */
34618c2ecf20Sopenharmony_cistatic int
34628c2ecf20Sopenharmony_ciSendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
34638c2ecf20Sopenharmony_ci{
34648c2ecf20Sopenharmony_ci	PortEnable_t		 port_enable;
34658c2ecf20Sopenharmony_ci	MPIDefaultReply_t	 reply_buf;
34668c2ecf20Sopenharmony_ci	int	 rc;
34678c2ecf20Sopenharmony_ci	int	 req_sz;
34688c2ecf20Sopenharmony_ci	int	 reply_sz;
34698c2ecf20Sopenharmony_ci
34708c2ecf20Sopenharmony_ci	/*  Destination...  */
34718c2ecf20Sopenharmony_ci	reply_sz = sizeof(MPIDefaultReply_t);
34728c2ecf20Sopenharmony_ci	memset(&reply_buf, 0, reply_sz);
34738c2ecf20Sopenharmony_ci
34748c2ecf20Sopenharmony_ci	req_sz = sizeof(PortEnable_t);
34758c2ecf20Sopenharmony_ci	memset(&port_enable, 0, req_sz);
34768c2ecf20Sopenharmony_ci
34778c2ecf20Sopenharmony_ci	port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
34788c2ecf20Sopenharmony_ci	port_enable.PortNumber = portnum;
34798c2ecf20Sopenharmony_ci/*	port_enable.ChainOffset = 0;		*/
34808c2ecf20Sopenharmony_ci/*	port_enable.MsgFlags = 0;		*/
34818c2ecf20Sopenharmony_ci/*	port_enable.MsgContext = 0;		*/
34828c2ecf20Sopenharmony_ci
34838c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
34848c2ecf20Sopenharmony_ci			ioc->name, portnum, &port_enable));
34858c2ecf20Sopenharmony_ci
34868c2ecf20Sopenharmony_ci	/* RAID FW may take a long time to enable
34878c2ecf20Sopenharmony_ci	 */
34888c2ecf20Sopenharmony_ci	if (ioc->ir_firmware || ioc->bus_type == SAS) {
34898c2ecf20Sopenharmony_ci		rc = mpt_handshake_req_reply_wait(ioc, req_sz,
34908c2ecf20Sopenharmony_ci		(u32*)&port_enable, reply_sz, (u16*)&reply_buf,
34918c2ecf20Sopenharmony_ci		300 /*seconds*/, sleepFlag);
34928c2ecf20Sopenharmony_ci	} else {
34938c2ecf20Sopenharmony_ci		rc = mpt_handshake_req_reply_wait(ioc, req_sz,
34948c2ecf20Sopenharmony_ci		(u32*)&port_enable, reply_sz, (u16*)&reply_buf,
34958c2ecf20Sopenharmony_ci		30 /*seconds*/, sleepFlag);
34968c2ecf20Sopenharmony_ci	}
34978c2ecf20Sopenharmony_ci	return rc;
34988c2ecf20Sopenharmony_ci}
34998c2ecf20Sopenharmony_ci
35008c2ecf20Sopenharmony_ci/**
35018c2ecf20Sopenharmony_ci *	mpt_alloc_fw_memory - allocate firmware memory
35028c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
35038c2ecf20Sopenharmony_ci *      @size: total FW bytes
35048c2ecf20Sopenharmony_ci *
35058c2ecf20Sopenharmony_ci *	If memory has already been allocated, the same (cached) value
35068c2ecf20Sopenharmony_ci *	is returned.
35078c2ecf20Sopenharmony_ci *
35088c2ecf20Sopenharmony_ci *	Return 0 if successful, or non-zero for failure
35098c2ecf20Sopenharmony_ci **/
35108c2ecf20Sopenharmony_ciint
35118c2ecf20Sopenharmony_cimpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
35128c2ecf20Sopenharmony_ci{
35138c2ecf20Sopenharmony_ci	int rc;
35148c2ecf20Sopenharmony_ci
35158c2ecf20Sopenharmony_ci	if (ioc->cached_fw) {
35168c2ecf20Sopenharmony_ci		rc = 0;  /* use already allocated memory */
35178c2ecf20Sopenharmony_ci		goto out;
35188c2ecf20Sopenharmony_ci	}
35198c2ecf20Sopenharmony_ci	else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
35208c2ecf20Sopenharmony_ci		ioc->cached_fw = ioc->alt_ioc->cached_fw;  /* use alt_ioc's memory */
35218c2ecf20Sopenharmony_ci		ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
35228c2ecf20Sopenharmony_ci		rc = 0;
35238c2ecf20Sopenharmony_ci		goto out;
35248c2ecf20Sopenharmony_ci	}
35258c2ecf20Sopenharmony_ci	ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
35268c2ecf20Sopenharmony_ci	if (!ioc->cached_fw) {
35278c2ecf20Sopenharmony_ci		printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
35288c2ecf20Sopenharmony_ci		    ioc->name);
35298c2ecf20Sopenharmony_ci		rc = -1;
35308c2ecf20Sopenharmony_ci	} else {
35318c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image  @ %p[%p], sz=%d[%x] bytes\n",
35328c2ecf20Sopenharmony_ci		    ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
35338c2ecf20Sopenharmony_ci		ioc->alloc_total += size;
35348c2ecf20Sopenharmony_ci		rc = 0;
35358c2ecf20Sopenharmony_ci	}
35368c2ecf20Sopenharmony_ci out:
35378c2ecf20Sopenharmony_ci	return rc;
35388c2ecf20Sopenharmony_ci}
35398c2ecf20Sopenharmony_ci
35408c2ecf20Sopenharmony_ci/**
35418c2ecf20Sopenharmony_ci *	mpt_free_fw_memory - free firmware memory
35428c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
35438c2ecf20Sopenharmony_ci *
35448c2ecf20Sopenharmony_ci *	If alt_img is NULL, delete from ioc structure.
35458c2ecf20Sopenharmony_ci *	Else, delete a secondary image in same format.
35468c2ecf20Sopenharmony_ci **/
35478c2ecf20Sopenharmony_civoid
35488c2ecf20Sopenharmony_cimpt_free_fw_memory(MPT_ADAPTER *ioc)
35498c2ecf20Sopenharmony_ci{
35508c2ecf20Sopenharmony_ci	int sz;
35518c2ecf20Sopenharmony_ci
35528c2ecf20Sopenharmony_ci	if (!ioc->cached_fw)
35538c2ecf20Sopenharmony_ci		return;
35548c2ecf20Sopenharmony_ci
35558c2ecf20Sopenharmony_ci	sz = ioc->facts.FWImageSize;
35568c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image  @ %p[%p], sz=%d[%x] bytes\n",
35578c2ecf20Sopenharmony_ci		 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
35588c2ecf20Sopenharmony_ci	pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
35598c2ecf20Sopenharmony_ci	ioc->alloc_total -= sz;
35608c2ecf20Sopenharmony_ci	ioc->cached_fw = NULL;
35618c2ecf20Sopenharmony_ci}
35628c2ecf20Sopenharmony_ci
35638c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
35648c2ecf20Sopenharmony_ci/**
35658c2ecf20Sopenharmony_ci *	mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
35668c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
35678c2ecf20Sopenharmony_ci *	@sleepFlag: Specifies whether the process can sleep
35688c2ecf20Sopenharmony_ci *
35698c2ecf20Sopenharmony_ci *	Returns 0 for success, >0 for handshake failure
35708c2ecf20Sopenharmony_ci *		<0 for fw upload failure.
35718c2ecf20Sopenharmony_ci *
35728c2ecf20Sopenharmony_ci *	Remark: If bound IOC and a successful FWUpload was performed
35738c2ecf20Sopenharmony_ci *	on the bound IOC, the second image is discarded
35748c2ecf20Sopenharmony_ci *	and memory is free'd. Both channels must upload to prevent
35758c2ecf20Sopenharmony_ci *	IOC from running in degraded mode.
35768c2ecf20Sopenharmony_ci */
35778c2ecf20Sopenharmony_cistatic int
35788c2ecf20Sopenharmony_cimpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
35798c2ecf20Sopenharmony_ci{
35808c2ecf20Sopenharmony_ci	u8			 reply[sizeof(FWUploadReply_t)];
35818c2ecf20Sopenharmony_ci	FWUpload_t		*prequest;
35828c2ecf20Sopenharmony_ci	FWUploadReply_t		*preply;
35838c2ecf20Sopenharmony_ci	FWUploadTCSGE_t		*ptcsge;
35848c2ecf20Sopenharmony_ci	u32			 flagsLength;
35858c2ecf20Sopenharmony_ci	int			 ii, sz, reply_sz;
35868c2ecf20Sopenharmony_ci	int			 cmdStatus;
35878c2ecf20Sopenharmony_ci	int			request_size;
35888c2ecf20Sopenharmony_ci	/* If the image size is 0, we are done.
35898c2ecf20Sopenharmony_ci	 */
35908c2ecf20Sopenharmony_ci	if ((sz = ioc->facts.FWImageSize) == 0)
35918c2ecf20Sopenharmony_ci		return 0;
35928c2ecf20Sopenharmony_ci
35938c2ecf20Sopenharmony_ci	if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
35948c2ecf20Sopenharmony_ci		return -ENOMEM;
35958c2ecf20Sopenharmony_ci
35968c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image  @ %p[%p], sz=%d[%x] bytes\n",
35978c2ecf20Sopenharmony_ci	    ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
35988c2ecf20Sopenharmony_ci
35998c2ecf20Sopenharmony_ci	prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
36008c2ecf20Sopenharmony_ci	    kzalloc(ioc->req_sz, GFP_KERNEL);
36018c2ecf20Sopenharmony_ci	if (!prequest) {
36028c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
36038c2ecf20Sopenharmony_ci		    "while allocating memory \n", ioc->name));
36048c2ecf20Sopenharmony_ci		mpt_free_fw_memory(ioc);
36058c2ecf20Sopenharmony_ci		return -ENOMEM;
36068c2ecf20Sopenharmony_ci	}
36078c2ecf20Sopenharmony_ci
36088c2ecf20Sopenharmony_ci	preply = (FWUploadReply_t *)&reply;
36098c2ecf20Sopenharmony_ci
36108c2ecf20Sopenharmony_ci	reply_sz = sizeof(reply);
36118c2ecf20Sopenharmony_ci	memset(preply, 0, reply_sz);
36128c2ecf20Sopenharmony_ci
36138c2ecf20Sopenharmony_ci	prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
36148c2ecf20Sopenharmony_ci	prequest->Function = MPI_FUNCTION_FW_UPLOAD;
36158c2ecf20Sopenharmony_ci
36168c2ecf20Sopenharmony_ci	ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
36178c2ecf20Sopenharmony_ci	ptcsge->DetailsLength = 12;
36188c2ecf20Sopenharmony_ci	ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
36198c2ecf20Sopenharmony_ci	ptcsge->ImageSize = cpu_to_le32(sz);
36208c2ecf20Sopenharmony_ci	ptcsge++;
36218c2ecf20Sopenharmony_ci
36228c2ecf20Sopenharmony_ci	flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
36238c2ecf20Sopenharmony_ci	ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
36248c2ecf20Sopenharmony_ci	request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
36258c2ecf20Sopenharmony_ci	    ioc->SGE_size;
36268c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
36278c2ecf20Sopenharmony_ci	    " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
36288c2ecf20Sopenharmony_ci	    ioc->facts.FWImageSize, request_size));
36298c2ecf20Sopenharmony_ci	DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
36308c2ecf20Sopenharmony_ci
36318c2ecf20Sopenharmony_ci	ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
36328c2ecf20Sopenharmony_ci	    reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
36338c2ecf20Sopenharmony_ci
36348c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
36358c2ecf20Sopenharmony_ci	    "rc=%x \n", ioc->name, ii));
36368c2ecf20Sopenharmony_ci
36378c2ecf20Sopenharmony_ci	cmdStatus = -EFAULT;
36388c2ecf20Sopenharmony_ci	if (ii == 0) {
36398c2ecf20Sopenharmony_ci		/* Handshake transfer was complete and successful.
36408c2ecf20Sopenharmony_ci		 * Check the Reply Frame.
36418c2ecf20Sopenharmony_ci		 */
36428c2ecf20Sopenharmony_ci		int status;
36438c2ecf20Sopenharmony_ci		status = le16_to_cpu(preply->IOCStatus) &
36448c2ecf20Sopenharmony_ci				MPI_IOCSTATUS_MASK;
36458c2ecf20Sopenharmony_ci		if (status == MPI_IOCSTATUS_SUCCESS &&
36468c2ecf20Sopenharmony_ci		    ioc->facts.FWImageSize ==
36478c2ecf20Sopenharmony_ci		    le32_to_cpu(preply->ActualImageSize))
36488c2ecf20Sopenharmony_ci				cmdStatus = 0;
36498c2ecf20Sopenharmony_ci	}
36508c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
36518c2ecf20Sopenharmony_ci			ioc->name, cmdStatus));
36528c2ecf20Sopenharmony_ci
36538c2ecf20Sopenharmony_ci
36548c2ecf20Sopenharmony_ci	if (cmdStatus) {
36558c2ecf20Sopenharmony_ci		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
36568c2ecf20Sopenharmony_ci		    "freeing image \n", ioc->name));
36578c2ecf20Sopenharmony_ci		mpt_free_fw_memory(ioc);
36588c2ecf20Sopenharmony_ci	}
36598c2ecf20Sopenharmony_ci	kfree(prequest);
36608c2ecf20Sopenharmony_ci
36618c2ecf20Sopenharmony_ci	return cmdStatus;
36628c2ecf20Sopenharmony_ci}
36638c2ecf20Sopenharmony_ci
36648c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
36658c2ecf20Sopenharmony_ci/**
36668c2ecf20Sopenharmony_ci *	mpt_downloadboot - DownloadBoot code
36678c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
36688c2ecf20Sopenharmony_ci *	@pFwHeader: Pointer to firmware header info
36698c2ecf20Sopenharmony_ci *	@sleepFlag: Specifies whether the process can sleep
36708c2ecf20Sopenharmony_ci *
36718c2ecf20Sopenharmony_ci *	FwDownloadBoot requires Programmed IO access.
36728c2ecf20Sopenharmony_ci *
36738c2ecf20Sopenharmony_ci *	Returns 0 for success
36748c2ecf20Sopenharmony_ci *		-1 FW Image size is 0
36758c2ecf20Sopenharmony_ci *		-2 No valid cached_fw Pointer
36768c2ecf20Sopenharmony_ci *		<0 for fw upload failure.
36778c2ecf20Sopenharmony_ci */
36788c2ecf20Sopenharmony_cistatic int
36798c2ecf20Sopenharmony_cimpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
36808c2ecf20Sopenharmony_ci{
36818c2ecf20Sopenharmony_ci	MpiExtImageHeader_t	*pExtImage;
36828c2ecf20Sopenharmony_ci	u32			 fwSize;
36838c2ecf20Sopenharmony_ci	u32			 diag0val;
36848c2ecf20Sopenharmony_ci	int			 count;
36858c2ecf20Sopenharmony_ci	u32			*ptrFw;
36868c2ecf20Sopenharmony_ci	u32			 diagRwData;
36878c2ecf20Sopenharmony_ci	u32			 nextImage;
36888c2ecf20Sopenharmony_ci	u32			 load_addr;
36898c2ecf20Sopenharmony_ci	u32 			 ioc_state=0;
36908c2ecf20Sopenharmony_ci
36918c2ecf20Sopenharmony_ci	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
36928c2ecf20Sopenharmony_ci				ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
36938c2ecf20Sopenharmony_ci
36948c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
36958c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
36968c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
36978c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
36988c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
36998c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
37008c2ecf20Sopenharmony_ci
37018c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
37028c2ecf20Sopenharmony_ci
37038c2ecf20Sopenharmony_ci	/* wait 1 msec */
37048c2ecf20Sopenharmony_ci	if (sleepFlag == CAN_SLEEP) {
37058c2ecf20Sopenharmony_ci		msleep(1);
37068c2ecf20Sopenharmony_ci	} else {
37078c2ecf20Sopenharmony_ci		mdelay (1);
37088c2ecf20Sopenharmony_ci	}
37098c2ecf20Sopenharmony_ci
37108c2ecf20Sopenharmony_ci	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
37118c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
37128c2ecf20Sopenharmony_ci
37138c2ecf20Sopenharmony_ci	for (count = 0; count < 30; count ++) {
37148c2ecf20Sopenharmony_ci		diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
37158c2ecf20Sopenharmony_ci		if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
37168c2ecf20Sopenharmony_ci			ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
37178c2ecf20Sopenharmony_ci				ioc->name, count));
37188c2ecf20Sopenharmony_ci			break;
37198c2ecf20Sopenharmony_ci		}
37208c2ecf20Sopenharmony_ci		/* wait .1 sec */
37218c2ecf20Sopenharmony_ci		if (sleepFlag == CAN_SLEEP) {
37228c2ecf20Sopenharmony_ci			msleep (100);
37238c2ecf20Sopenharmony_ci		} else {
37248c2ecf20Sopenharmony_ci			mdelay (100);
37258c2ecf20Sopenharmony_ci		}
37268c2ecf20Sopenharmony_ci	}
37278c2ecf20Sopenharmony_ci
37288c2ecf20Sopenharmony_ci	if ( count == 30 ) {
37298c2ecf20Sopenharmony_ci		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
37308c2ecf20Sopenharmony_ci		"Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
37318c2ecf20Sopenharmony_ci		ioc->name, diag0val));
37328c2ecf20Sopenharmony_ci		return -3;
37338c2ecf20Sopenharmony_ci	}
37348c2ecf20Sopenharmony_ci
37358c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
37368c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
37378c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
37388c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
37398c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
37408c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
37418c2ecf20Sopenharmony_ci
37428c2ecf20Sopenharmony_ci	/* Set the DiagRwEn and Disable ARM bits */
37438c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
37448c2ecf20Sopenharmony_ci
37458c2ecf20Sopenharmony_ci	fwSize = (pFwHeader->ImageSize + 3)/4;
37468c2ecf20Sopenharmony_ci	ptrFw = (u32 *) pFwHeader;
37478c2ecf20Sopenharmony_ci
37488c2ecf20Sopenharmony_ci	/* Write the LoadStartAddress to the DiagRw Address Register
37498c2ecf20Sopenharmony_ci	 * using Programmed IO
37508c2ecf20Sopenharmony_ci	 */
37518c2ecf20Sopenharmony_ci	if (ioc->errata_flag_1064)
37528c2ecf20Sopenharmony_ci		pci_enable_io_access(ioc->pcidev);
37538c2ecf20Sopenharmony_ci
37548c2ecf20Sopenharmony_ci	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
37558c2ecf20Sopenharmony_ci	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
37568c2ecf20Sopenharmony_ci		ioc->name, pFwHeader->LoadStartAddress));
37578c2ecf20Sopenharmony_ci
37588c2ecf20Sopenharmony_ci	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
37598c2ecf20Sopenharmony_ci				ioc->name, fwSize*4, ptrFw));
37608c2ecf20Sopenharmony_ci	while (fwSize--) {
37618c2ecf20Sopenharmony_ci		CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
37628c2ecf20Sopenharmony_ci	}
37638c2ecf20Sopenharmony_ci
37648c2ecf20Sopenharmony_ci	nextImage = pFwHeader->NextImageHeaderOffset;
37658c2ecf20Sopenharmony_ci	while (nextImage) {
37668c2ecf20Sopenharmony_ci		pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
37678c2ecf20Sopenharmony_ci
37688c2ecf20Sopenharmony_ci		load_addr = pExtImage->LoadStartAddress;
37698c2ecf20Sopenharmony_ci
37708c2ecf20Sopenharmony_ci		fwSize = (pExtImage->ImageSize + 3) >> 2;
37718c2ecf20Sopenharmony_ci		ptrFw = (u32 *)pExtImage;
37728c2ecf20Sopenharmony_ci
37738c2ecf20Sopenharmony_ci		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
37748c2ecf20Sopenharmony_ci						ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
37758c2ecf20Sopenharmony_ci		CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
37768c2ecf20Sopenharmony_ci
37778c2ecf20Sopenharmony_ci		while (fwSize--) {
37788c2ecf20Sopenharmony_ci			CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
37798c2ecf20Sopenharmony_ci		}
37808c2ecf20Sopenharmony_ci		nextImage = pExtImage->NextImageHeaderOffset;
37818c2ecf20Sopenharmony_ci	}
37828c2ecf20Sopenharmony_ci
37838c2ecf20Sopenharmony_ci	/* Write the IopResetVectorRegAddr */
37848c2ecf20Sopenharmony_ci	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, 	pFwHeader->IopResetRegAddr));
37858c2ecf20Sopenharmony_ci	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
37868c2ecf20Sopenharmony_ci
37878c2ecf20Sopenharmony_ci	/* Write the IopResetVectorValue */
37888c2ecf20Sopenharmony_ci	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
37898c2ecf20Sopenharmony_ci	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
37908c2ecf20Sopenharmony_ci
37918c2ecf20Sopenharmony_ci	/* Clear the internal flash bad bit - autoincrementing register,
37928c2ecf20Sopenharmony_ci	 * so must do two writes.
37938c2ecf20Sopenharmony_ci	 */
37948c2ecf20Sopenharmony_ci	if (ioc->bus_type == SPI) {
37958c2ecf20Sopenharmony_ci		/*
37968c2ecf20Sopenharmony_ci		 * 1030 and 1035 H/W errata, workaround to access
37978c2ecf20Sopenharmony_ci		 * the ClearFlashBadSignatureBit
37988c2ecf20Sopenharmony_ci		 */
37998c2ecf20Sopenharmony_ci		CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
38008c2ecf20Sopenharmony_ci		diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
38018c2ecf20Sopenharmony_ci		diagRwData |= 0x40000000;
38028c2ecf20Sopenharmony_ci		CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
38038c2ecf20Sopenharmony_ci		CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
38048c2ecf20Sopenharmony_ci
38058c2ecf20Sopenharmony_ci	} else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
38068c2ecf20Sopenharmony_ci		diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
38078c2ecf20Sopenharmony_ci		CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
38088c2ecf20Sopenharmony_ci		    MPI_DIAG_CLEAR_FLASH_BAD_SIG);
38098c2ecf20Sopenharmony_ci
38108c2ecf20Sopenharmony_ci		/* wait 1 msec */
38118c2ecf20Sopenharmony_ci		if (sleepFlag == CAN_SLEEP) {
38128c2ecf20Sopenharmony_ci			msleep (1);
38138c2ecf20Sopenharmony_ci		} else {
38148c2ecf20Sopenharmony_ci			mdelay (1);
38158c2ecf20Sopenharmony_ci		}
38168c2ecf20Sopenharmony_ci	}
38178c2ecf20Sopenharmony_ci
38188c2ecf20Sopenharmony_ci	if (ioc->errata_flag_1064)
38198c2ecf20Sopenharmony_ci		pci_disable_io_access(ioc->pcidev);
38208c2ecf20Sopenharmony_ci
38218c2ecf20Sopenharmony_ci	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
38228c2ecf20Sopenharmony_ci	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
38238c2ecf20Sopenharmony_ci		"turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
38248c2ecf20Sopenharmony_ci		ioc->name, diag0val));
38258c2ecf20Sopenharmony_ci	diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
38268c2ecf20Sopenharmony_ci	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
38278c2ecf20Sopenharmony_ci		ioc->name, diag0val));
38288c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
38298c2ecf20Sopenharmony_ci
38308c2ecf20Sopenharmony_ci	/* Write 0xFF to reset the sequencer */
38318c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
38328c2ecf20Sopenharmony_ci
38338c2ecf20Sopenharmony_ci	if (ioc->bus_type == SAS) {
38348c2ecf20Sopenharmony_ci		ioc_state = mpt_GetIocState(ioc, 0);
38358c2ecf20Sopenharmony_ci		if ( (GetIocFacts(ioc, sleepFlag,
38368c2ecf20Sopenharmony_ci				MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
38378c2ecf20Sopenharmony_ci			ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
38388c2ecf20Sopenharmony_ci					ioc->name, ioc_state));
38398c2ecf20Sopenharmony_ci			return -EFAULT;
38408c2ecf20Sopenharmony_ci		}
38418c2ecf20Sopenharmony_ci	}
38428c2ecf20Sopenharmony_ci
38438c2ecf20Sopenharmony_ci	for (count=0; count<HZ*20; count++) {
38448c2ecf20Sopenharmony_ci		if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
38458c2ecf20Sopenharmony_ci			ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
38468c2ecf20Sopenharmony_ci				"downloadboot successful! (count=%d) IocState=%x\n",
38478c2ecf20Sopenharmony_ci				ioc->name, count, ioc_state));
38488c2ecf20Sopenharmony_ci			if (ioc->bus_type == SAS) {
38498c2ecf20Sopenharmony_ci				return 0;
38508c2ecf20Sopenharmony_ci			}
38518c2ecf20Sopenharmony_ci			if ((SendIocInit(ioc, sleepFlag)) != 0) {
38528c2ecf20Sopenharmony_ci				ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
38538c2ecf20Sopenharmony_ci					"downloadboot: SendIocInit failed\n",
38548c2ecf20Sopenharmony_ci					ioc->name));
38558c2ecf20Sopenharmony_ci				return -EFAULT;
38568c2ecf20Sopenharmony_ci			}
38578c2ecf20Sopenharmony_ci			ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
38588c2ecf20Sopenharmony_ci					"downloadboot: SendIocInit successful\n",
38598c2ecf20Sopenharmony_ci					ioc->name));
38608c2ecf20Sopenharmony_ci			return 0;
38618c2ecf20Sopenharmony_ci		}
38628c2ecf20Sopenharmony_ci		if (sleepFlag == CAN_SLEEP) {
38638c2ecf20Sopenharmony_ci			msleep (10);
38648c2ecf20Sopenharmony_ci		} else {
38658c2ecf20Sopenharmony_ci			mdelay (10);
38668c2ecf20Sopenharmony_ci		}
38678c2ecf20Sopenharmony_ci	}
38688c2ecf20Sopenharmony_ci	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
38698c2ecf20Sopenharmony_ci		"downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
38708c2ecf20Sopenharmony_ci	return -EFAULT;
38718c2ecf20Sopenharmony_ci}
38728c2ecf20Sopenharmony_ci
38738c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
38748c2ecf20Sopenharmony_ci/**
38758c2ecf20Sopenharmony_ci *	KickStart - Perform hard reset of MPT adapter.
38768c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
38778c2ecf20Sopenharmony_ci *	@force: Force hard reset
38788c2ecf20Sopenharmony_ci *	@sleepFlag: Specifies whether the process can sleep
38798c2ecf20Sopenharmony_ci *
38808c2ecf20Sopenharmony_ci *	This routine places MPT adapter in diagnostic mode via the
38818c2ecf20Sopenharmony_ci *	WriteSequence register, and then performs a hard reset of adapter
38828c2ecf20Sopenharmony_ci *	via the Diagnostic register.
38838c2ecf20Sopenharmony_ci *
38848c2ecf20Sopenharmony_ci *	Inputs:   sleepflag - CAN_SLEEP (non-interrupt thread)
38858c2ecf20Sopenharmony_ci *			or NO_SLEEP (interrupt thread, use mdelay)
38868c2ecf20Sopenharmony_ci *		  force - 1 if doorbell active, board fault state
38878c2ecf20Sopenharmony_ci *				board operational, IOC_RECOVERY or
38888c2ecf20Sopenharmony_ci *				IOC_BRINGUP and there is an alt_ioc.
38898c2ecf20Sopenharmony_ci *			  0 else
38908c2ecf20Sopenharmony_ci *
38918c2ecf20Sopenharmony_ci *	Returns:
38928c2ecf20Sopenharmony_ci *		 1 - hard reset, READY
38938c2ecf20Sopenharmony_ci *		 0 - no reset due to History bit, READY
38948c2ecf20Sopenharmony_ci *		-1 - no reset due to History bit but not READY
38958c2ecf20Sopenharmony_ci *		     OR reset but failed to come READY
38968c2ecf20Sopenharmony_ci *		-2 - no reset, could not enter DIAG mode
38978c2ecf20Sopenharmony_ci *		-3 - reset but bad FW bit
38988c2ecf20Sopenharmony_ci */
38998c2ecf20Sopenharmony_cistatic int
39008c2ecf20Sopenharmony_ciKickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
39018c2ecf20Sopenharmony_ci{
39028c2ecf20Sopenharmony_ci	int hard_reset_done = 0;
39038c2ecf20Sopenharmony_ci	u32 ioc_state=0;
39048c2ecf20Sopenharmony_ci	int cnt,cntdn;
39058c2ecf20Sopenharmony_ci
39068c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
39078c2ecf20Sopenharmony_ci	if (ioc->bus_type == SPI) {
39088c2ecf20Sopenharmony_ci		/* Always issue a Msg Unit Reset first. This will clear some
39098c2ecf20Sopenharmony_ci		 * SCSI bus hang conditions.
39108c2ecf20Sopenharmony_ci		 */
39118c2ecf20Sopenharmony_ci		SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
39128c2ecf20Sopenharmony_ci
39138c2ecf20Sopenharmony_ci		if (sleepFlag == CAN_SLEEP) {
39148c2ecf20Sopenharmony_ci			msleep (1000);
39158c2ecf20Sopenharmony_ci		} else {
39168c2ecf20Sopenharmony_ci			mdelay (1000);
39178c2ecf20Sopenharmony_ci		}
39188c2ecf20Sopenharmony_ci	}
39198c2ecf20Sopenharmony_ci
39208c2ecf20Sopenharmony_ci	hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
39218c2ecf20Sopenharmony_ci	if (hard_reset_done < 0)
39228c2ecf20Sopenharmony_ci		return hard_reset_done;
39238c2ecf20Sopenharmony_ci
39248c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
39258c2ecf20Sopenharmony_ci		ioc->name));
39268c2ecf20Sopenharmony_ci
39278c2ecf20Sopenharmony_ci	cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2;	/* 2 seconds */
39288c2ecf20Sopenharmony_ci	for (cnt=0; cnt<cntdn; cnt++) {
39298c2ecf20Sopenharmony_ci		ioc_state = mpt_GetIocState(ioc, 1);
39308c2ecf20Sopenharmony_ci		if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
39318c2ecf20Sopenharmony_ci			dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
39328c2ecf20Sopenharmony_ci 					ioc->name, cnt));
39338c2ecf20Sopenharmony_ci			return hard_reset_done;
39348c2ecf20Sopenharmony_ci		}
39358c2ecf20Sopenharmony_ci		if (sleepFlag == CAN_SLEEP) {
39368c2ecf20Sopenharmony_ci			msleep (10);
39378c2ecf20Sopenharmony_ci		} else {
39388c2ecf20Sopenharmony_ci			mdelay (10);
39398c2ecf20Sopenharmony_ci		}
39408c2ecf20Sopenharmony_ci	}
39418c2ecf20Sopenharmony_ci
39428c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
39438c2ecf20Sopenharmony_ci		ioc->name, mpt_GetIocState(ioc, 0)));
39448c2ecf20Sopenharmony_ci	return -1;
39458c2ecf20Sopenharmony_ci}
39468c2ecf20Sopenharmony_ci
39478c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
39488c2ecf20Sopenharmony_ci/**
39498c2ecf20Sopenharmony_ci *	mpt_diag_reset - Perform hard reset of the adapter.
39508c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
39518c2ecf20Sopenharmony_ci *	@ignore: Set if to honor and clear to ignore
39528c2ecf20Sopenharmony_ci *		the reset history bit
39538c2ecf20Sopenharmony_ci *	@sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
39548c2ecf20Sopenharmony_ci *		else set to NO_SLEEP (use mdelay instead)
39558c2ecf20Sopenharmony_ci *
39568c2ecf20Sopenharmony_ci *	This routine places the adapter in diagnostic mode via the
39578c2ecf20Sopenharmony_ci *	WriteSequence register and then performs a hard reset of adapter
39588c2ecf20Sopenharmony_ci *	via the Diagnostic register. Adapter should be in ready state
39598c2ecf20Sopenharmony_ci *	upon successful completion.
39608c2ecf20Sopenharmony_ci *
39618c2ecf20Sopenharmony_ci *	Returns:  1  hard reset successful
39628c2ecf20Sopenharmony_ci *		  0  no reset performed because reset history bit set
39638c2ecf20Sopenharmony_ci *		 -2  enabling diagnostic mode failed
39648c2ecf20Sopenharmony_ci *		 -3  diagnostic reset failed
39658c2ecf20Sopenharmony_ci */
39668c2ecf20Sopenharmony_cistatic int
39678c2ecf20Sopenharmony_cimpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
39688c2ecf20Sopenharmony_ci{
39698c2ecf20Sopenharmony_ci	u32 diag0val;
39708c2ecf20Sopenharmony_ci	u32 doorbell;
39718c2ecf20Sopenharmony_ci	int hard_reset_done = 0;
39728c2ecf20Sopenharmony_ci	int count = 0;
39738c2ecf20Sopenharmony_ci	u32 diag1val = 0;
39748c2ecf20Sopenharmony_ci	MpiFwHeader_t *cached_fw;	/* Pointer to FW */
39758c2ecf20Sopenharmony_ci	u8	 cb_idx;
39768c2ecf20Sopenharmony_ci
39778c2ecf20Sopenharmony_ci	/* Clear any existing interrupts */
39788c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
39798c2ecf20Sopenharmony_ci
39808c2ecf20Sopenharmony_ci	if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
39818c2ecf20Sopenharmony_ci
39828c2ecf20Sopenharmony_ci		if (!ignore)
39838c2ecf20Sopenharmony_ci			return 0;
39848c2ecf20Sopenharmony_ci
39858c2ecf20Sopenharmony_ci		drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
39868c2ecf20Sopenharmony_ci			"address=%p\n",  ioc->name, __func__,
39878c2ecf20Sopenharmony_ci			&ioc->chip->Doorbell, &ioc->chip->Reset_1078));
39888c2ecf20Sopenharmony_ci		CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
39898c2ecf20Sopenharmony_ci		if (sleepFlag == CAN_SLEEP)
39908c2ecf20Sopenharmony_ci			msleep(1);
39918c2ecf20Sopenharmony_ci		else
39928c2ecf20Sopenharmony_ci			mdelay(1);
39938c2ecf20Sopenharmony_ci
39948c2ecf20Sopenharmony_ci		/*
39958c2ecf20Sopenharmony_ci		 * Call each currently registered protocol IOC reset handler
39968c2ecf20Sopenharmony_ci		 * with pre-reset indication.
39978c2ecf20Sopenharmony_ci		 * NOTE: If we're doing _IOC_BRINGUP, there can be no
39988c2ecf20Sopenharmony_ci		 * MptResetHandlers[] registered yet.
39998c2ecf20Sopenharmony_ci		 */
40008c2ecf20Sopenharmony_ci		for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
40018c2ecf20Sopenharmony_ci			if (MptResetHandlers[cb_idx])
40028c2ecf20Sopenharmony_ci				(*(MptResetHandlers[cb_idx]))(ioc,
40038c2ecf20Sopenharmony_ci						MPT_IOC_PRE_RESET);
40048c2ecf20Sopenharmony_ci		}
40058c2ecf20Sopenharmony_ci
40068c2ecf20Sopenharmony_ci		for (count = 0; count < 60; count ++) {
40078c2ecf20Sopenharmony_ci			doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
40088c2ecf20Sopenharmony_ci			doorbell &= MPI_IOC_STATE_MASK;
40098c2ecf20Sopenharmony_ci
40108c2ecf20Sopenharmony_ci			drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
40118c2ecf20Sopenharmony_ci				"looking for READY STATE: doorbell=%x"
40128c2ecf20Sopenharmony_ci			        " count=%d\n",
40138c2ecf20Sopenharmony_ci				ioc->name, doorbell, count));
40148c2ecf20Sopenharmony_ci
40158c2ecf20Sopenharmony_ci			if (doorbell == MPI_IOC_STATE_READY) {
40168c2ecf20Sopenharmony_ci				return 1;
40178c2ecf20Sopenharmony_ci			}
40188c2ecf20Sopenharmony_ci
40198c2ecf20Sopenharmony_ci			/* wait 1 sec */
40208c2ecf20Sopenharmony_ci			if (sleepFlag == CAN_SLEEP)
40218c2ecf20Sopenharmony_ci				msleep(1000);
40228c2ecf20Sopenharmony_ci			else
40238c2ecf20Sopenharmony_ci				mdelay(1000);
40248c2ecf20Sopenharmony_ci		}
40258c2ecf20Sopenharmony_ci		return -1;
40268c2ecf20Sopenharmony_ci	}
40278c2ecf20Sopenharmony_ci
40288c2ecf20Sopenharmony_ci	/* Use "Diagnostic reset" method! (only thing available!) */
40298c2ecf20Sopenharmony_ci	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
40308c2ecf20Sopenharmony_ci
40318c2ecf20Sopenharmony_ci	if (ioc->debug_level & MPT_DEBUG) {
40328c2ecf20Sopenharmony_ci		if (ioc->alt_ioc)
40338c2ecf20Sopenharmony_ci			diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
40348c2ecf20Sopenharmony_ci		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
40358c2ecf20Sopenharmony_ci			ioc->name, diag0val, diag1val));
40368c2ecf20Sopenharmony_ci	}
40378c2ecf20Sopenharmony_ci
40388c2ecf20Sopenharmony_ci	/* Do the reset if we are told to ignore the reset history
40398c2ecf20Sopenharmony_ci	 * or if the reset history is 0
40408c2ecf20Sopenharmony_ci	 */
40418c2ecf20Sopenharmony_ci	if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
40428c2ecf20Sopenharmony_ci		while ((diag0val & MPI_DIAG_DRWE) == 0) {
40438c2ecf20Sopenharmony_ci			/* Write magic sequence to WriteSequence register
40448c2ecf20Sopenharmony_ci			 * Loop until in diagnostic mode
40458c2ecf20Sopenharmony_ci			 */
40468c2ecf20Sopenharmony_ci			CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
40478c2ecf20Sopenharmony_ci			CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
40488c2ecf20Sopenharmony_ci			CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
40498c2ecf20Sopenharmony_ci			CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
40508c2ecf20Sopenharmony_ci			CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
40518c2ecf20Sopenharmony_ci			CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
40528c2ecf20Sopenharmony_ci
40538c2ecf20Sopenharmony_ci			/* wait 100 msec */
40548c2ecf20Sopenharmony_ci			if (sleepFlag == CAN_SLEEP) {
40558c2ecf20Sopenharmony_ci				msleep (100);
40568c2ecf20Sopenharmony_ci			} else {
40578c2ecf20Sopenharmony_ci				mdelay (100);
40588c2ecf20Sopenharmony_ci			}
40598c2ecf20Sopenharmony_ci
40608c2ecf20Sopenharmony_ci			count++;
40618c2ecf20Sopenharmony_ci			if (count > 20) {
40628c2ecf20Sopenharmony_ci				printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
40638c2ecf20Sopenharmony_ci						ioc->name, diag0val);
40648c2ecf20Sopenharmony_ci				return -2;
40658c2ecf20Sopenharmony_ci
40668c2ecf20Sopenharmony_ci			}
40678c2ecf20Sopenharmony_ci
40688c2ecf20Sopenharmony_ci			diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
40698c2ecf20Sopenharmony_ci
40708c2ecf20Sopenharmony_ci			dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
40718c2ecf20Sopenharmony_ci					ioc->name, diag0val));
40728c2ecf20Sopenharmony_ci		}
40738c2ecf20Sopenharmony_ci
40748c2ecf20Sopenharmony_ci		if (ioc->debug_level & MPT_DEBUG) {
40758c2ecf20Sopenharmony_ci			if (ioc->alt_ioc)
40768c2ecf20Sopenharmony_ci				diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
40778c2ecf20Sopenharmony_ci			dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
40788c2ecf20Sopenharmony_ci				ioc->name, diag0val, diag1val));
40798c2ecf20Sopenharmony_ci		}
40808c2ecf20Sopenharmony_ci		/*
40818c2ecf20Sopenharmony_ci		 * Disable the ARM (Bug fix)
40828c2ecf20Sopenharmony_ci		 *
40838c2ecf20Sopenharmony_ci		 */
40848c2ecf20Sopenharmony_ci		CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
40858c2ecf20Sopenharmony_ci		mdelay(1);
40868c2ecf20Sopenharmony_ci
40878c2ecf20Sopenharmony_ci		/*
40888c2ecf20Sopenharmony_ci		 * Now hit the reset bit in the Diagnostic register
40898c2ecf20Sopenharmony_ci		 * (THE BIG HAMMER!) (Clears DRWE bit).
40908c2ecf20Sopenharmony_ci		 */
40918c2ecf20Sopenharmony_ci		CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
40928c2ecf20Sopenharmony_ci		hard_reset_done = 1;
40938c2ecf20Sopenharmony_ci		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
40948c2ecf20Sopenharmony_ci				ioc->name));
40958c2ecf20Sopenharmony_ci
40968c2ecf20Sopenharmony_ci		/*
40978c2ecf20Sopenharmony_ci		 * Call each currently registered protocol IOC reset handler
40988c2ecf20Sopenharmony_ci		 * with pre-reset indication.
40998c2ecf20Sopenharmony_ci		 * NOTE: If we're doing _IOC_BRINGUP, there can be no
41008c2ecf20Sopenharmony_ci		 * MptResetHandlers[] registered yet.
41018c2ecf20Sopenharmony_ci		 */
41028c2ecf20Sopenharmony_ci		for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
41038c2ecf20Sopenharmony_ci			if (MptResetHandlers[cb_idx]) {
41048c2ecf20Sopenharmony_ci				mpt_signal_reset(cb_idx,
41058c2ecf20Sopenharmony_ci					ioc, MPT_IOC_PRE_RESET);
41068c2ecf20Sopenharmony_ci				if (ioc->alt_ioc) {
41078c2ecf20Sopenharmony_ci					mpt_signal_reset(cb_idx,
41088c2ecf20Sopenharmony_ci					ioc->alt_ioc, MPT_IOC_PRE_RESET);
41098c2ecf20Sopenharmony_ci				}
41108c2ecf20Sopenharmony_ci			}
41118c2ecf20Sopenharmony_ci		}
41128c2ecf20Sopenharmony_ci
41138c2ecf20Sopenharmony_ci		if (ioc->cached_fw)
41148c2ecf20Sopenharmony_ci			cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
41158c2ecf20Sopenharmony_ci		else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
41168c2ecf20Sopenharmony_ci			cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
41178c2ecf20Sopenharmony_ci		else
41188c2ecf20Sopenharmony_ci			cached_fw = NULL;
41198c2ecf20Sopenharmony_ci		if (cached_fw) {
41208c2ecf20Sopenharmony_ci			/* If the DownloadBoot operation fails, the
41218c2ecf20Sopenharmony_ci			 * IOC will be left unusable. This is a fatal error
41228c2ecf20Sopenharmony_ci			 * case.  _diag_reset will return < 0
41238c2ecf20Sopenharmony_ci			 */
41248c2ecf20Sopenharmony_ci			for (count = 0; count < 30; count ++) {
41258c2ecf20Sopenharmony_ci				diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
41268c2ecf20Sopenharmony_ci				if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
41278c2ecf20Sopenharmony_ci					break;
41288c2ecf20Sopenharmony_ci				}
41298c2ecf20Sopenharmony_ci
41308c2ecf20Sopenharmony_ci				dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
41318c2ecf20Sopenharmony_ci					ioc->name, diag0val, count));
41328c2ecf20Sopenharmony_ci				/* wait 1 sec */
41338c2ecf20Sopenharmony_ci				if (sleepFlag == CAN_SLEEP) {
41348c2ecf20Sopenharmony_ci					msleep (1000);
41358c2ecf20Sopenharmony_ci				} else {
41368c2ecf20Sopenharmony_ci					mdelay (1000);
41378c2ecf20Sopenharmony_ci				}
41388c2ecf20Sopenharmony_ci			}
41398c2ecf20Sopenharmony_ci			if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
41408c2ecf20Sopenharmony_ci				printk(MYIOC_s_WARN_FMT
41418c2ecf20Sopenharmony_ci					"firmware downloadboot failure (%d)!\n", ioc->name, count);
41428c2ecf20Sopenharmony_ci			}
41438c2ecf20Sopenharmony_ci
41448c2ecf20Sopenharmony_ci		} else {
41458c2ecf20Sopenharmony_ci			/* Wait for FW to reload and for board
41468c2ecf20Sopenharmony_ci			 * to go to the READY state.
41478c2ecf20Sopenharmony_ci			 * Maximum wait is 60 seconds.
41488c2ecf20Sopenharmony_ci			 * If fail, no error will check again
41498c2ecf20Sopenharmony_ci			 * with calling program.
41508c2ecf20Sopenharmony_ci			 */
41518c2ecf20Sopenharmony_ci			for (count = 0; count < 60; count ++) {
41528c2ecf20Sopenharmony_ci				doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
41538c2ecf20Sopenharmony_ci				doorbell &= MPI_IOC_STATE_MASK;
41548c2ecf20Sopenharmony_ci
41558c2ecf20Sopenharmony_ci				drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
41568c2ecf20Sopenharmony_ci				    "looking for READY STATE: doorbell=%x"
41578c2ecf20Sopenharmony_ci				    " count=%d\n", ioc->name, doorbell, count));
41588c2ecf20Sopenharmony_ci
41598c2ecf20Sopenharmony_ci				if (doorbell == MPI_IOC_STATE_READY) {
41608c2ecf20Sopenharmony_ci					break;
41618c2ecf20Sopenharmony_ci				}
41628c2ecf20Sopenharmony_ci
41638c2ecf20Sopenharmony_ci				/* wait 1 sec */
41648c2ecf20Sopenharmony_ci				if (sleepFlag == CAN_SLEEP) {
41658c2ecf20Sopenharmony_ci					msleep (1000);
41668c2ecf20Sopenharmony_ci				} else {
41678c2ecf20Sopenharmony_ci					mdelay (1000);
41688c2ecf20Sopenharmony_ci				}
41698c2ecf20Sopenharmony_ci			}
41708c2ecf20Sopenharmony_ci
41718c2ecf20Sopenharmony_ci			if (doorbell != MPI_IOC_STATE_READY)
41728c2ecf20Sopenharmony_ci				printk(MYIOC_s_ERR_FMT "Failed to come READY "
41738c2ecf20Sopenharmony_ci				    "after reset! IocState=%x", ioc->name,
41748c2ecf20Sopenharmony_ci				    doorbell);
41758c2ecf20Sopenharmony_ci		}
41768c2ecf20Sopenharmony_ci	}
41778c2ecf20Sopenharmony_ci
41788c2ecf20Sopenharmony_ci	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
41798c2ecf20Sopenharmony_ci	if (ioc->debug_level & MPT_DEBUG) {
41808c2ecf20Sopenharmony_ci		if (ioc->alt_ioc)
41818c2ecf20Sopenharmony_ci			diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
41828c2ecf20Sopenharmony_ci		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
41838c2ecf20Sopenharmony_ci			ioc->name, diag0val, diag1val));
41848c2ecf20Sopenharmony_ci	}
41858c2ecf20Sopenharmony_ci
41868c2ecf20Sopenharmony_ci	/* Clear RESET_HISTORY bit!  Place board in the
41878c2ecf20Sopenharmony_ci	 * diagnostic mode to update the diag register.
41888c2ecf20Sopenharmony_ci	 */
41898c2ecf20Sopenharmony_ci	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
41908c2ecf20Sopenharmony_ci	count = 0;
41918c2ecf20Sopenharmony_ci	while ((diag0val & MPI_DIAG_DRWE) == 0) {
41928c2ecf20Sopenharmony_ci		/* Write magic sequence to WriteSequence register
41938c2ecf20Sopenharmony_ci		 * Loop until in diagnostic mode
41948c2ecf20Sopenharmony_ci		 */
41958c2ecf20Sopenharmony_ci		CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
41968c2ecf20Sopenharmony_ci		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
41978c2ecf20Sopenharmony_ci		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
41988c2ecf20Sopenharmony_ci		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
41998c2ecf20Sopenharmony_ci		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
42008c2ecf20Sopenharmony_ci		CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
42018c2ecf20Sopenharmony_ci
42028c2ecf20Sopenharmony_ci		/* wait 100 msec */
42038c2ecf20Sopenharmony_ci		if (sleepFlag == CAN_SLEEP) {
42048c2ecf20Sopenharmony_ci			msleep (100);
42058c2ecf20Sopenharmony_ci		} else {
42068c2ecf20Sopenharmony_ci			mdelay (100);
42078c2ecf20Sopenharmony_ci		}
42088c2ecf20Sopenharmony_ci
42098c2ecf20Sopenharmony_ci		count++;
42108c2ecf20Sopenharmony_ci		if (count > 20) {
42118c2ecf20Sopenharmony_ci			printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
42128c2ecf20Sopenharmony_ci					ioc->name, diag0val);
42138c2ecf20Sopenharmony_ci			break;
42148c2ecf20Sopenharmony_ci		}
42158c2ecf20Sopenharmony_ci		diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
42168c2ecf20Sopenharmony_ci	}
42178c2ecf20Sopenharmony_ci	diag0val &= ~MPI_DIAG_RESET_HISTORY;
42188c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
42198c2ecf20Sopenharmony_ci	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
42208c2ecf20Sopenharmony_ci	if (diag0val & MPI_DIAG_RESET_HISTORY) {
42218c2ecf20Sopenharmony_ci		printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
42228c2ecf20Sopenharmony_ci				ioc->name);
42238c2ecf20Sopenharmony_ci	}
42248c2ecf20Sopenharmony_ci
42258c2ecf20Sopenharmony_ci	/* Disable Diagnostic Mode
42268c2ecf20Sopenharmony_ci	 */
42278c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
42288c2ecf20Sopenharmony_ci
42298c2ecf20Sopenharmony_ci	/* Check FW reload status flags.
42308c2ecf20Sopenharmony_ci	 */
42318c2ecf20Sopenharmony_ci	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
42328c2ecf20Sopenharmony_ci	if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
42338c2ecf20Sopenharmony_ci		printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
42348c2ecf20Sopenharmony_ci				ioc->name, diag0val);
42358c2ecf20Sopenharmony_ci		return -3;
42368c2ecf20Sopenharmony_ci	}
42378c2ecf20Sopenharmony_ci
42388c2ecf20Sopenharmony_ci	if (ioc->debug_level & MPT_DEBUG) {
42398c2ecf20Sopenharmony_ci		if (ioc->alt_ioc)
42408c2ecf20Sopenharmony_ci			diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
42418c2ecf20Sopenharmony_ci		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
42428c2ecf20Sopenharmony_ci			ioc->name, diag0val, diag1val));
42438c2ecf20Sopenharmony_ci	}
42448c2ecf20Sopenharmony_ci
42458c2ecf20Sopenharmony_ci	/*
42468c2ecf20Sopenharmony_ci	 * Reset flag that says we've enabled event notification
42478c2ecf20Sopenharmony_ci	 */
42488c2ecf20Sopenharmony_ci	ioc->facts.EventState = 0;
42498c2ecf20Sopenharmony_ci
42508c2ecf20Sopenharmony_ci	if (ioc->alt_ioc)
42518c2ecf20Sopenharmony_ci		ioc->alt_ioc->facts.EventState = 0;
42528c2ecf20Sopenharmony_ci
42538c2ecf20Sopenharmony_ci	return hard_reset_done;
42548c2ecf20Sopenharmony_ci}
42558c2ecf20Sopenharmony_ci
42568c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
42578c2ecf20Sopenharmony_ci/**
42588c2ecf20Sopenharmony_ci *	SendIocReset - Send IOCReset request to MPT adapter.
42598c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
42608c2ecf20Sopenharmony_ci *	@reset_type: reset type, expected values are
42618c2ecf20Sopenharmony_ci *	%MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
42628c2ecf20Sopenharmony_ci *	@sleepFlag: Specifies whether the process can sleep
42638c2ecf20Sopenharmony_ci *
42648c2ecf20Sopenharmony_ci *	Send IOCReset request to the MPT adapter.
42658c2ecf20Sopenharmony_ci *
42668c2ecf20Sopenharmony_ci *	Returns 0 for success, non-zero for failure.
42678c2ecf20Sopenharmony_ci */
42688c2ecf20Sopenharmony_cistatic int
42698c2ecf20Sopenharmony_ciSendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
42708c2ecf20Sopenharmony_ci{
42718c2ecf20Sopenharmony_ci	int r;
42728c2ecf20Sopenharmony_ci	u32 state;
42738c2ecf20Sopenharmony_ci	int cntdn, count;
42748c2ecf20Sopenharmony_ci
42758c2ecf20Sopenharmony_ci	drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
42768c2ecf20Sopenharmony_ci			ioc->name, reset_type));
42778c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
42788c2ecf20Sopenharmony_ci	if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
42798c2ecf20Sopenharmony_ci		return r;
42808c2ecf20Sopenharmony_ci
42818c2ecf20Sopenharmony_ci	/* FW ACK'd request, wait for READY state
42828c2ecf20Sopenharmony_ci	 */
42838c2ecf20Sopenharmony_ci	count = 0;
42848c2ecf20Sopenharmony_ci	cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15;	/* 15 seconds */
42858c2ecf20Sopenharmony_ci
42868c2ecf20Sopenharmony_ci	while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
42878c2ecf20Sopenharmony_ci		cntdn--;
42888c2ecf20Sopenharmony_ci		count++;
42898c2ecf20Sopenharmony_ci		if (!cntdn) {
42908c2ecf20Sopenharmony_ci			if (sleepFlag != CAN_SLEEP)
42918c2ecf20Sopenharmony_ci				count *= 10;
42928c2ecf20Sopenharmony_ci
42938c2ecf20Sopenharmony_ci			printk(MYIOC_s_ERR_FMT
42948c2ecf20Sopenharmony_ci			    "Wait IOC_READY state (0x%x) timeout(%d)!\n",
42958c2ecf20Sopenharmony_ci			    ioc->name, state, (int)((count+5)/HZ));
42968c2ecf20Sopenharmony_ci			return -ETIME;
42978c2ecf20Sopenharmony_ci		}
42988c2ecf20Sopenharmony_ci
42998c2ecf20Sopenharmony_ci		if (sleepFlag == CAN_SLEEP) {
43008c2ecf20Sopenharmony_ci			msleep(1);
43018c2ecf20Sopenharmony_ci		} else {
43028c2ecf20Sopenharmony_ci			mdelay (1);	/* 1 msec delay */
43038c2ecf20Sopenharmony_ci		}
43048c2ecf20Sopenharmony_ci	}
43058c2ecf20Sopenharmony_ci
43068c2ecf20Sopenharmony_ci	/* TODO!
43078c2ecf20Sopenharmony_ci	 *  Cleanup all event stuff for this IOC; re-issue EventNotification
43088c2ecf20Sopenharmony_ci	 *  request if needed.
43098c2ecf20Sopenharmony_ci	 */
43108c2ecf20Sopenharmony_ci	if (ioc->facts.Function)
43118c2ecf20Sopenharmony_ci		ioc->facts.EventState = 0;
43128c2ecf20Sopenharmony_ci
43138c2ecf20Sopenharmony_ci	return 0;
43148c2ecf20Sopenharmony_ci}
43158c2ecf20Sopenharmony_ci
43168c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
43178c2ecf20Sopenharmony_ci/**
43188c2ecf20Sopenharmony_ci *	initChainBuffers - Allocate memory for and initialize chain buffers
43198c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
43208c2ecf20Sopenharmony_ci *
43218c2ecf20Sopenharmony_ci *	Allocates memory for and initializes chain buffers,
43228c2ecf20Sopenharmony_ci *	chain buffer control arrays and spinlock.
43238c2ecf20Sopenharmony_ci */
43248c2ecf20Sopenharmony_cistatic int
43258c2ecf20Sopenharmony_ciinitChainBuffers(MPT_ADAPTER *ioc)
43268c2ecf20Sopenharmony_ci{
43278c2ecf20Sopenharmony_ci	u8		*mem;
43288c2ecf20Sopenharmony_ci	int		sz, ii, num_chain;
43298c2ecf20Sopenharmony_ci	int 		scale, num_sge, numSGE;
43308c2ecf20Sopenharmony_ci
43318c2ecf20Sopenharmony_ci	/* ReqToChain size must equal the req_depth
43328c2ecf20Sopenharmony_ci	 * index = req_idx
43338c2ecf20Sopenharmony_ci	 */
43348c2ecf20Sopenharmony_ci	if (ioc->ReqToChain == NULL) {
43358c2ecf20Sopenharmony_ci		sz = ioc->req_depth * sizeof(int);
43368c2ecf20Sopenharmony_ci		mem = kmalloc(sz, GFP_ATOMIC);
43378c2ecf20Sopenharmony_ci		if (mem == NULL)
43388c2ecf20Sopenharmony_ci			return -1;
43398c2ecf20Sopenharmony_ci
43408c2ecf20Sopenharmony_ci		ioc->ReqToChain = (int *) mem;
43418c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc  @ %p, sz=%d bytes\n",
43428c2ecf20Sopenharmony_ci			 	ioc->name, mem, sz));
43438c2ecf20Sopenharmony_ci		mem = kmalloc(sz, GFP_ATOMIC);
43448c2ecf20Sopenharmony_ci		if (mem == NULL)
43458c2ecf20Sopenharmony_ci			return -1;
43468c2ecf20Sopenharmony_ci
43478c2ecf20Sopenharmony_ci		ioc->RequestNB = (int *) mem;
43488c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc  @ %p, sz=%d bytes\n",
43498c2ecf20Sopenharmony_ci			 	ioc->name, mem, sz));
43508c2ecf20Sopenharmony_ci	}
43518c2ecf20Sopenharmony_ci	for (ii = 0; ii < ioc->req_depth; ii++) {
43528c2ecf20Sopenharmony_ci		ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
43538c2ecf20Sopenharmony_ci	}
43548c2ecf20Sopenharmony_ci
43558c2ecf20Sopenharmony_ci	/* ChainToChain size must equal the total number
43568c2ecf20Sopenharmony_ci	 * of chain buffers to be allocated.
43578c2ecf20Sopenharmony_ci	 * index = chain_idx
43588c2ecf20Sopenharmony_ci	 *
43598c2ecf20Sopenharmony_ci	 * Calculate the number of chain buffers needed(plus 1) per I/O
43608c2ecf20Sopenharmony_ci	 * then multiply the maximum number of simultaneous cmds
43618c2ecf20Sopenharmony_ci	 *
43628c2ecf20Sopenharmony_ci	 * num_sge = num sge in request frame + last chain buffer
43638c2ecf20Sopenharmony_ci	 * scale = num sge per chain buffer if no chain element
43648c2ecf20Sopenharmony_ci	 */
43658c2ecf20Sopenharmony_ci	scale = ioc->req_sz / ioc->SGE_size;
43668c2ecf20Sopenharmony_ci	if (ioc->sg_addr_size == sizeof(u64))
43678c2ecf20Sopenharmony_ci		num_sge =  scale + (ioc->req_sz - 60) / ioc->SGE_size;
43688c2ecf20Sopenharmony_ci	else
43698c2ecf20Sopenharmony_ci		num_sge =  1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
43708c2ecf20Sopenharmony_ci
43718c2ecf20Sopenharmony_ci	if (ioc->sg_addr_size == sizeof(u64)) {
43728c2ecf20Sopenharmony_ci		numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
43738c2ecf20Sopenharmony_ci			(ioc->req_sz - 60) / ioc->SGE_size;
43748c2ecf20Sopenharmony_ci	} else {
43758c2ecf20Sopenharmony_ci		numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
43768c2ecf20Sopenharmony_ci		    scale + (ioc->req_sz - 64) / ioc->SGE_size;
43778c2ecf20Sopenharmony_ci	}
43788c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
43798c2ecf20Sopenharmony_ci		ioc->name, num_sge, numSGE));
43808c2ecf20Sopenharmony_ci
43818c2ecf20Sopenharmony_ci	if (ioc->bus_type == FC) {
43828c2ecf20Sopenharmony_ci		if (numSGE > MPT_SCSI_FC_SG_DEPTH)
43838c2ecf20Sopenharmony_ci			numSGE = MPT_SCSI_FC_SG_DEPTH;
43848c2ecf20Sopenharmony_ci	} else {
43858c2ecf20Sopenharmony_ci		if (numSGE > MPT_SCSI_SG_DEPTH)
43868c2ecf20Sopenharmony_ci			numSGE = MPT_SCSI_SG_DEPTH;
43878c2ecf20Sopenharmony_ci	}
43888c2ecf20Sopenharmony_ci
43898c2ecf20Sopenharmony_ci	num_chain = 1;
43908c2ecf20Sopenharmony_ci	while (numSGE - num_sge > 0) {
43918c2ecf20Sopenharmony_ci		num_chain++;
43928c2ecf20Sopenharmony_ci		num_sge += (scale - 1);
43938c2ecf20Sopenharmony_ci	}
43948c2ecf20Sopenharmony_ci	num_chain++;
43958c2ecf20Sopenharmony_ci
43968c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
43978c2ecf20Sopenharmony_ci		ioc->name, numSGE, num_sge, num_chain));
43988c2ecf20Sopenharmony_ci
43998c2ecf20Sopenharmony_ci	if (ioc->bus_type == SPI)
44008c2ecf20Sopenharmony_ci		num_chain *= MPT_SCSI_CAN_QUEUE;
44018c2ecf20Sopenharmony_ci	else if (ioc->bus_type == SAS)
44028c2ecf20Sopenharmony_ci		num_chain *= MPT_SAS_CAN_QUEUE;
44038c2ecf20Sopenharmony_ci	else
44048c2ecf20Sopenharmony_ci		num_chain *= MPT_FC_CAN_QUEUE;
44058c2ecf20Sopenharmony_ci
44068c2ecf20Sopenharmony_ci	ioc->num_chain = num_chain;
44078c2ecf20Sopenharmony_ci
44088c2ecf20Sopenharmony_ci	sz = num_chain * sizeof(int);
44098c2ecf20Sopenharmony_ci	if (ioc->ChainToChain == NULL) {
44108c2ecf20Sopenharmony_ci		mem = kmalloc(sz, GFP_ATOMIC);
44118c2ecf20Sopenharmony_ci		if (mem == NULL)
44128c2ecf20Sopenharmony_ci			return -1;
44138c2ecf20Sopenharmony_ci
44148c2ecf20Sopenharmony_ci		ioc->ChainToChain = (int *) mem;
44158c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
44168c2ecf20Sopenharmony_ci			 	ioc->name, mem, sz));
44178c2ecf20Sopenharmony_ci	} else {
44188c2ecf20Sopenharmony_ci		mem = (u8 *) ioc->ChainToChain;
44198c2ecf20Sopenharmony_ci	}
44208c2ecf20Sopenharmony_ci	memset(mem, 0xFF, sz);
44218c2ecf20Sopenharmony_ci	return num_chain;
44228c2ecf20Sopenharmony_ci}
44238c2ecf20Sopenharmony_ci
44248c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
44258c2ecf20Sopenharmony_ci/**
44268c2ecf20Sopenharmony_ci *	PrimeIocFifos - Initialize IOC request and reply FIFOs.
44278c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
44288c2ecf20Sopenharmony_ci *
44298c2ecf20Sopenharmony_ci *	This routine allocates memory for the MPT reply and request frame
44308c2ecf20Sopenharmony_ci *	pools (if necessary), and primes the IOC reply FIFO with
44318c2ecf20Sopenharmony_ci *	reply frames.
44328c2ecf20Sopenharmony_ci *
44338c2ecf20Sopenharmony_ci *	Returns 0 for success, non-zero for failure.
44348c2ecf20Sopenharmony_ci */
44358c2ecf20Sopenharmony_cistatic int
44368c2ecf20Sopenharmony_ciPrimeIocFifos(MPT_ADAPTER *ioc)
44378c2ecf20Sopenharmony_ci{
44388c2ecf20Sopenharmony_ci	MPT_FRAME_HDR *mf;
44398c2ecf20Sopenharmony_ci	unsigned long flags;
44408c2ecf20Sopenharmony_ci	dma_addr_t alloc_dma;
44418c2ecf20Sopenharmony_ci	u8 *mem;
44428c2ecf20Sopenharmony_ci	int i, reply_sz, sz, total_size, num_chain;
44438c2ecf20Sopenharmony_ci	u64	dma_mask;
44448c2ecf20Sopenharmony_ci
44458c2ecf20Sopenharmony_ci	dma_mask = 0;
44468c2ecf20Sopenharmony_ci
44478c2ecf20Sopenharmony_ci	/*  Prime reply FIFO...  */
44488c2ecf20Sopenharmony_ci
44498c2ecf20Sopenharmony_ci	if (ioc->reply_frames == NULL) {
44508c2ecf20Sopenharmony_ci		if ( (num_chain = initChainBuffers(ioc)) < 0)
44518c2ecf20Sopenharmony_ci			return -1;
44528c2ecf20Sopenharmony_ci		/*
44538c2ecf20Sopenharmony_ci		 * 1078 errata workaround for the 36GB limitation
44548c2ecf20Sopenharmony_ci		 */
44558c2ecf20Sopenharmony_ci		if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
44568c2ecf20Sopenharmony_ci		    ioc->dma_mask > DMA_BIT_MASK(35)) {
44578c2ecf20Sopenharmony_ci			if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
44588c2ecf20Sopenharmony_ci			    && !pci_set_consistent_dma_mask(ioc->pcidev,
44598c2ecf20Sopenharmony_ci			    DMA_BIT_MASK(32))) {
44608c2ecf20Sopenharmony_ci				dma_mask = DMA_BIT_MASK(35);
44618c2ecf20Sopenharmony_ci				d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
44628c2ecf20Sopenharmony_ci				    "setting 35 bit addressing for "
44638c2ecf20Sopenharmony_ci				    "Request/Reply/Chain and Sense Buffers\n",
44648c2ecf20Sopenharmony_ci				    ioc->name));
44658c2ecf20Sopenharmony_ci			} else {
44668c2ecf20Sopenharmony_ci				/*Reseting DMA mask to 64 bit*/
44678c2ecf20Sopenharmony_ci				pci_set_dma_mask(ioc->pcidev,
44688c2ecf20Sopenharmony_ci					DMA_BIT_MASK(64));
44698c2ecf20Sopenharmony_ci				pci_set_consistent_dma_mask(ioc->pcidev,
44708c2ecf20Sopenharmony_ci					DMA_BIT_MASK(64));
44718c2ecf20Sopenharmony_ci
44728c2ecf20Sopenharmony_ci				printk(MYIOC_s_ERR_FMT
44738c2ecf20Sopenharmony_ci				    "failed setting 35 bit addressing for "
44748c2ecf20Sopenharmony_ci				    "Request/Reply/Chain and Sense Buffers\n",
44758c2ecf20Sopenharmony_ci				    ioc->name);
44768c2ecf20Sopenharmony_ci				return -1;
44778c2ecf20Sopenharmony_ci			}
44788c2ecf20Sopenharmony_ci		}
44798c2ecf20Sopenharmony_ci
44808c2ecf20Sopenharmony_ci		total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
44818c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
44828c2ecf20Sopenharmony_ci			 	ioc->name, ioc->reply_sz, ioc->reply_depth));
44838c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
44848c2ecf20Sopenharmony_ci			 	ioc->name, reply_sz, reply_sz));
44858c2ecf20Sopenharmony_ci
44868c2ecf20Sopenharmony_ci		sz = (ioc->req_sz * ioc->req_depth);
44878c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
44888c2ecf20Sopenharmony_ci			 	ioc->name, ioc->req_sz, ioc->req_depth));
44898c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
44908c2ecf20Sopenharmony_ci			 	ioc->name, sz, sz));
44918c2ecf20Sopenharmony_ci		total_size += sz;
44928c2ecf20Sopenharmony_ci
44938c2ecf20Sopenharmony_ci		sz = num_chain * ioc->req_sz; /* chain buffer pool size */
44948c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
44958c2ecf20Sopenharmony_ci			 	ioc->name, ioc->req_sz, num_chain));
44968c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
44978c2ecf20Sopenharmony_ci			 	ioc->name, sz, sz, num_chain));
44988c2ecf20Sopenharmony_ci
44998c2ecf20Sopenharmony_ci		total_size += sz;
45008c2ecf20Sopenharmony_ci		mem = dma_alloc_coherent(&ioc->pcidev->dev, total_size,
45018c2ecf20Sopenharmony_ci				&alloc_dma, GFP_KERNEL);
45028c2ecf20Sopenharmony_ci		if (mem == NULL) {
45038c2ecf20Sopenharmony_ci			printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
45048c2ecf20Sopenharmony_ci				ioc->name);
45058c2ecf20Sopenharmony_ci			goto out_fail;
45068c2ecf20Sopenharmony_ci		}
45078c2ecf20Sopenharmony_ci
45088c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
45098c2ecf20Sopenharmony_ci			 	ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
45108c2ecf20Sopenharmony_ci
45118c2ecf20Sopenharmony_ci		memset(mem, 0, total_size);
45128c2ecf20Sopenharmony_ci		ioc->alloc_total += total_size;
45138c2ecf20Sopenharmony_ci		ioc->alloc = mem;
45148c2ecf20Sopenharmony_ci		ioc->alloc_dma = alloc_dma;
45158c2ecf20Sopenharmony_ci		ioc->alloc_sz = total_size;
45168c2ecf20Sopenharmony_ci		ioc->reply_frames = (MPT_FRAME_HDR *) mem;
45178c2ecf20Sopenharmony_ci		ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
45188c2ecf20Sopenharmony_ci
45198c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
45208c2ecf20Sopenharmony_ci	 		ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
45218c2ecf20Sopenharmony_ci
45228c2ecf20Sopenharmony_ci		alloc_dma += reply_sz;
45238c2ecf20Sopenharmony_ci		mem += reply_sz;
45248c2ecf20Sopenharmony_ci
45258c2ecf20Sopenharmony_ci		/*  Request FIFO - WE manage this!  */
45268c2ecf20Sopenharmony_ci
45278c2ecf20Sopenharmony_ci		ioc->req_frames = (MPT_FRAME_HDR *) mem;
45288c2ecf20Sopenharmony_ci		ioc->req_frames_dma = alloc_dma;
45298c2ecf20Sopenharmony_ci
45308c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
45318c2ecf20Sopenharmony_ci			 	ioc->name, mem, (void *)(ulong)alloc_dma));
45328c2ecf20Sopenharmony_ci
45338c2ecf20Sopenharmony_ci		ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
45348c2ecf20Sopenharmony_ci
45358c2ecf20Sopenharmony_ci		for (i = 0; i < ioc->req_depth; i++) {
45368c2ecf20Sopenharmony_ci			alloc_dma += ioc->req_sz;
45378c2ecf20Sopenharmony_ci			mem += ioc->req_sz;
45388c2ecf20Sopenharmony_ci		}
45398c2ecf20Sopenharmony_ci
45408c2ecf20Sopenharmony_ci		ioc->ChainBuffer = mem;
45418c2ecf20Sopenharmony_ci		ioc->ChainBufferDMA = alloc_dma;
45428c2ecf20Sopenharmony_ci
45438c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
45448c2ecf20Sopenharmony_ci			ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
45458c2ecf20Sopenharmony_ci
45468c2ecf20Sopenharmony_ci		/* Initialize the free chain Q.
45478c2ecf20Sopenharmony_ci	 	*/
45488c2ecf20Sopenharmony_ci
45498c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&ioc->FreeChainQ);
45508c2ecf20Sopenharmony_ci
45518c2ecf20Sopenharmony_ci		/* Post the chain buffers to the FreeChainQ.
45528c2ecf20Sopenharmony_ci	 	*/
45538c2ecf20Sopenharmony_ci		mem = (u8 *)ioc->ChainBuffer;
45548c2ecf20Sopenharmony_ci		for (i=0; i < num_chain; i++) {
45558c2ecf20Sopenharmony_ci			mf = (MPT_FRAME_HDR *) mem;
45568c2ecf20Sopenharmony_ci			list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
45578c2ecf20Sopenharmony_ci			mem += ioc->req_sz;
45588c2ecf20Sopenharmony_ci		}
45598c2ecf20Sopenharmony_ci
45608c2ecf20Sopenharmony_ci		/* Initialize Request frames linked list
45618c2ecf20Sopenharmony_ci		 */
45628c2ecf20Sopenharmony_ci		alloc_dma = ioc->req_frames_dma;
45638c2ecf20Sopenharmony_ci		mem = (u8 *) ioc->req_frames;
45648c2ecf20Sopenharmony_ci
45658c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ioc->FreeQlock, flags);
45668c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&ioc->FreeQ);
45678c2ecf20Sopenharmony_ci		for (i = 0; i < ioc->req_depth; i++) {
45688c2ecf20Sopenharmony_ci			mf = (MPT_FRAME_HDR *) mem;
45698c2ecf20Sopenharmony_ci
45708c2ecf20Sopenharmony_ci			/*  Queue REQUESTs *internally*!  */
45718c2ecf20Sopenharmony_ci			list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
45728c2ecf20Sopenharmony_ci
45738c2ecf20Sopenharmony_ci			mem += ioc->req_sz;
45748c2ecf20Sopenharmony_ci		}
45758c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
45768c2ecf20Sopenharmony_ci
45778c2ecf20Sopenharmony_ci		sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
45788c2ecf20Sopenharmony_ci		ioc->sense_buf_pool = dma_alloc_coherent(&ioc->pcidev->dev, sz,
45798c2ecf20Sopenharmony_ci				&ioc->sense_buf_pool_dma, GFP_KERNEL);
45808c2ecf20Sopenharmony_ci		if (ioc->sense_buf_pool == NULL) {
45818c2ecf20Sopenharmony_ci			printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
45828c2ecf20Sopenharmony_ci				ioc->name);
45838c2ecf20Sopenharmony_ci			goto out_fail;
45848c2ecf20Sopenharmony_ci		}
45858c2ecf20Sopenharmony_ci
45868c2ecf20Sopenharmony_ci		ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
45878c2ecf20Sopenharmony_ci		ioc->alloc_total += sz;
45888c2ecf20Sopenharmony_ci		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
45898c2ecf20Sopenharmony_ci 			ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
45908c2ecf20Sopenharmony_ci
45918c2ecf20Sopenharmony_ci	}
45928c2ecf20Sopenharmony_ci
45938c2ecf20Sopenharmony_ci	/* Post Reply frames to FIFO
45948c2ecf20Sopenharmony_ci	 */
45958c2ecf20Sopenharmony_ci	alloc_dma = ioc->alloc_dma;
45968c2ecf20Sopenharmony_ci	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
45978c2ecf20Sopenharmony_ci	 	ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
45988c2ecf20Sopenharmony_ci
45998c2ecf20Sopenharmony_ci	for (i = 0; i < ioc->reply_depth; i++) {
46008c2ecf20Sopenharmony_ci		/*  Write each address to the IOC!  */
46018c2ecf20Sopenharmony_ci		CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
46028c2ecf20Sopenharmony_ci		alloc_dma += ioc->reply_sz;
46038c2ecf20Sopenharmony_ci	}
46048c2ecf20Sopenharmony_ci
46058c2ecf20Sopenharmony_ci	if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
46068c2ecf20Sopenharmony_ci	    ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
46078c2ecf20Sopenharmony_ci	    ioc->dma_mask))
46088c2ecf20Sopenharmony_ci		d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
46098c2ecf20Sopenharmony_ci		    "restoring 64 bit addressing\n", ioc->name));
46108c2ecf20Sopenharmony_ci
46118c2ecf20Sopenharmony_ci	return 0;
46128c2ecf20Sopenharmony_ci
46138c2ecf20Sopenharmony_ciout_fail:
46148c2ecf20Sopenharmony_ci
46158c2ecf20Sopenharmony_ci	if (ioc->alloc != NULL) {
46168c2ecf20Sopenharmony_ci		sz = ioc->alloc_sz;
46178c2ecf20Sopenharmony_ci		dma_free_coherent(&ioc->pcidev->dev, sz, ioc->alloc,
46188c2ecf20Sopenharmony_ci				ioc->alloc_dma);
46198c2ecf20Sopenharmony_ci		ioc->reply_frames = NULL;
46208c2ecf20Sopenharmony_ci		ioc->req_frames = NULL;
46218c2ecf20Sopenharmony_ci		ioc->alloc_total -= sz;
46228c2ecf20Sopenharmony_ci	}
46238c2ecf20Sopenharmony_ci	if (ioc->sense_buf_pool != NULL) {
46248c2ecf20Sopenharmony_ci		sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
46258c2ecf20Sopenharmony_ci		dma_free_coherent(&ioc->pcidev->dev, sz, ioc->sense_buf_pool,
46268c2ecf20Sopenharmony_ci				ioc->sense_buf_pool_dma);
46278c2ecf20Sopenharmony_ci		ioc->sense_buf_pool = NULL;
46288c2ecf20Sopenharmony_ci	}
46298c2ecf20Sopenharmony_ci
46308c2ecf20Sopenharmony_ci	if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
46318c2ecf20Sopenharmony_ci	    DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
46328c2ecf20Sopenharmony_ci	    DMA_BIT_MASK(64)))
46338c2ecf20Sopenharmony_ci		d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
46348c2ecf20Sopenharmony_ci		    "restoring 64 bit addressing\n", ioc->name));
46358c2ecf20Sopenharmony_ci
46368c2ecf20Sopenharmony_ci	return -1;
46378c2ecf20Sopenharmony_ci}
46388c2ecf20Sopenharmony_ci
46398c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46408c2ecf20Sopenharmony_ci/**
46418c2ecf20Sopenharmony_ci *	mpt_handshake_req_reply_wait - Send MPT request to and receive reply
46428c2ecf20Sopenharmony_ci *	from IOC via doorbell handshake method.
46438c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
46448c2ecf20Sopenharmony_ci *	@reqBytes: Size of the request in bytes
46458c2ecf20Sopenharmony_ci *	@req: Pointer to MPT request frame
46468c2ecf20Sopenharmony_ci *	@replyBytes: Expected size of the reply in bytes
46478c2ecf20Sopenharmony_ci *	@u16reply: Pointer to area where reply should be written
46488c2ecf20Sopenharmony_ci *	@maxwait: Max wait time for a reply (in seconds)
46498c2ecf20Sopenharmony_ci *	@sleepFlag: Specifies whether the process can sleep
46508c2ecf20Sopenharmony_ci *
46518c2ecf20Sopenharmony_ci *	NOTES: It is the callers responsibility to byte-swap fields in the
46528c2ecf20Sopenharmony_ci *	request which are greater than 1 byte in size.  It is also the
46538c2ecf20Sopenharmony_ci *	callers responsibility to byte-swap response fields which are
46548c2ecf20Sopenharmony_ci *	greater than 1 byte in size.
46558c2ecf20Sopenharmony_ci *
46568c2ecf20Sopenharmony_ci *	Returns 0 for success, non-zero for failure.
46578c2ecf20Sopenharmony_ci */
46588c2ecf20Sopenharmony_cistatic int
46598c2ecf20Sopenharmony_cimpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
46608c2ecf20Sopenharmony_ci		int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
46618c2ecf20Sopenharmony_ci{
46628c2ecf20Sopenharmony_ci	MPIDefaultReply_t *mptReply;
46638c2ecf20Sopenharmony_ci	int failcnt = 0;
46648c2ecf20Sopenharmony_ci	int t;
46658c2ecf20Sopenharmony_ci
46668c2ecf20Sopenharmony_ci	/*
46678c2ecf20Sopenharmony_ci	 * Get ready to cache a handshake reply
46688c2ecf20Sopenharmony_ci	 */
46698c2ecf20Sopenharmony_ci	ioc->hs_reply_idx = 0;
46708c2ecf20Sopenharmony_ci	mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
46718c2ecf20Sopenharmony_ci	mptReply->MsgLength = 0;
46728c2ecf20Sopenharmony_ci
46738c2ecf20Sopenharmony_ci	/*
46748c2ecf20Sopenharmony_ci	 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
46758c2ecf20Sopenharmony_ci	 * then tell IOC that we want to handshake a request of N words.
46768c2ecf20Sopenharmony_ci	 * (WRITE u32val to Doorbell reg).
46778c2ecf20Sopenharmony_ci	 */
46788c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
46798c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->Doorbell,
46808c2ecf20Sopenharmony_ci			((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
46818c2ecf20Sopenharmony_ci			 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
46828c2ecf20Sopenharmony_ci
46838c2ecf20Sopenharmony_ci	/*
46848c2ecf20Sopenharmony_ci	 * Wait for IOC's doorbell handshake int
46858c2ecf20Sopenharmony_ci	 */
46868c2ecf20Sopenharmony_ci	if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
46878c2ecf20Sopenharmony_ci		failcnt++;
46888c2ecf20Sopenharmony_ci
46898c2ecf20Sopenharmony_ci	dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
46908c2ecf20Sopenharmony_ci			ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
46918c2ecf20Sopenharmony_ci
46928c2ecf20Sopenharmony_ci	/* Read doorbell and check for active bit */
46938c2ecf20Sopenharmony_ci	if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
46948c2ecf20Sopenharmony_ci			return -1;
46958c2ecf20Sopenharmony_ci
46968c2ecf20Sopenharmony_ci	/*
46978c2ecf20Sopenharmony_ci	 * Clear doorbell int (WRITE 0 to IntStatus reg),
46988c2ecf20Sopenharmony_ci	 * then wait for IOC to ACKnowledge that it's ready for
46998c2ecf20Sopenharmony_ci	 * our handshake request.
47008c2ecf20Sopenharmony_ci	 */
47018c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
47028c2ecf20Sopenharmony_ci	if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
47038c2ecf20Sopenharmony_ci		failcnt++;
47048c2ecf20Sopenharmony_ci
47058c2ecf20Sopenharmony_ci	if (!failcnt) {
47068c2ecf20Sopenharmony_ci		int	 ii;
47078c2ecf20Sopenharmony_ci		u8	*req_as_bytes = (u8 *) req;
47088c2ecf20Sopenharmony_ci
47098c2ecf20Sopenharmony_ci		/*
47108c2ecf20Sopenharmony_ci		 * Stuff request words via doorbell handshake,
47118c2ecf20Sopenharmony_ci		 * with ACK from IOC for each.
47128c2ecf20Sopenharmony_ci		 */
47138c2ecf20Sopenharmony_ci		for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
47148c2ecf20Sopenharmony_ci			u32 word = ((req_as_bytes[(ii*4) + 0] <<  0) |
47158c2ecf20Sopenharmony_ci				    (req_as_bytes[(ii*4) + 1] <<  8) |
47168c2ecf20Sopenharmony_ci				    (req_as_bytes[(ii*4) + 2] << 16) |
47178c2ecf20Sopenharmony_ci				    (req_as_bytes[(ii*4) + 3] << 24));
47188c2ecf20Sopenharmony_ci
47198c2ecf20Sopenharmony_ci			CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
47208c2ecf20Sopenharmony_ci			if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
47218c2ecf20Sopenharmony_ci				failcnt++;
47228c2ecf20Sopenharmony_ci		}
47238c2ecf20Sopenharmony_ci
47248c2ecf20Sopenharmony_ci		dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
47258c2ecf20Sopenharmony_ci		DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
47268c2ecf20Sopenharmony_ci
47278c2ecf20Sopenharmony_ci		dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
47288c2ecf20Sopenharmony_ci				ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
47298c2ecf20Sopenharmony_ci
47308c2ecf20Sopenharmony_ci		/*
47318c2ecf20Sopenharmony_ci		 * Wait for completion of doorbell handshake reply from the IOC
47328c2ecf20Sopenharmony_ci		 */
47338c2ecf20Sopenharmony_ci		if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
47348c2ecf20Sopenharmony_ci			failcnt++;
47358c2ecf20Sopenharmony_ci
47368c2ecf20Sopenharmony_ci		dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
47378c2ecf20Sopenharmony_ci				ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
47388c2ecf20Sopenharmony_ci
47398c2ecf20Sopenharmony_ci		/*
47408c2ecf20Sopenharmony_ci		 * Copy out the cached reply...
47418c2ecf20Sopenharmony_ci		 */
47428c2ecf20Sopenharmony_ci		for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
47438c2ecf20Sopenharmony_ci			u16reply[ii] = ioc->hs_reply[ii];
47448c2ecf20Sopenharmony_ci	} else {
47458c2ecf20Sopenharmony_ci		return -99;
47468c2ecf20Sopenharmony_ci	}
47478c2ecf20Sopenharmony_ci
47488c2ecf20Sopenharmony_ci	return -failcnt;
47498c2ecf20Sopenharmony_ci}
47508c2ecf20Sopenharmony_ci
47518c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
47528c2ecf20Sopenharmony_ci/**
47538c2ecf20Sopenharmony_ci *	WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
47548c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
47558c2ecf20Sopenharmony_ci *	@howlong: How long to wait (in seconds)
47568c2ecf20Sopenharmony_ci *	@sleepFlag: Specifies whether the process can sleep
47578c2ecf20Sopenharmony_ci *
47588c2ecf20Sopenharmony_ci *	This routine waits (up to ~2 seconds max) for IOC doorbell
47598c2ecf20Sopenharmony_ci *	handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
47608c2ecf20Sopenharmony_ci *	bit in its IntStatus register being clear.
47618c2ecf20Sopenharmony_ci *
47628c2ecf20Sopenharmony_ci *	Returns a negative value on failure, else wait loop count.
47638c2ecf20Sopenharmony_ci */
47648c2ecf20Sopenharmony_cistatic int
47658c2ecf20Sopenharmony_ciWaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
47668c2ecf20Sopenharmony_ci{
47678c2ecf20Sopenharmony_ci	int cntdn;
47688c2ecf20Sopenharmony_ci	int count = 0;
47698c2ecf20Sopenharmony_ci	u32 intstat=0;
47708c2ecf20Sopenharmony_ci
47718c2ecf20Sopenharmony_ci	cntdn = 1000 * howlong;
47728c2ecf20Sopenharmony_ci
47738c2ecf20Sopenharmony_ci	if (sleepFlag == CAN_SLEEP) {
47748c2ecf20Sopenharmony_ci		while (--cntdn) {
47758c2ecf20Sopenharmony_ci			msleep (1);
47768c2ecf20Sopenharmony_ci			intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
47778c2ecf20Sopenharmony_ci			if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
47788c2ecf20Sopenharmony_ci				break;
47798c2ecf20Sopenharmony_ci			count++;
47808c2ecf20Sopenharmony_ci		}
47818c2ecf20Sopenharmony_ci	} else {
47828c2ecf20Sopenharmony_ci		while (--cntdn) {
47838c2ecf20Sopenharmony_ci			udelay (1000);
47848c2ecf20Sopenharmony_ci			intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
47858c2ecf20Sopenharmony_ci			if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
47868c2ecf20Sopenharmony_ci				break;
47878c2ecf20Sopenharmony_ci			count++;
47888c2ecf20Sopenharmony_ci		}
47898c2ecf20Sopenharmony_ci	}
47908c2ecf20Sopenharmony_ci
47918c2ecf20Sopenharmony_ci	if (cntdn) {
47928c2ecf20Sopenharmony_ci		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
47938c2ecf20Sopenharmony_ci				ioc->name, count));
47948c2ecf20Sopenharmony_ci		return count;
47958c2ecf20Sopenharmony_ci	}
47968c2ecf20Sopenharmony_ci
47978c2ecf20Sopenharmony_ci	printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
47988c2ecf20Sopenharmony_ci			ioc->name, count, intstat);
47998c2ecf20Sopenharmony_ci	return -1;
48008c2ecf20Sopenharmony_ci}
48018c2ecf20Sopenharmony_ci
48028c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48038c2ecf20Sopenharmony_ci/**
48048c2ecf20Sopenharmony_ci *	WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
48058c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
48068c2ecf20Sopenharmony_ci *	@howlong: How long to wait (in seconds)
48078c2ecf20Sopenharmony_ci *	@sleepFlag: Specifies whether the process can sleep
48088c2ecf20Sopenharmony_ci *
48098c2ecf20Sopenharmony_ci *	This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
48108c2ecf20Sopenharmony_ci *	(MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
48118c2ecf20Sopenharmony_ci *
48128c2ecf20Sopenharmony_ci *	Returns a negative value on failure, else wait loop count.
48138c2ecf20Sopenharmony_ci */
48148c2ecf20Sopenharmony_cistatic int
48158c2ecf20Sopenharmony_ciWaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
48168c2ecf20Sopenharmony_ci{
48178c2ecf20Sopenharmony_ci	int cntdn;
48188c2ecf20Sopenharmony_ci	int count = 0;
48198c2ecf20Sopenharmony_ci	u32 intstat=0;
48208c2ecf20Sopenharmony_ci
48218c2ecf20Sopenharmony_ci	cntdn = 1000 * howlong;
48228c2ecf20Sopenharmony_ci	if (sleepFlag == CAN_SLEEP) {
48238c2ecf20Sopenharmony_ci		while (--cntdn) {
48248c2ecf20Sopenharmony_ci			intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
48258c2ecf20Sopenharmony_ci			if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
48268c2ecf20Sopenharmony_ci				break;
48278c2ecf20Sopenharmony_ci			msleep(1);
48288c2ecf20Sopenharmony_ci			count++;
48298c2ecf20Sopenharmony_ci		}
48308c2ecf20Sopenharmony_ci	} else {
48318c2ecf20Sopenharmony_ci		while (--cntdn) {
48328c2ecf20Sopenharmony_ci			intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
48338c2ecf20Sopenharmony_ci			if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
48348c2ecf20Sopenharmony_ci				break;
48358c2ecf20Sopenharmony_ci			udelay (1000);
48368c2ecf20Sopenharmony_ci			count++;
48378c2ecf20Sopenharmony_ci		}
48388c2ecf20Sopenharmony_ci	}
48398c2ecf20Sopenharmony_ci
48408c2ecf20Sopenharmony_ci	if (cntdn) {
48418c2ecf20Sopenharmony_ci		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
48428c2ecf20Sopenharmony_ci				ioc->name, count, howlong));
48438c2ecf20Sopenharmony_ci		return count;
48448c2ecf20Sopenharmony_ci	}
48458c2ecf20Sopenharmony_ci
48468c2ecf20Sopenharmony_ci	printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
48478c2ecf20Sopenharmony_ci			ioc->name, count, intstat);
48488c2ecf20Sopenharmony_ci	return -1;
48498c2ecf20Sopenharmony_ci}
48508c2ecf20Sopenharmony_ci
48518c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48528c2ecf20Sopenharmony_ci/**
48538c2ecf20Sopenharmony_ci *	WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
48548c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
48558c2ecf20Sopenharmony_ci *	@howlong: How long to wait (in seconds)
48568c2ecf20Sopenharmony_ci *	@sleepFlag: Specifies whether the process can sleep
48578c2ecf20Sopenharmony_ci *
48588c2ecf20Sopenharmony_ci *	This routine polls the IOC for a handshake reply, 16 bits at a time.
48598c2ecf20Sopenharmony_ci *	Reply is cached to IOC private area large enough to hold a maximum
48608c2ecf20Sopenharmony_ci *	of 128 bytes of reply data.
48618c2ecf20Sopenharmony_ci *
48628c2ecf20Sopenharmony_ci *	Returns a negative value on failure, else size of reply in WORDS.
48638c2ecf20Sopenharmony_ci */
48648c2ecf20Sopenharmony_cistatic int
48658c2ecf20Sopenharmony_ciWaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
48668c2ecf20Sopenharmony_ci{
48678c2ecf20Sopenharmony_ci	int u16cnt = 0;
48688c2ecf20Sopenharmony_ci	int failcnt = 0;
48698c2ecf20Sopenharmony_ci	int t;
48708c2ecf20Sopenharmony_ci	u16 *hs_reply = ioc->hs_reply;
48718c2ecf20Sopenharmony_ci	volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
48728c2ecf20Sopenharmony_ci	u16 hword;
48738c2ecf20Sopenharmony_ci
48748c2ecf20Sopenharmony_ci	hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
48758c2ecf20Sopenharmony_ci
48768c2ecf20Sopenharmony_ci	/*
48778c2ecf20Sopenharmony_ci	 * Get first two u16's so we can look at IOC's intended reply MsgLength
48788c2ecf20Sopenharmony_ci	 */
48798c2ecf20Sopenharmony_ci	u16cnt=0;
48808c2ecf20Sopenharmony_ci	if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
48818c2ecf20Sopenharmony_ci		failcnt++;
48828c2ecf20Sopenharmony_ci	} else {
48838c2ecf20Sopenharmony_ci		hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
48848c2ecf20Sopenharmony_ci		CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
48858c2ecf20Sopenharmony_ci		if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
48868c2ecf20Sopenharmony_ci			failcnt++;
48878c2ecf20Sopenharmony_ci		else {
48888c2ecf20Sopenharmony_ci			hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
48898c2ecf20Sopenharmony_ci			CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
48908c2ecf20Sopenharmony_ci		}
48918c2ecf20Sopenharmony_ci	}
48928c2ecf20Sopenharmony_ci
48938c2ecf20Sopenharmony_ci	dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
48948c2ecf20Sopenharmony_ci			ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
48958c2ecf20Sopenharmony_ci			failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
48968c2ecf20Sopenharmony_ci
48978c2ecf20Sopenharmony_ci	/*
48988c2ecf20Sopenharmony_ci	 * If no error (and IOC said MsgLength is > 0), piece together
48998c2ecf20Sopenharmony_ci	 * reply 16 bits at a time.
49008c2ecf20Sopenharmony_ci	 */
49018c2ecf20Sopenharmony_ci	for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
49028c2ecf20Sopenharmony_ci		if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
49038c2ecf20Sopenharmony_ci			failcnt++;
49048c2ecf20Sopenharmony_ci		hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
49058c2ecf20Sopenharmony_ci		/* don't overflow our IOC hs_reply[] buffer! */
49068c2ecf20Sopenharmony_ci		if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
49078c2ecf20Sopenharmony_ci			hs_reply[u16cnt] = hword;
49088c2ecf20Sopenharmony_ci		CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
49098c2ecf20Sopenharmony_ci	}
49108c2ecf20Sopenharmony_ci
49118c2ecf20Sopenharmony_ci	if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
49128c2ecf20Sopenharmony_ci		failcnt++;
49138c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
49148c2ecf20Sopenharmony_ci
49158c2ecf20Sopenharmony_ci	if (failcnt) {
49168c2ecf20Sopenharmony_ci		printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
49178c2ecf20Sopenharmony_ci				ioc->name);
49188c2ecf20Sopenharmony_ci		return -failcnt;
49198c2ecf20Sopenharmony_ci	}
49208c2ecf20Sopenharmony_ci#if 0
49218c2ecf20Sopenharmony_ci	else if (u16cnt != (2 * mptReply->MsgLength)) {
49228c2ecf20Sopenharmony_ci		return -101;
49238c2ecf20Sopenharmony_ci	}
49248c2ecf20Sopenharmony_ci	else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
49258c2ecf20Sopenharmony_ci		return -102;
49268c2ecf20Sopenharmony_ci	}
49278c2ecf20Sopenharmony_ci#endif
49288c2ecf20Sopenharmony_ci
49298c2ecf20Sopenharmony_ci	dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
49308c2ecf20Sopenharmony_ci	DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
49318c2ecf20Sopenharmony_ci
49328c2ecf20Sopenharmony_ci	dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
49338c2ecf20Sopenharmony_ci			ioc->name, t, u16cnt/2));
49348c2ecf20Sopenharmony_ci	return u16cnt/2;
49358c2ecf20Sopenharmony_ci}
49368c2ecf20Sopenharmony_ci
49378c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
49388c2ecf20Sopenharmony_ci/**
49398c2ecf20Sopenharmony_ci *	GetLanConfigPages - Fetch LANConfig pages.
49408c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
49418c2ecf20Sopenharmony_ci *
49428c2ecf20Sopenharmony_ci *	Return: 0 for success
49438c2ecf20Sopenharmony_ci *	-ENOMEM if no memory available
49448c2ecf20Sopenharmony_ci *		-EPERM if not allowed due to ISR context
49458c2ecf20Sopenharmony_ci *		-EAGAIN if no msg frames currently available
49468c2ecf20Sopenharmony_ci *		-EFAULT for non-successful reply or no reply (timeout)
49478c2ecf20Sopenharmony_ci */
49488c2ecf20Sopenharmony_cistatic int
49498c2ecf20Sopenharmony_ciGetLanConfigPages(MPT_ADAPTER *ioc)
49508c2ecf20Sopenharmony_ci{
49518c2ecf20Sopenharmony_ci	ConfigPageHeader_t	 hdr;
49528c2ecf20Sopenharmony_ci	CONFIGPARMS		 cfg;
49538c2ecf20Sopenharmony_ci	LANPage0_t		*ppage0_alloc;
49548c2ecf20Sopenharmony_ci	dma_addr_t		 page0_dma;
49558c2ecf20Sopenharmony_ci	LANPage1_t		*ppage1_alloc;
49568c2ecf20Sopenharmony_ci	dma_addr_t		 page1_dma;
49578c2ecf20Sopenharmony_ci	int			 rc = 0;
49588c2ecf20Sopenharmony_ci	int			 data_sz;
49598c2ecf20Sopenharmony_ci	int			 copy_sz;
49608c2ecf20Sopenharmony_ci
49618c2ecf20Sopenharmony_ci	/* Get LAN Page 0 header */
49628c2ecf20Sopenharmony_ci	hdr.PageVersion = 0;
49638c2ecf20Sopenharmony_ci	hdr.PageLength = 0;
49648c2ecf20Sopenharmony_ci	hdr.PageNumber = 0;
49658c2ecf20Sopenharmony_ci	hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
49668c2ecf20Sopenharmony_ci	cfg.cfghdr.hdr = &hdr;
49678c2ecf20Sopenharmony_ci	cfg.physAddr = -1;
49688c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
49698c2ecf20Sopenharmony_ci	cfg.dir = 0;
49708c2ecf20Sopenharmony_ci	cfg.pageAddr = 0;
49718c2ecf20Sopenharmony_ci	cfg.timeout = 0;
49728c2ecf20Sopenharmony_ci
49738c2ecf20Sopenharmony_ci	if ((rc = mpt_config(ioc, &cfg)) != 0)
49748c2ecf20Sopenharmony_ci		return rc;
49758c2ecf20Sopenharmony_ci
49768c2ecf20Sopenharmony_ci	if (hdr.PageLength > 0) {
49778c2ecf20Sopenharmony_ci		data_sz = hdr.PageLength * 4;
49788c2ecf20Sopenharmony_ci		ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
49798c2ecf20Sopenharmony_ci		rc = -ENOMEM;
49808c2ecf20Sopenharmony_ci		if (ppage0_alloc) {
49818c2ecf20Sopenharmony_ci			memset((u8 *)ppage0_alloc, 0, data_sz);
49828c2ecf20Sopenharmony_ci			cfg.physAddr = page0_dma;
49838c2ecf20Sopenharmony_ci			cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
49848c2ecf20Sopenharmony_ci
49858c2ecf20Sopenharmony_ci			if ((rc = mpt_config(ioc, &cfg)) == 0) {
49868c2ecf20Sopenharmony_ci				/* save the data */
49878c2ecf20Sopenharmony_ci				copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
49888c2ecf20Sopenharmony_ci				memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
49898c2ecf20Sopenharmony_ci
49908c2ecf20Sopenharmony_ci			}
49918c2ecf20Sopenharmony_ci
49928c2ecf20Sopenharmony_ci			pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
49938c2ecf20Sopenharmony_ci
49948c2ecf20Sopenharmony_ci			/* FIXME!
49958c2ecf20Sopenharmony_ci			 *	Normalize endianness of structure data,
49968c2ecf20Sopenharmony_ci			 *	by byte-swapping all > 1 byte fields!
49978c2ecf20Sopenharmony_ci			 */
49988c2ecf20Sopenharmony_ci
49998c2ecf20Sopenharmony_ci		}
50008c2ecf20Sopenharmony_ci
50018c2ecf20Sopenharmony_ci		if (rc)
50028c2ecf20Sopenharmony_ci			return rc;
50038c2ecf20Sopenharmony_ci	}
50048c2ecf20Sopenharmony_ci
50058c2ecf20Sopenharmony_ci	/* Get LAN Page 1 header */
50068c2ecf20Sopenharmony_ci	hdr.PageVersion = 0;
50078c2ecf20Sopenharmony_ci	hdr.PageLength = 0;
50088c2ecf20Sopenharmony_ci	hdr.PageNumber = 1;
50098c2ecf20Sopenharmony_ci	hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
50108c2ecf20Sopenharmony_ci	cfg.cfghdr.hdr = &hdr;
50118c2ecf20Sopenharmony_ci	cfg.physAddr = -1;
50128c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
50138c2ecf20Sopenharmony_ci	cfg.dir = 0;
50148c2ecf20Sopenharmony_ci	cfg.pageAddr = 0;
50158c2ecf20Sopenharmony_ci
50168c2ecf20Sopenharmony_ci	if ((rc = mpt_config(ioc, &cfg)) != 0)
50178c2ecf20Sopenharmony_ci		return rc;
50188c2ecf20Sopenharmony_ci
50198c2ecf20Sopenharmony_ci	if (hdr.PageLength == 0)
50208c2ecf20Sopenharmony_ci		return 0;
50218c2ecf20Sopenharmony_ci
50228c2ecf20Sopenharmony_ci	data_sz = hdr.PageLength * 4;
50238c2ecf20Sopenharmony_ci	rc = -ENOMEM;
50248c2ecf20Sopenharmony_ci	ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
50258c2ecf20Sopenharmony_ci	if (ppage1_alloc) {
50268c2ecf20Sopenharmony_ci		memset((u8 *)ppage1_alloc, 0, data_sz);
50278c2ecf20Sopenharmony_ci		cfg.physAddr = page1_dma;
50288c2ecf20Sopenharmony_ci		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
50298c2ecf20Sopenharmony_ci
50308c2ecf20Sopenharmony_ci		if ((rc = mpt_config(ioc, &cfg)) == 0) {
50318c2ecf20Sopenharmony_ci			/* save the data */
50328c2ecf20Sopenharmony_ci			copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
50338c2ecf20Sopenharmony_ci			memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
50348c2ecf20Sopenharmony_ci		}
50358c2ecf20Sopenharmony_ci
50368c2ecf20Sopenharmony_ci		pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
50378c2ecf20Sopenharmony_ci
50388c2ecf20Sopenharmony_ci		/* FIXME!
50398c2ecf20Sopenharmony_ci		 *	Normalize endianness of structure data,
50408c2ecf20Sopenharmony_ci		 *	by byte-swapping all > 1 byte fields!
50418c2ecf20Sopenharmony_ci		 */
50428c2ecf20Sopenharmony_ci
50438c2ecf20Sopenharmony_ci	}
50448c2ecf20Sopenharmony_ci
50458c2ecf20Sopenharmony_ci	return rc;
50468c2ecf20Sopenharmony_ci}
50478c2ecf20Sopenharmony_ci
50488c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
50498c2ecf20Sopenharmony_ci/**
50508c2ecf20Sopenharmony_ci *	mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
50518c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
50528c2ecf20Sopenharmony_ci *	@persist_opcode: see below
50538c2ecf20Sopenharmony_ci *
50548c2ecf20Sopenharmony_ci *	===============================  ======================================
50558c2ecf20Sopenharmony_ci *	MPI_SAS_OP_CLEAR_NOT_PRESENT     Free all persist TargetID mappings for
50568c2ecf20Sopenharmony_ci *					 devices not currently present.
50578c2ecf20Sopenharmony_ci *	MPI_SAS_OP_CLEAR_ALL_PERSISTENT  Clear al persist TargetID mappings
50588c2ecf20Sopenharmony_ci *	===============================  ======================================
50598c2ecf20Sopenharmony_ci *
50608c2ecf20Sopenharmony_ci *	NOTE: Don't use not this function during interrupt time.
50618c2ecf20Sopenharmony_ci *
50628c2ecf20Sopenharmony_ci *	Returns 0 for success, non-zero error
50638c2ecf20Sopenharmony_ci */
50648c2ecf20Sopenharmony_ci
50658c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
50668c2ecf20Sopenharmony_ciint
50678c2ecf20Sopenharmony_cimptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
50688c2ecf20Sopenharmony_ci{
50698c2ecf20Sopenharmony_ci	SasIoUnitControlRequest_t	*sasIoUnitCntrReq;
50708c2ecf20Sopenharmony_ci	SasIoUnitControlReply_t		*sasIoUnitCntrReply;
50718c2ecf20Sopenharmony_ci	MPT_FRAME_HDR			*mf = NULL;
50728c2ecf20Sopenharmony_ci	MPIHeader_t			*mpi_hdr;
50738c2ecf20Sopenharmony_ci	int				ret = 0;
50748c2ecf20Sopenharmony_ci	unsigned long 	 		timeleft;
50758c2ecf20Sopenharmony_ci
50768c2ecf20Sopenharmony_ci	mutex_lock(&ioc->mptbase_cmds.mutex);
50778c2ecf20Sopenharmony_ci
50788c2ecf20Sopenharmony_ci	/* init the internal cmd struct */
50798c2ecf20Sopenharmony_ci	memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
50808c2ecf20Sopenharmony_ci	INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
50818c2ecf20Sopenharmony_ci
50828c2ecf20Sopenharmony_ci	/* insure garbage is not sent to fw */
50838c2ecf20Sopenharmony_ci	switch(persist_opcode) {
50848c2ecf20Sopenharmony_ci
50858c2ecf20Sopenharmony_ci	case MPI_SAS_OP_CLEAR_NOT_PRESENT:
50868c2ecf20Sopenharmony_ci	case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
50878c2ecf20Sopenharmony_ci		break;
50888c2ecf20Sopenharmony_ci
50898c2ecf20Sopenharmony_ci	default:
50908c2ecf20Sopenharmony_ci		ret = -1;
50918c2ecf20Sopenharmony_ci		goto out;
50928c2ecf20Sopenharmony_ci	}
50938c2ecf20Sopenharmony_ci
50948c2ecf20Sopenharmony_ci	printk(KERN_DEBUG  "%s: persist_opcode=%x\n",
50958c2ecf20Sopenharmony_ci		__func__, persist_opcode);
50968c2ecf20Sopenharmony_ci
50978c2ecf20Sopenharmony_ci	/* Get a MF for this command.
50988c2ecf20Sopenharmony_ci	 */
50998c2ecf20Sopenharmony_ci	if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
51008c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
51018c2ecf20Sopenharmony_ci		ret = -1;
51028c2ecf20Sopenharmony_ci		goto out;
51038c2ecf20Sopenharmony_ci        }
51048c2ecf20Sopenharmony_ci
51058c2ecf20Sopenharmony_ci	mpi_hdr = (MPIHeader_t *) mf;
51068c2ecf20Sopenharmony_ci	sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
51078c2ecf20Sopenharmony_ci	memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
51088c2ecf20Sopenharmony_ci	sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
51098c2ecf20Sopenharmony_ci	sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
51108c2ecf20Sopenharmony_ci	sasIoUnitCntrReq->Operation = persist_opcode;
51118c2ecf20Sopenharmony_ci
51128c2ecf20Sopenharmony_ci	mpt_put_msg_frame(mpt_base_index, ioc, mf);
51138c2ecf20Sopenharmony_ci	timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
51148c2ecf20Sopenharmony_ci	if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
51158c2ecf20Sopenharmony_ci		ret = -ETIME;
51168c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: failed\n", __func__);
51178c2ecf20Sopenharmony_ci		if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
51188c2ecf20Sopenharmony_ci			goto out;
51198c2ecf20Sopenharmony_ci		if (!timeleft) {
51208c2ecf20Sopenharmony_ci			printk(MYIOC_s_WARN_FMT
51218c2ecf20Sopenharmony_ci			       "Issuing Reset from %s!!, doorbell=0x%08x\n",
51228c2ecf20Sopenharmony_ci			       ioc->name, __func__, mpt_GetIocState(ioc, 0));
51238c2ecf20Sopenharmony_ci			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
51248c2ecf20Sopenharmony_ci			mpt_free_msg_frame(ioc, mf);
51258c2ecf20Sopenharmony_ci		}
51268c2ecf20Sopenharmony_ci		goto out;
51278c2ecf20Sopenharmony_ci	}
51288c2ecf20Sopenharmony_ci
51298c2ecf20Sopenharmony_ci	if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
51308c2ecf20Sopenharmony_ci		ret = -1;
51318c2ecf20Sopenharmony_ci		goto out;
51328c2ecf20Sopenharmony_ci	}
51338c2ecf20Sopenharmony_ci
51348c2ecf20Sopenharmony_ci	sasIoUnitCntrReply =
51358c2ecf20Sopenharmony_ci	    (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
51368c2ecf20Sopenharmony_ci	if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
51378c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
51388c2ecf20Sopenharmony_ci		    __func__, sasIoUnitCntrReply->IOCStatus,
51398c2ecf20Sopenharmony_ci		    sasIoUnitCntrReply->IOCLogInfo);
51408c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: failed\n", __func__);
51418c2ecf20Sopenharmony_ci		ret = -1;
51428c2ecf20Sopenharmony_ci	} else
51438c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "%s: success\n", __func__);
51448c2ecf20Sopenharmony_ci out:
51458c2ecf20Sopenharmony_ci
51468c2ecf20Sopenharmony_ci	CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
51478c2ecf20Sopenharmony_ci	mutex_unlock(&ioc->mptbase_cmds.mutex);
51488c2ecf20Sopenharmony_ci	return ret;
51498c2ecf20Sopenharmony_ci}
51508c2ecf20Sopenharmony_ci
51518c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
51528c2ecf20Sopenharmony_ci
51538c2ecf20Sopenharmony_cistatic void
51548c2ecf20Sopenharmony_cimptbase_raid_process_event_data(MPT_ADAPTER *ioc,
51558c2ecf20Sopenharmony_ci    MpiEventDataRaid_t * pRaidEventData)
51568c2ecf20Sopenharmony_ci{
51578c2ecf20Sopenharmony_ci	int 	volume;
51588c2ecf20Sopenharmony_ci	int 	reason;
51598c2ecf20Sopenharmony_ci	int 	disk;
51608c2ecf20Sopenharmony_ci	int 	status;
51618c2ecf20Sopenharmony_ci	int 	flags;
51628c2ecf20Sopenharmony_ci	int 	state;
51638c2ecf20Sopenharmony_ci
51648c2ecf20Sopenharmony_ci	volume	= pRaidEventData->VolumeID;
51658c2ecf20Sopenharmony_ci	reason	= pRaidEventData->ReasonCode;
51668c2ecf20Sopenharmony_ci	disk	= pRaidEventData->PhysDiskNum;
51678c2ecf20Sopenharmony_ci	status	= le32_to_cpu(pRaidEventData->SettingsStatus);
51688c2ecf20Sopenharmony_ci	flags	= (status >> 0) & 0xff;
51698c2ecf20Sopenharmony_ci	state	= (status >> 8) & 0xff;
51708c2ecf20Sopenharmony_ci
51718c2ecf20Sopenharmony_ci	if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
51728c2ecf20Sopenharmony_ci		return;
51738c2ecf20Sopenharmony_ci	}
51748c2ecf20Sopenharmony_ci
51758c2ecf20Sopenharmony_ci	if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
51768c2ecf20Sopenharmony_ci	     reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
51778c2ecf20Sopenharmony_ci	    (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
51788c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
51798c2ecf20Sopenharmony_ci			ioc->name, disk, volume);
51808c2ecf20Sopenharmony_ci	} else {
51818c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
51828c2ecf20Sopenharmony_ci			ioc->name, volume);
51838c2ecf20Sopenharmony_ci	}
51848c2ecf20Sopenharmony_ci
51858c2ecf20Sopenharmony_ci	switch(reason) {
51868c2ecf20Sopenharmony_ci	case MPI_EVENT_RAID_RC_VOLUME_CREATED:
51878c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "  volume has been created\n",
51888c2ecf20Sopenharmony_ci			ioc->name);
51898c2ecf20Sopenharmony_ci		break;
51908c2ecf20Sopenharmony_ci
51918c2ecf20Sopenharmony_ci	case MPI_EVENT_RAID_RC_VOLUME_DELETED:
51928c2ecf20Sopenharmony_ci
51938c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "  volume has been deleted\n",
51948c2ecf20Sopenharmony_ci			ioc->name);
51958c2ecf20Sopenharmony_ci		break;
51968c2ecf20Sopenharmony_ci
51978c2ecf20Sopenharmony_ci	case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
51988c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "  volume settings have been changed\n",
51998c2ecf20Sopenharmony_ci			ioc->name);
52008c2ecf20Sopenharmony_ci		break;
52018c2ecf20Sopenharmony_ci
52028c2ecf20Sopenharmony_ci	case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
52038c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "  volume is now %s%s%s%s\n",
52048c2ecf20Sopenharmony_ci			ioc->name,
52058c2ecf20Sopenharmony_ci			state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
52068c2ecf20Sopenharmony_ci			 ? "optimal"
52078c2ecf20Sopenharmony_ci			 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
52088c2ecf20Sopenharmony_ci			  ? "degraded"
52098c2ecf20Sopenharmony_ci			  : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
52108c2ecf20Sopenharmony_ci			   ? "failed"
52118c2ecf20Sopenharmony_ci			   : "state unknown",
52128c2ecf20Sopenharmony_ci			flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
52138c2ecf20Sopenharmony_ci			 ? ", enabled" : "",
52148c2ecf20Sopenharmony_ci			flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
52158c2ecf20Sopenharmony_ci			 ? ", quiesced" : "",
52168c2ecf20Sopenharmony_ci			flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
52178c2ecf20Sopenharmony_ci			 ? ", resync in progress" : "" );
52188c2ecf20Sopenharmony_ci		break;
52198c2ecf20Sopenharmony_ci
52208c2ecf20Sopenharmony_ci	case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
52218c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "  volume membership of PhysDisk %d has changed\n",
52228c2ecf20Sopenharmony_ci			ioc->name, disk);
52238c2ecf20Sopenharmony_ci		break;
52248c2ecf20Sopenharmony_ci
52258c2ecf20Sopenharmony_ci	case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
52268c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "  PhysDisk has been created\n",
52278c2ecf20Sopenharmony_ci			ioc->name);
52288c2ecf20Sopenharmony_ci		break;
52298c2ecf20Sopenharmony_ci
52308c2ecf20Sopenharmony_ci	case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
52318c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "  PhysDisk has been deleted\n",
52328c2ecf20Sopenharmony_ci			ioc->name);
52338c2ecf20Sopenharmony_ci		break;
52348c2ecf20Sopenharmony_ci
52358c2ecf20Sopenharmony_ci	case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
52368c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "  PhysDisk settings have been changed\n",
52378c2ecf20Sopenharmony_ci			ioc->name);
52388c2ecf20Sopenharmony_ci		break;
52398c2ecf20Sopenharmony_ci
52408c2ecf20Sopenharmony_ci	case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
52418c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "  PhysDisk is now %s%s%s\n",
52428c2ecf20Sopenharmony_ci			ioc->name,
52438c2ecf20Sopenharmony_ci			state == MPI_PHYSDISK0_STATUS_ONLINE
52448c2ecf20Sopenharmony_ci			 ? "online"
52458c2ecf20Sopenharmony_ci			 : state == MPI_PHYSDISK0_STATUS_MISSING
52468c2ecf20Sopenharmony_ci			  ? "missing"
52478c2ecf20Sopenharmony_ci			  : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
52488c2ecf20Sopenharmony_ci			   ? "not compatible"
52498c2ecf20Sopenharmony_ci			   : state == MPI_PHYSDISK0_STATUS_FAILED
52508c2ecf20Sopenharmony_ci			    ? "failed"
52518c2ecf20Sopenharmony_ci			    : state == MPI_PHYSDISK0_STATUS_INITIALIZING
52528c2ecf20Sopenharmony_ci			     ? "initializing"
52538c2ecf20Sopenharmony_ci			     : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
52548c2ecf20Sopenharmony_ci			      ? "offline requested"
52558c2ecf20Sopenharmony_ci			      : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
52568c2ecf20Sopenharmony_ci			       ? "failed requested"
52578c2ecf20Sopenharmony_ci			       : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
52588c2ecf20Sopenharmony_ci			        ? "offline"
52598c2ecf20Sopenharmony_ci			        : "state unknown",
52608c2ecf20Sopenharmony_ci			flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
52618c2ecf20Sopenharmony_ci			 ? ", out of sync" : "",
52628c2ecf20Sopenharmony_ci			flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
52638c2ecf20Sopenharmony_ci			 ? ", quiesced" : "" );
52648c2ecf20Sopenharmony_ci		break;
52658c2ecf20Sopenharmony_ci
52668c2ecf20Sopenharmony_ci	case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
52678c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "  Domain Validation needed for PhysDisk %d\n",
52688c2ecf20Sopenharmony_ci			ioc->name, disk);
52698c2ecf20Sopenharmony_ci		break;
52708c2ecf20Sopenharmony_ci
52718c2ecf20Sopenharmony_ci	case MPI_EVENT_RAID_RC_SMART_DATA:
52728c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "  SMART data received, ASC/ASCQ = %02xh/%02xh\n",
52738c2ecf20Sopenharmony_ci			ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
52748c2ecf20Sopenharmony_ci		break;
52758c2ecf20Sopenharmony_ci
52768c2ecf20Sopenharmony_ci	case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
52778c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "  replacement of PhysDisk %d has started\n",
52788c2ecf20Sopenharmony_ci			ioc->name, disk);
52798c2ecf20Sopenharmony_ci		break;
52808c2ecf20Sopenharmony_ci	}
52818c2ecf20Sopenharmony_ci}
52828c2ecf20Sopenharmony_ci
52838c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
52848c2ecf20Sopenharmony_ci/**
52858c2ecf20Sopenharmony_ci *	GetIoUnitPage2 - Retrieve BIOS version and boot order information.
52868c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
52878c2ecf20Sopenharmony_ci *
52888c2ecf20Sopenharmony_ci *	Returns: 0 for success
52898c2ecf20Sopenharmony_ci *	-ENOMEM if no memory available
52908c2ecf20Sopenharmony_ci *		-EPERM if not allowed due to ISR context
52918c2ecf20Sopenharmony_ci *		-EAGAIN if no msg frames currently available
52928c2ecf20Sopenharmony_ci *		-EFAULT for non-successful reply or no reply (timeout)
52938c2ecf20Sopenharmony_ci */
52948c2ecf20Sopenharmony_cistatic int
52958c2ecf20Sopenharmony_ciGetIoUnitPage2(MPT_ADAPTER *ioc)
52968c2ecf20Sopenharmony_ci{
52978c2ecf20Sopenharmony_ci	ConfigPageHeader_t	 hdr;
52988c2ecf20Sopenharmony_ci	CONFIGPARMS		 cfg;
52998c2ecf20Sopenharmony_ci	IOUnitPage2_t		*ppage_alloc;
53008c2ecf20Sopenharmony_ci	dma_addr_t		 page_dma;
53018c2ecf20Sopenharmony_ci	int			 data_sz;
53028c2ecf20Sopenharmony_ci	int			 rc;
53038c2ecf20Sopenharmony_ci
53048c2ecf20Sopenharmony_ci	/* Get the page header */
53058c2ecf20Sopenharmony_ci	hdr.PageVersion = 0;
53068c2ecf20Sopenharmony_ci	hdr.PageLength = 0;
53078c2ecf20Sopenharmony_ci	hdr.PageNumber = 2;
53088c2ecf20Sopenharmony_ci	hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
53098c2ecf20Sopenharmony_ci	cfg.cfghdr.hdr = &hdr;
53108c2ecf20Sopenharmony_ci	cfg.physAddr = -1;
53118c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
53128c2ecf20Sopenharmony_ci	cfg.dir = 0;
53138c2ecf20Sopenharmony_ci	cfg.pageAddr = 0;
53148c2ecf20Sopenharmony_ci	cfg.timeout = 0;
53158c2ecf20Sopenharmony_ci
53168c2ecf20Sopenharmony_ci	if ((rc = mpt_config(ioc, &cfg)) != 0)
53178c2ecf20Sopenharmony_ci		return rc;
53188c2ecf20Sopenharmony_ci
53198c2ecf20Sopenharmony_ci	if (hdr.PageLength == 0)
53208c2ecf20Sopenharmony_ci		return 0;
53218c2ecf20Sopenharmony_ci
53228c2ecf20Sopenharmony_ci	/* Read the config page */
53238c2ecf20Sopenharmony_ci	data_sz = hdr.PageLength * 4;
53248c2ecf20Sopenharmony_ci	rc = -ENOMEM;
53258c2ecf20Sopenharmony_ci	ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
53268c2ecf20Sopenharmony_ci	if (ppage_alloc) {
53278c2ecf20Sopenharmony_ci		memset((u8 *)ppage_alloc, 0, data_sz);
53288c2ecf20Sopenharmony_ci		cfg.physAddr = page_dma;
53298c2ecf20Sopenharmony_ci		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
53308c2ecf20Sopenharmony_ci
53318c2ecf20Sopenharmony_ci		/* If Good, save data */
53328c2ecf20Sopenharmony_ci		if ((rc = mpt_config(ioc, &cfg)) == 0)
53338c2ecf20Sopenharmony_ci			ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
53348c2ecf20Sopenharmony_ci
53358c2ecf20Sopenharmony_ci		pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
53368c2ecf20Sopenharmony_ci	}
53378c2ecf20Sopenharmony_ci
53388c2ecf20Sopenharmony_ci	return rc;
53398c2ecf20Sopenharmony_ci}
53408c2ecf20Sopenharmony_ci
53418c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
53428c2ecf20Sopenharmony_ci/**
53438c2ecf20Sopenharmony_ci *	mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
53448c2ecf20Sopenharmony_ci *	@ioc: Pointer to a Adapter Strucutre
53458c2ecf20Sopenharmony_ci *	@portnum: IOC port number
53468c2ecf20Sopenharmony_ci *
53478c2ecf20Sopenharmony_ci *	Return: -EFAULT if read of config page header fails
53488c2ecf20Sopenharmony_ci *			or if no nvram
53498c2ecf20Sopenharmony_ci *	If read of SCSI Port Page 0 fails,
53508c2ecf20Sopenharmony_ci *		NVRAM = MPT_HOST_NVRAM_INVALID  (0xFFFFFFFF)
53518c2ecf20Sopenharmony_ci *		Adapter settings: async, narrow
53528c2ecf20Sopenharmony_ci *		Return 1
53538c2ecf20Sopenharmony_ci *	If read of SCSI Port Page 2 fails,
53548c2ecf20Sopenharmony_ci *		Adapter settings valid
53558c2ecf20Sopenharmony_ci *		NVRAM = MPT_HOST_NVRAM_INVALID  (0xFFFFFFFF)
53568c2ecf20Sopenharmony_ci *		Return 1
53578c2ecf20Sopenharmony_ci *	Else
53588c2ecf20Sopenharmony_ci *		Both valid
53598c2ecf20Sopenharmony_ci *		Return 0
53608c2ecf20Sopenharmony_ci *	CHECK - what type of locking mechanisms should be used????
53618c2ecf20Sopenharmony_ci */
53628c2ecf20Sopenharmony_cistatic int
53638c2ecf20Sopenharmony_cimpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
53648c2ecf20Sopenharmony_ci{
53658c2ecf20Sopenharmony_ci	u8			*pbuf;
53668c2ecf20Sopenharmony_ci	dma_addr_t		 buf_dma;
53678c2ecf20Sopenharmony_ci	CONFIGPARMS		 cfg;
53688c2ecf20Sopenharmony_ci	ConfigPageHeader_t	 header;
53698c2ecf20Sopenharmony_ci	int			 ii;
53708c2ecf20Sopenharmony_ci	int			 data, rc = 0;
53718c2ecf20Sopenharmony_ci
53728c2ecf20Sopenharmony_ci	/* Allocate memory
53738c2ecf20Sopenharmony_ci	 */
53748c2ecf20Sopenharmony_ci	if (!ioc->spi_data.nvram) {
53758c2ecf20Sopenharmony_ci		int	 sz;
53768c2ecf20Sopenharmony_ci		u8	*mem;
53778c2ecf20Sopenharmony_ci		sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
53788c2ecf20Sopenharmony_ci		mem = kmalloc(sz, GFP_ATOMIC);
53798c2ecf20Sopenharmony_ci		if (mem == NULL)
53808c2ecf20Sopenharmony_ci			return -EFAULT;
53818c2ecf20Sopenharmony_ci
53828c2ecf20Sopenharmony_ci		ioc->spi_data.nvram = (int *) mem;
53838c2ecf20Sopenharmony_ci
53848c2ecf20Sopenharmony_ci		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
53858c2ecf20Sopenharmony_ci			ioc->name, ioc->spi_data.nvram, sz));
53868c2ecf20Sopenharmony_ci	}
53878c2ecf20Sopenharmony_ci
53888c2ecf20Sopenharmony_ci	/* Invalidate NVRAM information
53898c2ecf20Sopenharmony_ci	 */
53908c2ecf20Sopenharmony_ci	for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
53918c2ecf20Sopenharmony_ci		ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
53928c2ecf20Sopenharmony_ci	}
53938c2ecf20Sopenharmony_ci
53948c2ecf20Sopenharmony_ci	/* Read SPP0 header, allocate memory, then read page.
53958c2ecf20Sopenharmony_ci	 */
53968c2ecf20Sopenharmony_ci	header.PageVersion = 0;
53978c2ecf20Sopenharmony_ci	header.PageLength = 0;
53988c2ecf20Sopenharmony_ci	header.PageNumber = 0;
53998c2ecf20Sopenharmony_ci	header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
54008c2ecf20Sopenharmony_ci	cfg.cfghdr.hdr = &header;
54018c2ecf20Sopenharmony_ci	cfg.physAddr = -1;
54028c2ecf20Sopenharmony_ci	cfg.pageAddr = portnum;
54038c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
54048c2ecf20Sopenharmony_ci	cfg.dir = 0;
54058c2ecf20Sopenharmony_ci	cfg.timeout = 0;	/* use default */
54068c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0)
54078c2ecf20Sopenharmony_ci		 return -EFAULT;
54088c2ecf20Sopenharmony_ci
54098c2ecf20Sopenharmony_ci	if (header.PageLength > 0) {
54108c2ecf20Sopenharmony_ci		pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
54118c2ecf20Sopenharmony_ci		if (pbuf) {
54128c2ecf20Sopenharmony_ci			cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
54138c2ecf20Sopenharmony_ci			cfg.physAddr = buf_dma;
54148c2ecf20Sopenharmony_ci			if (mpt_config(ioc, &cfg) != 0) {
54158c2ecf20Sopenharmony_ci				ioc->spi_data.maxBusWidth = MPT_NARROW;
54168c2ecf20Sopenharmony_ci				ioc->spi_data.maxSyncOffset = 0;
54178c2ecf20Sopenharmony_ci				ioc->spi_data.minSyncFactor = MPT_ASYNC;
54188c2ecf20Sopenharmony_ci				ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
54198c2ecf20Sopenharmony_ci				rc = 1;
54208c2ecf20Sopenharmony_ci				ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
54218c2ecf20Sopenharmony_ci					"Unable to read PortPage0 minSyncFactor=%x\n",
54228c2ecf20Sopenharmony_ci					ioc->name, ioc->spi_data.minSyncFactor));
54238c2ecf20Sopenharmony_ci			} else {
54248c2ecf20Sopenharmony_ci				/* Save the Port Page 0 data
54258c2ecf20Sopenharmony_ci				 */
54268c2ecf20Sopenharmony_ci				SCSIPortPage0_t  *pPP0 = (SCSIPortPage0_t  *) pbuf;
54278c2ecf20Sopenharmony_ci				pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
54288c2ecf20Sopenharmony_ci				pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
54298c2ecf20Sopenharmony_ci
54308c2ecf20Sopenharmony_ci				if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
54318c2ecf20Sopenharmony_ci					ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
54328c2ecf20Sopenharmony_ci					ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
54338c2ecf20Sopenharmony_ci						"noQas due to Capabilities=%x\n",
54348c2ecf20Sopenharmony_ci						ioc->name, pPP0->Capabilities));
54358c2ecf20Sopenharmony_ci				}
54368c2ecf20Sopenharmony_ci				ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
54378c2ecf20Sopenharmony_ci				data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
54388c2ecf20Sopenharmony_ci				if (data) {
54398c2ecf20Sopenharmony_ci					ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
54408c2ecf20Sopenharmony_ci					data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
54418c2ecf20Sopenharmony_ci					ioc->spi_data.minSyncFactor = (u8) (data >> 8);
54428c2ecf20Sopenharmony_ci					ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
54438c2ecf20Sopenharmony_ci						"PortPage0 minSyncFactor=%x\n",
54448c2ecf20Sopenharmony_ci						ioc->name, ioc->spi_data.minSyncFactor));
54458c2ecf20Sopenharmony_ci				} else {
54468c2ecf20Sopenharmony_ci					ioc->spi_data.maxSyncOffset = 0;
54478c2ecf20Sopenharmony_ci					ioc->spi_data.minSyncFactor = MPT_ASYNC;
54488c2ecf20Sopenharmony_ci				}
54498c2ecf20Sopenharmony_ci
54508c2ecf20Sopenharmony_ci				ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
54518c2ecf20Sopenharmony_ci
54528c2ecf20Sopenharmony_ci				/* Update the minSyncFactor based on bus type.
54538c2ecf20Sopenharmony_ci				 */
54548c2ecf20Sopenharmony_ci				if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
54558c2ecf20Sopenharmony_ci					(ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE))  {
54568c2ecf20Sopenharmony_ci
54578c2ecf20Sopenharmony_ci					if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
54588c2ecf20Sopenharmony_ci						ioc->spi_data.minSyncFactor = MPT_ULTRA;
54598c2ecf20Sopenharmony_ci						ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
54608c2ecf20Sopenharmony_ci							"HVD or SE detected, minSyncFactor=%x\n",
54618c2ecf20Sopenharmony_ci							ioc->name, ioc->spi_data.minSyncFactor));
54628c2ecf20Sopenharmony_ci					}
54638c2ecf20Sopenharmony_ci				}
54648c2ecf20Sopenharmony_ci			}
54658c2ecf20Sopenharmony_ci			if (pbuf) {
54668c2ecf20Sopenharmony_ci				pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
54678c2ecf20Sopenharmony_ci			}
54688c2ecf20Sopenharmony_ci		}
54698c2ecf20Sopenharmony_ci	}
54708c2ecf20Sopenharmony_ci
54718c2ecf20Sopenharmony_ci	/* SCSI Port Page 2 - Read the header then the page.
54728c2ecf20Sopenharmony_ci	 */
54738c2ecf20Sopenharmony_ci	header.PageVersion = 0;
54748c2ecf20Sopenharmony_ci	header.PageLength = 0;
54758c2ecf20Sopenharmony_ci	header.PageNumber = 2;
54768c2ecf20Sopenharmony_ci	header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
54778c2ecf20Sopenharmony_ci	cfg.cfghdr.hdr = &header;
54788c2ecf20Sopenharmony_ci	cfg.physAddr = -1;
54798c2ecf20Sopenharmony_ci	cfg.pageAddr = portnum;
54808c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
54818c2ecf20Sopenharmony_ci	cfg.dir = 0;
54828c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0)
54838c2ecf20Sopenharmony_ci		return -EFAULT;
54848c2ecf20Sopenharmony_ci
54858c2ecf20Sopenharmony_ci	if (header.PageLength > 0) {
54868c2ecf20Sopenharmony_ci		/* Allocate memory and read SCSI Port Page 2
54878c2ecf20Sopenharmony_ci		 */
54888c2ecf20Sopenharmony_ci		pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
54898c2ecf20Sopenharmony_ci		if (pbuf) {
54908c2ecf20Sopenharmony_ci			cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
54918c2ecf20Sopenharmony_ci			cfg.physAddr = buf_dma;
54928c2ecf20Sopenharmony_ci			if (mpt_config(ioc, &cfg) != 0) {
54938c2ecf20Sopenharmony_ci				/* Nvram data is left with INVALID mark
54948c2ecf20Sopenharmony_ci				 */
54958c2ecf20Sopenharmony_ci				rc = 1;
54968c2ecf20Sopenharmony_ci			} else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
54978c2ecf20Sopenharmony_ci
54988c2ecf20Sopenharmony_ci				/* This is an ATTO adapter, read Page2 accordingly
54998c2ecf20Sopenharmony_ci				*/
55008c2ecf20Sopenharmony_ci				ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t  *) pbuf;
55018c2ecf20Sopenharmony_ci				ATTODeviceInfo_t *pdevice = NULL;
55028c2ecf20Sopenharmony_ci				u16 ATTOFlags;
55038c2ecf20Sopenharmony_ci
55048c2ecf20Sopenharmony_ci				/* Save the Port Page 2 data
55058c2ecf20Sopenharmony_ci				 * (reformat into a 32bit quantity)
55068c2ecf20Sopenharmony_ci				 */
55078c2ecf20Sopenharmony_ci				for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
55088c2ecf20Sopenharmony_ci				  pdevice = &pPP2->DeviceSettings[ii];
55098c2ecf20Sopenharmony_ci				  ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
55108c2ecf20Sopenharmony_ci				  data = 0;
55118c2ecf20Sopenharmony_ci
55128c2ecf20Sopenharmony_ci				  /* Translate ATTO device flags to LSI format
55138c2ecf20Sopenharmony_ci				   */
55148c2ecf20Sopenharmony_ci				  if (ATTOFlags & ATTOFLAG_DISC)
55158c2ecf20Sopenharmony_ci				    data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
55168c2ecf20Sopenharmony_ci				  if (ATTOFlags & ATTOFLAG_ID_ENB)
55178c2ecf20Sopenharmony_ci				    data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
55188c2ecf20Sopenharmony_ci				  if (ATTOFlags & ATTOFLAG_LUN_ENB)
55198c2ecf20Sopenharmony_ci				    data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
55208c2ecf20Sopenharmony_ci				  if (ATTOFlags & ATTOFLAG_TAGGED)
55218c2ecf20Sopenharmony_ci				    data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
55228c2ecf20Sopenharmony_ci				  if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
55238c2ecf20Sopenharmony_ci				    data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
55248c2ecf20Sopenharmony_ci
55258c2ecf20Sopenharmony_ci				  data = (data << 16) | (pdevice->Period << 8) | 10;
55268c2ecf20Sopenharmony_ci				  ioc->spi_data.nvram[ii] = data;
55278c2ecf20Sopenharmony_ci				}
55288c2ecf20Sopenharmony_ci			} else {
55298c2ecf20Sopenharmony_ci				SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t  *) pbuf;
55308c2ecf20Sopenharmony_ci				MpiDeviceInfo_t	*pdevice = NULL;
55318c2ecf20Sopenharmony_ci
55328c2ecf20Sopenharmony_ci				/*
55338c2ecf20Sopenharmony_ci				 * Save "Set to Avoid SCSI Bus Resets" flag
55348c2ecf20Sopenharmony_ci				 */
55358c2ecf20Sopenharmony_ci				ioc->spi_data.bus_reset =
55368c2ecf20Sopenharmony_ci				    (le32_to_cpu(pPP2->PortFlags) &
55378c2ecf20Sopenharmony_ci			        MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
55388c2ecf20Sopenharmony_ci				    0 : 1 ;
55398c2ecf20Sopenharmony_ci
55408c2ecf20Sopenharmony_ci				/* Save the Port Page 2 data
55418c2ecf20Sopenharmony_ci				 * (reformat into a 32bit quantity)
55428c2ecf20Sopenharmony_ci				 */
55438c2ecf20Sopenharmony_ci				data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
55448c2ecf20Sopenharmony_ci				ioc->spi_data.PortFlags = data;
55458c2ecf20Sopenharmony_ci				for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
55468c2ecf20Sopenharmony_ci					pdevice = &pPP2->DeviceSettings[ii];
55478c2ecf20Sopenharmony_ci					data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
55488c2ecf20Sopenharmony_ci						(pdevice->SyncFactor << 8) | pdevice->Timeout;
55498c2ecf20Sopenharmony_ci					ioc->spi_data.nvram[ii] = data;
55508c2ecf20Sopenharmony_ci				}
55518c2ecf20Sopenharmony_ci			}
55528c2ecf20Sopenharmony_ci
55538c2ecf20Sopenharmony_ci			pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
55548c2ecf20Sopenharmony_ci		}
55558c2ecf20Sopenharmony_ci	}
55568c2ecf20Sopenharmony_ci
55578c2ecf20Sopenharmony_ci	/* Update Adapter limits with those from NVRAM
55588c2ecf20Sopenharmony_ci	 * Comment: Don't need to do this. Target performance
55598c2ecf20Sopenharmony_ci	 * parameters will never exceed the adapters limits.
55608c2ecf20Sopenharmony_ci	 */
55618c2ecf20Sopenharmony_ci
55628c2ecf20Sopenharmony_ci	return rc;
55638c2ecf20Sopenharmony_ci}
55648c2ecf20Sopenharmony_ci
55658c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
55668c2ecf20Sopenharmony_ci/**
55678c2ecf20Sopenharmony_ci *	mpt_readScsiDevicePageHeaders - save version and length of SDP1
55688c2ecf20Sopenharmony_ci *	@ioc: Pointer to a Adapter Strucutre
55698c2ecf20Sopenharmony_ci *	@portnum: IOC port number
55708c2ecf20Sopenharmony_ci *
55718c2ecf20Sopenharmony_ci *	Return: -EFAULT if read of config page header fails
55728c2ecf20Sopenharmony_ci *		or 0 if success.
55738c2ecf20Sopenharmony_ci */
55748c2ecf20Sopenharmony_cistatic int
55758c2ecf20Sopenharmony_cimpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
55768c2ecf20Sopenharmony_ci{
55778c2ecf20Sopenharmony_ci	CONFIGPARMS		 cfg;
55788c2ecf20Sopenharmony_ci	ConfigPageHeader_t	 header;
55798c2ecf20Sopenharmony_ci
55808c2ecf20Sopenharmony_ci	/* Read the SCSI Device Page 1 header
55818c2ecf20Sopenharmony_ci	 */
55828c2ecf20Sopenharmony_ci	header.PageVersion = 0;
55838c2ecf20Sopenharmony_ci	header.PageLength = 0;
55848c2ecf20Sopenharmony_ci	header.PageNumber = 1;
55858c2ecf20Sopenharmony_ci	header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
55868c2ecf20Sopenharmony_ci	cfg.cfghdr.hdr = &header;
55878c2ecf20Sopenharmony_ci	cfg.physAddr = -1;
55888c2ecf20Sopenharmony_ci	cfg.pageAddr = portnum;
55898c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
55908c2ecf20Sopenharmony_ci	cfg.dir = 0;
55918c2ecf20Sopenharmony_ci	cfg.timeout = 0;
55928c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0)
55938c2ecf20Sopenharmony_ci		 return -EFAULT;
55948c2ecf20Sopenharmony_ci
55958c2ecf20Sopenharmony_ci	ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
55968c2ecf20Sopenharmony_ci	ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
55978c2ecf20Sopenharmony_ci
55988c2ecf20Sopenharmony_ci	header.PageVersion = 0;
55998c2ecf20Sopenharmony_ci	header.PageLength = 0;
56008c2ecf20Sopenharmony_ci	header.PageNumber = 0;
56018c2ecf20Sopenharmony_ci	header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
56028c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0)
56038c2ecf20Sopenharmony_ci		 return -EFAULT;
56048c2ecf20Sopenharmony_ci
56058c2ecf20Sopenharmony_ci	ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
56068c2ecf20Sopenharmony_ci	ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
56078c2ecf20Sopenharmony_ci
56088c2ecf20Sopenharmony_ci	dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
56098c2ecf20Sopenharmony_ci			ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
56108c2ecf20Sopenharmony_ci
56118c2ecf20Sopenharmony_ci	dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
56128c2ecf20Sopenharmony_ci			ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
56138c2ecf20Sopenharmony_ci	return 0;
56148c2ecf20Sopenharmony_ci}
56158c2ecf20Sopenharmony_ci
56168c2ecf20Sopenharmony_ci/**
56178c2ecf20Sopenharmony_ci * mpt_inactive_raid_list_free - This clears this link list.
56188c2ecf20Sopenharmony_ci * @ioc : pointer to per adapter structure
56198c2ecf20Sopenharmony_ci **/
56208c2ecf20Sopenharmony_cistatic void
56218c2ecf20Sopenharmony_cimpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
56228c2ecf20Sopenharmony_ci{
56238c2ecf20Sopenharmony_ci	struct inactive_raid_component_info *component_info, *pNext;
56248c2ecf20Sopenharmony_ci
56258c2ecf20Sopenharmony_ci	if (list_empty(&ioc->raid_data.inactive_list))
56268c2ecf20Sopenharmony_ci		return;
56278c2ecf20Sopenharmony_ci
56288c2ecf20Sopenharmony_ci	mutex_lock(&ioc->raid_data.inactive_list_mutex);
56298c2ecf20Sopenharmony_ci	list_for_each_entry_safe(component_info, pNext,
56308c2ecf20Sopenharmony_ci	    &ioc->raid_data.inactive_list, list) {
56318c2ecf20Sopenharmony_ci		list_del(&component_info->list);
56328c2ecf20Sopenharmony_ci		kfree(component_info);
56338c2ecf20Sopenharmony_ci	}
56348c2ecf20Sopenharmony_ci	mutex_unlock(&ioc->raid_data.inactive_list_mutex);
56358c2ecf20Sopenharmony_ci}
56368c2ecf20Sopenharmony_ci
56378c2ecf20Sopenharmony_ci/**
56388c2ecf20Sopenharmony_ci * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums for devices belonging in an inactive volume
56398c2ecf20Sopenharmony_ci *
56408c2ecf20Sopenharmony_ci * @ioc : pointer to per adapter structure
56418c2ecf20Sopenharmony_ci * @channel : volume channel
56428c2ecf20Sopenharmony_ci * @id : volume target id
56438c2ecf20Sopenharmony_ci **/
56448c2ecf20Sopenharmony_cistatic void
56458c2ecf20Sopenharmony_cimpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
56468c2ecf20Sopenharmony_ci{
56478c2ecf20Sopenharmony_ci	CONFIGPARMS			cfg;
56488c2ecf20Sopenharmony_ci	ConfigPageHeader_t		hdr;
56498c2ecf20Sopenharmony_ci	dma_addr_t			dma_handle;
56508c2ecf20Sopenharmony_ci	pRaidVolumePage0_t		buffer = NULL;
56518c2ecf20Sopenharmony_ci	int				i;
56528c2ecf20Sopenharmony_ci	RaidPhysDiskPage0_t 		phys_disk;
56538c2ecf20Sopenharmony_ci	struct inactive_raid_component_info *component_info;
56548c2ecf20Sopenharmony_ci	int				handle_inactive_volumes;
56558c2ecf20Sopenharmony_ci
56568c2ecf20Sopenharmony_ci	memset(&cfg, 0 , sizeof(CONFIGPARMS));
56578c2ecf20Sopenharmony_ci	memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
56588c2ecf20Sopenharmony_ci	hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
56598c2ecf20Sopenharmony_ci	cfg.pageAddr = (channel << 8) + id;
56608c2ecf20Sopenharmony_ci	cfg.cfghdr.hdr = &hdr;
56618c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
56628c2ecf20Sopenharmony_ci
56638c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0)
56648c2ecf20Sopenharmony_ci		goto out;
56658c2ecf20Sopenharmony_ci
56668c2ecf20Sopenharmony_ci	if (!hdr.PageLength)
56678c2ecf20Sopenharmony_ci		goto out;
56688c2ecf20Sopenharmony_ci
56698c2ecf20Sopenharmony_ci	buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
56708c2ecf20Sopenharmony_ci	    &dma_handle);
56718c2ecf20Sopenharmony_ci
56728c2ecf20Sopenharmony_ci	if (!buffer)
56738c2ecf20Sopenharmony_ci		goto out;
56748c2ecf20Sopenharmony_ci
56758c2ecf20Sopenharmony_ci	cfg.physAddr = dma_handle;
56768c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
56778c2ecf20Sopenharmony_ci
56788c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0)
56798c2ecf20Sopenharmony_ci		goto out;
56808c2ecf20Sopenharmony_ci
56818c2ecf20Sopenharmony_ci	if (!buffer->NumPhysDisks)
56828c2ecf20Sopenharmony_ci		goto out;
56838c2ecf20Sopenharmony_ci
56848c2ecf20Sopenharmony_ci	handle_inactive_volumes =
56858c2ecf20Sopenharmony_ci	   (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
56868c2ecf20Sopenharmony_ci	   (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
56878c2ecf20Sopenharmony_ci	    buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
56888c2ecf20Sopenharmony_ci	    buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
56898c2ecf20Sopenharmony_ci
56908c2ecf20Sopenharmony_ci	if (!handle_inactive_volumes)
56918c2ecf20Sopenharmony_ci		goto out;
56928c2ecf20Sopenharmony_ci
56938c2ecf20Sopenharmony_ci	mutex_lock(&ioc->raid_data.inactive_list_mutex);
56948c2ecf20Sopenharmony_ci	for (i = 0; i < buffer->NumPhysDisks; i++) {
56958c2ecf20Sopenharmony_ci		if(mpt_raid_phys_disk_pg0(ioc,
56968c2ecf20Sopenharmony_ci		    buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
56978c2ecf20Sopenharmony_ci			continue;
56988c2ecf20Sopenharmony_ci
56998c2ecf20Sopenharmony_ci		if ((component_info = kmalloc(sizeof (*component_info),
57008c2ecf20Sopenharmony_ci		 GFP_KERNEL)) == NULL)
57018c2ecf20Sopenharmony_ci			continue;
57028c2ecf20Sopenharmony_ci
57038c2ecf20Sopenharmony_ci		component_info->volumeID = id;
57048c2ecf20Sopenharmony_ci		component_info->volumeBus = channel;
57058c2ecf20Sopenharmony_ci		component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
57068c2ecf20Sopenharmony_ci		component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
57078c2ecf20Sopenharmony_ci		component_info->d.PhysDiskID = phys_disk.PhysDiskID;
57088c2ecf20Sopenharmony_ci		component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
57098c2ecf20Sopenharmony_ci
57108c2ecf20Sopenharmony_ci		list_add_tail(&component_info->list,
57118c2ecf20Sopenharmony_ci		    &ioc->raid_data.inactive_list);
57128c2ecf20Sopenharmony_ci	}
57138c2ecf20Sopenharmony_ci	mutex_unlock(&ioc->raid_data.inactive_list_mutex);
57148c2ecf20Sopenharmony_ci
57158c2ecf20Sopenharmony_ci out:
57168c2ecf20Sopenharmony_ci	if (buffer)
57178c2ecf20Sopenharmony_ci		pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
57188c2ecf20Sopenharmony_ci		    dma_handle);
57198c2ecf20Sopenharmony_ci}
57208c2ecf20Sopenharmony_ci
57218c2ecf20Sopenharmony_ci/**
57228c2ecf20Sopenharmony_ci *	mpt_raid_phys_disk_pg0 - returns phys disk page zero
57238c2ecf20Sopenharmony_ci *	@ioc: Pointer to a Adapter Structure
57248c2ecf20Sopenharmony_ci *	@phys_disk_num: io unit unique phys disk num generated by the ioc
57258c2ecf20Sopenharmony_ci *	@phys_disk: requested payload data returned
57268c2ecf20Sopenharmony_ci *
57278c2ecf20Sopenharmony_ci *	Return:
57288c2ecf20Sopenharmony_ci *	0 on success
57298c2ecf20Sopenharmony_ci *	-EFAULT if read of config page header fails or data pointer not NULL
57308c2ecf20Sopenharmony_ci *	-ENOMEM if pci_alloc failed
57318c2ecf20Sopenharmony_ci **/
57328c2ecf20Sopenharmony_ciint
57338c2ecf20Sopenharmony_cimpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
57348c2ecf20Sopenharmony_ci			RaidPhysDiskPage0_t *phys_disk)
57358c2ecf20Sopenharmony_ci{
57368c2ecf20Sopenharmony_ci	CONFIGPARMS			cfg;
57378c2ecf20Sopenharmony_ci	ConfigPageHeader_t		hdr;
57388c2ecf20Sopenharmony_ci	dma_addr_t			dma_handle;
57398c2ecf20Sopenharmony_ci	pRaidPhysDiskPage0_t		buffer = NULL;
57408c2ecf20Sopenharmony_ci	int				rc;
57418c2ecf20Sopenharmony_ci
57428c2ecf20Sopenharmony_ci	memset(&cfg, 0 , sizeof(CONFIGPARMS));
57438c2ecf20Sopenharmony_ci	memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
57448c2ecf20Sopenharmony_ci	memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
57458c2ecf20Sopenharmony_ci
57468c2ecf20Sopenharmony_ci	hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
57478c2ecf20Sopenharmony_ci	hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
57488c2ecf20Sopenharmony_ci	cfg.cfghdr.hdr = &hdr;
57498c2ecf20Sopenharmony_ci	cfg.physAddr = -1;
57508c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
57518c2ecf20Sopenharmony_ci
57528c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0) {
57538c2ecf20Sopenharmony_ci		rc = -EFAULT;
57548c2ecf20Sopenharmony_ci		goto out;
57558c2ecf20Sopenharmony_ci	}
57568c2ecf20Sopenharmony_ci
57578c2ecf20Sopenharmony_ci	if (!hdr.PageLength) {
57588c2ecf20Sopenharmony_ci		rc = -EFAULT;
57598c2ecf20Sopenharmony_ci		goto out;
57608c2ecf20Sopenharmony_ci	}
57618c2ecf20Sopenharmony_ci
57628c2ecf20Sopenharmony_ci	buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
57638c2ecf20Sopenharmony_ci	    &dma_handle);
57648c2ecf20Sopenharmony_ci
57658c2ecf20Sopenharmony_ci	if (!buffer) {
57668c2ecf20Sopenharmony_ci		rc = -ENOMEM;
57678c2ecf20Sopenharmony_ci		goto out;
57688c2ecf20Sopenharmony_ci	}
57698c2ecf20Sopenharmony_ci
57708c2ecf20Sopenharmony_ci	cfg.physAddr = dma_handle;
57718c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
57728c2ecf20Sopenharmony_ci	cfg.pageAddr = phys_disk_num;
57738c2ecf20Sopenharmony_ci
57748c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0) {
57758c2ecf20Sopenharmony_ci		rc = -EFAULT;
57768c2ecf20Sopenharmony_ci		goto out;
57778c2ecf20Sopenharmony_ci	}
57788c2ecf20Sopenharmony_ci
57798c2ecf20Sopenharmony_ci	rc = 0;
57808c2ecf20Sopenharmony_ci	memcpy(phys_disk, buffer, sizeof(*buffer));
57818c2ecf20Sopenharmony_ci	phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
57828c2ecf20Sopenharmony_ci
57838c2ecf20Sopenharmony_ci out:
57848c2ecf20Sopenharmony_ci
57858c2ecf20Sopenharmony_ci	if (buffer)
57868c2ecf20Sopenharmony_ci		pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
57878c2ecf20Sopenharmony_ci		    dma_handle);
57888c2ecf20Sopenharmony_ci
57898c2ecf20Sopenharmony_ci	return rc;
57908c2ecf20Sopenharmony_ci}
57918c2ecf20Sopenharmony_ci
57928c2ecf20Sopenharmony_ci/**
57938c2ecf20Sopenharmony_ci *	mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
57948c2ecf20Sopenharmony_ci *	@ioc: Pointer to a Adapter Structure
57958c2ecf20Sopenharmony_ci *	@phys_disk_num: io unit unique phys disk num generated by the ioc
57968c2ecf20Sopenharmony_ci *
57978c2ecf20Sopenharmony_ci *	Return:
57988c2ecf20Sopenharmony_ci *	returns number paths
57998c2ecf20Sopenharmony_ci **/
58008c2ecf20Sopenharmony_ciint
58018c2ecf20Sopenharmony_cimpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
58028c2ecf20Sopenharmony_ci{
58038c2ecf20Sopenharmony_ci	CONFIGPARMS		 	cfg;
58048c2ecf20Sopenharmony_ci	ConfigPageHeader_t	 	hdr;
58058c2ecf20Sopenharmony_ci	dma_addr_t			dma_handle;
58068c2ecf20Sopenharmony_ci	pRaidPhysDiskPage1_t		buffer = NULL;
58078c2ecf20Sopenharmony_ci	int				rc;
58088c2ecf20Sopenharmony_ci
58098c2ecf20Sopenharmony_ci	memset(&cfg, 0 , sizeof(CONFIGPARMS));
58108c2ecf20Sopenharmony_ci	memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
58118c2ecf20Sopenharmony_ci
58128c2ecf20Sopenharmony_ci	hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
58138c2ecf20Sopenharmony_ci	hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
58148c2ecf20Sopenharmony_ci	hdr.PageNumber = 1;
58158c2ecf20Sopenharmony_ci	cfg.cfghdr.hdr = &hdr;
58168c2ecf20Sopenharmony_ci	cfg.physAddr = -1;
58178c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
58188c2ecf20Sopenharmony_ci
58198c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0) {
58208c2ecf20Sopenharmony_ci		rc = 0;
58218c2ecf20Sopenharmony_ci		goto out;
58228c2ecf20Sopenharmony_ci	}
58238c2ecf20Sopenharmony_ci
58248c2ecf20Sopenharmony_ci	if (!hdr.PageLength) {
58258c2ecf20Sopenharmony_ci		rc = 0;
58268c2ecf20Sopenharmony_ci		goto out;
58278c2ecf20Sopenharmony_ci	}
58288c2ecf20Sopenharmony_ci
58298c2ecf20Sopenharmony_ci	buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
58308c2ecf20Sopenharmony_ci	    &dma_handle);
58318c2ecf20Sopenharmony_ci
58328c2ecf20Sopenharmony_ci	if (!buffer) {
58338c2ecf20Sopenharmony_ci		rc = 0;
58348c2ecf20Sopenharmony_ci		goto out;
58358c2ecf20Sopenharmony_ci	}
58368c2ecf20Sopenharmony_ci
58378c2ecf20Sopenharmony_ci	cfg.physAddr = dma_handle;
58388c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
58398c2ecf20Sopenharmony_ci	cfg.pageAddr = phys_disk_num;
58408c2ecf20Sopenharmony_ci
58418c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0) {
58428c2ecf20Sopenharmony_ci		rc = 0;
58438c2ecf20Sopenharmony_ci		goto out;
58448c2ecf20Sopenharmony_ci	}
58458c2ecf20Sopenharmony_ci
58468c2ecf20Sopenharmony_ci	rc = buffer->NumPhysDiskPaths;
58478c2ecf20Sopenharmony_ci out:
58488c2ecf20Sopenharmony_ci
58498c2ecf20Sopenharmony_ci	if (buffer)
58508c2ecf20Sopenharmony_ci		pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
58518c2ecf20Sopenharmony_ci		    dma_handle);
58528c2ecf20Sopenharmony_ci
58538c2ecf20Sopenharmony_ci	return rc;
58548c2ecf20Sopenharmony_ci}
58558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
58568c2ecf20Sopenharmony_ci
58578c2ecf20Sopenharmony_ci/**
58588c2ecf20Sopenharmony_ci *	mpt_raid_phys_disk_pg1 - returns phys disk page 1
58598c2ecf20Sopenharmony_ci *	@ioc: Pointer to a Adapter Structure
58608c2ecf20Sopenharmony_ci *	@phys_disk_num: io unit unique phys disk num generated by the ioc
58618c2ecf20Sopenharmony_ci *	@phys_disk: requested payload data returned
58628c2ecf20Sopenharmony_ci *
58638c2ecf20Sopenharmony_ci *	Return:
58648c2ecf20Sopenharmony_ci *	0 on success
58658c2ecf20Sopenharmony_ci *	-EFAULT if read of config page header fails or data pointer not NULL
58668c2ecf20Sopenharmony_ci *	-ENOMEM if pci_alloc failed
58678c2ecf20Sopenharmony_ci **/
58688c2ecf20Sopenharmony_ciint
58698c2ecf20Sopenharmony_cimpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
58708c2ecf20Sopenharmony_ci		RaidPhysDiskPage1_t *phys_disk)
58718c2ecf20Sopenharmony_ci{
58728c2ecf20Sopenharmony_ci	CONFIGPARMS		 	cfg;
58738c2ecf20Sopenharmony_ci	ConfigPageHeader_t	 	hdr;
58748c2ecf20Sopenharmony_ci	dma_addr_t			dma_handle;
58758c2ecf20Sopenharmony_ci	pRaidPhysDiskPage1_t		buffer = NULL;
58768c2ecf20Sopenharmony_ci	int				rc;
58778c2ecf20Sopenharmony_ci	int				i;
58788c2ecf20Sopenharmony_ci	__le64				sas_address;
58798c2ecf20Sopenharmony_ci
58808c2ecf20Sopenharmony_ci	memset(&cfg, 0 , sizeof(CONFIGPARMS));
58818c2ecf20Sopenharmony_ci	memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
58828c2ecf20Sopenharmony_ci	rc = 0;
58838c2ecf20Sopenharmony_ci
58848c2ecf20Sopenharmony_ci	hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
58858c2ecf20Sopenharmony_ci	hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
58868c2ecf20Sopenharmony_ci	hdr.PageNumber = 1;
58878c2ecf20Sopenharmony_ci	cfg.cfghdr.hdr = &hdr;
58888c2ecf20Sopenharmony_ci	cfg.physAddr = -1;
58898c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
58908c2ecf20Sopenharmony_ci
58918c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0) {
58928c2ecf20Sopenharmony_ci		rc = -EFAULT;
58938c2ecf20Sopenharmony_ci		goto out;
58948c2ecf20Sopenharmony_ci	}
58958c2ecf20Sopenharmony_ci
58968c2ecf20Sopenharmony_ci	if (!hdr.PageLength) {
58978c2ecf20Sopenharmony_ci		rc = -EFAULT;
58988c2ecf20Sopenharmony_ci		goto out;
58998c2ecf20Sopenharmony_ci	}
59008c2ecf20Sopenharmony_ci
59018c2ecf20Sopenharmony_ci	buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
59028c2ecf20Sopenharmony_ci	    &dma_handle);
59038c2ecf20Sopenharmony_ci
59048c2ecf20Sopenharmony_ci	if (!buffer) {
59058c2ecf20Sopenharmony_ci		rc = -ENOMEM;
59068c2ecf20Sopenharmony_ci		goto out;
59078c2ecf20Sopenharmony_ci	}
59088c2ecf20Sopenharmony_ci
59098c2ecf20Sopenharmony_ci	cfg.physAddr = dma_handle;
59108c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
59118c2ecf20Sopenharmony_ci	cfg.pageAddr = phys_disk_num;
59128c2ecf20Sopenharmony_ci
59138c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0) {
59148c2ecf20Sopenharmony_ci		rc = -EFAULT;
59158c2ecf20Sopenharmony_ci		goto out;
59168c2ecf20Sopenharmony_ci	}
59178c2ecf20Sopenharmony_ci
59188c2ecf20Sopenharmony_ci	phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
59198c2ecf20Sopenharmony_ci	phys_disk->PhysDiskNum = phys_disk_num;
59208c2ecf20Sopenharmony_ci	for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
59218c2ecf20Sopenharmony_ci		phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
59228c2ecf20Sopenharmony_ci		phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
59238c2ecf20Sopenharmony_ci		phys_disk->Path[i].OwnerIdentifier =
59248c2ecf20Sopenharmony_ci				buffer->Path[i].OwnerIdentifier;
59258c2ecf20Sopenharmony_ci		phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
59268c2ecf20Sopenharmony_ci		memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
59278c2ecf20Sopenharmony_ci		sas_address = le64_to_cpu(sas_address);
59288c2ecf20Sopenharmony_ci		memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
59298c2ecf20Sopenharmony_ci		memcpy(&sas_address,
59308c2ecf20Sopenharmony_ci				&buffer->Path[i].OwnerWWID, sizeof(__le64));
59318c2ecf20Sopenharmony_ci		sas_address = le64_to_cpu(sas_address);
59328c2ecf20Sopenharmony_ci		memcpy(&phys_disk->Path[i].OwnerWWID,
59338c2ecf20Sopenharmony_ci				&sas_address, sizeof(__le64));
59348c2ecf20Sopenharmony_ci	}
59358c2ecf20Sopenharmony_ci
59368c2ecf20Sopenharmony_ci out:
59378c2ecf20Sopenharmony_ci
59388c2ecf20Sopenharmony_ci	if (buffer)
59398c2ecf20Sopenharmony_ci		pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
59408c2ecf20Sopenharmony_ci		    dma_handle);
59418c2ecf20Sopenharmony_ci
59428c2ecf20Sopenharmony_ci	return rc;
59438c2ecf20Sopenharmony_ci}
59448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
59458c2ecf20Sopenharmony_ci
59468c2ecf20Sopenharmony_ci
59478c2ecf20Sopenharmony_ci/**
59488c2ecf20Sopenharmony_ci *	mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
59498c2ecf20Sopenharmony_ci *	@ioc: Pointer to a Adapter Strucutre
59508c2ecf20Sopenharmony_ci *
59518c2ecf20Sopenharmony_ci *	Return:
59528c2ecf20Sopenharmony_ci *	0 on success
59538c2ecf20Sopenharmony_ci *	-EFAULT if read of config page header fails or data pointer not NULL
59548c2ecf20Sopenharmony_ci *	-ENOMEM if pci_alloc failed
59558c2ecf20Sopenharmony_ci **/
59568c2ecf20Sopenharmony_ciint
59578c2ecf20Sopenharmony_cimpt_findImVolumes(MPT_ADAPTER *ioc)
59588c2ecf20Sopenharmony_ci{
59598c2ecf20Sopenharmony_ci	IOCPage2_t		*pIoc2;
59608c2ecf20Sopenharmony_ci	u8			*mem;
59618c2ecf20Sopenharmony_ci	dma_addr_t		 ioc2_dma;
59628c2ecf20Sopenharmony_ci	CONFIGPARMS		 cfg;
59638c2ecf20Sopenharmony_ci	ConfigPageHeader_t	 header;
59648c2ecf20Sopenharmony_ci	int			 rc = 0;
59658c2ecf20Sopenharmony_ci	int			 iocpage2sz;
59668c2ecf20Sopenharmony_ci	int			 i;
59678c2ecf20Sopenharmony_ci
59688c2ecf20Sopenharmony_ci	if (!ioc->ir_firmware)
59698c2ecf20Sopenharmony_ci		return 0;
59708c2ecf20Sopenharmony_ci
59718c2ecf20Sopenharmony_ci	/* Free the old page
59728c2ecf20Sopenharmony_ci	 */
59738c2ecf20Sopenharmony_ci	kfree(ioc->raid_data.pIocPg2);
59748c2ecf20Sopenharmony_ci	ioc->raid_data.pIocPg2 = NULL;
59758c2ecf20Sopenharmony_ci	mpt_inactive_raid_list_free(ioc);
59768c2ecf20Sopenharmony_ci
59778c2ecf20Sopenharmony_ci	/* Read IOCP2 header then the page.
59788c2ecf20Sopenharmony_ci	 */
59798c2ecf20Sopenharmony_ci	header.PageVersion = 0;
59808c2ecf20Sopenharmony_ci	header.PageLength = 0;
59818c2ecf20Sopenharmony_ci	header.PageNumber = 2;
59828c2ecf20Sopenharmony_ci	header.PageType = MPI_CONFIG_PAGETYPE_IOC;
59838c2ecf20Sopenharmony_ci	cfg.cfghdr.hdr = &header;
59848c2ecf20Sopenharmony_ci	cfg.physAddr = -1;
59858c2ecf20Sopenharmony_ci	cfg.pageAddr = 0;
59868c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
59878c2ecf20Sopenharmony_ci	cfg.dir = 0;
59888c2ecf20Sopenharmony_ci	cfg.timeout = 0;
59898c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0)
59908c2ecf20Sopenharmony_ci		 return -EFAULT;
59918c2ecf20Sopenharmony_ci
59928c2ecf20Sopenharmony_ci	if (header.PageLength == 0)
59938c2ecf20Sopenharmony_ci		return -EFAULT;
59948c2ecf20Sopenharmony_ci
59958c2ecf20Sopenharmony_ci	iocpage2sz = header.PageLength * 4;
59968c2ecf20Sopenharmony_ci	pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
59978c2ecf20Sopenharmony_ci	if (!pIoc2)
59988c2ecf20Sopenharmony_ci		return -ENOMEM;
59998c2ecf20Sopenharmony_ci
60008c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
60018c2ecf20Sopenharmony_ci	cfg.physAddr = ioc2_dma;
60028c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0)
60038c2ecf20Sopenharmony_ci		goto out;
60048c2ecf20Sopenharmony_ci
60058c2ecf20Sopenharmony_ci	mem = kmemdup(pIoc2, iocpage2sz, GFP_KERNEL);
60068c2ecf20Sopenharmony_ci	if (!mem) {
60078c2ecf20Sopenharmony_ci		rc = -ENOMEM;
60088c2ecf20Sopenharmony_ci		goto out;
60098c2ecf20Sopenharmony_ci	}
60108c2ecf20Sopenharmony_ci
60118c2ecf20Sopenharmony_ci	ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
60128c2ecf20Sopenharmony_ci
60138c2ecf20Sopenharmony_ci	mpt_read_ioc_pg_3(ioc);
60148c2ecf20Sopenharmony_ci
60158c2ecf20Sopenharmony_ci	for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
60168c2ecf20Sopenharmony_ci		mpt_inactive_raid_volumes(ioc,
60178c2ecf20Sopenharmony_ci		    pIoc2->RaidVolume[i].VolumeBus,
60188c2ecf20Sopenharmony_ci		    pIoc2->RaidVolume[i].VolumeID);
60198c2ecf20Sopenharmony_ci
60208c2ecf20Sopenharmony_ci out:
60218c2ecf20Sopenharmony_ci	pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
60228c2ecf20Sopenharmony_ci
60238c2ecf20Sopenharmony_ci	return rc;
60248c2ecf20Sopenharmony_ci}
60258c2ecf20Sopenharmony_ci
60268c2ecf20Sopenharmony_cistatic int
60278c2ecf20Sopenharmony_cimpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
60288c2ecf20Sopenharmony_ci{
60298c2ecf20Sopenharmony_ci	IOCPage3_t		*pIoc3;
60308c2ecf20Sopenharmony_ci	u8			*mem;
60318c2ecf20Sopenharmony_ci	CONFIGPARMS		 cfg;
60328c2ecf20Sopenharmony_ci	ConfigPageHeader_t	 header;
60338c2ecf20Sopenharmony_ci	dma_addr_t		 ioc3_dma;
60348c2ecf20Sopenharmony_ci	int			 iocpage3sz = 0;
60358c2ecf20Sopenharmony_ci
60368c2ecf20Sopenharmony_ci	/* Free the old page
60378c2ecf20Sopenharmony_ci	 */
60388c2ecf20Sopenharmony_ci	kfree(ioc->raid_data.pIocPg3);
60398c2ecf20Sopenharmony_ci	ioc->raid_data.pIocPg3 = NULL;
60408c2ecf20Sopenharmony_ci
60418c2ecf20Sopenharmony_ci	/* There is at least one physical disk.
60428c2ecf20Sopenharmony_ci	 * Read and save IOC Page 3
60438c2ecf20Sopenharmony_ci	 */
60448c2ecf20Sopenharmony_ci	header.PageVersion = 0;
60458c2ecf20Sopenharmony_ci	header.PageLength = 0;
60468c2ecf20Sopenharmony_ci	header.PageNumber = 3;
60478c2ecf20Sopenharmony_ci	header.PageType = MPI_CONFIG_PAGETYPE_IOC;
60488c2ecf20Sopenharmony_ci	cfg.cfghdr.hdr = &header;
60498c2ecf20Sopenharmony_ci	cfg.physAddr = -1;
60508c2ecf20Sopenharmony_ci	cfg.pageAddr = 0;
60518c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
60528c2ecf20Sopenharmony_ci	cfg.dir = 0;
60538c2ecf20Sopenharmony_ci	cfg.timeout = 0;
60548c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0)
60558c2ecf20Sopenharmony_ci		return 0;
60568c2ecf20Sopenharmony_ci
60578c2ecf20Sopenharmony_ci	if (header.PageLength == 0)
60588c2ecf20Sopenharmony_ci		return 0;
60598c2ecf20Sopenharmony_ci
60608c2ecf20Sopenharmony_ci	/* Read Header good, alloc memory
60618c2ecf20Sopenharmony_ci	 */
60628c2ecf20Sopenharmony_ci	iocpage3sz = header.PageLength * 4;
60638c2ecf20Sopenharmony_ci	pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
60648c2ecf20Sopenharmony_ci	if (!pIoc3)
60658c2ecf20Sopenharmony_ci		return 0;
60668c2ecf20Sopenharmony_ci
60678c2ecf20Sopenharmony_ci	/* Read the Page and save the data
60688c2ecf20Sopenharmony_ci	 * into malloc'd memory.
60698c2ecf20Sopenharmony_ci	 */
60708c2ecf20Sopenharmony_ci	cfg.physAddr = ioc3_dma;
60718c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
60728c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) == 0) {
60738c2ecf20Sopenharmony_ci		mem = kmalloc(iocpage3sz, GFP_KERNEL);
60748c2ecf20Sopenharmony_ci		if (mem) {
60758c2ecf20Sopenharmony_ci			memcpy(mem, (u8 *)pIoc3, iocpage3sz);
60768c2ecf20Sopenharmony_ci			ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
60778c2ecf20Sopenharmony_ci		}
60788c2ecf20Sopenharmony_ci	}
60798c2ecf20Sopenharmony_ci
60808c2ecf20Sopenharmony_ci	pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
60818c2ecf20Sopenharmony_ci
60828c2ecf20Sopenharmony_ci	return 0;
60838c2ecf20Sopenharmony_ci}
60848c2ecf20Sopenharmony_ci
60858c2ecf20Sopenharmony_cistatic void
60868c2ecf20Sopenharmony_cimpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
60878c2ecf20Sopenharmony_ci{
60888c2ecf20Sopenharmony_ci	IOCPage4_t		*pIoc4;
60898c2ecf20Sopenharmony_ci	CONFIGPARMS		 cfg;
60908c2ecf20Sopenharmony_ci	ConfigPageHeader_t	 header;
60918c2ecf20Sopenharmony_ci	dma_addr_t		 ioc4_dma;
60928c2ecf20Sopenharmony_ci	int			 iocpage4sz;
60938c2ecf20Sopenharmony_ci
60948c2ecf20Sopenharmony_ci	/* Read and save IOC Page 4
60958c2ecf20Sopenharmony_ci	 */
60968c2ecf20Sopenharmony_ci	header.PageVersion = 0;
60978c2ecf20Sopenharmony_ci	header.PageLength = 0;
60988c2ecf20Sopenharmony_ci	header.PageNumber = 4;
60998c2ecf20Sopenharmony_ci	header.PageType = MPI_CONFIG_PAGETYPE_IOC;
61008c2ecf20Sopenharmony_ci	cfg.cfghdr.hdr = &header;
61018c2ecf20Sopenharmony_ci	cfg.physAddr = -1;
61028c2ecf20Sopenharmony_ci	cfg.pageAddr = 0;
61038c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
61048c2ecf20Sopenharmony_ci	cfg.dir = 0;
61058c2ecf20Sopenharmony_ci	cfg.timeout = 0;
61068c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0)
61078c2ecf20Sopenharmony_ci		return;
61088c2ecf20Sopenharmony_ci
61098c2ecf20Sopenharmony_ci	if (header.PageLength == 0)
61108c2ecf20Sopenharmony_ci		return;
61118c2ecf20Sopenharmony_ci
61128c2ecf20Sopenharmony_ci	if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
61138c2ecf20Sopenharmony_ci		iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
61148c2ecf20Sopenharmony_ci		pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
61158c2ecf20Sopenharmony_ci		if (!pIoc4)
61168c2ecf20Sopenharmony_ci			return;
61178c2ecf20Sopenharmony_ci		ioc->alloc_total += iocpage4sz;
61188c2ecf20Sopenharmony_ci	} else {
61198c2ecf20Sopenharmony_ci		ioc4_dma = ioc->spi_data.IocPg4_dma;
61208c2ecf20Sopenharmony_ci		iocpage4sz = ioc->spi_data.IocPg4Sz;
61218c2ecf20Sopenharmony_ci	}
61228c2ecf20Sopenharmony_ci
61238c2ecf20Sopenharmony_ci	/* Read the Page into dma memory.
61248c2ecf20Sopenharmony_ci	 */
61258c2ecf20Sopenharmony_ci	cfg.physAddr = ioc4_dma;
61268c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
61278c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) == 0) {
61288c2ecf20Sopenharmony_ci		ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
61298c2ecf20Sopenharmony_ci		ioc->spi_data.IocPg4_dma = ioc4_dma;
61308c2ecf20Sopenharmony_ci		ioc->spi_data.IocPg4Sz = iocpage4sz;
61318c2ecf20Sopenharmony_ci	} else {
61328c2ecf20Sopenharmony_ci		pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
61338c2ecf20Sopenharmony_ci		ioc->spi_data.pIocPg4 = NULL;
61348c2ecf20Sopenharmony_ci		ioc->alloc_total -= iocpage4sz;
61358c2ecf20Sopenharmony_ci	}
61368c2ecf20Sopenharmony_ci}
61378c2ecf20Sopenharmony_ci
61388c2ecf20Sopenharmony_cistatic void
61398c2ecf20Sopenharmony_cimpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
61408c2ecf20Sopenharmony_ci{
61418c2ecf20Sopenharmony_ci	IOCPage1_t		*pIoc1;
61428c2ecf20Sopenharmony_ci	CONFIGPARMS		 cfg;
61438c2ecf20Sopenharmony_ci	ConfigPageHeader_t	 header;
61448c2ecf20Sopenharmony_ci	dma_addr_t		 ioc1_dma;
61458c2ecf20Sopenharmony_ci	int			 iocpage1sz = 0;
61468c2ecf20Sopenharmony_ci	u32			 tmp;
61478c2ecf20Sopenharmony_ci
61488c2ecf20Sopenharmony_ci	/* Check the Coalescing Timeout in IOC Page 1
61498c2ecf20Sopenharmony_ci	 */
61508c2ecf20Sopenharmony_ci	header.PageVersion = 0;
61518c2ecf20Sopenharmony_ci	header.PageLength = 0;
61528c2ecf20Sopenharmony_ci	header.PageNumber = 1;
61538c2ecf20Sopenharmony_ci	header.PageType = MPI_CONFIG_PAGETYPE_IOC;
61548c2ecf20Sopenharmony_ci	cfg.cfghdr.hdr = &header;
61558c2ecf20Sopenharmony_ci	cfg.physAddr = -1;
61568c2ecf20Sopenharmony_ci	cfg.pageAddr = 0;
61578c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
61588c2ecf20Sopenharmony_ci	cfg.dir = 0;
61598c2ecf20Sopenharmony_ci	cfg.timeout = 0;
61608c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0)
61618c2ecf20Sopenharmony_ci		return;
61628c2ecf20Sopenharmony_ci
61638c2ecf20Sopenharmony_ci	if (header.PageLength == 0)
61648c2ecf20Sopenharmony_ci		return;
61658c2ecf20Sopenharmony_ci
61668c2ecf20Sopenharmony_ci	/* Read Header good, alloc memory
61678c2ecf20Sopenharmony_ci	 */
61688c2ecf20Sopenharmony_ci	iocpage1sz = header.PageLength * 4;
61698c2ecf20Sopenharmony_ci	pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
61708c2ecf20Sopenharmony_ci	if (!pIoc1)
61718c2ecf20Sopenharmony_ci		return;
61728c2ecf20Sopenharmony_ci
61738c2ecf20Sopenharmony_ci	/* Read the Page and check coalescing timeout
61748c2ecf20Sopenharmony_ci	 */
61758c2ecf20Sopenharmony_ci	cfg.physAddr = ioc1_dma;
61768c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
61778c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) == 0) {
61788c2ecf20Sopenharmony_ci
61798c2ecf20Sopenharmony_ci		tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
61808c2ecf20Sopenharmony_ci		if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
61818c2ecf20Sopenharmony_ci			tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
61828c2ecf20Sopenharmony_ci
61838c2ecf20Sopenharmony_ci			dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
61848c2ecf20Sopenharmony_ci					ioc->name, tmp));
61858c2ecf20Sopenharmony_ci
61868c2ecf20Sopenharmony_ci			if (tmp > MPT_COALESCING_TIMEOUT) {
61878c2ecf20Sopenharmony_ci				pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
61888c2ecf20Sopenharmony_ci
61898c2ecf20Sopenharmony_ci				/* Write NVRAM and current
61908c2ecf20Sopenharmony_ci				 */
61918c2ecf20Sopenharmony_ci				cfg.dir = 1;
61928c2ecf20Sopenharmony_ci				cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
61938c2ecf20Sopenharmony_ci				if (mpt_config(ioc, &cfg) == 0) {
61948c2ecf20Sopenharmony_ci					dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
61958c2ecf20Sopenharmony_ci							ioc->name, MPT_COALESCING_TIMEOUT));
61968c2ecf20Sopenharmony_ci
61978c2ecf20Sopenharmony_ci					cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
61988c2ecf20Sopenharmony_ci					if (mpt_config(ioc, &cfg) == 0) {
61998c2ecf20Sopenharmony_ci						dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
62008c2ecf20Sopenharmony_ci								"Reset NVRAM Coalescing Timeout to = %d\n",
62018c2ecf20Sopenharmony_ci								ioc->name, MPT_COALESCING_TIMEOUT));
62028c2ecf20Sopenharmony_ci					} else {
62038c2ecf20Sopenharmony_ci						dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
62048c2ecf20Sopenharmony_ci								"Reset NVRAM Coalescing Timeout Failed\n",
62058c2ecf20Sopenharmony_ci								ioc->name));
62068c2ecf20Sopenharmony_ci					}
62078c2ecf20Sopenharmony_ci
62088c2ecf20Sopenharmony_ci				} else {
62098c2ecf20Sopenharmony_ci					dprintk(ioc, printk(MYIOC_s_WARN_FMT
62108c2ecf20Sopenharmony_ci						"Reset of Current Coalescing Timeout Failed!\n",
62118c2ecf20Sopenharmony_ci						ioc->name));
62128c2ecf20Sopenharmony_ci				}
62138c2ecf20Sopenharmony_ci			}
62148c2ecf20Sopenharmony_ci
62158c2ecf20Sopenharmony_ci		} else {
62168c2ecf20Sopenharmony_ci			dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
62178c2ecf20Sopenharmony_ci		}
62188c2ecf20Sopenharmony_ci	}
62198c2ecf20Sopenharmony_ci
62208c2ecf20Sopenharmony_ci	pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
62218c2ecf20Sopenharmony_ci
62228c2ecf20Sopenharmony_ci	return;
62238c2ecf20Sopenharmony_ci}
62248c2ecf20Sopenharmony_ci
62258c2ecf20Sopenharmony_cistatic void
62268c2ecf20Sopenharmony_cimpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
62278c2ecf20Sopenharmony_ci{
62288c2ecf20Sopenharmony_ci	CONFIGPARMS		cfg;
62298c2ecf20Sopenharmony_ci	ConfigPageHeader_t	hdr;
62308c2ecf20Sopenharmony_ci	dma_addr_t		buf_dma;
62318c2ecf20Sopenharmony_ci	ManufacturingPage0_t	*pbuf = NULL;
62328c2ecf20Sopenharmony_ci
62338c2ecf20Sopenharmony_ci	memset(&cfg, 0 , sizeof(CONFIGPARMS));
62348c2ecf20Sopenharmony_ci	memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
62358c2ecf20Sopenharmony_ci
62368c2ecf20Sopenharmony_ci	hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
62378c2ecf20Sopenharmony_ci	cfg.cfghdr.hdr = &hdr;
62388c2ecf20Sopenharmony_ci	cfg.physAddr = -1;
62398c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
62408c2ecf20Sopenharmony_ci	cfg.timeout = 10;
62418c2ecf20Sopenharmony_ci
62428c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0)
62438c2ecf20Sopenharmony_ci		goto out;
62448c2ecf20Sopenharmony_ci
62458c2ecf20Sopenharmony_ci	if (!cfg.cfghdr.hdr->PageLength)
62468c2ecf20Sopenharmony_ci		goto out;
62478c2ecf20Sopenharmony_ci
62488c2ecf20Sopenharmony_ci	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
62498c2ecf20Sopenharmony_ci	pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
62508c2ecf20Sopenharmony_ci	if (!pbuf)
62518c2ecf20Sopenharmony_ci		goto out;
62528c2ecf20Sopenharmony_ci
62538c2ecf20Sopenharmony_ci	cfg.physAddr = buf_dma;
62548c2ecf20Sopenharmony_ci
62558c2ecf20Sopenharmony_ci	if (mpt_config(ioc, &cfg) != 0)
62568c2ecf20Sopenharmony_ci		goto out;
62578c2ecf20Sopenharmony_ci
62588c2ecf20Sopenharmony_ci	memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
62598c2ecf20Sopenharmony_ci	memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
62608c2ecf20Sopenharmony_ci	memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
62618c2ecf20Sopenharmony_ci
62628c2ecf20Sopenharmony_ciout:
62638c2ecf20Sopenharmony_ci
62648c2ecf20Sopenharmony_ci	if (pbuf)
62658c2ecf20Sopenharmony_ci		pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
62668c2ecf20Sopenharmony_ci}
62678c2ecf20Sopenharmony_ci
62688c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
62698c2ecf20Sopenharmony_ci/**
62708c2ecf20Sopenharmony_ci *	SendEventNotification - Send EventNotification (on or off) request to adapter
62718c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
62728c2ecf20Sopenharmony_ci *	@EvSwitch: Event switch flags
62738c2ecf20Sopenharmony_ci *	@sleepFlag: Specifies whether the process can sleep
62748c2ecf20Sopenharmony_ci */
62758c2ecf20Sopenharmony_cistatic int
62768c2ecf20Sopenharmony_ciSendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
62778c2ecf20Sopenharmony_ci{
62788c2ecf20Sopenharmony_ci	EventNotification_t	evn;
62798c2ecf20Sopenharmony_ci	MPIDefaultReply_t	reply_buf;
62808c2ecf20Sopenharmony_ci
62818c2ecf20Sopenharmony_ci	memset(&evn, 0, sizeof(EventNotification_t));
62828c2ecf20Sopenharmony_ci	memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
62838c2ecf20Sopenharmony_ci
62848c2ecf20Sopenharmony_ci	evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
62858c2ecf20Sopenharmony_ci	evn.Switch = EvSwitch;
62868c2ecf20Sopenharmony_ci	evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
62878c2ecf20Sopenharmony_ci
62888c2ecf20Sopenharmony_ci	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
62898c2ecf20Sopenharmony_ci	    "Sending EventNotification (%d) request %p\n",
62908c2ecf20Sopenharmony_ci	    ioc->name, EvSwitch, &evn));
62918c2ecf20Sopenharmony_ci
62928c2ecf20Sopenharmony_ci	return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
62938c2ecf20Sopenharmony_ci	    (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
62948c2ecf20Sopenharmony_ci	    sleepFlag);
62958c2ecf20Sopenharmony_ci}
62968c2ecf20Sopenharmony_ci
62978c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
62988c2ecf20Sopenharmony_ci/**
62998c2ecf20Sopenharmony_ci *	SendEventAck - Send EventAck request to MPT adapter.
63008c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
63018c2ecf20Sopenharmony_ci *	@evnp: Pointer to original EventNotification request
63028c2ecf20Sopenharmony_ci */
63038c2ecf20Sopenharmony_cistatic int
63048c2ecf20Sopenharmony_ciSendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
63058c2ecf20Sopenharmony_ci{
63068c2ecf20Sopenharmony_ci	EventAck_t	*pAck;
63078c2ecf20Sopenharmony_ci
63088c2ecf20Sopenharmony_ci	if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
63098c2ecf20Sopenharmony_ci		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
63108c2ecf20Sopenharmony_ci		    ioc->name, __func__));
63118c2ecf20Sopenharmony_ci		return -1;
63128c2ecf20Sopenharmony_ci	}
63138c2ecf20Sopenharmony_ci
63148c2ecf20Sopenharmony_ci	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
63158c2ecf20Sopenharmony_ci
63168c2ecf20Sopenharmony_ci	pAck->Function     = MPI_FUNCTION_EVENT_ACK;
63178c2ecf20Sopenharmony_ci	pAck->ChainOffset  = 0;
63188c2ecf20Sopenharmony_ci	pAck->Reserved[0]  = pAck->Reserved[1] = 0;
63198c2ecf20Sopenharmony_ci	pAck->MsgFlags     = 0;
63208c2ecf20Sopenharmony_ci	pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
63218c2ecf20Sopenharmony_ci	pAck->Event        = evnp->Event;
63228c2ecf20Sopenharmony_ci	pAck->EventContext = evnp->EventContext;
63238c2ecf20Sopenharmony_ci
63248c2ecf20Sopenharmony_ci	mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
63258c2ecf20Sopenharmony_ci
63268c2ecf20Sopenharmony_ci	return 0;
63278c2ecf20Sopenharmony_ci}
63288c2ecf20Sopenharmony_ci
63298c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
63308c2ecf20Sopenharmony_ci/**
63318c2ecf20Sopenharmony_ci *	mpt_config - Generic function to issue config message
63328c2ecf20Sopenharmony_ci *	@ioc:   Pointer to an adapter structure
63338c2ecf20Sopenharmony_ci *	@pCfg:  Pointer to a configuration structure. Struct contains
63348c2ecf20Sopenharmony_ci *		action, page address, direction, physical address
63358c2ecf20Sopenharmony_ci *		and pointer to a configuration page header
63368c2ecf20Sopenharmony_ci *		Page header is updated.
63378c2ecf20Sopenharmony_ci *
63388c2ecf20Sopenharmony_ci *	Returns 0 for success
63398c2ecf20Sopenharmony_ci *	-EPERM if not allowed due to ISR context
63408c2ecf20Sopenharmony_ci *	-EAGAIN if no msg frames currently available
63418c2ecf20Sopenharmony_ci *	-EFAULT for non-successful reply or no reply (timeout)
63428c2ecf20Sopenharmony_ci */
63438c2ecf20Sopenharmony_ciint
63448c2ecf20Sopenharmony_cimpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
63458c2ecf20Sopenharmony_ci{
63468c2ecf20Sopenharmony_ci	Config_t	*pReq;
63478c2ecf20Sopenharmony_ci	ConfigReply_t	*pReply;
63488c2ecf20Sopenharmony_ci	ConfigExtendedPageHeader_t  *pExtHdr = NULL;
63498c2ecf20Sopenharmony_ci	MPT_FRAME_HDR	*mf;
63508c2ecf20Sopenharmony_ci	int		 ii;
63518c2ecf20Sopenharmony_ci	int		 flagsLength;
63528c2ecf20Sopenharmony_ci	long		 timeout;
63538c2ecf20Sopenharmony_ci	int		 ret;
63548c2ecf20Sopenharmony_ci	u8		 page_type = 0, extend_page;
63558c2ecf20Sopenharmony_ci	unsigned long 	 timeleft;
63568c2ecf20Sopenharmony_ci	unsigned long	 flags;
63578c2ecf20Sopenharmony_ci	int		 in_isr;
63588c2ecf20Sopenharmony_ci	u8		 issue_hard_reset = 0;
63598c2ecf20Sopenharmony_ci	u8		 retry_count = 0;
63608c2ecf20Sopenharmony_ci
63618c2ecf20Sopenharmony_ci	/*	Prevent calling wait_event() (below), if caller happens
63628c2ecf20Sopenharmony_ci	 *	to be in ISR context, because that is fatal!
63638c2ecf20Sopenharmony_ci	 */
63648c2ecf20Sopenharmony_ci	in_isr = in_interrupt();
63658c2ecf20Sopenharmony_ci	if (in_isr) {
63668c2ecf20Sopenharmony_ci		dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
63678c2ecf20Sopenharmony_ci				ioc->name));
63688c2ecf20Sopenharmony_ci		return -EPERM;
63698c2ecf20Sopenharmony_ci    }
63708c2ecf20Sopenharmony_ci
63718c2ecf20Sopenharmony_ci	/* don't send a config page during diag reset */
63728c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
63738c2ecf20Sopenharmony_ci	if (ioc->ioc_reset_in_progress) {
63748c2ecf20Sopenharmony_ci		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
63758c2ecf20Sopenharmony_ci		    "%s: busy with host reset\n", ioc->name, __func__));
63768c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
63778c2ecf20Sopenharmony_ci		return -EBUSY;
63788c2ecf20Sopenharmony_ci	}
63798c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
63808c2ecf20Sopenharmony_ci
63818c2ecf20Sopenharmony_ci	/* don't send if no chance of success */
63828c2ecf20Sopenharmony_ci	if (!ioc->active ||
63838c2ecf20Sopenharmony_ci	    mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
63848c2ecf20Sopenharmony_ci		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
63858c2ecf20Sopenharmony_ci		    "%s: ioc not operational, %d, %xh\n",
63868c2ecf20Sopenharmony_ci		    ioc->name, __func__, ioc->active,
63878c2ecf20Sopenharmony_ci		    mpt_GetIocState(ioc, 0)));
63888c2ecf20Sopenharmony_ci		return -EFAULT;
63898c2ecf20Sopenharmony_ci	}
63908c2ecf20Sopenharmony_ci
63918c2ecf20Sopenharmony_ci retry_config:
63928c2ecf20Sopenharmony_ci	mutex_lock(&ioc->mptbase_cmds.mutex);
63938c2ecf20Sopenharmony_ci	/* init the internal cmd struct */
63948c2ecf20Sopenharmony_ci	memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
63958c2ecf20Sopenharmony_ci	INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
63968c2ecf20Sopenharmony_ci
63978c2ecf20Sopenharmony_ci	/* Get and Populate a free Frame
63988c2ecf20Sopenharmony_ci	 */
63998c2ecf20Sopenharmony_ci	if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
64008c2ecf20Sopenharmony_ci		dcprintk(ioc, printk(MYIOC_s_WARN_FMT
64018c2ecf20Sopenharmony_ci		"mpt_config: no msg frames!\n", ioc->name));
64028c2ecf20Sopenharmony_ci		ret = -EAGAIN;
64038c2ecf20Sopenharmony_ci		goto out;
64048c2ecf20Sopenharmony_ci	}
64058c2ecf20Sopenharmony_ci
64068c2ecf20Sopenharmony_ci	pReq = (Config_t *)mf;
64078c2ecf20Sopenharmony_ci	pReq->Action = pCfg->action;
64088c2ecf20Sopenharmony_ci	pReq->Reserved = 0;
64098c2ecf20Sopenharmony_ci	pReq->ChainOffset = 0;
64108c2ecf20Sopenharmony_ci	pReq->Function = MPI_FUNCTION_CONFIG;
64118c2ecf20Sopenharmony_ci
64128c2ecf20Sopenharmony_ci	/* Assume page type is not extended and clear "reserved" fields. */
64138c2ecf20Sopenharmony_ci	pReq->ExtPageLength = 0;
64148c2ecf20Sopenharmony_ci	pReq->ExtPageType = 0;
64158c2ecf20Sopenharmony_ci	pReq->MsgFlags = 0;
64168c2ecf20Sopenharmony_ci
64178c2ecf20Sopenharmony_ci	for (ii=0; ii < 8; ii++)
64188c2ecf20Sopenharmony_ci		pReq->Reserved2[ii] = 0;
64198c2ecf20Sopenharmony_ci
64208c2ecf20Sopenharmony_ci	pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
64218c2ecf20Sopenharmony_ci	pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
64228c2ecf20Sopenharmony_ci	pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
64238c2ecf20Sopenharmony_ci	pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
64248c2ecf20Sopenharmony_ci
64258c2ecf20Sopenharmony_ci	if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
64268c2ecf20Sopenharmony_ci		pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
64278c2ecf20Sopenharmony_ci		pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
64288c2ecf20Sopenharmony_ci		pReq->ExtPageType = pExtHdr->ExtPageType;
64298c2ecf20Sopenharmony_ci		pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
64308c2ecf20Sopenharmony_ci
64318c2ecf20Sopenharmony_ci		/* Page Length must be treated as a reserved field for the
64328c2ecf20Sopenharmony_ci		 * extended header.
64338c2ecf20Sopenharmony_ci		 */
64348c2ecf20Sopenharmony_ci		pReq->Header.PageLength = 0;
64358c2ecf20Sopenharmony_ci	}
64368c2ecf20Sopenharmony_ci
64378c2ecf20Sopenharmony_ci	pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
64388c2ecf20Sopenharmony_ci
64398c2ecf20Sopenharmony_ci	/* Add a SGE to the config request.
64408c2ecf20Sopenharmony_ci	 */
64418c2ecf20Sopenharmony_ci	if (pCfg->dir)
64428c2ecf20Sopenharmony_ci		flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
64438c2ecf20Sopenharmony_ci	else
64448c2ecf20Sopenharmony_ci		flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
64458c2ecf20Sopenharmony_ci
64468c2ecf20Sopenharmony_ci	if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
64478c2ecf20Sopenharmony_ci	    MPI_CONFIG_PAGETYPE_EXTENDED) {
64488c2ecf20Sopenharmony_ci		flagsLength |= pExtHdr->ExtPageLength * 4;
64498c2ecf20Sopenharmony_ci		page_type = pReq->ExtPageType;
64508c2ecf20Sopenharmony_ci		extend_page = 1;
64518c2ecf20Sopenharmony_ci	} else {
64528c2ecf20Sopenharmony_ci		flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
64538c2ecf20Sopenharmony_ci		page_type = pReq->Header.PageType;
64548c2ecf20Sopenharmony_ci		extend_page = 0;
64558c2ecf20Sopenharmony_ci	}
64568c2ecf20Sopenharmony_ci
64578c2ecf20Sopenharmony_ci	dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
64588c2ecf20Sopenharmony_ci	    "Sending Config request type 0x%x, page 0x%x and action %d\n",
64598c2ecf20Sopenharmony_ci	    ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
64608c2ecf20Sopenharmony_ci
64618c2ecf20Sopenharmony_ci	ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
64628c2ecf20Sopenharmony_ci	timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
64638c2ecf20Sopenharmony_ci	mpt_put_msg_frame(mpt_base_index, ioc, mf);
64648c2ecf20Sopenharmony_ci	timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
64658c2ecf20Sopenharmony_ci		timeout);
64668c2ecf20Sopenharmony_ci	if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
64678c2ecf20Sopenharmony_ci		ret = -ETIME;
64688c2ecf20Sopenharmony_ci		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
64698c2ecf20Sopenharmony_ci		    "Failed Sending Config request type 0x%x, page 0x%x,"
64708c2ecf20Sopenharmony_ci		    " action %d, status %xh, time left %ld\n\n",
64718c2ecf20Sopenharmony_ci			ioc->name, page_type, pReq->Header.PageNumber,
64728c2ecf20Sopenharmony_ci			pReq->Action, ioc->mptbase_cmds.status, timeleft));
64738c2ecf20Sopenharmony_ci		if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
64748c2ecf20Sopenharmony_ci			goto out;
64758c2ecf20Sopenharmony_ci		if (!timeleft) {
64768c2ecf20Sopenharmony_ci			spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
64778c2ecf20Sopenharmony_ci			if (ioc->ioc_reset_in_progress) {
64788c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&ioc->taskmgmt_lock,
64798c2ecf20Sopenharmony_ci					flags);
64808c2ecf20Sopenharmony_ci				printk(MYIOC_s_INFO_FMT "%s: host reset in"
64818c2ecf20Sopenharmony_ci					" progress mpt_config timed out.!!\n",
64828c2ecf20Sopenharmony_ci					__func__, ioc->name);
64838c2ecf20Sopenharmony_ci				mutex_unlock(&ioc->mptbase_cmds.mutex);
64848c2ecf20Sopenharmony_ci				return -EFAULT;
64858c2ecf20Sopenharmony_ci			}
64868c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
64878c2ecf20Sopenharmony_ci			issue_hard_reset = 1;
64888c2ecf20Sopenharmony_ci		}
64898c2ecf20Sopenharmony_ci		goto out;
64908c2ecf20Sopenharmony_ci	}
64918c2ecf20Sopenharmony_ci
64928c2ecf20Sopenharmony_ci	if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
64938c2ecf20Sopenharmony_ci		ret = -1;
64948c2ecf20Sopenharmony_ci		goto out;
64958c2ecf20Sopenharmony_ci	}
64968c2ecf20Sopenharmony_ci	pReply = (ConfigReply_t	*)ioc->mptbase_cmds.reply;
64978c2ecf20Sopenharmony_ci	ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
64988c2ecf20Sopenharmony_ci	if (ret == MPI_IOCSTATUS_SUCCESS) {
64998c2ecf20Sopenharmony_ci		if (extend_page) {
65008c2ecf20Sopenharmony_ci			pCfg->cfghdr.ehdr->ExtPageLength =
65018c2ecf20Sopenharmony_ci			    le16_to_cpu(pReply->ExtPageLength);
65028c2ecf20Sopenharmony_ci			pCfg->cfghdr.ehdr->ExtPageType =
65038c2ecf20Sopenharmony_ci			    pReply->ExtPageType;
65048c2ecf20Sopenharmony_ci		}
65058c2ecf20Sopenharmony_ci		pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
65068c2ecf20Sopenharmony_ci		pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
65078c2ecf20Sopenharmony_ci		pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
65088c2ecf20Sopenharmony_ci		pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
65098c2ecf20Sopenharmony_ci
65108c2ecf20Sopenharmony_ci	}
65118c2ecf20Sopenharmony_ci
65128c2ecf20Sopenharmony_ci	if (retry_count)
65138c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT "Retry completed "
65148c2ecf20Sopenharmony_ci		    "ret=0x%x timeleft=%ld\n",
65158c2ecf20Sopenharmony_ci		    ioc->name, ret, timeleft);
65168c2ecf20Sopenharmony_ci
65178c2ecf20Sopenharmony_ci	dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
65188c2ecf20Sopenharmony_ci	     ret, le32_to_cpu(pReply->IOCLogInfo)));
65198c2ecf20Sopenharmony_ci
65208c2ecf20Sopenharmony_ciout:
65218c2ecf20Sopenharmony_ci
65228c2ecf20Sopenharmony_ci	CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
65238c2ecf20Sopenharmony_ci	mutex_unlock(&ioc->mptbase_cmds.mutex);
65248c2ecf20Sopenharmony_ci	if (issue_hard_reset) {
65258c2ecf20Sopenharmony_ci		issue_hard_reset = 0;
65268c2ecf20Sopenharmony_ci		printk(MYIOC_s_WARN_FMT
65278c2ecf20Sopenharmony_ci		       "Issuing Reset from %s!!, doorbell=0x%08x\n",
65288c2ecf20Sopenharmony_ci		       ioc->name, __func__, mpt_GetIocState(ioc, 0));
65298c2ecf20Sopenharmony_ci		if (retry_count == 0) {
65308c2ecf20Sopenharmony_ci			if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)
65318c2ecf20Sopenharmony_ci				retry_count++;
65328c2ecf20Sopenharmony_ci		} else
65338c2ecf20Sopenharmony_ci			mpt_HardResetHandler(ioc, CAN_SLEEP);
65348c2ecf20Sopenharmony_ci
65358c2ecf20Sopenharmony_ci		mpt_free_msg_frame(ioc, mf);
65368c2ecf20Sopenharmony_ci		/* attempt one retry for a timed out command */
65378c2ecf20Sopenharmony_ci		if (retry_count < 2) {
65388c2ecf20Sopenharmony_ci			printk(MYIOC_s_INFO_FMT
65398c2ecf20Sopenharmony_ci			    "Attempting Retry Config request"
65408c2ecf20Sopenharmony_ci			    " type 0x%x, page 0x%x,"
65418c2ecf20Sopenharmony_ci			    " action %d\n", ioc->name, page_type,
65428c2ecf20Sopenharmony_ci			    pCfg->cfghdr.hdr->PageNumber, pCfg->action);
65438c2ecf20Sopenharmony_ci			retry_count++;
65448c2ecf20Sopenharmony_ci			goto retry_config;
65458c2ecf20Sopenharmony_ci		}
65468c2ecf20Sopenharmony_ci	}
65478c2ecf20Sopenharmony_ci	return ret;
65488c2ecf20Sopenharmony_ci
65498c2ecf20Sopenharmony_ci}
65508c2ecf20Sopenharmony_ci
65518c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
65528c2ecf20Sopenharmony_ci/**
65538c2ecf20Sopenharmony_ci *	mpt_ioc_reset - Base cleanup for hard reset
65548c2ecf20Sopenharmony_ci *	@ioc: Pointer to the adapter structure
65558c2ecf20Sopenharmony_ci *	@reset_phase: Indicates pre- or post-reset functionality
65568c2ecf20Sopenharmony_ci *
65578c2ecf20Sopenharmony_ci *	Remark: Frees resources with internally generated commands.
65588c2ecf20Sopenharmony_ci */
65598c2ecf20Sopenharmony_cistatic int
65608c2ecf20Sopenharmony_cimpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
65618c2ecf20Sopenharmony_ci{
65628c2ecf20Sopenharmony_ci	switch (reset_phase) {
65638c2ecf20Sopenharmony_ci	case MPT_IOC_SETUP_RESET:
65648c2ecf20Sopenharmony_ci		ioc->taskmgmt_quiesce_io = 1;
65658c2ecf20Sopenharmony_ci		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
65668c2ecf20Sopenharmony_ci		    "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
65678c2ecf20Sopenharmony_ci		break;
65688c2ecf20Sopenharmony_ci	case MPT_IOC_PRE_RESET:
65698c2ecf20Sopenharmony_ci		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
65708c2ecf20Sopenharmony_ci		    "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
65718c2ecf20Sopenharmony_ci		break;
65728c2ecf20Sopenharmony_ci	case MPT_IOC_POST_RESET:
65738c2ecf20Sopenharmony_ci		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
65748c2ecf20Sopenharmony_ci		    "%s: MPT_IOC_POST_RESET\n",  ioc->name, __func__));
65758c2ecf20Sopenharmony_ci/* wake up mptbase_cmds */
65768c2ecf20Sopenharmony_ci		if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
65778c2ecf20Sopenharmony_ci			ioc->mptbase_cmds.status |=
65788c2ecf20Sopenharmony_ci			    MPT_MGMT_STATUS_DID_IOCRESET;
65798c2ecf20Sopenharmony_ci			complete(&ioc->mptbase_cmds.done);
65808c2ecf20Sopenharmony_ci		}
65818c2ecf20Sopenharmony_ci/* wake up taskmgmt_cmds */
65828c2ecf20Sopenharmony_ci		if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
65838c2ecf20Sopenharmony_ci			ioc->taskmgmt_cmds.status |=
65848c2ecf20Sopenharmony_ci				MPT_MGMT_STATUS_DID_IOCRESET;
65858c2ecf20Sopenharmony_ci			complete(&ioc->taskmgmt_cmds.done);
65868c2ecf20Sopenharmony_ci		}
65878c2ecf20Sopenharmony_ci		break;
65888c2ecf20Sopenharmony_ci	default:
65898c2ecf20Sopenharmony_ci		break;
65908c2ecf20Sopenharmony_ci	}
65918c2ecf20Sopenharmony_ci
65928c2ecf20Sopenharmony_ci	return 1;		/* currently means nothing really */
65938c2ecf20Sopenharmony_ci}
65948c2ecf20Sopenharmony_ci
65958c2ecf20Sopenharmony_ci
65968c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS		/* { */
65978c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
65988c2ecf20Sopenharmony_ci/*
65998c2ecf20Sopenharmony_ci *	procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
66008c2ecf20Sopenharmony_ci */
66018c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
66028c2ecf20Sopenharmony_ci/**
66038c2ecf20Sopenharmony_ci *	procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
66048c2ecf20Sopenharmony_ci *
66058c2ecf20Sopenharmony_ci *	Returns 0 for success, non-zero for failure.
66068c2ecf20Sopenharmony_ci */
66078c2ecf20Sopenharmony_cistatic int
66088c2ecf20Sopenharmony_ciprocmpt_create(void)
66098c2ecf20Sopenharmony_ci{
66108c2ecf20Sopenharmony_ci	mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
66118c2ecf20Sopenharmony_ci	if (mpt_proc_root_dir == NULL)
66128c2ecf20Sopenharmony_ci		return -ENOTDIR;
66138c2ecf20Sopenharmony_ci
66148c2ecf20Sopenharmony_ci	proc_create_single("summary", S_IRUGO, mpt_proc_root_dir,
66158c2ecf20Sopenharmony_ci			mpt_summary_proc_show);
66168c2ecf20Sopenharmony_ci	proc_create_single("version", S_IRUGO, mpt_proc_root_dir,
66178c2ecf20Sopenharmony_ci			mpt_version_proc_show);
66188c2ecf20Sopenharmony_ci	return 0;
66198c2ecf20Sopenharmony_ci}
66208c2ecf20Sopenharmony_ci
66218c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
66228c2ecf20Sopenharmony_ci/**
66238c2ecf20Sopenharmony_ci *	procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
66248c2ecf20Sopenharmony_ci *
66258c2ecf20Sopenharmony_ci *	Returns 0 for success, non-zero for failure.
66268c2ecf20Sopenharmony_ci */
66278c2ecf20Sopenharmony_cistatic void
66288c2ecf20Sopenharmony_ciprocmpt_destroy(void)
66298c2ecf20Sopenharmony_ci{
66308c2ecf20Sopenharmony_ci	remove_proc_entry("version", mpt_proc_root_dir);
66318c2ecf20Sopenharmony_ci	remove_proc_entry("summary", mpt_proc_root_dir);
66328c2ecf20Sopenharmony_ci	remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
66338c2ecf20Sopenharmony_ci}
66348c2ecf20Sopenharmony_ci
66358c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
66368c2ecf20Sopenharmony_ci/*
66378c2ecf20Sopenharmony_ci *	Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
66388c2ecf20Sopenharmony_ci */
66398c2ecf20Sopenharmony_cistatic void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan);
66408c2ecf20Sopenharmony_ci
66418c2ecf20Sopenharmony_cistatic int mpt_summary_proc_show(struct seq_file *m, void *v)
66428c2ecf20Sopenharmony_ci{
66438c2ecf20Sopenharmony_ci	MPT_ADAPTER *ioc = m->private;
66448c2ecf20Sopenharmony_ci
66458c2ecf20Sopenharmony_ci	if (ioc) {
66468c2ecf20Sopenharmony_ci		seq_mpt_print_ioc_summary(ioc, m, 1);
66478c2ecf20Sopenharmony_ci	} else {
66488c2ecf20Sopenharmony_ci		list_for_each_entry(ioc, &ioc_list, list) {
66498c2ecf20Sopenharmony_ci			seq_mpt_print_ioc_summary(ioc, m, 1);
66508c2ecf20Sopenharmony_ci		}
66518c2ecf20Sopenharmony_ci	}
66528c2ecf20Sopenharmony_ci
66538c2ecf20Sopenharmony_ci	return 0;
66548c2ecf20Sopenharmony_ci}
66558c2ecf20Sopenharmony_ci
66568c2ecf20Sopenharmony_cistatic int mpt_version_proc_show(struct seq_file *m, void *v)
66578c2ecf20Sopenharmony_ci{
66588c2ecf20Sopenharmony_ci	u8	 cb_idx;
66598c2ecf20Sopenharmony_ci	int	 scsi, fc, sas, lan, ctl, targ, dmp;
66608c2ecf20Sopenharmony_ci	char	*drvname;
66618c2ecf20Sopenharmony_ci
66628c2ecf20Sopenharmony_ci	seq_printf(m, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
66638c2ecf20Sopenharmony_ci	seq_printf(m, "  Fusion MPT base driver\n");
66648c2ecf20Sopenharmony_ci
66658c2ecf20Sopenharmony_ci	scsi = fc = sas = lan = ctl = targ = dmp = 0;
66668c2ecf20Sopenharmony_ci	for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
66678c2ecf20Sopenharmony_ci		drvname = NULL;
66688c2ecf20Sopenharmony_ci		if (MptCallbacks[cb_idx]) {
66698c2ecf20Sopenharmony_ci			switch (MptDriverClass[cb_idx]) {
66708c2ecf20Sopenharmony_ci			case MPTSPI_DRIVER:
66718c2ecf20Sopenharmony_ci				if (!scsi++) drvname = "SPI host";
66728c2ecf20Sopenharmony_ci				break;
66738c2ecf20Sopenharmony_ci			case MPTFC_DRIVER:
66748c2ecf20Sopenharmony_ci				if (!fc++) drvname = "FC host";
66758c2ecf20Sopenharmony_ci				break;
66768c2ecf20Sopenharmony_ci			case MPTSAS_DRIVER:
66778c2ecf20Sopenharmony_ci				if (!sas++) drvname = "SAS host";
66788c2ecf20Sopenharmony_ci				break;
66798c2ecf20Sopenharmony_ci			case MPTLAN_DRIVER:
66808c2ecf20Sopenharmony_ci				if (!lan++) drvname = "LAN";
66818c2ecf20Sopenharmony_ci				break;
66828c2ecf20Sopenharmony_ci			case MPTSTM_DRIVER:
66838c2ecf20Sopenharmony_ci				if (!targ++) drvname = "SCSI target";
66848c2ecf20Sopenharmony_ci				break;
66858c2ecf20Sopenharmony_ci			case MPTCTL_DRIVER:
66868c2ecf20Sopenharmony_ci				if (!ctl++) drvname = "ioctl";
66878c2ecf20Sopenharmony_ci				break;
66888c2ecf20Sopenharmony_ci			}
66898c2ecf20Sopenharmony_ci
66908c2ecf20Sopenharmony_ci			if (drvname)
66918c2ecf20Sopenharmony_ci				seq_printf(m, "  Fusion MPT %s driver\n", drvname);
66928c2ecf20Sopenharmony_ci		}
66938c2ecf20Sopenharmony_ci	}
66948c2ecf20Sopenharmony_ci
66958c2ecf20Sopenharmony_ci	return 0;
66968c2ecf20Sopenharmony_ci}
66978c2ecf20Sopenharmony_ci
66988c2ecf20Sopenharmony_cistatic int mpt_iocinfo_proc_show(struct seq_file *m, void *v)
66998c2ecf20Sopenharmony_ci{
67008c2ecf20Sopenharmony_ci	MPT_ADAPTER	*ioc = m->private;
67018c2ecf20Sopenharmony_ci	char		 expVer[32];
67028c2ecf20Sopenharmony_ci	int		 sz;
67038c2ecf20Sopenharmony_ci	int		 p;
67048c2ecf20Sopenharmony_ci
67058c2ecf20Sopenharmony_ci	mpt_get_fw_exp_ver(expVer, ioc);
67068c2ecf20Sopenharmony_ci
67078c2ecf20Sopenharmony_ci	seq_printf(m, "%s:", ioc->name);
67088c2ecf20Sopenharmony_ci	if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
67098c2ecf20Sopenharmony_ci		seq_printf(m, "  (f/w download boot flag set)");
67108c2ecf20Sopenharmony_ci//	if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
67118c2ecf20Sopenharmony_ci//		seq_printf(m, "  CONFIG_CHECKSUM_FAIL!");
67128c2ecf20Sopenharmony_ci
67138c2ecf20Sopenharmony_ci	seq_printf(m, "\n  ProductID = 0x%04x (%s)\n",
67148c2ecf20Sopenharmony_ci			ioc->facts.ProductID,
67158c2ecf20Sopenharmony_ci			ioc->prod_name);
67168c2ecf20Sopenharmony_ci	seq_printf(m, "  FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
67178c2ecf20Sopenharmony_ci	if (ioc->facts.FWImageSize)
67188c2ecf20Sopenharmony_ci		seq_printf(m, " (fw_size=%d)", ioc->facts.FWImageSize);
67198c2ecf20Sopenharmony_ci	seq_printf(m, "\n  MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
67208c2ecf20Sopenharmony_ci	seq_printf(m, "  FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
67218c2ecf20Sopenharmony_ci	seq_printf(m, "  EventState = 0x%02x\n", ioc->facts.EventState);
67228c2ecf20Sopenharmony_ci
67238c2ecf20Sopenharmony_ci	seq_printf(m, "  CurrentHostMfaHighAddr = 0x%08x\n",
67248c2ecf20Sopenharmony_ci			ioc->facts.CurrentHostMfaHighAddr);
67258c2ecf20Sopenharmony_ci	seq_printf(m, "  CurrentSenseBufferHighAddr = 0x%08x\n",
67268c2ecf20Sopenharmony_ci			ioc->facts.CurrentSenseBufferHighAddr);
67278c2ecf20Sopenharmony_ci
67288c2ecf20Sopenharmony_ci	seq_printf(m, "  MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
67298c2ecf20Sopenharmony_ci	seq_printf(m, "  MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
67308c2ecf20Sopenharmony_ci
67318c2ecf20Sopenharmony_ci	seq_printf(m, "  RequestFrames @ 0x%p (Dma @ 0x%p)\n",
67328c2ecf20Sopenharmony_ci					(void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
67338c2ecf20Sopenharmony_ci	/*
67348c2ecf20Sopenharmony_ci	 *  Rounding UP to nearest 4-kB boundary here...
67358c2ecf20Sopenharmony_ci	 */
67368c2ecf20Sopenharmony_ci	sz = (ioc->req_sz * ioc->req_depth) + 128;
67378c2ecf20Sopenharmony_ci	sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
67388c2ecf20Sopenharmony_ci	seq_printf(m, "    {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
67398c2ecf20Sopenharmony_ci					ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
67408c2ecf20Sopenharmony_ci	seq_printf(m, "    {MaxReqSz=%d}   {MaxReqDepth=%d}\n",
67418c2ecf20Sopenharmony_ci					4*ioc->facts.RequestFrameSize,
67428c2ecf20Sopenharmony_ci					ioc->facts.GlobalCredits);
67438c2ecf20Sopenharmony_ci
67448c2ecf20Sopenharmony_ci	seq_printf(m, "  Frames   @ 0x%p (Dma @ 0x%p)\n",
67458c2ecf20Sopenharmony_ci					(void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
67468c2ecf20Sopenharmony_ci	sz = (ioc->reply_sz * ioc->reply_depth) + 128;
67478c2ecf20Sopenharmony_ci	seq_printf(m, "    {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
67488c2ecf20Sopenharmony_ci					ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
67498c2ecf20Sopenharmony_ci	seq_printf(m, "    {MaxRepSz=%d}   {MaxRepDepth=%d}\n",
67508c2ecf20Sopenharmony_ci					ioc->facts.CurReplyFrameSize,
67518c2ecf20Sopenharmony_ci					ioc->facts.ReplyQueueDepth);
67528c2ecf20Sopenharmony_ci
67538c2ecf20Sopenharmony_ci	seq_printf(m, "  MaxDevices = %d\n",
67548c2ecf20Sopenharmony_ci			(ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
67558c2ecf20Sopenharmony_ci	seq_printf(m, "  MaxBuses = %d\n", ioc->facts.MaxBuses);
67568c2ecf20Sopenharmony_ci
67578c2ecf20Sopenharmony_ci	/* per-port info */
67588c2ecf20Sopenharmony_ci	for (p=0; p < ioc->facts.NumberOfPorts; p++) {
67598c2ecf20Sopenharmony_ci		seq_printf(m, "  PortNumber = %d (of %d)\n",
67608c2ecf20Sopenharmony_ci				p+1,
67618c2ecf20Sopenharmony_ci				ioc->facts.NumberOfPorts);
67628c2ecf20Sopenharmony_ci		if (ioc->bus_type == FC) {
67638c2ecf20Sopenharmony_ci			if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
67648c2ecf20Sopenharmony_ci				u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
67658c2ecf20Sopenharmony_ci				seq_printf(m, "    LanAddr = %pMR\n", a);
67668c2ecf20Sopenharmony_ci			}
67678c2ecf20Sopenharmony_ci			seq_printf(m, "    WWN = %08X%08X:%08X%08X\n",
67688c2ecf20Sopenharmony_ci					ioc->fc_port_page0[p].WWNN.High,
67698c2ecf20Sopenharmony_ci					ioc->fc_port_page0[p].WWNN.Low,
67708c2ecf20Sopenharmony_ci					ioc->fc_port_page0[p].WWPN.High,
67718c2ecf20Sopenharmony_ci					ioc->fc_port_page0[p].WWPN.Low);
67728c2ecf20Sopenharmony_ci		}
67738c2ecf20Sopenharmony_ci	}
67748c2ecf20Sopenharmony_ci
67758c2ecf20Sopenharmony_ci	return 0;
67768c2ecf20Sopenharmony_ci}
67778c2ecf20Sopenharmony_ci#endif		/* CONFIG_PROC_FS } */
67788c2ecf20Sopenharmony_ci
67798c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
67808c2ecf20Sopenharmony_cistatic void
67818c2ecf20Sopenharmony_cimpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
67828c2ecf20Sopenharmony_ci{
67838c2ecf20Sopenharmony_ci	buf[0] ='\0';
67848c2ecf20Sopenharmony_ci	if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
67858c2ecf20Sopenharmony_ci		sprintf(buf, " (Exp %02d%02d)",
67868c2ecf20Sopenharmony_ci			(ioc->facts.FWVersion.Word >> 16) & 0x00FF,	/* Month */
67878c2ecf20Sopenharmony_ci			(ioc->facts.FWVersion.Word >> 8) & 0x1F);	/* Day */
67888c2ecf20Sopenharmony_ci
67898c2ecf20Sopenharmony_ci		/* insider hack! */
67908c2ecf20Sopenharmony_ci		if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
67918c2ecf20Sopenharmony_ci			strcat(buf, " [MDBG]");
67928c2ecf20Sopenharmony_ci	}
67938c2ecf20Sopenharmony_ci}
67948c2ecf20Sopenharmony_ci
67958c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
67968c2ecf20Sopenharmony_ci/**
67978c2ecf20Sopenharmony_ci *	mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
67988c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
67998c2ecf20Sopenharmony_ci *	@buffer: Pointer to buffer where IOC summary info should be written
68008c2ecf20Sopenharmony_ci *	@size: Pointer to number of bytes we wrote (set by this routine)
68018c2ecf20Sopenharmony_ci *	@len: Offset at which to start writing in buffer
68028c2ecf20Sopenharmony_ci *	@showlan: Display LAN stuff?
68038c2ecf20Sopenharmony_ci *
68048c2ecf20Sopenharmony_ci *	This routine writes (english readable) ASCII text, which represents
68058c2ecf20Sopenharmony_ci *	a summary of IOC information, to a buffer.
68068c2ecf20Sopenharmony_ci */
68078c2ecf20Sopenharmony_civoid
68088c2ecf20Sopenharmony_cimpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
68098c2ecf20Sopenharmony_ci{
68108c2ecf20Sopenharmony_ci	char expVer[32];
68118c2ecf20Sopenharmony_ci	int y;
68128c2ecf20Sopenharmony_ci
68138c2ecf20Sopenharmony_ci	mpt_get_fw_exp_ver(expVer, ioc);
68148c2ecf20Sopenharmony_ci
68158c2ecf20Sopenharmony_ci	/*
68168c2ecf20Sopenharmony_ci	 *  Shorter summary of attached ioc's...
68178c2ecf20Sopenharmony_ci	 */
68188c2ecf20Sopenharmony_ci	y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
68198c2ecf20Sopenharmony_ci			ioc->name,
68208c2ecf20Sopenharmony_ci			ioc->prod_name,
68218c2ecf20Sopenharmony_ci			MPT_FW_REV_MAGIC_ID_STRING,	/* "FwRev=" or somesuch */
68228c2ecf20Sopenharmony_ci			ioc->facts.FWVersion.Word,
68238c2ecf20Sopenharmony_ci			expVer,
68248c2ecf20Sopenharmony_ci			ioc->facts.NumberOfPorts,
68258c2ecf20Sopenharmony_ci			ioc->req_depth);
68268c2ecf20Sopenharmony_ci
68278c2ecf20Sopenharmony_ci	if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
68288c2ecf20Sopenharmony_ci		u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
68298c2ecf20Sopenharmony_ci		y += sprintf(buffer+len+y, ", LanAddr=%pMR", a);
68308c2ecf20Sopenharmony_ci	}
68318c2ecf20Sopenharmony_ci
68328c2ecf20Sopenharmony_ci	y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
68338c2ecf20Sopenharmony_ci
68348c2ecf20Sopenharmony_ci	if (!ioc->active)
68358c2ecf20Sopenharmony_ci		y += sprintf(buffer+len+y, " (disabled)");
68368c2ecf20Sopenharmony_ci
68378c2ecf20Sopenharmony_ci	y += sprintf(buffer+len+y, "\n");
68388c2ecf20Sopenharmony_ci
68398c2ecf20Sopenharmony_ci	*size = y;
68408c2ecf20Sopenharmony_ci}
68418c2ecf20Sopenharmony_ci
68428c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
68438c2ecf20Sopenharmony_cistatic void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan)
68448c2ecf20Sopenharmony_ci{
68458c2ecf20Sopenharmony_ci	char expVer[32];
68468c2ecf20Sopenharmony_ci
68478c2ecf20Sopenharmony_ci	mpt_get_fw_exp_ver(expVer, ioc);
68488c2ecf20Sopenharmony_ci
68498c2ecf20Sopenharmony_ci	/*
68508c2ecf20Sopenharmony_ci	 *  Shorter summary of attached ioc's...
68518c2ecf20Sopenharmony_ci	 */
68528c2ecf20Sopenharmony_ci	seq_printf(m, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
68538c2ecf20Sopenharmony_ci			ioc->name,
68548c2ecf20Sopenharmony_ci			ioc->prod_name,
68558c2ecf20Sopenharmony_ci			MPT_FW_REV_MAGIC_ID_STRING,	/* "FwRev=" or somesuch */
68568c2ecf20Sopenharmony_ci			ioc->facts.FWVersion.Word,
68578c2ecf20Sopenharmony_ci			expVer,
68588c2ecf20Sopenharmony_ci			ioc->facts.NumberOfPorts,
68598c2ecf20Sopenharmony_ci			ioc->req_depth);
68608c2ecf20Sopenharmony_ci
68618c2ecf20Sopenharmony_ci	if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
68628c2ecf20Sopenharmony_ci		u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
68638c2ecf20Sopenharmony_ci		seq_printf(m, ", LanAddr=%pMR", a);
68648c2ecf20Sopenharmony_ci	}
68658c2ecf20Sopenharmony_ci
68668c2ecf20Sopenharmony_ci	seq_printf(m, ", IRQ=%d", ioc->pci_irq);
68678c2ecf20Sopenharmony_ci
68688c2ecf20Sopenharmony_ci	if (!ioc->active)
68698c2ecf20Sopenharmony_ci		seq_printf(m, " (disabled)");
68708c2ecf20Sopenharmony_ci
68718c2ecf20Sopenharmony_ci	seq_putc(m, '\n');
68728c2ecf20Sopenharmony_ci}
68738c2ecf20Sopenharmony_ci#endif
68748c2ecf20Sopenharmony_ci
68758c2ecf20Sopenharmony_ci/**
68768c2ecf20Sopenharmony_ci *	mpt_set_taskmgmt_in_progress_flag - set flags associated with task management
68778c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
68788c2ecf20Sopenharmony_ci *
68798c2ecf20Sopenharmony_ci *	Returns 0 for SUCCESS or -1 if FAILED.
68808c2ecf20Sopenharmony_ci *
68818c2ecf20Sopenharmony_ci *	If -1 is return, then it was not possible to set the flags
68828c2ecf20Sopenharmony_ci **/
68838c2ecf20Sopenharmony_ciint
68848c2ecf20Sopenharmony_cimpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
68858c2ecf20Sopenharmony_ci{
68868c2ecf20Sopenharmony_ci	unsigned long	 flags;
68878c2ecf20Sopenharmony_ci	int		 retval;
68888c2ecf20Sopenharmony_ci
68898c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
68908c2ecf20Sopenharmony_ci	if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
68918c2ecf20Sopenharmony_ci	    (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
68928c2ecf20Sopenharmony_ci		retval = -1;
68938c2ecf20Sopenharmony_ci		goto out;
68948c2ecf20Sopenharmony_ci	}
68958c2ecf20Sopenharmony_ci	retval = 0;
68968c2ecf20Sopenharmony_ci	ioc->taskmgmt_in_progress = 1;
68978c2ecf20Sopenharmony_ci	ioc->taskmgmt_quiesce_io = 1;
68988c2ecf20Sopenharmony_ci	if (ioc->alt_ioc) {
68998c2ecf20Sopenharmony_ci		ioc->alt_ioc->taskmgmt_in_progress = 1;
69008c2ecf20Sopenharmony_ci		ioc->alt_ioc->taskmgmt_quiesce_io = 1;
69018c2ecf20Sopenharmony_ci	}
69028c2ecf20Sopenharmony_ci out:
69038c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
69048c2ecf20Sopenharmony_ci	return retval;
69058c2ecf20Sopenharmony_ci}
69068c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
69078c2ecf20Sopenharmony_ci
69088c2ecf20Sopenharmony_ci/**
69098c2ecf20Sopenharmony_ci *	mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management
69108c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
69118c2ecf20Sopenharmony_ci *
69128c2ecf20Sopenharmony_ci **/
69138c2ecf20Sopenharmony_civoid
69148c2ecf20Sopenharmony_cimpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
69158c2ecf20Sopenharmony_ci{
69168c2ecf20Sopenharmony_ci	unsigned long	 flags;
69178c2ecf20Sopenharmony_ci
69188c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
69198c2ecf20Sopenharmony_ci	ioc->taskmgmt_in_progress = 0;
69208c2ecf20Sopenharmony_ci	ioc->taskmgmt_quiesce_io = 0;
69218c2ecf20Sopenharmony_ci	if (ioc->alt_ioc) {
69228c2ecf20Sopenharmony_ci		ioc->alt_ioc->taskmgmt_in_progress = 0;
69238c2ecf20Sopenharmony_ci		ioc->alt_ioc->taskmgmt_quiesce_io = 0;
69248c2ecf20Sopenharmony_ci	}
69258c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
69268c2ecf20Sopenharmony_ci}
69278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
69288c2ecf20Sopenharmony_ci
69298c2ecf20Sopenharmony_ci
69308c2ecf20Sopenharmony_ci/**
69318c2ecf20Sopenharmony_ci *	mpt_halt_firmware - Halts the firmware if it is operational and panic
69328c2ecf20Sopenharmony_ci *	the kernel
69338c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
69348c2ecf20Sopenharmony_ci *
69358c2ecf20Sopenharmony_ci **/
69368c2ecf20Sopenharmony_civoid
69378c2ecf20Sopenharmony_cimpt_halt_firmware(MPT_ADAPTER *ioc)
69388c2ecf20Sopenharmony_ci{
69398c2ecf20Sopenharmony_ci	u32	 ioc_raw_state;
69408c2ecf20Sopenharmony_ci
69418c2ecf20Sopenharmony_ci	ioc_raw_state = mpt_GetIocState(ioc, 0);
69428c2ecf20Sopenharmony_ci
69438c2ecf20Sopenharmony_ci	if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
69448c2ecf20Sopenharmony_ci		printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
69458c2ecf20Sopenharmony_ci			ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
69468c2ecf20Sopenharmony_ci		panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
69478c2ecf20Sopenharmony_ci			ioc_raw_state & MPI_DOORBELL_DATA_MASK);
69488c2ecf20Sopenharmony_ci	} else {
69498c2ecf20Sopenharmony_ci		CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
69508c2ecf20Sopenharmony_ci		panic("%s: Firmware is halted due to command timeout\n",
69518c2ecf20Sopenharmony_ci			ioc->name);
69528c2ecf20Sopenharmony_ci	}
69538c2ecf20Sopenharmony_ci}
69548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_halt_firmware);
69558c2ecf20Sopenharmony_ci
69568c2ecf20Sopenharmony_ci/**
69578c2ecf20Sopenharmony_ci *	mpt_SoftResetHandler - Issues a less expensive reset
69588c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
69598c2ecf20Sopenharmony_ci *	@sleepFlag: Indicates if sleep or schedule must be called.
69608c2ecf20Sopenharmony_ci *
69618c2ecf20Sopenharmony_ci *	Returns 0 for SUCCESS or -1 if FAILED.
69628c2ecf20Sopenharmony_ci *
69638c2ecf20Sopenharmony_ci *	Message Unit Reset - instructs the IOC to reset the Reply Post and
69648c2ecf20Sopenharmony_ci *	Free FIFO's. All the Message Frames on Reply Free FIFO are discarded.
69658c2ecf20Sopenharmony_ci *	All posted buffers are freed, and event notification is turned off.
69668c2ecf20Sopenharmony_ci *	IOC doesn't reply to any outstanding request. This will transfer IOC
69678c2ecf20Sopenharmony_ci *	to READY state.
69688c2ecf20Sopenharmony_ci **/
69698c2ecf20Sopenharmony_cistatic int
69708c2ecf20Sopenharmony_cimpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
69718c2ecf20Sopenharmony_ci{
69728c2ecf20Sopenharmony_ci	int		 rc;
69738c2ecf20Sopenharmony_ci	int		 ii;
69748c2ecf20Sopenharmony_ci	u8		 cb_idx;
69758c2ecf20Sopenharmony_ci	unsigned long	 flags;
69768c2ecf20Sopenharmony_ci	u32		 ioc_state;
69778c2ecf20Sopenharmony_ci	unsigned long	 time_count;
69788c2ecf20Sopenharmony_ci
69798c2ecf20Sopenharmony_ci	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n",
69808c2ecf20Sopenharmony_ci		ioc->name));
69818c2ecf20Sopenharmony_ci
69828c2ecf20Sopenharmony_ci	ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
69838c2ecf20Sopenharmony_ci
69848c2ecf20Sopenharmony_ci	if (mpt_fwfault_debug)
69858c2ecf20Sopenharmony_ci		mpt_halt_firmware(ioc);
69868c2ecf20Sopenharmony_ci
69878c2ecf20Sopenharmony_ci	if (ioc_state == MPI_IOC_STATE_FAULT ||
69888c2ecf20Sopenharmony_ci	    ioc_state == MPI_IOC_STATE_RESET) {
69898c2ecf20Sopenharmony_ci		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
69908c2ecf20Sopenharmony_ci		    "skipping, either in FAULT or RESET state!\n", ioc->name));
69918c2ecf20Sopenharmony_ci		return -1;
69928c2ecf20Sopenharmony_ci	}
69938c2ecf20Sopenharmony_ci
69948c2ecf20Sopenharmony_ci	if (ioc->bus_type == FC) {
69958c2ecf20Sopenharmony_ci		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
69968c2ecf20Sopenharmony_ci		    "skipping, because the bus type is FC!\n", ioc->name));
69978c2ecf20Sopenharmony_ci		return -1;
69988c2ecf20Sopenharmony_ci	}
69998c2ecf20Sopenharmony_ci
70008c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
70018c2ecf20Sopenharmony_ci	if (ioc->ioc_reset_in_progress) {
70028c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
70038c2ecf20Sopenharmony_ci		return -1;
70048c2ecf20Sopenharmony_ci	}
70058c2ecf20Sopenharmony_ci	ioc->ioc_reset_in_progress = 1;
70068c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
70078c2ecf20Sopenharmony_ci
70088c2ecf20Sopenharmony_ci	rc = -1;
70098c2ecf20Sopenharmony_ci
70108c2ecf20Sopenharmony_ci	for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
70118c2ecf20Sopenharmony_ci		if (MptResetHandlers[cb_idx])
70128c2ecf20Sopenharmony_ci			mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
70138c2ecf20Sopenharmony_ci	}
70148c2ecf20Sopenharmony_ci
70158c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
70168c2ecf20Sopenharmony_ci	if (ioc->taskmgmt_in_progress) {
70178c2ecf20Sopenharmony_ci		ioc->ioc_reset_in_progress = 0;
70188c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
70198c2ecf20Sopenharmony_ci		return -1;
70208c2ecf20Sopenharmony_ci	}
70218c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
70228c2ecf20Sopenharmony_ci	/* Disable reply interrupts (also blocks FreeQ) */
70238c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
70248c2ecf20Sopenharmony_ci	ioc->active = 0;
70258c2ecf20Sopenharmony_ci	time_count = jiffies;
70268c2ecf20Sopenharmony_ci
70278c2ecf20Sopenharmony_ci	rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
70288c2ecf20Sopenharmony_ci
70298c2ecf20Sopenharmony_ci	for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
70308c2ecf20Sopenharmony_ci		if (MptResetHandlers[cb_idx])
70318c2ecf20Sopenharmony_ci			mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
70328c2ecf20Sopenharmony_ci	}
70338c2ecf20Sopenharmony_ci
70348c2ecf20Sopenharmony_ci	if (rc)
70358c2ecf20Sopenharmony_ci		goto out;
70368c2ecf20Sopenharmony_ci
70378c2ecf20Sopenharmony_ci	ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
70388c2ecf20Sopenharmony_ci	if (ioc_state != MPI_IOC_STATE_READY)
70398c2ecf20Sopenharmony_ci		goto out;
70408c2ecf20Sopenharmony_ci
70418c2ecf20Sopenharmony_ci	for (ii = 0; ii < 5; ii++) {
70428c2ecf20Sopenharmony_ci		/* Get IOC facts! Allow 5 retries */
70438c2ecf20Sopenharmony_ci		rc = GetIocFacts(ioc, sleepFlag,
70448c2ecf20Sopenharmony_ci			MPT_HOSTEVENT_IOC_RECOVER);
70458c2ecf20Sopenharmony_ci		if (rc == 0)
70468c2ecf20Sopenharmony_ci			break;
70478c2ecf20Sopenharmony_ci		if (sleepFlag == CAN_SLEEP)
70488c2ecf20Sopenharmony_ci			msleep(100);
70498c2ecf20Sopenharmony_ci		else
70508c2ecf20Sopenharmony_ci			mdelay(100);
70518c2ecf20Sopenharmony_ci	}
70528c2ecf20Sopenharmony_ci	if (ii == 5)
70538c2ecf20Sopenharmony_ci		goto out;
70548c2ecf20Sopenharmony_ci
70558c2ecf20Sopenharmony_ci	rc = PrimeIocFifos(ioc);
70568c2ecf20Sopenharmony_ci	if (rc != 0)
70578c2ecf20Sopenharmony_ci		goto out;
70588c2ecf20Sopenharmony_ci
70598c2ecf20Sopenharmony_ci	rc = SendIocInit(ioc, sleepFlag);
70608c2ecf20Sopenharmony_ci	if (rc != 0)
70618c2ecf20Sopenharmony_ci		goto out;
70628c2ecf20Sopenharmony_ci
70638c2ecf20Sopenharmony_ci	rc = SendEventNotification(ioc, 1, sleepFlag);
70648c2ecf20Sopenharmony_ci	if (rc != 0)
70658c2ecf20Sopenharmony_ci		goto out;
70668c2ecf20Sopenharmony_ci
70678c2ecf20Sopenharmony_ci	if (ioc->hard_resets < -1)
70688c2ecf20Sopenharmony_ci		ioc->hard_resets++;
70698c2ecf20Sopenharmony_ci
70708c2ecf20Sopenharmony_ci	/*
70718c2ecf20Sopenharmony_ci	 * At this point, we know soft reset succeeded.
70728c2ecf20Sopenharmony_ci	 */
70738c2ecf20Sopenharmony_ci
70748c2ecf20Sopenharmony_ci	ioc->active = 1;
70758c2ecf20Sopenharmony_ci	CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
70768c2ecf20Sopenharmony_ci
70778c2ecf20Sopenharmony_ci out:
70788c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
70798c2ecf20Sopenharmony_ci	ioc->ioc_reset_in_progress = 0;
70808c2ecf20Sopenharmony_ci	ioc->taskmgmt_quiesce_io = 0;
70818c2ecf20Sopenharmony_ci	ioc->taskmgmt_in_progress = 0;
70828c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
70838c2ecf20Sopenharmony_ci
70848c2ecf20Sopenharmony_ci	if (ioc->active) {	/* otherwise, hard reset coming */
70858c2ecf20Sopenharmony_ci		for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
70868c2ecf20Sopenharmony_ci			if (MptResetHandlers[cb_idx])
70878c2ecf20Sopenharmony_ci				mpt_signal_reset(cb_idx, ioc,
70888c2ecf20Sopenharmony_ci					MPT_IOC_POST_RESET);
70898c2ecf20Sopenharmony_ci		}
70908c2ecf20Sopenharmony_ci	}
70918c2ecf20Sopenharmony_ci
70928c2ecf20Sopenharmony_ci	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
70938c2ecf20Sopenharmony_ci		"SoftResetHandler: completed (%d seconds): %s\n",
70948c2ecf20Sopenharmony_ci		ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
70958c2ecf20Sopenharmony_ci		((rc == 0) ? "SUCCESS" : "FAILED")));
70968c2ecf20Sopenharmony_ci
70978c2ecf20Sopenharmony_ci	return rc;
70988c2ecf20Sopenharmony_ci}
70998c2ecf20Sopenharmony_ci
71008c2ecf20Sopenharmony_ci/**
71018c2ecf20Sopenharmony_ci *	mpt_Soft_Hard_ResetHandler - Try less expensive reset
71028c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
71038c2ecf20Sopenharmony_ci *	@sleepFlag: Indicates if sleep or schedule must be called.
71048c2ecf20Sopenharmony_ci *
71058c2ecf20Sopenharmony_ci *	Returns 0 for SUCCESS or -1 if FAILED.
71068c2ecf20Sopenharmony_ci *	Try for softreset first, only if it fails go for expensive
71078c2ecf20Sopenharmony_ci *	HardReset.
71088c2ecf20Sopenharmony_ci **/
71098c2ecf20Sopenharmony_ciint
71108c2ecf20Sopenharmony_cimpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) {
71118c2ecf20Sopenharmony_ci	int ret = -1;
71128c2ecf20Sopenharmony_ci
71138c2ecf20Sopenharmony_ci	ret = mpt_SoftResetHandler(ioc, sleepFlag);
71148c2ecf20Sopenharmony_ci	if (ret == 0)
71158c2ecf20Sopenharmony_ci		return ret;
71168c2ecf20Sopenharmony_ci	ret = mpt_HardResetHandler(ioc, sleepFlag);
71178c2ecf20Sopenharmony_ci	return ret;
71188c2ecf20Sopenharmony_ci}
71198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler);
71208c2ecf20Sopenharmony_ci
71218c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
71228c2ecf20Sopenharmony_ci/*
71238c2ecf20Sopenharmony_ci *	Reset Handling
71248c2ecf20Sopenharmony_ci */
71258c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
71268c2ecf20Sopenharmony_ci/**
71278c2ecf20Sopenharmony_ci *	mpt_HardResetHandler - Generic reset handler
71288c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
71298c2ecf20Sopenharmony_ci *	@sleepFlag: Indicates if sleep or schedule must be called.
71308c2ecf20Sopenharmony_ci *
71318c2ecf20Sopenharmony_ci *	Issues SCSI Task Management call based on input arg values.
71328c2ecf20Sopenharmony_ci *	If TaskMgmt fails, returns associated SCSI request.
71338c2ecf20Sopenharmony_ci *
71348c2ecf20Sopenharmony_ci *	Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
71358c2ecf20Sopenharmony_ci *	or a non-interrupt thread.  In the former, must not call schedule().
71368c2ecf20Sopenharmony_ci *
71378c2ecf20Sopenharmony_ci *	Note: A return of -1 is a FATAL error case, as it means a
71388c2ecf20Sopenharmony_ci *	FW reload/initialization failed.
71398c2ecf20Sopenharmony_ci *
71408c2ecf20Sopenharmony_ci *	Returns 0 for SUCCESS or -1 if FAILED.
71418c2ecf20Sopenharmony_ci */
71428c2ecf20Sopenharmony_ciint
71438c2ecf20Sopenharmony_cimpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
71448c2ecf20Sopenharmony_ci{
71458c2ecf20Sopenharmony_ci	int	 rc;
71468c2ecf20Sopenharmony_ci	u8	 cb_idx;
71478c2ecf20Sopenharmony_ci	unsigned long	 flags;
71488c2ecf20Sopenharmony_ci	unsigned long	 time_count;
71498c2ecf20Sopenharmony_ci
71508c2ecf20Sopenharmony_ci	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
71518c2ecf20Sopenharmony_ci#ifdef MFCNT
71528c2ecf20Sopenharmony_ci	printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
71538c2ecf20Sopenharmony_ci	printk("MF count 0x%x !\n", ioc->mfcnt);
71548c2ecf20Sopenharmony_ci#endif
71558c2ecf20Sopenharmony_ci	if (mpt_fwfault_debug)
71568c2ecf20Sopenharmony_ci		mpt_halt_firmware(ioc);
71578c2ecf20Sopenharmony_ci
71588c2ecf20Sopenharmony_ci	/* Reset the adapter. Prevent more than 1 call to
71598c2ecf20Sopenharmony_ci	 * mpt_do_ioc_recovery at any instant in time.
71608c2ecf20Sopenharmony_ci	 */
71618c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
71628c2ecf20Sopenharmony_ci	if (ioc->ioc_reset_in_progress) {
71638c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
71648c2ecf20Sopenharmony_ci		ioc->wait_on_reset_completion = 1;
71658c2ecf20Sopenharmony_ci		do {
71668c2ecf20Sopenharmony_ci			ssleep(1);
71678c2ecf20Sopenharmony_ci		} while (ioc->ioc_reset_in_progress == 1);
71688c2ecf20Sopenharmony_ci		ioc->wait_on_reset_completion = 0;
71698c2ecf20Sopenharmony_ci		return ioc->reset_status;
71708c2ecf20Sopenharmony_ci	}
71718c2ecf20Sopenharmony_ci	if (ioc->wait_on_reset_completion) {
71728c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
71738c2ecf20Sopenharmony_ci		rc = 0;
71748c2ecf20Sopenharmony_ci		time_count = jiffies;
71758c2ecf20Sopenharmony_ci		goto exit;
71768c2ecf20Sopenharmony_ci	}
71778c2ecf20Sopenharmony_ci	ioc->ioc_reset_in_progress = 1;
71788c2ecf20Sopenharmony_ci	if (ioc->alt_ioc)
71798c2ecf20Sopenharmony_ci		ioc->alt_ioc->ioc_reset_in_progress = 1;
71808c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
71818c2ecf20Sopenharmony_ci
71828c2ecf20Sopenharmony_ci
71838c2ecf20Sopenharmony_ci	/* The SCSI driver needs to adjust timeouts on all current
71848c2ecf20Sopenharmony_ci	 * commands prior to the diagnostic reset being issued.
71858c2ecf20Sopenharmony_ci	 * Prevents timeouts occurring during a diagnostic reset...very bad.
71868c2ecf20Sopenharmony_ci	 * For all other protocol drivers, this is a no-op.
71878c2ecf20Sopenharmony_ci	 */
71888c2ecf20Sopenharmony_ci	for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
71898c2ecf20Sopenharmony_ci		if (MptResetHandlers[cb_idx]) {
71908c2ecf20Sopenharmony_ci			mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
71918c2ecf20Sopenharmony_ci			if (ioc->alt_ioc)
71928c2ecf20Sopenharmony_ci				mpt_signal_reset(cb_idx, ioc->alt_ioc,
71938c2ecf20Sopenharmony_ci					MPT_IOC_SETUP_RESET);
71948c2ecf20Sopenharmony_ci		}
71958c2ecf20Sopenharmony_ci	}
71968c2ecf20Sopenharmony_ci
71978c2ecf20Sopenharmony_ci	time_count = jiffies;
71988c2ecf20Sopenharmony_ci	rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
71998c2ecf20Sopenharmony_ci	if (rc != 0) {
72008c2ecf20Sopenharmony_ci		printk(KERN_WARNING MYNAM
72018c2ecf20Sopenharmony_ci		       ": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n",
72028c2ecf20Sopenharmony_ci		       rc, ioc->name, mpt_GetIocState(ioc, 0));
72038c2ecf20Sopenharmony_ci	} else {
72048c2ecf20Sopenharmony_ci		if (ioc->hard_resets < -1)
72058c2ecf20Sopenharmony_ci			ioc->hard_resets++;
72068c2ecf20Sopenharmony_ci	}
72078c2ecf20Sopenharmony_ci
72088c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
72098c2ecf20Sopenharmony_ci	ioc->ioc_reset_in_progress = 0;
72108c2ecf20Sopenharmony_ci	ioc->taskmgmt_quiesce_io = 0;
72118c2ecf20Sopenharmony_ci	ioc->taskmgmt_in_progress = 0;
72128c2ecf20Sopenharmony_ci	ioc->reset_status = rc;
72138c2ecf20Sopenharmony_ci	if (ioc->alt_ioc) {
72148c2ecf20Sopenharmony_ci		ioc->alt_ioc->ioc_reset_in_progress = 0;
72158c2ecf20Sopenharmony_ci		ioc->alt_ioc->taskmgmt_quiesce_io = 0;
72168c2ecf20Sopenharmony_ci		ioc->alt_ioc->taskmgmt_in_progress = 0;
72178c2ecf20Sopenharmony_ci	}
72188c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
72198c2ecf20Sopenharmony_ci
72208c2ecf20Sopenharmony_ci	for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
72218c2ecf20Sopenharmony_ci		if (MptResetHandlers[cb_idx]) {
72228c2ecf20Sopenharmony_ci			mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
72238c2ecf20Sopenharmony_ci			if (ioc->alt_ioc)
72248c2ecf20Sopenharmony_ci				mpt_signal_reset(cb_idx,
72258c2ecf20Sopenharmony_ci					ioc->alt_ioc, MPT_IOC_POST_RESET);
72268c2ecf20Sopenharmony_ci		}
72278c2ecf20Sopenharmony_ci	}
72288c2ecf20Sopenharmony_ciexit:
72298c2ecf20Sopenharmony_ci	dtmprintk(ioc,
72308c2ecf20Sopenharmony_ci	    printk(MYIOC_s_DEBUG_FMT
72318c2ecf20Sopenharmony_ci		"HardResetHandler: completed (%d seconds): %s\n", ioc->name,
72328c2ecf20Sopenharmony_ci		jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
72338c2ecf20Sopenharmony_ci		"SUCCESS" : "FAILED")));
72348c2ecf20Sopenharmony_ci
72358c2ecf20Sopenharmony_ci	return rc;
72368c2ecf20Sopenharmony_ci}
72378c2ecf20Sopenharmony_ci
72388c2ecf20Sopenharmony_ci#ifdef CONFIG_FUSION_LOGGING
72398c2ecf20Sopenharmony_cistatic void
72408c2ecf20Sopenharmony_cimpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
72418c2ecf20Sopenharmony_ci{
72428c2ecf20Sopenharmony_ci	char *ds = NULL;
72438c2ecf20Sopenharmony_ci	u32 evData0;
72448c2ecf20Sopenharmony_ci	int ii;
72458c2ecf20Sopenharmony_ci	u8 event;
72468c2ecf20Sopenharmony_ci	char *evStr = ioc->evStr;
72478c2ecf20Sopenharmony_ci
72488c2ecf20Sopenharmony_ci	event = le32_to_cpu(pEventReply->Event) & 0xFF;
72498c2ecf20Sopenharmony_ci	evData0 = le32_to_cpu(pEventReply->Data[0]);
72508c2ecf20Sopenharmony_ci
72518c2ecf20Sopenharmony_ci	switch(event) {
72528c2ecf20Sopenharmony_ci	case MPI_EVENT_NONE:
72538c2ecf20Sopenharmony_ci		ds = "None";
72548c2ecf20Sopenharmony_ci		break;
72558c2ecf20Sopenharmony_ci	case MPI_EVENT_LOG_DATA:
72568c2ecf20Sopenharmony_ci		ds = "Log Data";
72578c2ecf20Sopenharmony_ci		break;
72588c2ecf20Sopenharmony_ci	case MPI_EVENT_STATE_CHANGE:
72598c2ecf20Sopenharmony_ci		ds = "State Change";
72608c2ecf20Sopenharmony_ci		break;
72618c2ecf20Sopenharmony_ci	case MPI_EVENT_UNIT_ATTENTION:
72628c2ecf20Sopenharmony_ci		ds = "Unit Attention";
72638c2ecf20Sopenharmony_ci		break;
72648c2ecf20Sopenharmony_ci	case MPI_EVENT_IOC_BUS_RESET:
72658c2ecf20Sopenharmony_ci		ds = "IOC Bus Reset";
72668c2ecf20Sopenharmony_ci		break;
72678c2ecf20Sopenharmony_ci	case MPI_EVENT_EXT_BUS_RESET:
72688c2ecf20Sopenharmony_ci		ds = "External Bus Reset";
72698c2ecf20Sopenharmony_ci		break;
72708c2ecf20Sopenharmony_ci	case MPI_EVENT_RESCAN:
72718c2ecf20Sopenharmony_ci		ds = "Bus Rescan Event";
72728c2ecf20Sopenharmony_ci		break;
72738c2ecf20Sopenharmony_ci	case MPI_EVENT_LINK_STATUS_CHANGE:
72748c2ecf20Sopenharmony_ci		if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
72758c2ecf20Sopenharmony_ci			ds = "Link Status(FAILURE) Change";
72768c2ecf20Sopenharmony_ci		else
72778c2ecf20Sopenharmony_ci			ds = "Link Status(ACTIVE) Change";
72788c2ecf20Sopenharmony_ci		break;
72798c2ecf20Sopenharmony_ci	case MPI_EVENT_LOOP_STATE_CHANGE:
72808c2ecf20Sopenharmony_ci		if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
72818c2ecf20Sopenharmony_ci			ds = "Loop State(LIP) Change";
72828c2ecf20Sopenharmony_ci		else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
72838c2ecf20Sopenharmony_ci			ds = "Loop State(LPE) Change";
72848c2ecf20Sopenharmony_ci		else
72858c2ecf20Sopenharmony_ci			ds = "Loop State(LPB) Change";
72868c2ecf20Sopenharmony_ci		break;
72878c2ecf20Sopenharmony_ci	case MPI_EVENT_LOGOUT:
72888c2ecf20Sopenharmony_ci		ds = "Logout";
72898c2ecf20Sopenharmony_ci		break;
72908c2ecf20Sopenharmony_ci	case MPI_EVENT_EVENT_CHANGE:
72918c2ecf20Sopenharmony_ci		if (evData0)
72928c2ecf20Sopenharmony_ci			ds = "Events ON";
72938c2ecf20Sopenharmony_ci		else
72948c2ecf20Sopenharmony_ci			ds = "Events OFF";
72958c2ecf20Sopenharmony_ci		break;
72968c2ecf20Sopenharmony_ci	case MPI_EVENT_INTEGRATED_RAID:
72978c2ecf20Sopenharmony_ci	{
72988c2ecf20Sopenharmony_ci		u8 ReasonCode = (u8)(evData0 >> 16);
72998c2ecf20Sopenharmony_ci		switch (ReasonCode) {
73008c2ecf20Sopenharmony_ci		case MPI_EVENT_RAID_RC_VOLUME_CREATED :
73018c2ecf20Sopenharmony_ci			ds = "Integrated Raid: Volume Created";
73028c2ecf20Sopenharmony_ci			break;
73038c2ecf20Sopenharmony_ci		case MPI_EVENT_RAID_RC_VOLUME_DELETED :
73048c2ecf20Sopenharmony_ci			ds = "Integrated Raid: Volume Deleted";
73058c2ecf20Sopenharmony_ci			break;
73068c2ecf20Sopenharmony_ci		case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
73078c2ecf20Sopenharmony_ci			ds = "Integrated Raid: Volume Settings Changed";
73088c2ecf20Sopenharmony_ci			break;
73098c2ecf20Sopenharmony_ci		case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
73108c2ecf20Sopenharmony_ci			ds = "Integrated Raid: Volume Status Changed";
73118c2ecf20Sopenharmony_ci			break;
73128c2ecf20Sopenharmony_ci		case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
73138c2ecf20Sopenharmony_ci			ds = "Integrated Raid: Volume Physdisk Changed";
73148c2ecf20Sopenharmony_ci			break;
73158c2ecf20Sopenharmony_ci		case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
73168c2ecf20Sopenharmony_ci			ds = "Integrated Raid: Physdisk Created";
73178c2ecf20Sopenharmony_ci			break;
73188c2ecf20Sopenharmony_ci		case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
73198c2ecf20Sopenharmony_ci			ds = "Integrated Raid: Physdisk Deleted";
73208c2ecf20Sopenharmony_ci			break;
73218c2ecf20Sopenharmony_ci		case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
73228c2ecf20Sopenharmony_ci			ds = "Integrated Raid: Physdisk Settings Changed";
73238c2ecf20Sopenharmony_ci			break;
73248c2ecf20Sopenharmony_ci		case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
73258c2ecf20Sopenharmony_ci			ds = "Integrated Raid: Physdisk Status Changed";
73268c2ecf20Sopenharmony_ci			break;
73278c2ecf20Sopenharmony_ci		case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
73288c2ecf20Sopenharmony_ci			ds = "Integrated Raid: Domain Validation Needed";
73298c2ecf20Sopenharmony_ci			break;
73308c2ecf20Sopenharmony_ci		case MPI_EVENT_RAID_RC_SMART_DATA :
73318c2ecf20Sopenharmony_ci			ds = "Integrated Raid; Smart Data";
73328c2ecf20Sopenharmony_ci			break;
73338c2ecf20Sopenharmony_ci		case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
73348c2ecf20Sopenharmony_ci			ds = "Integrated Raid: Replace Action Started";
73358c2ecf20Sopenharmony_ci			break;
73368c2ecf20Sopenharmony_ci		default:
73378c2ecf20Sopenharmony_ci			ds = "Integrated Raid";
73388c2ecf20Sopenharmony_ci		break;
73398c2ecf20Sopenharmony_ci		}
73408c2ecf20Sopenharmony_ci		break;
73418c2ecf20Sopenharmony_ci	}
73428c2ecf20Sopenharmony_ci	case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
73438c2ecf20Sopenharmony_ci		ds = "SCSI Device Status Change";
73448c2ecf20Sopenharmony_ci		break;
73458c2ecf20Sopenharmony_ci	case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
73468c2ecf20Sopenharmony_ci	{
73478c2ecf20Sopenharmony_ci		u8 id = (u8)(evData0);
73488c2ecf20Sopenharmony_ci		u8 channel = (u8)(evData0 >> 8);
73498c2ecf20Sopenharmony_ci		u8 ReasonCode = (u8)(evData0 >> 16);
73508c2ecf20Sopenharmony_ci		switch (ReasonCode) {
73518c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
73528c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
73538c2ecf20Sopenharmony_ci			    "SAS Device Status Change: Added: "
73548c2ecf20Sopenharmony_ci			    "id=%d channel=%d", id, channel);
73558c2ecf20Sopenharmony_ci			break;
73568c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
73578c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
73588c2ecf20Sopenharmony_ci			    "SAS Device Status Change: Deleted: "
73598c2ecf20Sopenharmony_ci			    "id=%d channel=%d", id, channel);
73608c2ecf20Sopenharmony_ci			break;
73618c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
73628c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
73638c2ecf20Sopenharmony_ci			    "SAS Device Status Change: SMART Data: "
73648c2ecf20Sopenharmony_ci			    "id=%d channel=%d", id, channel);
73658c2ecf20Sopenharmony_ci			break;
73668c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
73678c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
73688c2ecf20Sopenharmony_ci			    "SAS Device Status Change: No Persistency: "
73698c2ecf20Sopenharmony_ci			    "id=%d channel=%d", id, channel);
73708c2ecf20Sopenharmony_ci			break;
73718c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
73728c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
73738c2ecf20Sopenharmony_ci			    "SAS Device Status Change: Unsupported Device "
73748c2ecf20Sopenharmony_ci			    "Discovered : id=%d channel=%d", id, channel);
73758c2ecf20Sopenharmony_ci			break;
73768c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
73778c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
73788c2ecf20Sopenharmony_ci			    "SAS Device Status Change: Internal Device "
73798c2ecf20Sopenharmony_ci			    "Reset : id=%d channel=%d", id, channel);
73808c2ecf20Sopenharmony_ci			break;
73818c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
73828c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
73838c2ecf20Sopenharmony_ci			    "SAS Device Status Change: Internal Task "
73848c2ecf20Sopenharmony_ci			    "Abort : id=%d channel=%d", id, channel);
73858c2ecf20Sopenharmony_ci			break;
73868c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
73878c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
73888c2ecf20Sopenharmony_ci			    "SAS Device Status Change: Internal Abort "
73898c2ecf20Sopenharmony_ci			    "Task Set : id=%d channel=%d", id, channel);
73908c2ecf20Sopenharmony_ci			break;
73918c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
73928c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
73938c2ecf20Sopenharmony_ci			    "SAS Device Status Change: Internal Clear "
73948c2ecf20Sopenharmony_ci			    "Task Set : id=%d channel=%d", id, channel);
73958c2ecf20Sopenharmony_ci			break;
73968c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
73978c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
73988c2ecf20Sopenharmony_ci			    "SAS Device Status Change: Internal Query "
73998c2ecf20Sopenharmony_ci			    "Task : id=%d channel=%d", id, channel);
74008c2ecf20Sopenharmony_ci			break;
74018c2ecf20Sopenharmony_ci		default:
74028c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
74038c2ecf20Sopenharmony_ci			    "SAS Device Status Change: Unknown: "
74048c2ecf20Sopenharmony_ci			    "id=%d channel=%d", id, channel);
74058c2ecf20Sopenharmony_ci			break;
74068c2ecf20Sopenharmony_ci		}
74078c2ecf20Sopenharmony_ci		break;
74088c2ecf20Sopenharmony_ci	}
74098c2ecf20Sopenharmony_ci	case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
74108c2ecf20Sopenharmony_ci		ds = "Bus Timer Expired";
74118c2ecf20Sopenharmony_ci		break;
74128c2ecf20Sopenharmony_ci	case MPI_EVENT_QUEUE_FULL:
74138c2ecf20Sopenharmony_ci	{
74148c2ecf20Sopenharmony_ci		u16 curr_depth = (u16)(evData0 >> 16);
74158c2ecf20Sopenharmony_ci		u8 channel = (u8)(evData0 >> 8);
74168c2ecf20Sopenharmony_ci		u8 id = (u8)(evData0);
74178c2ecf20Sopenharmony_ci
74188c2ecf20Sopenharmony_ci		snprintf(evStr, EVENT_DESCR_STR_SZ,
74198c2ecf20Sopenharmony_ci		   "Queue Full: channel=%d id=%d depth=%d",
74208c2ecf20Sopenharmony_ci		   channel, id, curr_depth);
74218c2ecf20Sopenharmony_ci		break;
74228c2ecf20Sopenharmony_ci	}
74238c2ecf20Sopenharmony_ci	case MPI_EVENT_SAS_SES:
74248c2ecf20Sopenharmony_ci		ds = "SAS SES Event";
74258c2ecf20Sopenharmony_ci		break;
74268c2ecf20Sopenharmony_ci	case MPI_EVENT_PERSISTENT_TABLE_FULL:
74278c2ecf20Sopenharmony_ci		ds = "Persistent Table Full";
74288c2ecf20Sopenharmony_ci		break;
74298c2ecf20Sopenharmony_ci	case MPI_EVENT_SAS_PHY_LINK_STATUS:
74308c2ecf20Sopenharmony_ci	{
74318c2ecf20Sopenharmony_ci		u8 LinkRates = (u8)(evData0 >> 8);
74328c2ecf20Sopenharmony_ci		u8 PhyNumber = (u8)(evData0);
74338c2ecf20Sopenharmony_ci		LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
74348c2ecf20Sopenharmony_ci			MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
74358c2ecf20Sopenharmony_ci		switch (LinkRates) {
74368c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
74378c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
74388c2ecf20Sopenharmony_ci			   "SAS PHY Link Status: Phy=%d:"
74398c2ecf20Sopenharmony_ci			   " Rate Unknown",PhyNumber);
74408c2ecf20Sopenharmony_ci			break;
74418c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
74428c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
74438c2ecf20Sopenharmony_ci			   "SAS PHY Link Status: Phy=%d:"
74448c2ecf20Sopenharmony_ci			   " Phy Disabled",PhyNumber);
74458c2ecf20Sopenharmony_ci			break;
74468c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
74478c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
74488c2ecf20Sopenharmony_ci			   "SAS PHY Link Status: Phy=%d:"
74498c2ecf20Sopenharmony_ci			   " Failed Speed Nego",PhyNumber);
74508c2ecf20Sopenharmony_ci			break;
74518c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
74528c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
74538c2ecf20Sopenharmony_ci			   "SAS PHY Link Status: Phy=%d:"
74548c2ecf20Sopenharmony_ci			   " Sata OOB Completed",PhyNumber);
74558c2ecf20Sopenharmony_ci			break;
74568c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
74578c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
74588c2ecf20Sopenharmony_ci			   "SAS PHY Link Status: Phy=%d:"
74598c2ecf20Sopenharmony_ci			   " Rate 1.5 Gbps",PhyNumber);
74608c2ecf20Sopenharmony_ci			break;
74618c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
74628c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
74638c2ecf20Sopenharmony_ci			   "SAS PHY Link Status: Phy=%d:"
74648c2ecf20Sopenharmony_ci			   " Rate 3.0 Gbps", PhyNumber);
74658c2ecf20Sopenharmony_ci			break;
74668c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_PLS_LR_RATE_6_0:
74678c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
74688c2ecf20Sopenharmony_ci			   "SAS PHY Link Status: Phy=%d:"
74698c2ecf20Sopenharmony_ci			   " Rate 6.0 Gbps", PhyNumber);
74708c2ecf20Sopenharmony_ci			break;
74718c2ecf20Sopenharmony_ci		default:
74728c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
74738c2ecf20Sopenharmony_ci			   "SAS PHY Link Status: Phy=%d", PhyNumber);
74748c2ecf20Sopenharmony_ci			break;
74758c2ecf20Sopenharmony_ci		}
74768c2ecf20Sopenharmony_ci		break;
74778c2ecf20Sopenharmony_ci	}
74788c2ecf20Sopenharmony_ci	case MPI_EVENT_SAS_DISCOVERY_ERROR:
74798c2ecf20Sopenharmony_ci		ds = "SAS Discovery Error";
74808c2ecf20Sopenharmony_ci		break;
74818c2ecf20Sopenharmony_ci	case MPI_EVENT_IR_RESYNC_UPDATE:
74828c2ecf20Sopenharmony_ci	{
74838c2ecf20Sopenharmony_ci		u8 resync_complete = (u8)(evData0 >> 16);
74848c2ecf20Sopenharmony_ci		snprintf(evStr, EVENT_DESCR_STR_SZ,
74858c2ecf20Sopenharmony_ci		    "IR Resync Update: Complete = %d:",resync_complete);
74868c2ecf20Sopenharmony_ci		break;
74878c2ecf20Sopenharmony_ci	}
74888c2ecf20Sopenharmony_ci	case MPI_EVENT_IR2:
74898c2ecf20Sopenharmony_ci	{
74908c2ecf20Sopenharmony_ci		u8 id = (u8)(evData0);
74918c2ecf20Sopenharmony_ci		u8 channel = (u8)(evData0 >> 8);
74928c2ecf20Sopenharmony_ci		u8 phys_num = (u8)(evData0 >> 24);
74938c2ecf20Sopenharmony_ci		u8 ReasonCode = (u8)(evData0 >> 16);
74948c2ecf20Sopenharmony_ci
74958c2ecf20Sopenharmony_ci		switch (ReasonCode) {
74968c2ecf20Sopenharmony_ci		case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
74978c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
74988c2ecf20Sopenharmony_ci			    "IR2: LD State Changed: "
74998c2ecf20Sopenharmony_ci			    "id=%d channel=%d phys_num=%d",
75008c2ecf20Sopenharmony_ci			    id, channel, phys_num);
75018c2ecf20Sopenharmony_ci			break;
75028c2ecf20Sopenharmony_ci		case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
75038c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
75048c2ecf20Sopenharmony_ci			    "IR2: PD State Changed "
75058c2ecf20Sopenharmony_ci			    "id=%d channel=%d phys_num=%d",
75068c2ecf20Sopenharmony_ci			    id, channel, phys_num);
75078c2ecf20Sopenharmony_ci			break;
75088c2ecf20Sopenharmony_ci		case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
75098c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
75108c2ecf20Sopenharmony_ci			    "IR2: Bad Block Table Full: "
75118c2ecf20Sopenharmony_ci			    "id=%d channel=%d phys_num=%d",
75128c2ecf20Sopenharmony_ci			    id, channel, phys_num);
75138c2ecf20Sopenharmony_ci			break;
75148c2ecf20Sopenharmony_ci		case MPI_EVENT_IR2_RC_PD_INSERTED:
75158c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
75168c2ecf20Sopenharmony_ci			    "IR2: PD Inserted: "
75178c2ecf20Sopenharmony_ci			    "id=%d channel=%d phys_num=%d",
75188c2ecf20Sopenharmony_ci			    id, channel, phys_num);
75198c2ecf20Sopenharmony_ci			break;
75208c2ecf20Sopenharmony_ci		case MPI_EVENT_IR2_RC_PD_REMOVED:
75218c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
75228c2ecf20Sopenharmony_ci			    "IR2: PD Removed: "
75238c2ecf20Sopenharmony_ci			    "id=%d channel=%d phys_num=%d",
75248c2ecf20Sopenharmony_ci			    id, channel, phys_num);
75258c2ecf20Sopenharmony_ci			break;
75268c2ecf20Sopenharmony_ci		case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
75278c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
75288c2ecf20Sopenharmony_ci			    "IR2: Foreign CFG Detected: "
75298c2ecf20Sopenharmony_ci			    "id=%d channel=%d phys_num=%d",
75308c2ecf20Sopenharmony_ci			    id, channel, phys_num);
75318c2ecf20Sopenharmony_ci			break;
75328c2ecf20Sopenharmony_ci		case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
75338c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
75348c2ecf20Sopenharmony_ci			    "IR2: Rebuild Medium Error: "
75358c2ecf20Sopenharmony_ci			    "id=%d channel=%d phys_num=%d",
75368c2ecf20Sopenharmony_ci			    id, channel, phys_num);
75378c2ecf20Sopenharmony_ci			break;
75388c2ecf20Sopenharmony_ci		case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
75398c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
75408c2ecf20Sopenharmony_ci			    "IR2: Dual Port Added: "
75418c2ecf20Sopenharmony_ci			    "id=%d channel=%d phys_num=%d",
75428c2ecf20Sopenharmony_ci			    id, channel, phys_num);
75438c2ecf20Sopenharmony_ci			break;
75448c2ecf20Sopenharmony_ci		case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
75458c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
75468c2ecf20Sopenharmony_ci			    "IR2: Dual Port Removed: "
75478c2ecf20Sopenharmony_ci			    "id=%d channel=%d phys_num=%d",
75488c2ecf20Sopenharmony_ci			    id, channel, phys_num);
75498c2ecf20Sopenharmony_ci			break;
75508c2ecf20Sopenharmony_ci		default:
75518c2ecf20Sopenharmony_ci			ds = "IR2";
75528c2ecf20Sopenharmony_ci		break;
75538c2ecf20Sopenharmony_ci		}
75548c2ecf20Sopenharmony_ci		break;
75558c2ecf20Sopenharmony_ci	}
75568c2ecf20Sopenharmony_ci	case MPI_EVENT_SAS_DISCOVERY:
75578c2ecf20Sopenharmony_ci	{
75588c2ecf20Sopenharmony_ci		if (evData0)
75598c2ecf20Sopenharmony_ci			ds = "SAS Discovery: Start";
75608c2ecf20Sopenharmony_ci		else
75618c2ecf20Sopenharmony_ci			ds = "SAS Discovery: Stop";
75628c2ecf20Sopenharmony_ci		break;
75638c2ecf20Sopenharmony_ci	}
75648c2ecf20Sopenharmony_ci	case MPI_EVENT_LOG_ENTRY_ADDED:
75658c2ecf20Sopenharmony_ci		ds = "SAS Log Entry Added";
75668c2ecf20Sopenharmony_ci		break;
75678c2ecf20Sopenharmony_ci
75688c2ecf20Sopenharmony_ci	case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
75698c2ecf20Sopenharmony_ci	{
75708c2ecf20Sopenharmony_ci		u8 phy_num = (u8)(evData0);
75718c2ecf20Sopenharmony_ci		u8 port_num = (u8)(evData0 >> 8);
75728c2ecf20Sopenharmony_ci		u8 port_width = (u8)(evData0 >> 16);
75738c2ecf20Sopenharmony_ci		u8 primitive = (u8)(evData0 >> 24);
75748c2ecf20Sopenharmony_ci		snprintf(evStr, EVENT_DESCR_STR_SZ,
75758c2ecf20Sopenharmony_ci		    "SAS Broadcast Primitive: phy=%d port=%d "
75768c2ecf20Sopenharmony_ci		    "width=%d primitive=0x%02x",
75778c2ecf20Sopenharmony_ci		    phy_num, port_num, port_width, primitive);
75788c2ecf20Sopenharmony_ci		break;
75798c2ecf20Sopenharmony_ci	}
75808c2ecf20Sopenharmony_ci
75818c2ecf20Sopenharmony_ci	case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
75828c2ecf20Sopenharmony_ci	{
75838c2ecf20Sopenharmony_ci		u8 reason = (u8)(evData0);
75848c2ecf20Sopenharmony_ci
75858c2ecf20Sopenharmony_ci		switch (reason) {
75868c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_INIT_RC_ADDED:
75878c2ecf20Sopenharmony_ci			ds = "SAS Initiator Status Change: Added";
75888c2ecf20Sopenharmony_ci			break;
75898c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_INIT_RC_REMOVED:
75908c2ecf20Sopenharmony_ci			ds = "SAS Initiator Status Change: Deleted";
75918c2ecf20Sopenharmony_ci			break;
75928c2ecf20Sopenharmony_ci		default:
75938c2ecf20Sopenharmony_ci			ds = "SAS Initiator Status Change";
75948c2ecf20Sopenharmony_ci			break;
75958c2ecf20Sopenharmony_ci		}
75968c2ecf20Sopenharmony_ci		break;
75978c2ecf20Sopenharmony_ci	}
75988c2ecf20Sopenharmony_ci
75998c2ecf20Sopenharmony_ci	case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
76008c2ecf20Sopenharmony_ci	{
76018c2ecf20Sopenharmony_ci		u8 max_init = (u8)(evData0);
76028c2ecf20Sopenharmony_ci		u8 current_init = (u8)(evData0 >> 8);
76038c2ecf20Sopenharmony_ci
76048c2ecf20Sopenharmony_ci		snprintf(evStr, EVENT_DESCR_STR_SZ,
76058c2ecf20Sopenharmony_ci		    "SAS Initiator Device Table Overflow: max initiators=%02d "
76068c2ecf20Sopenharmony_ci		    "current initiators=%02d",
76078c2ecf20Sopenharmony_ci		    max_init, current_init);
76088c2ecf20Sopenharmony_ci		break;
76098c2ecf20Sopenharmony_ci	}
76108c2ecf20Sopenharmony_ci	case MPI_EVENT_SAS_SMP_ERROR:
76118c2ecf20Sopenharmony_ci	{
76128c2ecf20Sopenharmony_ci		u8 status = (u8)(evData0);
76138c2ecf20Sopenharmony_ci		u8 port_num = (u8)(evData0 >> 8);
76148c2ecf20Sopenharmony_ci		u8 result = (u8)(evData0 >> 16);
76158c2ecf20Sopenharmony_ci
76168c2ecf20Sopenharmony_ci		if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
76178c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
76188c2ecf20Sopenharmony_ci			    "SAS SMP Error: port=%d result=0x%02x",
76198c2ecf20Sopenharmony_ci			    port_num, result);
76208c2ecf20Sopenharmony_ci		else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
76218c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
76228c2ecf20Sopenharmony_ci			    "SAS SMP Error: port=%d : CRC Error",
76238c2ecf20Sopenharmony_ci			    port_num);
76248c2ecf20Sopenharmony_ci		else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
76258c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
76268c2ecf20Sopenharmony_ci			    "SAS SMP Error: port=%d : Timeout",
76278c2ecf20Sopenharmony_ci			    port_num);
76288c2ecf20Sopenharmony_ci		else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
76298c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
76308c2ecf20Sopenharmony_ci			    "SAS SMP Error: port=%d : No Destination",
76318c2ecf20Sopenharmony_ci			    port_num);
76328c2ecf20Sopenharmony_ci		else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
76338c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
76348c2ecf20Sopenharmony_ci			    "SAS SMP Error: port=%d : Bad Destination",
76358c2ecf20Sopenharmony_ci			    port_num);
76368c2ecf20Sopenharmony_ci		else
76378c2ecf20Sopenharmony_ci			snprintf(evStr, EVENT_DESCR_STR_SZ,
76388c2ecf20Sopenharmony_ci			    "SAS SMP Error: port=%d : status=0x%02x",
76398c2ecf20Sopenharmony_ci			    port_num, status);
76408c2ecf20Sopenharmony_ci		break;
76418c2ecf20Sopenharmony_ci	}
76428c2ecf20Sopenharmony_ci
76438c2ecf20Sopenharmony_ci	case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
76448c2ecf20Sopenharmony_ci	{
76458c2ecf20Sopenharmony_ci		u8 reason = (u8)(evData0);
76468c2ecf20Sopenharmony_ci
76478c2ecf20Sopenharmony_ci		switch (reason) {
76488c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_EXP_RC_ADDED:
76498c2ecf20Sopenharmony_ci			ds = "Expander Status Change: Added";
76508c2ecf20Sopenharmony_ci			break;
76518c2ecf20Sopenharmony_ci		case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
76528c2ecf20Sopenharmony_ci			ds = "Expander Status Change: Deleted";
76538c2ecf20Sopenharmony_ci			break;
76548c2ecf20Sopenharmony_ci		default:
76558c2ecf20Sopenharmony_ci			ds = "Expander Status Change";
76568c2ecf20Sopenharmony_ci			break;
76578c2ecf20Sopenharmony_ci		}
76588c2ecf20Sopenharmony_ci		break;
76598c2ecf20Sopenharmony_ci	}
76608c2ecf20Sopenharmony_ci
76618c2ecf20Sopenharmony_ci	/*
76628c2ecf20Sopenharmony_ci	 *  MPT base "custom" events may be added here...
76638c2ecf20Sopenharmony_ci	 */
76648c2ecf20Sopenharmony_ci	default:
76658c2ecf20Sopenharmony_ci		ds = "Unknown";
76668c2ecf20Sopenharmony_ci		break;
76678c2ecf20Sopenharmony_ci	}
76688c2ecf20Sopenharmony_ci	if (ds)
76698c2ecf20Sopenharmony_ci		strlcpy(evStr, ds, EVENT_DESCR_STR_SZ);
76708c2ecf20Sopenharmony_ci
76718c2ecf20Sopenharmony_ci
76728c2ecf20Sopenharmony_ci	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
76738c2ecf20Sopenharmony_ci	    "MPT event:(%02Xh) : %s\n",
76748c2ecf20Sopenharmony_ci	    ioc->name, event, evStr));
76758c2ecf20Sopenharmony_ci
76768c2ecf20Sopenharmony_ci	devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
76778c2ecf20Sopenharmony_ci	    ": Event data:\n"));
76788c2ecf20Sopenharmony_ci	for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
76798c2ecf20Sopenharmony_ci		devtverboseprintk(ioc, printk(" %08x",
76808c2ecf20Sopenharmony_ci		    le32_to_cpu(pEventReply->Data[ii])));
76818c2ecf20Sopenharmony_ci	devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
76828c2ecf20Sopenharmony_ci}
76838c2ecf20Sopenharmony_ci#endif
76848c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
76858c2ecf20Sopenharmony_ci/**
76868c2ecf20Sopenharmony_ci *	ProcessEventNotification - Route EventNotificationReply to all event handlers
76878c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
76888c2ecf20Sopenharmony_ci *	@pEventReply: Pointer to EventNotification reply frame
76898c2ecf20Sopenharmony_ci *	@evHandlers: Pointer to integer, number of event handlers
76908c2ecf20Sopenharmony_ci *
76918c2ecf20Sopenharmony_ci *	Routes a received EventNotificationReply to all currently registered
76928c2ecf20Sopenharmony_ci *	event handlers.
76938c2ecf20Sopenharmony_ci *	Returns sum of event handlers return values.
76948c2ecf20Sopenharmony_ci */
76958c2ecf20Sopenharmony_cistatic int
76968c2ecf20Sopenharmony_ciProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
76978c2ecf20Sopenharmony_ci{
76988c2ecf20Sopenharmony_ci	u16 evDataLen;
76998c2ecf20Sopenharmony_ci	u32 evData0 = 0;
77008c2ecf20Sopenharmony_ci	int ii;
77018c2ecf20Sopenharmony_ci	u8 cb_idx;
77028c2ecf20Sopenharmony_ci	int r = 0;
77038c2ecf20Sopenharmony_ci	int handlers = 0;
77048c2ecf20Sopenharmony_ci	u8 event;
77058c2ecf20Sopenharmony_ci
77068c2ecf20Sopenharmony_ci	/*
77078c2ecf20Sopenharmony_ci	 *  Do platform normalization of values
77088c2ecf20Sopenharmony_ci	 */
77098c2ecf20Sopenharmony_ci	event = le32_to_cpu(pEventReply->Event) & 0xFF;
77108c2ecf20Sopenharmony_ci	evDataLen = le16_to_cpu(pEventReply->EventDataLength);
77118c2ecf20Sopenharmony_ci	if (evDataLen) {
77128c2ecf20Sopenharmony_ci		evData0 = le32_to_cpu(pEventReply->Data[0]);
77138c2ecf20Sopenharmony_ci	}
77148c2ecf20Sopenharmony_ci
77158c2ecf20Sopenharmony_ci#ifdef CONFIG_FUSION_LOGGING
77168c2ecf20Sopenharmony_ci	if (evDataLen)
77178c2ecf20Sopenharmony_ci		mpt_display_event_info(ioc, pEventReply);
77188c2ecf20Sopenharmony_ci#endif
77198c2ecf20Sopenharmony_ci
77208c2ecf20Sopenharmony_ci	/*
77218c2ecf20Sopenharmony_ci	 *  Do general / base driver event processing
77228c2ecf20Sopenharmony_ci	 */
77238c2ecf20Sopenharmony_ci	switch(event) {
77248c2ecf20Sopenharmony_ci	case MPI_EVENT_EVENT_CHANGE:		/* 0A */
77258c2ecf20Sopenharmony_ci		if (evDataLen) {
77268c2ecf20Sopenharmony_ci			u8 evState = evData0 & 0xFF;
77278c2ecf20Sopenharmony_ci
77288c2ecf20Sopenharmony_ci			/* CHECKME! What if evState unexpectedly says OFF (0)? */
77298c2ecf20Sopenharmony_ci
77308c2ecf20Sopenharmony_ci			/* Update EventState field in cached IocFacts */
77318c2ecf20Sopenharmony_ci			if (ioc->facts.Function) {
77328c2ecf20Sopenharmony_ci				ioc->facts.EventState = evState;
77338c2ecf20Sopenharmony_ci			}
77348c2ecf20Sopenharmony_ci		}
77358c2ecf20Sopenharmony_ci		break;
77368c2ecf20Sopenharmony_ci	case MPI_EVENT_INTEGRATED_RAID:
77378c2ecf20Sopenharmony_ci		mptbase_raid_process_event_data(ioc,
77388c2ecf20Sopenharmony_ci		    (MpiEventDataRaid_t *)pEventReply->Data);
77398c2ecf20Sopenharmony_ci		break;
77408c2ecf20Sopenharmony_ci	default:
77418c2ecf20Sopenharmony_ci		break;
77428c2ecf20Sopenharmony_ci	}
77438c2ecf20Sopenharmony_ci
77448c2ecf20Sopenharmony_ci	/*
77458c2ecf20Sopenharmony_ci	 * Should this event be logged? Events are written sequentially.
77468c2ecf20Sopenharmony_ci	 * When buffer is full, start again at the top.
77478c2ecf20Sopenharmony_ci	 */
77488c2ecf20Sopenharmony_ci	if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
77498c2ecf20Sopenharmony_ci		int idx;
77508c2ecf20Sopenharmony_ci
77518c2ecf20Sopenharmony_ci		idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
77528c2ecf20Sopenharmony_ci
77538c2ecf20Sopenharmony_ci		ioc->events[idx].event = event;
77548c2ecf20Sopenharmony_ci		ioc->events[idx].eventContext = ioc->eventContext;
77558c2ecf20Sopenharmony_ci
77568c2ecf20Sopenharmony_ci		for (ii = 0; ii < 2; ii++) {
77578c2ecf20Sopenharmony_ci			if (ii < evDataLen)
77588c2ecf20Sopenharmony_ci				ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
77598c2ecf20Sopenharmony_ci			else
77608c2ecf20Sopenharmony_ci				ioc->events[idx].data[ii] =  0;
77618c2ecf20Sopenharmony_ci		}
77628c2ecf20Sopenharmony_ci
77638c2ecf20Sopenharmony_ci		ioc->eventContext++;
77648c2ecf20Sopenharmony_ci	}
77658c2ecf20Sopenharmony_ci
77668c2ecf20Sopenharmony_ci
77678c2ecf20Sopenharmony_ci	/*
77688c2ecf20Sopenharmony_ci	 *  Call each currently registered protocol event handler.
77698c2ecf20Sopenharmony_ci	 */
77708c2ecf20Sopenharmony_ci	for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
77718c2ecf20Sopenharmony_ci		if (MptEvHandlers[cb_idx]) {
77728c2ecf20Sopenharmony_ci			devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
77738c2ecf20Sopenharmony_ci			    "Routing Event to event handler #%d\n",
77748c2ecf20Sopenharmony_ci			    ioc->name, cb_idx));
77758c2ecf20Sopenharmony_ci			r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
77768c2ecf20Sopenharmony_ci			handlers++;
77778c2ecf20Sopenharmony_ci		}
77788c2ecf20Sopenharmony_ci	}
77798c2ecf20Sopenharmony_ci	/* FIXME?  Examine results here? */
77808c2ecf20Sopenharmony_ci
77818c2ecf20Sopenharmony_ci	/*
77828c2ecf20Sopenharmony_ci	 *  If needed, send (a single) EventAck.
77838c2ecf20Sopenharmony_ci	 */
77848c2ecf20Sopenharmony_ci	if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
77858c2ecf20Sopenharmony_ci		devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
77868c2ecf20Sopenharmony_ci			"EventAck required\n",ioc->name));
77878c2ecf20Sopenharmony_ci		if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
77888c2ecf20Sopenharmony_ci			devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
77898c2ecf20Sopenharmony_ci					ioc->name, ii));
77908c2ecf20Sopenharmony_ci		}
77918c2ecf20Sopenharmony_ci	}
77928c2ecf20Sopenharmony_ci
77938c2ecf20Sopenharmony_ci	*evHandlers = handlers;
77948c2ecf20Sopenharmony_ci	return r;
77958c2ecf20Sopenharmony_ci}
77968c2ecf20Sopenharmony_ci
77978c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
77988c2ecf20Sopenharmony_ci/**
77998c2ecf20Sopenharmony_ci *	mpt_fc_log_info - Log information returned from Fibre Channel IOC.
78008c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
78018c2ecf20Sopenharmony_ci *	@log_info: U32 LogInfo reply word from the IOC
78028c2ecf20Sopenharmony_ci *
78038c2ecf20Sopenharmony_ci *	Refer to lsi/mpi_log_fc.h.
78048c2ecf20Sopenharmony_ci */
78058c2ecf20Sopenharmony_cistatic void
78068c2ecf20Sopenharmony_cimpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
78078c2ecf20Sopenharmony_ci{
78088c2ecf20Sopenharmony_ci	char *desc = "unknown";
78098c2ecf20Sopenharmony_ci
78108c2ecf20Sopenharmony_ci	switch (log_info & 0xFF000000) {
78118c2ecf20Sopenharmony_ci	case MPI_IOCLOGINFO_FC_INIT_BASE:
78128c2ecf20Sopenharmony_ci		desc = "FCP Initiator";
78138c2ecf20Sopenharmony_ci		break;
78148c2ecf20Sopenharmony_ci	case MPI_IOCLOGINFO_FC_TARGET_BASE:
78158c2ecf20Sopenharmony_ci		desc = "FCP Target";
78168c2ecf20Sopenharmony_ci		break;
78178c2ecf20Sopenharmony_ci	case MPI_IOCLOGINFO_FC_LAN_BASE:
78188c2ecf20Sopenharmony_ci		desc = "LAN";
78198c2ecf20Sopenharmony_ci		break;
78208c2ecf20Sopenharmony_ci	case MPI_IOCLOGINFO_FC_MSG_BASE:
78218c2ecf20Sopenharmony_ci		desc = "MPI Message Layer";
78228c2ecf20Sopenharmony_ci		break;
78238c2ecf20Sopenharmony_ci	case MPI_IOCLOGINFO_FC_LINK_BASE:
78248c2ecf20Sopenharmony_ci		desc = "FC Link";
78258c2ecf20Sopenharmony_ci		break;
78268c2ecf20Sopenharmony_ci	case MPI_IOCLOGINFO_FC_CTX_BASE:
78278c2ecf20Sopenharmony_ci		desc = "Context Manager";
78288c2ecf20Sopenharmony_ci		break;
78298c2ecf20Sopenharmony_ci	case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
78308c2ecf20Sopenharmony_ci		desc = "Invalid Field Offset";
78318c2ecf20Sopenharmony_ci		break;
78328c2ecf20Sopenharmony_ci	case MPI_IOCLOGINFO_FC_STATE_CHANGE:
78338c2ecf20Sopenharmony_ci		desc = "State Change Info";
78348c2ecf20Sopenharmony_ci		break;
78358c2ecf20Sopenharmony_ci	}
78368c2ecf20Sopenharmony_ci
78378c2ecf20Sopenharmony_ci	printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
78388c2ecf20Sopenharmony_ci			ioc->name, log_info, desc, (log_info & 0xFFFFFF));
78398c2ecf20Sopenharmony_ci}
78408c2ecf20Sopenharmony_ci
78418c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
78428c2ecf20Sopenharmony_ci/**
78438c2ecf20Sopenharmony_ci *	mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
78448c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
78458c2ecf20Sopenharmony_ci *	@log_info: U32 LogInfo word from the IOC
78468c2ecf20Sopenharmony_ci *
78478c2ecf20Sopenharmony_ci *	Refer to lsi/sp_log.h.
78488c2ecf20Sopenharmony_ci */
78498c2ecf20Sopenharmony_cistatic void
78508c2ecf20Sopenharmony_cimpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
78518c2ecf20Sopenharmony_ci{
78528c2ecf20Sopenharmony_ci	u32 info = log_info & 0x00FF0000;
78538c2ecf20Sopenharmony_ci	char *desc = "unknown";
78548c2ecf20Sopenharmony_ci
78558c2ecf20Sopenharmony_ci	switch (info) {
78568c2ecf20Sopenharmony_ci	case 0x00010000:
78578c2ecf20Sopenharmony_ci		desc = "bug! MID not found";
78588c2ecf20Sopenharmony_ci		break;
78598c2ecf20Sopenharmony_ci
78608c2ecf20Sopenharmony_ci	case 0x00020000:
78618c2ecf20Sopenharmony_ci		desc = "Parity Error";
78628c2ecf20Sopenharmony_ci		break;
78638c2ecf20Sopenharmony_ci
78648c2ecf20Sopenharmony_ci	case 0x00030000:
78658c2ecf20Sopenharmony_ci		desc = "ASYNC Outbound Overrun";
78668c2ecf20Sopenharmony_ci		break;
78678c2ecf20Sopenharmony_ci
78688c2ecf20Sopenharmony_ci	case 0x00040000:
78698c2ecf20Sopenharmony_ci		desc = "SYNC Offset Error";
78708c2ecf20Sopenharmony_ci		break;
78718c2ecf20Sopenharmony_ci
78728c2ecf20Sopenharmony_ci	case 0x00050000:
78738c2ecf20Sopenharmony_ci		desc = "BM Change";
78748c2ecf20Sopenharmony_ci		break;
78758c2ecf20Sopenharmony_ci
78768c2ecf20Sopenharmony_ci	case 0x00060000:
78778c2ecf20Sopenharmony_ci		desc = "Msg In Overflow";
78788c2ecf20Sopenharmony_ci		break;
78798c2ecf20Sopenharmony_ci
78808c2ecf20Sopenharmony_ci	case 0x00070000:
78818c2ecf20Sopenharmony_ci		desc = "DMA Error";
78828c2ecf20Sopenharmony_ci		break;
78838c2ecf20Sopenharmony_ci
78848c2ecf20Sopenharmony_ci	case 0x00080000:
78858c2ecf20Sopenharmony_ci		desc = "Outbound DMA Overrun";
78868c2ecf20Sopenharmony_ci		break;
78878c2ecf20Sopenharmony_ci
78888c2ecf20Sopenharmony_ci	case 0x00090000:
78898c2ecf20Sopenharmony_ci		desc = "Task Management";
78908c2ecf20Sopenharmony_ci		break;
78918c2ecf20Sopenharmony_ci
78928c2ecf20Sopenharmony_ci	case 0x000A0000:
78938c2ecf20Sopenharmony_ci		desc = "Device Problem";
78948c2ecf20Sopenharmony_ci		break;
78958c2ecf20Sopenharmony_ci
78968c2ecf20Sopenharmony_ci	case 0x000B0000:
78978c2ecf20Sopenharmony_ci		desc = "Invalid Phase Change";
78988c2ecf20Sopenharmony_ci		break;
78998c2ecf20Sopenharmony_ci
79008c2ecf20Sopenharmony_ci	case 0x000C0000:
79018c2ecf20Sopenharmony_ci		desc = "Untagged Table Size";
79028c2ecf20Sopenharmony_ci		break;
79038c2ecf20Sopenharmony_ci
79048c2ecf20Sopenharmony_ci	}
79058c2ecf20Sopenharmony_ci
79068c2ecf20Sopenharmony_ci	printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
79078c2ecf20Sopenharmony_ci}
79088c2ecf20Sopenharmony_ci
79098c2ecf20Sopenharmony_ci/* strings for sas loginfo */
79108c2ecf20Sopenharmony_ci	static char *originator_str[] = {
79118c2ecf20Sopenharmony_ci		"IOP",						/* 00h */
79128c2ecf20Sopenharmony_ci		"PL",						/* 01h */
79138c2ecf20Sopenharmony_ci		"IR"						/* 02h */
79148c2ecf20Sopenharmony_ci	};
79158c2ecf20Sopenharmony_ci	static char *iop_code_str[] = {
79168c2ecf20Sopenharmony_ci		NULL,						/* 00h */
79178c2ecf20Sopenharmony_ci		"Invalid SAS Address",				/* 01h */
79188c2ecf20Sopenharmony_ci		NULL,						/* 02h */
79198c2ecf20Sopenharmony_ci		"Invalid Page",					/* 03h */
79208c2ecf20Sopenharmony_ci		"Diag Message Error",				/* 04h */
79218c2ecf20Sopenharmony_ci		"Task Terminated",				/* 05h */
79228c2ecf20Sopenharmony_ci		"Enclosure Management",				/* 06h */
79238c2ecf20Sopenharmony_ci		"Target Mode"					/* 07h */
79248c2ecf20Sopenharmony_ci	};
79258c2ecf20Sopenharmony_ci	static char *pl_code_str[] = {
79268c2ecf20Sopenharmony_ci		NULL,						/* 00h */
79278c2ecf20Sopenharmony_ci		"Open Failure",					/* 01h */
79288c2ecf20Sopenharmony_ci		"Invalid Scatter Gather List",			/* 02h */
79298c2ecf20Sopenharmony_ci		"Wrong Relative Offset or Frame Length",	/* 03h */
79308c2ecf20Sopenharmony_ci		"Frame Transfer Error",				/* 04h */
79318c2ecf20Sopenharmony_ci		"Transmit Frame Connected Low",			/* 05h */
79328c2ecf20Sopenharmony_ci		"SATA Non-NCQ RW Error Bit Set",		/* 06h */
79338c2ecf20Sopenharmony_ci		"SATA Read Log Receive Data Error",		/* 07h */
79348c2ecf20Sopenharmony_ci		"SATA NCQ Fail All Commands After Error",	/* 08h */
79358c2ecf20Sopenharmony_ci		"SATA Error in Receive Set Device Bit FIS",	/* 09h */
79368c2ecf20Sopenharmony_ci		"Receive Frame Invalid Message",		/* 0Ah */
79378c2ecf20Sopenharmony_ci		"Receive Context Message Valid Error",		/* 0Bh */
79388c2ecf20Sopenharmony_ci		"Receive Frame Current Frame Error",		/* 0Ch */
79398c2ecf20Sopenharmony_ci		"SATA Link Down",				/* 0Dh */
79408c2ecf20Sopenharmony_ci		"Discovery SATA Init W IOS",			/* 0Eh */
79418c2ecf20Sopenharmony_ci		"Config Invalid Page",				/* 0Fh */
79428c2ecf20Sopenharmony_ci		"Discovery SATA Init Timeout",			/* 10h */
79438c2ecf20Sopenharmony_ci		"Reset",					/* 11h */
79448c2ecf20Sopenharmony_ci		"Abort",					/* 12h */
79458c2ecf20Sopenharmony_ci		"IO Not Yet Executed",				/* 13h */
79468c2ecf20Sopenharmony_ci		"IO Executed",					/* 14h */
79478c2ecf20Sopenharmony_ci		"Persistent Reservation Out Not Affiliation "
79488c2ecf20Sopenharmony_ci		    "Owner", 					/* 15h */
79498c2ecf20Sopenharmony_ci		"Open Transmit DMA Abort",			/* 16h */
79508c2ecf20Sopenharmony_ci		"IO Device Missing Delay Retry",		/* 17h */
79518c2ecf20Sopenharmony_ci		"IO Cancelled Due to Receive Error",		/* 18h */
79528c2ecf20Sopenharmony_ci		NULL,						/* 19h */
79538c2ecf20Sopenharmony_ci		NULL,						/* 1Ah */
79548c2ecf20Sopenharmony_ci		NULL,						/* 1Bh */
79558c2ecf20Sopenharmony_ci		NULL,						/* 1Ch */
79568c2ecf20Sopenharmony_ci		NULL,						/* 1Dh */
79578c2ecf20Sopenharmony_ci		NULL,						/* 1Eh */
79588c2ecf20Sopenharmony_ci		NULL,						/* 1Fh */
79598c2ecf20Sopenharmony_ci		"Enclosure Management"				/* 20h */
79608c2ecf20Sopenharmony_ci	};
79618c2ecf20Sopenharmony_ci	static char *ir_code_str[] = {
79628c2ecf20Sopenharmony_ci		"Raid Action Error",				/* 00h */
79638c2ecf20Sopenharmony_ci		NULL,						/* 00h */
79648c2ecf20Sopenharmony_ci		NULL,						/* 01h */
79658c2ecf20Sopenharmony_ci		NULL,						/* 02h */
79668c2ecf20Sopenharmony_ci		NULL,						/* 03h */
79678c2ecf20Sopenharmony_ci		NULL,						/* 04h */
79688c2ecf20Sopenharmony_ci		NULL,						/* 05h */
79698c2ecf20Sopenharmony_ci		NULL,						/* 06h */
79708c2ecf20Sopenharmony_ci		NULL						/* 07h */
79718c2ecf20Sopenharmony_ci	};
79728c2ecf20Sopenharmony_ci	static char *raid_sub_code_str[] = {
79738c2ecf20Sopenharmony_ci		NULL, 						/* 00h */
79748c2ecf20Sopenharmony_ci		"Volume Creation Failed: Data Passed too "
79758c2ecf20Sopenharmony_ci		    "Large", 					/* 01h */
79768c2ecf20Sopenharmony_ci		"Volume Creation Failed: Duplicate Volumes "
79778c2ecf20Sopenharmony_ci		    "Attempted", 				/* 02h */
79788c2ecf20Sopenharmony_ci		"Volume Creation Failed: Max Number "
79798c2ecf20Sopenharmony_ci		    "Supported Volumes Exceeded",		/* 03h */
79808c2ecf20Sopenharmony_ci		"Volume Creation Failed: DMA Error",		/* 04h */
79818c2ecf20Sopenharmony_ci		"Volume Creation Failed: Invalid Volume Type",	/* 05h */
79828c2ecf20Sopenharmony_ci		"Volume Creation Failed: Error Reading "
79838c2ecf20Sopenharmony_ci		    "MFG Page 4", 				/* 06h */
79848c2ecf20Sopenharmony_ci		"Volume Creation Failed: Creating Internal "
79858c2ecf20Sopenharmony_ci		    "Structures", 				/* 07h */
79868c2ecf20Sopenharmony_ci		NULL,						/* 08h */
79878c2ecf20Sopenharmony_ci		NULL,						/* 09h */
79888c2ecf20Sopenharmony_ci		NULL,						/* 0Ah */
79898c2ecf20Sopenharmony_ci		NULL,						/* 0Bh */
79908c2ecf20Sopenharmony_ci		NULL,						/* 0Ch */
79918c2ecf20Sopenharmony_ci		NULL,						/* 0Dh */
79928c2ecf20Sopenharmony_ci		NULL,						/* 0Eh */
79938c2ecf20Sopenharmony_ci		NULL,						/* 0Fh */
79948c2ecf20Sopenharmony_ci		"Activation failed: Already Active Volume", 	/* 10h */
79958c2ecf20Sopenharmony_ci		"Activation failed: Unsupported Volume Type", 	/* 11h */
79968c2ecf20Sopenharmony_ci		"Activation failed: Too Many Active Volumes", 	/* 12h */
79978c2ecf20Sopenharmony_ci		"Activation failed: Volume ID in Use", 		/* 13h */
79988c2ecf20Sopenharmony_ci		"Activation failed: Reported Failure", 		/* 14h */
79998c2ecf20Sopenharmony_ci		"Activation failed: Importing a Volume", 	/* 15h */
80008c2ecf20Sopenharmony_ci		NULL,						/* 16h */
80018c2ecf20Sopenharmony_ci		NULL,						/* 17h */
80028c2ecf20Sopenharmony_ci		NULL,						/* 18h */
80038c2ecf20Sopenharmony_ci		NULL,						/* 19h */
80048c2ecf20Sopenharmony_ci		NULL,						/* 1Ah */
80058c2ecf20Sopenharmony_ci		NULL,						/* 1Bh */
80068c2ecf20Sopenharmony_ci		NULL,						/* 1Ch */
80078c2ecf20Sopenharmony_ci		NULL,						/* 1Dh */
80088c2ecf20Sopenharmony_ci		NULL,						/* 1Eh */
80098c2ecf20Sopenharmony_ci		NULL,						/* 1Fh */
80108c2ecf20Sopenharmony_ci		"Phys Disk failed: Too Many Phys Disks", 	/* 20h */
80118c2ecf20Sopenharmony_ci		"Phys Disk failed: Data Passed too Large",	/* 21h */
80128c2ecf20Sopenharmony_ci		"Phys Disk failed: DMA Error", 			/* 22h */
80138c2ecf20Sopenharmony_ci		"Phys Disk failed: Invalid <channel:id>", 	/* 23h */
80148c2ecf20Sopenharmony_ci		"Phys Disk failed: Creating Phys Disk Config "
80158c2ecf20Sopenharmony_ci		    "Page", 					/* 24h */
80168c2ecf20Sopenharmony_ci		NULL,						/* 25h */
80178c2ecf20Sopenharmony_ci		NULL,						/* 26h */
80188c2ecf20Sopenharmony_ci		NULL,						/* 27h */
80198c2ecf20Sopenharmony_ci		NULL,						/* 28h */
80208c2ecf20Sopenharmony_ci		NULL,						/* 29h */
80218c2ecf20Sopenharmony_ci		NULL,						/* 2Ah */
80228c2ecf20Sopenharmony_ci		NULL,						/* 2Bh */
80238c2ecf20Sopenharmony_ci		NULL,						/* 2Ch */
80248c2ecf20Sopenharmony_ci		NULL,						/* 2Dh */
80258c2ecf20Sopenharmony_ci		NULL,						/* 2Eh */
80268c2ecf20Sopenharmony_ci		NULL,						/* 2Fh */
80278c2ecf20Sopenharmony_ci		"Compatibility Error: IR Disabled",		/* 30h */
80288c2ecf20Sopenharmony_ci		"Compatibility Error: Inquiry Command Failed",	/* 31h */
80298c2ecf20Sopenharmony_ci		"Compatibility Error: Device not Direct Access "
80308c2ecf20Sopenharmony_ci		    "Device ",					/* 32h */
80318c2ecf20Sopenharmony_ci		"Compatibility Error: Removable Device Found",	/* 33h */
80328c2ecf20Sopenharmony_ci		"Compatibility Error: Device SCSI Version not "
80338c2ecf20Sopenharmony_ci		    "2 or Higher", 				/* 34h */
80348c2ecf20Sopenharmony_ci		"Compatibility Error: SATA Device, 48 BIT LBA "
80358c2ecf20Sopenharmony_ci		    "not Supported", 				/* 35h */
80368c2ecf20Sopenharmony_ci		"Compatibility Error: Device doesn't have "
80378c2ecf20Sopenharmony_ci		    "512 Byte Block Sizes", 			/* 36h */
80388c2ecf20Sopenharmony_ci		"Compatibility Error: Volume Type Check Failed", /* 37h */
80398c2ecf20Sopenharmony_ci		"Compatibility Error: Volume Type is "
80408c2ecf20Sopenharmony_ci		    "Unsupported by FW", 			/* 38h */
80418c2ecf20Sopenharmony_ci		"Compatibility Error: Disk Drive too Small for "
80428c2ecf20Sopenharmony_ci		    "use in Volume", 				/* 39h */
80438c2ecf20Sopenharmony_ci		"Compatibility Error: Phys Disk for Create "
80448c2ecf20Sopenharmony_ci		    "Volume not Found", 			/* 3Ah */
80458c2ecf20Sopenharmony_ci		"Compatibility Error: Too Many or too Few "
80468c2ecf20Sopenharmony_ci		    "Disks for Volume Type", 			/* 3Bh */
80478c2ecf20Sopenharmony_ci		"Compatibility Error: Disk stripe Sizes "
80488c2ecf20Sopenharmony_ci		    "Must be 64KB", 				/* 3Ch */
80498c2ecf20Sopenharmony_ci		"Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
80508c2ecf20Sopenharmony_ci	};
80518c2ecf20Sopenharmony_ci
80528c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
80538c2ecf20Sopenharmony_ci/**
80548c2ecf20Sopenharmony_ci *	mpt_sas_log_info - Log information returned from SAS IOC.
80558c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
80568c2ecf20Sopenharmony_ci *	@log_info: U32 LogInfo reply word from the IOC
80578c2ecf20Sopenharmony_ci *	@cb_idx: callback function's handle
80588c2ecf20Sopenharmony_ci *
80598c2ecf20Sopenharmony_ci *	Refer to lsi/mpi_log_sas.h.
80608c2ecf20Sopenharmony_ci **/
80618c2ecf20Sopenharmony_cistatic void
80628c2ecf20Sopenharmony_cimpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info, u8 cb_idx)
80638c2ecf20Sopenharmony_ci{
80648c2ecf20Sopenharmony_ci	union loginfo_type {
80658c2ecf20Sopenharmony_ci		u32	loginfo;
80668c2ecf20Sopenharmony_ci		struct {
80678c2ecf20Sopenharmony_ci			u32	subcode:16;
80688c2ecf20Sopenharmony_ci			u32	code:8;
80698c2ecf20Sopenharmony_ci			u32	originator:4;
80708c2ecf20Sopenharmony_ci			u32	bus_type:4;
80718c2ecf20Sopenharmony_ci		} dw;
80728c2ecf20Sopenharmony_ci	};
80738c2ecf20Sopenharmony_ci	union loginfo_type sas_loginfo;
80748c2ecf20Sopenharmony_ci	char *originator_desc = NULL;
80758c2ecf20Sopenharmony_ci	char *code_desc = NULL;
80768c2ecf20Sopenharmony_ci	char *sub_code_desc = NULL;
80778c2ecf20Sopenharmony_ci
80788c2ecf20Sopenharmony_ci	sas_loginfo.loginfo = log_info;
80798c2ecf20Sopenharmony_ci	if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
80808c2ecf20Sopenharmony_ci	    (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
80818c2ecf20Sopenharmony_ci		return;
80828c2ecf20Sopenharmony_ci
80838c2ecf20Sopenharmony_ci	originator_desc = originator_str[sas_loginfo.dw.originator];
80848c2ecf20Sopenharmony_ci
80858c2ecf20Sopenharmony_ci	switch (sas_loginfo.dw.originator) {
80868c2ecf20Sopenharmony_ci
80878c2ecf20Sopenharmony_ci		case 0:  /* IOP */
80888c2ecf20Sopenharmony_ci			if (sas_loginfo.dw.code <
80898c2ecf20Sopenharmony_ci			    ARRAY_SIZE(iop_code_str))
80908c2ecf20Sopenharmony_ci				code_desc = iop_code_str[sas_loginfo.dw.code];
80918c2ecf20Sopenharmony_ci			break;
80928c2ecf20Sopenharmony_ci		case 1:  /* PL */
80938c2ecf20Sopenharmony_ci			if (sas_loginfo.dw.code <
80948c2ecf20Sopenharmony_ci			    ARRAY_SIZE(pl_code_str))
80958c2ecf20Sopenharmony_ci				code_desc = pl_code_str[sas_loginfo.dw.code];
80968c2ecf20Sopenharmony_ci			break;
80978c2ecf20Sopenharmony_ci		case 2:  /* IR */
80988c2ecf20Sopenharmony_ci			if (sas_loginfo.dw.code >=
80998c2ecf20Sopenharmony_ci			    ARRAY_SIZE(ir_code_str))
81008c2ecf20Sopenharmony_ci				break;
81018c2ecf20Sopenharmony_ci			code_desc = ir_code_str[sas_loginfo.dw.code];
81028c2ecf20Sopenharmony_ci			if (sas_loginfo.dw.subcode >=
81038c2ecf20Sopenharmony_ci			    ARRAY_SIZE(raid_sub_code_str))
81048c2ecf20Sopenharmony_ci				break;
81058c2ecf20Sopenharmony_ci			if (sas_loginfo.dw.code == 0)
81068c2ecf20Sopenharmony_ci				sub_code_desc =
81078c2ecf20Sopenharmony_ci				    raid_sub_code_str[sas_loginfo.dw.subcode];
81088c2ecf20Sopenharmony_ci			break;
81098c2ecf20Sopenharmony_ci		default:
81108c2ecf20Sopenharmony_ci			return;
81118c2ecf20Sopenharmony_ci	}
81128c2ecf20Sopenharmony_ci
81138c2ecf20Sopenharmony_ci	if (sub_code_desc != NULL)
81148c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT
81158c2ecf20Sopenharmony_ci			"LogInfo(0x%08x): Originator={%s}, Code={%s},"
81168c2ecf20Sopenharmony_ci			" SubCode={%s} cb_idx %s\n",
81178c2ecf20Sopenharmony_ci			ioc->name, log_info, originator_desc, code_desc,
81188c2ecf20Sopenharmony_ci			sub_code_desc, MptCallbacksName[cb_idx]);
81198c2ecf20Sopenharmony_ci	else if (code_desc != NULL)
81208c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT
81218c2ecf20Sopenharmony_ci			"LogInfo(0x%08x): Originator={%s}, Code={%s},"
81228c2ecf20Sopenharmony_ci			" SubCode(0x%04x) cb_idx %s\n",
81238c2ecf20Sopenharmony_ci			ioc->name, log_info, originator_desc, code_desc,
81248c2ecf20Sopenharmony_ci			sas_loginfo.dw.subcode, MptCallbacksName[cb_idx]);
81258c2ecf20Sopenharmony_ci	else
81268c2ecf20Sopenharmony_ci		printk(MYIOC_s_INFO_FMT
81278c2ecf20Sopenharmony_ci			"LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
81288c2ecf20Sopenharmony_ci			" SubCode(0x%04x) cb_idx %s\n",
81298c2ecf20Sopenharmony_ci			ioc->name, log_info, originator_desc,
81308c2ecf20Sopenharmony_ci			sas_loginfo.dw.code, sas_loginfo.dw.subcode,
81318c2ecf20Sopenharmony_ci			MptCallbacksName[cb_idx]);
81328c2ecf20Sopenharmony_ci}
81338c2ecf20Sopenharmony_ci
81348c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
81358c2ecf20Sopenharmony_ci/**
81368c2ecf20Sopenharmony_ci *	mpt_iocstatus_info_config - IOCSTATUS information for config pages
81378c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
81388c2ecf20Sopenharmony_ci *	@ioc_status: U32 IOCStatus word from IOC
81398c2ecf20Sopenharmony_ci *	@mf: Pointer to MPT request frame
81408c2ecf20Sopenharmony_ci *
81418c2ecf20Sopenharmony_ci *	Refer to lsi/mpi.h.
81428c2ecf20Sopenharmony_ci **/
81438c2ecf20Sopenharmony_cistatic void
81448c2ecf20Sopenharmony_cimpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
81458c2ecf20Sopenharmony_ci{
81468c2ecf20Sopenharmony_ci	Config_t *pReq = (Config_t *)mf;
81478c2ecf20Sopenharmony_ci	char extend_desc[EVENT_DESCR_STR_SZ];
81488c2ecf20Sopenharmony_ci	char *desc = NULL;
81498c2ecf20Sopenharmony_ci	u32 form;
81508c2ecf20Sopenharmony_ci	u8 page_type;
81518c2ecf20Sopenharmony_ci
81528c2ecf20Sopenharmony_ci	if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
81538c2ecf20Sopenharmony_ci		page_type = pReq->ExtPageType;
81548c2ecf20Sopenharmony_ci	else
81558c2ecf20Sopenharmony_ci		page_type = pReq->Header.PageType;
81568c2ecf20Sopenharmony_ci
81578c2ecf20Sopenharmony_ci	/*
81588c2ecf20Sopenharmony_ci	 * ignore invalid page messages for GET_NEXT_HANDLE
81598c2ecf20Sopenharmony_ci	 */
81608c2ecf20Sopenharmony_ci	form = le32_to_cpu(pReq->PageAddress);
81618c2ecf20Sopenharmony_ci	if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
81628c2ecf20Sopenharmony_ci		if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
81638c2ecf20Sopenharmony_ci		    page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
81648c2ecf20Sopenharmony_ci		    page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
81658c2ecf20Sopenharmony_ci			if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
81668c2ecf20Sopenharmony_ci				MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
81678c2ecf20Sopenharmony_ci				return;
81688c2ecf20Sopenharmony_ci		}
81698c2ecf20Sopenharmony_ci		if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
81708c2ecf20Sopenharmony_ci			if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
81718c2ecf20Sopenharmony_ci				MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
81728c2ecf20Sopenharmony_ci				return;
81738c2ecf20Sopenharmony_ci	}
81748c2ecf20Sopenharmony_ci
81758c2ecf20Sopenharmony_ci	snprintf(extend_desc, EVENT_DESCR_STR_SZ,
81768c2ecf20Sopenharmony_ci	    "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
81778c2ecf20Sopenharmony_ci	    page_type, pReq->Header.PageNumber, pReq->Action, form);
81788c2ecf20Sopenharmony_ci
81798c2ecf20Sopenharmony_ci	switch (ioc_status) {
81808c2ecf20Sopenharmony_ci
81818c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
81828c2ecf20Sopenharmony_ci		desc = "Config Page Invalid Action";
81838c2ecf20Sopenharmony_ci		break;
81848c2ecf20Sopenharmony_ci
81858c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_CONFIG_INVALID_TYPE:   /* 0x0021 */
81868c2ecf20Sopenharmony_ci		desc = "Config Page Invalid Type";
81878c2ecf20Sopenharmony_ci		break;
81888c2ecf20Sopenharmony_ci
81898c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_CONFIG_INVALID_PAGE:   /* 0x0022 */
81908c2ecf20Sopenharmony_ci		desc = "Config Page Invalid Page";
81918c2ecf20Sopenharmony_ci		break;
81928c2ecf20Sopenharmony_ci
81938c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_CONFIG_INVALID_DATA:   /* 0x0023 */
81948c2ecf20Sopenharmony_ci		desc = "Config Page Invalid Data";
81958c2ecf20Sopenharmony_ci		break;
81968c2ecf20Sopenharmony_ci
81978c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS:    /* 0x0024 */
81988c2ecf20Sopenharmony_ci		desc = "Config Page No Defaults";
81998c2ecf20Sopenharmony_ci		break;
82008c2ecf20Sopenharmony_ci
82018c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_CONFIG_CANT_COMMIT:    /* 0x0025 */
82028c2ecf20Sopenharmony_ci		desc = "Config Page Can't Commit";
82038c2ecf20Sopenharmony_ci		break;
82048c2ecf20Sopenharmony_ci	}
82058c2ecf20Sopenharmony_ci
82068c2ecf20Sopenharmony_ci	if (!desc)
82078c2ecf20Sopenharmony_ci		return;
82088c2ecf20Sopenharmony_ci
82098c2ecf20Sopenharmony_ci	dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
82108c2ecf20Sopenharmony_ci	    ioc->name, ioc_status, desc, extend_desc));
82118c2ecf20Sopenharmony_ci}
82128c2ecf20Sopenharmony_ci
82138c2ecf20Sopenharmony_ci/**
82148c2ecf20Sopenharmony_ci *	mpt_iocstatus_info - IOCSTATUS information returned from IOC.
82158c2ecf20Sopenharmony_ci *	@ioc: Pointer to MPT_ADAPTER structure
82168c2ecf20Sopenharmony_ci *	@ioc_status: U32 IOCStatus word from IOC
82178c2ecf20Sopenharmony_ci *	@mf: Pointer to MPT request frame
82188c2ecf20Sopenharmony_ci *
82198c2ecf20Sopenharmony_ci *	Refer to lsi/mpi.h.
82208c2ecf20Sopenharmony_ci **/
82218c2ecf20Sopenharmony_cistatic void
82228c2ecf20Sopenharmony_cimpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
82238c2ecf20Sopenharmony_ci{
82248c2ecf20Sopenharmony_ci	u32 status = ioc_status & MPI_IOCSTATUS_MASK;
82258c2ecf20Sopenharmony_ci	char *desc = NULL;
82268c2ecf20Sopenharmony_ci
82278c2ecf20Sopenharmony_ci	switch (status) {
82288c2ecf20Sopenharmony_ci
82298c2ecf20Sopenharmony_ci/****************************************************************************/
82308c2ecf20Sopenharmony_ci/*  Common IOCStatus values for all replies                                 */
82318c2ecf20Sopenharmony_ci/****************************************************************************/
82328c2ecf20Sopenharmony_ci
82338c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
82348c2ecf20Sopenharmony_ci		desc = "Invalid Function";
82358c2ecf20Sopenharmony_ci		break;
82368c2ecf20Sopenharmony_ci
82378c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_BUSY: /* 0x0002 */
82388c2ecf20Sopenharmony_ci		desc = "Busy";
82398c2ecf20Sopenharmony_ci		break;
82408c2ecf20Sopenharmony_ci
82418c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
82428c2ecf20Sopenharmony_ci		desc = "Invalid SGL";
82438c2ecf20Sopenharmony_ci		break;
82448c2ecf20Sopenharmony_ci
82458c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
82468c2ecf20Sopenharmony_ci		desc = "Internal Error";
82478c2ecf20Sopenharmony_ci		break;
82488c2ecf20Sopenharmony_ci
82498c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
82508c2ecf20Sopenharmony_ci		desc = "Reserved";
82518c2ecf20Sopenharmony_ci		break;
82528c2ecf20Sopenharmony_ci
82538c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
82548c2ecf20Sopenharmony_ci		desc = "Insufficient Resources";
82558c2ecf20Sopenharmony_ci		break;
82568c2ecf20Sopenharmony_ci
82578c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
82588c2ecf20Sopenharmony_ci		desc = "Invalid Field";
82598c2ecf20Sopenharmony_ci		break;
82608c2ecf20Sopenharmony_ci
82618c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
82628c2ecf20Sopenharmony_ci		desc = "Invalid State";
82638c2ecf20Sopenharmony_ci		break;
82648c2ecf20Sopenharmony_ci
82658c2ecf20Sopenharmony_ci/****************************************************************************/
82668c2ecf20Sopenharmony_ci/*  Config IOCStatus values                                                 */
82678c2ecf20Sopenharmony_ci/****************************************************************************/
82688c2ecf20Sopenharmony_ci
82698c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
82708c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_CONFIG_INVALID_TYPE:   /* 0x0021 */
82718c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_CONFIG_INVALID_PAGE:   /* 0x0022 */
82728c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_CONFIG_INVALID_DATA:   /* 0x0023 */
82738c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS:    /* 0x0024 */
82748c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_CONFIG_CANT_COMMIT:    /* 0x0025 */
82758c2ecf20Sopenharmony_ci		mpt_iocstatus_info_config(ioc, status, mf);
82768c2ecf20Sopenharmony_ci		break;
82778c2ecf20Sopenharmony_ci
82788c2ecf20Sopenharmony_ci/****************************************************************************/
82798c2ecf20Sopenharmony_ci/*  SCSIIO Reply (SPI, FCP, SAS) initiator values                           */
82808c2ecf20Sopenharmony_ci/*                                                                          */
82818c2ecf20Sopenharmony_ci/*  Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
82828c2ecf20Sopenharmony_ci/*                                                                          */
82838c2ecf20Sopenharmony_ci/****************************************************************************/
82848c2ecf20Sopenharmony_ci
82858c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
82868c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
82878c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
82888c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
82898c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
82908c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
82918c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
82928c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
82938c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
82948c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
82958c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
82968c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
82978c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
82988c2ecf20Sopenharmony_ci		break;
82998c2ecf20Sopenharmony_ci
83008c2ecf20Sopenharmony_ci/****************************************************************************/
83018c2ecf20Sopenharmony_ci/*  SCSI Target values                                                      */
83028c2ecf20Sopenharmony_ci/****************************************************************************/
83038c2ecf20Sopenharmony_ci
83048c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
83058c2ecf20Sopenharmony_ci		desc = "Target: Priority IO";
83068c2ecf20Sopenharmony_ci		break;
83078c2ecf20Sopenharmony_ci
83088c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
83098c2ecf20Sopenharmony_ci		desc = "Target: Invalid Port";
83108c2ecf20Sopenharmony_ci		break;
83118c2ecf20Sopenharmony_ci
83128c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
83138c2ecf20Sopenharmony_ci		desc = "Target Invalid IO Index:";
83148c2ecf20Sopenharmony_ci		break;
83158c2ecf20Sopenharmony_ci
83168c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
83178c2ecf20Sopenharmony_ci		desc = "Target: Aborted";
83188c2ecf20Sopenharmony_ci		break;
83198c2ecf20Sopenharmony_ci
83208c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
83218c2ecf20Sopenharmony_ci		desc = "Target: No Conn Retryable";
83228c2ecf20Sopenharmony_ci		break;
83238c2ecf20Sopenharmony_ci
83248c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
83258c2ecf20Sopenharmony_ci		desc = "Target: No Connection";
83268c2ecf20Sopenharmony_ci		break;
83278c2ecf20Sopenharmony_ci
83288c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
83298c2ecf20Sopenharmony_ci		desc = "Target: Transfer Count Mismatch";
83308c2ecf20Sopenharmony_ci		break;
83318c2ecf20Sopenharmony_ci
83328c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
83338c2ecf20Sopenharmony_ci		desc = "Target: STS Data not Sent";
83348c2ecf20Sopenharmony_ci		break;
83358c2ecf20Sopenharmony_ci
83368c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
83378c2ecf20Sopenharmony_ci		desc = "Target: Data Offset Error";
83388c2ecf20Sopenharmony_ci		break;
83398c2ecf20Sopenharmony_ci
83408c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
83418c2ecf20Sopenharmony_ci		desc = "Target: Too Much Write Data";
83428c2ecf20Sopenharmony_ci		break;
83438c2ecf20Sopenharmony_ci
83448c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
83458c2ecf20Sopenharmony_ci		desc = "Target: IU Too Short";
83468c2ecf20Sopenharmony_ci		break;
83478c2ecf20Sopenharmony_ci
83488c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
83498c2ecf20Sopenharmony_ci		desc = "Target: ACK NAK Timeout";
83508c2ecf20Sopenharmony_ci		break;
83518c2ecf20Sopenharmony_ci
83528c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
83538c2ecf20Sopenharmony_ci		desc = "Target: Nak Received";
83548c2ecf20Sopenharmony_ci		break;
83558c2ecf20Sopenharmony_ci
83568c2ecf20Sopenharmony_ci/****************************************************************************/
83578c2ecf20Sopenharmony_ci/*  Fibre Channel Direct Access values                                      */
83588c2ecf20Sopenharmony_ci/****************************************************************************/
83598c2ecf20Sopenharmony_ci
83608c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
83618c2ecf20Sopenharmony_ci		desc = "FC: Aborted";
83628c2ecf20Sopenharmony_ci		break;
83638c2ecf20Sopenharmony_ci
83648c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
83658c2ecf20Sopenharmony_ci		desc = "FC: RX ID Invalid";
83668c2ecf20Sopenharmony_ci		break;
83678c2ecf20Sopenharmony_ci
83688c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
83698c2ecf20Sopenharmony_ci		desc = "FC: DID Invalid";
83708c2ecf20Sopenharmony_ci		break;
83718c2ecf20Sopenharmony_ci
83728c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
83738c2ecf20Sopenharmony_ci		desc = "FC: Node Logged Out";
83748c2ecf20Sopenharmony_ci		break;
83758c2ecf20Sopenharmony_ci
83768c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
83778c2ecf20Sopenharmony_ci		desc = "FC: Exchange Canceled";
83788c2ecf20Sopenharmony_ci		break;
83798c2ecf20Sopenharmony_ci
83808c2ecf20Sopenharmony_ci/****************************************************************************/
83818c2ecf20Sopenharmony_ci/*  LAN values                                                              */
83828c2ecf20Sopenharmony_ci/****************************************************************************/
83838c2ecf20Sopenharmony_ci
83848c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
83858c2ecf20Sopenharmony_ci		desc = "LAN: Device not Found";
83868c2ecf20Sopenharmony_ci		break;
83878c2ecf20Sopenharmony_ci
83888c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
83898c2ecf20Sopenharmony_ci		desc = "LAN: Device Failure";
83908c2ecf20Sopenharmony_ci		break;
83918c2ecf20Sopenharmony_ci
83928c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
83938c2ecf20Sopenharmony_ci		desc = "LAN: Transmit Error";
83948c2ecf20Sopenharmony_ci		break;
83958c2ecf20Sopenharmony_ci
83968c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
83978c2ecf20Sopenharmony_ci		desc = "LAN: Transmit Aborted";
83988c2ecf20Sopenharmony_ci		break;
83998c2ecf20Sopenharmony_ci
84008c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
84018c2ecf20Sopenharmony_ci		desc = "LAN: Receive Error";
84028c2ecf20Sopenharmony_ci		break;
84038c2ecf20Sopenharmony_ci
84048c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
84058c2ecf20Sopenharmony_ci		desc = "LAN: Receive Aborted";
84068c2ecf20Sopenharmony_ci		break;
84078c2ecf20Sopenharmony_ci
84088c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
84098c2ecf20Sopenharmony_ci		desc = "LAN: Partial Packet";
84108c2ecf20Sopenharmony_ci		break;
84118c2ecf20Sopenharmony_ci
84128c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
84138c2ecf20Sopenharmony_ci		desc = "LAN: Canceled";
84148c2ecf20Sopenharmony_ci		break;
84158c2ecf20Sopenharmony_ci
84168c2ecf20Sopenharmony_ci/****************************************************************************/
84178c2ecf20Sopenharmony_ci/*  Serial Attached SCSI values                                             */
84188c2ecf20Sopenharmony_ci/****************************************************************************/
84198c2ecf20Sopenharmony_ci
84208c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
84218c2ecf20Sopenharmony_ci		desc = "SAS: SMP Request Failed";
84228c2ecf20Sopenharmony_ci		break;
84238c2ecf20Sopenharmony_ci
84248c2ecf20Sopenharmony_ci	case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
84258c2ecf20Sopenharmony_ci		desc = "SAS: SMP Data Overrun";
84268c2ecf20Sopenharmony_ci		break;
84278c2ecf20Sopenharmony_ci
84288c2ecf20Sopenharmony_ci	default:
84298c2ecf20Sopenharmony_ci		desc = "Others";
84308c2ecf20Sopenharmony_ci		break;
84318c2ecf20Sopenharmony_ci	}
84328c2ecf20Sopenharmony_ci
84338c2ecf20Sopenharmony_ci	if (!desc)
84348c2ecf20Sopenharmony_ci		return;
84358c2ecf20Sopenharmony_ci
84368c2ecf20Sopenharmony_ci	dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
84378c2ecf20Sopenharmony_ci	    ioc->name, status, desc));
84388c2ecf20Sopenharmony_ci}
84398c2ecf20Sopenharmony_ci
84408c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
84418c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_attach);
84428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_detach);
84438c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
84448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_resume);
84458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_suspend);
84468c2ecf20Sopenharmony_ci#endif
84478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ioc_list);
84488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_register);
84498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_deregister);
84508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_event_register);
84518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_event_deregister);
84528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_reset_register);
84538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_reset_deregister);
84548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_device_driver_register);
84558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_device_driver_deregister);
84568c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_get_msg_frame);
84578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_put_msg_frame);
84588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
84598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_free_msg_frame);
84608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_send_handshake_request);
84618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_verify_adapter);
84628c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_GetIocState);
84638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_print_ioc_summary);
84648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_HardResetHandler);
84658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_config);
84668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_findImVolumes);
84678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_alloc_fw_memory);
84688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_free_fw_memory);
84698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mptbase_sas_persist_operation);
84708c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
84718c2ecf20Sopenharmony_ci
84728c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
84738c2ecf20Sopenharmony_ci/**
84748c2ecf20Sopenharmony_ci *	fusion_init - Fusion MPT base driver initialization routine.
84758c2ecf20Sopenharmony_ci *
84768c2ecf20Sopenharmony_ci *	Returns 0 for success, non-zero for failure.
84778c2ecf20Sopenharmony_ci */
84788c2ecf20Sopenharmony_cistatic int __init
84798c2ecf20Sopenharmony_cifusion_init(void)
84808c2ecf20Sopenharmony_ci{
84818c2ecf20Sopenharmony_ci	u8 cb_idx;
84828c2ecf20Sopenharmony_ci
84838c2ecf20Sopenharmony_ci	show_mptmod_ver(my_NAME, my_VERSION);
84848c2ecf20Sopenharmony_ci	printk(KERN_INFO COPYRIGHT "\n");
84858c2ecf20Sopenharmony_ci
84868c2ecf20Sopenharmony_ci	for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
84878c2ecf20Sopenharmony_ci		MptCallbacks[cb_idx] = NULL;
84888c2ecf20Sopenharmony_ci		MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
84898c2ecf20Sopenharmony_ci		MptEvHandlers[cb_idx] = NULL;
84908c2ecf20Sopenharmony_ci		MptResetHandlers[cb_idx] = NULL;
84918c2ecf20Sopenharmony_ci	}
84928c2ecf20Sopenharmony_ci
84938c2ecf20Sopenharmony_ci	/*  Register ourselves (mptbase) in order to facilitate
84948c2ecf20Sopenharmony_ci	 *  EventNotification handling.
84958c2ecf20Sopenharmony_ci	 */
84968c2ecf20Sopenharmony_ci	mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER,
84978c2ecf20Sopenharmony_ci	    "mptbase_reply");
84988c2ecf20Sopenharmony_ci
84998c2ecf20Sopenharmony_ci	/* Register for hard reset handling callbacks.
85008c2ecf20Sopenharmony_ci	 */
85018c2ecf20Sopenharmony_ci	mpt_reset_register(mpt_base_index, mpt_ioc_reset);
85028c2ecf20Sopenharmony_ci
85038c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
85048c2ecf20Sopenharmony_ci	(void) procmpt_create();
85058c2ecf20Sopenharmony_ci#endif
85068c2ecf20Sopenharmony_ci	return 0;
85078c2ecf20Sopenharmony_ci}
85088c2ecf20Sopenharmony_ci
85098c2ecf20Sopenharmony_ci/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
85108c2ecf20Sopenharmony_ci/**
85118c2ecf20Sopenharmony_ci *	fusion_exit - Perform driver unload cleanup.
85128c2ecf20Sopenharmony_ci *
85138c2ecf20Sopenharmony_ci *	This routine frees all resources associated with each MPT adapter
85148c2ecf20Sopenharmony_ci *	and removes all %MPT_PROCFS_MPTBASEDIR entries.
85158c2ecf20Sopenharmony_ci */
85168c2ecf20Sopenharmony_cistatic void __exit
85178c2ecf20Sopenharmony_cifusion_exit(void)
85188c2ecf20Sopenharmony_ci{
85198c2ecf20Sopenharmony_ci
85208c2ecf20Sopenharmony_ci	mpt_reset_deregister(mpt_base_index);
85218c2ecf20Sopenharmony_ci
85228c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
85238c2ecf20Sopenharmony_ci	procmpt_destroy();
85248c2ecf20Sopenharmony_ci#endif
85258c2ecf20Sopenharmony_ci}
85268c2ecf20Sopenharmony_ci
85278c2ecf20Sopenharmony_cimodule_init(fusion_init);
85288c2ecf20Sopenharmony_cimodule_exit(fusion_exit);
8529