diff --git a/sys/dev/mpi3mr/mpi/mpi30_api.h b/sys/dev/mpi3mr/mpi/mpi30_api.h new file mode 100644 index 000000000000..aa7b54ec470e --- /dev/null +++ b/sys/dev/mpi3mr/mpi/mpi30_api.h @@ -0,0 +1,57 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2016-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + * + */ + +#ifndef MPI30_API_H +#define MPI30_API_H 1 + +#include "mpi30_type.h" +#include "mpi30_transport.h" +#include "mpi30_cnfg.h" +#include "mpi30_image.h" +#include "mpi30_init.h" +#include "mpi30_ioc.h" +#include "mpi30_pci.h" +#include "mpi30_raid.h" +#include "mpi30_sas.h" +#include "mpi30_targ.h" +#include "mpi30_tool.h" + +#endif /* MPI30_API_H */ diff --git a/sys/dev/mpi3mr/mpi/mpi30_cnfg.h b/sys/dev/mpi3mr/mpi/mpi30_cnfg.h new file mode 100644 index 000000000000..d1ae2ebfa372 --- /dev/null +++ b/sys/dev/mpi3mr/mpi/mpi30_cnfg.h @@ -0,0 +1,3839 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2016-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + * + */ + +#ifndef MPI30_CNFG_H +#define MPI30_CNFG_H 1 + +/***************************************************************************** + * Configuration Page Types * + ****************************************************************************/ +#define MPI3_CONFIG_PAGETYPE_IO_UNIT (0x00) +#define MPI3_CONFIG_PAGETYPE_MANUFACTURING (0x01) +#define MPI3_CONFIG_PAGETYPE_IOC (0x02) +#define MPI3_CONFIG_PAGETYPE_DRIVER (0x03) +#define MPI3_CONFIG_PAGETYPE_SECURITY (0x04) +#define MPI3_CONFIG_PAGETYPE_ENCLOSURE (0x11) +#define MPI3_CONFIG_PAGETYPE_DEVICE (0x12) +#define MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT (0x20) +#define MPI3_CONFIG_PAGETYPE_SAS_EXPANDER (0x21) +#define MPI3_CONFIG_PAGETYPE_SAS_PHY (0x23) +#define MPI3_CONFIG_PAGETYPE_SAS_PORT (0x24) +#define MPI3_CONFIG_PAGETYPE_PCIE_IO_UNIT (0x30) +#define MPI3_CONFIG_PAGETYPE_PCIE_SWITCH (0x31) +#define MPI3_CONFIG_PAGETYPE_PCIE_LINK (0x33) + +/***************************************************************************** + * Configuration Page Attributes * + ****************************************************************************/ +#define MPI3_CONFIG_PAGEATTR_MASK (0xF0) +#define MPI3_CONFIG_PAGEATTR_READ_ONLY (0x00) +#define MPI3_CONFIG_PAGEATTR_CHANGEABLE (0x10) +#define MPI3_CONFIG_PAGEATTR_PERSISTENT (0x20) + +/***************************************************************************** + * Configuration Page Actions * + ****************************************************************************/ +#define MPI3_CONFIG_ACTION_PAGE_HEADER (0x00) +#define MPI3_CONFIG_ACTION_READ_DEFAULT (0x01) +#define MPI3_CONFIG_ACTION_READ_CURRENT (0x02) +#define MPI3_CONFIG_ACTION_WRITE_CURRENT (0x03) +#define MPI3_CONFIG_ACTION_READ_PERSISTENT (0x04) +#define MPI3_CONFIG_ACTION_WRITE_PERSISTENT (0x05) + +/***************************************************************************** + * Configuration Page Addressing * + ****************************************************************************/ + +/**** Device PageAddress Format ****/ +#define MPI3_DEVICE_PGAD_FORM_MASK (0xF0000000) +#define MPI3_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI3_DEVICE_PGAD_FORM_HANDLE (0x20000000) +#define MPI3_DEVICE_PGAD_HANDLE_MASK (0x0000FFFF) + +/**** SAS Expander PageAddress Format ****/ +#define MPI3_SAS_EXPAND_PGAD_FORM_MASK (0xF0000000) +#define MPI3_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM (0x10000000) +#define MPI3_SAS_EXPAND_PGAD_FORM_HANDLE (0x20000000) +#define MPI3_SAS_EXPAND_PGAD_PHYNUM_MASK (0x00FF0000) +#define MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT (16) +#define MPI3_SAS_EXPAND_PGAD_HANDLE_MASK (0x0000FFFF) + +/**** SAS Phy PageAddress Format ****/ +#define MPI3_SAS_PHY_PGAD_FORM_MASK (0xF0000000) +#define MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER (0x00000000) +#define MPI3_SAS_PHY_PGAD_PHY_NUMBER_MASK (0x000000FF) + +/**** SAS Port PageAddress Format ****/ +#define MPI3_SASPORT_PGAD_FORM_MASK (0xF0000000) +#define MPI3_SASPORT_PGAD_FORM_GET_NEXT_PORT (0x00000000) +#define MPI3_SASPORT_PGAD_FORM_PORT_NUM (0x10000000) +#define MPI3_SASPORT_PGAD_PORT_NUMBER_MASK (0x000000FF) + +/**** Enclosure PageAddress Format ****/ +#define MPI3_ENCLOS_PGAD_FORM_MASK (0xF0000000) +#define MPI3_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI3_ENCLOS_PGAD_FORM_HANDLE (0x10000000) +#define MPI3_ENCLOS_PGAD_HANDLE_MASK (0x0000FFFF) + +/**** PCIe Switch PageAddress Format ****/ +#define MPI3_PCIE_SWITCH_PGAD_FORM_MASK (0xF0000000) +#define MPI3_PCIE_SWITCH_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI3_PCIE_SWITCH_PGAD_FORM_HANDLE_PORT_NUM (0x10000000) +#define MPI3_PCIE_SWITCH_PGAD_FORM_HANDLE (0x20000000) +#define MPI3_PCIE_SWITCH_PGAD_PORTNUM_MASK (0x00FF0000) +#define MPI3_PCIE_SWITCH_PGAD_PORTNUM_SHIFT (16) +#define MPI3_PCIE_SWITCH_PGAD_HANDLE_MASK (0x0000FFFF) + +/**** PCIe Link PageAddress Format ****/ +#define MPI3_PCIE_LINK_PGAD_FORM_MASK (0xF0000000) +#define MPI3_PCIE_LINK_PGAD_FORM_GET_NEXT_LINK (0x00000000) +#define MPI3_PCIE_LINK_PGAD_FORM_LINK_NUM (0x10000000) +#define MPI3_PCIE_LINK_PGAD_LINKNUM_MASK (0x000000FF) + +/**** Security PageAddress Format ****/ +#define MPI3_SECURITY_PGAD_FORM_MASK (0xF0000000) +#define MPI3_SECURITY_PGAD_FORM_GET_NEXT_SLOT (0x00000000) +#define MPI3_SECURITY_PGAD_FORM_SLOT_NUM (0x10000000) +#define MPI3_SECURITY_PGAD_SLOT_GROUP_MASK (0x0000FF00) +#define MPI3_SECURITY_PGAD_SLOT_GROUP_SHIFT (8) +#define MPI3_SECURITY_PGAD_SLOT_MASK (0x000000FF) + +/***************************************************************************** + * Configuration Request Message * + ****************************************************************************/ +typedef struct _MPI3_CONFIG_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U8 PageVersion; /* 0x0C */ + U8 PageNumber; /* 0x0D */ + U8 PageType; /* 0x0E */ + U8 Action; /* 0x0F */ + U32 PageAddress; /* 0x10 */ + U16 PageLength; /* 0x14 */ + U16 Reserved16; /* 0x16 */ + U32 Reserved18[2]; /* 0x18 */ + MPI3_SGE_UNION SGL; /* 0x20 */ +} MPI3_CONFIG_REQUEST, MPI3_POINTER PTR_MPI3_CONFIG_REQUEST, + Mpi3ConfigRequest_t, MPI3_POINTER pMpi3ConfigRequest_t; + +/***************************************************************************** + * Configuration Pages * + ****************************************************************************/ + +/***************************************************************************** + * Configuration Page Header * + ****************************************************************************/ +typedef struct _MPI3_CONFIG_PAGE_HEADER +{ + U8 PageVersion; /* 0x00 */ + U8 Reserved01; /* 0x01 */ + U8 PageNumber; /* 0x02 */ + U8 PageAttribute; /* 0x03 */ + U16 PageLength; /* 0x04 */ + U8 PageType; /* 0x06 */ + U8 Reserved07; /* 0x07 */ +} MPI3_CONFIG_PAGE_HEADER, MPI3_POINTER PTR_MPI3_CONFIG_PAGE_HEADER, + Mpi3ConfigPageHeader_t, MPI3_POINTER pMpi3ConfigPageHeader_t; + +/***************************************************************************** + * Common definitions used by Configuration Pages * + ****************************************************************************/ + +/**** Defines for Negotiated Link Rates ****/ +#define MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK (0xF0) +#define MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT (4) +#define MPI3_SAS_NEG_LINK_RATE_PHYSICAL_MASK (0x0F) +#define MPI3_SAS_NEG_LINK_RATE_PHYSICAL_SHIFT (0) +/*** Below defines are used in both the PhysicalLinkRate and ***/ +/*** LogicalLinkRate fields above. ***/ +/*** (by applying the proper _SHIFT value) ***/ +#define MPI3_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE (0x00) +#define MPI3_SAS_NEG_LINK_RATE_PHY_DISABLED (0x01) +#define MPI3_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED (0x02) +#define MPI3_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE (0x03) +#define MPI3_SAS_NEG_LINK_RATE_PORT_SELECTOR (0x04) +#define MPI3_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS (0x05) +#define MPI3_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY (0x06) +#define MPI3_SAS_NEG_LINK_RATE_1_5 (0x08) +#define MPI3_SAS_NEG_LINK_RATE_3_0 (0x09) +#define MPI3_SAS_NEG_LINK_RATE_6_0 (0x0A) +#define MPI3_SAS_NEG_LINK_RATE_12_0 (0x0B) +#define MPI3_SAS_NEG_LINK_RATE_22_5 (0x0C) + +/**** Defines for the AttachedPhyInfo field ****/ +#define MPI3_SAS_APHYINFO_INSIDE_ZPSDS_PERSISTENT (0x00000040) +#define MPI3_SAS_APHYINFO_REQUESTED_INSIDE_ZPSDS (0x00000020) +#define MPI3_SAS_APHYINFO_BREAK_REPLY_CAPABLE (0x00000010) + +#define MPI3_SAS_APHYINFO_REASON_MASK (0x0000000F) +#define MPI3_SAS_APHYINFO_REASON_UNKNOWN (0x00000000) +#define MPI3_SAS_APHYINFO_REASON_POWER_ON (0x00000001) +#define MPI3_SAS_APHYINFO_REASON_HARD_RESET (0x00000002) +#define MPI3_SAS_APHYINFO_REASON_SMP_PHY_CONTROL (0x00000003) +#define MPI3_SAS_APHYINFO_REASON_LOSS_OF_SYNC (0x00000004) +#define MPI3_SAS_APHYINFO_REASON_MULTIPLEXING_SEQ (0x00000005) +#define MPI3_SAS_APHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00000006) +#define MPI3_SAS_APHYINFO_REASON_BREAK_TIMEOUT (0x00000007) +#define MPI3_SAS_APHYINFO_REASON_PHY_TEST_STOPPED (0x00000008) +#define MPI3_SAS_APHYINFO_REASON_EXP_REDUCED_FUNC (0x00000009) + +/**** Defines for the PhyInfo field ****/ +#define MPI3_SAS_PHYINFO_STATUS_MASK (0xC0000000) +#define MPI3_SAS_PHYINFO_STATUS_SHIFT (30) +#define MPI3_SAS_PHYINFO_STATUS_ACCESSIBLE (0x00000000) +#define MPI3_SAS_PHYINFO_STATUS_NOT_EXIST (0x40000000) +#define MPI3_SAS_PHYINFO_STATUS_VACANT (0x80000000) + +#define MPI3_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000) +#define MPI3_SAS_PHYINFO_PHY_POWER_CONDITION_ACTIVE (0x00000000) +#define MPI3_SAS_PHYINFO_PHY_POWER_CONDITION_PARTIAL (0x08000000) +#define MPI3_SAS_PHYINFO_PHY_POWER_CONDITION_SLUMBER (0x10000000) + +#define MPI3_SAS_PHYINFO_REQUESTED_INSIDE_ZPSDS_CHANGED_MASK (0x04000000) +#define MPI3_SAS_PHYINFO_REQUESTED_INSIDE_ZPSDS_CHANGED_SHIFT (26) +#define MPI3_SAS_PHYINFO_INSIDE_ZPSDS_PERSISTENT_MASK (0x02000000) +#define MPI3_SAS_PHYINFO_INSIDE_ZPSDS_PERSISTENT_SHIFT (25) +#define MPI3_SAS_PHYINFO_REQUESTED_INSIDE_ZPSDS_MASK (0x01000000) +#define MPI3_SAS_PHYINFO_REQUESTED_INSIDE_ZPSDS_SHIFT (24) + +#define MPI3_SAS_PHYINFO_ZONE_GROUP_PERSISTENT (0x00400000) +#define MPI3_SAS_PHYINFO_INSIDE_ZPSDS_WITHIN (0x00200000) +#define MPI3_SAS_PHYINFO_ZONING_ENABLED (0x00100000) + +#define MPI3_SAS_PHYINFO_REASON_MASK (0x000F0000) +#define MPI3_SAS_PHYINFO_REASON_UNKNOWN (0x00000000) +#define MPI3_SAS_PHYINFO_REASON_POWER_ON (0x00010000) +#define MPI3_SAS_PHYINFO_REASON_HARD_RESET (0x00020000) +#define MPI3_SAS_PHYINFO_REASON_SMP_PHY_CONTROL (0x00030000) +#define MPI3_SAS_PHYINFO_REASON_LOSS_OF_SYNC (0x00040000) +#define MPI3_SAS_PHYINFO_REASON_MULTIPLEXING_SEQ (0x00050000) +#define MPI3_SAS_PHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00060000) +#define MPI3_SAS_PHYINFO_REASON_BREAK_TIMEOUT (0x00070000) +#define MPI3_SAS_PHYINFO_REASON_PHY_TEST_STOPPED (0x00080000) +#define MPI3_SAS_PHYINFO_REASON_EXP_REDUCED_FUNC (0x00090000) + +#define MPI3_SAS_PHYINFO_SATA_PORT_ACTIVE (0x00004000) +#define MPI3_SAS_PHYINFO_SATA_PORT_SELECTOR_PRESENT (0x00002000) +#define MPI3_SAS_PHYINFO_VIRTUAL_PHY (0x00001000) + +#define MPI3_SAS_PHYINFO_PARTIAL_PATHWAY_TIME_MASK (0x00000F00) +#define MPI3_SAS_PHYINFO_PARTIAL_PATHWAY_TIME_SHIFT (8) + +#define MPI3_SAS_PHYINFO_ROUTING_ATTRIBUTE_MASK (0x000000F0) +#define MPI3_SAS_PHYINFO_ROUTING_ATTRIBUTE_DIRECT (0x00000000) +#define MPI3_SAS_PHYINFO_ROUTING_ATTRIBUTE_SUBTRACTIVE (0x00000010) +#define MPI3_SAS_PHYINFO_ROUTING_ATTRIBUTE_TABLE (0x00000020) + +/**** Defines for the ProgrammedLinkRate field ****/ +#define MPI3_SAS_PRATE_MAX_RATE_MASK (0xF0) +#define MPI3_SAS_PRATE_MAX_RATE_NOT_PROGRAMMABLE (0x00) +#define MPI3_SAS_PRATE_MAX_RATE_1_5 (0x80) +#define MPI3_SAS_PRATE_MAX_RATE_3_0 (0x90) +#define MPI3_SAS_PRATE_MAX_RATE_6_0 (0xA0) +#define MPI3_SAS_PRATE_MAX_RATE_12_0 (0xB0) +#define MPI3_SAS_PRATE_MAX_RATE_22_5 (0xC0) +#define MPI3_SAS_PRATE_MIN_RATE_MASK (0x0F) +#define MPI3_SAS_PRATE_MIN_RATE_NOT_PROGRAMMABLE (0x00) +#define MPI3_SAS_PRATE_MIN_RATE_1_5 (0x08) +#define MPI3_SAS_PRATE_MIN_RATE_3_0 (0x09) +#define MPI3_SAS_PRATE_MIN_RATE_6_0 (0x0A) +#define MPI3_SAS_PRATE_MIN_RATE_12_0 (0x0B) +#define MPI3_SAS_PRATE_MIN_RATE_22_5 (0x0C) + +/**** Defines for the HwLinkRate field ****/ +#define MPI3_SAS_HWRATE_MAX_RATE_MASK (0xF0) +#define MPI3_SAS_HWRATE_MAX_RATE_1_5 (0x80) +#define MPI3_SAS_HWRATE_MAX_RATE_3_0 (0x90) +#define MPI3_SAS_HWRATE_MAX_RATE_6_0 (0xA0) +#define MPI3_SAS_HWRATE_MAX_RATE_12_0 (0xB0) +#define MPI3_SAS_HWRATE_MAX_RATE_22_5 (0xC0) +#define MPI3_SAS_HWRATE_MIN_RATE_MASK (0x0F) +#define MPI3_SAS_HWRATE_MIN_RATE_1_5 (0x08) +#define MPI3_SAS_HWRATE_MIN_RATE_3_0 (0x09) +#define MPI3_SAS_HWRATE_MIN_RATE_6_0 (0x0A) +#define MPI3_SAS_HWRATE_MIN_RATE_12_0 (0x0B) +#define MPI3_SAS_HWRATE_MIN_RATE_22_5 (0x0C) + +/**** Defines for the Slot field ****/ +#define MPI3_SLOT_INVALID (0xFFFF) + +/**** Defines for the SlotIndex field ****/ +#define MPI3_SLOT_INDEX_INVALID (0xFFFF) + +/**** Defines for the LinkChangeCount fields ****/ +#define MPI3_LINK_CHANGE_COUNT_INVALID (0xFFFF) + +/**** Defines for the RateChangeCount fields ****/ +#define MPI3_RATE_CHANGE_COUNT_INVALID (0xFFFF) + +/**** Defines for the Temp Sensor Location field ****/ +#define MPI3_TEMP_SENSOR_LOCATION_INTERNAL (0x0) +#define MPI3_TEMP_SENSOR_LOCATION_INLET (0x1) +#define MPI3_TEMP_SENSOR_LOCATION_OUTLET (0x2) +#define MPI3_TEMP_SENSOR_LOCATION_DRAM (0x3) + +/***************************************************************************** + * Manufacturing Configuration Pages * + ****************************************************************************/ + +#define MPI3_MFGPAGE_VENDORID_BROADCOM (0x1000) + +/* MPI v3.0 SAS Products */ +#define MPI3_MFGPAGE_DEVID_SAS4116 (0x00A5) +#define MPI3_MFGPAGE_DEVID_SAS5116_MPI (0x00B3) +#define MPI3_MFGPAGE_DEVID_SAS5116_NVME (0x00B4) +#define MPI3_MFGPAGE_DEVID_SAS5116_MPI_NS (0x00B5) +#define MPI3_MFGPAGE_DEVID_SAS5116_NVME_NS (0x00B6) +#define MPI3_MFGPAGE_DEVID_SAS5116_PCIE_SWITCH (0x00B8) + +/***************************************************************************** + * Manufacturing Page 0 * + ****************************************************************************/ +typedef struct _MPI3_MAN_PAGE0 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 ChipRevision[8]; /* 0x08 */ + U8 ChipName[32]; /* 0x10 */ + U8 BoardName[32]; /* 0x30 */ + U8 BoardAssembly[32]; /* 0x50 */ + U8 BoardTracerNumber[32]; /* 0x70 */ + U32 BoardPower; /* 0x90 */ + U32 Reserved94; /* 0x94 */ + U32 Reserved98; /* 0x98 */ + U8 OEM; /* 0x9C */ + U8 ProfileIdentifier; /* 0x9D */ + U16 Flags; /* 0x9E */ + U8 BoardMfgDay; /* 0xA0 */ + U8 BoardMfgMonth; /* 0xA1 */ + U16 BoardMfgYear; /* 0xA2 */ + U8 BoardReworkDay; /* 0xA4 */ + U8 BoardReworkMonth; /* 0xA5 */ + U16 BoardReworkYear; /* 0xA6 */ + U8 BoardRevision[8]; /* 0xA8 */ + U8 EPackFRU[16]; /* 0xB0 */ + U8 ProductName[256]; /* 0xC0 */ +} MPI3_MAN_PAGE0, MPI3_POINTER PTR_MPI3_MAN_PAGE0, + Mpi3ManPage0_t, MPI3_POINTER pMpi3ManPage0_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN0_PAGEVERSION (0x00) + +/**** Defines for the Flags field ****/ +#define MPI3_MAN0_FLAGS_SWITCH_PRESENT (0x0002) +#define MPI3_MAN0_FLAGS_EXPANDER_PRESENT (0x0001) + +/***************************************************************************** + * Manufacturing Page 1 * + ****************************************************************************/ + +#define MPI3_MAN1_VPD_SIZE (512) + +typedef struct _MPI3_MAN_PAGE1 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08[2]; /* 0x08 */ + U8 VPD[MPI3_MAN1_VPD_SIZE]; /* 0x10 */ +} MPI3_MAN_PAGE1, MPI3_POINTER PTR_MPI3_MAN_PAGE1, + Mpi3ManPage1_t, MPI3_POINTER pMpi3ManPage1_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN1_PAGEVERSION (0x00) + + +/***************************************************************************** + * Manufacturing Page 2 * + ****************************************************************************/ + +typedef struct _MPI3_MAN_PAGE2 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 Flags; /* 0x08 */ + U8 Reserved09[3]; /* 0x09 */ + U32 Reserved0C[3]; /* 0x0C */ + U8 OEMBoardTracerNumber[32]; /* 0x18 */ +} MPI3_MAN_PAGE2, MPI3_POINTER PTR_MPI3_MAN_PAGE2, + Mpi3ManPage2_t, MPI3_POINTER pMpi3ManPage2_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN2_PAGEVERSION (0x00) + +/**** Defines for the Flags field ****/ +#define MPI3_MAN2_FLAGS_TRACER_PRESENT (0x01) + +/***************************************************************************** + * Manufacturing Page 5 * + ****************************************************************************/ +typedef struct _MPI3_MAN5_PHY_ENTRY +{ + U64 IOC_WWID; /* 0x00 */ + U64 DeviceName; /* 0x08 */ + U64 SATA_WWID; /* 0x10 */ +} MPI3_MAN5_PHY_ENTRY, MPI3_POINTER PTR_MPI3_MAN5_PHY_ENTRY, + Mpi3Man5PhyEntry_t, MPI3_POINTER pMpi3Man5PhyEntry_t; + +#ifndef MPI3_MAN5_PHY_MAX +#define MPI3_MAN5_PHY_MAX (1) +#endif /* MPI3_MAN5_PHY_MAX */ + +typedef struct _MPI3_MAN_PAGE5 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumPhys; /* 0x08 */ + U8 Reserved09[3]; /* 0x09 */ + U32 Reserved0C; /* 0x0C */ + MPI3_MAN5_PHY_ENTRY Phy[MPI3_MAN5_PHY_MAX]; /* 0x10 */ +} MPI3_MAN_PAGE5, MPI3_POINTER PTR_MPI3_MAN_PAGE5, + Mpi3ManPage5_t, MPI3_POINTER pMpi3ManPage5_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN5_PAGEVERSION (0x00) + +/***************************************************************************** + * Manufacturing Page 6 * + ****************************************************************************/ +typedef struct _MPI3_MAN6_GPIO_ENTRY +{ + U8 FunctionCode; /* 0x00 */ + U8 FunctionFlags; /* 0x01 */ + U16 Flags; /* 0x02 */ + U8 Param1; /* 0x04 */ + U8 Param2; /* 0x05 */ + U16 Reserved06; /* 0x06 */ + U32 Param3; /* 0x08 */ +} MPI3_MAN6_GPIO_ENTRY, MPI3_POINTER PTR_MPI3_MAN6_GPIO_ENTRY, + Mpi3Man6GpioEntry_t, MPI3_POINTER pMpi3Man6GpioEntry_t; + +/**** Defines for the FunctionCode field ****/ +#define MPI3_MAN6_GPIO_FUNCTION_GENERIC (0x00) +#define MPI3_MAN6_GPIO_FUNCTION_ALTERNATE (0x01) +#define MPI3_MAN6_GPIO_FUNCTION_EXT_INTERRUPT (0x02) +#define MPI3_MAN6_GPIO_FUNCTION_GLOBAL_ACTIVITY (0x03) +#define MPI3_MAN6_GPIO_FUNCTION_OVER_TEMPERATURE (0x04) +#define MPI3_MAN6_GPIO_FUNCTION_PORT_STATUS_GREEN (0x05) +#define MPI3_MAN6_GPIO_FUNCTION_PORT_STATUS_YELLOW (0x06) +#define MPI3_MAN6_GPIO_FUNCTION_CABLE_MANAGEMENT (0x07) +#define MPI3_MAN6_GPIO_FUNCTION_BKPLANE_MGMT_TYPE (0x08) +#define MPI3_MAN6_GPIO_FUNCTION_ISTWI_RESET (0x0A) +#define MPI3_MAN6_GPIO_FUNCTION_BACKEND_PCIE_RESET (0x0B) +#define MPI3_MAN6_GPIO_FUNCTION_GLOBAL_FAULT (0x0C) +#define MPI3_MAN6_GPIO_FUNCTION_PBLP_STATUS_CHANGE (0x0D) +#define MPI3_MAN6_GPIO_FUNCTION_EPACK_ONLINE (0x0E) +#define MPI3_MAN6_GPIO_FUNCTION_EPACK_FAULT (0x0F) +#define MPI3_MAN6_GPIO_FUNCTION_CTRL_TYPE (0x10) +#define MPI3_MAN6_GPIO_FUNCTION_LICENSE (0x11) +#define MPI3_MAN6_GPIO_FUNCTION_REFCLK_CONTROL (0x12) +#define MPI3_MAN6_GPIO_FUNCTION_BACKEND_PCIE_RESET_CLAMP (0x13) +#define MPI3_MAN6_GPIO_FUNCTION_AUXILIARY_POWER (0x14) +#define MPI3_MAN6_GPIO_FUNCTION_RAID_DATA_CACHE_DIRTY (0x15) +#define MPI3_MAN6_GPIO_FUNCTION_BOARD_FAN_CONTROL (0x16) +#define MPI3_MAN6_GPIO_FUNCTION_BOARD_FAN_FAULT (0x17) +#define MPI3_MAN6_GPIO_FUNCTION_POWER_BRAKE (0x18) +#define MPI3_MAN6_GPIO_FUNCTION_MGMT_CONTROLLER_RESET (0x19) + +/**** Defines for FunctionFlags when FunctionCode is ISTWI_RESET ****/ +#define MPI3_MAN6_GPIO_ISTWI_RESET_FUNCTIONFLAGS_DEVSELECT_MASK (0x01) +#define MPI3_MAN6_GPIO_ISTWI_RESET_FUNCTIONFLAGS_DEVSELECT_ISTWI (0x00) +#define MPI3_MAN6_GPIO_ISTWI_RESET_FUNCTIONFLAGS_DEVSELECT_RECEPTACLEID (0x01) + +/**** Defines for Param1 (Flags) when FunctionCode is EXT_INTERRUPT ****/ +#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_SOURCE_MASK (0xF0) +#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_SOURCE_GENERIC (0x00) +#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_SOURCE_CABLE_MGMT (0x10) +#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_SOURCE_ACTIVE_CABLE_OVERCURRENT (0x20) + +#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_TRIGGER_MASK (0x01) +#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_TRIGGER_EDGE (0x00) +#define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_TRIGGER_LEVEL (0x01) + +/**** Defines for Param1 (PHY STATE) when FunctionCode is PORT_STATUS_GREEN ****/ +#define MPI3_MAN6_GPIO_PORT_GREEN_PARAM1_PHY_STATUS_ALL_UP (0x00) +#define MPI3_MAN6_GPIO_PORT_GREEN_PARAM1_PHY_STATUS_ONE_OR_MORE_UP (0x01) + +/**** Defines for Param1 (INTERFACE_SIGNAL) when FunctionCode is CABLE_MANAGEMENT ****/ +#define MPI3_MAN6_GPIO_CABLE_MGMT_PARAM1_INTERFACE_MODULE_PRESENT (0x00) +#define MPI3_MAN6_GPIO_CABLE_MGMT_PARAM1_INTERFACE_ACTIVE_CABLE_ENABLE (0x01) +#define MPI3_MAN6_GPIO_CABLE_MGMT_PARAM1_INTERFACE_CABLE_MGMT_ENABLE (0x02) + +/**** Defines for Param1 (LICENSE_TYPE) when FunctionCode is LICENSE ****/ +#define MPI3_MAN6_GPIO_LICENSE_PARAM1_TYPE_IBUTTON (0x00) + + +/**** Defines for the Flags field ****/ +#define MPI3_MAN6_GPIO_FLAGS_SLEW_RATE_MASK (0x0100) +#define MPI3_MAN6_GPIO_FLAGS_SLEW_RATE_FAST_EDGE (0x0100) +#define MPI3_MAN6_GPIO_FLAGS_SLEW_RATE_SLOW_EDGE (0x0000) +#define MPI3_MAN6_GPIO_FLAGS_DRIVE_STRENGTH_MASK (0x00C0) +#define MPI3_MAN6_GPIO_FLAGS_DRIVE_STRENGTH_100OHM (0x0000) +#define MPI3_MAN6_GPIO_FLAGS_DRIVE_STRENGTH_66OHM (0x0040) +#define MPI3_MAN6_GPIO_FLAGS_DRIVE_STRENGTH_50OHM (0x0080) +#define MPI3_MAN6_GPIO_FLAGS_DRIVE_STRENGTH_33OHM (0x00C0) +#define MPI3_MAN6_GPIO_FLAGS_ALT_DATA_SEL_MASK (0x0030) +#define MPI3_MAN6_GPIO_FLAGS_ALT_DATA_SEL_SHIFT (4) +#define MPI3_MAN6_GPIO_FLAGS_ACTIVE_HIGH (0x0008) +#define MPI3_MAN6_GPIO_FLAGS_BI_DIR_ENABLED (0x0004) +#define MPI3_MAN6_GPIO_FLAGS_DIRECTION_MASK (0x0003) +#define MPI3_MAN6_GPIO_FLAGS_DIRECTION_INPUT (0x0000) +#define MPI3_MAN6_GPIO_FLAGS_DIRECTION_OPEN_DRAIN_OUTPUT (0x0001) +#define MPI3_MAN6_GPIO_FLAGS_DIRECTION_OPEN_SOURCE_OUTPUT (0x0002) +#define MPI3_MAN6_GPIO_FLAGS_DIRECTION_PUSH_PULL_OUTPUT (0x0003) + +#ifndef MPI3_MAN6_GPIO_MAX +#define MPI3_MAN6_GPIO_MAX (1) +#endif /* MPI3_MAN6_GPIO_MAX */ + +typedef struct _MPI3_MAN_PAGE6 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 Flags; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U8 NumGPIO; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + MPI3_MAN6_GPIO_ENTRY GPIO[MPI3_MAN6_GPIO_MAX]; /* 0x10 */ +} MPI3_MAN_PAGE6, MPI3_POINTER PTR_MPI3_MAN_PAGE6, + Mpi3ManPage6_t, MPI3_POINTER pMpi3ManPage6_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN6_PAGEVERSION (0x00) + +/**** Defines for the Flags field ****/ +#define MPI3_MAN6_FLAGS_HEARTBEAT_LED_DISABLED (0x0001) + +/***************************************************************************** + * Manufacturing Page 7 * + ****************************************************************************/ +typedef struct _MPI3_MAN7_RECEPTACLE_INFO +{ + U32 Name[4]; /* 0x00 */ + U8 Location; /* 0x10 */ + U8 ConnectorType; /* 0x11 */ + U8 PEDClk; /* 0x12 */ + U8 ConnectorID; /* 0x13 */ + U32 Reserved14; /* 0x14 */ +} MPI3_MAN7_RECEPTACLE_INFO, MPI3_POINTER PTR_MPI3_MAN7_RECEPTACLE_INFO, + Mpi3Man7ReceptacleInfo_t, MPI3_POINTER pMpi3Man7ReceptacleInfo_t; + +/**** Defines for Location field ****/ +#define MPI3_MAN7_LOCATION_UNKNOWN (0x00) +#define MPI3_MAN7_LOCATION_INTERNAL (0x01) +#define MPI3_MAN7_LOCATION_EXTERNAL (0x02) +#define MPI3_MAN7_LOCATION_VIRTUAL (0x03) +#define MPI3_MAN7_LOCATION_HOST (0x04) + +/**** Defines for ConnectorType - Use definitions from SES-4 ****/ +#define MPI3_MAN7_CONNECTOR_TYPE_NO_INFO (0x00) + +/**** Defines for PEDClk field ****/ +#define MPI3_MAN7_PEDCLK_ROUTING_MASK (0x10) +#define MPI3_MAN7_PEDCLK_ROUTING_DIRECT (0x00) +#define MPI3_MAN7_PEDCLK_ROUTING_CLOCK_BUFFER (0x10) +#define MPI3_MAN7_PEDCLK_ID_MASK (0x0F) + +#ifndef MPI3_MAN7_RECEPTACLE_INFO_MAX +#define MPI3_MAN7_RECEPTACLE_INFO_MAX (1) +#endif /* MPI3_MAN7_RECEPTACLE_INFO_MAX */ + +typedef struct _MPI3_MAN_PAGE7 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Flags; /* 0x08 */ + U8 NumReceptacles; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + U32 EnclosureName[4]; /* 0x10 */ + MPI3_MAN7_RECEPTACLE_INFO ReceptacleInfo[MPI3_MAN7_RECEPTACLE_INFO_MAX]; /* 0x20 */ /* variable length array */ +} MPI3_MAN_PAGE7, MPI3_POINTER PTR_MPI3_MAN_PAGE7, + Mpi3ManPage7_t, MPI3_POINTER pMpi3ManPage7_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN7_PAGEVERSION (0x00) + +/**** Defines for Flags field ****/ +#define MPI3_MAN7_FLAGS_BASE_ENCLOSURE_LEVEL_MASK (0x01) +#define MPI3_MAN7_FLAGS_BASE_ENCLOSURE_LEVEL_0 (0x00) +#define MPI3_MAN7_FLAGS_BASE_ENCLOSURE_LEVEL_1 (0x01) + + +/***************************************************************************** + * Manufacturing Page 8 * + ****************************************************************************/ + +typedef struct _MPI3_MAN8_PHY_INFO +{ + U8 ReceptacleID; /* 0x00 */ + U8 ConnectorLane; /* 0x01 */ + U16 Reserved02; /* 0x02 */ + U16 Slotx1; /* 0x04 */ + U16 Slotx2; /* 0x06 */ + U16 Slotx4; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U32 Reserved0C; /* 0x0C */ +} MPI3_MAN8_PHY_INFO, MPI3_POINTER PTR_MPI3_MAN8_PHY_INFO, + Mpi3Man8PhyInfo_t, MPI3_POINTER pMpi3Man8PhyInfo_t; + +/**** Defines for ReceptacleID field ****/ +#define MPI3_MAN8_PHY_INFO_RECEPTACLE_ID_NOT_ASSOCIATED (0xFF) + +/**** Defines for ConnectorLane field ****/ +#define MPI3_MAN8_PHY_INFO_CONNECTOR_LANE_NOT_ASSOCIATED (0xFF) + +#ifndef MPI3_MAN8_PHY_INFO_MAX +#define MPI3_MAN8_PHY_INFO_MAX (1) +#endif /* MPI3_MAN8_PHY_INFO_MAX */ + +typedef struct _MPI3_MAN_PAGE8 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U8 NumPhys; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + MPI3_MAN8_PHY_INFO PhyInfo[MPI3_MAN8_PHY_INFO_MAX]; /* 0x10 */ /* variable length array */ +} MPI3_MAN_PAGE8, MPI3_POINTER PTR_MPI3_MAN_PAGE8, + Mpi3ManPage8_t, MPI3_POINTER pMpi3ManPage8_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN8_PAGEVERSION (0x00) + +/***************************************************************************** + * Manufacturing Page 9 * + ****************************************************************************/ +typedef struct _MPI3_MAN9_RSRC_ENTRY +{ + U32 Maximum; /* 0x00 */ + U32 Decrement; /* 0x04 */ + U32 Minimum; /* 0x08 */ + U32 Actual; /* 0x0C */ +} MPI3_MAN9_RSRC_ENTRY, MPI3_POINTER PTR_MPI3_MAN9_RSRC_ENTRY, + Mpi3Man9RsrcEntry_t, MPI3_POINTER pMpi3Man9RsrcEntry_t; + +typedef enum _MPI3_MAN9_RESOURCES +{ + MPI3_MAN9_RSRC_OUTSTANDING_REQS = 0, + MPI3_MAN9_RSRC_TARGET_CMDS = 1, + MPI3_MAN9_RSRC_RESERVED02 = 2, + MPI3_MAN9_RSRC_NVME = 3, + MPI3_MAN9_RSRC_INITIATORS = 4, + MPI3_MAN9_RSRC_VDS = 5, + MPI3_MAN9_RSRC_ENCLOSURES = 6, + MPI3_MAN9_RSRC_ENCLOSURE_PHYS = 7, + MPI3_MAN9_RSRC_EXPANDERS = 8, + MPI3_MAN9_RSRC_PCIE_SWITCHES = 9, + MPI3_MAN9_RSRC_RESERVED10 = 10, + MPI3_MAN9_RSRC_HOST_PD_DRIVES = 11, + MPI3_MAN9_RSRC_ADV_HOST_PD_DRIVES = 12, + MPI3_MAN9_RSRC_RAID_PD_DRIVES = 13, + MPI3_MAN9_RSRC_DRV_DIAG_BUF = 14, + MPI3_MAN9_RSRC_NAMESPACE_COUNT = 15, + MPI3_MAN9_RSRC_NUM_RESOURCES +} MPI3_MAN9_RESOURCES; + +#define MPI3_MAN9_MIN_OUTSTANDING_REQS (1) +#define MPI3_MAN9_MAX_OUTSTANDING_REQS (65000) + +#define MPI3_MAN9_MIN_TARGET_CMDS (0) +#define MPI3_MAN9_MAX_TARGET_CMDS (65535) + +#define MPI3_MAN9_MIN_NVME_TARGETS (0) +/* Max NVMe Targets is product specific */ + +#define MPI3_MAN9_MIN_INITIATORS (0) +/* Max Initiators is product specific */ + +#define MPI3_MAN9_MIN_VDS (0) +/* Max VDs is product specific */ + +#define MPI3_MAN9_MIN_ENCLOSURES (1) +#define MPI3_MAN9_MAX_ENCLOSURES (65535) + +#define MPI3_MAN9_MIN_ENCLOSURE_PHYS (0) +/* Max Enclosure Phys is product specific */ + +#define MPI3_MAN9_MIN_EXPANDERS (0) +#define MPI3_MAN9_MAX_EXPANDERS (65535) + +#define MPI3_MAN9_MIN_PCIE_SWITCHES (0) +/* Max PCIe Switches is product specific */ + +#define MPI3_MAN9_MIN_HOST_PD_DRIVES (0) +/* Max Host PD Drives is product specific */ + +#define MPI3_MAN9_ADV_HOST_PD_DRIVES (0) +/* Max Advanced Host PD Drives is product specific */ + +#define MPI3_MAN9_RAID_PD_DRIVES (0) +/* Max RAID PD Drives is product specific */ + +#define MPI3_MAN9_DRIVER_DIAG_BUFFER (0) +/* Max Driver Diag Buffer is product specific */ + +#define MPI3_MAN9_MIN_NAMESPACE_COUNT (1) + +#define MPI3_MAN9_MIN_EXPANDERS (0) +#define MPI3_MAN9_MAX_EXPANDERS (65535) + + +typedef struct _MPI3_MAN_PAGE9 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumResources; /* 0x08 */ + U8 Reserved09; /* 0x09 */ + U16 Reserved0A; /* 0x0A */ + U32 Reserved0C; /* 0x0C */ + U32 Reserved10; /* 0x10 */ + U32 Reserved14; /* 0x14 */ + U32 Reserved18; /* 0x18 */ + U32 Reserved1C; /* 0x1C */ + MPI3_MAN9_RSRC_ENTRY Resource[MPI3_MAN9_RSRC_NUM_RESOURCES]; /* 0x20 */ +} MPI3_MAN_PAGE9, MPI3_POINTER PTR_MPI3_MAN_PAGE9, + Mpi3ManPage9_t, MPI3_POINTER pMpi3ManPage9_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN9_PAGEVERSION (0x00) + +/***************************************************************************** + * Manufacturing Page 10 * + ****************************************************************************/ +typedef struct _MPI3_MAN10_ISTWI_CTRLR_ENTRY +{ + U16 TargetAddress; /* 0x00 */ + U16 Flags; /* 0x02 */ + U8 SCLLowOverride; /* 0x04 */ + U8 SCLHighOverride; /* 0x05 */ + U16 Reserved06; /* 0x06 */ +} MPI3_MAN10_ISTWI_CTRLR_ENTRY, MPI3_POINTER PTR_MPI3_MAN10_ISTWI_CTRLR_ENTRY, + Mpi3Man10IstwiCtrlrEntry_t, MPI3_POINTER pMpi3Man10IstwiCtrlrEntry_t; + +/**** Defines for the Flags field ****/ + +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLICH_FLTR_MASK (0xC000) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLICH_FLTR_SHIFT (14) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLICH_FLTR_50_NS (0x0000) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLICH_FLTR_10_NS (0x4000) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLICH_FLTR_5_NS (0x8000) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLICH_FLTR_0_NS (0xC000) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_TYPE_MASK (0x3000) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_TYPE_SHIFT (12) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_TYPE_I2C (0x0000) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_TYPE_I3C (0x1000) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_TYPE_AUTO (0x2000) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_MASK (0x0E00) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_SHIFT (9) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_12_5_MHZ (0x0000) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_8_MHZ (0x0200) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_6_MHZ (0x0400) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_4_MHZ (0x0600) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_2_MHZ (0x0800) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_MASK (0x000C) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_SHIFT (0) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_100_KHZ (0x0000) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_400_KHZ (0x0004) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_TARGET_ENABLED (0x0002) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_INITIATOR_ENABLED (0x0001) + +#ifndef MPI3_MAN10_ISTWI_CTRLR_MAX +#define MPI3_MAN10_ISTWI_CTRLR_MAX (1) +#endif /* MPI3_MAN10_ISTWI_CTRLR_MAX */ + +typedef struct _MPI3_MAN_PAGE10 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U8 NumISTWICtrl; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + MPI3_MAN10_ISTWI_CTRLR_ENTRY ISTWIController[MPI3_MAN10_ISTWI_CTRLR_MAX]; /* 0x10 */ +} MPI3_MAN_PAGE10, MPI3_POINTER PTR_MPI3_MAN_PAGE10, + Mpi3ManPage10_t, MPI3_POINTER pMpi3ManPage10_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN10_PAGEVERSION (0x00) + +/***************************************************************************** + * Manufacturing Page 11 * + ****************************************************************************/ +typedef struct _MPI3_MAN11_MUX_DEVICE_FORMAT +{ + U8 MaxChannel; /* 0x00 */ + U8 Reserved01[3]; /* 0x01 */ + U32 Reserved04; /* 0x04 */ +} MPI3_MAN11_MUX_DEVICE_FORMAT, MPI3_POINTER PTR_MPI3_MAN11_MUX_DEVICE_FORMAT, + Mpi3Man11MuxDeviceFormat_t, MPI3_POINTER pMpi3Man11MuxDeviceFormat_t; + +typedef struct _MPI3_MAN11_TEMP_SENSOR_DEVICE_FORMAT +{ + U8 Type; /* 0x00 */ + U8 Reserved01[3]; /* 0x01 */ + U8 TempChannel[4]; /* 0x04 */ +} MPI3_MAN11_TEMP_SENSOR_DEVICE_FORMAT, MPI3_POINTER PTR_MPI3_MAN11_TEMP_SENSOR_DEVICE_FORMAT, + Mpi3Man11TempSensorDeviceFormat_t, MPI3_POINTER pMpi3Man11TempSensorDeviceFormat_t; + +/**** Defines for the Type field ****/ +#define MPI3_MAN11_TEMP_SENSOR_TYPE_MAX6654 (0x00) +#define MPI3_MAN11_TEMP_SENSOR_TYPE_EMC1442 (0x01) +#define MPI3_MAN11_TEMP_SENSOR_TYPE_ADT7476 (0x02) +#define MPI3_MAN11_TEMP_SENSOR_TYPE_SE97B (0x03) + +/**** Define for the TempChannel field ****/ +#define MPI3_MAN11_TEMP_SENSOR_CHANNEL_LOCATION_MASK (0xE0) +#define MPI3_MAN11_TEMP_SENSOR_CHANNEL_LOCATION_SHIFT (5) +/**** for the Location field values - use MPI3_TEMP_SENSOR_LOCATION_ defines ****/ +#define MPI3_MAN11_TEMP_SENSOR_CHANNEL_ENABLED (0x01) + + +typedef struct _MPI3_MAN11_SEEPROM_DEVICE_FORMAT +{ + U8 Size; /* 0x00 */ + U8 PageWriteSize; /* 0x01 */ + U16 Reserved02; /* 0x02 */ + U32 Reserved04; /* 0x04 */ +} MPI3_MAN11_SEEPROM_DEVICE_FORMAT, MPI3_POINTER PTR_MPI3_MAN11_SEEPROM_DEVICE_FORMAT, + Mpi3Man11SeepromDeviceFormat_t, MPI3_POINTER pMpi3Man11SeepromDeviceFormat_t; + +/**** Defines for the Size field ****/ +#define MPI3_MAN11_SEEPROM_SIZE_1KBITS (0x01) +#define MPI3_MAN11_SEEPROM_SIZE_2KBITS (0x02) +#define MPI3_MAN11_SEEPROM_SIZE_4KBITS (0x03) +#define MPI3_MAN11_SEEPROM_SIZE_8KBITS (0x04) +#define MPI3_MAN11_SEEPROM_SIZE_16KBITS (0x05) +#define MPI3_MAN11_SEEPROM_SIZE_32KBITS (0x06) +#define MPI3_MAN11_SEEPROM_SIZE_64KBITS (0x07) +#define MPI3_MAN11_SEEPROM_SIZE_128KBITS (0x08) + +typedef struct _MPI3_MAN11_DDR_SPD_DEVICE_FORMAT +{ + U8 Channel; /* 0x00 */ + U8 Reserved01[3]; /* 0x01 */ + U32 Reserved04; /* 0x04 */ +} MPI3_MAN11_DDR_SPD_DEVICE_FORMAT, MPI3_POINTER PTR_MPI3_MAN11_DDR_SPD_DEVICE_FORMAT, + Mpi3Man11DdrSpdDeviceFormat_t, MPI3_POINTER pMpi3Man11DdrSpdDeviceFormat_t; + +typedef struct _MPI3_MAN11_CABLE_MGMT_DEVICE_FORMAT +{ + U8 Type; /* 0x00 */ + U8 ReceptacleID; /* 0x01 */ + U16 Reserved02; /* 0x02 */ + U32 Reserved04; /* 0x04 */ +} MPI3_MAN11_CABLE_MGMT_DEVICE_FORMAT, MPI3_POINTER PTR_MPI3_MAN11_CABLE_MGMT_DEVICE_FORMAT, + Mpi3Man11CableMgmtDeviceFormat_t, MPI3_POINTER pMpi3Man11CableMgmtDeviceFormat_t; + +/**** Defines for the Type field ****/ +#define MPI3_MAN11_CABLE_MGMT_TYPE_SFF_8636 (0x00) + +typedef struct _MPI3_MAN11_BKPLANE_SPEC_UBM_FORMAT +{ + U16 Flags; /* 0x00 */ + U16 Reserved02; /* 0x02 */ +} MPI3_MAN11_BKPLANE_SPEC_UBM_FORMAT, MPI3_POINTER PTR_MPI3_MAN11_BKPLANE_SPEC_UBM_FORMAT, + Mpi3Man11BkplaneSpecUBMFormat_t, MPI3_POINTER pMpi3Man11BkplaneSpecUBMFormat_t; + +/**** Defines for the Flags field ****/ +#define MPI3_MAN11_BKPLANE_UBM_FLAGS_REFCLK_POLICY_ALWAYS_ENABLED (0x0200) +#define MPI3_MAN11_BKPLANE_UBM_FLAGS_FORCE_POLLING (0x0100) +#define MPI3_MAN11_BKPLANE_UBM_FLAGS_MAX_FRU_MASK (0x00F0) +#define MPI3_MAN11_BKPLANE_UBM_FLAGS_MAX_FRU_SHIFT (4) +#define MPI3_MAN11_BKPLANE_UBM_FLAGS_POLL_INTERVAL_MASK (0x000F) +#define MPI3_MAN11_BKPLANE_UBM_FLAGS_POLL_INTERVAL_SHIFT (0) + +typedef struct _MPI3_MAN11_BKPLANE_SPEC_NON_UBM_FORMAT +{ + U16 Flags; /* 0x00 */ + U8 Reserved02; /* 0x02 */ + U8 Type; /* 0x03 */ +} MPI3_MAN11_BKPLANE_SPEC_NON_UBM_FORMAT, MPI3_POINTER PTR_MPI3_MAN11_BKPLANE_SPEC_NON_UBM_FORMAT, + Mpi3Man11BkplaneSpecNonUBMFormat_t, MPI3_POINTER pMpi3Man11BkplaneSpecNonUBMFormat_t; + +/**** Defines for the Flags field ****/ +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_GROUP_MASK (0xF000) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_GROUP_SHIFT (12) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_REFCLK_POLICY_MASK (0x0600) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_REFCLK_POLICY_SHIFT (9) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_REFCLK_POLICY_DEVICE_PRESENT (0x0000) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_REFCLK_POLICY_ALWAYS_ENABLED (0x0200) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_REFCLK_POLICY_SRIS (0x0400) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_LINKWIDTH_MASK (0x00C0) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_LINKWIDTH_SHIFT (6) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_LINKWIDTH_4 (0x0000) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_LINKWIDTH_2 (0x0040) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_LINKWIDTH_1 (0x0080) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_PRESENCE_DETECT_MASK (0x0030) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_PRESENCE_DETECT_SHIFT (4) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_PRESENCE_DETECT_GPIO (0x0000) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_PRESENCE_DETECT_REG (0x0010) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_POLL_INTERVAL_MASK (0x000F) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_POLL_INTERVAL_SHIFT (0) + +/**** Defines for the Type field ****/ +#define MPI3_MAN11_BKPLANE_NON_UBM_TYPE_VPP (0x00) + +typedef union _MPI3_MAN11_BKPLANE_SPEC_FORMAT +{ + MPI3_MAN11_BKPLANE_SPEC_UBM_FORMAT Ubm; + MPI3_MAN11_BKPLANE_SPEC_NON_UBM_FORMAT NonUbm; +} MPI3_MAN11_BKPLANE_SPEC_FORMAT, MPI3_POINTER PTR_MPI3_MAN11_BKPLANE_SPEC_FORMAT, + Mpi3Man11BkplaneSpecFormat_t, MPI3_POINTER pMpi3Man11BkplaneSpecFormat_t; + +typedef struct _MPI3_MAN11_BKPLANE_MGMT_DEVICE_FORMAT +{ + U8 Type; /* 0x00 */ + U8 ReceptacleID; /* 0x01 */ + U8 ResetInfo; /* 0x02 */ + U8 Reserved03; /* 0x03 */ + MPI3_MAN11_BKPLANE_SPEC_FORMAT BackplaneMgmtSpecific; /* 0x04 */ +} MPI3_MAN11_BKPLANE_MGMT_DEVICE_FORMAT, MPI3_POINTER PTR_MPI3_MAN11_BKPLANE_MGMT_DEVICE_FORMAT, + Mpi3Man11BkplaneMgmtDeviceFormat_t, MPI3_POINTER pMpi3Man11BkplaneMgmtDeviceFormat_t; + +/**** Defines for the Type field ****/ +#define MPI3_MAN11_BKPLANE_MGMT_TYPE_UBM (0x00) +#define MPI3_MAN11_BKPLANE_MGMT_TYPE_NON_UBM (0x01) + +/**** Defines for the ResetInfo field ****/ +#define MPI3_MAN11_BACKPLANE_RESETINFO_ASSERT_TIME_MASK (0xF0) +#define MPI3_MAN11_BACKPLANE_RESETINFO_ASSERT_TIME_SHIFT (4) +#define MPI3_MAN11_BACKPLANE_RESETINFO_READY_TIME_MASK (0x0F) +#define MPI3_MAN11_BACKPLANE_RESETINFO_READY_TIME_SHIFT (0) + +typedef struct _MPI3_MAN11_GAS_GAUGE_DEVICE_FORMAT +{ + U8 Type; /* 0x00 */ + U8 Reserved01[3]; /* 0x01 */ + U32 Reserved04; /* 0x04 */ +} MPI3_MAN11_GAS_GAUGE_DEVICE_FORMAT, MPI3_POINTER PTR_MPI3_MAN11_GAS_GAUGE_DEVICE_FORMAT, + Mpi3Man11GasGaugeDeviceFormat_t, MPI3_POINTER pMpi3Man11GasGaugeDeviceFormat_t; + +/**** Defines for the Type field ****/ +#define MPI3_MAN11_GAS_GAUGE_TYPE_STANDARD (0x00) + +typedef struct _MPI3_MAN11_MGMT_CTRLR_DEVICE_FORMAT +{ + U32 Reserved00; /* 0x00 */ + U32 Reserved04; /* 0x04 */ +} MPI3_MAN11_MGMT_CTRLR_DEVICE_FORMAT, MPI3_POINTER PTR_MPI3_MAN11_MGMT_CTRLR_DEVICE_FORMAT, + Mpi3Man11MgmtCtrlrDeviceFormat_t, MPI3_POINTER pMpi3Man11MgmtCtrlrDeviceFormat_t; + +typedef struct _MPI3_MAN11_BOARD_FAN_DEVICE_FORMAT +{ + U8 Flags; /* 0x00 */ + U8 Reserved01; /* 0x01 */ + U8 MinFanSpeed; /* 0x02 */ + U8 MaxFanSpeed; /* 0x03 */ + U32 Reserved04; /* 0x04 */ +} MPI3_MAN11_BOARD_FAN_DEVICE_FORMAT, MPI3_POINTER PTR_MPI3_MAN11_BOARD_FAN_DEVICE_FORMAT, + Mpi3Man11BoardFanDeviceFormat_t, MPI3_POINTER pMpi3Man11BoardFanDeviceFormat_t; + +/**** Defines for the Flags field ****/ +#define MPI3_MAN11_BOARD_FAN_FLAGS_FAN_CTRLR_TYPE_MASK (0x07) +#define MPI3_MAN11_BOARD_FAN_FLAGS_FAN_CTRLR_TYPE_AMC6821 (0x00) + +typedef union _MPI3_MAN11_DEVICE_SPECIFIC_FORMAT +{ + MPI3_MAN11_MUX_DEVICE_FORMAT Mux; + MPI3_MAN11_TEMP_SENSOR_DEVICE_FORMAT TempSensor; + MPI3_MAN11_SEEPROM_DEVICE_FORMAT Seeprom; + MPI3_MAN11_DDR_SPD_DEVICE_FORMAT DdrSpd; + MPI3_MAN11_CABLE_MGMT_DEVICE_FORMAT CableMgmt; + MPI3_MAN11_BKPLANE_MGMT_DEVICE_FORMAT BkplaneMgmt; + MPI3_MAN11_GAS_GAUGE_DEVICE_FORMAT GasGauge; + MPI3_MAN11_MGMT_CTRLR_DEVICE_FORMAT MgmtController; + MPI3_MAN11_BOARD_FAN_DEVICE_FORMAT BoardFan; + U32 Words[2]; +} MPI3_MAN11_DEVICE_SPECIFIC_FORMAT, MPI3_POINTER PTR_MPI3_MAN11_DEVICE_SPECIFIC_FORMAT, + Mpi3Man11DeviceSpecificFormat_t, MPI3_POINTER pMpi3Man11DeviceSpecificFormat_t; + +typedef struct _MPI3_MAN11_ISTWI_DEVICE_FORMAT +{ + U8 DeviceType; /* 0x00 */ + U8 Controller; /* 0x01 */ + U8 Reserved02; /* 0x02 */ + U8 Flags; /* 0x03 */ + U16 DeviceAddress; /* 0x04 */ + U8 MuxChannel; /* 0x06 */ + U8 MuxIndex; /* 0x07 */ + MPI3_MAN11_DEVICE_SPECIFIC_FORMAT DeviceSpecific; /* 0x08 */ +} MPI3_MAN11_ISTWI_DEVICE_FORMAT, MPI3_POINTER PTR_MPI3_MAN11_ISTWI_DEVICE_FORMAT, + Mpi3Man11IstwiDeviceFormat_t, MPI3_POINTER pMpi3Man11IstwiDeviceFormat_t; + +/**** Defines for the DeviceType field ****/ +#define MPI3_MAN11_ISTWI_DEVTYPE_MUX (0x00) +#define MPI3_MAN11_ISTWI_DEVTYPE_TEMP_SENSOR (0x01) +#define MPI3_MAN11_ISTWI_DEVTYPE_SEEPROM (0x02) +#define MPI3_MAN11_ISTWI_DEVTYPE_DDR_SPD (0x03) +#define MPI3_MAN11_ISTWI_DEVTYPE_CABLE_MGMT (0x04) +#define MPI3_MAN11_ISTWI_DEVTYPE_BACKPLANE_MGMT (0x05) +#define MPI3_MAN11_ISTWI_DEVTYPE_GAS_GAUGE (0x06) +#define MPI3_MAN11_ISTWI_DEVTYPE_MGMT_CONTROLLER (0x07) +#define MPI3_MAN11_ISTWI_DEVTYPE_BOARD_FAN (0x08) + +/**** Defines for the Flags field ****/ +#define MPI3_MAN11_ISTWI_FLAGS_MUX_PRESENT (0x01) + +#ifndef MPI3_MAN11_ISTWI_DEVICE_MAX +#define MPI3_MAN11_ISTWI_DEVICE_MAX (1) +#endif /* MPI3_MAN11_ISTWI_DEVICE_MAX */ + +typedef struct _MPI3_MAN_PAGE11 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U8 NumISTWIDev; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + MPI3_MAN11_ISTWI_DEVICE_FORMAT ISTWIDevice[MPI3_MAN11_ISTWI_DEVICE_MAX]; /* 0x10 */ +} MPI3_MAN_PAGE11, MPI3_POINTER PTR_MPI3_MAN_PAGE11, + Mpi3ManPage11_t, MPI3_POINTER pMpi3ManPage11_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN11_PAGEVERSION (0x00) + + +/***************************************************************************** + * Manufacturing Page 12 * + ****************************************************************************/ +#ifndef MPI3_MAN12_NUM_SGPIO_MAX +#define MPI3_MAN12_NUM_SGPIO_MAX (1) +#endif /* MPI3_MAN12_NUM_SGPIO_MAX */ + +typedef struct _MPI3_MAN12_SGPIO_INFO +{ + U8 SlotCount; /* 0x00 */ + U8 Reserved01[3]; /* 0x01 */ + U32 Reserved04; /* 0x04 */ + U8 PhyOrder[32]; /* 0x08 */ +} MPI3_MAN12_SGPIO_INFO, MPI3_POINTER PTR_MPI3_MAN12_SGPIO_INFO, + Mpi3Man12SGPIOInfo_t, MPI3_POINTER pMpi3Man12SGPIOInfo_t; + +typedef struct _MPI3_MAN_PAGE12 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Flags; /* 0x08 */ + U32 SClockFreq; /* 0x0C */ + U32 ActivityModulation; /* 0x10 */ + U8 NumSGPIO; /* 0x14 */ + U8 Reserved15[3]; /* 0x15 */ + U32 Reserved18; /* 0x18 */ + U32 Reserved1C; /* 0x1C */ + U32 Pattern[8]; /* 0x20 */ + MPI3_MAN12_SGPIO_INFO SGPIOInfo[MPI3_MAN12_NUM_SGPIO_MAX]; /* 0x40 */ /* variable length */ +} MPI3_MAN_PAGE12, MPI3_POINTER PTR_MPI3_MAN_PAGE12, + Mpi3ManPage12_t, MPI3_POINTER pMpi3ManPage12_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN12_PAGEVERSION (0x00) + +/**** Defines for the Flags field ****/ +#define MPI3_MAN12_FLAGS_ERROR_PRESENCE_ENABLED (0x0400) +#define MPI3_MAN12_FLAGS_ACTIVITY_INVERT_ENABLED (0x0200) +#define MPI3_MAN12_FLAGS_GROUP_ID_DISABLED (0x0100) +#define MPI3_MAN12_FLAGS_SIO_CLK_FILTER_ENABLED (0x0004) +#define MPI3_MAN12_FLAGS_SCLOCK_SLOAD_TYPE_MASK (0x0002) +#define MPI3_MAN12_FLAGS_SCLOCK_SLOAD_TYPE_PUSH_PULL (0x0000) +#define MPI3_MAN12_FLAGS_SCLOCK_SLOAD_TYPE_OPEN_DRAIN (0x0002) +#define MPI3_MAN12_FLAGS_SDATAOUT_TYPE_MASK (0x0001) +#define MPI3_MAN12_FLAGS_SDATAOUT_TYPE_PUSH_PULL (0x0000) +#define MPI3_MAN12_FLAGS_SDATAOUT_TYPE_OPEN_DRAIN (0x0001) + +/**** Defines for the SioClkFreq field ****/ +#define MPI3_MAN12_SIO_CLK_FREQ_MIN (32) /* 32 Hz min SIO Clk Freq */ +#define MPI3_MAN12_SIO_CLK_FREQ_MAX (100000) /* 100 KHz max SIO Clk Freq */ + +/**** Defines for the ActivityModulation field ****/ +#define MPI3_MAN12_ACTIVITY_MODULATION_FORCE_OFF_MASK (0x0000F000) +#define MPI3_MAN12_ACTIVITY_MODULATION_FORCE_OFF_SHIFT (12) +#define MPI3_MAN12_ACTIVITY_MODULATION_MAX_ON_MASK (0x00000F00) +#define MPI3_MAN12_ACTIVITY_MODULATION_MAX_ON_SHIFT (8) +#define MPI3_MAN12_ACTIVITY_MODULATION_STRETCH_OFF_MASK (0x000000F0) +#define MPI3_MAN12_ACTIVITY_MODULATION_STRETCH_OFF_SHIFT (4) +#define MPI3_MAN12_ACTIVITY_MODULATION_STRETCH_ON_MASK (0x0000000F) +#define MPI3_MAN12_ACTIVITY_MODULATION_STRETCH_ON_SHIFT (0) + +/*** Defines for the Pattern field ****/ +#define MPI3_MAN12_PATTERN_RATE_MASK (0xE0000000) +#define MPI3_MAN12_PATTERN_RATE_2_HZ (0x00000000) +#define MPI3_MAN12_PATTERN_RATE_4_HZ (0x20000000) +#define MPI3_MAN12_PATTERN_RATE_8_HZ (0x40000000) +#define MPI3_MAN12_PATTERN_RATE_16_HZ (0x60000000) +#define MPI3_MAN12_PATTERN_RATE_10_HZ (0x80000000) +#define MPI3_MAN12_PATTERN_RATE_20_HZ (0xA0000000) +#define MPI3_MAN12_PATTERN_RATE_40_HZ (0xC0000000) +#define MPI3_MAN12_PATTERN_LENGTH_MASK (0x1F000000) +#define MPI3_MAN12_PATTERN_LENGTH_SHIFT (24) +#define MPI3_MAN12_PATTERN_BIT_PATTERN_MASK (0x00FFFFFF) +#define MPI3_MAN12_PATTERN_BIT_PATTERN_SHIFT (0) + + +/***************************************************************************** + * Manufacturing Page 13 * + ****************************************************************************/ + +#ifndef MPI3_MAN13_NUM_TRANSLATION_MAX +#define MPI3_MAN13_NUM_TRANSLATION_MAX (1) +#endif /* MPI3_MAN13_NUM_TRANSLATION_MAX */ + +typedef struct _MPI3_MAN13_TRANSLATION_INFO +{ + U32 SlotStatus; /* 0x00 */ + U32 Mask; /* 0x04 */ + U8 Activity; /* 0x08 */ + U8 Locate; /* 0x09 */ + U8 Error; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ +} MPI3_MAN13_TRANSLATION_INFO, MPI3_POINTER PTR_MPI3_MAN13_TRANSLATION_INFO, + Mpi3Man13TranslationInfo_t, MPI3_POINTER pMpi3Man13TranslationInfo_t; + +/**** Defines for the SlotStatus field ****/ +#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_FAULT (0x20000000) +#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_DEVICE_OFF (0x10000000) +#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_DEVICE_ACTIVITY (0x00800000) +#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_DO_NOT_REMOVE (0x00400000) +#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_DEVICE_MISSING (0x00100000) +#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_INSERT (0x00080000) +#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_REMOVAL (0x00040000) +#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_IDENTIFY (0x00020000) +#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_OK (0x00008000) +#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_RESERVED_DEVICE (0x00004000) +#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_HOT_SPARE (0x00002000) +#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_CONSISTENCY_CHECK (0x00001000) +#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000800) +#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_IN_FAILED_ARRAY (0x00000400) +#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_REBUILD_REMAP (0x00000200) +#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_REBUILD_REMAP_ABORT (0x00000100) +#define MPI3_MAN13_TRANSLATION_SLOTSTATUS_PREDICTED_FAILURE (0x00000040) + +/**** Defines for the Mask field - use MPI3_MAN13_TRANSLATION_SLOTSTATUS_ defines ****/ + +/**** Defines for the Activity, Locate, and Error fields ****/ +#define MPI3_MAN13_BLINK_PATTERN_FORCE_OFF (0x00) +#define MPI3_MAN13_BLINK_PATTERN_FORCE_ON (0x01) +#define MPI3_MAN13_BLINK_PATTERN_PATTERN_0 (0x02) +#define MPI3_MAN13_BLINK_PATTERN_PATTERN_1 (0x03) +#define MPI3_MAN13_BLINK_PATTERN_PATTERN_2 (0x04) +#define MPI3_MAN13_BLINK_PATTERN_PATTERN_3 (0x05) +#define MPI3_MAN13_BLINK_PATTERN_PATTERN_4 (0x06) +#define MPI3_MAN13_BLINK_PATTERN_PATTERN_5 (0x07) +#define MPI3_MAN13_BLINK_PATTERN_PATTERN_6 (0x08) +#define MPI3_MAN13_BLINK_PATTERN_PATTERN_7 (0x09) +#define MPI3_MAN13_BLINK_PATTERN_ACTIVITY (0x0A) +#define MPI3_MAN13_BLINK_PATTERN_ACTIVITY_TRAIL (0x0B) + +typedef struct _MPI3_MAN_PAGE13 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumTrans; /* 0x08 */ + U8 Reserved09[3]; /* 0x09 */ + U32 Reserved0C; /* 0x0C */ + MPI3_MAN13_TRANSLATION_INFO Translation[MPI3_MAN13_NUM_TRANSLATION_MAX]; /* 0x10 */ /* variable length */ +} MPI3_MAN_PAGE13, MPI3_POINTER PTR_MPI3_MAN_PAGE13, + Mpi3ManPage13_t, MPI3_POINTER pMpi3ManPage13_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN13_PAGEVERSION (0x00) + +/***************************************************************************** + * Manufacturing Page 14 * + ****************************************************************************/ + +typedef struct _MPI3_MAN_PAGE14 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U8 NumSlotGroups; /* 0x0C */ + U8 NumSlots; /* 0x0D */ + U16 MaxCertChainLength; /* 0x0E */ + U32 SealedSlots; /* 0x10 */ + U32 PopulatedSlots; /* 0x14 */ + U32 MgmtPTUpdatableSlots; /* 0x18 */ +} MPI3_MAN_PAGE14, MPI3_POINTER PTR_MPI3_MAN_PAGE14, + Mpi3ManPage14_t, MPI3_POINTER pMpi3ManPage14_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN14_PAGEVERSION (0x00) + +/**** Defines for the NumSlots field ****/ +#define MPI3_MAN14_NUMSLOTS_MAX (32) + +/***************************************************************************** + * Manufacturing Page 15 * + ****************************************************************************/ + +#ifndef MPI3_MAN15_VERSION_RECORD_MAX +#define MPI3_MAN15_VERSION_RECORD_MAX 1 +#endif /* MPI3_MAN15_VERSION_RECORD_MAX */ + +typedef struct _MPI3_MAN15_VERSION_RECORD +{ + U16 SPDMVersion; /* 0x00 */ + U16 Reserved02; /* 0x02 */ +} MPI3_MAN15_VERSION_RECORD, MPI3_POINTER PTR_MPI3_MAN15_VERSION_RECORD, + Mpi3Man15VersionRecord_t, MPI3_POINTER pMpi3Man15VersionRecord_t; + +typedef struct _MPI3_MAN_PAGE15 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumVersionRecords; /* 0x08 */ + U8 Reserved09[3]; /* 0x09 */ + U32 Reserved0C; /* 0x0C */ + MPI3_MAN15_VERSION_RECORD VersionRecord[MPI3_MAN15_VERSION_RECORD_MAX]; /* 0x10 */ +} MPI3_MAN_PAGE15, MPI3_POINTER PTR_MPI3_MAN_PAGE15, + Mpi3ManPage15_t, MPI3_POINTER pMpi3ManPage15_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN15_PAGEVERSION (0x00) + +/***************************************************************************** + * Manufacturing Page 16 * + ****************************************************************************/ + +#ifndef MPI3_MAN16_CERT_ALGO_MAX +#define MPI3_MAN16_CERT_ALGO_MAX 1 +#endif /* MPI3_MAN16_CERT_ALGO_MAX */ + +typedef struct _MPI3_MAN16_CERTIFICATE_ALGORITHM +{ + U8 SlotGroup; /* 0x00 */ + U8 Reserved01[3]; /* 0x01 */ + U32 BaseAsymAlgo; /* 0x04 */ + U32 BaseHashAlgo; /* 0x08 */ + U32 Reserved0C[3]; /* 0x0C */ +} MPI3_MAN16_CERTIFICATE_ALGORITHM, MPI3_POINTER PTR_MPI3_MAN16_CERTIFICATE_ALGORITHM, + Mpi3Man16CertificateAlgorithm_t, MPI3_POINTER pMpi3Man16CertificateAlgorithm_t; + +typedef struct _MPI3_MAN_PAGE16 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U8 NumCertAlgos; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + MPI3_MAN16_CERTIFICATE_ALGORITHM CertificateAlgorithm[MPI3_MAN16_CERT_ALGO_MAX]; /* 0x10 */ +} MPI3_MAN_PAGE16, MPI3_POINTER PTR_MPI3_MAN_PAGE16, + Mpi3ManPage16_t, MPI3_POINTER pMpi3ManPage16_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN16_PAGEVERSION (0x00) + +/***************************************************************************** + * Manufacturing Page 17 * + ****************************************************************************/ + +#ifndef MPI3_MAN17_HASH_ALGORITHM_MAX +#define MPI3_MAN17_HASH_ALGORITHM_MAX 1 +#endif /* MPI3_MAN17_HASH_ALGORITHM_MAX */ + +typedef struct _MPI3_MAN17_HASH_ALGORITHM +{ + U8 MeasSpecification; /* 0x00 */ + U8 Reserved01[3]; /* 0x01 */ + U32 MeasurementHashAlgo; /* 0x04 */ + U32 Reserved08[2]; /* 0x08 */ +} MPI3_MAN17_HASH_ALGORITHM, MPI3_POINTER PTR_MPI3_MAN17_HASH_ALGORITHM, + Mpi3Man17HashAlgorithm_t, MPI3_POINTER pMpi3Man17HashAlgorithm_t; + +typedef struct _MPI3_MAN_PAGE17 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U8 NumHashAlgos; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + MPI3_MAN17_HASH_ALGORITHM HashAlgorithm[MPI3_MAN17_HASH_ALGORITHM_MAX]; /* 0x10 */ +} MPI3_MAN_PAGE17, MPI3_POINTER PTR_MPI3_MAN_PAGE17, + Mpi3ManPage17_t, MPI3_POINTER pMpi3ManPage17_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN17_PAGEVERSION (0x00) + +/***************************************************************************** + * Manufacturing Page 20 * + ****************************************************************************/ + +typedef struct _MPI3_MAN_PAGE20 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U32 NonpremiumFeatures; /* 0x0C */ + U8 AllowedPersonalities; /* 0x10 */ + U8 Reserved11[3]; /* 0x11 */ +} MPI3_MAN_PAGE20, MPI3_POINTER PTR_MPI3_MAN_PAGE20, + Mpi3ManPage20_t, MPI3_POINTER pMpi3ManPage20_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN20_PAGEVERSION (0x00) + +/**** Defines for the AllowedPersonalities field ****/ +#define MPI3_MAN20_ALLOWEDPERSON_RAID_MASK (0x02) +#define MPI3_MAN20_ALLOWEDPERSON_RAID_ALLOWED (0x02) +#define MPI3_MAN20_ALLOWEDPERSON_RAID_NOT_ALLOWED (0x00) +#define MPI3_MAN20_ALLOWEDPERSON_EHBA_MASK (0x01) +#define MPI3_MAN20_ALLOWEDPERSON_EHBA_ALLOWED (0x01) +#define MPI3_MAN20_ALLOWEDPERSON_EHBA_NOT_ALLOWED (0x00) + +/**** Defines for the NonpremuimFeatures field ****/ +#define MPI3_MAN20_NONPREMUIM_DISABLE_PD_DEGRADED_MASK (0x01) +#define MPI3_MAN20_NONPREMUIM_DISABLE_PD_DEGRADED_ENABLED (0x00) +#define MPI3_MAN20_NONPREMUIM_DISABLE_PD_DEGRADED_DISABLED (0x01) + +/***************************************************************************** + * Manufacturing Page 21 * + ****************************************************************************/ + +typedef struct _MPI3_MAN_PAGE21 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U32 Flags; /* 0x0C */ +} MPI3_MAN_PAGE21, MPI3_POINTER PTR_MPI3_MAN_PAGE21, + Mpi3ManPage21_t, MPI3_POINTER pMpi3ManPage21_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_MAN21_PAGEVERSION (0x00) + +/**** Defines for the Flags field ****/ +#define MPI3_MAN21_FLAGS_UNCERTIFIED_DRIVES_MASK (0x00000060) +#define MPI3_MAN21_FLAGS_UNCERTIFIED_DRIVES_BLOCK (0x00000000) +#define MPI3_MAN21_FLAGS_UNCERTIFIED_DRIVES_ALLOW (0x00000020) +#define MPI3_MAN21_FLAGS_UNCERTIFIED_DRIVES_WARN (0x00000040) +#define MPI3_MAN21_FLAGS_BLOCK_SSD_WR_CACHE_CHANGE_MASK (0x00000008) +#define MPI3_MAN21_FLAGS_BLOCK_SSD_WR_CACHE_CHANGE_ALLOW (0x00000000) +#define MPI3_MAN21_FLAGS_BLOCK_SSD_WR_CACHE_CHANGE_PREVENT (0x00000008) +#define MPI3_MAN21_FLAGS_SES_VPD_ASSOC_MASK (0x00000001) +#define MPI3_MAN21_FLAGS_SES_VPD_ASSOC_DEFAULT (0x00000000) +#define MPI3_MAN21_FLAGS_SES_VPD_ASSOC_OEM_SPECIFIC (0x00000001) + +/***************************************************************************** + * Manufacturing Pages 32-63 (ProductSpecific) * + ****************************************************************************/ +#ifndef MPI3_MAN_PROD_SPECIFIC_MAX +#define MPI3_MAN_PROD_SPECIFIC_MAX (1) +#endif /* MPI3_MAN_PROD_SPECIFIC_MAX */ + +typedef struct _MPI3_MAN_PAGE_PRODUCT_SPECIFIC +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 ProductSpecificInfo[MPI3_MAN_PROD_SPECIFIC_MAX]; /* 0x08 */ /* variable length array */ +} MPI3_MAN_PAGE_PRODUCT_SPECIFIC, MPI3_POINTER PTR_MPI3_MAN_PAGE_PRODUCT_SPECIFIC, + Mpi3ManPageProductSpecific_t, MPI3_POINTER pMpi3ManPageProductSpecific_t; + +/***************************************************************************** + * IO Unit Configuration Pages * + ****************************************************************************/ + +/***************************************************************************** + * IO Unit Page 0 * + ****************************************************************************/ +typedef struct _MPI3_IO_UNIT_PAGE0 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U64 UniqueValue; /* 0x08 */ + U32 NvdataVersionDefault; /* 0x10 */ + U32 NvdataVersionPersistent; /* 0x14 */ +} MPI3_IO_UNIT_PAGE0, MPI3_POINTER PTR_MPI3_IO_UNIT_PAGE0, + Mpi3IOUnitPage0_t, MPI3_POINTER pMpi3IOUnitPage0_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOUNIT0_PAGEVERSION (0x00) + +/***************************************************************************** + * IO Unit Page 1 * + ****************************************************************************/ +typedef struct _MPI3_IO_UNIT_PAGE1 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Flags; /* 0x08 */ + U8 DMDIoDelay; /* 0x0C */ + U8 DMDReportPCIe; /* 0x0D */ + U8 DMDReportSATA; /* 0x0E */ + U8 DMDReportSAS; /* 0x0F */ +} MPI3_IO_UNIT_PAGE1, MPI3_POINTER PTR_MPI3_IO_UNIT_PAGE1, + Mpi3IOUnitPage1_t, MPI3_POINTER pMpi3IOUnitPage1_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOUNIT1_PAGEVERSION (0x00) + +/**** Defines for the Flags field ****/ +#define MPI3_IOUNIT1_FLAGS_NVME_WRITE_CACHE_MASK (0x00000030) +#define MPI3_IOUNIT1_FLAGS_NVME_WRITE_CACHE_ENABLE (0x00000000) +#define MPI3_IOUNIT1_FLAGS_NVME_WRITE_CACHE_DISABLE (0x00000010) +#define MPI3_IOUNIT1_FLAGS_NVME_WRITE_CACHE_NO_MODIFY (0x00000020) +#define MPI3_IOUNIT1_FLAGS_ATA_SECURITY_FREEZE_LOCK (0x00000008) +#define MPI3_IOUNIT1_FLAGS_WRITE_SAME_BUFFER (0x00000004) +#define MPI3_IOUNIT1_FLAGS_SATA_WRITE_CACHE_MASK (0x00000003) +#define MPI3_IOUNIT1_FLAGS_SATA_WRITE_CACHE_ENABLE (0x00000000) +#define MPI3_IOUNIT1_FLAGS_SATA_WRITE_CACHE_DISABLE (0x00000001) +#define MPI3_IOUNIT1_FLAGS_SATA_WRITE_CACHE_UNCHANGED (0x00000002) + +/**** Defines for the DMDReport PCIe/SATA/SAS fields ****/ +#define MPI3_IOUNIT1_DMD_REPORT_DELAY_TIME_MASK (0x7F) +#define MPI3_IOUNIT1_DMD_REPORT_UNIT_16_SEC (0x80) + +/***************************************************************************** + * IO Unit Page 2 * + ****************************************************************************/ +#ifndef MPI3_IO_UNIT2_GPIO_VAL_MAX +#define MPI3_IO_UNIT2_GPIO_VAL_MAX (1) +#endif /* MPI3_IO_UNIT2_GPIO_VAL_MAX */ + +typedef struct _MPI3_IO_UNIT_PAGE2 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 GPIOCount; /* 0x08 */ + U8 Reserved09[3]; /* 0x09 */ + U16 GPIOVal[MPI3_IO_UNIT2_GPIO_VAL_MAX]; /* 0x0C */ +} MPI3_IO_UNIT_PAGE2, MPI3_POINTER PTR_MPI3_IO_UNIT_PAGE2, + Mpi3IOUnitPage2_t, MPI3_POINTER pMpi3IOUnitPage2_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOUNIT2_PAGEVERSION (0x00) + +/**** Define for the GPIOVal field ****/ +#define MPI3_IOUNIT2_GPIO_FUNCTION_MASK (0xFFFC) +#define MPI3_IOUNIT2_GPIO_FUNCTION_SHIFT (2) +#define MPI3_IOUNIT2_GPIO_SETTING_MASK (0x0001) +#define MPI3_IOUNIT2_GPIO_SETTING_OFF (0x0000) +#define MPI3_IOUNIT2_GPIO_SETTING_ON (0x0001) + +/***************************************************************************** + * IO Unit Page 3 * + ****************************************************************************/ + +typedef struct _MPI3_IO_UNIT3_SENSOR +{ + U16 Flags; /* 0x00 */ + U8 ThresholdMargin; /* 0x02 */ + U8 Reserved03; /* 0x03 */ + U16 Threshold[3]; /* 0x04 */ + U16 Reserved0A; /* 0x0A */ + U32 Reserved0C; /* 0x0C */ + U32 Reserved10; /* 0x10 */ + U32 Reserved14; /* 0x14 */ +} MPI3_IO_UNIT3_SENSOR, MPI3_POINTER PTR_MPI3_IO_UNIT3_SENSOR, + Mpi3IOUnit3Sensor_t, MPI3_POINTER pMpi3IOUnit3Sensor_t; + +/**** Defines for the Flags field ****/ +#define MPI3_IOUNIT3_SENSOR_FLAGS_FATAL_EVENT_ENABLED (0x0010) +#define MPI3_IOUNIT3_SENSOR_FLAGS_FATAL_ACTION_ENABLED (0x0008) +#define MPI3_IOUNIT3_SENSOR_FLAGS_CRITICAL_EVENT_ENABLED (0x0004) +#define MPI3_IOUNIT3_SENSOR_FLAGS_CRITICAL_ACTION_ENABLED (0x0002) +#define MPI3_IOUNIT3_SENSOR_FLAGS_WARNING_EVENT_ENABLED (0x0001) + +#ifndef MPI3_IO_UNIT3_SENSOR_MAX +#define MPI3_IO_UNIT3_SENSOR_MAX (1) +#endif /* MPI3_IO_UNIT3_SENSOR_MAX */ + +typedef struct _MPI3_IO_UNIT_PAGE3 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U8 NumSensors; /* 0x0C */ + U8 NominalPollInterval; /* 0x0D */ + U8 WarningPollInterval; /* 0x0E */ + U8 Reserved0F; /* 0x0F */ + MPI3_IO_UNIT3_SENSOR Sensor[MPI3_IO_UNIT3_SENSOR_MAX]; /* 0x10 */ +} MPI3_IO_UNIT_PAGE3, MPI3_POINTER PTR_MPI3_IO_UNIT_PAGE3, + Mpi3IOUnitPage3_t, MPI3_POINTER pMpi3IOUnitPage3_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOUNIT3_PAGEVERSION (0x00) + + +/***************************************************************************** + * IO Unit Page 4 * + ****************************************************************************/ +typedef struct _MPI3_IO_UNIT4_SENSOR +{ + U16 CurrentTemperature; /* 0x00 */ + U16 Reserved02; /* 0x02 */ + U8 Flags; /* 0x04 */ + U8 Reserved05[3]; /* 0x05 */ + U16 ISTWIIndex; /* 0x08 */ + U8 Channel; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U32 Reserved0C; /* 0x0C */ +} MPI3_IO_UNIT4_SENSOR, MPI3_POINTER PTR_MPI3_IO_UNIT4_SENSOR, + Mpi3IOUnit4Sensor_t, MPI3_POINTER pMpi3IOUnit4Sensor_t; + +/**** Defines for the Flags field ****/ +#define MPI3_IOUNIT4_SENSOR_FLAGS_LOC_MASK (0xE0) +#define MPI3_IOUNIT4_SENSOR_FLAGS_LOC_SHIFT (5) +/**** for the Location field values - use MPI3_TEMP_SENSOR_LOCATION_ defines ****/ +#define MPI3_IOUNIT4_SENSOR_FLAGS_TEMP_VALID (0x01) + + +/**** Defines for the ISTWIIndex field ****/ +#define MPI3_IOUNIT4_SENSOR_ISTWI_INDEX_INTERNAL (0xFFFF) + +/**** Defines for the Channel field ****/ +#define MPI3_IOUNIT4_SENSOR_CHANNEL_RESERVED (0xFF) + +#ifndef MPI3_IO_UNIT4_SENSOR_MAX +#define MPI3_IO_UNIT4_SENSOR_MAX (1) +#endif /* MPI3_IO_UNIT4_SENSOR_MAX */ + +typedef struct _MPI3_IO_UNIT_PAGE4 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U8 NumSensors; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + MPI3_IO_UNIT4_SENSOR Sensor[MPI3_IO_UNIT4_SENSOR_MAX]; /* 0x10 */ +} MPI3_IO_UNIT_PAGE4, MPI3_POINTER PTR_MPI3_IO_UNIT_PAGE4, + Mpi3IOUnitPage4_t, MPI3_POINTER pMpi3IOUnitPage4_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOUNIT4_PAGEVERSION (0x00) + +/***************************************************************************** + * IO Unit Page 5 * + ****************************************************************************/ +typedef struct _MPI3_IO_UNIT5_SPINUP_GROUP +{ + U8 MaxTargetSpinup; /* 0x00 */ + U8 SpinupDelay; /* 0x01 */ + U8 SpinupFlags; /* 0x02 */ + U8 Reserved03; /* 0x03 */ +} MPI3_IO_UNIT5_SPINUP_GROUP, MPI3_POINTER PTR_MPI3_IO_UNIT5_SPINUP_GROUP, + Mpi3IOUnit5SpinupGroup_t, MPI3_POINTER pMpi3IOUnit5SpinupGroup_t; + +/**** Defines for the SpinupFlags field ****/ +#define MPI3_IOUNIT5_SPINUP_FLAGS_DISABLE (0x01) + +#ifndef MPI3_IO_UNIT5_PHY_MAX +#define MPI3_IO_UNIT5_PHY_MAX (4) +#endif /* MPI3_IO_UNIT5_PHY_MAX */ + +typedef struct _MPI3_IO_UNIT_PAGE5 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + MPI3_IO_UNIT5_SPINUP_GROUP SpinupGroupParameters[4]; /* 0x08 */ + U32 Reserved18; /* 0x18 */ + U32 Reserved1C; /* 0x1C */ + U16 DeviceShutdown; /* 0x20 */ + U16 Reserved22; /* 0x22 */ + U8 PCIeDeviceWaitTime; /* 0x24 */ + U8 SATADeviceWaitTime; /* 0x25 */ + U8 SpinupEnclDriveCount; /* 0x26 */ + U8 SpinupEnclDelay; /* 0x27 */ + U8 NumPhys; /* 0x28 */ + U8 PEInitialSpinupDelay; /* 0x29 */ + U8 TopologyStableTime; /* 0x2A */ + U8 Flags; /* 0x2B */ + U8 Phy[MPI3_IO_UNIT5_PHY_MAX]; /* 0x2C */ +} MPI3_IO_UNIT_PAGE5, MPI3_POINTER PTR_MPI3_IO_UNIT_PAGE5, + Mpi3IOUnitPage5_t, MPI3_POINTER pMpi3IOUnitPage5_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOUNIT5_PAGEVERSION (0x00) + +/**** Defines for the DeviceShutdown field ****/ +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_NO_ACTION (0x00) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_DIRECT_ATTACHED (0x01) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_EXPANDER_ATTACHED (0x02) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SWITCH_ATTACHED (0x02) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_DIRECT_AND_EXPANDER (0x03) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_DIRECT_AND_SWITCH (0x03) + +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SATA_HDD_MASK (0x0300) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SATA_HDD_SHIFT (8) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SAS_HDD_MASK (0x00C0) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SAS_HDD_SHIFT (6) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_NVME_SSD_MASK (0x0030) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_NVME_SSD_SHIFT (4) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SATA_SSD_MASK (0x000C) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SATA_SSD_SHIFT (2) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SAS_SSD_MASK (0x0003) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SAS_SSD_SHIFT (0) + +/**** Defines for the Flags field ****/ +#define MPI3_IOUNIT5_FLAGS_SATAPUIS_MASK (0x0C) +#define MPI3_IOUNIT5_FLAGS_SATAPUIS_SHIFT (2) +#define MPI3_IOUNIT5_FLAGS_SATAPUIS_NOT_SUPPORTED (0x00) +#define MPI3_IOUNIT5_FLAGS_SATAPUIS_OS_CONTROLLED (0x04) +#define MPI3_IOUNIT5_FLAGS_SATAPUIS_APP_CONTROLLED (0x08) +#define MPI3_IOUNIT5_FLAGS_SATAPUIS_BLOCKED (0x0C) +#define MPI3_IOUNIT5_FLAGS_POWER_CAPABLE_SPINUP (0x02) +#define MPI3_IOUNIT5_FLAGS_AUTO_PORT_ENABLE (0x01) + +/**** Defines for the PHY field ****/ +#define MPI3_IOUNIT5_PHY_SPINUP_GROUP_MASK (0x03) + +/***************************************************************************** + * IO Unit Page 6 * + ****************************************************************************/ +typedef struct _MPI3_IO_UNIT_PAGE6 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 BoardPowerRequirement; /* 0x08 */ + U32 PCISlotPowerAllocation; /* 0x0C */ + U8 Flags; /* 0x10 */ + U8 Reserved11[3]; /* 0x11 */ +} MPI3_IO_UNIT_PAGE6, MPI3_POINTER PTR_MPI3_IO_UNIT_PAGE6, + Mpi3IOUnitPage6_t, MPI3_POINTER pMpi3IOUnitPage6_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOUNIT6_PAGEVERSION (0x00) + +/**** Defines for the Flags field ****/ +#define MPI3_IOUNIT6_FLAGS_ACT_CABLE_PWR_EXC (0x01) + +/***************************************************************************** + * IO Unit Page 8 * + ****************************************************************************/ + +#ifndef MPI3_IOUNIT8_DIGEST_MAX +#define MPI3_IOUNIT8_DIGEST_MAX (1) +#endif /* MPI3_IOUNIT8_DIGEST_MAX */ + +typedef union _MPI3_IOUNIT8_DIGEST +{ + U32 Dword[16]; + U16 Word[32]; + U8 Byte[64]; +} MPI3_IOUNIT8_DIGEST, MPI3_POINTER PTR_MPI3_IOUNIT8_DIGEST, + Mpi3IOUnit8Digest_t, MPI3_POINTER pMpi3IOUnit8Digest_t; + +typedef struct _MPI3_IO_UNIT_PAGE8 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 SBMode; /* 0x08 */ + U8 SbState; /* 0x09 */ + U16 Reserved0A; /* 0x0A */ + U8 NumSlots; /* 0x0C */ + U8 SlotsAvailable; /* 0x0D */ + U8 CurrentKeyEncryptionAlgo; /* 0x0E */ + U8 KeyDigestHashAlgo; /* 0x0F */ + MPI3_VERSION_UNION CurrentSvn; /* 0x10 */ + U32 Reserved14; /* 0x14 */ + U32 CurrentKey[128]; /* 0x18 */ + MPI3_IOUNIT8_DIGEST Digest[MPI3_IOUNIT8_DIGEST_MAX]; /* 0x218 */ /* variable length */ +} MPI3_IO_UNIT_PAGE8, MPI3_POINTER PTR_MPI3_IO_UNIT_PAGE8, + Mpi3IOUnitPage8_t, MPI3_POINTER pMpi3IOUnitPage8_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOUNIT8_PAGEVERSION (0x00) + +/**** Defines for the SBMode field ****/ +#define MPI3_IOUNIT8_SBMODE_SECURE_DEBUG (0x04) +#define MPI3_IOUNIT8_SBMODE_HARD_SECURE (0x02) +#define MPI3_IOUNIT8_SBMODE_CONFIG_SECURE (0x01) + +/**** Defines for the SBState field ****/ +#define MPI3_IOUNIT8_SBSTATE_SVN_UPDATE_PENDING (0x04) +#define MPI3_IOUNIT8_SBSTATE_KEY_UPDATE_PENDING (0x02) +#define MPI3_IOUNIT8_SBSTATE_SECURE_BOOT_ENABLED (0x01) + +/***************************************************************************** + * IO Unit Page 9 * + ****************************************************************************/ + +typedef struct _MPI3_IO_UNIT_PAGE9 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Flags; /* 0x08 */ + U16 FirstDevice; /* 0x0C */ + U16 Reserved0E; /* 0x0E */ +} MPI3_IO_UNIT_PAGE9, MPI3_POINTER PTR_MPI3_IO_UNIT_PAGE9, + Mpi3IOUnitPage9_t, MPI3_POINTER pMpi3IOUnitPage9_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOUNIT9_PAGEVERSION (0x00) + +/**** Defines for the Flags field ****/ +#define MPI3_IOUNIT9_FLAGS_UBM_ENCLOSURE_ORDER_MASK (0x00000006) +#define MPI3_IOUNIT9_FLAGS_UBM_ENCLOSURE_ORDER_SHIFT (1) +#define MPI3_IOUNIT9_FLAGS_UBM_ENCLOSURE_ORDER_NONE (0x00000000) +#define MPI3_IOUNIT9_FLAGS_UBM_ENCLOSURE_ORDER_RECEPTACLE (0x00000002) +#define MPI3_IOUNIT9_FLAGS_UBM_ENCLOSURE_ORDER_BACKPLANE_TYPE (0x00000004) +#define MPI3_IOUNIT9_FLAGS_VDFIRST_ENABLED (0x00000001) + +/**** Defines for the FirstDevice field ****/ +#define MPI3_IOUNIT9_FIRSTDEVICE_UNKNOWN (0xFFFF) + +/***************************************************************************** + * IO Unit Page 10 * + ****************************************************************************/ + +typedef struct _MPI3_IO_UNIT_PAGE10 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 Flags; /* 0x08 */ + U8 Reserved09[3]; /* 0x09 */ + U32 SiliconID; /* 0x0C */ + U8 FWVersionMinor; /* 0x10 */ + U8 FWVersionMajor; /* 0x11 */ + U8 HWVersionMinor; /* 0x12 */ + U8 HWVersionMajor; /* 0x13 */ + U8 PartNumber[16]; /* 0x14 */ +} MPI3_IO_UNIT_PAGE10, MPI3_POINTER PTR_MPI3_IO_UNIT_PAGE10, + Mpi3IOUnitPage10_t, MPI3_POINTER pMpi3IOUnitPage10_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOUNIT10_PAGEVERSION (0x00) + +/**** Defines for the Flags field ****/ +#define MPI3_IOUNIT10_FLAGS_VALID (0x01) +#define MPI3_IOUNIT10_FLAGS_ACTIVEID_MASK (0x02) +#define MPI3_IOUNIT10_FLAGS_ACTIVEID_FIRST_REGION (0x00) +#define MPI3_IOUNIT10_FLAGS_ACTIVEID_SECOND_REGION (0x02) +#define MPI3_IOUNIT10_FLAGS_PBLP_EXPECTED (0x80) + +/***************************************************************************** + * IO Unit Page 11 * + ****************************************************************************/ + +#ifndef MPI3_IOUNIT11_PROFILE_MAX +#define MPI3_IOUNIT11_PROFILE_MAX (1) +#endif /* MPI3_IOUNIT11_PROFILE_MAX */ + +typedef struct _MPI3_IOUNIT11_PROFILE +{ + U8 ProfileIdentifier; /* 0x00 */ + U8 Reserved01[3]; /* 0x01 */ + U16 MaxVDs; /* 0x04 */ + U16 MaxHostPDs; /* 0x06 */ + U16 MaxAdvHostPDs; /* 0x08 */ + U16 MaxRAIDPDs; /* 0x0A */ + U16 MaxNVMe; /* 0x0C */ + U16 MaxOutstandingRequests; /* 0x0E */ + U16 SubsystemID; /* 0x10 */ + U16 Reserved12; /* 0x12 */ + U32 Reserved14[2]; /* 0x14 */ +} MPI3_IOUNIT11_PROFILE, MPI3_POINTER PTR_MPI3_IOUNIT11_PROFILE, + Mpi3IOUnit11Profile_t, MPI3_POINTER pMpi3IOUnit11Profile_t; + +typedef struct _MPI3_IO_UNIT_PAGE11 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U8 NumProfiles; /* 0x0C */ + U8 CurrentProfileIdentifier; /* 0x0D */ + U16 Reserved0E; /* 0x0E */ + MPI3_IOUNIT11_PROFILE Profile[MPI3_IOUNIT11_PROFILE_MAX]; /* 0x10 */ /* variable length */ +} MPI3_IO_UNIT_PAGE11, MPI3_POINTER PTR_MPI3_IO_UNIT_PAGE11, + Mpi3IOUnitPage11_t, MPI3_POINTER pMpi3IOUnitPage11_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOUNIT11_PAGEVERSION (0x00) + +/***************************************************************************** + * IO Unit Page 12 * + ****************************************************************************/ + +#ifndef MPI3_IOUNIT12_BUCKET_MAX +#define MPI3_IOUNIT12_BUCKET_MAX (1) +#endif /* MPI3_IOUNIT12_BUCKET_MAX */ + +typedef struct _MPI3_IOUNIT12_BUCKET +{ + U8 CoalescingDepth; /* 0x00 */ + U8 CoalescingTimeout; /* 0x01 */ + U16 IOCountLowBoundary; /* 0x02 */ + U32 Reserved04; /* 0x04 */ +} MPI3_IOUNIT12_BUCKET, MPI3_POINTER PTR_MPI3_IOUNIT12_BUCKET, + Mpi3IOUnit12Bucket_t, MPI3_POINTER pMpi3IOUnit12Bucket_t; + +typedef struct _MPI3_IO_UNIT_PAGE12 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Flags; /* 0x08 */ + U32 Reserved0C[4]; /* 0x0C */ + U8 NumBuckets; /* 0x1C */ + U8 Reserved1D[3]; /* 0x1D */ + MPI3_IOUNIT12_BUCKET Bucket[MPI3_IOUNIT12_BUCKET_MAX]; /* 0x20 */ /* variable length */ +} MPI3_IO_UNIT_PAGE12, MPI3_POINTER PTR_MPI3_IO_UNIT_PAGE12, + Mpi3IOUnitPage12_t, MPI3_POINTER pMpi3IOUnitPage12_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOUNIT12_PAGEVERSION (0x00) + +/**** Defines for the Flags field ****/ +#define MPI3_IOUNIT12_FLAGS_NUMPASSES_MASK (0x00000300) +#define MPI3_IOUNIT12_FLAGS_NUMPASSES_SHIFT (8) +#define MPI3_IOUNIT12_FLAGS_NUMPASSES_8 (0x00000000) +#define MPI3_IOUNIT12_FLAGS_NUMPASSES_16 (0x00000100) +#define MPI3_IOUNIT12_FLAGS_NUMPASSES_32 (0x00000200) +#define MPI3_IOUNIT12_FLAGS_NUMPASSES_64 (0x00000300) +#define MPI3_IOUNIT12_FLAGS_PASSPERIOD_MASK (0x00000003) +#define MPI3_IOUNIT12_FLAGS_PASSPERIOD_DISABLED (0x00000000) +#define MPI3_IOUNIT12_FLAGS_PASSPERIOD_500US (0x00000001) +#define MPI3_IOUNIT12_FLAGS_PASSPERIOD_1MS (0x00000002) +#define MPI3_IOUNIT12_FLAGS_PASSPERIOD_2MS (0x00000003) + +/***************************************************************************** + * IO Unit Page 13 * + ****************************************************************************/ + +#ifndef MPI3_IOUNIT13_FUNC_MAX +#define MPI3_IOUNIT13_FUNC_MAX (1) +#endif /* MPI3_IOUNIT13_FUNC_MAX */ + +typedef struct _MPI3_IOUNIT13_ALLOWED_FUNCTION +{ + U16 SubFunction; /* 0x00 */ + U8 FunctionCode; /* 0x02 */ + U8 FunctionFlags; /* 0x03 */ +} MPI3_IOUNIT13_ALLOWED_FUNCTION, MPI3_POINTER PTR_MPI3_IOUNIT13_ALLOWED_FUNCTION, + Mpi3IOUnit13AllowedFunction_t, MPI3_POINTER pMpi3IOUnit13AllowedFunction_t; + +/**** Defines for the FunctionFlags field ****/ +#define MPI3_IOUNIT13_FUNCTION_FLAGS_ADMIN_BLOCKED (0x04) +#define MPI3_IOUNIT13_FUNCTION_FLAGS_OOB_BLOCKED (0x02) +#define MPI3_IOUNIT13_FUNCTION_FLAGS_CHECK_SUBFUNCTION_ENABLED (0x01) + +typedef struct _MPI3_IO_UNIT_PAGE13 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 Flags; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U8 NumAllowedFunctions; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + MPI3_IOUNIT13_ALLOWED_FUNCTION AllowedFunction[MPI3_IOUNIT13_FUNC_MAX]; /* 0x10 */ /* variable length */ +} MPI3_IO_UNIT_PAGE13, MPI3_POINTER PTR_MPI3_IO_UNIT_PAGE13, + Mpi3IOUnitPage13_t, MPI3_POINTER pMpi3IOUnitPage13_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOUNIT13_PAGEVERSION (0x00) + +/**** Defines for the Flags field ****/ +#define MPI3_IOUNIT13_FLAGS_ADMIN_BLOCKED (0x0002) +#define MPI3_IOUNIT13_FLAGS_OOB_BLOCKED (0x0001) + +/***************************************************************************** + * IO Unit Page 14 * + ****************************************************************************/ + +#ifndef MPI3_IOUNIT14_MD_MAX +#define MPI3_IOUNIT14_MD_MAX (1) +#endif /* MPI3_IOUNIT14_MD_MAX */ + +typedef struct _MPI3_IOUNIT14_PAGEMETADATA +{ + U8 PageType; /* 0x00 */ + U8 PageNumber; /* 0x01 */ + U8 Reserved02; /* 0x02 */ + U8 PageFlags; /* 0x03 */ +} MPI3_IOUNIT14_PAGEMETADATA, MPI3_POINTER PTR_MPI3_IOUNIT14_PAGEMETADATA, + Mpi3IOUnit14PageMetadata_t, MPI3_POINTER pMpi3IOUnit14PageMetadata_t; + +/**** Defines for the PageFlags field ****/ +#define MPI3_IOUNIT14_PAGEMETADATA_PAGEFLAGS_OOBWRITE_ALLOWED (0x02) +#define MPI3_IOUNIT14_PAGEMETADATA_PAGEFLAGS_HOSTWRITE_ALLOWED (0x01) + +typedef struct _MPI3_IO_UNIT_PAGE14 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 Flags; /* 0x08 */ + U8 Reserved09[3]; /* 0x09 */ + U8 NumPages; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + MPI3_IOUNIT14_PAGEMETADATA PageMetadata[MPI3_IOUNIT14_MD_MAX]; /* 0x10 */ /* variable length */ +} MPI3_IO_UNIT_PAGE14, MPI3_POINTER PTR_MPI3_IO_UNIT_PAGE14, + Mpi3IOUnitPage14_t, MPI3_POINTER pMpi3IOUnitPage14_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOUNIT14_PAGEVERSION (0x00) + +/**** Defines for the Flags field ****/ +#define MPI3_IOUNIT14_FLAGS_READONLY (0x01) + +/***************************************************************************** + * IO Unit Page 15 * + ****************************************************************************/ + +#ifndef MPI3_IOUNIT15_PBD_MAX +#define MPI3_IOUNIT15_PBD_MAX (1) +#endif /* MPI3_IOUNIT15_PBD_MAX */ + +typedef struct _MPI3_IO_UNIT_PAGE15 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 Flags; /* 0x08 */ + U8 Reserved09[3]; /* 0x09 */ + U32 Reserved0C; /* 0x0C */ + U8 PowerBudgetingCapability; /* 0x10 */ + U8 Reserved11[3]; /* 0x11 */ + U8 NumPowerBudgetData; /* 0x14 */ + U8 Reserved15[3]; /* 0x15 */ + U32 PowerBudgetData[MPI3_IOUNIT15_PBD_MAX]; /* 0x18 */ /* variable length */ +} MPI3_IO_UNIT_PAGE15, MPI3_POINTER PTR_MPI3_IO_UNIT_PAGE15, + Mpi3IOUnitPage15_t, MPI3_POINTER pMpi3IOUnitPage15_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOUNIT15_PAGEVERSION (0x00) + +/**** Defines for the Flags field ****/ +#define MPI3_IOUNIT15_FLAGS_EPRINIT_INITREQUIRED (0x04) +#define MPI3_IOUNIT15_FLAGS_EPRSUPPORT_MASK (0x03) +#define MPI3_IOUNIT15_FLAGS_EPRSUPPORT_NOT_SUPPORTED (0x00) +#define MPI3_IOUNIT15_FLAGS_EPRSUPPORT_WITHOUT_POWER_BRAKE_GPIO (0x01) +#define MPI3_IOUNIT15_FLAGS_EPRSUPPORT_WITH_POWER_BRAKE_GPIO (0x02) + +/**** Defines for the NumPowerBudgetData field ****/ +#define MPI3_IOUNIT15_NUMPOWERBUDGETDATA_POWER_BUDGETING_DISABLED (0x00) + +/***************************************************************************** + * IOC Configuration Pages * + ****************************************************************************/ + +/***************************************************************************** + * IOC Page 0 * + ****************************************************************************/ +typedef struct _MPI3_IOC_PAGE0 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U16 VendorID; /* 0x0C */ + U16 DeviceID; /* 0x0E */ + U8 RevisionID; /* 0x10 */ + U8 Reserved11[3]; /* 0x11 */ + U32 ClassCode; /* 0x14 */ + U16 SubsystemVendorID; /* 0x18 */ + U16 SubsystemID; /* 0x1A */ +} MPI3_IOC_PAGE0, MPI3_POINTER PTR_MPI3_IOC_PAGE0, + Mpi3IOCPage0_t, MPI3_POINTER pMpi3IOCPage0_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOC0_PAGEVERSION (0x00) + +/***************************************************************************** + * IOC Page 1 * + ****************************************************************************/ +typedef struct _MPI3_IOC_PAGE1 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 CoalescingTimeout; /* 0x08 */ + U8 CoalescingDepth; /* 0x0C */ + U8 Obsolete; /* 0x0D */ + U16 Reserved0E; /* 0x0E */ +} MPI3_IOC_PAGE1, MPI3_POINTER PTR_MPI3_IOC_PAGE1, + Mpi3IOCPage1_t, MPI3_POINTER pMpi3IOCPage1_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOC1_PAGEVERSION (0x00) + +/***************************************************************************** + * IOC Page 2 * + ****************************************************************************/ +#ifndef MPI3_IOC2_EVENTMASK_WORDS +#define MPI3_IOC2_EVENTMASK_WORDS (4) +#endif /* MPI3_IOC2_EVENTMASK_WORDS */ + +typedef struct _MPI3_IOC_PAGE2 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U16 SASBroadcastPrimitiveMasks; /* 0x0C */ + U16 SASNotifyPrimitiveMasks; /* 0x0E */ + U32 EventMasks[MPI3_IOC2_EVENTMASK_WORDS]; /* 0x10 */ +} MPI3_IOC_PAGE2, MPI3_POINTER PTR_MPI3_IOC_PAGE2, + Mpi3IOCPage2_t, MPI3_POINTER pMpi3IOCPage2_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_IOC2_PAGEVERSION (0x00) + + +/***************************************************************************** + * Driver Configuration Pages * + ****************************************************************************/ + +/**** Defines for the Flags field ****/ +#define MPI3_DRIVER_FLAGS_ADMINRAIDPD_BLOCKED (0x0010) +#define MPI3_DRIVER_FLAGS_OOBRAIDPD_BLOCKED (0x0008) +#define MPI3_DRIVER_FLAGS_OOBRAIDVD_BLOCKED (0x0004) +#define MPI3_DRIVER_FLAGS_OOBADVHOSTPD_BLOCKED (0x0002) +#define MPI3_DRIVER_FLAGS_OOBHOSTPD_BLOCKED (0x0001) + +typedef struct _MPI3_ALLOWED_CMD_SCSI +{ + U16 ServiceAction; /* 0x00 */ + U8 OperationCode; /* 0x02 */ + U8 CommandFlags; /* 0x03 */ +} MPI3_ALLOWED_CMD_SCSI, MPI3_POINTER PTR_MPI3_ALLOWED_CMD_SCSI, + Mpi3AllowedCmdScsi_t, MPI3_POINTER pMpi3AllowedCmdScsi_t; + +typedef struct _MPI3_ALLOWED_CMD_ATA +{ + U8 Subcommand; /* 0x00 */ + U8 Reserved01; /* 0x01 */ + U8 Command; /* 0x02 */ + U8 CommandFlags; /* 0x03 */ +} MPI3_ALLOWED_CMD_ATA, MPI3_POINTER PTR_MPI3_ALLOWED_CMD_ATA, + Mpi3AllowedCmdAta_t, MPI3_POINTER pMpi3AllowedCmdAta_t; + +typedef struct _MPI3_ALLOWED_CMD_NVME +{ + U8 Reserved00; /* 0x00 */ + U8 NVMeCmdFlags; /* 0x01 */ + U8 OpCode; /* 0x02 */ + U8 CommandFlags; /* 0x03 */ +} MPI3_ALLOWED_CMD_NVME, MPI3_POINTER PTR_MPI3_ALLOWED_CMD_NVME, + Mpi3AllowedCmdNvme_t, MPI3_POINTER pMpi3AllowedCmdNvme_t; + +/**** Defines for the CommandFlags field ****/ +#define MPI3_DRIVER_ALLOWEDCMD_NVMECMDFLAGS_SUBQ_TYPE_MASK (0x80) +#define MPI3_DRIVER_ALLOWEDCMD_NVMECMDFLAGS_SUBQ_TYPE_IO (0x00) +#define MPI3_DRIVER_ALLOWEDCMD_NVMECMDFLAGS_SUBQ_TYPE_ADMIN (0x80) +#define MPI3_DRIVER_ALLOWEDCMD_NVMECMDFLAGS_CMDSET_MASK (0x3F) +#define MPI3_DRIVER_ALLOWEDCMD_NVMECMDFLAGS_CMDSET_NVM (0x00) + +typedef union _MPI3_ALLOWED_CMD +{ + MPI3_ALLOWED_CMD_SCSI Scsi; + MPI3_ALLOWED_CMD_ATA Ata; + MPI3_ALLOWED_CMD_NVME NVMe; +} MPI3_ALLOWED_CMD, MPI3_POINTER PTR_MPI3_ALLOWED_CMD, + Mpi3AllowedCmd_t, MPI3_POINTER pMpi3AllowedCmd_t; + +/**** Defines for the CommandFlags field ****/ +#define MPI3_DRIVER_ALLOWEDCMD_CMDFLAGS_ADMINRAIDPD_BLOCKED (0x20) +#define MPI3_DRIVER_ALLOWEDCMD_CMDFLAGS_OOBRAIDPD_BLOCKED (0x10) +#define MPI3_DRIVER_ALLOWEDCMD_CMDFLAGS_OOBRAIDVD_BLOCKED (0x08) +#define MPI3_DRIVER_ALLOWEDCMD_CMDFLAGS_OOBADVHOSTPD_BLOCKED (0x04) +#define MPI3_DRIVER_ALLOWEDCMD_CMDFLAGS_OOBHOSTPD_BLOCKED (0x02) +#define MPI3_DRIVER_ALLOWEDCMD_CMDFLAGS_CHECKSUBCMD_ENABLED (0x01) + + +#ifndef MPI3_ALLOWED_CMDS_MAX +#define MPI3_ALLOWED_CMDS_MAX (1) +#endif /* MPI3_ALLOWED_CMDS_MAX */ + +/***************************************************************************** + * Driver Page 0 * + ****************************************************************************/ +typedef struct _MPI3_DRIVER_PAGE0 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 BSDOptions; /* 0x08 */ + U8 SSUTimeout; /* 0x0C */ + U8 IOTimeout; /* 0x0D */ + U8 TURRetries; /* 0x0E */ + U8 TURInterval; /* 0x0F */ + U8 Reserved10; /* 0x10 */ + U8 SecurityKeyTimeout; /* 0x11 */ + U16 Reserved12; /* 0x12 */ + U32 Reserved14; /* 0x14 */ + U32 Reserved18; /* 0x18 */ +} MPI3_DRIVER_PAGE0, MPI3_POINTER PTR_MPI3_DRIVER_PAGE0, + Mpi3DriverPage0_t, MPI3_POINTER pMpi3DriverPage0_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_DRIVER0_PAGEVERSION (0x00) + +/**** Defines for the BSDOptions field ****/ +#define MPI3_DRIVER0_BSDOPTS_HEADLESS_MODE_ENABLE (0x00000008) +#define MPI3_DRIVER0_BSDOPTS_DIS_HII_CONFIG_UTIL (0x00000004) +#define MPI3_DRIVER0_BSDOPTS_REGISTRATION_MASK (0x00000003) +#define MPI3_DRIVER0_BSDOPTS_REGISTRATION_IOC_AND_DEVS (0x00000000) +#define MPI3_DRIVER0_BSDOPTS_REGISTRATION_IOC_ONLY (0x00000001) +#define MPI3_DRIVER0_BSDOPTS_REGISTRATION_IOC_AND_INTERNAL_DEVS (0x00000002) + +/***************************************************************************** + * Driver Page 1 * + ****************************************************************************/ +typedef struct _MPI3_DRIVER_PAGE1 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Flags; /* 0x08 */ + U32 Reserved0C; /* 0x0C */ + U16 HostDiagTraceMaxSize; /* 0x10 */ + U16 HostDiagTraceMinSize; /* 0x12 */ + U16 HostDiagTraceDecrementSize; /* 0x14 */ + U16 Reserved16; /* 0x16 */ + U16 HostDiagFwMaxSize; /* 0x18 */ + U16 HostDiagFwMinSize; /* 0x1A */ + U16 HostDiagFwDecrementSize; /* 0x1C */ + U16 Reserved1E; /* 0x1E */ + U16 HostDiagDriverMaxSize; /* 0x20 */ + U16 HostDiagDriverMinSize; /* 0x22 */ + U16 HostDiagDriverDecrementSize; /* 0x24 */ + U16 Reserved26; /* 0x26 */ +} MPI3_DRIVER_PAGE1, MPI3_POINTER PTR_MPI3_DRIVER_PAGE1, + Mpi3DriverPage1_t, MPI3_POINTER pMpi3DriverPage1_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_DRIVER1_PAGEVERSION (0x00) + +/***************************************************************************** + * Driver Page 2 * + ****************************************************************************/ +#ifndef MPI3_DRIVER2_TRIGGER_MAX +#define MPI3_DRIVER2_TRIGGER_MAX (1) +#endif /* MPI3_DRIVER2_TRIGGER_MAX */ + +typedef struct _MPI3_DRIVER2_TRIGGER_EVENT +{ + U8 Type; /* 0x00 */ + U8 Flags; /* 0x01 */ + U8 Reserved02; /* 0x02 */ + U8 Event; /* 0x03 */ + U32 Reserved04[3]; /* 0x04 */ +} MPI3_DRIVER2_TRIGGER_EVENT, MPI3_POINTER PTR_MPI3_DRIVER2_TRIGGER_EVENT, + Mpi3Driver2TriggerEvent_t, MPI3_POINTER pMpi3Driver2TriggerEvent_t; + +typedef struct _MPI3_DRIVER2_TRIGGER_SCSI_SENSE +{ + U8 Type; /* 0x00 */ + U8 Flags; /* 0x01 */ + U16 Reserved02; /* 0x02 */ + U8 ASCQ; /* 0x04 */ + U8 ASC; /* 0x05 */ + U8 SenseKey; /* 0x06 */ + U8 Reserved07; /* 0x07 */ + U32 Reserved08[2]; /* 0x08 */ +} MPI3_DRIVER2_TRIGGER_SCSI_SENSE, MPI3_POINTER PTR_MPI3_DRIVER2_TRIGGER_SCSI_SENSE, + Mpi3Driver2TriggerScsiSense_t, MPI3_POINTER pMpi3Driver2TriggerScsiSense_t; + +/**** Defines for the ASCQ field ****/ +#define MPI3_DRIVER2_TRIGGER_SCSI_SENSE_ASCQ_MATCH_ALL (0xFF) + +/**** Defines for the ASC field ****/ +#define MPI3_DRIVER2_TRIGGER_SCSI_SENSE_ASC_MATCH_ALL (0xFF) + +/**** Defines for the SenseKey field ****/ +#define MPI3_DRIVER2_TRIGGER_SCSI_SENSE_SENSE_KEY_MATCH_ALL (0xFF) + +typedef struct _MPI3_DRIVER2_TRIGGER_REPLY +{ + U8 Type; /* 0x00 */ + U8 Flags; /* 0x01 */ + U16 IOCStatus; /* 0x02 */ + U32 IOCLogInfo; /* 0x04 */ + U32 IOCLogInfoMask; /* 0x08 */ + U32 Reserved0C; /* 0x0C */ +} MPI3_DRIVER2_TRIGGER_REPLY, MPI3_POINTER PTR_MPI3_DRIVER2_TRIGGER_REPLY, + Mpi3Driver2TriggerReply_t, MPI3_POINTER pMpi3Driver2TriggerReply_t; + +/**** Defines for the IOCStatus field ****/ +#define MPI3_DRIVER2_TRIGGER_REPLY_IOCSTATUS_MATCH_ALL (0xFFFF) + +typedef union _MPI3_DRIVER2_TRIGGER_ELEMENT +{ + MPI3_DRIVER2_TRIGGER_EVENT Event; + MPI3_DRIVER2_TRIGGER_SCSI_SENSE ScsiSense; + MPI3_DRIVER2_TRIGGER_REPLY Reply; +} MPI3_DRIVER2_TRIGGER_ELEMENT, MPI3_POINTER PTR_MPI3_DRIVER2_TRIGGER_ELEMENT, + Mpi3Driver2TriggerElement_t, MPI3_POINTER pMpi3Driver2TriggerElement_t; + +/**** Defines for the Type field ****/ +#define MPI3_DRIVER2_TRIGGER_TYPE_EVENT (0x00) +#define MPI3_DRIVER2_TRIGGER_TYPE_SCSI_SENSE (0x01) +#define MPI3_DRIVER2_TRIGGER_TYPE_REPLY (0x02) + +/**** Defines for the Flags field ****/ +#define MPI3_DRIVER2_TRIGGER_FLAGS_DIAG_TRACE_RELEASE (0x02) +#define MPI3_DRIVER2_TRIGGER_FLAGS_DIAG_FW_RELEASE (0x01) + +typedef struct _MPI3_DRIVER_PAGE2 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U64 GlobalTrigger; /* 0x08 */ + U32 Reserved10[3]; /* 0x10 */ + U8 NumTriggers; /* 0x1C */ + U8 Reserved1D[3]; /* 0x1D */ + MPI3_DRIVER2_TRIGGER_ELEMENT Trigger[MPI3_DRIVER2_TRIGGER_MAX]; /* 0x20 */ /* variable length */ +} MPI3_DRIVER_PAGE2, MPI3_POINTER PTR_MPI3_DRIVER_PAGE2, + Mpi3DriverPage2_t, MPI3_POINTER pMpi3DriverPage2_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_DRIVER2_PAGEVERSION (0x00) + +/**** Defines for the GlobalTrigger field ****/ +#define MPI3_DRIVER2_GLOBALTRIGGER_DIAG_TRACE_RELEASE (0x8000000000000000ULL) +#define MPI3_DRIVER2_GLOBALTRIGGER_DIAG_FW_RELEASE (0x4000000000000000ULL) +#define MPI3_DRIVER2_GLOBALTRIGGER_SNAPDUMP_ENABLED (0x2000000000000000ULL) +#define MPI3_DRIVER2_GLOBALTRIGGER_POST_DIAG_TRACE_DISABLED (0x1000000000000000ULL) +#define MPI3_DRIVER2_GLOBALTRIGGER_POST_DIAG_FW_DISABLED (0x0800000000000000ULL) +#define MPI3_DRIVER2_GLOBALTRIGGER_DEVICE_REMOVAL_ENABLED (0x0000000000000004ULL) +#define MPI3_DRIVER2_GLOBALTRIGGER_TASK_MANAGEMENT_ENABLED (0x0000000000000002ULL) + +/***************************************************************************** + * Driver Page 10 * + ****************************************************************************/ + +typedef struct _MPI3_DRIVER_PAGE10 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 Flags; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U8 NumAllowedCommands; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + MPI3_ALLOWED_CMD AllowedCommand[MPI3_ALLOWED_CMDS_MAX]; /* 0x10 */ /* variable length */ +} MPI3_DRIVER_PAGE10, MPI3_POINTER PTR_MPI3_DRIVER_PAGE10, + Mpi3DriverPage10_t, MPI3_POINTER pMpi3DriverPage10_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_DRIVER10_PAGEVERSION (0x00) + +/**** Defines for the Flags field - use MPI3_DRIVER_FLAGS_ defines ****/ + +/***************************************************************************** + * Driver Page 20 * + ****************************************************************************/ + +typedef struct _MPI3_DRIVER_PAGE20 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 Flags; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U8 NumAllowedCommands; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + MPI3_ALLOWED_CMD AllowedCommand[MPI3_ALLOWED_CMDS_MAX]; /* 0x10 */ /* variable length */ +} MPI3_DRIVER_PAGE20, MPI3_POINTER PTR_MPI3_DRIVER_PAGE20, + Mpi3DriverPage20_t, MPI3_POINTER pMpi3DriverPage20_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_DRIVER20_PAGEVERSION (0x00) + +/**** Defines for the Flags field - use MPI3_DRIVER_FLAGS_ defines ****/ + +/***************************************************************************** + * Driver Page 30 * + ****************************************************************************/ + +typedef struct _MPI3_DRIVER_PAGE30 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 Flags; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U8 NumAllowedCommands; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + MPI3_ALLOWED_CMD AllowedCommand[MPI3_ALLOWED_CMDS_MAX]; /* 0x10 */ /* variable length */ +} MPI3_DRIVER_PAGE30, MPI3_POINTER PTR_MPI3_DRIVER_PAGE30, + Mpi3DriverPage30_t, MPI3_POINTER pMpi3DriverPage30_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_DRIVER30_PAGEVERSION (0x00) + +/**** Defines for the Flags field - use MPI3_DRIVER_FLAGS_ defines ****/ + +/***************************************************************************** + * Security Configuration Pages * + ****************************************************************************/ + +typedef union _MPI3_SECURITY_MAC +{ + U32 Dword[16]; + U16 Word[32]; + U8 Byte[64]; +} MPI3_SECURITY_MAC, MPI3_POINTER PTR_MPI3_SECURITY_MAC, + Mpi3SecurityMAC_t, MPI3_POINTER pMpi3SecurityMAC_t; + +typedef union _MPI3_SECURITY_NONCE +{ + U32 Dword[16]; + U16 Word[32]; + U8 Byte[64]; +} MPI3_SECURITY_NONCE, MPI3_POINTER PTR_MPI3_SECURITY_NONCE, + Mpi3SecurityNonce_t, MPI3_POINTER pMpi3SecurityNonce_t; + +typedef union _MPI3_SECURITY_ROOT_DIGEST +{ + U32 Dword[16]; + U16 Word[32]; + U8 Byte[64]; +} MPI3_SECURITY_ROOT_DIGEST, MPI3_POINTER PTR_MPI3_SECURITY_ROOT_DIGEST, + Mpi3SecurityRootDigest_t, MPI3_POINTER pMpi3SecurityRootDigest_t; + +/***************************************************************************** + * Security Page 0 * + ****************************************************************************/ + +typedef union _MPI3_SECURITY0_CERT_CHAIN +{ + U32 Dword[1024]; + U16 Word[2048]; + U8 Byte[4096]; +} MPI3_SECURITY0_CERT_CHAIN, MPI3_POINTER PTR_MPI3_SECURITY0_CERT_CHAIN, + Mpi3Security0CertChain_t, MPI3_POINTER pMpi3Security0CertChain_t; + +typedef struct _MPI3_SECURITY_PAGE0 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 SlotNumGroup; /* 0x08 */ + U8 SlotNum; /* 0x09 */ + U16 CertChainLength; /* 0x0A */ + U8 CertChainFlags; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + U32 BaseAsymAlgo; /* 0x10 */ + U32 BaseHashAlgo; /* 0x14 */ + U32 Reserved18[4]; /* 0x18 */ + MPI3_SECURITY_MAC Mac; /* 0x28 */ + MPI3_SECURITY_NONCE Nonce; /* 0x68 */ + MPI3_SECURITY0_CERT_CHAIN CertificateChain; /* 0xA8 */ +} MPI3_SECURITY_PAGE0, MPI3_POINTER PTR_MPI3_SECURITY_PAGE0, + Mpi3SecurityPage0_t, MPI3_POINTER pMpi3SecurityPage0_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_SECURITY0_PAGEVERSION (0x00) + +/**** Defines for the CertChainFlags field ****/ +#define MPI3_SECURITY0_CERTCHAIN_FLAGS_AUTH_API_MASK (0x0E) +#define MPI3_SECURITY0_CERTCHAIN_FLAGS_AUTH_API_UNUSED (0x00) +#define MPI3_SECURITY0_CERTCHAIN_FLAGS_AUTH_API_CERBERUS (0x02) +#define MPI3_SECURITY0_CERTCHAIN_FLAGS_AUTH_API_SPDM (0x04) +#define MPI3_SECURITY0_CERTCHAIN_FLAGS_SEALED (0x01) + +/***************************************************************************** + * Security Page 1 * + ****************************************************************************/ + +#ifndef MPI3_SECURITY1_KEY_RECORD_MAX +#define MPI3_SECURITY1_KEY_RECORD_MAX 1 +#endif /* MPI3_SECURITY1_KEY_RECORD_MAX */ + +#ifndef MPI3_SECURITY1_PAD_MAX +#define MPI3_SECURITY1_PAD_MAX 4 +#endif /* MPI3_SECURITY1_PAD_MAX */ + +typedef union _MPI3_SECURITY1_KEY_DATA +{ + U32 Dword[128]; + U16 Word[256]; + U8 Byte[512]; +} MPI3_SECURITY1_KEY_DATA, MPI3_POINTER PTR_MPI3_SECURITY1_KEY_DATA, + Mpi3Security1KeyData_t, MPI3_POINTER pMpi3Security1KeyData_t; + +typedef struct _MPI3_SECURITY1_KEY_RECORD +{ + U8 Flags; /* 0x00 */ + U8 Consumer; /* 0x01 */ + U16 KeyDataSize; /* 0x02 */ + U32 AdditionalKeyData; /* 0x04 */ + U32 Reserved08[2]; /* 0x08 */ + MPI3_SECURITY1_KEY_DATA KeyData; /* 0x10 */ +} MPI3_SECURITY1_KEY_RECORD, MPI3_POINTER PTR_MPI3_SECURITY1_KEY_RECORD, + Mpi3Security1KeyRecord_t, MPI3_POINTER pMpi3Security1KeyRecord_t; + +/**** Defines for the Flags field ****/ +#define MPI3_SECURITY1_KEY_RECORD_FLAGS_TYPE_MASK (0x1F) +#define MPI3_SECURITY1_KEY_RECORD_FLAGS_TYPE_NOT_VALID (0x00) +#define MPI3_SECURITY1_KEY_RECORD_FLAGS_TYPE_HMAC (0x01) +#define MPI3_SECURITY1_KEY_RECORD_FLAGS_TYPE_AES (0x02) +#define MPI3_SECURITY1_KEY_RECORD_FLAGS_TYPE_ECDSA_PRIVATE (0x03) +#define MPI3_SECURITY1_KEY_RECORD_FLAGS_TYPE_ECDSA_PUBLIC (0x04) + +/**** Defines for the Consumer field ****/ +#define MPI3_SECURITY1_KEY_RECORD_CONSUMER_NOT_VALID (0x00) +#define MPI3_SECURITY1_KEY_RECORD_CONSUMER_SAFESTORE (0x01) +#define MPI3_SECURITY1_KEY_RECORD_CONSUMER_CERT_CHAIN (0x02) +#define MPI3_SECURITY1_KEY_RECORD_CONSUMER_DEVICE_KEY (0x03) +#define MPI3_SECURITY1_KEY_RECORD_CONSUMER_CACHE_OFFLOAD (0x04) + +typedef struct _MPI3_SECURITY_PAGE1 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08[2]; /* 0x08 */ + MPI3_SECURITY_MAC Mac; /* 0x10 */ + MPI3_SECURITY_NONCE Nonce; /* 0x50 */ + U8 NumKeys; /* 0x90 */ + U8 Reserved91[3]; /* 0x91 */ + U32 Reserved94[3]; /* 0x94 */ + MPI3_SECURITY1_KEY_RECORD KeyRecord[MPI3_SECURITY1_KEY_RECORD_MAX]; /* 0xA0 */ + U8 Pad[MPI3_SECURITY1_PAD_MAX]; /* ?? */ +} MPI3_SECURITY_PAGE1, MPI3_POINTER PTR_MPI3_SECURITY_PAGE1, + Mpi3SecurityPage1_t, MPI3_POINTER pMpi3SecurityPage1_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_SECURITY1_PAGEVERSION (0x00) + + +/***************************************************************************** + * Security Page 2 * + ****************************************************************************/ + +#ifndef MPI3_SECURITY2_TRUSTED_ROOT_MAX +#define MPI3_SECURITY2_TRUSTED_ROOT_MAX 1 +#endif /* MPI3_SECURITY2_TRUSTED_ROOT_MAX */ + +typedef struct _MPI3_SECURITY2_TRUSTED_ROOT +{ + U8 Level; /* 0x00 */ + U8 HashAlgorithm; /* 0x01 */ + U16 TrustedRootFlags; /* 0x02 */ + U32 Reserved04[3]; /* 0x04 */ + MPI3_SECURITY_ROOT_DIGEST RootDigest; /* 0x10 */ +} MPI3_SECURITY2_TRUSTED_ROOT, MPI3_POINTER PTR_MPI3_SECURITY2_TRUSTED_ROOT, + Mpi3Security2TrustedRoot_t, MPI3_POINTER pMpi3Security2TrustedRoot_t; + +/**** Defines for the TrustedRootFlags field ****/ +#define MPI3_SECURITY2_TRUSTEDROOT_TRUSTEDROOTFLAGS_HASHALGOSOURCE_MASK (0x0006) +#define MPI3_SECURITY2_TRUSTEDROOT_TRUSTEDROOTFLAGS_HASHALGOSOURCE_SHIFT (1) +#define MPI3_SECURITY2_TRUSTEDROOT_TRUSTEDROOTFLAGS_HASHALGOSOURCE_HA_FIELD (0x0000) +#define MPI3_SECURITY2_TRUSTEDROOT_TRUSTEDROOTFLAGS_HASHALGOSOURCE_AKI (0x0002) +#define MPI3_SECURITY2_TRUSTEDROOT_TRUSTEDROOTFLAGS_USERPROVISIONED_YES (0x0001) + +typedef struct _MPI3_SECURITY_PAGE2 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08[2]; /* 0x08 */ + MPI3_SECURITY_MAC Mac; /* 0x10 */ + MPI3_SECURITY_NONCE Nonce; /* 0x50 */ + U32 Reserved90[3]; /* 0x90 */ + U8 NumRoots; /* 0x9C */ + U8 Reserved9D[3]; /* 0x9D */ + MPI3_SECURITY2_TRUSTED_ROOT TrustedRoot[MPI3_SECURITY2_TRUSTED_ROOT_MAX]; /* 0xA0 */ /* variable length */ +} MPI3_SECURITY_PAGE2, MPI3_POINTER PTR_MPI3_SECURITY_PAGE2, + Mpi3SecurityPage2_t, MPI3_POINTER pMpi3SecurityPage2_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_SECURITY2_PAGEVERSION (0x00) + + +/***************************************************************************** + * SAS IO Unit Configuration Pages * + ****************************************************************************/ + +/***************************************************************************** + * SAS IO Unit Page 0 * + ****************************************************************************/ +typedef struct _MPI3_SAS_IO_UNIT0_PHY_DATA +{ + U8 IOUnitPort; /* 0x00 */ + U8 PortFlags; /* 0x01 */ + U8 PhyFlags; /* 0x02 */ + U8 NegotiatedLinkRate; /* 0x03 */ + U16 ControllerPhyDeviceInfo; /* 0x04 */ + U16 Reserved06; /* 0x06 */ + U16 AttachedDevHandle; /* 0x08 */ + U16 ControllerDevHandle; /* 0x0A */ + U32 DiscoveryStatus; /* 0x0C */ + U32 Reserved10; /* 0x10 */ +} MPI3_SAS_IO_UNIT0_PHY_DATA, MPI3_POINTER PTR_MPI3_SAS_IO_UNIT0_PHY_DATA, + Mpi3SasIOUnit0PhyData_t, MPI3_POINTER pMpi3SasIOUnit0PhyData_t; + +#ifndef MPI3_SAS_IO_UNIT0_PHY_MAX +#define MPI3_SAS_IO_UNIT0_PHY_MAX (1) +#endif /* MPI3_SAS_IO_UNIT0_PHY_MAX */ + +typedef struct _MPI3_SAS_IO_UNIT_PAGE0 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U8 NumPhys; /* 0x0C */ + U8 InitStatus; /* 0x0D */ + U16 Reserved0E; /* 0x0E */ + MPI3_SAS_IO_UNIT0_PHY_DATA PhyData[MPI3_SAS_IO_UNIT0_PHY_MAX]; /* 0x10 */ +} MPI3_SAS_IO_UNIT_PAGE0, MPI3_POINTER PTR_MPI3_SAS_IO_UNIT_PAGE0, + Mpi3SasIOUnitPage0_t, MPI3_POINTER pMpi3SasIOUnitPage0_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_SASIOUNIT0_PAGEVERSION (0x00) + +/**** Defines for the InitStatus field ****/ +#define MPI3_SASIOUNIT0_INITSTATUS_NO_ERRORS (0x00) +#define MPI3_SASIOUNIT0_INITSTATUS_NEEDS_INITIALIZATION (0x01) +#define MPI3_SASIOUNIT0_INITSTATUS_NO_TARGETS_ALLOCATED (0x02) +#define MPI3_SASIOUNIT0_INITSTATUS_BAD_NUM_PHYS (0x04) +#define MPI3_SASIOUNIT0_INITSTATUS_UNSUPPORTED_CONFIG (0x05) +#define MPI3_SASIOUNIT0_INITSTATUS_HOST_PHYS_ENABLED (0x06) +#define MPI3_SASIOUNIT0_INITSTATUS_PRODUCT_SPECIFIC_MIN (0xF0) +#define MPI3_SASIOUNIT0_INITSTATUS_PRODUCT_SPECIFIC_MAX (0xFF) + +/**** Defines for the PortFlags field ****/ +#define MPI3_SASIOUNIT0_PORTFLAGS_DISC_IN_PROGRESS (0x08) +#define MPI3_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG_MASK (0x03) +#define MPI3_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG_IOUNIT1 (0x00) +#define MPI3_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG_DYNAMIC (0x01) +#define MPI3_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG_BACKPLANE (0x02) + +/**** Defines for the PhyFlags field ****/ +#define MPI3_SASIOUNIT0_PHYFLAGS_INIT_PERSIST_CONNECT (0x40) +#define MPI3_SASIOUNIT0_PHYFLAGS_TARG_PERSIST_CONNECT (0x20) +#define MPI3_SASIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08) +#define MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY (0x02) +#define MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY (0x01) + +/**** Use MPI3_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field ****/ + +/**** Use MPI3_SAS_DEVICE_INFO_ defines (see mpi30_sas.h) for the ControllerPhyDeviceInfo field ****/ + +/**** Use MPI3_SAS_DISC_STATUS_ defines (see mpi30_ioc.h) for the DiscoveryStatus field ****/ + +/***************************************************************************** + * SAS IO Unit Page 1 * + ****************************************************************************/ +typedef struct _MPI3_SAS_IO_UNIT1_PHY_DATA +{ + U8 IOUnitPort; /* 0x00 */ + U8 PortFlags; /* 0x01 */ + U8 PhyFlags; /* 0x02 */ + U8 MaxMinLinkRate; /* 0x03 */ + U16 ControllerPhyDeviceInfo; /* 0x04 */ + U16 MaxTargetPortConnectTime; /* 0x06 */ + U32 Reserved08; /* 0x08 */ +} MPI3_SAS_IO_UNIT1_PHY_DATA, MPI3_POINTER PTR_MPI3_SAS_IO_UNIT1_PHY_DATA, + Mpi3SasIOUnit1PhyData_t, MPI3_POINTER pMpi3SasIOUnit1PhyData_t; + +#ifndef MPI3_SAS_IO_UNIT1_PHY_MAX +#define MPI3_SAS_IO_UNIT1_PHY_MAX (1) +#endif /* MPI3_SAS_IO_UNIT1_PHY_MAX */ + +typedef struct _MPI3_SAS_IO_UNIT_PAGE1 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 ControlFlags; /* 0x08 */ + U16 SASNarrowMaxQueueDepth; /* 0x0A */ + U16 AdditionalControlFlags; /* 0x0C */ + U16 SASWideMaxQueueDepth; /* 0x0E */ + U8 NumPhys; /* 0x10 */ + U8 SATAMaxQDepth; /* 0x11 */ + U16 Reserved12; /* 0x12 */ + MPI3_SAS_IO_UNIT1_PHY_DATA PhyData[MPI3_SAS_IO_UNIT1_PHY_MAX]; /* 0x14 */ +} MPI3_SAS_IO_UNIT_PAGE1, MPI3_POINTER PTR_MPI3_SAS_IO_UNIT_PAGE1, + Mpi3SasIOUnitPage1_t, MPI3_POINTER pMpi3SasIOUnitPage1_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_SASIOUNIT1_PAGEVERSION (0x00) + +/**** Defines for the ControlFlags field ****/ +#define MPI3_SASIOUNIT1_CONTROL_CONTROLLER_DEVICE_SELF_TEST (0x8000) +#define MPI3_SASIOUNIT1_CONTROL_SATA_SW_PRESERVE (0x1000) +#define MPI3_SASIOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED (0x0080) +#define MPI3_SASIOUNIT1_CONTROL_SATA_SMART_REQUIRED (0x0040) +#define MPI3_SASIOUNIT1_CONTROL_SATA_NCQ_REQUIRED (0x0020) +#define MPI3_SASIOUNIT1_CONTROL_SATA_FUA_REQUIRED (0x0010) +#define MPI3_SASIOUNIT1_CONTROL_TABLE_SUBTRACTIVE_ILLEGAL (0x0008) +#define MPI3_SASIOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL (0x0004) +#define MPI3_SASIOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY (0x0002) +#define MPI3_SASIOUNIT1_CONTROL_HARD_RESET_MASK (0x0001) +#define MPI3_SASIOUNIT1_CONTROL_HARD_RESET_DEVICE_NAME (0x0000) +#define MPI3_SASIOUNIT1_CONTROL_HARD_RESET_SAS_ADDRESS (0x0001) + +/**** Defines for the AdditionalControlFlags field ****/ +#define MPI3_SASIOUNIT1_ACONTROL_DA_PERSIST_CONNECT (0x0100) +#define MPI3_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080) +#define MPI3_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040) +#define MPI3_SASIOUNIT1_ACONTROL_INVALID_TOPOLOGY_CORRECTION (0x0020) +#define MPI3_SASIOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET (0x0010) +#define MPI3_SASIOUNIT1_ACONTROL_OTHER_AFFILIATION_SATA_LINK_RESET (0x0008) +#define MPI3_SASIOUNIT1_ACONTROL_SELF_AFFILIATION_SATA_LINK_RESET (0x0004) +#define MPI3_SASIOUNIT1_ACONTROL_NO_AFFILIATION_SATA_LINK_RESET (0x0002) +#define MPI3_SASIOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001) + +/**** Defines for the PortFlags field ****/ +#define MPI3_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) + +/**** Defines for the PhyFlags field ****/ +#define MPI3_SASIOUNIT1_PHYFLAGS_INIT_PERSIST_CONNECT (0x40) +#define MPI3_SASIOUNIT1_PHYFLAGS_TARG_PERSIST_CONNECT (0x20) +#define MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08) + +/**** Defines for the MaxMinLinkRate field ****/ +#define MPI3_SASIOUNIT1_MMLR_MAX_RATE_MASK (0xF0) +#define MPI3_SASIOUNIT1_MMLR_MAX_RATE_SHIFT (4) +#define MPI3_SASIOUNIT1_MMLR_MAX_RATE_6_0 (0xA0) +#define MPI3_SASIOUNIT1_MMLR_MAX_RATE_12_0 (0xB0) +#define MPI3_SASIOUNIT1_MMLR_MAX_RATE_22_5 (0xC0) +#define MPI3_SASIOUNIT1_MMLR_MIN_RATE_MASK (0x0F) +#define MPI3_SASIOUNIT1_MMLR_MIN_RATE_6_0 (0x0A) +#define MPI3_SASIOUNIT1_MMLR_MIN_RATE_12_0 (0x0B) +#define MPI3_SASIOUNIT1_MMLR_MIN_RATE_22_5 (0x0C) + +/**** Use MPI3_SAS_DEVICE_INFO_ defines (see mpi30_sas.h) for the ControllerPhyDeviceInfo field ****/ + +/***************************************************************************** + * SAS IO Unit Page 2 * + ****************************************************************************/ +typedef struct _MPI3_SAS_IO_UNIT2_PHY_PM_SETTINGS +{ + U8 ControlFlags; /* 0x00 */ + U8 Reserved01; /* 0x01 */ + U16 InactivityTimerExponent; /* 0x02 */ + U8 SATAPartialTimeout; /* 0x04 */ + U8 Reserved05; /* 0x05 */ + U8 SATASlumberTimeout; /* 0x06 */ + U8 Reserved07; /* 0x07 */ + U8 SASPartialTimeout; /* 0x08 */ + U8 Reserved09; /* 0x09 */ + U8 SASSlumberTimeout; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ +} MPI3_SAS_IO_UNIT2_PHY_PM_SETTINGS, MPI3_POINTER PTR_MPI3_SAS_IO_UNIT2_PHY_PM_SETTINGS, + Mpi3SasIOUnit2PhyPmSettings_t, MPI3_POINTER pMpi3SasIOUnit2PhyPmSettings_t; + +#ifndef MPI3_SAS_IO_UNIT2_PHY_MAX +#define MPI3_SAS_IO_UNIT2_PHY_MAX (1) +#endif /* MPI3_SAS_IO_UNIT2_PHY_MAX */ + +typedef struct _MPI3_SAS_IO_UNIT_PAGE2 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumPhys; /* 0x08 */ + U8 Reserved09[3]; /* 0x09 */ + U32 Reserved0C; /* 0x0C */ + MPI3_SAS_IO_UNIT2_PHY_PM_SETTINGS SASPhyPowerManagementSettings[MPI3_SAS_IO_UNIT2_PHY_MAX]; /* 0x10 */ +} MPI3_SAS_IO_UNIT_PAGE2, MPI3_POINTER PTR_MPI3_SAS_IO_UNIT_PAGE2, + Mpi3SasIOUnitPage2_t, MPI3_POINTER pMpi3SasIOUnitPage2_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_SASIOUNIT2_PAGEVERSION (0x00) + +/**** Defines for the ControlFlags field ****/ +#define MPI3_SASIOUNIT2_CONTROL_SAS_SLUMBER_ENABLE (0x08) +#define MPI3_SASIOUNIT2_CONTROL_SAS_PARTIAL_ENABLE (0x04) +#define MPI3_SASIOUNIT2_CONTROL_SATA_SLUMBER_ENABLE (0x02) +#define MPI3_SASIOUNIT2_CONTROL_SATA_PARTIAL_ENABLE (0x01) + +/**** Defines for the InactivityTimerExponent field ****/ +#define MPI3_SASIOUNIT2_ITE_SAS_SLUMBER_MASK (0x7000) +#define MPI3_SASIOUNIT2_ITE_SAS_SLUMBER_SHIFT (12) +#define MPI3_SASIOUNIT2_ITE_SAS_PARTIAL_MASK (0x0700) +#define MPI3_SASIOUNIT2_ITE_SAS_PARTIAL_SHIFT (8) +#define MPI3_SASIOUNIT2_ITE_SATA_SLUMBER_MASK (0x0070) +#define MPI3_SASIOUNIT2_ITE_SATA_SLUMBER_SHIFT (4) +#define MPI3_SASIOUNIT2_ITE_SATA_PARTIAL_MASK (0x0007) +#define MPI3_SASIOUNIT2_ITE_SATA_PARTIAL_SHIFT (0) + +#define MPI3_SASIOUNIT2_ITE_EXP_TEN_SECONDS (7) +#define MPI3_SASIOUNIT2_ITE_EXP_ONE_SECOND (6) +#define MPI3_SASIOUNIT2_ITE_EXP_HUNDRED_MILLISECONDS (5) +#define MPI3_SASIOUNIT2_ITE_EXP_TEN_MILLISECONDS (4) +#define MPI3_SASIOUNIT2_ITE_EXP_ONE_MILLISECOND (3) +#define MPI3_SASIOUNIT2_ITE_EXP_HUNDRED_MICROSECONDS (2) +#define MPI3_SASIOUNIT2_ITE_EXP_TEN_MICROSECONDS (1) +#define MPI3_SASIOUNIT2_ITE_EXP_ONE_MICROSECOND (0) + +/***************************************************************************** + * SAS IO Unit Page 3 * + ****************************************************************************/ +typedef struct _MPI3_SAS_IO_UNIT_PAGE3 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U32 PowerManagementCapabilities; /* 0x0C */ +} MPI3_SAS_IO_UNIT_PAGE3, MPI3_POINTER PTR_MPI3_SAS_IO_UNIT_PAGE3, + Mpi3SasIOUnitPage3_t, MPI3_POINTER pMpi3SasIOUnitPage3_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_SASIOUNIT3_PAGEVERSION (0x00) + +/**** Defines for the PowerManagementCapabilities field ****/ +#define MPI3_SASIOUNIT3_PM_HOST_SAS_SLUMBER_MODE (0x00000800) +#define MPI3_SASIOUNIT3_PM_HOST_SAS_PARTIAL_MODE (0x00000400) +#define MPI3_SASIOUNIT3_PM_HOST_SATA_SLUMBER_MODE (0x00000200) +#define MPI3_SASIOUNIT3_PM_HOST_SATA_PARTIAL_MODE (0x00000100) +#define MPI3_SASIOUNIT3_PM_IOUNIT_SAS_SLUMBER_MODE (0x00000008) +#define MPI3_SASIOUNIT3_PM_IOUNIT_SAS_PARTIAL_MODE (0x00000004) +#define MPI3_SASIOUNIT3_PM_IOUNIT_SATA_SLUMBER_MODE (0x00000002) +#define MPI3_SASIOUNIT3_PM_IOUNIT_SATA_PARTIAL_MODE (0x00000001) + + +/***************************************************************************** + * SAS Expander Configuration Pages * + ****************************************************************************/ + +/***************************************************************************** + * SAS Expander Page 0 * + ****************************************************************************/ +typedef struct _MPI3_SAS_EXPANDER_PAGE0 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 IOUnitPort; /* 0x08 */ + U8 ReportGenLength; /* 0x09 */ + U16 EnclosureHandle; /* 0x0A */ + U32 Reserved0C; /* 0x0C */ + U64 SASAddress; /* 0x10 */ + U32 DiscoveryStatus; /* 0x18 */ + U16 DevHandle; /* 0x1C */ + U16 ParentDevHandle; /* 0x1E */ + U16 ExpanderChangeCount; /* 0x20 */ + U16 ExpanderRouteIndexes; /* 0x22 */ + U8 NumPhys; /* 0x24 */ + U8 SASLevel; /* 0x25 */ + U16 Flags; /* 0x26 */ + U16 STPBusInactivityTimeLimit; /* 0x28 */ + U16 STPMaxConnectTimeLimit; /* 0x2A */ + U16 STP_SMP_NexusLossTime; /* 0x2C */ + U16 MaxNumRoutedSASAddresses; /* 0x2E */ + U64 ActiveZoneManagerSASAddress; /* 0x30 */ + U16 ZoneLockInactivityLimit; /* 0x38 */ + U16 Reserved3A; /* 0x3A */ + U8 TimeToReducedFunc; /* 0x3C */ + U8 InitialTimeToReducedFunc; /* 0x3D */ + U8 MaxReducedFuncTime; /* 0x3E */ + U8 ExpStatus; /* 0x3F */ +} MPI3_SAS_EXPANDER_PAGE0, MPI3_POINTER PTR_MPI3_SAS_EXPANDER_PAGE0, + Mpi3SasExpanderPage0_t, MPI3_POINTER pMpi3SasExpanderPage0_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_SASEXPANDER0_PAGEVERSION (0x00) + +/**** Use MPI3_SAS_DISC_STATUS_ defines (see mpi30_ioc.h) for the DiscoveryStatus field ****/ + +/**** Defines for the Flags field ****/ +#define MPI3_SASEXPANDER0_FLAGS_REDUCED_FUNCTIONALITY (0x2000) +#define MPI3_SASEXPANDER0_FLAGS_ZONE_LOCKED (0x1000) +#define MPI3_SASEXPANDER0_FLAGS_SUPPORTED_PHYSICAL_PRES (0x0800) +#define MPI3_SASEXPANDER0_FLAGS_ASSERTED_PHYSICAL_PRES (0x0400) +#define MPI3_SASEXPANDER0_FLAGS_ZONING_SUPPORT (0x0200) +#define MPI3_SASEXPANDER0_FLAGS_ENABLED_ZONING (0x0100) +#define MPI3_SASEXPANDER0_FLAGS_TABLE_TO_TABLE_SUPPORT (0x0080) +#define MPI3_SASEXPANDER0_FLAGS_CONNECTOR_END_DEVICE (0x0010) +#define MPI3_SASEXPANDER0_FLAGS_OTHERS_CONFIG (0x0004) +#define MPI3_SASEXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x0002) +#define MPI3_SASEXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x0001) + +/**** Defines for the ExpStatus field ****/ +#define MPI3_SASEXPANDER0_ES_NOT_RESPONDING (0x02) +#define MPI3_SASEXPANDER0_ES_RESPONDING (0x03) +#define MPI3_SASEXPANDER0_ES_DELAY_NOT_RESPONDING (0x04) + +/***************************************************************************** + * SAS Expander Page 1 * + ****************************************************************************/ +typedef struct _MPI3_SAS_EXPANDER_PAGE1 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 IOUnitPort; /* 0x08 */ + U8 Reserved09[3]; /* 0x09 */ + U8 NumPhys; /* 0x0C */ + U8 Phy; /* 0x0D */ + U16 NumTableEntriesProgrammed; /* 0x0E */ + U8 ProgrammedLinkRate; /* 0x10 */ + U8 HwLinkRate; /* 0x11 */ + U16 AttachedDevHandle; /* 0x12 */ + U32 PhyInfo; /* 0x14 */ + U16 AttachedDeviceInfo; /* 0x18 */ + U16 Reserved1A; /* 0x1A */ + U16 ExpanderDevHandle; /* 0x1C */ + U8 ChangeCount; /* 0x1E */ + U8 NegotiatedLinkRate; /* 0x1F */ + U8 PhyIdentifier; /* 0x20 */ + U8 AttachedPhyIdentifier; /* 0x21 */ + U8 Reserved22; /* 0x22 */ + U8 DiscoveryInfo; /* 0x23 */ + U32 AttachedPhyInfo; /* 0x24 */ + U8 ZoneGroup; /* 0x28 */ + U8 SelfConfigStatus; /* 0x29 */ + U16 Reserved2A; /* 0x2A */ + U16 Slot; /* 0x2C */ + U16 SlotIndex; /* 0x2E */ +} MPI3_SAS_EXPANDER_PAGE1, MPI3_POINTER PTR_MPI3_SAS_EXPANDER_PAGE1, + Mpi3SasExpanderPage1_t, MPI3_POINTER pMpi3SasExpanderPage1_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_SASEXPANDER1_PAGEVERSION (0x00) + +/**** Defines for the ProgrammedLinkRate field - use MPI3_SAS_PRATE_ defines ****/ + +/**** Defines for the HwLinkRate field - use MPI3_SAS_HWRATE_ defines ****/ + +/**** Defines for the PhyInfo field - use MPI3_SAS_PHYINFO_ defines ****/ + +/**** Defines for the AttachedDeviceInfo field - use MPI3_SAS_DEVICE_INFO_ defines ****/ + +/**** Defines for the NegotiatedLinkRate field - use use MPI3_SAS_NEG_LINK_RATE_ defines ****/ + +/**** Defines for the DiscoveryInfo field ****/ +#define MPI3_SASEXPANDER1_DISCINFO_BAD_PHY_DISABLED (0x04) +#define MPI3_SASEXPANDER1_DISCINFO_LINK_STATUS_CHANGE (0x02) +#define MPI3_SASEXPANDER1_DISCINFO_NO_ROUTING_ENTRIES (0x01) + +/**** Defines for the AttachedPhyInfo field - use MPI3_SAS_APHYINFO_ defines ****/ + +/**** Defines for the Slot field - use MPI3_SLOT_ defines ****/ + +/**** Defines for the SlotIndex field - use MPI3_SLOT_INDEX_ ****/ + + +/***************************************************************************** + * SAS Expander Page 2 * + ****************************************************************************/ +#ifndef MPI3_SASEXPANDER2_MAX_NUM_PHYS +#define MPI3_SASEXPANDER2_MAX_NUM_PHYS (1) +#endif /* MPI3_SASEXPANDER2_MAX_NUM_PHYS */ + +typedef struct _MPI3_SASEXPANDER2_PHY_ELEMENT +{ + U8 LinkChangeCount; /* 0x00 */ + U8 Reserved01; /* 0x01 */ + U16 RateChangeCount; /* 0x02 */ + U32 Reserved04; /* 0x04 */ +} MPI3_SASEXPANDER2_PHY_ELEMENT, MPI3_POINTER PTR_MPI3_SASEXPANDER2_PHY_ELEMENT, + Mpi3SasExpander2PhyElement_t, MPI3_POINTER pMpi3SasExpander2PhyElement_t; + +typedef struct _MPI3_SAS_EXPANDER_PAGE2 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumPhys; /* 0x08 */ + U8 Reserved09; /* 0x09 */ + U16 DevHandle; /* 0x0A */ + U32 Reserved0C; /* 0x0C */ + MPI3_SASEXPANDER2_PHY_ELEMENT Phy[MPI3_SASEXPANDER2_MAX_NUM_PHYS]; /* 0x10 */ /* variable length */ + +} MPI3_SAS_EXPANDER_PAGE2, MPI3_POINTER PTR_MPI3_SAS_EXPANDER_PAGE2, + Mpi3SasExpanderPage2_t, MPI3_POINTER pMpi3SasExpanderPage2_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_SASEXPANDER2_PAGEVERSION (0x00) + + +/***************************************************************************** + * SAS Port Configuration Pages * + ****************************************************************************/ + +/***************************************************************************** + * SAS Port Page 0 * + ****************************************************************************/ +typedef struct _MPI3_SAS_PORT_PAGE0 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 PortNumber; /* 0x08 */ + U8 Reserved09; /* 0x09 */ + U8 PortWidth; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U8 ZoneGroup; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + U64 SASAddress; /* 0x10 */ + U16 DeviceInfo; /* 0x18 */ + U16 Reserved1A; /* 0x1A */ + U32 Reserved1C; /* 0x1C */ +} MPI3_SAS_PORT_PAGE0, MPI3_POINTER PTR_MPI3_SAS_PORT_PAGE0, + Mpi3SasPortPage0_t, MPI3_POINTER pMpi3SasPortPage0_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_SASPORT0_PAGEVERSION (0x00) + +/**** Defines for the DeviceInfo field - use MPI3_SAS_DEVICE_INFO_ defines ****/ + +/***************************************************************************** + * SAS PHY Configuration Pages * + ****************************************************************************/ + +/***************************************************************************** + * SAS PHY Page 0 * + ****************************************************************************/ +typedef struct _MPI3_SAS_PHY_PAGE0 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 OwnerDevHandle; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U16 AttachedDevHandle; /* 0x0C */ + U8 AttachedPhyIdentifier; /* 0x0E */ + U8 Reserved0F; /* 0x0F */ + U32 AttachedPhyInfo; /* 0x10 */ + U8 ProgrammedLinkRate; /* 0x14 */ + U8 HwLinkRate; /* 0x15 */ + U8 ChangeCount; /* 0x16 */ + U8 Flags; /* 0x17 */ + U32 PhyInfo; /* 0x18 */ + U8 NegotiatedLinkRate; /* 0x1C */ + U8 Reserved1D[3]; /* 0x1D */ + U16 Slot; /* 0x20 */ + U16 SlotIndex; /* 0x22 */ +} MPI3_SAS_PHY_PAGE0, MPI3_POINTER PTR_MPI3_SAS_PHY_PAGE0, + Mpi3SasPhyPage0_t, MPI3_POINTER pMpi3SasPhyPage0_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_SASPHY0_PAGEVERSION (0x00) + +/**** Defines for the AttachedPhyInfo field - use MPI3_SAS_APHYINFO_ defines ****/ + +/**** Defines for the ProgrammedLinkRate field - use MPI3_SAS_PRATE_ defines ****/ + +/**** Defines for the HwLinkRate field - use MPI3_SAS_HWRATE_ defines ****/ + +/**** Defines for the Flags field ****/ +#define MPI3_SASPHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC (0x01) + +/**** Defines for the PhyInfo field - use MPI3_SAS_PHYINFO_ defines ****/ + +/**** Defines for the NegotiatedLinkRate field - use MPI3_SAS_NEG_LINK_RATE_ defines ****/ + +/**** Defines for the Slot field - use MPI3_SLOT_ defines ****/ + +/**** Defines for the SlotIndex field - use MPI3_SLOT_INDEX_ ****/ + +/***************************************************************************** + * SAS PHY Page 1 * + ****************************************************************************/ +typedef struct _MPI3_SAS_PHY_PAGE1 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U32 InvalidDwordCount; /* 0x0C */ + U32 RunningDisparityErrorCount; /* 0x10 */ + U32 LossDwordSynchCount; /* 0x14 */ + U32 PhyResetProblemCount; /* 0x18 */ +} MPI3_SAS_PHY_PAGE1, MPI3_POINTER PTR_MPI3_SAS_PHY_PAGE1, + Mpi3SasPhyPage1_t, MPI3_POINTER pMpi3SasPhyPage1_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_SASPHY1_PAGEVERSION (0x00) + +/***************************************************************************** + * SAS PHY Page 2 * + ****************************************************************************/ +typedef struct _MPI3_SAS_PHY2_PHY_EVENT +{ + U8 PhyEventCode; /* 0x00 */ + U8 Reserved01[3]; /* 0x01 */ + U32 PhyEventInfo; /* 0x04 */ +} MPI3_SAS_PHY2_PHY_EVENT, MPI3_POINTER PTR_MPI3_SAS_PHY2_PHY_EVENT, + Mpi3SasPhy2PhyEvent_t, MPI3_POINTER pMpi3SasPhy2PhyEvent_t; + +/**** Defines for the PhyEventCode field - use MPI3_SASPHY3_EVENT_CODE_ defines */ + +#ifndef MPI3_SAS_PHY2_PHY_EVENT_MAX +#define MPI3_SAS_PHY2_PHY_EVENT_MAX (1) +#endif /* MPI3_SAS_PHY2_PHY_EVENT_MAX */ + +typedef struct _MPI3_SAS_PHY_PAGE2 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U8 NumPhyEvents; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + MPI3_SAS_PHY2_PHY_EVENT PhyEvent[MPI3_SAS_PHY2_PHY_EVENT_MAX]; /* 0x10 */ +} MPI3_SAS_PHY_PAGE2, MPI3_POINTER PTR_MPI3_SAS_PHY_PAGE2, + Mpi3SasPhyPage2_t, MPI3_POINTER pMpi3SasPhyPage2_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_SASPHY2_PAGEVERSION (0x00) + +/***************************************************************************** + * SAS PHY Page 3 * + ****************************************************************************/ +typedef struct _MPI3_SAS_PHY3_PHY_EVENT_CONFIG +{ + U8 PhyEventCode; /* 0x00 */ + U8 Reserved01[3]; /* 0x01 */ + U8 CounterType; /* 0x04 */ + U8 ThresholdWindow; /* 0x05 */ + U8 TimeUnits; /* 0x06 */ + U8 Reserved07; /* 0x07 */ + U32 EventThreshold; /* 0x08 */ + U16 ThresholdFlags; /* 0x0C */ + U16 Reserved0E; /* 0x0E */ +} MPI3_SAS_PHY3_PHY_EVENT_CONFIG, MPI3_POINTER PTR_MPI3_SAS_PHY3_PHY_EVENT_CONFIG, + Mpi3SasPhy3PhyEventConfig_t, MPI3_POINTER pMpi3SasPhy3PhyEventConfig_t; + +/**** Defines for the PhyEventCode field ****/ +#define MPI3_SASPHY3_EVENT_CODE_NO_EVENT (0x00) +#define MPI3_SASPHY3_EVENT_CODE_INVALID_DWORD (0x01) +#define MPI3_SASPHY3_EVENT_CODE_RUNNING_DISPARITY_ERROR (0x02) +#define MPI3_SASPHY3_EVENT_CODE_LOSS_DWORD_SYNC (0x03) +#define MPI3_SASPHY3_EVENT_CODE_PHY_RESET_PROBLEM (0x04) +#define MPI3_SASPHY3_EVENT_CODE_ELASTICITY_BUF_OVERFLOW (0x05) +#define MPI3_SASPHY3_EVENT_CODE_RX_ERROR (0x06) +#define MPI3_SASPHY3_EVENT_CODE_INV_SPL_PACKETS (0x07) +#define MPI3_SASPHY3_EVENT_CODE_LOSS_SPL_PACKET_SYNC (0x08) +#define MPI3_SASPHY3_EVENT_CODE_RX_ADDR_FRAME_ERROR (0x20) +#define MPI3_SASPHY3_EVENT_CODE_TX_AC_OPEN_REJECT (0x21) +#define MPI3_SASPHY3_EVENT_CODE_RX_AC_OPEN_REJECT (0x22) +#define MPI3_SASPHY3_EVENT_CODE_TX_RC_OPEN_REJECT (0x23) +#define MPI3_SASPHY3_EVENT_CODE_RX_RC_OPEN_REJECT (0x24) +#define MPI3_SASPHY3_EVENT_CODE_RX_AIP_PARTIAL_WAITING_ON (0x25) +#define MPI3_SASPHY3_EVENT_CODE_RX_AIP_CONNECT_WAITING_ON (0x26) +#define MPI3_SASPHY3_EVENT_CODE_TX_BREAK (0x27) +#define MPI3_SASPHY3_EVENT_CODE_RX_BREAK (0x28) +#define MPI3_SASPHY3_EVENT_CODE_BREAK_TIMEOUT (0x29) +#define MPI3_SASPHY3_EVENT_CODE_CONNECTION (0x2A) +#define MPI3_SASPHY3_EVENT_CODE_PEAKTX_PATHWAY_BLOCKED (0x2B) +#define MPI3_SASPHY3_EVENT_CODE_PEAKTX_ARB_WAIT_TIME (0x2C) +#define MPI3_SASPHY3_EVENT_CODE_PEAK_ARB_WAIT_TIME (0x2D) +#define MPI3_SASPHY3_EVENT_CODE_PEAK_CONNECT_TIME (0x2E) +#define MPI3_SASPHY3_EVENT_CODE_PERSIST_CONN (0x2F) +#define MPI3_SASPHY3_EVENT_CODE_TX_SSP_FRAMES (0x40) +#define MPI3_SASPHY3_EVENT_CODE_RX_SSP_FRAMES (0x41) +#define MPI3_SASPHY3_EVENT_CODE_TX_SSP_ERROR_FRAMES (0x42) +#define MPI3_SASPHY3_EVENT_CODE_RX_SSP_ERROR_FRAMES (0x43) +#define MPI3_SASPHY3_EVENT_CODE_TX_CREDIT_BLOCKED (0x44) +#define MPI3_SASPHY3_EVENT_CODE_RX_CREDIT_BLOCKED (0x45) +#define MPI3_SASPHY3_EVENT_CODE_TX_SATA_FRAMES (0x50) +#define MPI3_SASPHY3_EVENT_CODE_RX_SATA_FRAMES (0x51) +#define MPI3_SASPHY3_EVENT_CODE_SATA_OVERFLOW (0x52) +#define MPI3_SASPHY3_EVENT_CODE_TX_SMP_FRAMES (0x60) +#define MPI3_SASPHY3_EVENT_CODE_RX_SMP_FRAMES (0x61) +#define MPI3_SASPHY3_EVENT_CODE_RX_SMP_ERROR_FRAMES (0x63) +#define MPI3_SASPHY3_EVENT_CODE_HOTPLUG_TIMEOUT (0xD0) +#define MPI3_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE (0xD1) +#define MPI3_SASPHY3_EVENT_CODE_RX_AIP (0xD2) +#define MPI3_SASPHY3_EVENT_CODE_LCARB_WAIT_TIME (0xD3) +#define MPI3_SASPHY3_EVENT_CODE_RCVD_CONN_RESP_WAIT_TIME (0xD4) +#define MPI3_SASPHY3_EVENT_CODE_LCCONN_TIME (0xD5) +#define MPI3_SASPHY3_EVENT_CODE_SSP_TX_START_TRANSMIT (0xD6) +#define MPI3_SASPHY3_EVENT_CODE_SATA_TX_START (0xD7) +#define MPI3_SASPHY3_EVENT_CODE_SMP_TX_START_TRANSMT (0xD8) +#define MPI3_SASPHY3_EVENT_CODE_TX_SMP_BREAK_CONN (0xD9) +#define MPI3_SASPHY3_EVENT_CODE_SSP_RX_START_RECEIVE (0xDA) +#define MPI3_SASPHY3_EVENT_CODE_SATA_RX_START_RECEIVE (0xDB) +#define MPI3_SASPHY3_EVENT_CODE_SMP_RX_START_RECEIVE (0xDC) + +/**** Defines for the CounterType field ****/ +#define MPI3_SASPHY3_COUNTER_TYPE_WRAPPING (0x00) +#define MPI3_SASPHY3_COUNTER_TYPE_SATURATING (0x01) +#define MPI3_SASPHY3_COUNTER_TYPE_PEAK_VALUE (0x02) + +/**** Defines for the TimeUnits field ****/ +#define MPI3_SASPHY3_TIME_UNITS_10_MICROSECONDS (0x00) +#define MPI3_SASPHY3_TIME_UNITS_100_MICROSECONDS (0x01) +#define MPI3_SASPHY3_TIME_UNITS_1_MILLISECOND (0x02) +#define MPI3_SASPHY3_TIME_UNITS_10_MILLISECONDS (0x03) + +/**** Defines for the ThresholdFlags field ****/ +#define MPI3_SASPHY3_TFLAGS_PHY_RESET (0x0002) +#define MPI3_SASPHY3_TFLAGS_EVENT_NOTIFY (0x0001) + +#ifndef MPI3_SAS_PHY3_PHY_EVENT_MAX +#define MPI3_SAS_PHY3_PHY_EVENT_MAX (1) +#endif /* MPI3_SAS_PHY3_PHY_EVENT_MAX */ + +typedef struct _MPI3_SAS_PHY_PAGE3 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U8 NumPhyEvents; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + MPI3_SAS_PHY3_PHY_EVENT_CONFIG PhyEventConfig[MPI3_SAS_PHY3_PHY_EVENT_MAX]; /* 0x10 */ +} MPI3_SAS_PHY_PAGE3, MPI3_POINTER PTR_MPI3_SAS_PHY_PAGE3, + Mpi3SasPhyPage3_t, MPI3_POINTER pMpi3SasPhyPage3_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_SASPHY3_PAGEVERSION (0x00) + +/***************************************************************************** + * SAS PHY Page 4 * + ****************************************************************************/ +typedef struct _MPI3_SAS_PHY_PAGE4 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 Reserved08[3]; /* 0x08 */ + U8 Flags; /* 0x0B */ + U8 InitialFrame[28]; /* 0x0C */ +} MPI3_SAS_PHY_PAGE4, MPI3_POINTER PTR_MPI3_SAS_PHY_PAGE4, + Mpi3SasPhyPage4_t, MPI3_POINTER pMpi3SasPhyPage4_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_SASPHY4_PAGEVERSION (0x00) + +/**** Defines for the Flags field ****/ +#define MPI3_SASPHY4_FLAGS_FRAME_VALID (0x02) +#define MPI3_SASPHY4_FLAGS_SATA_FRAME (0x01) + + +/***************************************************************************** + * Common definitions used by PCIe Configuration Pages * + ****************************************************************************/ + +/**** Defines for Negotiated Link Rates ****/ +#define MPI3_PCIE_LINK_RETIMERS_MASK (0x30) +#define MPI3_PCIE_LINK_RETIMERS_SHIFT (4) +#define MPI3_PCIE_NEG_LINK_RATE_MASK (0x0F) +#define MPI3_PCIE_NEG_LINK_RATE_UNKNOWN (0x00) +#define MPI3_PCIE_NEG_LINK_RATE_PHY_DISABLED (0x01) +#define MPI3_PCIE_NEG_LINK_RATE_2_5 (0x02) +#define MPI3_PCIE_NEG_LINK_RATE_5_0 (0x03) +#define MPI3_PCIE_NEG_LINK_RATE_8_0 (0x04) +#define MPI3_PCIE_NEG_LINK_RATE_16_0 (0x05) +#define MPI3_PCIE_NEG_LINK_RATE_32_0 (0x06) + +/**** Defines for Enabled ASPM States ****/ +#define MPI3_PCIE_ASPM_ENABLE_NONE (0x0) +#define MPI3_PCIE_ASPM_ENABLE_L0s (0x1) +#define MPI3_PCIE_ASPM_ENABLE_L1 (0x2) +#define MPI3_PCIE_ASPM_ENABLE_L0s_L1 (0x3) + +/**** Defines for Enabled ASPM States ****/ +#define MPI3_PCIE_ASPM_SUPPORT_NONE (0x0) +#define MPI3_PCIE_ASPM_SUPPORT_L0s (0x1) +#define MPI3_PCIE_ASPM_SUPPORT_L1 (0x2) +#define MPI3_PCIE_ASPM_SUPPORT_L0s_L1 (0x3) + +/***************************************************************************** + * PCIe IO Unit Configuration Pages * + ****************************************************************************/ + +/***************************************************************************** + * PCIe IO Unit Page 0 * + ****************************************************************************/ +typedef struct _MPI3_PCIE_IO_UNIT0_PHY_DATA +{ + U8 Link; /* 0x00 */ + U8 LinkFlags; /* 0x01 */ + U8 PhyFlags; /* 0x02 */ + U8 NegotiatedLinkRate; /* 0x03 */ + U16 AttachedDevHandle; /* 0x04 */ + U16 ControllerDevHandle; /* 0x06 */ + U32 EnumerationStatus; /* 0x08 */ + U8 IOUnitPort; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ +} MPI3_PCIE_IO_UNIT0_PHY_DATA, MPI3_POINTER PTR_MPI3_PCIE_IO_UNIT0_PHY_DATA, + Mpi3PcieIOUnit0PhyData_t, MPI3_POINTER pMpi3PcieIOUnit0PhyData_t; + +/**** Defines for the LinkFlags field ****/ +#define MPI3_PCIEIOUNIT0_LINKFLAGS_CONFIG_SOURCE_MASK (0x10) +#define MPI3_PCIEIOUNIT0_LINKFLAGS_CONFIG_SOURCE_IOUNIT1 (0x00) +#define MPI3_PCIEIOUNIT0_LINKFLAGS_CONFIG_SOURCE_BKPLANE (0x10) +#define MPI3_PCIEIOUNIT0_LINKFLAGS_ENUM_IN_PROGRESS (0x08) + +/**** Defines for the PhyFlags field ****/ +#define MPI3_PCIEIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08) +#define MPI3_PCIEIOUNIT0_PHYFLAGS_HOST_PHY (0x01) + +/**** Defines for the NegotiatedLinkRate field - use MPI3_PCIE_NEG_LINK_RATE_ defines ****/ + +/**** Defines for the EnumerationStatus field ****/ +#define MPI3_PCIEIOUNIT0_ES_MAX_SWITCH_DEPTH_EXCEEDED (0x80000000) +#define MPI3_PCIEIOUNIT0_ES_MAX_SWITCHES_EXCEEDED (0x40000000) +#define MPI3_PCIEIOUNIT0_ES_MAX_ENDPOINTS_EXCEEDED (0x20000000) +#define MPI3_PCIEIOUNIT0_ES_INSUFFICIENT_RESOURCES (0x10000000) + +#ifndef MPI3_PCIE_IO_UNIT0_PHY_MAX +#define MPI3_PCIE_IO_UNIT0_PHY_MAX (1) +#endif /* MPI3_PCIE_IO_UNIT0_PHY_MAX */ + +typedef struct _MPI3_PCIE_IO_UNIT_PAGE0 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U8 NumPhys; /* 0x0C */ + U8 InitStatus; /* 0x0D */ + U8 ASPM; /* 0x0E */ + U8 Reserved0F; /* 0x0F */ + MPI3_PCIE_IO_UNIT0_PHY_DATA PhyData[MPI3_PCIE_IO_UNIT0_PHY_MAX]; /* 0x10 */ +} MPI3_PCIE_IO_UNIT_PAGE0, MPI3_POINTER PTR_MPI3_PCIE_IO_UNIT_PAGE0, + Mpi3PcieIOUnitPage0_t, MPI3_POINTER pMpi3PcieIOUnitPage0_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_PCIEIOUNIT0_PAGEVERSION (0x00) + +/**** Defines for the InitStatus field ****/ +#define MPI3_PCIEIOUNIT0_INITSTATUS_NO_ERRORS (0x00) +#define MPI3_PCIEIOUNIT0_INITSTATUS_NEEDS_INITIALIZATION (0x01) +#define MPI3_PCIEIOUNIT0_INITSTATUS_NO_TARGETS_ALLOCATED (0x02) +#define MPI3_PCIEIOUNIT0_INITSTATUS_RESOURCE_ALLOC_FAILED (0x03) +#define MPI3_PCIEIOUNIT0_INITSTATUS_BAD_NUM_PHYS (0x04) +#define MPI3_PCIEIOUNIT0_INITSTATUS_UNSUPPORTED_CONFIG (0x05) +#define MPI3_PCIEIOUNIT0_INITSTATUS_HOST_PORT_MISMATCH (0x06) +#define MPI3_PCIEIOUNIT0_INITSTATUS_PHYS_NOT_CONSECUTIVE (0x07) +#define MPI3_PCIEIOUNIT0_INITSTATUS_BAD_CLOCKING_MODE (0x08) +#define MPI3_PCIEIOUNIT0_INITSTATUS_PROD_SPEC_START (0xF0) +#define MPI3_PCIEIOUNIT0_INITSTATUS_PROD_SPEC_END (0xFF) + +/**** Defines for the ASPM field ****/ +#define MPI3_PCIEIOUNIT0_ASPM_SWITCH_STATES_MASK (0xC0) +#define MPI3_PCIEIOUNIT0_ASPM_SWITCH_STATES_SHIFT (6) +#define MPI3_PCIEIOUNIT0_ASPM_DIRECT_STATES_MASK (0x30) +#define MPI3_PCIEIOUNIT0_ASPM_DIRECT_STATES_SHIFT (4) +/*** use MPI3_PCIE_ASPM_ENABLE_ defines for field values ***/ +#define MPI3_PCIEIOUNIT0_ASPM_SWITCH_SUPPORT_MASK (0x0C) +#define MPI3_PCIEIOUNIT0_ASPM_SWITCH_SUPPORT_SHIFT (2) +#define MPI3_PCIEIOUNIT0_ASPM_DIRECT_SUPPORT_MASK (0x03) +#define MPI3_PCIEIOUNIT0_ASPM_DIRECT_SUPPORT_SHIFT (0) +/*** use MPI3_PCIE_ASPM_SUPPORT_ defines for field values ***/ + +/***************************************************************************** + * PCIe IO Unit Page 1 * + ****************************************************************************/ +typedef struct _MPI3_PCIE_IO_UNIT1_PHY_DATA +{ + U8 Link; /* 0x00 */ + U8 LinkFlags; /* 0x01 */ + U8 PhyFlags; /* 0x02 */ + U8 MaxMinLinkRate; /* 0x03 */ + U32 Reserved04; /* 0x04 */ + U32 Reserved08; /* 0x08 */ +} MPI3_PCIE_IO_UNIT1_PHY_DATA, MPI3_POINTER PTR_MPI3_PCIE_IO_UNIT1_PHY_DATA, + Mpi3PcieIOUnit1PhyData_t, MPI3_POINTER pMpi3PcieIOUnit1PhyData_t; + +/**** Defines for the LinkFlags field ****/ +#define MPI3_PCIEIOUNIT1_LINKFLAGS_PCIE_CLK_MODE_MASK (0x03) +#define MPI3_PCIEIOUNIT1_LINKFLAGS_PCIE_CLK_MODE_DIS_SEPARATE_REFCLK (0x00) +#define MPI3_PCIEIOUNIT1_LINKFLAGS_PCIE_CLK_MODE_EN_SRIS (0x01) +#define MPI3_PCIEIOUNIT1_LINKFLAGS_PCIE_CLK_MODE_EN_SRNS (0x02) + +/**** Defines for the PhyFlags field ****/ +#define MPI3_PCIEIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08) + +/**** Defines for the MaxMinLinkRate ****/ +#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_MASK (0xF0) +#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_SHIFT (4) +#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_2_5 (0x20) +#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_5_0 (0x30) +#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_8_0 (0x40) +#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_16_0 (0x50) +#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_32_0 (0x60) + +#ifndef MPI3_PCIE_IO_UNIT1_PHY_MAX +#define MPI3_PCIE_IO_UNIT1_PHY_MAX (1) +#endif /* MPI3_PCIE_IO_UNIT1_PHY_MAX */ + +typedef struct _MPI3_PCIE_IO_UNIT_PAGE1 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 ControlFlags; /* 0x08 */ + U32 Reserved0C; /* 0x0C */ + U8 NumPhys; /* 0x10 */ + U8 Reserved11; /* 0x11 */ + U8 ASPM; /* 0x12 */ + U8 Reserved13; /* 0x13 */ + MPI3_PCIE_IO_UNIT1_PHY_DATA PhyData[MPI3_PCIE_IO_UNIT1_PHY_MAX]; /* 0x14 */ +} MPI3_PCIE_IO_UNIT_PAGE1, MPI3_POINTER PTR_MPI3_PCIE_IO_UNIT_PAGE1, + Mpi3PcieIOUnitPage1_t, MPI3_POINTER pMpi3PcieIOUnitPage1_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_PCIEIOUNIT1_PAGEVERSION (0x00) + +/**** Defines for the ControlFlags field ****/ +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_PERST_OVERRIDE_MASK (0xE0000000) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_PERST_OVERRIDE_NONE (0x00000000) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_PERST_OVERRIDE_DEASSERT (0x20000000) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_PERST_OVERRIDE_ASSERT (0x40000000) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_PERST_OVERRIDE_BACKPLANE_ERROR (0x60000000) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_REFCLK_OVERRIDE_MASK (0x1C000000) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_REFCLK_OVERRIDE_NONE (0x00000000) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_REFCLK_OVERRIDE_DEASSERT (0x04000000) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_REFCLK_OVERRIDE_ASSERT (0x08000000) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_REFCLK_OVERRIDE_BACKPLANE_ERROR (0x0C000000) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_PARTIAL_CAPACITY_ENABLE (0x00000100) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_LINK_OVERRIDE_DISABLE (0x00000080) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_CLOCK_OVERRIDE_DISABLE (0x00000040) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_CLOCK_OVERRIDE_MODE_MASK (0x00000030) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_CLOCK_OVERRIDE_MODE_SHIFT (4) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_CLOCK_OVERRIDE_MODE_SRIS_SRNS_DISABLED (0x00000000) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_CLOCK_OVERRIDE_MODE_SRIS_ENABLED (0x00000010) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_CLOCK_OVERRIDE_MODE_SRNS_ENABLED (0x00000020) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_LINK_RATE_OVERRIDE_MASK (0x0000000F) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_LINK_RATE_OVERRIDE_USE_BACKPLANE (0x00000000) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_LINK_RATE_OVERRIDE_MAX_2_5 (0x00000002) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_LINK_RATE_OVERRIDE_MAX_5_0 (0x00000003) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_LINK_RATE_OVERRIDE_MAX_8_0 (0x00000004) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_LINK_RATE_OVERRIDE_MAX_16_0 (0x00000005) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_LINK_RATE_OVERRIDE_MAX_32_0 (0x00000006) + +/**** Defines for the ASPM field ****/ +#define MPI3_PCIEIOUNIT1_ASPM_SWITCH_MASK (0x0C) +#define MPI3_PCIEIOUNIT1_ASPM_SWITCH_SHIFT (2) +#define MPI3_PCIEIOUNIT1_ASPM_DIRECT_MASK (0x03) +#define MPI3_PCIEIOUNIT1_ASPM_DIRECT_SHIFT (0) +/*** use MPI3_PCIE_ASPM_ENABLE_ defines for ASPM field values ***/ + +/***************************************************************************** + * PCIe IO Unit Page 2 * + ****************************************************************************/ +typedef struct _MPI3_PCIE_IO_UNIT_PAGE2 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 NVMeMaxQDx1; /* 0x08 */ + U16 NVMeMaxQDx2; /* 0x0A */ + U8 NVMeAbortTO; /* 0x0C */ + U8 Reserved0D; /* 0x0D */ + U16 NVMeMaxQDx4; /* 0x0E */ +} MPI3_PCIE_IO_UNIT_PAGE2, MPI3_POINTER PTR_MPI3_PCIE_IO_UNIT_PAGE2, + Mpi3PcieIOUnitPage2_t, MPI3_POINTER pMpi3PcieIOUnitPage2_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_PCIEIOUNIT2_PAGEVERSION (0x00) + +/***************************************************************************** + * PCIe IO Unit Page 3 * + ****************************************************************************/ + +/**** Defines for Error Indexes ****/ +#define MPI3_PCIEIOUNIT3_ERROR_RECEIVER_ERROR (0) +#define MPI3_PCIEIOUNIT3_ERROR_RECOVERY (1) +#define MPI3_PCIEIOUNIT3_ERROR_CORRECTABLE_ERROR_MSG (2) +#define MPI3_PCIEIOUNIT3_ERROR_BAD_DLLP (3) +#define MPI3_PCIEIOUNIT3_ERROR_BAD_TLP (4) +#define MPI3_PCIEIOUNIT3_NUM_ERROR_INDEX (5) + + +typedef struct _MPI3_PCIE_IO_UNIT3_ERROR +{ + U16 ThresholdCount; /* 0x00 */ + U16 Reserved02; /* 0x02 */ +} MPI3_PCIE_IO_UNIT3_ERROR, MPI3_POINTER PTR_MPI3_PCIE_IO_UNIT3_ERROR, + Mpi3PcieIOUnit3Error_t, MPI3_POINTER pMpi3PcieIOUnit3Error_t; + +typedef struct _MPI3_PCIE_IO_UNIT_PAGE3 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 ThresholdWindow; /* 0x08 */ + U8 ThresholdAction; /* 0x09 */ + U8 EscalationCount; /* 0x0A */ + U8 EscalationAction; /* 0x0B */ + U8 NumErrors; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + MPI3_PCIE_IO_UNIT3_ERROR Error[MPI3_PCIEIOUNIT3_NUM_ERROR_INDEX]; /* 0x10 */ +} MPI3_PCIE_IO_UNIT_PAGE3, MPI3_POINTER PTR_MPI3_PCIE_IO_UNIT_PAGE3, + Mpi3PcieIOUnitPage3_t, MPI3_POINTER pMpi3PcieIOUnitPage3_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_PCIEIOUNIT3_PAGEVERSION (0x00) + +/**** Defines for the ThresholdAction and EscalationAction fields ****/ +#define MPI3_PCIEIOUNIT3_ACTION_NO_ACTION (0x00) +#define MPI3_PCIEIOUNIT3_ACTION_HOT_RESET (0x01) +#define MPI3_PCIEIOUNIT3_ACTION_REDUCE_LINK_RATE_ONLY (0x02) +#define MPI3_PCIEIOUNIT3_ACTION_REDUCE_LINK_RATE_NO_ACCESS (0x03) + +/**** Defines for Error Indexes - use MPI3_PCIEIOUNIT3_ERROR_ defines ****/ + +/***************************************************************************** + * PCIe Switch Configuration Pages * + ****************************************************************************/ + +/***************************************************************************** + * PCIe Switch Page 0 * + ****************************************************************************/ +typedef struct _MPI3_PCIE_SWITCH_PAGE0 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 IOUnitPort; /* 0x08 */ + U8 SwitchStatus; /* 0x09 */ + U8 Reserved0A[2]; /* 0x0A */ + U16 DevHandle; /* 0x0C */ + U16 ParentDevHandle; /* 0x0E */ + U8 NumPorts; /* 0x10 */ + U8 PCIeLevel; /* 0x11 */ + U16 Reserved12; /* 0x12 */ + U32 Reserved14; /* 0x14 */ + U32 Reserved18; /* 0x18 */ + U32 Reserved1C; /* 0x1C */ +} MPI3_PCIE_SWITCH_PAGE0, MPI3_POINTER PTR_MPI3_PCIE_SWITCH_PAGE0, + Mpi3PcieSwitchPage0_t, MPI3_POINTER pMpi3PcieSwitchPage0_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_PCIESWITCH0_PAGEVERSION (0x00) + +/**** Defines for the SwitchStatus field ****/ +#define MPI3_PCIESWITCH0_SS_NOT_RESPONDING (0x02) +#define MPI3_PCIESWITCH0_SS_RESPONDING (0x03) +#define MPI3_PCIESWITCH0_SS_DELAY_NOT_RESPONDING (0x04) + +/***************************************************************************** + * PCIe Switch Page 1 * + ****************************************************************************/ +typedef struct _MPI3_PCIE_SWITCH_PAGE1 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 IOUnitPort; /* 0x08 */ + U8 Flags; /* 0x09 */ + U16 Reserved0A; /* 0x0A */ + U8 NumPorts; /* 0x0C */ + U8 PortNum; /* 0x0D */ + U16 AttachedDevHandle; /* 0x0E */ + U16 SwitchDevHandle; /* 0x10 */ + U8 NegotiatedPortWidth; /* 0x12 */ + U8 NegotiatedLinkRate; /* 0x13 */ + U16 Slot; /* 0x14 */ + U16 SlotIndex; /* 0x16 */ + U32 Reserved18; /* 0x18 */ +} MPI3_PCIE_SWITCH_PAGE1, MPI3_POINTER PTR_MPI3_PCIE_SWITCH_PAGE1, + Mpi3PcieSwitchPage1_t, MPI3_POINTER pMpi3PcieSwitchPage1_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_PCIESWITCH1_PAGEVERSION (0x00) + +/**** Defines for the FLAGS field ****/ +#define MPI3_PCIESWITCH1_FLAGS_ASPMSTATE_MASK (0x0C) +#define MPI3_PCIESWITCH1_FLAGS_ASPMSTATE_SHIFT (2) +/*** use MPI3_PCIE_ASPM_ENABLE_ defines for ASPMState field values ***/ +#define MPI3_PCIESWITCH1_FLAGS_ASPMSUPPORT_MASK (0x03) +#define MPI3_PCIESWITCH1_FLAGS_ASPMSUPPORT_SHIFT (0) +/*** use MPI3_PCIE_ASPM_SUPPORT_ defines for ASPMSupport field values ***/ + +/**** Defines for the NegotiatedLinkRate field - use MPI3_PCIE_NEG_LINK_RATE_ defines ****/ + +/**** Defines for the Slot field - use MPI3_SLOT_ defines ****/ + +/**** Defines for the SlotIndex field - use MPI3_SLOT_INDEX_ ****/ + +/***************************************************************************** + * PCIe Switch Page 2 * + ****************************************************************************/ +#ifndef MPI3_PCIESWITCH2_MAX_NUM_PORTS +#define MPI3_PCIESWITCH2_MAX_NUM_PORTS (1) +#endif /* MPI3_PCIESWITCH2_MAX_NUM_PORTS */ + +typedef struct _MPI3_PCIESWITCH2_PORT_ELEMENT +{ + U16 LinkChangeCount; /* 0x00 */ + U16 RateChangeCount; /* 0x02 */ + U32 Reserved04; /* 0x04 */ +} MPI3_PCIESWITCH2_PORT_ELEMENT, MPI3_POINTER PTR_MPI3_PCIESWITCH2_PORT_ELEMENT, + Mpi3PcieSwitch2PortElement_t, MPI3_POINTER pMpi3PcieSwitch2PortElement_t; + +typedef struct _MPI3_PCIE_SWITCH_PAGE2 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumPorts; /* 0x08 */ + U8 Reserved09; /* 0x09 */ + U16 DevHandle; /* 0x0A */ + U32 Reserved0C; /* 0x0C */ + MPI3_PCIESWITCH2_PORT_ELEMENT Port[MPI3_PCIESWITCH2_MAX_NUM_PORTS]; /* 0x10 */ /* variable length */ +} MPI3_PCIE_SWITCH_PAGE2, MPI3_POINTER PTR_MPI3_PCIE_SWITCH_PAGE2, + Mpi3PcieSwitchPage2_t, MPI3_POINTER pMpi3PcieSwitchPage2_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_PCIESWITCH2_PAGEVERSION (0x00) + +/***************************************************************************** + * PCIe Link Configuration Pages * + ****************************************************************************/ + +/***************************************************************************** + * PCIe Link Page 0 * + ****************************************************************************/ +typedef struct _MPI3_PCIE_LINK_PAGE0 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 Link; /* 0x08 */ + U8 Reserved09[3]; /* 0x09 */ + U32 Reserved0C; /* 0x0C */ + U32 ReceiverErrorCount; /* 0x10 */ + U32 RecoveryCount; /* 0x14 */ + U32 CorrErrorMsgCount; /* 0x18 */ + U32 NonFatalErrorMsgCount; /* 0x1C */ + U32 FatalErrorMsgCount; /* 0x20 */ + U32 NonFatalErrorCount; /* 0x24 */ + U32 FatalErrorCount; /* 0x28 */ + U32 BadDLLPCount; /* 0x2C */ + U32 BadTLPCount; /* 0x30 */ +} MPI3_PCIE_LINK_PAGE0, MPI3_POINTER PTR_MPI3_PCIE_LINK_PAGE0, + Mpi3PcieLinkPage0_t, MPI3_POINTER pMpi3PcieLinkPage0_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_PCIELINK0_PAGEVERSION (0x00) + + +/***************************************************************************** + * Enclosure Configuration Pages * + ****************************************************************************/ + +/***************************************************************************** + * Enclosure Page 0 * + ****************************************************************************/ +typedef struct _MPI3_ENCLOSURE_PAGE0 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U64 EnclosureLogicalID; /* 0x08 */ + U16 Flags; /* 0x10 */ + U16 EnclosureHandle; /* 0x12 */ + U16 NumSlots; /* 0x14 */ + U16 Reserved16; /* 0x16 */ + U8 IOUnitPort; /* 0x18 */ + U8 EnclosureLevel; /* 0x19 */ + U16 SEPDevHandle; /* 0x1A */ + U8 ChassisSlot; /* 0x1C */ + U8 Reserved1D[3]; /* 0x1D */ +} MPI3_ENCLOSURE_PAGE0, MPI3_POINTER PTR_MPI3_ENCLOSURE_PAGE0, + Mpi3EnclosurePage0_t, MPI3_POINTER pMpi3EnclosurePage0_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_ENCLOSURE0_PAGEVERSION (0x00) + +/**** Defines for the Flags field ****/ +#define MPI3_ENCLS0_FLAGS_ENCL_TYPE_MASK (0xC000) +#define MPI3_ENCLS0_FLAGS_ENCL_TYPE_VIRTUAL (0x0000) +#define MPI3_ENCLS0_FLAGS_ENCL_TYPE_SAS (0x4000) +#define MPI3_ENCLS0_FLAGS_ENCL_TYPE_PCIE (0x8000) +#define MPI3_ENCLS0_FLAGS_CHASSIS_SLOT_VALID (0x0020) +#define MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT_MASK (0x0010) +#define MPI3_ENCLS0_FLAGS_ENCL_DEV_NOT_FOUND (0x0000) +#define MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT (0x0010) +#define MPI3_ENCLS0_FLAGS_MNG_MASK (0x000F) +#define MPI3_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000) +#define MPI3_ENCLS0_FLAGS_MNG_IOC_SES (0x0001) +#define MPI3_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0002) + +/**** Defines for the PhysicalPort field - use MPI3_DEVICE0_PHYPORT_ defines ****/ + +/***************************************************************************** + * Device Configuration Pages * + ****************************************************************************/ + +/***************************************************************************** + * Common definitions used by Device Configuration Pages * + ****************************************************************************/ + +/**** Defines for the DeviceForm field ****/ +#define MPI3_DEVICE_DEVFORM_SAS_SATA (0x00) +#define MPI3_DEVICE_DEVFORM_PCIE (0x01) +#define MPI3_DEVICE_DEVFORM_VD (0x02) + +/***************************************************************************** + * Device Page 0 * + ****************************************************************************/ +typedef struct _MPI3_DEVICE0_SAS_SATA_FORMAT +{ + U64 SASAddress; /* 0x00 */ + U16 Flags; /* 0x08 */ + U16 DeviceInfo; /* 0x0A */ + U8 PhyNum; /* 0x0C */ + U8 AttachedPhyIdentifier; /* 0x0D */ + U8 MaxPortConnections; /* 0x0E */ + U8 ZoneGroup; /* 0x0F */ +} MPI3_DEVICE0_SAS_SATA_FORMAT, MPI3_POINTER PTR_MPI3_DEVICE0_SAS_SATA_FORMAT, + Mpi3Device0SasSataFormat_t, MPI3_POINTER pMpi3Device0SasSataFormat_t; + +/**** Defines for the Flags field ****/ +#define MPI3_DEVICE0_SASSATA_FLAGS_WRITE_SAME_UNMAP_NCQ (0x0400) +#define MPI3_DEVICE0_SASSATA_FLAGS_SLUMBER_CAP (0x0200) +#define MPI3_DEVICE0_SASSATA_FLAGS_PARTIAL_CAP (0x0100) +#define MPI3_DEVICE0_SASSATA_FLAGS_ASYNC_NOTIFY (0x0080) +#define MPI3_DEVICE0_SASSATA_FLAGS_SW_PRESERVE (0x0040) +#define MPI3_DEVICE0_SASSATA_FLAGS_UNSUPP_DEV (0x0020) +#define MPI3_DEVICE0_SASSATA_FLAGS_48BIT_LBA (0x0010) +#define MPI3_DEVICE0_SASSATA_FLAGS_SMART_SUPP (0x0008) +#define MPI3_DEVICE0_SASSATA_FLAGS_NCQ_SUPP (0x0004) +#define MPI3_DEVICE0_SASSATA_FLAGS_FUA_SUPP (0x0002) +#define MPI3_DEVICE0_SASSATA_FLAGS_PERSIST_CAP (0x0001) + +/**** Defines for the DeviceInfo field - use MPI3_SAS_DEVICE_INFO_ defines (see mpi30_sas.h) ****/ + +typedef struct _MPI3_DEVICE0_PCIE_FORMAT +{ + U8 SupportedLinkRates; /* 0x00 */ + U8 MaxPortWidth; /* 0x01 */ + U8 NegotiatedPortWidth; /* 0x02 */ + U8 NegotiatedLinkRate; /* 0x03 */ + U8 PortNum; /* 0x04 */ + U8 ControllerResetTO; /* 0x05 */ + U16 DeviceInfo; /* 0x06 */ + U32 MaximumDataTransferSize; /* 0x08 */ + U32 Capabilities; /* 0x0C */ + U16 NOIOB; /* 0x10 */ + U8 NVMeAbortTO; /* 0x12 */ + U8 PageSize; /* 0x13 */ + U16 ShutdownLatency; /* 0x14 */ + U8 RecoveryInfo; /* 0x16 */ + U8 Reserved17; /* 0x17 */ +} MPI3_DEVICE0_PCIE_FORMAT, MPI3_POINTER PTR_MPI3_DEVICE0_PCIE_FORMAT, + Mpi3Device0PcieFormat_t, MPI3_POINTER pMpi3Device0PcieFormat_t; + +/**** Defines for the SupportedLinkRates field ****/ +#define MPI3_DEVICE0_PCIE_LINK_RATE_32_0_SUPP (0x10) +#define MPI3_DEVICE0_PCIE_LINK_RATE_16_0_SUPP (0x08) +#define MPI3_DEVICE0_PCIE_LINK_RATE_8_0_SUPP (0x04) +#define MPI3_DEVICE0_PCIE_LINK_RATE_5_0_SUPP (0x02) +#define MPI3_DEVICE0_PCIE_LINK_RATE_2_5_SUPP (0x01) + +/**** Defines for the NegotiatedLinkRate field - use MPI3_PCIE_NEG_LINK_RATE_ defines ****/ + +/**** Defines for DeviceInfo bitfield ****/ +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK (0x0007) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NO_DEVICE (0x0000) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE (0x0001) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_SWITCH_DEVICE (0x0002) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_SCSI_DEVICE (0x0003) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_ASPM_MASK (0x0030) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_ASPM_SHIFT (4) +/*** use MPI3_PCIE_ASPM_ENABLE_ defines for ASPM field values ***/ +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_MASK (0x00C0) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_SHIFT (6) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_0 (0x0000) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_1 (0x0040) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_2 (0x0080) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_3 (0x00C0) + + +/**** Defines for the Capabilities field ****/ +#define MPI3_DEVICE0_PCIE_CAP_SGL_EXTRA_LENGTH_SUPPORTED (0x00000020) +#define MPI3_DEVICE0_PCIE_CAP_METADATA_SEPARATED (0x00000010) +#define MPI3_DEVICE0_PCIE_CAP_SGL_DWORD_ALIGN_REQUIRED (0x00000008) +#define MPI3_DEVICE0_PCIE_CAP_SGL_FORMAT_SGL (0x00000004) +#define MPI3_DEVICE0_PCIE_CAP_SGL_FORMAT_PRP (0x00000000) +#define MPI3_DEVICE0_PCIE_CAP_BIT_BUCKET_SGL_SUPP (0x00000002) +#define MPI3_DEVICE0_PCIE_CAP_SGL_SUPP (0x00000001) +#define MPI3_DEVICE0_PCIE_CAP_ASPM_MASK (0x000000C0) +#define MPI3_DEVICE0_PCIE_CAP_ASPM_SHIFT (6) +/*** use MPI3_PCIE_ASPM_SUPPORT_ defines for ASPM field values ***/ + +/**** Defines for the RecoverMethod field ****/ +#define MPI3_DEVICE0_PCIE_RECOVER_METHOD_MASK (0xE0) +#define MPI3_DEVICE0_PCIE_RECOVER_METHOD_NS_MGMT (0x00) +#define MPI3_DEVICE0_PCIE_RECOVER_METHOD_FORMAT (0x20) +#define MPI3_DEVICE0_PCIE_RECOVER_REASON_MASK (0x1F) +#define MPI3_DEVICE0_PCIE_RECOVER_REASON_NO_NS (0x00) +#define MPI3_DEVICE0_PCIE_RECOVER_REASON_NO_NSID_1 (0x01) +#define MPI3_DEVICE0_PCIE_RECOVER_REASON_TOO_MANY_NS (0x02) +#define MPI3_DEVICE0_PCIE_RECOVER_REASON_PROTECTION (0x03) +#define MPI3_DEVICE0_PCIE_RECOVER_REASON_METADATA_SZ (0x04) +#define MPI3_DEVICE0_PCIE_RECOVER_REASON_LBA_DATA_SZ (0x05) +#define MPI3_DEVICE0_PCIE_RECOVER_REASON_PARTIAL_CAP (0x06) + +typedef struct _MPI3_DEVICE0_VD_FORMAT +{ + U8 VdState; /* 0x00 */ + U8 RAIDLevel; /* 0x01 */ + U16 DeviceInfo; /* 0x02 */ + U16 Flags; /* 0x04 */ + U16 IOThrottleGroup; /* 0x06 */ + U16 IOThrottleGroupLow; /* 0x08 */ + U16 IOThrottleGroupHigh; /* 0x0A */ + U32 Reserved0C; /* 0x0C */ +} MPI3_DEVICE0_VD_FORMAT, MPI3_POINTER PTR_MPI3_DEVICE0_VD_FORMAT, + Mpi3Device0VdFormat_t, MPI3_POINTER pMpi3Device0VdFormat_t; + +/**** Defines for the VdState field ****/ +#define MPI3_DEVICE0_VD_STATE_OFFLINE (0x00) +#define MPI3_DEVICE0_VD_STATE_PARTIALLY_DEGRADED (0x01) +#define MPI3_DEVICE0_VD_STATE_DEGRADED (0x02) +#define MPI3_DEVICE0_VD_STATE_OPTIMAL (0x03) + +/**** Defines for RAIDLevel field ****/ +#define MPI3_DEVICE0_VD_RAIDLEVEL_RAID_0 (0) +#define MPI3_DEVICE0_VD_RAIDLEVEL_RAID_1 (1) +#define MPI3_DEVICE0_VD_RAIDLEVEL_RAID_5 (5) +#define MPI3_DEVICE0_VD_RAIDLEVEL_RAID_6 (6) +#define MPI3_DEVICE0_VD_RAIDLEVEL_RAID_10 (10) +#define MPI3_DEVICE0_VD_RAIDLEVEL_RAID_50 (50) +#define MPI3_DEVICE0_VD_RAIDLEVEL_RAID_60 (60) + +/**** Defines for DeviceInfo field ****/ +#define MPI3_DEVICE0_VD_DEVICE_INFO_HDD (0x0010) +#define MPI3_DEVICE0_VD_DEVICE_INFO_SSD (0x0008) +#define MPI3_DEVICE0_VD_DEVICE_INFO_NVME (0x0004) +#define MPI3_DEVICE0_VD_DEVICE_INFO_SATA (0x0002) +#define MPI3_DEVICE0_VD_DEVICE_INFO_SAS (0x0001) + +/**** Defines for the Flags field ****/ +#define MPI3_DEVICE0_VD_FLAGS_IO_THROTTLE_GROUP_QD_MASK (0xF000) +#define MPI3_DEVICE0_VD_FLAGS_IO_THROTTLE_GROUP_QD_SHIFT (12) + +typedef union _MPI3_DEVICE0_DEV_SPEC_FORMAT +{ + MPI3_DEVICE0_SAS_SATA_FORMAT SasSataFormat; + MPI3_DEVICE0_PCIE_FORMAT PcieFormat; + MPI3_DEVICE0_VD_FORMAT VdFormat; +} MPI3_DEVICE0_DEV_SPEC_FORMAT, MPI3_POINTER PTR_MPI3_DEVICE0_DEV_SPEC_FORMAT, + Mpi3Device0DevSpecFormat_t, MPI3_POINTER pMpi3Device0DevSpecFormat_t; + +typedef struct _MPI3_DEVICE_PAGE0 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 DevHandle; /* 0x08 */ + U16 ParentDevHandle; /* 0x0A */ + U16 Slot; /* 0x0C */ + U16 EnclosureHandle; /* 0x0E */ + U64 WWID; /* 0x10 */ + U16 PersistentID; /* 0x18 */ + U8 IOUnitPort; /* 0x1A */ + U8 AccessStatus; /* 0x1B */ + U16 Flags; /* 0x1C */ + U16 Reserved1E; /* 0x1E */ + U16 SlotIndex; /* 0x20 */ + U16 QueueDepth; /* 0x22 */ + U8 Reserved24[3]; /* 0x24 */ + U8 DeviceForm; /* 0x27 */ + MPI3_DEVICE0_DEV_SPEC_FORMAT DeviceSpecific; /* 0x28 */ +} MPI3_DEVICE_PAGE0, MPI3_POINTER PTR_MPI3_DEVICE_PAGE0, + Mpi3DevicePage0_t, MPI3_POINTER pMpi3DevicePage0_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_DEVICE0_PAGEVERSION (0x00) + +/**** Defines for the ParentDevHandle field ****/ +#define MPI3_DEVICE0_PARENT_INVALID (0xFFFF) + +/**** Defines for the Slot field - use MPI3_SLOT_ defines ****/ + +/**** Defines for the EnclosureHandle field ****/ +#define MPI3_DEVICE0_ENCLOSURE_HANDLE_NO_ENCLOSURE (0x0000) + +/**** Defines for the WWID field ****/ +#define MPI3_DEVICE0_WWID_INVALID (0xFFFFFFFFFFFFFFFF) + +/**** Defines for the PersistentID field ****/ +#define MPI3_DEVICE0_PERSISTENTID_INVALID (0xFFFF) + +/**** Defines for the IOUnitPort field ****/ +#define MPI3_DEVICE0_IOUNITPORT_INVALID (0xFF) + +/**** Defines for the AccessStatus field ****/ +/* Generic Access Status Codes */ +#define MPI3_DEVICE0_ASTATUS_NO_ERRORS (0x00) +#define MPI3_DEVICE0_ASTATUS_NEEDS_INITIALIZATION (0x01) +#define MPI3_DEVICE0_ASTATUS_CAP_UNSUPPORTED (0x02) +#define MPI3_DEVICE0_ASTATUS_DEVICE_BLOCKED (0x03) +#define MPI3_DEVICE0_ASTATUS_UNAUTHORIZED (0x04) +#define MPI3_DEVICE0_ASTATUS_DEVICE_MISSING_DELAY (0x05) +#define MPI3_DEVICE0_ASTATUS_PREPARE (0x06) +#define MPI3_DEVICE0_ASTATUS_SAFE_MODE (0x07) +#define MPI3_DEVICE0_ASTATUS_GENERIC_MAX (0x0F) +/* SAS Access Status Codes */ +#define MPI3_DEVICE0_ASTATUS_SAS_UNKNOWN (0x10) +#define MPI3_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE (0x11) +#define MPI3_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE (0x12) +#define MPI3_DEVICE0_ASTATUS_SAS_MAX (0x1F) +/* SATA Access Status Codes */ +#define MPI3_DEVICE0_ASTATUS_SIF_UNKNOWN (0x20) +#define MPI3_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x21) +#define MPI3_DEVICE0_ASTATUS_SIF_DIAG (0x22) +#define MPI3_DEVICE0_ASTATUS_SIF_IDENTIFICATION (0x23) +#define MPI3_DEVICE0_ASTATUS_SIF_CHECK_POWER (0x24) +#define MPI3_DEVICE0_ASTATUS_SIF_PIO_SN (0x25) +#define MPI3_DEVICE0_ASTATUS_SIF_MDMA_SN (0x26) +#define MPI3_DEVICE0_ASTATUS_SIF_UDMA_SN (0x27) +#define MPI3_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION (0x28) +#define MPI3_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE (0x29) +#define MPI3_DEVICE0_ASTATUS_SIF_MAX (0x2F) +/* PCIe Access Status Codes */ +#define MPI3_DEVICE0_ASTATUS_PCIE_UNKNOWN (0x30) +#define MPI3_DEVICE0_ASTATUS_PCIE_MEM_SPACE_ACCESS (0x31) +#define MPI3_DEVICE0_ASTATUS_PCIE_UNSUPPORTED (0x32) +#define MPI3_DEVICE0_ASTATUS_PCIE_MSIX_REQUIRED (0x33) +#define MPI3_DEVICE0_ASTATUS_PCIE_ECRC_REQUIRED (0x34) +#define MPI3_DEVICE0_ASTATUS_PCIE_MAX (0x3F) +/* NVMe Access Status Codes */ +#define MPI3_DEVICE0_ASTATUS_NVME_UNKNOWN (0x40) +#define MPI3_DEVICE0_ASTATUS_NVME_READY_TIMEOUT (0x41) +#define MPI3_DEVICE0_ASTATUS_NVME_DEVCFG_UNSUPPORTED (0x42) +#define MPI3_DEVICE0_ASTATUS_NVME_IDENTIFY_FAILED (0x43) +#define MPI3_DEVICE0_ASTATUS_NVME_QCONFIG_FAILED (0x44) +#define MPI3_DEVICE0_ASTATUS_NVME_QCREATION_FAILED (0x45) +#define MPI3_DEVICE0_ASTATUS_NVME_EVENTCFG_FAILED (0x46) +#define MPI3_DEVICE0_ASTATUS_NVME_GET_FEATURE_STAT_FAILED (0x47) +#define MPI3_DEVICE0_ASTATUS_NVME_IDLE_TIMEOUT (0x48) +#define MPI3_DEVICE0_ASTATUS_NVME_CTRL_FAILURE_STATUS (0x49) +#define MPI3_DEVICE0_ASTATUS_NVME_INSUFFICIENT_POWER (0x4A) +#define MPI3_DEVICE0_ASTATUS_NVME_DOORBELL_STRIDE (0x4B) +#define MPI3_DEVICE0_ASTATUS_NVME_MEM_PAGE_MIN_SIZE (0x4C) +#define MPI3_DEVICE0_ASTATUS_NVME_MEMORY_ALLOCATION (0x4D) +#define MPI3_DEVICE0_ASTATUS_NVME_COMPLETION_TIME (0x4E) +#define MPI3_DEVICE0_ASTATUS_NVME_BAR (0x4F) +#define MPI3_DEVICE0_ASTATUS_NVME_NS_DESCRIPTOR (0x50) +#define MPI3_DEVICE0_ASTATUS_NVME_INCOMPATIBLE_SETTINGS (0x51) +#define MPI3_DEVICE0_ASTATUS_NVME_TOO_MANY_ERRORS (0x52) +#define MPI3_DEVICE0_ASTATUS_NVME_MAX (0x5F) +/* Virtual Device Access Status Codes */ +#define MPI3_DEVICE0_ASTATUS_VD_UNKNOWN (0x80) +#define MPI3_DEVICE0_ASTATUS_VD_MAX (0x8F) + +/**** Defines for the Flags field ****/ +#define MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_MASK (0xE000) +#define MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_NO_LIMIT (0x0000) +#define MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_256_LB (0x2000) +#define MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_2048_LB (0x4000) +#define MPI3_DEVICE0_FLAGS_CONTROLLER_DEV_HANDLE (0x0080) +#define MPI3_DEVICE0_FLAGS_IO_THROTTLING_REQUIRED (0x0010) +#define MPI3_DEVICE0_FLAGS_HIDDEN (0x0008) +#define MPI3_DEVICE0_FLAGS_ATT_METHOD_VIRTUAL (0x0004) +#define MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED (0x0002) +#define MPI3_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001) + +/**** Defines for the SlotIndex field - use MPI3_SLOT_INDEX_ defines ****/ + +/**** Defines for the DeviceForm field - use MPI3_DEVICE_DEVFORM_ defines ****/ + +/**** Defines for the QueueDepth field ****/ +#define MPI3_DEVICE0_QUEUE_DEPTH_NOT_APPLICABLE (0x0000) + + +/***************************************************************************** + * Device Page 1 * + ****************************************************************************/ +typedef struct _MPI3_DEVICE1_SAS_SATA_FORMAT +{ + U32 Reserved00; /* 0x00 */ +} MPI3_DEVICE1_SAS_SATA_FORMAT, MPI3_POINTER PTR_MPI3_DEVICE1_SAS_SATA_FORMAT, + Mpi3Device1SasSataFormat_t, MPI3_POINTER pMpi3Device1SasSataFormat_t; + +typedef struct _MPI3_DEVICE1_PCIE_FORMAT +{ + U16 VendorID; /* 0x00 */ + U16 DeviceID; /* 0x02 */ + U16 SubsystemVendorID; /* 0x04 */ + U16 SubsystemID; /* 0x06 */ + U32 Reserved08; /* 0x08 */ + U8 RevisionID; /* 0x0C */ + U8 Reserved0D; /* 0x0D */ + U16 PCIParameters; /* 0x0E */ +} MPI3_DEVICE1_PCIE_FORMAT, MPI3_POINTER PTR_MPI3_DEVICE1_PCIE_FORMAT, + Mpi3Device1PcieFormat_t, MPI3_POINTER pMpi3Device1PcieFormat_t; + +/**** Defines for the PCIParameters field ****/ +#define MPI3_DEVICE1_PCIE_PARAMS_DATA_SIZE_128B (0x0) +#define MPI3_DEVICE1_PCIE_PARAMS_DATA_SIZE_256B (0x1) +#define MPI3_DEVICE1_PCIE_PARAMS_DATA_SIZE_512B (0x2) +#define MPI3_DEVICE1_PCIE_PARAMS_DATA_SIZE_1024B (0x3) +#define MPI3_DEVICE1_PCIE_PARAMS_DATA_SIZE_2048B (0x4) +#define MPI3_DEVICE1_PCIE_PARAMS_DATA_SIZE_4096B (0x5) + +/*** MaxReadRequestSize, CurrentMaxPayloadSize, and MaxPayloadSizeSupported ***/ +/*** all use the size definitions above - shifted to the proper position ***/ +#define MPI3_DEVICE1_PCIE_PARAMS_MAX_READ_REQ_MASK (0x01C0) +#define MPI3_DEVICE1_PCIE_PARAMS_MAX_READ_REQ_SHIFT (6) +#define MPI3_DEVICE1_PCIE_PARAMS_CURR_MAX_PAYLOAD_MASK (0x0038) +#define MPI3_DEVICE1_PCIE_PARAMS_CURR_MAX_PAYLOAD_SHIFT (3) +#define MPI3_DEVICE1_PCIE_PARAMS_SUPP_MAX_PAYLOAD_MASK (0x0007) +#define MPI3_DEVICE1_PCIE_PARAMS_SUPP_MAX_PAYLOAD_SHIFT (0) + +typedef struct _MPI3_DEVICE1_VD_FORMAT +{ + U32 Reserved00; /* 0x00 */ +} MPI3_DEVICE1_VD_FORMAT, MPI3_POINTER PTR_MPI3_DEVICE1_VD_FORMAT, + Mpi3Device1VdFormat_t, MPI3_POINTER pMpi3Device1VdFormat_t; + +typedef union _MPI3_DEVICE1_DEV_SPEC_FORMAT +{ + MPI3_DEVICE1_SAS_SATA_FORMAT SasSataFormat; + MPI3_DEVICE1_PCIE_FORMAT PcieFormat; + MPI3_DEVICE1_VD_FORMAT VdFormat; +} MPI3_DEVICE1_DEV_SPEC_FORMAT, MPI3_POINTER PTR_MPI3_DEVICE1_DEV_SPEC_FORMAT, + Mpi3Device1DevSpecFormat_t, MPI3_POINTER pMpi3Device1DevSpecFormat_t; + +typedef struct _MPI3_DEVICE_PAGE1 +{ + MPI3_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 DevHandle; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U16 LinkChangeCount; /* 0x0C */ + U16 RateChangeCount; /* 0x0E */ + U16 TMCount; /* 0x10 */ + U16 Reserved12; /* 0x12 */ + U32 Reserved14[10]; /* 0x14 */ + U8 Reserved3C[3]; /* 0x3C */ + U8 DeviceForm; /* 0x3F */ + MPI3_DEVICE1_DEV_SPEC_FORMAT DeviceSpecific; /* 0x40 */ +} MPI3_DEVICE_PAGE1, MPI3_POINTER PTR_MPI3_DEVICE_PAGE1, + Mpi3DevicePage1_t, MPI3_POINTER pMpi3DevicePage1_t; + +/**** Defines for the PageVersion field ****/ +#define MPI3_DEVICE1_PAGEVERSION (0x00) + +/**** Defines for the LinkChangeCount, RateChangeCount, TMCount fields ****/ +#define MPI3_DEVICE1_COUNTER_MAX (0xFFFE) +#define MPI3_DEVICE1_COUNTER_INVALID (0xFFFF) + +/**** Defines for the DeviceForm field - use MPI3_DEVICE_DEVFORM_ defines ****/ + +#endif /* MPI30_CNFG_H */ diff --git a/sys/dev/mpi3mr/mpi/mpi30_image.h b/sys/dev/mpi3mr/mpi/mpi30_image.h new file mode 100644 index 000000000000..7b953cb3b1a6 --- /dev/null +++ b/sys/dev/mpi3mr/mpi/mpi30_image.h @@ -0,0 +1,426 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2016-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + * + */ + +#ifndef MPI30_IMAGE_H +#define MPI30_IMAGE_H 1 + +/* Component Image Version */ +typedef struct _MPI3_COMP_IMAGE_VERSION +{ + U16 BuildNum; /* 0x00 */ + U16 CustomerID; /* 0x02 */ + U8 PhaseMinor; /* 0x04 */ + U8 PhaseMajor; /* 0x05 */ + U8 GenMinor; /* 0x06 */ + U8 GenMajor; /* 0x07 */ +} MPI3_COMP_IMAGE_VERSION, MPI3_POINTER PTR_MPI3_COMP_IMAGE_VERSION, + Mpi3CompImageVersion_t, MPI3_POINTER pMpi3CompImageVersion_t; + +/* Hash Exclusion Format */ +typedef struct _MPI3_HASH_EXCLUSION_FORMAT +{ + U32 Offset; /* 0x00 */ + U32 Size; /* 0x04 */ +} MPI3_HASH_EXCLUSION_FORMAT, MPI3_POINTER PTR_MPI3_HASH_EXCLUSION_FORMAT, +Mpi3HashSxclusionFormat_t, MPI3_POINTER pMpi3HashExclusionFormat_t; + +#define MPI3_IMAGE_HASH_EXCUSION_NUM (4) + +/* FW Image Header */ +typedef struct _MPI3_COMPONENT_IMAGE_HEADER +{ + U32 Signature0; /* 0x00 */ + U32 LoadAddress; /* 0x04 */ + U32 DataSize; /* 0x08 */ + U32 StartOffset; /* 0x0C */ + U32 Signature1; /* 0x10 */ + U32 FlashOffset; /* 0x14 */ + U32 ImageSize; /* 0x18 */ + U32 VersionStringOffset; /* 0x1C */ + U32 BuildDateStringOffset; /* 0x20 */ + U32 BuildTimeStringOffset; /* 0x24 */ + U32 EnvironmentVariableOffset; /* 0x28 */ + U32 ApplicationSpecific; /* 0x2C */ + U32 Signature2; /* 0x30 */ + U32 HeaderSize; /* 0x34 */ + U32 Crc; /* 0x38 */ + U32 Flags; /* 0x3C */ + U32 SecondaryFlashOffset; /* 0x40 */ + U32 ETPOffset; /* 0x44 */ + U32 ETPSize; /* 0x48 */ + MPI3_VERSION_UNION RMCInterfaceVersion; /* 0x4C */ + MPI3_VERSION_UNION ETPInterfaceVersion; /* 0x50 */ + MPI3_COMP_IMAGE_VERSION ComponentImageVersion; /* 0x54 */ + MPI3_HASH_EXCLUSION_FORMAT HashExclusion[MPI3_IMAGE_HASH_EXCUSION_NUM]; /* 0x5C */ + U32 NextImageHeaderOffset; /* 0x7C */ + MPI3_VERSION_UNION SecurityVersion; /* 0x80 */ + U32 Reserved84[31]; /* 0x84 -- 0xFC */ +} MPI3_COMPONENT_IMAGE_HEADER, MPI3_POINTER PTR_MPI3_COMPONENT_IMAGE_HEADER, + Mpi3ComponentImageHeader_t, MPI3_POINTER pMpi3ComponentImageHeader_t; + + +/**** Definitions for Signature0 field ****/ +#define MPI3_IMAGE_HEADER_SIGNATURE0_MPI3 (0xEB00003E) + +/**** Definitions for LoadAddress field ****/ +#define MPI3_IMAGE_HEADER_LOAD_ADDRESS_INVALID (0x00000000) + +/**** Definitions for Signature1 field ****/ +#define MPI3_IMAGE_HEADER_SIGNATURE1_APPLICATION (0x20505041) /* string "APP " */ +#define MPI3_IMAGE_HEADER_SIGNATURE1_FIRST_MUTABLE (0x20434D46) /* string "FMC " */ +#define MPI3_IMAGE_HEADER_SIGNATURE1_BSP (0x20505342) /* string "BSP " */ +#define MPI3_IMAGE_HEADER_SIGNATURE1_ROM_BIOS (0x534F4942) /* string "BIOS" */ +#define MPI3_IMAGE_HEADER_SIGNATURE1_HII_X64 (0x4D494948) /* string "HIIM" */ +#define MPI3_IMAGE_HEADER_SIGNATURE1_HII_ARM (0x41494948) /* string "HIIA" */ +#define MPI3_IMAGE_HEADER_SIGNATURE1_CPLD (0x444C5043) /* string "CPLD" */ +#define MPI3_IMAGE_HEADER_SIGNATURE1_SPD (0x20445053) /* string "SPD " */ +#define MPI3_IMAGE_HEADER_SIGNATURE1_GAS_GAUGE (0x20534147) /* string "GAS " */ +#define MPI3_IMAGE_HEADER_SIGNATURE1_PBLP (0x504C4250) /* string "PBLP" */ +#define MPI3_IMAGE_HEADER_SIGNATURE1_MANIFEST (0x464E414D) /* string "MANF" */ +#define MPI3_IMAGE_HEADER_SIGNATURE1_OEM (0x204D454F) /* string "OEM " */ +#define MPI3_IMAGE_HEADER_SIGNATURE1_RMC (0x20434D52) /* string "RMC " */ +#define MPI3_IMAGE_HEADER_SIGNATURE1_SMM (0x204D4D53) /* string "SMM " */ +#define MPI3_IMAGE_HEADER_SIGNATURE1_PSW (0x20575350) /* string "PSW " */ + + +/**** Definitions for Signature2 field ****/ +#define MPI3_IMAGE_HEADER_SIGNATURE2_VALUE (0x50584546) + +/**** Definitions for Flags field ****/ +#define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_MASK (0x00000030) +#define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_CDI (0x00000000) +#define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_DI (0x00000010) +#define MPI3_IMAGE_HEADER_FLAGS_SIGNED_NVDATA (0x00000008) +#define MPI3_IMAGE_HEADER_FLAGS_REQUIRES_ACTIVATION (0x00000004) +#define MPI3_IMAGE_HEADER_FLAGS_COMPRESSED (0x00000002) +#define MPI3_IMAGE_HEADER_FLAGS_FLASH (0x00000001) + + +/**** Offsets for Image Header Fields ****/ +#define MPI3_IMAGE_HEADER_SIGNATURE0_OFFSET (0x00) +#define MPI3_IMAGE_HEADER_LOAD_ADDRESS_OFFSET (0x04) +#define MPI3_IMAGE_HEADER_DATA_SIZE_OFFSET (0x08) +#define MPI3_IMAGE_HEADER_START_OFFSET_OFFSET (0x0C) +#define MPI3_IMAGE_HEADER_SIGNATURE1_OFFSET (0x10) +#define MPI3_IMAGE_HEADER_FLASH_OFFSET_OFFSET (0x14) +#define MPI3_IMAGE_HEADER_FLASH_SIZE_OFFSET (0x18) +#define MPI3_IMAGE_HEADER_VERSION_STRING_OFFSET_OFFSET (0x1C) +#define MPI3_IMAGE_HEADER_BUILD_DATE_STRING_OFFSET_OFFSET (0x20) +#define MPI3_IMAGE_HEADER_BUILD_TIME_OFFSET_OFFSET (0x24) +#define MPI3_IMAGE_HEADER_ENVIROMENT_VAR_OFFSET_OFFSET (0x28) +#define MPI3_IMAGE_HEADER_APPLICATION_SPECIFIC_OFFSET (0x2C) +#define MPI3_IMAGE_HEADER_SIGNATURE2_OFFSET (0x30) +#define MPI3_IMAGE_HEADER_HEADER_SIZE_OFFSET (0x34) +#define MPI3_IMAGE_HEADER_CRC_OFFSET (0x38) +#define MPI3_IMAGE_HEADER_FLAGS_OFFSET (0x3C) +#define MPI3_IMAGE_HEADER_SECONDARY_FLASH_OFFSET_OFFSET (0x40) +#define MPI3_IMAGE_HEADER_ETP_OFFSET_OFFSET (0x44) +#define MPI3_IMAGE_HEADER_ETP_SIZE_OFFSET (0x48) +#define MPI3_IMAGE_HEADER_RMC_INTERFACE_VER_OFFSET (0x4C) +#define MPI3_IMAGE_HEADER_ETP_INTERFACE_VER_OFFSET (0x50) +#define MPI3_IMAGE_HEADER_COMPONENT_IMAGE_VER_OFFSET (0x54) +#define MPI3_IMAGE_HEADER_HASH_EXCLUSION_OFFSET (0x5C) +#define MPI3_IMAGE_HEADER_NEXT_IMAGE_HEADER_OFFSET_OFFSET (0x7C) + + +#define MPI3_IMAGE_HEADER_SIZE (0x100) + + + +/***************************************************************************** + * Component Image Data * + *****************************************************************************/ + +/* Package Manifest Data */ + +#ifndef MPI3_CI_MANIFEST_MPI_MAX +#define MPI3_CI_MANIFEST_MPI_MAX (1) +#endif /* MPI3_CI_MANIFEST_MPI_MAX */ + +typedef struct _MPI3_CI_MANIFEST_MPI_COMP_IMAGE_REF +{ + U32 Signature1; /* 0x00 */ + U32 Reserved04[3]; /* 0x04 */ + MPI3_COMP_IMAGE_VERSION ComponentImageVersion; /* 0x10 */ + U32 ComponentImageVersionStringOffset; /* 0x18 */ + U32 CRC; /* 0x1C */ +} MPI3_CI_MANIFEST_MPI_COMP_IMAGE_REF, MPI3_POINTER PTR_MPI3_CI_MANIFEST_MPI_COMP_IMAGE_REF, + Mpi3CIManifestMpiCompImageRef_t, MPI3_POINTER pMpi3CIManifestMpiCompImageRef_t; + +typedef struct _MPI3_CI_MANIFEST_MPI +{ + U8 ManifestType; /* 0x00 */ + U8 Reserved01[3]; /* 0x01 */ + U32 Reserved04[3]; /* 0x04 */ + U8 NumImageReferences; /* 0x10 */ + U8 ReleaseLevel; /* 0x11 */ + U16 Reserved12; /* 0x12 */ + U16 Reserved14; /* 0x14 */ + U16 Flags; /* 0x16 */ + U32 Reserved18[2]; /* 0x18 */ + U16 VendorID; /* 0x20 */ + U16 DeviceID; /* 0x22 */ + U16 SubsystemVendorID; /* 0x24 */ + U16 SubsystemID; /* 0x26 */ + U32 Reserved28[2]; /* 0x28 */ + MPI3_VERSION_UNION PackageSecurityVersion; /* 0x30 */ + U32 Reserved34; /* 0x34 */ + MPI3_COMP_IMAGE_VERSION PackageVersion; /* 0x38 */ + U32 PackageVersionStringOffset; /* 0x40 */ + U32 PackageBuildDateStringOffset; /* 0x44 */ + U32 PackageBuildTimeStringOffset; /* 0x48 */ + U32 Reserved4C; /* 0x4C */ + U32 DiagAuthorizationIdentifier[16]; /* 0x50 */ + MPI3_CI_MANIFEST_MPI_COMP_IMAGE_REF ComponentImageRef[MPI3_CI_MANIFEST_MPI_MAX]; /* 0x90 */ /* variable length */ + /* StringData - offset of this field must be calculated */ /* variable length */ +} MPI3_CI_MANIFEST_MPI, MPI3_POINTER PTR_MPI3_CI_MANIFEST_MPI, + Mpi3CIManifestMpi_t, MPI3_POINTER pMpi3CIManifestMpi_t; + +/* defines for the ReleaseLevel field */ +#define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_DEV (0x00) +#define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_PREALPHA (0x10) +#define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_ALPHA (0x20) +#define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_BETA (0x30) +#define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_RC (0x40) +#define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_GCA (0x50) +#define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_POINT (0x60) + +/* defines for the Flags field */ +#define MPI3_CI_MANIFEST_MPI_FLAGS_DIAG_AUTHORIZATION (0x01) + +/* defines for the SubsystemID field */ +#define MPI3_CI_MANIFEST_MPI_SUBSYSTEMID_IGNORED (0xFFFF) + +/* defines for the PackageVersionStringOffset field */ +#define MPI3_CI_MANIFEST_MPI_PKG_VER_STR_OFF_UNSPECIFIED (0x00000000) + +/* defines for the PackageBuildDateStringOffset field */ +#define MPI3_CI_MANIFEST_MPI_PKG_BUILD_DATE_STR_OFF_UNSPECIFIED (0x00000000) + +/* defines for the PackageBuildTimeStringOffset field */ +#define MPI3_CI_MANIFEST_MPI_PKG_BUILD_TIME_STR_OFF_UNSPECIFIED (0x00000000) + +typedef union _MPI3_CI_MANIFEST +{ + MPI3_CI_MANIFEST_MPI Mpi; + U32 Dword[1]; +} MPI3_CI_MANIFEST, MPI3_POINTER PTR_MPI3_CI_MANIFEST, + Mpi3CIManifest_t, MPI3_POINTER pMpi3CIManifest_t; + +/* defines for ManifestType field */ +#define MPI3_CI_MANIFEST_TYPE_MPI (0x00) + + +/***************************************************************************** + * Extended Image Data * + *****************************************************************************/ + +/* Extended Image Header */ +typedef struct _MPI3_EXTENDED_IMAGE_HEADER +{ + U8 ImageType; /* 0x00 */ + U8 Reserved01[3]; /* 0x01 */ + U32 Checksum; /* 0x04 */ + U32 ImageSize; /* 0x08 */ + U32 NextImageHeaderOffset; /* 0x0C */ + U32 Reserved10[4]; /* 0x10 */ + U32 IdentifyString[8]; /* 0x20 */ +} MPI3_EXTENDED_IMAGE_HEADER, MPI3_POINTER PTR_MPI3_EXTENDED_IMAGE_HEADER, + Mpi3ExtendedImageHeader_t, MPI3_POINTER pMpi3ExtendedImageHeader_t; + +/* useful offsets */ +#define MPI3_EXT_IMAGE_IMAGETYPE_OFFSET (0x00) +#define MPI3_EXT_IMAGE_IMAGESIZE_OFFSET (0x08) +#define MPI3_EXT_IMAGE_NEXTIMAGE_OFFSET (0x0C) + +#define MPI3_EXT_IMAGE_HEADER_SIZE (0x40) + +/* defines for the ImageType field */ +#define MPI3_EXT_IMAGE_TYPE_UNSPECIFIED (0x00) +#define MPI3_EXT_IMAGE_TYPE_NVDATA (0x03) +#define MPI3_EXT_IMAGE_TYPE_SUPPORTED_DEVICES (0x07) +#define MPI3_EXT_IMAGE_TYPE_ENCRYPTED_HASH (0x09) +#define MPI3_EXT_IMAGE_TYPE_RDE (0x0A) +#define MPI3_EXT_IMAGE_TYPE_AUXILIARY_PROCESSOR (0x0B) +#define MPI3_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC (0x80) +#define MPI3_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC (0xFF) + + +/* Supported Device Data Format */ +typedef struct _MPI3_SUPPORTED_DEVICE +{ + U16 DeviceID; /* 0x00 */ + U16 VendorID; /* 0x02 */ + U16 DeviceIDMask; /* 0x04 */ + U16 Reserved06; /* 0x06 */ + U8 LowPCIRev; /* 0x08 */ + U8 HighPCIRev; /* 0x09 */ + U16 Reserved0A; /* 0x0A */ + U32 Reserved0C; /* 0x0C */ +} MPI3_SUPPORTED_DEVICE, MPI3_POINTER PTR_MPI3_SUPPORTED_DEVICE, + Mpi3SupportedDevice_t, MPI3_POINTER pMpi3SupportedDevice_t; + +#ifndef MPI3_SUPPORTED_DEVICE_MAX +#define MPI3_SUPPORTED_DEVICE_MAX (1) +#endif /* MPI3_SUPPORTED_DEVICE_MAX */ + +/* Supported Devices Extended Image Data */ +typedef struct _MPI3_SUPPORTED_DEVICES_DATA +{ + U8 ImageVersion; /* 0x00 */ + U8 Reserved01; /* 0x01 */ + U8 NumDevices; /* 0x02 */ + U8 Reserved03; /* 0x03 */ + U32 Reserved04; /* 0x04 */ + MPI3_SUPPORTED_DEVICE SupportedDevice[MPI3_SUPPORTED_DEVICE_MAX]; /* 0x08 */ /* variable length */ +} MPI3_SUPPORTED_DEVICES_DATA, MPI3_POINTER PTR_MPI3_SUPPORTED_DEVICES_DATA, + Mpi3SupportedDevicesData_t, MPI3_POINTER pMpi3SupportedDevicesData_t; + +#ifndef MPI3_ENCRYPTED_HASH_MAX +#define MPI3_ENCRYPTED_HASH_MAX (1) +#endif /* MPI3_ENCRYPTED_HASH_MAX */ + +/* Encrypted Hash Entry Format */ +typedef struct _MPI3_ENCRYPTED_HASH_ENTRY +{ + U8 HashImageType; /* 0x00 */ + U8 HashAlgorithm; /* 0x01 */ + U8 EncryptionAlgorithm; /* 0x02 */ + U8 Reserved03; /* 0x03 */ + U32 Reserved04; /* 0x04 */ + U32 EncryptedHash[MPI3_ENCRYPTED_HASH_MAX]; /* 0x08 */ /* variable length */ +} MPI3_ENCRYPTED_HASH_ENTRY, MPI3_POINTER PTR_MPI3_ENCRYPTED_HASH_ENTRY, + Mpi3EncryptedHashEntry_t, MPI3_POINTER pMpi3EncryptedHashEntry_t; + + +/* defines for the HashImageType field */ +#define MPI3_HASH_IMAGE_TYPE_KEY_WITH_SIGNATURE (0x03) + +/* defines for the HashAlgorithm field */ +#define MPI3_HASH_ALGORITHM_VERSION_MASK (0xE0) +#define MPI3_HASH_ALGORITHM_VERSION_NONE (0x00) +#define MPI3_HASH_ALGORITHM_VERSION_SHA1 (0x20) /* Obsolete */ +#define MPI3_HASH_ALGORITHM_VERSION_SHA2 (0x40) +#define MPI3_HASH_ALGORITHM_VERSION_SHA3 (0x60) + +#define MPI3_HASH_ALGORITHM_SIZE_MASK (0x1F) +#define MPI3_HASH_ALGORITHM_SIZE_UNUSED (0x00) +#define MPI3_HASH_ALGORITHM_SIZE_SHA256 (0x01) +#define MPI3_HASH_ALGORITHM_SIZE_SHA512 (0x02) +#define MPI3_HASH_ALGORITHM_SIZE_SHA384 (0x03) + +/* defines for the EncryptionAlgorithm field */ +#define MPI3_ENCRYPTION_ALGORITHM_UNUSED (0x00) +#define MPI3_ENCRYPTION_ALGORITHM_RSA256 (0x01) /* Obsolete */ +#define MPI3_ENCRYPTION_ALGORITHM_RSA512 (0x02) /* Obsolete */ +#define MPI3_ENCRYPTION_ALGORITHM_RSA1024 (0x03) /* Obsolete */ +#define MPI3_ENCRYPTION_ALGORITHM_RSA2048 (0x04) +#define MPI3_ENCRYPTION_ALGORITHM_RSA4096 (0x05) +#define MPI3_ENCRYPTION_ALGORITHM_RSA3072 (0x06) +#define MPI3_ENCRYPTION_ALGORITHM_ECDSA_P256 (0x07) /* NIST secp256r1 curve */ +#define MPI3_ENCRYPTION_ALGORITHM_ECDSA_P384 (0x08) /* NIST secp384r1 curve */ +#define MPI3_ENCRYPTION_ALGORITHM_ECDSA_P521 (0x09) /* NIST secp521r1 curve */ + + +#ifndef MPI3_PUBLIC_KEY_MAX +#define MPI3_PUBLIC_KEY_MAX (1) +#endif /* MPI3_PUBLIC_KEY_MAX */ + +/* Encrypted Key with Hash Entry Format */ +typedef struct _MPI3_ENCRYPTED_KEY_WITH_HASH_ENTRY +{ + U8 HashImageType; /* 0x00 */ + U8 HashAlgorithm; /* 0x01 */ + U8 EncryptionAlgorithm; /* 0x02 */ + U8 Reserved03; /* 0x03 */ + U32 Reserved04; /* 0x04 */ + U32 PublicKey[MPI3_PUBLIC_KEY_MAX]; /* 0x08 */ /* variable length */ + /* EncryptedHash - offset of this field must be calculated */ /* variable length */ +} MPI3_ENCRYPTED_KEY_WITH_HASH_ENTRY, MPI3_POINTER PTR_MPI3_ENCRYPTED_KEY_WITH_HASH_ENTRY, + Mpi3EncryptedKeyWithHashEntry_t, MPI3_POINTER pMpi3EncryptedKeyWithHashEntry_t; + +#ifndef MPI3_ENCRYPTED_HASH_ENTRY_MAX +#define MPI3_ENCRYPTED_HASH_ENTRY_MAX (1) +#endif /* MPI3_ENCRYPTED_HASH_ENTRY_MAX */ + +/* Encrypted Hash Image Data */ +typedef struct _MPI3_ENCRYPTED_HASH_DATA +{ + U8 ImageVersion; /* 0x00 */ + U8 NumHash; /* 0x01 */ + U16 Reserved02; /* 0x02 */ + U32 Reserved04; /* 0x04 */ + MPI3_ENCRYPTED_HASH_ENTRY EncryptedHashEntry[MPI3_ENCRYPTED_HASH_ENTRY_MAX]; /* 0x08 */ /* variable length */ +} MPI3_ENCRYPTED_HASH_DATA, MPI3_POINTER PTR_MPI3_ENCRYPTED_HASH_DATA, + Mpi3EncryptedHashData_t, MPI3_POINTER pMpi3EncryptedHashData_t; + + +#ifndef MPI3_AUX_PROC_DATA_MAX +#define MPI3_AUX_PROC_DATA_MAX (1) +#endif /* MPI3_ENCRYPTED_HASH_ENTRY_MAX */ + +/* Auxiliary Processor Extended Image Data */ +typedef struct _MPI3_AUX_PROCESSOR_DATA +{ + U8 BootMethod; /* 0x00 */ + U8 NumLoadAddr; /* 0x01 */ + U8 Reserved02; /* 0x02 */ + U8 Type; /* 0x03 */ + U32 Version; /* 0x04 */ + U32 LoadAddress[8]; /* 0x08 */ + U32 Reserved28[22]; /* 0x28 */ + U32 AuxProcessorData[MPI3_AUX_PROC_DATA_MAX]; /* 0x80 */ /* variable length */ +} MPI3_AUX_PROCESSOR_DATA, MPI3_POINTER PTR_MPI3_AUX_PROCESSOR_DATA, + Mpi3AuxProcessorData_t, MPI3_POINTER pMpi3AuxProcessorData_t; + +#define MPI3_AUX_PROC_DATA_OFFSET (0x80) + +/* defines for the BootMethod field */ +#define MPI3_AUXPROCESSOR_BOOT_METHOD_MO_MSG (0x00) +#define MPI3_AUXPROCESSOR_BOOT_METHOD_MO_DOORBELL (0x01) +#define MPI3_AUXPROCESSOR_BOOT_METHOD_COMPONENT (0x02) + +/* defines for the Type field */ +#define MPI3_AUXPROCESSOR_TYPE_ARM_A15 (0x00) +#define MPI3_AUXPROCESSOR_TYPE_ARM_M0 (0x01) +#define MPI3_AUXPROCESSOR_TYPE_ARM_R4 (0x02) + +#endif /* MPI30_IMAGE_H */ diff --git a/sys/dev/mpi3mr/mpi/mpi30_init.h b/sys/dev/mpi3mr/mpi/mpi30_init.h new file mode 100644 index 000000000000..c0ba14909ac1 --- /dev/null +++ b/sys/dev/mpi3mr/mpi/mpi30_init.h @@ -0,0 +1,265 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2016-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + * + */ + +#ifndef MPI30_INIT_H +#define MPI30_INIT_H 1 + +/***************************************************************************** + * SCSI Initiator Messages * + ****************************************************************************/ + +/***************************************************************************** + * SCSI IO Request Message * + ****************************************************************************/ +typedef struct _MPI3_SCSI_IO_CDB_EEDP32 +{ + U8 CDB[20]; /* 0x00 */ + U32 PrimaryReferenceTag; /* 0x14 */ + U16 PrimaryApplicationTag; /* 0x18 */ + U16 PrimaryApplicationTagMask; /* 0x1A */ + U32 TransferLength; /* 0x1C */ +} MPI3_SCSI_IO_CDB_EEDP32, MPI3_POINTER PTR_MPI3_SCSI_IO_CDB_EEDP32, + Mpi3ScsiIoCdbEedp32_t, MPI3_POINTER pMpi3ScsiIoCdbEedp32_t; + +typedef union _MPI3_SCSI_IO_CDB_UNION +{ + U8 CDB32[32]; + MPI3_SCSI_IO_CDB_EEDP32 EEDP32; + MPI3_SGE_SIMPLE SGE; +} MPI3_SCSI_IO_CDB_UNION, MPI3_POINTER PTR_MPI3_SCSI_IO_CDB_UNION, + Mpi3ScsiIoCdb_t, MPI3_POINTER pMpi3ScsiIoCdb_t; + +typedef struct _MPI3_SCSI_IO_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 DevHandle; /* 0x0A */ + U32 Flags; /* 0x0C */ + U32 SkipCount; /* 0x10 */ + U32 DataLength; /* 0x14 */ + U8 LUN[8]; /* 0x18 */ + MPI3_SCSI_IO_CDB_UNION CDB; /* 0x20 */ + MPI3_SGE_UNION SGL[4]; /* 0x40 */ +} MPI3_SCSI_IO_REQUEST, MPI3_POINTER PTR_MPI3_SCSI_IO_REQUEST, + Mpi3SCSIIORequest_t, MPI3_POINTER pMpi3SCSIIORequest_t; + +/**** Defines for the MsgFlags field ****/ +#define MPI3_SCSIIO_MSGFLAGS_METASGL_VALID (0x80) +#define MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE (0x40) + +/**** Defines for the Flags field ****/ +#define MPI3_SCSIIO_FLAGS_LARGE_CDB (0x60000000) +#define MPI3_SCSIIO_FLAGS_CDB_16_OR_LESS (0x00000000) +#define MPI3_SCSIIO_FLAGS_CDB_GREATER_THAN_16 (0x20000000) +#define MPI3_SCSIIO_FLAGS_CDB_IN_SEPARATE_BUFFER (0x40000000) +#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_MASK (0x07000000) +#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_SIMPLEQ (0x00000000) +#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_HEADOFQ (0x01000000) +#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_ORDEREDQ (0x02000000) +#define MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_ACAQ (0x04000000) +#define MPI3_SCSIIO_FLAGS_CMDPRI_MASK (0x00F00000) +#define MPI3_SCSIIO_FLAGS_CMDPRI_SHIFT (20) +#define MPI3_SCSIIO_FLAGS_DATADIRECTION_MASK (0x000C0000) +#define MPI3_SCSIIO_FLAGS_DATADIRECTION_NO_DATA_TRANSFER (0x00000000) +#define MPI3_SCSIIO_FLAGS_DATADIRECTION_WRITE (0x00040000) +#define MPI3_SCSIIO_FLAGS_DATADIRECTION_READ (0x00080000) +#define MPI3_SCSIIO_FLAGS_DMAOPERATION_MASK (0x00030000) +#define MPI3_SCSIIO_FLAGS_DMAOPERATION_HOST_PI (0x00010000) +#define MPI3_SCSIIO_FLAGS_DIVERT_REASON_MASK (0x000000F0) +#define MPI3_SCSIIO_FLAGS_DIVERT_REASON_IO_THROTTLING (0x00000010) +#define MPI3_SCSIIO_FLAGS_DIVERT_REASON_WRITE_SAME_TOO_LARGE (0x00000020) +#define MPI3_SCSIIO_FLAGS_DIVERT_REASON_PROD_SPECIFIC (0x00000080) + +/**** Defines for the SGL field ****/ +#define MPI3_SCSIIO_METASGL_INDEX (3) + +/***************************************************************************** + * SCSI IO Error Reply Message * + ****************************************************************************/ +typedef struct _MPI3_SCSI_IO_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ + U8 SCSIStatus; /* 0x10 */ + U8 SCSIState; /* 0x11 */ + U16 DevHandle; /* 0x12 */ + U32 TransferCount; /* 0x14 */ + U32 SenseCount; /* 0x18 */ + U32 ResponseData; /* 0x1C */ + U16 TaskTag; /* 0x20 */ + U16 SCSIStatusQualifier; /* 0x22 */ + U32 EEDPErrorOffset; /* 0x24 */ + U16 EEDPObservedAppTag; /* 0x28 */ + U16 EEDPObservedGuard; /* 0x2A */ + U32 EEDPObservedRefTag; /* 0x2C */ + U64 SenseDataBufferAddress; /* 0x30 */ +} MPI3_SCSI_IO_REPLY, MPI3_POINTER PTR_MPI3_SCSI_IO_REPLY, + Mpi3SCSIIOReply_t, MPI3_POINTER pMpi3SCSIIOReply_t; + +/**** Defines for the MsgFlags field ****/ +#define MPI3_SCSIIO_REPLY_MSGFLAGS_REFTAG_OBSERVED_VALID (0x01) +#define MPI3_SCSIIO_REPLY_MSGFLAGS_APPTAG_OBSERVED_VALID (0x02) +#define MPI3_SCSIIO_REPLY_MSGFLAGS_GUARD_OBSERVED_VALID (0x04) + +/**** Defines for the SCSIStatus field ****/ +#define MPI3_SCSI_STATUS_GOOD (0x00) +#define MPI3_SCSI_STATUS_CHECK_CONDITION (0x02) +#define MPI3_SCSI_STATUS_CONDITION_MET (0x04) +#define MPI3_SCSI_STATUS_BUSY (0x08) +#define MPI3_SCSI_STATUS_INTERMEDIATE (0x10) +#define MPI3_SCSI_STATUS_INTERMEDIATE_CONDMET (0x14) +#define MPI3_SCSI_STATUS_RESERVATION_CONFLICT (0x18) +#define MPI3_SCSI_STATUS_COMMAND_TERMINATED (0x22) +#define MPI3_SCSI_STATUS_TASK_SET_FULL (0x28) +#define MPI3_SCSI_STATUS_ACA_ACTIVE (0x30) +#define MPI3_SCSI_STATUS_TASK_ABORTED (0x40) + +/**** Defines for the SCSIState field ****/ +#define MPI3_SCSI_STATE_SENSE_MASK (0x03) +#define MPI3_SCSI_STATE_SENSE_VALID (0x00) +#define MPI3_SCSI_STATE_SENSE_FAILED (0x01) +#define MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY (0x02) +#define MPI3_SCSI_STATE_SENSE_NOT_AVAILABLE (0x03) +#define MPI3_SCSI_STATE_NO_SCSI_STATUS (0x04) +#define MPI3_SCSI_STATE_TERMINATED (0x08) +#define MPI3_SCSI_STATE_RESPONSE_DATA_VALID (0x10) + +/**** Defines for the ResponseData field ****/ +#define MPI3_SCSI_RSP_RESPONSECODE_MASK (0x000000FF) +#define MPI3_SCSI_RSP_RESPONSECODE_SHIFT (0) +#define MPI3_SCSI_RSP_ARI2_MASK (0x0000FF00) +#define MPI3_SCSI_RSP_ARI2_SHIFT (8) +#define MPI3_SCSI_RSP_ARI1_MASK (0x00FF0000) +#define MPI3_SCSI_RSP_ARI1_SHIFT (16) +#define MPI3_SCSI_RSP_ARI0_MASK (0xFF000000) +#define MPI3_SCSI_RSP_ARI0_SHIFT (24) + +/**** Defines for the TaskTag field ****/ +#define MPI3_SCSI_TASKTAG_UNKNOWN (0xFFFF) + + +/***************************************************************************** + * SCSI Task Management Request Message * + ****************************************************************************/ +typedef struct _MPI3_SCSI_TASK_MGMT_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 DevHandle; /* 0x0A */ + U16 TaskHostTag; /* 0x0C */ + U8 TaskType; /* 0x0E */ + U8 Reserved0F; /* 0x0F */ + U16 TaskRequestQueueID; /* 0x10 */ + U8 IOCUseOnly12; /* 0x12 */ + U8 Reserved13; /* 0x13 */ + U32 Reserved14; /* 0x14 */ + U8 LUN[8]; /* 0x18 */ +} MPI3_SCSI_TASK_MGMT_REQUEST, MPI3_POINTER PTR_MPI3_SCSI_TASK_MGMT_REQUEST, + Mpi3SCSITaskMgmtRequest_t, MPI3_POINTER pMpi3SCSITaskMgmtRequest_t; + +/**** Defines for the MsgFlags field ****/ +#define MPI3_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x08) + +/**** Defines for the TaskType field ****/ +#define MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01) +#define MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK_SET (0x02) +#define MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03) +#define MPI3_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) +#define MPI3_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) +#define MPI3_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07) +#define MPI3_SCSITASKMGMT_TASKTYPE_CLEAR_ACA (0x08) +#define MPI3_SCSITASKMGMT_TASKTYPE_QUERY_TASK_SET (0x09) +#define MPI3_SCSITASKMGMT_TASKTYPE_QUERY_ASYNC_EVENT (0x0A) +#define MPI3_SCSITASKMGMT_TASKTYPE_I_T_NEXUS_RESET (0x0B) + + +/***************************************************************************** + * SCSI Task Management Reply Message * + ****************************************************************************/ +typedef struct _MPI3_SCSI_TASK_MGMT_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ + U32 TerminationCount; /* 0x10 */ + U32 ResponseData; /* 0x14 */ + U32 Reserved18; /* 0x18 */ +} MPI3_SCSI_TASK_MGMT_REPLY, MPI3_POINTER PTR_MPI3_SCSI_TASK_MGMT_REPLY, + Mpi3SCSITaskMgmtReply_t, MPI3_POINTER pMpi3SCSITaskMgmtReply_t; + +/**** Defines for the ResponseData field - use MPI3_SCSI_RSP_ defines ****/ + +/**** Defines for the ResponseCode field - Byte 0 of ResponseData ****/ +#define MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE (0x00) +#define MPI3_SCSITASKMGMT_RSPCODE_INVALID_FRAME (0x02) +#define MPI3_SCSITASKMGMT_RSPCODE_TM_FUNCTION_NOT_SUPPORTED (0x04) +#define MPI3_SCSITASKMGMT_RSPCODE_TM_FAILED (0x05) +#define MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED (0x08) +#define MPI3_SCSITASKMGMT_RSPCODE_TM_INVALID_LUN (0x09) +#define MPI3_SCSITASKMGMT_RSPCODE_TM_OVERLAPPED_TAG (0x0A) + +#define MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC (0x80) +#define MPI3_SCSITASKMGMT_RSPCODE_TM_NVME_DENIED (0x81) + +#endif /* MPI30_INIT_H */ diff --git a/sys/dev/mpi3mr/mpi/mpi30_ioc.h b/sys/dev/mpi3mr/mpi/mpi30_ioc.h new file mode 100644 index 000000000000..77f6be5b2694 --- /dev/null +++ b/sys/dev/mpi3mr/mpi/mpi30_ioc.h @@ -0,0 +1,1615 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2016-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + * + */ + +#ifndef MPI30_IOC_H +#define MPI30_IOC_H 1 + +/***************************************************************************** + * IOC Messages * + ****************************************************************************/ + +/***************************************************************************** + * IOCInit Request Message * + ****************************************************************************/ +typedef struct _MPI3_IOC_INIT_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + MPI3_VERSION_UNION MPIVersion; /* 0x0C */ + U64 TimeStamp; /* 0x10 */ + U8 Reserved18; /* 0x18 */ + U8 WhoInit; /* 0x19 */ + U16 Reserved1A; /* 0x1A */ + U16 ReplyFreeQueueDepth; /* 0x1C */ + U16 Reserved1E; /* 0x1E */ + U64 ReplyFreeQueueAddress; /* 0x20 */ + U32 Reserved28; /* 0x28 */ + U16 SenseBufferFreeQueueDepth; /* 0x2C */ + U16 SenseBufferLength; /* 0x2E */ + U64 SenseBufferFreeQueueAddress; /* 0x30 */ + U64 DriverInformationAddress; /* 0x38 */ +} MPI3_IOC_INIT_REQUEST, MPI3_POINTER PTR_MPI3_IOC_INIT_REQUEST, + Mpi3IOCInitRequest_t, MPI3_POINTER pMpi3IOCInitRequest_t; + +/**** Defines for the MsgFlags field ****/ +#define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_MASK (0x03) +#define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_NOT_USED (0x00) +#define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_SEPARATED (0x01) +#define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_INLINE (0x02) +#define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_BOTH (0x03) + +/**** Defines for the WhoInit field ****/ +#define MPI3_WHOINIT_NOT_INITIALIZED (0x00) +#define MPI3_WHOINIT_ROM_BIOS (0x02) +#define MPI3_WHOINIT_HOST_DRIVER (0x03) +#define MPI3_WHOINIT_MANUFACTURER (0x04) + +/**** Defines for the DriverInformationAddress field */ +typedef struct _MPI3_DRIVER_INFO_LAYOUT +{ + U32 InformationLength; /* 0x00 */ + U8 DriverSignature[12]; /* 0x04 */ + U8 OsName[16]; /* 0x10 */ + U8 OsVersion[12]; /* 0x20 */ + U8 DriverName[20]; /* 0x2C */ + U8 DriverVersion[32]; /* 0x40 */ + U8 DriverReleaseDate[20]; /* 0x60 */ + U32 DriverCapabilities; /* 0x74 */ +} MPI3_DRIVER_INFO_LAYOUT, MPI3_POINTER PTR_MPI3_DRIVER_INFO_LAYOUT, + Mpi3DriverInfoLayout_t, MPI3_POINTER pMpi3DriverInfoLayout_t; + +/***************************************************************************** + * IOCFacts Request Message * + ****************************************************************************/ +typedef struct _MPI3_IOC_FACTS_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U32 Reserved0C; /* 0x0C */ + MPI3_SGE_UNION SGL; /* 0x10 */ +} MPI3_IOC_FACTS_REQUEST, MPI3_POINTER PTR_MPI3_IOC_FACTS_REQUEST, + Mpi3IOCFactsRequest_t, MPI3_POINTER pMpi3IOCFactsRequest_t; + +/***************************************************************************** + * IOCFacts Data * + ****************************************************************************/ +typedef struct _MPI3_IOC_FACTS_DATA +{ + U16 IOCFactsDataLength; /* 0x00 */ + U16 Reserved02; /* 0x02 */ + MPI3_VERSION_UNION MPIVersion; /* 0x04 */ + MPI3_COMP_IMAGE_VERSION FWVersion; /* 0x08 */ + U32 IOCCapabilities; /* 0x10 */ + U8 IOCNumber; /* 0x14 */ + U8 WhoInit; /* 0x15 */ + U16 MaxMSIxVectors; /* 0x16 */ + U16 MaxOutstandingRequests; /* 0x18 */ + U16 ProductID; /* 0x1A */ + U16 IOCRequestFrameSize; /* 0x1C */ + U16 ReplyFrameSize; /* 0x1E */ + U16 IOCExceptions; /* 0x20 */ + U16 MaxPersistentID; /* 0x22 */ + U8 SGEModifierMask; /* 0x24 */ + U8 SGEModifierValue; /* 0x25 */ + U8 SGEModifierShift; /* 0x26 */ + U8 ProtocolFlags; /* 0x27 */ + U16 MaxSASInitiators; /* 0x28 */ + U16 MaxDataLength; /* 0x2A */ + U16 MaxSASExpanders; /* 0x2C */ + U16 MaxEnclosures; /* 0x2E */ + U16 MinDevHandle; /* 0x30 */ + U16 MaxDevHandle; /* 0x32 */ + U16 MaxPCIeSwitches; /* 0x34 */ + U16 MaxNVMe; /* 0x36 */ + U16 Reserved38; /* 0x38 */ + U16 MaxVDs; /* 0x3A */ + U16 MaxHostPDs; /* 0x3C */ + U16 MaxAdvHostPDs; /* 0x3E */ + U16 MaxRAIDPDs; /* 0x40 */ + U16 MaxPostedCmdBuffers; /* 0x42 */ + U32 Flags; /* 0x44 */ + U16 MaxOperationalRequestQueues; /* 0x48 */ + U16 MaxOperationalReplyQueues; /* 0x4A */ + U16 ShutdownTimeout; /* 0x4C */ + U16 Reserved4E; /* 0x4E */ + U32 DiagTraceSize; /* 0x50 */ + U32 DiagFwSize; /* 0x54 */ + U32 DiagDriverSize; /* 0x58 */ + U8 MaxHostPDNsCount; /* 0x5C */ + U8 MaxAdvHostPDNsCount; /* 0x5D */ + U8 MaxRAIDPDNsCount; /* 0x5E */ + U8 MaxDevicesPerThrottleGroup; /* 0x5F */ + U16 IOThrottleDataLength; /* 0x60 */ + U16 MaxIOThrottleGroup; /* 0x62 */ + U16 IOThrottleLow; /* 0x64 */ + U16 IOThrottleHigh; /* 0x66 */ +} MPI3_IOC_FACTS_DATA, MPI3_POINTER PTR_MPI3_IOC_FACTS_DATA, + Mpi3IOCFactsData_t, MPI3_POINTER pMpi3IOCFactsData_t; + +/**** Defines for the IOCCapabilities field ****/ +#define MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_MASK (0x80000000) +#define MPI3_IOCFACTS_CAPABILITY_SUPERVISOR_IOC (0x00000000) +#define MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_IOC (0x80000000) +#define MPI3_IOCFACTS_CAPABILITY_INT_COALESCE_MASK (0x00000600) +#define MPI3_IOCFACTS_CAPABILITY_INT_COALESCE_FIXED_THRESHOLD (0x00000000) +#define MPI3_IOCFACTS_CAPABILITY_INT_COALESCE_OUTSTANDING_IO (0x00000200) +#define MPI3_IOCFACTS_CAPABILITY_COMPLETE_RESET_CAPABLE (0x00000100) +#define MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_TRACE_ENABLED (0x00000080) +#define MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_FW_ENABLED (0x00000040) +#define MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_DRIVER_ENABLED (0x00000020) +#define MPI3_IOCFACTS_CAPABILITY_ADVANCED_HOST_PD_ENABLED (0x00000010) +#define MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE (0x00000008) +#define MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED (0x00000002) +#define MPI3_IOCFACTS_CAPABILITY_COALESCE_CTRL_SUPPORTED (0x00000001) + +/**** WhoInit values are defined under IOCInit Request Message definition ****/ + +/**** Defines for the ProductID field ****/ +#define MPI3_IOCFACTS_PID_TYPE_MASK (0xF000) +#define MPI3_IOCFACTS_PID_TYPE_SHIFT (12) +#define MPI3_IOCFACTS_PID_PRODUCT_MASK (0x0F00) +#define MPI3_IOCFACTS_PID_PRODUCT_SHIFT (8) +#define MPI3_IOCFACTS_PID_FAMILY_MASK (0x00FF) +#define MPI3_IOCFACTS_PID_FAMILY_SHIFT (0) + +/**** Defines for the IOCExceptions field ****/ +#define MPI3_IOCFACTS_EXCEPT_SECURITY_REKEY (0x2000) +#define MPI3_IOCFACTS_EXCEPT_SAS_DISABLED (0x1000) +#define MPI3_IOCFACTS_EXCEPT_SAFE_MODE (0x0800) +#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_MASK (0x0700) +#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_NONE (0x0000) +#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_LOCAL_VIA_MGMT (0x0100) +#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_EXT_VIA_MGMT (0x0200) +#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_DRIVE_EXT_VIA_MGMT (0x0300) +#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_LOCAL_VIA_OOB (0x0400) +#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_EXT_VIA_OOB (0x0500) +#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_DRIVE_EXT_VIA_OOB (0x0600) +#define MPI3_IOCFACTS_EXCEPT_PCIE_DISABLED (0x0080) +#define MPI3_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE (0x0040) +#define MPI3_IOCFACTS_EXCEPT_MANUFACT_CHECKSUM_FAIL (0x0020) +#define MPI3_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0010) +#define MPI3_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (0x0008) +#define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_MASK (0x0001) +#define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_PRIMARY (0x0000) +#define MPI3_IOCFACTS_EXCEPT_BOOTSTAT_SECONDARY (0x0001) + +/**** Defines for the ProtocolFlags field ****/ +#define MPI3_IOCFACTS_PROTOCOL_SAS (0x0010) +#define MPI3_IOCFACTS_PROTOCOL_SATA (0x0008) +#define MPI3_IOCFACTS_PROTOCOL_NVME (0x0004) +#define MPI3_IOCFACTS_PROTOCOL_SCSI_INITIATOR (0x0002) +#define MPI3_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001) + +/**** Defines for the MaxDataLength field ****/ +#define MPI3_IOCFACTS_MAX_DATA_LENGTH_NOT_REPORTED (0x0000) + +/**** Defines for the Flags field ****/ +#define MPI3_IOCFACTS_FLAGS_SIGNED_NVDATA_REQUIRED (0x00010000) +#define MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK (0x0000FF00) +#define MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT (8) +#define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK (0x00000030) +#define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_NOT_STARTED (0x00000000) +#define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_IN_PROGRESS (0x00000010) +#define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_COMPLETE (0x00000020) +#define MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK (0x0000000F) +#define MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA (0x00000000) +#define MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR (0x00000002) + +/**** Defines for the IOThrottleDataLength field ****/ +#define MPI3_IOCFACTS_IO_THROTTLE_DATA_LENGTH_NOT_REQUIRED (0x0000) + +/**** Defines for the IOThrottleDataLength field ****/ +#define MPI3_IOCFACTS_MAX_IO_THROTTLE_GROUP_NOT_REQUIRED (0x0000) + +/***************************************************************************** + * Management Passthrough Request Message * + ****************************************************************************/ +typedef struct _MPI3_MGMT_PASSTHROUGH_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U32 Reserved0C[5]; /* 0x0C */ + MPI3_SGE_UNION CommandSGL; /* 0x20 */ + MPI3_SGE_UNION ResponseSGL; /* 0x30 */ +} MPI3_MGMT_PASSTHROUGH_REQUEST, MPI3_POINTER PTR_MPI3_MGMT_PASSTHROUGH_REQUEST, + Mpi3MgmtPassthroughRequest_t, MPI3_POINTER pMpi3MgmtPassthroughRequest_t; + +/***************************************************************************** + * CreateRequestQueue Request Message * + ****************************************************************************/ +typedef struct _MPI3_CREATE_REQUEST_QUEUE_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Flags; /* 0x0A */ + U8 Burst; /* 0x0B */ + U16 Size; /* 0x0C */ + U16 QueueID; /* 0x0E */ + U16 ReplyQueueID; /* 0x10 */ + U16 Reserved12; /* 0x12 */ + U32 Reserved14; /* 0x14 */ + U64 BaseAddress; /* 0x18 */ +} MPI3_CREATE_REQUEST_QUEUE_REQUEST, MPI3_POINTER PTR_MPI3_CREATE_REQUEST_QUEUE_REQUEST, + Mpi3CreateRequestQueueRequest_t, MPI3_POINTER pMpi3CreateRequestQueueRequest_t; + +/**** Defines for the Flags field ****/ +#define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_MASK (0x80) +#define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED (0x80) +#define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_CONTIGUOUS (0x00) + +/**** Defines for the Size field ****/ +#define MPI3_CREATE_REQUEST_QUEUE_SIZE_MINIMUM (2) + +/***************************************************************************** + * DeleteRequestQueue Request Message * + ****************************************************************************/ +typedef struct _MPI3_DELETE_REQUEST_QUEUE_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 QueueID; /* 0x0A */ +} MPI3_DELETE_REQUEST_QUEUE_REQUEST, MPI3_POINTER PTR_MPI3_DELETE_REQUEST_QUEUE_REQUEST, + Mpi3DeleteRequestQueueRequest_t, MPI3_POINTER pMpi3DeleteRequestQueueRequest_t; + + +/***************************************************************************** + * CreateReplyQueue Request Message * + ****************************************************************************/ +typedef struct _MPI3_CREATE_REPLY_QUEUE_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Flags; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U16 Size; /* 0x0C */ + U16 QueueID; /* 0x0E */ + U16 MSIxIndex; /* 0x10 */ + U16 Reserved12; /* 0x12 */ + U32 Reserved14; /* 0x14 */ + U64 BaseAddress; /* 0x18 */ +} MPI3_CREATE_REPLY_QUEUE_REQUEST, MPI3_POINTER PTR_MPI3_CREATE_REPLY_QUEUE_REQUEST, + Mpi3CreateReplyQueueRequest_t, MPI3_POINTER pMpi3CreateReplyQueueRequest_t; + +/**** Defines for the Flags field ****/ +#define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_MASK (0x80) +#define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_SEGMENTED (0x80) +#define MPI3_CREATE_REPLY_QUEUE_FLAGS_SEGMENTED_CONTIGUOUS (0x00) +#define MPI3_CREATE_REPLY_QUEUE_FLAGS_COALESCE_DISABLE (0x02) +#define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_MASK (0x01) +#define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_DISABLE (0x00) +#define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE (0x01) + +/**** Defines for the Size field ****/ +#define MPI3_CREATE_REPLY_QUEUE_SIZE_MINIMUM (2) + +/***************************************************************************** + * DeleteReplyQueue Request Message * + ****************************************************************************/ +typedef struct _MPI3_DELETE_REPLY_QUEUE_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 QueueID; /* 0x0A */ +} MPI3_DELETE_REPLY_QUEUE_REQUEST, MPI3_POINTER PTR_MPI3_DELETE_REPLY_QUEUE_REQUEST, + Mpi3DeleteReplyQueueRequest_t, MPI3_POINTER pMpi3DeleteReplyQueueRequest_t; + + +/***************************************************************************** + * PortEnable Request Message * + ****************************************************************************/ +typedef struct _MPI3_PORT_ENABLE_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ +} MPI3_PORT_ENABLE_REQUEST, MPI3_POINTER PTR_MPI3_PORT_ENABLE_REQUEST, + Mpi3PortEnableRequest_t, MPI3_POINTER pMpi3PortEnableRequest_t; + + +/***************************************************************************** + * IOC Events and Event Management * + ****************************************************************************/ +#define MPI3_EVENT_LOG_DATA (0x01) +#define MPI3_EVENT_CHANGE (0x02) +#define MPI3_EVENT_GPIO_INTERRUPT (0x04) +#define MPI3_EVENT_CABLE_MGMT (0x06) +#define MPI3_EVENT_DEVICE_ADDED (0x07) +#define MPI3_EVENT_DEVICE_INFO_CHANGED (0x08) +#define MPI3_EVENT_PREPARE_FOR_RESET (0x09) +#define MPI3_EVENT_COMP_IMAGE_ACT_START (0x0A) +#define MPI3_EVENT_ENCL_DEVICE_ADDED (0x0B) +#define MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE (0x0C) +#define MPI3_EVENT_DEVICE_STATUS_CHANGE (0x0D) +#define MPI3_EVENT_ENERGY_PACK_CHANGE (0x0E) +#define MPI3_EVENT_SAS_DISCOVERY (0x11) +#define MPI3_EVENT_SAS_BROADCAST_PRIMITIVE (0x12) +#define MPI3_EVENT_SAS_NOTIFY_PRIMITIVE (0x13) +#define MPI3_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x14) +#define MPI3_EVENT_SAS_INIT_TABLE_OVERFLOW (0x15) +#define MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST (0x16) +#define MPI3_EVENT_SAS_PHY_COUNTER (0x18) +#define MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR (0x19) +#define MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST (0x20) +#define MPI3_EVENT_PCIE_ENUMERATION (0x22) +#define MPI3_EVENT_PCIE_ERROR_THRESHOLD (0x23) +#define MPI3_EVENT_HARD_RESET_RECEIVED (0x40) +#define MPI3_EVENT_DIAGNOSTIC_BUFFER_STATUS_CHANGE (0x50) +#define MPI3_EVENT_MIN_PRODUCT_SPECIFIC (0x60) +#define MPI3_EVENT_MAX_PRODUCT_SPECIFIC (0x7F) + + +/***************************************************************************** + * Event Notification Request Message * + ****************************************************************************/ +#define MPI3_EVENT_NOTIFY_EVENTMASK_WORDS (4) + +typedef struct _MPI3_EVENT_NOTIFICATION_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U16 SASBroadcastPrimitiveMasks; /* 0x0C */ + U16 SASNotifyPrimitiveMasks; /* 0x0E */ + U32 EventMasks[MPI3_EVENT_NOTIFY_EVENTMASK_WORDS]; /* 0x10 */ +} MPI3_EVENT_NOTIFICATION_REQUEST, MPI3_POINTER PTR_MPI3_EVENT_NOTIFICATION_REQUEST, + Mpi3EventNotificationRequest_t, MPI3_POINTER pMpi3EventNotificationRequest_t; + +/**** Defines for the SASBroadcastPrimitiveMasks field - use MPI3_EVENT_PRIMITIVE_ values ****/ + +/**** Defines for the SASNotifyPrimitiveMasks field - use MPI3_EVENT_NOTIFY_ values ****/ + +/**** Defines for the EventMasks field - use MPI3_EVENT_ values ****/ + +/***************************************************************************** + * Event Notification Reply Message * + ****************************************************************************/ +typedef struct _MPI3_EVENT_NOTIFICATION_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ + U8 EventDataLength; /* 0x10 */ + U8 Event; /* 0x11 */ + U16 IOCChangeCount; /* 0x12 */ + U32 EventContext; /* 0x14 */ + U32 EventData[1]; /* 0x18 */ +} MPI3_EVENT_NOTIFICATION_REPLY, MPI3_POINTER PTR_MPI3_EVENT_NOTIFICATION_REPLY, + Mpi3EventNotificationReply_t, MPI3_POINTER pMpi3EventNotificationReply_t; + +/**** Defines for the MsgFlags field ****/ +#define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK (0x01) +#define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED (0x01) +#define MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_NOT_REQUIRED (0x00) +#define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_MASK (0x02) +#define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_ORIGINAL (0x00) +#define MPI3_EVENT_NOTIFY_MSGFLAGS_EVENT_ORIGINALITY_REPLAY (0x02) + +/**** Defines for the Event field - use MPI3_EVENT_ values ****/ + + +/***************************************************************************** + * GPIO Interrupt Event * + ****************************************************************************/ +typedef struct _MPI3_EVENT_DATA_GPIO_INTERRUPT +{ + U8 GPIONum; /* 0x00 */ + U8 Reserved01[3]; /* 0x01 */ +} MPI3_EVENT_DATA_GPIO_INTERRUPT, MPI3_POINTER PTR_MPI3_EVENT_DATA_GPIO_INTERRUPT, + Mpi3EventDataGpioInterrupt_t, MPI3_POINTER pMpi3EventDataGpioInterrupt_t; + + +/***************************************************************************** + * Cable Management Event * + ****************************************************************************/ +typedef struct _MPI3_EVENT_DATA_CABLE_MANAGEMENT +{ + U32 ActiveCablePowerRequirement; /* 0x00 */ + U8 Status; /* 0x04 */ + U8 ReceptacleID; /* 0x05 */ + U16 Reserved06; /* 0x06 */ +} MPI3_EVENT_DATA_CABLE_MANAGEMENT, MPI3_POINTER PTR_MPI3_EVENT_DATA_CABLE_MANAGEMENT, + Mpi3EventDataCableManagement_t, MPI3_POINTER pMpi3EventDataCableManagement_t; + +/**** Defines for the ActiveCablePowerRequirement field ****/ +#define MPI3_EVENT_CABLE_MGMT_ACT_CABLE_PWR_INVALID (0xFFFFFFFF) + +/**** Defines for the Status field ****/ +#define MPI3_EVENT_CABLE_MGMT_STATUS_INSUFFICIENT_POWER (0x00) +#define MPI3_EVENT_CABLE_MGMT_STATUS_PRESENT (0x01) +#define MPI3_EVENT_CABLE_MGMT_STATUS_DEGRADED (0x02) + + +/***************************************************************************** + * Event Ack Request Message * + ****************************************************************************/ +typedef struct _MPI3_EVENT_ACK_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U8 Event; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + U32 EventContext; /* 0x10 */ +} MPI3_EVENT_ACK_REQUEST, MPI3_POINTER PTR_MPI3_EVENT_ACK_REQUEST, + Mpi3EventAckRequest_t, MPI3_POINTER pMpi3EventAckRequest_t; + +/**** Defines for the Event field - use MPI3_EVENT_ values ****/ + + +/***************************************************************************** + * Prepare for Reset Event * + ****************************************************************************/ +typedef struct _MPI3_EVENT_DATA_PREPARE_FOR_RESET +{ + U8 ReasonCode; /* 0x00 */ + U8 Reserved01; /* 0x01 */ + U16 Reserved02; /* 0x02 */ +} MPI3_EVENT_DATA_PREPARE_FOR_RESET, MPI3_POINTER PTR_MPI3_EVENT_DATA_PREPARE_FOR_RESET, + Mpi3EventDataPrepareForReset_t, MPI3_POINTER pMpi3EventDataPrepareForReset_t; + +/**** Defines for the ReasonCode field ****/ +#define MPI3_EVENT_PREPARE_RESET_RC_START (0x01) +#define MPI3_EVENT_PREPARE_RESET_RC_ABORT (0x02) + + +/***************************************************************************** + * Component Image Activation Start Event * + ****************************************************************************/ +typedef struct _MPI3_EVENT_DATA_COMP_IMAGE_ACTIVATION +{ + U32 Reserved00; /* 0x00 */ +} MPI3_EVENT_DATA_COMP_IMAGE_ACTIVATION, MPI3_POINTER PTR_MPI3_EVENT_DATA_COMP_IMAGE_ACTIVATION, + Mpi3EventDataCompImageActivation_t, MPI3_POINTER pMpi3EventDataCompImageActivation_t; + +/***************************************************************************** + * Device Added Event * + ****************************************************************************/ +/* + * The Device Added Event Data is exactly the same as Device Page 0 data + * (including the Configuration Page header). So, please use/refer to + * MPI3_DEVICE_PAGE0 structure for Device Added Event data. + */ + +/**************************************************************************** + * Device Info Changed Event * + ****************************************************************************/ +/* + * The Device Info Changed Event Data is exactly the same as Device Page 0 data + * (including the Configuration Page header). So, please use/refer to + * MPI3_DEVICE_PAGE0 structure for Device Added Event data. + */ + +/***************************************************************************** + * Device Status Change Event * + ****************************************************************************/ +typedef struct _MPI3_EVENT_DATA_DEVICE_STATUS_CHANGE +{ + U16 TaskTag; /* 0x00 */ + U8 ReasonCode; /* 0x02 */ + U8 IOUnitPort; /* 0x03 */ + U16 ParentDevHandle; /* 0x04 */ + U16 DevHandle; /* 0x06 */ + U64 WWID; /* 0x08 */ + U8 LUN[8]; /* 0x10 */ +} MPI3_EVENT_DATA_DEVICE_STATUS_CHANGE, MPI3_POINTER PTR_MPI3_EVENT_DATA_DEVICE_STATUS_CHANGE, + Mpi3EventDataDeviceStatusChange_t, MPI3_POINTER pMpi3EventDataDeviceStatusChange_t; + +/**** Defines for the ReasonCode field ****/ +#define MPI3_EVENT_DEV_STAT_RC_MOVED (0x01) +#define MPI3_EVENT_DEV_STAT_RC_HIDDEN (0x02) +#define MPI3_EVENT_DEV_STAT_RC_NOT_HIDDEN (0x03) +#define MPI3_EVENT_DEV_STAT_RC_ASYNC_NOTIFICATION (0x04) +#define MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_STRT (0x20) +#define MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_CMP (0x21) +#define MPI3_EVENT_DEV_STAT_RC_INT_TASK_ABORT_STRT (0x22) +#define MPI3_EVENT_DEV_STAT_RC_INT_TASK_ABORT_CMP (0x23) +#define MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_STRT (0x24) +#define MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_CMP (0x25) +#define MPI3_EVENT_DEV_STAT_RC_PCIE_HOT_RESET_FAILED (0x30) +#define MPI3_EVENT_DEV_STAT_RC_EXPANDER_REDUCED_FUNC_STRT (0x40) +#define MPI3_EVENT_DEV_STAT_RC_EXPANDER_REDUCED_FUNC_CMP (0x41) +#define MPI3_EVENT_DEV_STAT_RC_VD_NOT_RESPONDING (0x50) + +/***************************************************************************** + * Energy Pack Change Event * + ****************************************************************************/ +typedef struct _MPI3_EVENT_DATA_ENERGY_PACK_CHANGE +{ + U32 Reserved00; /* 0x00 */ + U16 ShutdownTimeout; /* 0x04 */ + U16 Reserved06; /* 0x06 */ +} MPI3_EVENT_DATA_ENERGY_PACK_CHANGE, MPI3_POINTER PTR_MPI3_EVENT_DATA_ENERGY_PACK_CHANGE, + Mpi3EventDataEnergyPackChange_t, MPI3_POINTER pMpi3EventDataEnergyPackChange_t; + +/***************************************************************************** + * SAS Discovery Event * + ****************************************************************************/ +typedef struct _MPI3_EVENT_DATA_SAS_DISCOVERY +{ + U8 Flags; /* 0x00 */ + U8 ReasonCode; /* 0x01 */ + U8 IOUnitPort; /* 0x02 */ + U8 Reserved03; /* 0x03 */ + U32 DiscoveryStatus; /* 0x04 */ +} MPI3_EVENT_DATA_SAS_DISCOVERY, MPI3_POINTER PTR_MPI3_EVENT_DATA_SAS_DISCOVERY, + Mpi3EventDataSasDiscovery_t, MPI3_POINTER pMpi3EventDataSasDiscovery_t; + +/**** Defines for the Flags field ****/ +#define MPI3_EVENT_SAS_DISC_FLAGS_DEVICE_CHANGE (0x02) +#define MPI3_EVENT_SAS_DISC_FLAGS_IN_PROGRESS (0x01) + +/**** Defines for the ReasonCode field ****/ +#define MPI3_EVENT_SAS_DISC_RC_STARTED (0x01) +#define MPI3_EVENT_SAS_DISC_RC_COMPLETED (0x02) + +/**** Defines for the DiscoveryStatus field ****/ +#define MPI3_SAS_DISC_STATUS_MAX_ENCLOSURES_EXCEED (0x80000000) +#define MPI3_SAS_DISC_STATUS_MAX_EXPANDERS_EXCEED (0x40000000) +#define MPI3_SAS_DISC_STATUS_MAX_DEVICES_EXCEED (0x20000000) +#define MPI3_SAS_DISC_STATUS_MAX_TOPO_PHYS_EXCEED (0x10000000) +#define MPI3_SAS_DISC_STATUS_INVALID_CEI (0x00010000) +#define MPI3_SAS_DISC_STATUS_FECEI_MISMATCH (0x00008000) +#define MPI3_SAS_DISC_STATUS_MULTIPLE_DEVICES_IN_SLOT (0x00004000) +#define MPI3_SAS_DISC_STATUS_NECEI_MISMATCH (0x00002000) +#define MPI3_SAS_DISC_STATUS_TOO_MANY_SLOTS (0x00001000) +#define MPI3_SAS_DISC_STATUS_EXP_MULTI_SUBTRACTIVE (0x00000800) +#define MPI3_SAS_DISC_STATUS_MULTI_PORT_DOMAIN (0x00000400) +#define MPI3_SAS_DISC_STATUS_TABLE_TO_SUBTRACTIVE_LINK (0x00000200) +#define MPI3_SAS_DISC_STATUS_UNSUPPORTED_DEVICE (0x00000100) +#define MPI3_SAS_DISC_STATUS_TABLE_LINK (0x00000080) +#define MPI3_SAS_DISC_STATUS_SUBTRACTIVE_LINK (0x00000040) +#define MPI3_SAS_DISC_STATUS_SMP_CRC_ERROR (0x00000020) +#define MPI3_SAS_DISC_STATUS_SMP_FUNCTION_FAILED (0x00000010) +#define MPI3_SAS_DISC_STATUS_SMP_TIMEOUT (0x00000008) +#define MPI3_SAS_DISC_STATUS_MULTIPLE_PORTS (0x00000004) +#define MPI3_SAS_DISC_STATUS_INVALID_SAS_ADDRESS (0x00000002) +#define MPI3_SAS_DISC_STATUS_LOOP_DETECTED (0x00000001) + + +/***************************************************************************** + * SAS Broadcast Primitive Event * + ****************************************************************************/ +typedef struct _MPI3_EVENT_DATA_SAS_BROADCAST_PRIMITIVE +{ + U8 PhyNum; /* 0x00 */ + U8 IOUnitPort; /* 0x01 */ + U8 PortWidth; /* 0x02 */ + U8 Primitive; /* 0x03 */ +} MPI3_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, MPI3_POINTER PTR_MPI3_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, + Mpi3EventDataSasBroadcastPrimitive_t, MPI3_POINTER pMpi3EventDataSasBroadcastPrimitive_t; + +/**** Defines for the Primitive field ****/ +#define MPI3_EVENT_BROADCAST_PRIMITIVE_CHANGE (0x01) +#define MPI3_EVENT_BROADCAST_PRIMITIVE_SES (0x02) +#define MPI3_EVENT_BROADCAST_PRIMITIVE_EXPANDER (0x03) +#define MPI3_EVENT_BROADCAST_PRIMITIVE_ASYNCHRONOUS_EVENT (0x04) +#define MPI3_EVENT_BROADCAST_PRIMITIVE_RESERVED3 (0x05) +#define MPI3_EVENT_BROADCAST_PRIMITIVE_RESERVED4 (0x06) +#define MPI3_EVENT_BROADCAST_PRIMITIVE_CHANGE0_RESERVED (0x07) +#define MPI3_EVENT_BROADCAST_PRIMITIVE_CHANGE1_RESERVED (0x08) + + +/***************************************************************************** + * SAS Notify Primitive Event * + ****************************************************************************/ +typedef struct _MPI3_EVENT_DATA_SAS_NOTIFY_PRIMITIVE +{ + U8 PhyNum; /* 0x00 */ + U8 IOUnitPort; /* 0x01 */ + U8 Reserved02; /* 0x02 */ + U8 Primitive; /* 0x03 */ +} MPI3_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, MPI3_POINTER PTR_MPI3_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, + Mpi3EventDataSasNotifyPrimitive_t, MPI3_POINTER pMpi3EventDataSasNotifyPrimitive_t; + +/**** Defines for the Primitive field ****/ +#define MPI3_EVENT_NOTIFY_PRIMITIVE_ENABLE_SPINUP (0x01) +#define MPI3_EVENT_NOTIFY_PRIMITIVE_POWER_LOSS_EXPECTED (0x02) +#define MPI3_EVENT_NOTIFY_PRIMITIVE_RESERVED1 (0x03) +#define MPI3_EVENT_NOTIFY_PRIMITIVE_RESERVED2 (0x04) + + +/***************************************************************************** + * SAS Topology Change List Event * + ****************************************************************************/ +#ifndef MPI3_EVENT_SAS_TOPO_PHY_COUNT +#define MPI3_EVENT_SAS_TOPO_PHY_COUNT (1) +#endif /* MPI3_EVENT_SAS_TOPO_PHY_COUNT */ + +typedef struct _MPI3_EVENT_SAS_TOPO_PHY_ENTRY +{ + U16 AttachedDevHandle; /* 0x00 */ + U8 LinkRate; /* 0x02 */ + U8 Status; /* 0x03 */ +} MPI3_EVENT_SAS_TOPO_PHY_ENTRY, MPI3_POINTER PTR_MPI3_EVENT_SAS_TOPO_PHY_ENTRY, + Mpi3EventSasTopoPhyEntry_t, MPI3_POINTER pMpi3EventSasTopoPhyEntry_t; + +/**** Defines for the LinkRate field ****/ +#define MPI3_EVENT_SAS_TOPO_LR_CURRENT_MASK (0xF0) +#define MPI3_EVENT_SAS_TOPO_LR_CURRENT_SHIFT (4) +#define MPI3_EVENT_SAS_TOPO_LR_PREV_MASK (0x0F) +#define MPI3_EVENT_SAS_TOPO_LR_PREV_SHIFT (0) +#define MPI3_EVENT_SAS_TOPO_LR_UNKNOWN_LINK_RATE (0x00) +#define MPI3_EVENT_SAS_TOPO_LR_PHY_DISABLED (0x01) +#define MPI3_EVENT_SAS_TOPO_LR_NEGOTIATION_FAILED (0x02) +#define MPI3_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE (0x03) +#define MPI3_EVENT_SAS_TOPO_LR_PORT_SELECTOR (0x04) +#define MPI3_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS (0x05) +#define MPI3_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY (0x06) +#define MPI3_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A) +#define MPI3_EVENT_SAS_TOPO_LR_RATE_12_0 (0x0B) +#define MPI3_EVENT_SAS_TOPO_LR_RATE_22_5 (0x0C) + +/**** Defines for the PhyStatus field ****/ +#define MPI3_EVENT_SAS_TOPO_PHY_STATUS_MASK (0xC0) +#define MPI3_EVENT_SAS_TOPO_PHY_STATUS_SHIFT (6) +#define MPI3_EVENT_SAS_TOPO_PHY_STATUS_ACCESSIBLE (0x00) +#define MPI3_EVENT_SAS_TOPO_PHY_STATUS_NO_EXIST (0x40) +#define MPI3_EVENT_SAS_TOPO_PHY_STATUS_VACANT (0x80) +#define MPI3_EVENT_SAS_TOPO_PHY_RC_MASK (0x0F) +#define MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING (0x02) +#define MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED (0x03) +#define MPI3_EVENT_SAS_TOPO_PHY_RC_NO_CHANGE (0x04) +#define MPI3_EVENT_SAS_TOPO_PHY_RC_DELAY_NOT_RESPONDING (0x05) +#define MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING (0x06) + + +typedef struct _MPI3_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST +{ + U16 EnclosureHandle; /* 0x00 */ + U16 ExpanderDevHandle; /* 0x02 */ + U8 NumPhys; /* 0x04 */ + U8 Reserved05[3]; /* 0x05 */ + U8 NumEntries; /* 0x08 */ + U8 StartPhyNum; /* 0x09 */ + U8 ExpStatus; /* 0x0A */ + U8 IOUnitPort; /* 0x0B */ + MPI3_EVENT_SAS_TOPO_PHY_ENTRY PhyEntry[MPI3_EVENT_SAS_TOPO_PHY_COUNT]; /* 0x0C */ +} MPI3_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, MPI3_POINTER PTR_MPI3_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, + Mpi3EventDataSasTopologyChangeList_t, MPI3_POINTER pMpi3EventDataSasTopologyChangeList_t; + +/**** Defines for the ExpStatus field ****/ +#define MPI3_EVENT_SAS_TOPO_ES_NO_EXPANDER (0x00) +#define MPI3_EVENT_SAS_TOPO_ES_NOT_RESPONDING (0x02) +#define MPI3_EVENT_SAS_TOPO_ES_RESPONDING (0x03) +#define MPI3_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING (0x04) + +/***************************************************************************** + * SAS PHY Counter Event * + ****************************************************************************/ +typedef struct _MPI3_EVENT_DATA_SAS_PHY_COUNTER +{ + U64 TimeStamp; /* 0x00 */ + U32 Reserved08; /* 0x08 */ + U8 PhyEventCode; /* 0x0C */ + U8 PhyNum; /* 0x0D */ + U16 Reserved0E; /* 0x0E */ + U32 PhyEventInfo; /* 0x10 */ + U8 CounterType; /* 0x14 */ + U8 ThresholdWindow; /* 0x15 */ + U8 TimeUnits; /* 0x16 */ + U8 Reserved17; /* 0x17 */ + U32 EventThreshold; /* 0x18 */ + U16 ThresholdFlags; /* 0x1C */ + U16 Reserved1E; /* 0x1E */ +} MPI3_EVENT_DATA_SAS_PHY_COUNTER, MPI3_POINTER PTR_MPI3_EVENT_DATA_SAS_PHY_COUNTER, + Mpi3EventDataSasPhyCounter_t, MPI3_POINTER pMpi3EventDataSasPhyCounter_t; + +/**** Defines for the PhyEventCode field - use MPI3_SASPHY3_EVENT_CODE_ defines ****/ + +/**** Defines for the CounterType field - use MPI3_SASPHY3_COUNTER_TYPE_ defines ****/ + +/**** Defines for the TimeUnits field - use MPI3_SASPHY3_TIME_UNITS_ defines ****/ + +/**** Defines for the ThresholdFlags field - use MPI3_SASPHY3_TFLAGS_ defines ****/ + + +/***************************************************************************** + * SAS Device Discovery Error Event * + ****************************************************************************/ +typedef struct _MPI3_EVENT_DATA_SAS_DEVICE_DISC_ERR +{ + U16 DevHandle; /* 0x00 */ + U8 ReasonCode; /* 0x02 */ + U8 IOUnitPort; /* 0x03 */ + U32 Reserved04; /* 0x04 */ + U64 SASAddress; /* 0x08 */ +} MPI3_EVENT_DATA_SAS_DEVICE_DISC_ERR, MPI3_POINTER PTR_MPI3_EVENT_DATA_SAS_DEVICE_DISC_ERR, + Mpi3EventDataSasDeviceDiscErr_t, MPI3_POINTER pMpi3EventDataSasDeviceDiscErr_t; + +/**** Defines for the ReasonCode field ****/ +#define MPI3_EVENT_SAS_DISC_ERR_RC_SMP_FAILED (0x01) +#define MPI3_EVENT_SAS_DISC_ERR_RC_SMP_TIMEOUT (0x02) + +/***************************************************************************** + * PCIe Enumeration Event * + ****************************************************************************/ +typedef struct _MPI3_EVENT_DATA_PCIE_ENUMERATION +{ + U8 Flags; /* 0x00 */ + U8 ReasonCode; /* 0x01 */ + U8 IOUnitPort; /* 0x02 */ + U8 Reserved03; /* 0x03 */ + U32 EnumerationStatus; /* 0x04 */ +} MPI3_EVENT_DATA_PCIE_ENUMERATION, MPI3_POINTER PTR_MPI3_EVENT_DATA_PCIE_ENUMERATION, + Mpi3EventDataPcieEnumeration_t, MPI3_POINTER pMpi3EventDataPcieEnumeration_t; + +/**** Defines for the Flags field ****/ +#define MPI3_EVENT_PCIE_ENUM_FLAGS_DEVICE_CHANGE (0x02) +#define MPI3_EVENT_PCIE_ENUM_FLAGS_IN_PROGRESS (0x01) + +/**** Defines for the ReasonCode field ****/ +#define MPI3_EVENT_PCIE_ENUM_RC_STARTED (0x01) +#define MPI3_EVENT_PCIE_ENUM_RC_COMPLETED (0x02) + +/**** Defines for the EnumerationStatus field ****/ +#define MPI3_EVENT_PCIE_ENUM_ES_MAX_SWITCH_DEPTH_EXCEED (0x80000000) +#define MPI3_EVENT_PCIE_ENUM_ES_MAX_SWITCHES_EXCEED (0x40000000) +#define MPI3_EVENT_PCIE_ENUM_ES_MAX_DEVICES_EXCEED (0x20000000) +#define MPI3_EVENT_PCIE_ENUM_ES_RESOURCES_EXHAUSTED (0x10000000) + + +/***************************************************************************** + * PCIe Topology Change List Event * + ****************************************************************************/ +#ifndef MPI3_EVENT_PCIE_TOPO_PORT_COUNT +#define MPI3_EVENT_PCIE_TOPO_PORT_COUNT (1) +#endif /* MPI3_EVENT_PCIE_TOPO_PORT_COUNT */ + +typedef struct _MPI3_EVENT_PCIE_TOPO_PORT_ENTRY +{ + U16 AttachedDevHandle; /* 0x00 */ + U8 PortStatus; /* 0x02 */ + U8 Reserved03; /* 0x03 */ + U8 CurrentPortInfo; /* 0x04 */ + U8 Reserved05; /* 0x05 */ + U8 PreviousPortInfo; /* 0x06 */ + U8 Reserved07; /* 0x07 */ +} MPI3_EVENT_PCIE_TOPO_PORT_ENTRY, MPI3_POINTER PTR_MPI3_EVENT_PCIE_TOPO_PORT_ENTRY, + Mpi3EventPcieTopoPortEntry_t, MPI3_POINTER pMpi3EventPcieTopoPortEntry_t; + +/**** Defines for the PortStatus field ****/ +#define MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING (0x02) +#define MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED (0x03) +#define MPI3_EVENT_PCIE_TOPO_PS_NO_CHANGE (0x04) +#define MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING (0x05) +#define MPI3_EVENT_PCIE_TOPO_PS_RESPONDING (0x06) + +/**** Defines for the CurrentPortInfo and PreviousPortInfo field ****/ +#define MPI3_EVENT_PCIE_TOPO_PI_LANES_MASK (0xF0) +#define MPI3_EVENT_PCIE_TOPO_PI_LANES_UNKNOWN (0x00) +#define MPI3_EVENT_PCIE_TOPO_PI_LANES_1 (0x10) +#define MPI3_EVENT_PCIE_TOPO_PI_LANES_2 (0x20) +#define MPI3_EVENT_PCIE_TOPO_PI_LANES_4 (0x30) +#define MPI3_EVENT_PCIE_TOPO_PI_LANES_8 (0x40) +#define MPI3_EVENT_PCIE_TOPO_PI_LANES_16 (0x50) + +#define MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK (0x0F) +#define MPI3_EVENT_PCIE_TOPO_PI_RATE_UNKNOWN (0x00) +#define MPI3_EVENT_PCIE_TOPO_PI_RATE_DISABLED (0x01) +#define MPI3_EVENT_PCIE_TOPO_PI_RATE_2_5 (0x02) +#define MPI3_EVENT_PCIE_TOPO_PI_RATE_5_0 (0x03) +#define MPI3_EVENT_PCIE_TOPO_PI_RATE_8_0 (0x04) +#define MPI3_EVENT_PCIE_TOPO_PI_RATE_16_0 (0x05) +#define MPI3_EVENT_PCIE_TOPO_PI_RATE_32_0 (0x06) + +typedef struct _MPI3_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST +{ + U16 EnclosureHandle; /* 0x00 */ + U16 SwitchDevHandle; /* 0x02 */ + U8 NumPorts; /* 0x04 */ + U8 Reserved05[3]; /* 0x05 */ + U8 NumEntries; /* 0x08 */ + U8 StartPortNum; /* 0x09 */ + U8 SwitchStatus; /* 0x0A */ + U8 IOUnitPort; /* 0x0B */ + U32 Reserved0C; /* 0x0C */ + MPI3_EVENT_PCIE_TOPO_PORT_ENTRY PortEntry[MPI3_EVENT_PCIE_TOPO_PORT_COUNT]; /* 0x10 */ +} MPI3_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST, MPI3_POINTER PTR_MPI3_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST, + Mpi3EventDataPcieTopologyChangeList_t, MPI3_POINTER pMpi3EventDataPcieTopologyChangeList_t; + +/**** Defines for the SwitchStatus field ****/ +#define MPI3_EVENT_PCIE_TOPO_SS_NO_PCIE_SWITCH (0x00) +#define MPI3_EVENT_PCIE_TOPO_SS_NOT_RESPONDING (0x02) +#define MPI3_EVENT_PCIE_TOPO_SS_RESPONDING (0x03) +#define MPI3_EVENT_PCIE_TOPO_SS_DELAY_NOT_RESPONDING (0x04) + +/***************************************************************************** + * PCIe Error Threshold Event * + ****************************************************************************/ + +typedef struct _MPI3_EVENT_DATA_PCIE_ERROR_THRESHOLD +{ + U64 Timestamp; /* 0x00 */ + U8 ReasonCode; /* 0x08 */ + U8 Port; /* 0x09 */ + U16 SwitchDevHandle; /* 0x0A */ + U8 Error; /* 0x0C */ + U8 Action; /* 0x0D */ + U16 ThresholdCount; /* 0x0E */ + U16 AttachedDevHandle; /* 0x10 */ + U16 Reserved12; /* 0x12 */ + U32 Reserved14; /* 0x14 */ +} MPI3_EVENT_DATA_PCIE_ERROR_THRESHOLD, MPI3_POINTER PTR_MPI3_EVENT_DATA_PCIE_ERROR_THRESHOLD, + Mpi3EventDataPcieErrorThreshold_t, MPI3_POINTER pMpi3EventDataPcieErrorThreshold_t; + + +/**** Defines for the ReasonCode field ****/ +#define MPI3_EVENT_PCI_ERROR_RC_THRESHOLD_EXCEEDED (0x00) +#define MPI3_EVENT_PCI_ERROR_RC_ESCALATION (0x01) + +/**** Defines for the Error field - use MPI3_PCIEIOUNIT3_ERROR_ values ****/ + +/**** Defines for the Action field - use MPI3_PCIEIOUNIT3_ACTION_ values ****/ + +/**************************************************************************** + * Enclosure Device Added Event * + ****************************************************************************/ +/* + * The Enclosure Device Added Event Data is exactly the same as Enclosure + * Page 0 data (including the Configuration Page header). So, please + * use/refer to MPI3_ENCLOSURE_PAGE0 structure for Enclosure Device Added + * Event data. + */ + +/**************************************************************************** + * Enclosure Device Changed Event * + ****************************************************************************/ +/* + * The Enclosure Device Change Event Data is exactly the same as Enclosure + * Page 0 data (including the Configuration Page header). So, please + * use/refer to MPI3_ENCLOSURE_PAGE0 structure for Enclosure Device Change + * Event data. + */ + +/***************************************************************************** + * SAS Initiator Device Status Change Event * + ****************************************************************************/ +typedef struct _MPI3_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE +{ + U8 ReasonCode; /* 0x00 */ + U8 IOUnitPort; /* 0x01 */ + U16 DevHandle; /* 0x02 */ + U32 Reserved04; /* 0x04 */ + U64 SASAddress; /* 0x08 */ +} MPI3_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, MPI3_POINTER PTR_MPI3_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, + Mpi3EventDataSasInitDevStatusChange_t, MPI3_POINTER pMpi3EventDataSasInitDevStatusChange_t; + +/**** Defines for the ReasonCode field ****/ +#define MPI3_EVENT_SAS_INIT_RC_ADDED (0x01) +#define MPI3_EVENT_SAS_INIT_RC_NOT_RESPONDING (0x02) + + +/***************************************************************************** + * SAS Initiator Device Table Overflow Event * + ****************************************************************************/ +typedef struct _MPI3_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW +{ + U16 MaxInit; /* 0x00 */ + U16 CurrentInit; /* 0x02 */ + U32 Reserved04; /* 0x04 */ + U64 SASAddress; /* 0x08 */ +} MPI3_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, MPI3_POINTER PTR_MPI3_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, + Mpi3EventDataSasInitTableOverflow_t, MPI3_POINTER pMpi3EventDataSasInitTableOverflow_t; + + +/***************************************************************************** + * Hard Reset Received Event * + ****************************************************************************/ +typedef struct _MPI3_EVENT_DATA_HARD_RESET_RECEIVED +{ + U8 Reserved00; /* 0x00 */ + U8 IOUnitPort; /* 0x01 */ + U16 Reserved02; /* 0x02 */ +} MPI3_EVENT_DATA_HARD_RESET_RECEIVED, MPI3_POINTER PTR_MPI3_EVENT_DATA_HARD_RESET_RECEIVED, + Mpi3EventDataHardResetReceived_t, MPI3_POINTER pMpi3EventDataHardResetReceived_t; + + +/***************************************************************************** + * Diagnostic Tool Events * + *****************************************************************************/ + +/***************************************************************************** + * Diagnostic Buffer Status Change Event * + *****************************************************************************/ +typedef struct _MPI3_EVENT_DATA_DIAG_BUFFER_STATUS_CHANGE +{ + U8 Type; /* 0x00 */ + U8 ReasonCode; /* 0x01 */ + U16 Reserved02; /* 0x02 */ + U32 Reserved04; /* 0x04 */ +} MPI3_EVENT_DATA_DIAG_BUFFER_STATUS_CHANGE, MPI3_POINTER PTR_MPI3_EVENT_DATA_DIAG_BUFFER_STATUS_CHANGE, + Mpi3EventDataDiagBufferStatusChange_t, MPI3_POINTER pMpi3EventDataDiagBufferStatusChange_t; + +/**** Defines for the Type field - use MPI3_DIAG_BUFFER_TYPE_ values ****/ + +/**** Defines for the ReasonCode field ****/ +#define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_RELEASED (0x01) +#define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_PAUSED (0x02) +#define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_RESUMED (0x03) + +/***************************************************************************** + * Persistent Event Logs * + ****************************************************************************/ + +/**** Definitions for the Locale field ****/ +#define MPI3_PEL_LOCALE_FLAGS_NON_BLOCKING_BOOT_EVENT (0x0200) +#define MPI3_PEL_LOCALE_FLAGS_BLOCKING_BOOT_EVENT (0x0100) +#define MPI3_PEL_LOCALE_FLAGS_PCIE (0x0080) +#define MPI3_PEL_LOCALE_FLAGS_CONFIGURATION (0x0040) +#define MPI3_PEL_LOCALE_FLAGS_CONTROLER (0x0020) +#define MPI3_PEL_LOCALE_FLAGS_SAS (0x0010) +#define MPI3_PEL_LOCALE_FLAGS_EPACK (0x0008) +#define MPI3_PEL_LOCALE_FLAGS_ENCLOSURE (0x0004) +#define MPI3_PEL_LOCALE_FLAGS_PD (0x0002) +#define MPI3_PEL_LOCALE_FLAGS_VD (0x0001) + +/**** Definitions for the Class field ****/ +#define MPI3_PEL_CLASS_DEBUG (0x00) +#define MPI3_PEL_CLASS_PROGRESS (0x01) +#define MPI3_PEL_CLASS_INFORMATIONAL (0x02) +#define MPI3_PEL_CLASS_WARNING (0x03) +#define MPI3_PEL_CLASS_CRITICAL (0x04) +#define MPI3_PEL_CLASS_FATAL (0x05) +#define MPI3_PEL_CLASS_FAULT (0x06) + +/**** Definitions for the ClearType field ****/ +#define MPI3_PEL_CLEARTYPE_CLEAR (0x00) + +/**** Definitions for the WaitTime field ****/ +#define MPI3_PEL_WAITTIME_INFINITE_WAIT (0x00) + +/**** Definitions for the Action field ****/ +#define MPI3_PEL_ACTION_GET_SEQNUM (0x01) +#define MPI3_PEL_ACTION_MARK_CLEAR (0x02) +#define MPI3_PEL_ACTION_GET_LOG (0x03) +#define MPI3_PEL_ACTION_GET_COUNT (0x04) +#define MPI3_PEL_ACTION_WAIT (0x05) +#define MPI3_PEL_ACTION_ABORT (0x06) +#define MPI3_PEL_ACTION_GET_PRINT_STRINGS (0x07) +#define MPI3_PEL_ACTION_ACKNOWLEDGE (0x08) + +/**** Definitions for the LogStatus field ****/ +#define MPI3_PEL_STATUS_SUCCESS (0x00) +#define MPI3_PEL_STATUS_NOT_FOUND (0x01) +#define MPI3_PEL_STATUS_ABORTED (0x02) +#define MPI3_PEL_STATUS_NOT_READY (0x03) + +/**************************************************************************** + * PEL Sequence Numbers * + ****************************************************************************/ +typedef struct _MPI3_PEL_SEQ +{ + U32 Newest; /* 0x00 */ + U32 Oldest; /* 0x04 */ + U32 Clear; /* 0x08 */ + U32 Shutdown; /* 0x0C */ + U32 Boot; /* 0x10 */ + U32 LastAcknowledged; /* 0x14 */ +} MPI3_PEL_SEQ, MPI3_POINTER PTR_MPI3_PEL_SEQ, + Mpi3PELSeq_t, MPI3_POINTER pMpi3PELSeq_t; + +/**************************************************************************** + * PEL Entry * + ****************************************************************************/ + +typedef struct _MPI3_PEL_ENTRY +{ + U64 TimeStamp; /* 0x00 */ + U32 SequenceNumber; /* 0x08 */ + U16 LogCode; /* 0x0C */ + U16 ArgType; /* 0x0E */ + U16 Locale; /* 0x10 */ + U8 Class; /* 0x12 */ + U8 Flags; /* 0x13 */ + U8 ExtNum; /* 0x14 */ + U8 NumExts; /* 0x15 */ + U8 ArgDataSize; /* 0x16 */ + U8 FixedFormatStringsSize; /* 0x17 */ + U32 Reserved18[2]; /* 0x18 */ + U32 PELInfo[24]; /* 0x20 - 0x7F */ +} MPI3_PEL_ENTRY, MPI3_POINTER PTR_MPI3_PEL_ENTRY, + Mpi3PELEntry_t, MPI3_POINTER pMpi3PELEntry_t; + + +/**** Definitions for the Flags field ****/ + +#define MPI3_PEL_FLAGS_COMPLETE_RESET_NEEDED (0x02) +#define MPI3_PEL_FLAGS_ACK_NEEDED (0x01) + +/**************************************************************************** + * PEL Event List * + ****************************************************************************/ +typedef struct _MPI3_PEL_LIST +{ + U32 LogCount; /* 0x00 */ + U32 Reserved04; /* 0x04 */ + MPI3_PEL_ENTRY Entry[1]; /* 0x08 */ /* variable length */ +} MPI3_PEL_LIST, MPI3_POINTER PTR_MPI3_PEL_LIST, + Mpi3PELList_t, MPI3_POINTER pMpi3PELList_t; + +/**************************************************************************** + * PEL Count Data * + ****************************************************************************/ +typedef U32 MPI3_PEL_LOG_COUNT, MPI3_POINTER PTR_MPI3_PEL_LOG_COUNT, + Mpi3PELLogCount_t, MPI3_POINTER pMpi3PELLogCount_t; + +/**************************************************************************** + * PEL Arg Map * + ****************************************************************************/ +typedef struct _MPI3_PEL_ARG_MAP +{ + U8 ArgType; /* 0x00 */ + U8 Length; /* 0x01 */ + U16 StartLocation; /* 0x02 */ +} MPI3_PEL_ARG_MAP, MPI3_POINTER PTR_MPI3_PEL_ARG_MAP, + Mpi3PELArgMap_t, MPI3_POINTER pMpi3PELArgMap_t; + +/**** Definitions for the ArgType field ****/ +#define MPI3_PEL_ARG_MAP_ARG_TYPE_APPEND_STRING (0x00) +#define MPI3_PEL_ARG_MAP_ARG_TYPE_INTEGER (0x01) +#define MPI3_PEL_ARG_MAP_ARG_TYPE_STRING (0x02) +#define MPI3_PEL_ARG_MAP_ARG_TYPE_BIT_FIELD (0x03) + + +/**************************************************************************** + * PEL Print String * + ****************************************************************************/ +typedef struct _MPI3_PEL_PRINT_STRING +{ + U16 LogCode; /* 0x00 */ + U16 StringLength; /* 0x02 */ + U8 NumArgMap; /* 0x04 */ + U8 Reserved05[3]; /* 0x05 */ + MPI3_PEL_ARG_MAP ArgMap[1]; /* 0x08 */ /* variable length */ + /* FormatString - offset must be calculated */ /* variable length */ +} MPI3_PEL_PRINT_STRING, MPI3_POINTER PTR_MPI3_PEL_PRINT_STRING, + Mpi3PELPrintString_t, MPI3_POINTER pMpi3PELPrintString_t; + +/**************************************************************************** + * PEL Print String List * + ****************************************************************************/ +typedef struct _MPI3_PEL_PRINT_STRING_LIST +{ + U32 NumPrintStrings; /* 0x00 */ + U32 ResidualBytesRemain; /* 0x04 */ + U32 Reserved08[2]; /* 0x08 */ + MPI3_PEL_PRINT_STRING PrintString[1]; /* 0x10 */ /* variable length */ +} MPI3_PEL_PRINT_STRING_LIST, MPI3_POINTER PTR_MPI3_PEL_PRINT_STRING_LIST, + Mpi3PELPrintStringList_t, MPI3_POINTER pMpi3PELPrintStringList_t; + + +/**************************************************************************** + * PEL Request Msg - generic to allow header decoding * + ****************************************************************************/ +#ifndef MPI3_PEL_ACTION_SPECIFIC_MAX +#define MPI3_PEL_ACTION_SPECIFIC_MAX (1) +#endif /* MPI3_PEL_ACTION_SPECIFIC_MAX */ + +typedef struct _MPI3_PEL_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Action; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U32 ActionSpecific[MPI3_PEL_ACTION_SPECIFIC_MAX]; /* 0x0C */ /* variable length */ +} MPI3_PEL_REQUEST, MPI3_POINTER PTR_MPI3_PEL_REQUEST, + Mpi3PELRequest_t, MPI3_POINTER pMpi3PELRequest_t; + +/**************************************************************************** + * PEL ACTION Get Sequence Nembers * + ****************************************************************************/ +typedef struct _MPI3_PEL_REQ_ACTION_GET_SEQUENCE_NUMBERS +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Action; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U32 Reserved0C[5]; /* 0x0C */ + MPI3_SGE_UNION SGL; /* 0x20 */ +} MPI3_PEL_REQ_ACTION_GET_SEQUENCE_NUMBERS, MPI3_POINTER PTR_MPI3_PEL_REQ_ACTION_GET_SEQUENCE_NUMBERS, + Mpi3PELReqActionGetSequenceNumbers_t, MPI3_POINTER pMpi3PELReqActionGetSequenceNumbers_t; + +/**************************************************************************** + * PEL ACTION Clear Log * + ****************************************************************************/ +typedef struct _MPI3_PEL_REQ_ACTION_CLEAR_LOG_MARKER +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Action; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U8 ClearType; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ +} MPI3_PEL_REQ_ACTION_CLEAR_LOG_MARKER, MPI3_POINTER PTR_MPI3_PEL_REQ_ACTION_CLEAR_LOG_MARKER, + Mpi3PELReqActionClearLogMMarker_t, MPI3_POINTER pMpi3PELReqActionClearLogMMarker_t; + +/**************************************************************************** + * PEL ACTION Get Log * + ****************************************************************************/ +typedef struct _MPI3_PEL_REQ_ACTION_GET_LOG +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Action; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U32 StartingSequenceNumber; /* 0x0C */ + U16 Locale; /* 0x10 */ + U8 Class; /* 0x12 */ + U8 Reserved13; /* 0x13 */ + U32 Reserved14[3]; /* 0x14 */ + MPI3_SGE_UNION SGL; /* 0x20 */ +} MPI3_PEL_REQ_ACTION_GET_LOG, MPI3_POINTER PTR_MPI3_PEL_REQ_ACTION_GET_LOG, + Mpi3PELReqActionGetLog_t, MPI3_POINTER pMpi3PELReqActionGetLog_t; + +/**************************************************************************** + * PEL ACTION Get Count * + ****************************************************************************/ +typedef struct _MPI3_PEL_REQ_ACTION_GET_COUNT +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Action; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U32 StartingSequenceNumber; /* 0x0C */ + U16 Locale; /* 0x10 */ + U8 Class; /* 0x12 */ + U8 Reserved13; /* 0x13 */ + U32 Reserved14[3]; /* 0x14 */ + MPI3_SGE_UNION SGL; /* 0x20 */ +} MPI3_PEL_REQ_ACTION_GET_COUNT, MPI3_POINTER PTR_MPI3_PEL_REQ_ACTION_GET_COUNT, + Mpi3PELReqActionGetCount_t, MPI3_POINTER pMpi3PELReqActionGetCount_t; + +/**************************************************************************** + * PEL ACTION Wait * + ****************************************************************************/ +typedef struct _MPI3_PEL_REQ_ACTION_WAIT +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Action; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U32 StartingSequenceNumber; /* 0x0C */ + U16 Locale; /* 0x10 */ + U8 Class; /* 0x12 */ + U8 Reserved13; /* 0x13 */ + U16 WaitTime; /* 0x14 */ + U16 Reserved16; /* 0x16 */ + U32 Reserved18[2]; /* 0x18 */ +} MPI3_PEL_REQ_ACTION_WAIT, MPI3_POINTER PTR_MPI3_PEL_REQ_ACTION_WAIT, + Mpi3PELReqActionWait_t, MPI3_POINTER pMpi3PELReqActionWait_t; + +/**************************************************************************** + * PEL ACTION Abort * + ****************************************************************************/ +typedef struct _MPI3_PEL_REQ_ACTION_ABORT +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Action; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U32 Reserved0C; /* 0x0C */ + U16 AbortHostTag; /* 0x10 */ + U16 Reserved12; /* 0x12 */ + U32 Reserved14; /* 0x14 */ +} MPI3_PEL_REQ_ACTION_ABORT, MPI3_POINTER PTR_MPI3_PEL_REQ_ACTION_ABORT, + Mpi3PELReqActionAbort_t, MPI3_POINTER pMpi3PELReqActionAbort_t; + +/**************************************************************************** + * PEL ACTION Get Print Strings * + ****************************************************************************/ +typedef struct _MPI3_PEL_REQ_ACTION_GET_PRINT_STRINGS +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Action; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U32 Reserved0C; /* 0x0C */ + U16 StartLogCode; /* 0x10 */ + U16 Reserved12; /* 0x12 */ + U32 Reserved14[3]; /* 0x14 */ + MPI3_SGE_UNION SGL; /* 0x20 */ +} MPI3_PEL_REQ_ACTION_GET_PRINT_STRINGS, MPI3_POINTER PTR_MPI3_PEL_REQ_ACTION_GET_PRINT_STRINGS, + Mpi3PELReqActionGetPrintStrings_t, MPI3_POINTER pMpi3PELReqActionGetPrintStrings_t; + +/**************************************************************************** + * PEL ACTION Acknowledge * + ****************************************************************************/ +typedef struct _MPI3_PEL_REQ_ACTION_ACKNOWLEDGE +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Action; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U32 SequenceNumber; /* 0x0C */ + U32 Reserved10; /* 0x10 */ +} MPI3_PEL_REQ_ACTION_ACKNOWLEDGE, MPI3_POINTER PTR_MPI3_PEL_REQ_ACTION_ACKNOWLEDGE, + Mpi3PELReqActionAcknowledge_t, MPI3_POINTER pMpi3PELReqActionAcknowledge_t; + +/**** Definitions for the MsgFlags field ****/ +#define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_MASK (0x03) +#define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_NO_GUIDANCE (0x00) +#define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_CONTINUE_OP (0x01) +#define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_TRANSITION_TO_FAULT (0x02) + +/**************************************************************************** + * PEL Reply * + ****************************************************************************/ +typedef struct _MPI3_PEL_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ + U8 Action; /* 0x10 */ + U8 Reserved11; /* 0x11 */ + U16 Reserved12; /* 0x12 */ + U16 PELogStatus; /* 0x14 */ + U16 Reserved16; /* 0x16 */ + U32 TransferLength; /* 0x18 */ +} MPI3_PEL_REPLY, MPI3_POINTER PTR_MPI3_PEL_REPLY, + Mpi3PELReply_t, MPI3_POINTER pMpi3PELReply_t; + + +/***************************************************************************** + * Component Image Download * + ****************************************************************************/ +typedef struct _MPI3_CI_DOWNLOAD_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Action; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U32 Signature1; /* 0x0C */ + U32 TotalImageSize; /* 0x10 */ + U32 ImageOffset; /* 0x14 */ + U32 SegmentSize; /* 0x18 */ + U32 Reserved1C; /* 0x1C */ + MPI3_SGE_UNION SGL; /* 0x20 */ +} MPI3_CI_DOWNLOAD_REQUEST, MPI3_POINTER PTR_MPI3_CI_DOWNLOAD_REQUEST, + Mpi3CIDownloadRequest_t, MPI3_POINTER pMpi3CIDownloadRequest_t; + +/**** Definitions for the MsgFlags field ****/ +#define MPI3_CI_DOWNLOAD_MSGFLAGS_LAST_SEGMENT (0x80) +#define MPI3_CI_DOWNLOAD_MSGFLAGS_FORCE_FMC_ENABLE (0x40) +#define MPI3_CI_DOWNLOAD_MSGFLAGS_SIGNED_NVDATA (0x20) +#define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_MASK (0x03) +#define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_FAST (0x00) +#define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_MEDIUM (0x01) +#define MPI3_CI_DOWNLOAD_MSGFLAGS_WRITE_CACHE_FLUSH_SLOW (0x02) + +/**** Definitions for the Action field ****/ +#define MPI3_CI_DOWNLOAD_ACTION_DOWNLOAD (0x01) +#define MPI3_CI_DOWNLOAD_ACTION_ONLINE_ACTIVATION (0x02) +#define MPI3_CI_DOWNLOAD_ACTION_OFFLINE_ACTIVATION (0x03) +#define MPI3_CI_DOWNLOAD_ACTION_GET_STATUS (0x04) +#define MPI3_CI_DOWNLOAD_ACTION_CANCEL_OFFLINE_ACTIVATION (0x05) + +typedef struct _MPI3_CI_DOWNLOAD_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ + U8 Flags; /* 0x10 */ + U8 CacheDirty; /* 0x11 */ + U8 PendingCount; /* 0x12 */ + U8 Reserved13; /* 0x13 */ +} MPI3_CI_DOWNLOAD_REPLY, MPI3_POINTER PTR_MPI3_CI_DOWNLOAD_REPLY, + Mpi3CIDownloadReply_t, MPI3_POINTER pMpi3CIDownloadReply_t; + +/**** Definitions for the Flags field ****/ +#define MPI3_CI_DOWNLOAD_FLAGS_DOWNLOAD_IN_PROGRESS (0x80) +#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_FAILURE (0x40) +#define MPI3_CI_DOWNLOAD_FLAGS_OFFLINE_ACTIVATION_REQUIRED (0x20) +#define MPI3_CI_DOWNLOAD_FLAGS_KEY_UPDATE_PENDING (0x10) +#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_MASK (0x0E) +#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_NOT_NEEDED (0x00) +#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_AWAITING (0x02) +#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_ONLINE_PENDING (0x04) +#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_OFFLINE_PENDING (0x06) +#define MPI3_CI_DOWNLOAD_FLAGS_COMPATIBLE (0x01) + +/***************************************************************************** + * Component Image Upload * + ****************************************************************************/ +typedef struct _MPI3_CI_UPLOAD_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U32 Signature1; /* 0x0C */ + U32 Reserved10; /* 0x10 */ + U32 ImageOffset; /* 0x14 */ + U32 SegmentSize; /* 0x18 */ + U32 Reserved1C; /* 0x1C */ + MPI3_SGE_UNION SGL; /* 0x20 */ +} MPI3_CI_UPLOAD_REQUEST, MPI3_POINTER PTR_MPI3_CI_UPLOAD_REQUEST, + Mpi3CIUploadRequest_t, MPI3_POINTER pMpi3CIUploadRequest_t; + +/**** Defines for the MsgFlags field ****/ +#define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_MASK (0x01) +#define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_PRIMARY (0x00) +#define MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_SECONDARY (0x01) +#define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_MASK (0x02) +#define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_FLASH (0x00) +#define MPI3_CI_UPLOAD_MSGFLAGS_FORMAT_EXECUTABLE (0x02) + +/**** Defines for Signature1 field - use MPI3_IMAGE_HEADER_SIGNATURE1_ defines */ + +/***************************************************************************** + * IO Unit Control * + ****************************************************************************/ + +/**** Definitions for the Operation field ****/ +#define MPI3_CTRL_OP_FORCE_FULL_DISCOVERY (0x01) +#define MPI3_CTRL_OP_LOOKUP_MAPPING (0x02) +#define MPI3_CTRL_OP_UPDATE_TIMESTAMP (0x04) +#define MPI3_CTRL_OP_GET_TIMESTAMP (0x05) +#define MPI3_CTRL_OP_GET_IOC_CHANGE_COUNT (0x06) +#define MPI3_CTRL_OP_CHANGE_PROFILE (0x07) +#define MPI3_CTRL_OP_REMOVE_DEVICE (0x10) +#define MPI3_CTRL_OP_CLOSE_PERSISTENT_CONNECTION (0x11) +#define MPI3_CTRL_OP_HIDDEN_ACK (0x12) +#define MPI3_CTRL_OP_CLEAR_DEVICE_COUNTERS (0x13) +#define MPI3_CTRL_OP_SEND_SAS_PRIMITIVE (0x20) +#define MPI3_CTRL_OP_SAS_PHY_CONTROL (0x21) +#define MPI3_CTRL_OP_READ_INTERNAL_BUS (0x23) +#define MPI3_CTRL_OP_WRITE_INTERNAL_BUS (0x24) +#define MPI3_CTRL_OP_PCIE_LINK_CONTROL (0x30) + +/**** Depending on the Operation selected, the various ParamX fields *****/ +/**** contain defined data values. These indexes help identify those values *****/ +#define MPI3_CTRL_OP_LOOKUP_MAPPING_PARAM8_LOOKUP_METHOD_INDEX (0x00) +#define MPI3_CTRL_OP_UPDATE_TIMESTAMP_PARAM64_TIMESTAMP_INDEX (0x00) +#define MPI3_CTRL_OP_CHANGE_PROFILE_PARAM8_PROFILE_ID_INDEX (0x00) +#define MPI3_CTRL_OP_REMOVE_DEVICE_PARAM16_DEVHANDLE_INDEX (0x00) +#define MPI3_CTRL_OP_CLOSE_PERSIST_CONN_PARAM16_DEVHANDLE_INDEX (0x00) +#define MPI3_CTRL_OP_HIDDEN_ACK_PARAM16_DEVHANDLE_INDEX (0x00) +#define MPI3_CTRL_OP_CLEAR_DEVICE_COUNTERS_PARAM16_DEVHANDLE_INDEX (0x00) +#define MPI3_CTRL_OP_SEND_SAS_PRIM_PARAM8_PHY_INDEX (0x00) +#define MPI3_CTRL_OP_SEND_SAS_PRIM_PARAM8_PRIMSEQ_INDEX (0x01) +#define MPI3_CTRL_OP_SEND_SAS_PRIM_PARAM32_PRIMITIVE_INDEX (0x00) +#define MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_ACTION_INDEX (0x00) +#define MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_PHY_INDEX (0x01) +#define MPI3_CTRL_OP_READ_INTERNAL_BUS_PARAM64_ADDRESS_INDEX (0x00) +#define MPI3_CTRL_OP_WRITE_INTERNAL_BUS_PARAM64_ADDRESS_INDEX (0x00) +#define MPI3_CTRL_OP_WRITE_INTERNAL_BUS_PARAM32_VALUE_INDEX (0x00) +#define MPI3_CTRL_OP_PCIE_LINK_CONTROL_PARAM8_ACTION_INDEX (0x00) +#define MPI3_CTRL_OP_PCIE_LINK_CONTROL_PARAM8_LINK_INDEX (0x01) + +/**** Definitions for the LookupMethod field in LOOKUP_MAPPING reqs ****/ +#define MPI3_CTRL_LOOKUP_METHOD_WWID_ADDRESS (0x01) +#define MPI3_CTRL_LOOKUP_METHOD_ENCLOSURE_SLOT (0x02) +#define MPI3_CTRL_LOOKUP_METHOD_SAS_DEVICE_NAME (0x03) +#define MPI3_CTRL_LOOKUP_METHOD_PERSISTENT_ID (0x04) + +/**** Definitions for IoUnitControl Lookup Mapping Method Parameters ****/ +#define MPI3_CTRL_LOOKUP_METHOD_WWIDADDR_PARAM16_DEVH_INDEX (0) +#define MPI3_CTRL_LOOKUP_METHOD_WWIDADDR_PARAM64_WWID_INDEX (0) +#define MPI3_CTRL_LOOKUP_METHOD_ENCLSLOT_PARAM16_SLOTNUM_INDEX (0) +#define MPI3_CTRL_LOOKUP_METHOD_ENCLSLOT_PARAM64_ENCLOSURELID_INDEX (0) +#define MPI3_CTRL_LOOKUP_METHOD_SASDEVNAME_PARAM16_DEVH_INDEX (0) +#define MPI3_CTRL_LOOKUP_METHOD_SASDEVNAME_PARAM64_DEVNAME_INDEX (0) +#define MPI3_CTRL_LOOKUP_METHOD_PERSISTID_PARAM16_DEVH_INDEX (0) +#define MPI3_CTRL_LOOKUP_METHOD_PERSISTID_PARAM16_PERSISTENT_ID_INDEX (1) + +/*** Definitions for IoUnitControl Reply fields ****/ +#define MPI3_CTRL_LOOKUP_METHOD_VALUE16_DEVH_INDEX (0) +#define MPI3_CTRL_GET_TIMESTAMP_VALUE64_TIMESTAMP_INDEX (0) +#define MPI3_CTRL_GET_IOC_CHANGE_COUNT_VALUE16_CHANGECOUNT_INDEX (0) +#define MPI3_CTRL_READ_INTERNAL_BUS_VALUE32_VALUE_INDEX (0) + +/**** Definitions for the PrimSeq field in SEND_SAS_PRIMITIVE reqs ****/ +#define MPI3_CTRL_PRIMFLAGS_SINGLE (0x01) +#define MPI3_CTRL_PRIMFLAGS_TRIPLE (0x03) +#define MPI3_CTRL_PRIMFLAGS_REDUNDANT (0x06) + +/**** Definitions for the Action field in PCIE_LINK_CONTROL and SAS_PHY_CONTROL reqs ****/ +#define MPI3_CTRL_ACTION_NOP (0x00) +#define MPI3_CTRL_ACTION_LINK_RESET (0x01) +#define MPI3_CTRL_ACTION_HARD_RESET (0x02) +#define MPI3_CTRL_ACTION_CLEAR_ERROR_LOG (0x05) + +typedef struct _MPI3_IOUNIT_CONTROL_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Reserved0A; /* 0x0A */ + U8 Operation; /* 0x0B */ + U32 Reserved0C; /* 0x0C */ + U64 Param64[2]; /* 0x10 */ + U32 Param32[4]; /* 0x20 */ + U16 Param16[4]; /* 0x30 */ + U8 Param8[8]; /* 0x38 */ +} MPI3_IOUNIT_CONTROL_REQUEST, MPI3_POINTER PTR_MPI3_IOUNIT_CONTROL_REQUEST, + Mpi3IoUnitControlRequest_t, MPI3_POINTER pMpi3IoUnitControlRequest_t; + + +typedef struct _MPI3_IOUNIT_CONTROL_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ + U64 Value64[2]; /* 0x10 */ + U32 Value32[4]; /* 0x20 */ + U16 Value16[4]; /* 0x30 */ + U8 Value8[8]; /* 0x38 */ +} MPI3_IOUNIT_CONTROL_REPLY, MPI3_POINTER PTR_MPI3_IOUNIT_CONTROL_REPLY, + Mpi3IoUnitControlReply_t, MPI3_POINTER pMpi3IoUnitControlReply_t; + +#endif /* MPI30_IOC_H */ + + diff --git a/sys/dev/mpi3mr/mpi/mpi30_pci.h b/sys/dev/mpi3mr/mpi/mpi30_pci.h new file mode 100644 index 000000000000..f15dab2a5a9c --- /dev/null +++ b/sys/dev/mpi3mr/mpi/mpi30_pci.h @@ -0,0 +1,97 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2016-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + * + */ + +#ifndef MPI30_PCI_H +#define MPI30_PCI_H 1 + +/***************************************************************************** + * NVMe Encapsulated Request Message * + ****************************************************************************/ +#ifndef MPI3_NVME_ENCAP_CMD_MAX +#define MPI3_NVME_ENCAP_CMD_MAX (1) +#endif /* MPI3_NVME_ENCAP_CMD_MAX */ + +typedef struct _MPI3_NVME_ENCAPSULATED_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 DevHandle; /* 0x0A */ + U16 EncapsulatedCommandLength; /* 0x0C */ + U16 Flags; /* 0x0E */ + U32 DataLength; /* 0x10 */ + U32 Reserved14[3]; /* 0x14 */ + U32 Command[MPI3_NVME_ENCAP_CMD_MAX]; /* 0x20 */ /* variable length */ +} MPI3_NVME_ENCAPSULATED_REQUEST, MPI3_POINTER PTR_MPI3_NVME_ENCAPSULATED_REQUEST, + Mpi3NVMeEncapsulatedRequest_t, MPI3_POINTER pMpi3NVMeEncapsulatedRequest_t; + +/**** Defines for the Flags field ****/ +#define MPI3_NVME_FLAGS_FORCE_ADMIN_ERR_REPLY_MASK (0x0002) +#define MPI3_NVME_FLAGS_FORCE_ADMIN_ERR_REPLY_FAIL_ONLY (0x0000) +#define MPI3_NVME_FLAGS_FORCE_ADMIN_ERR_REPLY_ALL (0x0002) +#define MPI3_NVME_FLAGS_SUBMISSIONQ_MASK (0x0001) +#define MPI3_NVME_FLAGS_SUBMISSIONQ_IO (0x0000) +#define MPI3_NVME_FLAGS_SUBMISSIONQ_ADMIN (0x0001) + + +/***************************************************************************** + * NVMe Encapsulated Error Reply Message * + ****************************************************************************/ +typedef struct _MPI3_NVME_ENCAPSULATED_ERROR_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ + U32 NVMeCompletionEntry[4]; /* 0x10 */ +} MPI3_NVME_ENCAPSULATED_ERROR_REPLY, MPI3_POINTER PTR_MPI3_NVME_ENCAPSULATED_ERROR_REPLY, + Mpi3NVMeEncapsulatedErrorReply_t, MPI3_POINTER pMpi3NVMeEncapsulatedErrorReply_t; + +#endif /* MPI30_PCI_H */ diff --git a/sys/dev/mpi3mr/mpi/mpi30_raid.h b/sys/dev/mpi3mr/mpi/mpi30_raid.h new file mode 100644 index 000000000000..fe2c4baffd3c --- /dev/null +++ b/sys/dev/mpi3mr/mpi/mpi30_raid.h @@ -0,0 +1,46 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2016-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + * + */ + +#ifndef MPI30_RAID_H +#define MPI30_RAID_H 1 + + +#endif /* MPI30_RAID_H */ diff --git a/sys/dev/mpi3mr/mpi/mpi30_sas.h b/sys/dev/mpi3mr/mpi/mpi30_sas.h new file mode 100644 index 000000000000..c28de07c9fdd --- /dev/null +++ b/sys/dev/mpi3mr/mpi/mpi30_sas.h @@ -0,0 +1,99 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2016-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + * + */ + +#ifndef MPI30_SAS_H +#define MPI30_SAS_H 1 + +/***************************************************************************** + * SAS Device Info Definitions * + ****************************************************************************/ +#define MPI3_SAS_DEVICE_INFO_SSP_TARGET (0x00000100) +#define MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET (0x00000080) +#define MPI3_SAS_DEVICE_INFO_SMP_TARGET (0x00000040) +#define MPI3_SAS_DEVICE_INFO_SSP_INITIATOR (0x00000020) +#define MPI3_SAS_DEVICE_INFO_STP_INITIATOR (0x00000010) +#define MPI3_SAS_DEVICE_INFO_SMP_INITIATOR (0x00000008) +#define MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK (0x00000007) +#define MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_NO_DEVICE (0x00000000) +#define MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE (0x00000001) +#define MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER (0x00000002) + +/***************************************************************************** + * SMP Passthrough Request Message * + ****************************************************************************/ +typedef struct _MPI3_SMP_PASSTHROUGH_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Reserved0A; /* 0x0A */ + U8 IOUnitPort; /* 0x0B */ + U32 Reserved0C[3]; /* 0x0C */ + U64 SASAddress; /* 0x18 */ + MPI3_SGE_SIMPLE RequestSGE; /* 0x20 */ + MPI3_SGE_SIMPLE ResponseSGE; /* 0x30 */ +} MPI3_SMP_PASSTHROUGH_REQUEST, MPI3_POINTER PTR_MPI3_SMP_PASSTHROUGH_REQUEST, + Mpi3SmpPassthroughRequest_t, MPI3_POINTER pMpi3SmpPassthroughRequest_t; + +/***************************************************************************** + * SMP Passthrough Reply Message * + ****************************************************************************/ +typedef struct _MPI3_SMP_PASSTHROUGH_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ + U16 ResponseDataLength; /* 0x10 */ + U16 Reserved12; /* 0x12 */ +} MPI3_SMP_PASSTHROUGH_REPLY, MPI3_POINTER PTR_MPI3_SMP_PASSTHROUGH_REPLY, + Mpi3SmpPassthroughReply_t, MPI3_POINTER pMpi3SmpPassthroughReply_t; + +#endif /* MPI30_SAS_H */ diff --git a/sys/dev/mpi3mr/mpi/mpi30_targ.h b/sys/dev/mpi3mr/mpi/mpi30_targ.h new file mode 100644 index 000000000000..d9aee48a6437 --- /dev/null +++ b/sys/dev/mpi3mr/mpi/mpi30_targ.h @@ -0,0 +1,316 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2016-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + * + */ + +#ifndef MPI30_TARG_H +#define MPI30_TARG_H 1 + +/***************************************************************************** + * Command Buffer Formats * + ****************************************************************************/ +typedef struct _MPI3_TARGET_SSP_CMD_BUFFER +{ + U8 FrameType; /* 0x00 */ + U8 Reserved01; /* 0x01 */ + U16 InitiatorConnectionTag; /* 0x02 */ + U32 HashedSourceSASAddress; /* 0x04 */ + U16 Reserved08; /* 0x08 */ + U16 Flags; /* 0x0A */ + U32 Reserved0C; /* 0x0C */ + U16 Tag; /* 0x10 */ + U16 TargetPortTransferTag; /* 0x12 */ + U32 DataOffset; /* 0x14 */ + U8 LogicalUnitNumber[8]; /* 0x18 */ + U8 Reserved20; /* 0x20 */ + U8 TaskAttribute; /* 0x21 */ + U8 Reserved22; /* 0x22 */ + U8 AdditionalCDBLength; /* 0x23 */ + U8 CDB[16]; /* 0x24 */ + /* AdditionalCDBBytes field starts here */ /* 0x34 */ +} MPI3_TARGET_SSP_CMD_BUFFER, MPI3_POINTER PTR_MPI3_TARGET_SSP_CMD_BUFFER, + Mpi3TargetSspCmdBuffer_t, MPI3_POINTER pMpi3TargetSspCmdBuffer_t; + +typedef struct _MPI3_TARGET_SSP_TASK_BUFFER +{ + U8 FrameType; /* 0x00 */ + U8 Reserved01; /* 0x01 */ + U16 InitiatorConnectionTag; /* 0x02 */ + U32 HashedSourceSASAddress; /* 0x04 */ + U16 Reserved08; /* 0x08 */ + U16 Flags; /* 0x0A */ + U32 Reserved0C; /* 0x0C */ + U16 Tag; /* 0x10 */ + U16 TargetPortTransferTag; /* 0x12 */ + U32 DataOffset; /* 0x14 */ + U8 LogicalUnitNumber[8]; /* 0x18 */ + U16 Reserved20; /* 0x20 */ + U8 TaskManagementFunction; /* 0x22 */ + U8 Reserved23; /* 0x23 */ + U16 ManagedTaskTag; /* 0x24 */ + U16 Reserved26; /* 0x26 */ + U32 Reserved28[3]; /* 0x28 */ +} MPI3_TARGET_SSP_TASK_BUFFER, MPI3_POINTER PTR_MPI3_TARGET_SSP_TASK_BUFFER, + Mpi3TargetSspTaskBuffer_t, MPI3_POINTER pMpi3TargetSspTaskBuffer_t; + +/**** Defines for the FrameType field ****/ +#define MPI3_TARGET_FRAME_TYPE_COMMAND (0x06) +#define MPI3_TARGET_FRAME_TYPE_TASK (0x16) + +/**** Defines for the HashedSourceSASAddress field ****/ +#define MPI3_TARGET_HASHED_SAS_ADDRESS_MASK (0xFFFFFF00) +#define MPI3_TARGET_HASHED_SAS_ADDRESS_SHIFT (8) + + +/***************************************************************************** + * Target Command Buffer Post Base Request Message * + ****************************************************************************/ +typedef struct _MPI3_TARGET_CMD_BUF_POST_BASE_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 BufferPostFlags; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U16 MinReplyQueueID; /* 0x0C */ + U16 MaxReplyQueueID; /* 0x0E */ + U64 BaseAddress; /* 0x10 */ + U16 CmdBufferLength; /* 0x18 */ + U16 TotalCmdBuffers; /* 0x1A */ + U32 Reserved1C; /* 0x1C */ +} MPI3_TARGET_CMD_BUF_POST_BASE_REQUEST, MPI3_POINTER PTR_MPI3_TARGET_CMD_BUF_POST_BASE_REQUEST, + Mpi3TargetCmdBufPostBaseRequest_t, MPI3_POINTER pMpi3TargetCmdBufPostBaseRequest_t; + +/**** Defines for the BufferPostFlags field ****/ +#define MPI3_CMD_BUF_POST_BASE_FLAGS_DLAS_MASK (0x0C) +#define MPI3_CMD_BUF_POST_BASE_FLAGS_DLAS_SYSTEM (0x00) +#define MPI3_CMD_BUF_POST_BASE_FLAGS_DLAS_IOCUDP (0x04) +#define MPI3_CMD_BUF_POST_BASE_FLAGS_DLAS_IOCCTL (0x08) +#define MPI3_CMD_BUF_POST_BASE_FLAGS_AUTO_POST_ALL (0x01) + +/**** Defines for the CmdBufferLength field ****/ +#define MPI3_CMD_BUF_POST_BASE_MIN_BUF_LENGTH (0x34) +#define MPI3_CMD_BUF_POST_BASE_MAX_BUF_LENGTH (0x3FC) + +/***************************************************************************** + * Target Command Buffer Post List Request Message * + ****************************************************************************/ +typedef struct _MPI3_TARGET_CMD_BUF_POST_LIST_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U8 CmdBufferCount; /* 0x0C */ + U8 Reserved0D[3]; /* 0x0D */ + U16 IoIndex[2]; /* 0x10 */ +} MPI3_TARGET_CMD_BUF_POST_LIST_REQUEST, MPI3_POINTER PTR_MPI3_TARGET_CMD_BUF_POST_LIST_REQUEST, + Mpi3TargetCmdBufPostListRequest_t, MPI3_POINTER pMpi3TargetCmdBufPostListRequest_t; + + +/***************************************************************************** + * Target Command Buffer Post Base List Reply Message * + ****************************************************************************/ +typedef struct _MPI3_TARGET_CMD_BUF_POST_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ + U8 CmdBufferCount; /* 0x10 */ + U8 Reserved11[3]; /* 0x11 */ + U16 IoIndex[2]; /* 0x14 */ +} MPI3_TARGET_CMD_BUF_POST_REPLY, MPI3_POINTER PTR_MPI3_TARGET_CMD_BUF_POST_REPLY, + Mpi3TargetCmdBufPostReply_t, MPI3_POINTER pMpi3TargetCmdBufPostReply_t; + + +/***************************************************************************** + * Target Assist Request Message * + ****************************************************************************/ +typedef struct _MPI3_TARGET_ASSIST_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 DevHandle; /* 0x0A */ + U32 Flags; /* 0x0C */ + U16 Reserved10; /* 0x10 */ + U16 QueueTag; /* 0x12 */ + U16 IoIndex; /* 0x14 */ + U16 InitiatorConnectionTag; /* 0x16 */ + U32 SkipCount; /* 0x18 */ + U32 DataLength; /* 0x1C */ + U32 PortTransferLength; /* 0x20 */ + U32 PrimaryReferenceTag; /* 0x24 */ + U16 PrimaryApplicationTag; /* 0x28 */ + U16 PrimaryApplicationTagMask; /* 0x2A */ + U32 RelativeOffset; /* 0x2C */ + MPI3_SGE_UNION SGL[5]; /* 0x30 */ +} MPI3_TARGET_ASSIST_REQUEST, MPI3_POINTER PTR_MPI3_TARGET_ASSIST_REQUEST, + Mpi3TargetAssistRequest_t, MPI3_POINTER pMpi3TargetAssistRequest_t; + +/**** Defines for the MsgFlags field ****/ +#define MPI3_TARGET_ASSIST_MSGFLAGS_METASGL_VALID (0x80) + +/**** Defines for the Flags field ****/ +#define MPI3_TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER (0x00200000) +#define MPI3_TARGET_ASSIST_FLAGS_AUTO_STATUS (0x00100000) +#define MPI3_TARGET_ASSIST_FLAGS_DATADIRECTION_MASK (0x000C0000) +#define MPI3_TARGET_ASSIST_FLAGS_DATADIRECTION_WRITE (0x00040000) +#define MPI3_TARGET_ASSIST_FLAGS_DATADIRECTION_READ (0x00080000) +#define MPI3_TARGET_ASSIST_FLAGS_DMAOPERATION_MASK (0x00030000) +#define MPI3_TARGET_ASSIST_FLAGS_DMAOPERATION_HOST_PI (0x00010000) + +/**** Defines for the SGL field ****/ +#define MPI3_TARGET_ASSIST_METASGL_INDEX (4) + +/***************************************************************************** + * Target Status Send Request Message * + ****************************************************************************/ +typedef struct _MPI3_TARGET_STATUS_SEND_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 DevHandle; /* 0x0A */ + U16 ResponseIULength; /* 0x0C */ + U16 Flags; /* 0x0E */ + U16 Reserved10; /* 0x10 */ + U16 QueueTag; /* 0x12 */ + U16 IoIndex; /* 0x14 */ + U16 InitiatorConnectionTag; /* 0x16 */ + U32 IOCUseOnly18[6]; /* 0x18 */ + U32 IOCUseOnly30[4]; /* 0x30 */ + MPI3_SGE_UNION SGL; /* 0x40 */ +} MPI3_TARGET_STATUS_SEND_REQUEST, MPI3_POINTER PTR_MPI3_TARGET_STATUS_SEND_REQUEST, + Mpi3TargetStatusSendRequest_t, MPI3_POINTER pMpi3TargetStatusSendRequest_t; + +/**** Defines for the Flags field ****/ +#define MPI3_TSS_FLAGS_REPOST_CMD_BUFFER (0x0020) +#define MPI3_TSS_FLAGS_AUTO_SEND_GOOD_STATUS (0x0010) + + +/***************************************************************************** + * Standard Target Mode Reply Message * + ****************************************************************************/ +typedef struct _MPI3_TARGET_STANDARD_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ + U32 TransferCount; /* 0x10 */ +} MPI3_TARGET_STANDARD_REPLY, MPI3_POINTER PTR_MPI3_TARGET_STANDARD_REPLY, + Mpi3TargetStandardReply_t, MPI3_POINTER pMpi3TargetStandardReply_t; + + +/***************************************************************************** + * Target Mode Abort Request Message * + ****************************************************************************/ +typedef struct _MPI3_TARGET_MODE_ABORT_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 AbortType; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U16 RequestQueueIDToAbort; /* 0x0C */ + U16 HostTagToAbort; /* 0x0E */ + U16 DevHandle; /* 0x10 */ + U8 IOCUseOnly12; /* 0x12 */ + U8 Reserved13; /* 0x13 */ +} MPI3_TARGET_MODE_ABORT_REQUEST, MPI3_POINTER PTR_MPI3_TARGET_MODE_ABORT_REQUEST, + Mpi3TargetModeAbortRequest_t, MPI3_POINTER pMpi3TargetModeAbortRequest_t; + +/**** Defines for the AbortType field ****/ +#define MPI3_TARGET_MODE_ABORT_ALL_CMD_BUFFERS (0x00) +#define MPI3_TARGET_MODE_ABORT_EXACT_IO_REQUEST (0x01) +#define MPI3_TARGET_MODE_ABORT_ALL_COMMANDS (0x02) + + +/***************************************************************************** + * Target Mode Abort Reply Message * + ****************************************************************************/ +typedef struct _MPI3_TARGET_MODE_ABORT_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ + U32 AbortCount; /* 0x10 */ +} MPI3_TARGET_MODE_ABORT_REPLY, MPI3_POINTER PTR_MPI3_TARGET_MODE_ABORT_REPLY, + Mpi3TargetModeAbortReply_t, MPI3_POINTER pMpi3TargetModeAbortReply_t; + +#endif /* MPI30_TARG_H */ + diff --git a/sys/dev/mpi3mr/mpi/mpi30_tool.h b/sys/dev/mpi3mr/mpi/mpi30_tool.h new file mode 100644 index 000000000000..55fb53601863 --- /dev/null +++ b/sys/dev/mpi3mr/mpi/mpi30_tool.h @@ -0,0 +1,476 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2016-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + * + */ + +#ifndef MPI30_TOOL_H +#define MPI30_TOOL_H 1 + +/***************************************************************************** + * Toolbox Messages * + *****************************************************************************/ + +/***************************************************************************** + * Clean Tool Request Message * + *****************************************************************************/ +typedef struct _MPI3_TOOL_CLEAN_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Tool; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U32 Area; /* 0x0C */ +} MPI3_TOOL_CLEAN_REQUEST, MPI3_POINTER PTR_MPI3_TOOL_CLEAN_REQUEST, + Mpi3ToolCleanRequest_t, MPI3_POINTER pMpi3ToolCleanRequest_t; + +/**** Defines for the Tool field ****/ +#define MPI3_TOOLBOX_TOOL_CLEAN (0x01) +#define MPI3_TOOLBOX_TOOL_ISTWI_READ_WRITE (0x02) +#define MPI3_TOOLBOX_TOOL_DIAGNOSTIC_CLI (0x03) +#define MPI3_TOOLBOX_TOOL_LANE_MARGINING (0x04) +#define MPI3_TOOLBOX_TOOL_RECOVER_DEVICE (0x05) +#define MPI3_TOOLBOX_TOOL_LOOPBACK (0x06) + +/**** Bitfield definitions for Area field ****/ +#define MPI3_TOOLBOX_CLEAN_AREA_BIOS_BOOT_SERVICES (0x00000008) +#define MPI3_TOOLBOX_CLEAN_AREA_ALL_BUT_MFG (0x00000002) +#define MPI3_TOOLBOX_CLEAN_AREA_NVSTORE (0x00000001) + + +/***************************************************************************** + * ISTWI Read Write Tool Request Message * + *****************************************************************************/ +typedef struct _MPI3_TOOL_ISTWI_READ_WRITE_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Tool; /* 0x0A */ + U8 Flags; /* 0x0B */ + U8 DevIndex; /* 0x0C */ + U8 Action; /* 0x0D */ + U16 Reserved0E; /* 0x0E */ + U16 TxDataLength; /* 0x10 */ + U16 RxDataLength; /* 0x12 */ + U32 Reserved14[3]; /* 0x14 */ + MPI3_MAN11_ISTWI_DEVICE_FORMAT IstwiDevice; /* 0x20 */ + MPI3_SGE_UNION SGL; /* 0x30 */ +} MPI3_TOOL_ISTWI_READ_WRITE_REQUEST, MPI3_POINTER PTR_MPI3_TOOL_ISTWI_READ_WRITE_REQUEST, + Mpi3ToolIstwiReadWriteRequest_t, MPI3_POINTER pMpi3ToolIstwiReadWRiteRequest_t; + +/**** Bitfield definitions for Flags field ****/ +#define MPI3_TOOLBOX_ISTWI_FLAGS_AUTO_RESERVE_RELEASE (0x80) +#define MPI3_TOOLBOX_ISTWI_FLAGS_ADDRESS_MODE_MASK (0x04) +#define MPI3_TOOLBOX_ISTWI_FLAGS_ADDRESS_MODE_DEVINDEX (0x00) +#define MPI3_TOOLBOX_ISTWI_FLAGS_ADDRESS_MODE_DEVICE_FIELD (0x04) +#define MPI3_TOOLBOX_ISTWI_FLAGS_PAGE_ADDRESS_MASK (0x03) + +/**** Definitions for the Action field ****/ +#define MPI3_TOOLBOX_ISTWI_ACTION_RESERVE_BUS (0x00) +#define MPI3_TOOLBOX_ISTWI_ACTION_RELEASE_BUS (0x01) +#define MPI3_TOOLBOX_ISTWI_ACTION_RESET (0x02) +#define MPI3_TOOLBOX_ISTWI_ACTION_READ_DATA (0x03) +#define MPI3_TOOLBOX_ISTWI_ACTION_WRITE_DATA (0x04) +#define MPI3_TOOLBOX_ISTWI_ACTION_SEQUENCE (0x05) + + +/**** Defines for the IstwiDevice field - refer to struct definition in mpi30_cnfg.h ****/ + + +/***************************************************************************** + * ISTWI Read Write Tool Reply Message * + *****************************************************************************/ +typedef struct _MPI3_TOOL_ISTWI_READ_WRITE_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ + U16 IstwiStatus; /* 0x10 */ + U16 Reserved12; /* 0x12 */ + U16 TxDataCount; /* 0x14 */ + U16 RxDataCount; /* 0x16 */ +} MPI3_TOOL_ISTWI_READ_WRITE_REPLY, MPI3_POINTER PTR_MPI3_TOOL_ISTWI_READ_WRITE_REPLY, + Mpi3ToolIstwiReadWriteReply_t, MPI3_POINTER pMpi3ToolIstwiReadWRiteReply_t; + + + +/***************************************************************************** + * Diagnostic CLI Tool Request Message * + *****************************************************************************/ +typedef struct _MPI3_TOOL_DIAGNOSTIC_CLI_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Tool; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U32 CommandDataLength; /* 0x0C */ + U32 ResponseDataLength; /* 0x10 */ + U32 Reserved14[3]; /* 0x14 */ + MPI3_SGE_UNION SGL; /* 0x20 */ +} MPI3_TOOL_DIAGNOSTIC_CLI_REQUEST, MPI3_POINTER PTR_MPI3_TOOL_DIAGNOSTIC_CLI_REQUEST, + Mpi3ToolDiagnosticCliRequest_t, MPI3_POINTER pMpi3ToolDiagnosticCliRequest_t; + + +/***************************************************************************** + * Diagnostic CLI Tool Reply Message * + *****************************************************************************/ +typedef struct _MPI3_TOOL_DIAGNOSTIC_CLI_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ + U32 ReturnedDataLength; /* 0x10 */ +} MPI3_TOOL_DIAGNOSTIC_CLI_REPLY, MPI3_POINTER PTR_MPI3_TOOL_DIAGNOSTIC_CLI_REPLY, + Mpi3ToolDiagnosticCliReply_t, MPI3_POINTER pMpi3ToolDiagnosticCliReply_t; + + +/***************************************************************************** + * Lane Margining Tool Request Message * + *****************************************************************************/ +typedef struct _MPI3_TOOL_LANE_MARGIN_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Tool; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U8 Action; /* 0x0C */ + U8 SwitchPort; /* 0x0D */ + U16 DevHandle; /* 0x0E */ + U8 StartLane; /* 0x10 */ + U8 NumLanes; /* 0x11 */ + U16 Reserved12; /* 0x12 */ + U32 Reserved14[3]; /* 0x14 */ + MPI3_SGE_UNION SGL; /* 0x20 */ +} MPI3_TOOL_LANE_MARGIN_REQUEST, MPI3_POINTER PTR_MPI3_TOOL_LANE_MARGIN_REQUEST, + Mpi3ToolIstwiLaneMarginRequest_t, MPI3_POINTER pMpi3ToolLaneMarginRequest_t; + +/**** Definitions for the Action field ****/ +#define MPI3_TOOLBOX_LM_ACTION_ENTER (0x00) +#define MPI3_TOOLBOX_LM_ACTION_EXIT (0x01) +#define MPI3_TOOLBOX_LM_ACTION_READ (0x02) +#define MPI3_TOOLBOX_LM_ACTION_WRITE (0x03) + +typedef struct _MPI3_LANE_MARGIN_ELEMENT +{ + U16 Control; /* 0x00 */ + U16 Status; /* 0x02 */ +} MPI3_LANE_MARGIN_ELEMENT, MPI3_POINTER PTR_MPI3_LANE_MARGIN_ELEMENT, + Mpi3LaneMarginElement_t, MPI3_POINTER pMpi3LaneMarginElement_t; + +/***************************************************************************** + * Lane Margining Tool Reply Message * + *****************************************************************************/ +typedef struct _MPI3_TOOL_LANE_MARGIN_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ + U32 ReturnedDataLength; /* 0x10 */ +} MPI3_TOOL_LANE_MARGIN_REPLY, MPI3_POINTER PTR_MPI3_TOOL_LANE_MARGIN_REPLY, + Mpi3ToolLaneMarginReply_t, MPI3_POINTER pMpi3ToolLaneMarginReply_t; + +/***************************************************************************** + * Recover Device Request Message * + *****************************************************************************/ +typedef struct _MPI3_TOOL_RECOVER_DEVICE_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Tool; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U8 Action; /* 0x0C */ + U8 Reserved0D; /* 0x0D */ + U16 DevHandle; /* 0x0E */ +} MPI3_TOOL_RECOVER_DEVICE_REQUEST, MPI3_POINTER PTR_MPI3_TOOL_RECOVER_DEVICE_REQUEST, + Mpi3ToolRecoverDeviceRequest_t, MPI3_POINTER pMpi3ToolRecoverDeviceRequest_t; + +/**** Bitfield definitions for the Action field ****/ +#define MPI3_TOOLBOX_RD_ACTION_START (0x01) +#define MPI3_TOOLBOX_RD_ACTION_GET_STATUS (0x02) +#define MPI3_TOOLBOX_RD_ACTION_ABORT (0x03) + +/***************************************************************************** + * Recover Device Reply Message * + *****************************************************************************/ +typedef struct _MPI3_TOOL_RECOVER_DEVICE_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ + U8 Status; /* 0x10 */ + U8 Reserved11; /* 0x11 */ + U16 Reserved1C; /* 0x12 */ +} MPI3_TOOL_RECOVER_DEVICE_REPLY, MPI3_POINTER PTR_MPI3_TOOL_RECOVER_DEVICE_REPLY, + Mpi3ToolRecoverDeviceReply_t, MPI3_POINTER pMpi3ToolRecoverDeviceReply_t; + +/**** Bitfield definitions for the Status field ****/ +#define MPI3_TOOLBOX_RD_STATUS_NOT_NEEDED (0x01) +#define MPI3_TOOLBOX_RD_STATUS_NEEDED (0x02) +#define MPI3_TOOLBOX_RD_STATUS_IN_PROGRESS (0x03) +#define MPI3_TOOLBOX_RD_STATUS_ABORTING (0x04) + +/***************************************************************************** + * Loopback Tool Request Message * + *****************************************************************************/ +typedef struct _MPI3_TOOL_LOOPBACK_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U8 Tool; /* 0x0A */ + U8 Reserved0B; /* 0x0B */ + U32 Reserved0C; /* 0x0C */ + U64 Phys; /* 0x10 */ +} MPI3_TOOL_LOOPBACK_REQUEST, MPI3_POINTER PTR_MPI3_TOOL_LOOPBACK_REQUEST, + Mpi3ToolLoopbackRequest_t, MPI3_POINTER pMpi3ToolLoopbackRequest_t; + +/***************************************************************************** + * Loopback Tool Reply Message * + *****************************************************************************/ +typedef struct _MPI3_TOOL_LOOPBACK_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ + U64 TestedPhys; /* 0x10 */ + U64 FailedPhys; /* 0x18 */ +} MPI3_TOOL_LOOPBACK_REPLY, MPI3_POINTER PTR_MPI3_TOOL_LOOPBACK_REPLY, + Mpi3ToolLoopbackReply_t, MPI3_POINTER pMpi3ToolLoopbackReply_t; + + +/***************************************************************************** + * Diagnostic Buffer Messages * + *****************************************************************************/ + +/***************************************************************************** + * Diagnostic Buffer Post Request Message * + *****************************************************************************/ +typedef struct _MPI3_DIAG_BUFFER_POST_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U8 Type; /* 0x0C */ + U8 Reserved0D; /* 0x0D */ + U16 Reserved0E; /* 0x0E */ + U64 Address; /* 0x10 */ + U32 Length; /* 0x18 */ + U32 Reserved1C; /* 0x1C */ +} MPI3_DIAG_BUFFER_POST_REQUEST, MPI3_POINTER PTR_MPI3_DIAG_BUFFER_POST_REQUEST, + Mpi3DiagBufferPostRequest_t, MPI3_POINTER pMpi3DiagBufferPostRequest_t; + +/**** Defines for the MsgFlags field ****/ +#define MPI3_DIAG_BUFFER_POST_MSGFLAGS_SEGMENTED (0x01) + +/**** Defines for the Type field ****/ +#define MPI3_DIAG_BUFFER_TYPE_TRACE (0x01) +#define MPI3_DIAG_BUFFER_TYPE_FW (0x02) +#define MPI3_DIAG_BUFFER_TYPE_DRIVER (0x10) +#define MPI3_DIAG_BUFFER_TYPE_FDL (0x20) +#define MPI3_DIAG_BUFFER_MIN_PRODUCT_SPECIFIC (0xF0) +#define MPI3_DIAG_BUFFER_MAX_PRODUCT_SPECIFIC (0xFF) + + +/***************************************************************************** + * DRIVER DIAGNOSTIC Buffer * + *****************************************************************************/ +typedef struct _MPI3_DRIVER_BUFFER_HEADER +{ + U32 Signature; /* 0x00 */ + U16 HeaderSize; /* 0x04 */ + U16 RTTFileHeaderOffset; /* 0x06 */ + U32 Flags; /* 0x08 */ + U32 CircularBufferSize; /* 0x0C */ + U32 LogicalBufferEnd; /* 0x10 */ + U32 LogicalBufferStart; /* 0x14 */ + U32 IOCUseOnly18[2]; /* 0x18 */ + U32 Reserved20[760]; /* 0x20 - 0xBFC */ + U32 ReservedRTTRACE[256]; /* 0xC00 - 0xFFC */ +} MPI3_DRIVER_BUFFER_HEADER, MPI3_POINTER PTR_MPI3_DRIVER_BUFFER_HEADER, + Mpi3DriverBufferHeader_t, MPI3_POINTER pMpi3DriverBufferHeader_t; + +/**** Defines for the Type field ****/ +#define MPI3_DRIVER_DIAG_BUFFER_HEADER_SIGNATURE_CIRCULAR (0x43495243) + +/**** Defines for the Flags field ****/ +#define MPI3_DRIVER_DIAG_BUFFER_HEADER_FLAGS_CIRCULAR_BUF_FORMAT_MASK (0x00000003) +#define MPI3_DRIVER_DIAG_BUFFER_HEADER_FLAGS_CIRCULAR_BUF_FORMAT_ASCII (0x00000000) +#define MPI3_DRIVER_DIAG_BUFFER_HEADER_FLAGS_CIRCULAR_BUF_FORMAT_RTTRACE (0x00000001) + +/***************************************************************************** + * Diagnostic Buffer Manage Request Message * + *****************************************************************************/ +typedef struct _MPI3_DIAG_BUFFER_MANAGE_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U8 Type; /* 0x0C */ + U8 Action; /* 0x0D */ + U16 Reserved0E; /* 0x0E */ +} MPI3_DIAG_BUFFER_MANAGE_REQUEST, MPI3_POINTER PTR_MPI3_DIAG_BUFFER_MANAGE_REQUEST, + Mpi3DiagBufferManageRequest_t, MPI3_POINTER pMpi3DiagBufferManageRequest_t; + +/**** Defines for the Type field - use MPI3_DIAG_BUFFER_TYPE_ values ****/ + +/**** Defined for the Action field ****/ +#define MPI3_DIAG_BUFFER_ACTION_RELEASE (0x01) +#define MPI3_DIAG_BUFFER_ACTION_PAUSE (0x02) +#define MPI3_DIAG_BUFFER_ACTION_RESUME (0x03) + +/***************************************************************************** + * Diagnostic Buffer Upload Request Message * + *****************************************************************************/ +typedef struct _MPI3_DIAG_BUFFER_UPLOAD_REQUEST +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 Reserved0A; /* 0x0A */ + U8 Type; /* 0x0C */ + U8 Flags; /* 0x0D */ + U16 Reserved0E; /* 0x0E */ + U64 Context; /* 0x10 */ + U32 Reserved18; /* 0x18 */ + U32 Reserved1C; /* 0x1C */ + MPI3_SGE_UNION SGL; /* 0x20 */ +} MPI3_DIAG_BUFFER_UPLOAD_REQUEST, MPI3_POINTER PTR_MPI3_DIAG_BUFFER_UPLOAD_REQUEST, + Mpi3DiagBufferUploadRequest_t, MPI3_POINTER pMpi3DiagBufferUploadRequest_t; + +/**** Defines for the Type field - use MPI3_DIAG_BUFFER_TYPE_ values ****/ + +/**** Defined for the Flags field ****/ +#define MPI3_DIAG_BUFFER_UPLOAD_FLAGS_FORMAT_MASK (0x01) +#define MPI3_DIAG_BUFFER_UPLOAD_FLAGS_FORMAT_DECODED (0x00) +#define MPI3_DIAG_BUFFER_UPLOAD_FLAGS_FORMAT_ENCODED (0x01) + +/***************************************************************************** + * Diagnostic Buffer Upload Reply Message * + *****************************************************************************/ +typedef struct _MPI3_DIAG_BUFFER_UPLOAD_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ + U64 Context; /* 0x10 */ + U32 ReturnedDataLength; /* 0x18 */ + U32 Reserved1C; /* 0x1C */ +} MPI3_DIAG_BUFFER_UPLOAD_REPLY, MPI3_POINTER PTR_MPI3_DIAG_BUFFER_UPLOAD_REPLY, + Mpi3DiagBufferUploadReply_t, MPI3_POINTER pMpi3DiagBufferUploadReply_t; + +#endif /* MPI30_TOOL_H */ + diff --git a/sys/dev/mpi3mr/mpi/mpi30_transport.h b/sys/dev/mpi3mr/mpi/mpi30_transport.h new file mode 100644 index 000000000000..436496411309 --- /dev/null +++ b/sys/dev/mpi3mr/mpi/mpi30_transport.h @@ -0,0 +1,748 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2016-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + * + */ + +/* + * Version History + * --------------- + * + * Date Version Description + * -------- ----------- ------------------------------------------------------ + * 11-30-18 03.00.00.08 Corresponds to Fusion-MPT MPI 3.0 Specification Rev H. + * 02-08-19 03.00.00.09 Corresponds to Fusion-MPT MPI 3.0 Specification Rev I. + * 05-03-19 03.00.00.10 Corresponds to Fusion-MPT MPI 3.0 Specification Rev J. + * 08-30-19 03.00.00.12 Corresponds to Fusion-MPT MPI 3.0 Specification Rev L. + * 11-01-19 03.00.00.13 Corresponds to Fusion-MPT MPI 3.0 Specification Rev M. + * 12-16-19 03.00.00.14 Corresponds to Fusion-MPT MPI 3.0 Specification Rev N. + * 02-28-20 03.00.00.15 Corresponds to Fusion-MPT MPI 3.0 Specification Rev O. + * 05-01-20 03.00.00.16 Corresponds to Fusion-MPT MPI 3.0 Specification Rev P. + * 06-26-20 03.00.00.17 Corresponds to Fusion-MPT MPI 3.0 Specification Rev Q. + * 08-28-20 03.00.00.18 Corresponds to Fusion-MPT MPI 3.0 Specification Rev R. + * 10-30-20 03.00.00.19 Corresponds to Fusion-MPT MPI 3.0 Specification Rev S. + * 12-18-20 03.00.00.20 Corresponds to Fusion-MPT MPI 3.0 Specification Rev T. + * 02-09-21 03.00.20.01 Corresponds to Fusion-MPT MPI 3.0 Specification Rev T - Interim Release 1. + * 02-26-21 03.00.21.00 Corresponds to Fusion-MPT MPI 3.0 Specification Rev U. + * 04-16-21 03.00.21.01 Corresponds to Fusion-MPT MPI 3.0 Specification Rev U - Interim Release 1. + * 04-28-21 03.00.21.02 Corresponds to Fusion-MPT MPI 3.0 Specification Rev U - Interim Release 2. + * 05-28-21 03.00.22.00 Corresponds to Fusion-MPT MPI 3.0 Specification Rev V. + * 07-23-21 03.00.22.01 Corresponds to Fusion-MPT MPI 3.0 Specification Rev V - Interim Release 1. + * 09-03-21 03.00.23.00 Corresponds to Fusion-MPT MPI 3.0 Specification Rev 23. + * 10-23-21 03.00.23.01 Corresponds to Fusion-MPT MPI 3.0 Specification Rev 23 - Interim Release 1. + * 12-03-21 03.00.24.00 Corresponds to Fusion-MPT MPI 3.0 Specification Rev 24. + * 02-25-22 03.00.25.00 Corresponds to Fusion-MPT MPI 3.0 Specification Rev 25. + * 06-03-22 03.00.26.00 Corresponds to Fusion-MPT MPI 3.0 Specification Rev 26. + * 08-09-22 03.00.26.01 Corresponds to Fusion-MPT MPI 3.0 Specification Rev 26 - Interim Release 1. + * 09-02-22 03.00.27.00 Corresponds to Fusion-MPT MPI 3.0 Specification Rev 27. + * 10-20-22 03.00.27.01 Corresponds to Fusion-MPT MPI 3.0 Specification Rev 27 - Interim Release 1. + * 12-02-22 03.00.28.00 Corresponds to Fusion-MPT MPI 3.0 Specification Rev 28. + * 02-24-22 03.00.29.00 Corresponds to Fusion-MPT MPI 3.0 Specification Rev 29. + */ +#ifndef MPI30_TRANSPORT_H +#define MPI30_TRANSPORT_H 1 + +/***************************************************************************** + * Common version structure/union used in * + * messages and configuration pages * + ****************************************************************************/ + +typedef struct _MPI3_VERSION_STRUCT +{ + U8 Dev; /* 0x00 */ + U8 Unit; /* 0x01 */ + U8 Minor; /* 0x02 */ + U8 Major; /* 0x03 */ +} MPI3_VERSION_STRUCT, MPI3_POINTER PTR_MPI3_VERSION_STRUCT, + Mpi3VersionStruct_t, MPI3_POINTER pMpi3VersionStruct_t; + +typedef union _MPI3_VERSION_UNION +{ + MPI3_VERSION_STRUCT Struct; + U32 Word; +} MPI3_VERSION_UNION, MPI3_POINTER PTR_MPI3_VERSION_UNION, + Mpi3VersionUnion_t, MPI3_POINTER pMpi3VersionUnion_t; + +/****** Version constants for this revision ****/ +#define MPI3_VERSION_MAJOR (3) +#define MPI3_VERSION_MINOR (0) +#define MPI3_VERSION_UNIT (29) +#define MPI3_VERSION_DEV (0) + +/****** DevHandle definitions *****/ +#define MPI3_DEVHANDLE_INVALID (0xFFFF) + +/***************************************************************************** + * System Interface Register Definitions * + ****************************************************************************/ +typedef struct _MPI3_SYSIF_OPER_QUEUE_INDEXES +{ + U16 ProducerIndex; /* 0x00 */ + U16 Reserved02; /* 0x02 */ + U16 ConsumerIndex; /* 0x04 */ + U16 Reserved06; /* 0x06 */ +} MPI3_SYSIF_OPER_QUEUE_INDEXES, MPI3_POINTER PTR_MPI3_SYSIF_OPER_QUEUE_INDEXES; + +typedef volatile struct _MPI3_SYSIF_REGISTERS +{ + U64 IOCInformation; /* 0x00 */ + MPI3_VERSION_UNION Version; /* 0x08 */ + U32 Reserved0C[2]; /* 0x0C */ + U32 IOCConfiguration; /* 0x14 */ + U32 Reserved18; /* 0x18 */ + U32 IOCStatus; /* 0x1C */ + U32 Reserved20; /* 0x20 */ + U32 AdminQueueNumEntries; /* 0x24 */ + U64 AdminRequestQueueAddress; /* 0x28 */ + U64 AdminReplyQueueAddress; /* 0x30 */ + U32 Reserved38[2]; /* 0x38 */ + U32 CoalesceControl; /* 0x40 */ + U32 Reserved44[1007]; /* 0x44 */ + U16 AdminRequestQueuePI; /* 0x1000 */ + U16 Reserved1002; /* 0x1002 */ + U16 AdminReplyQueueCI; /* 0x1004 */ + U16 Reserved1006; /* 0x1006 */ + MPI3_SYSIF_OPER_QUEUE_INDEXES OperQueueIndexes[383]; /* 0x1008 */ + U32 Reserved1C00; /* 0x1C00 */ + U32 WriteSequence; /* 0x1C04 */ + U32 HostDiagnostic; /* 0x1C08 */ + U32 Reserved1C0C; /* 0x1C0C */ + U32 Fault; /* 0x1C10 */ + U32 FaultInfo[3]; /* 0x1C14 */ + U32 Reserved1C20[4]; /* 0x1C20 */ + U64 HCBAddress; /* 0x1C30 */ + U32 HCBSize; /* 0x1C38 */ + U32 Reserved1C3C; /* 0x1C3C */ + U32 ReplyFreeHostIndex; /* 0x1C40 */ + U32 SenseBufferFreeHostIndex; /* 0x1C44 */ + U32 Reserved1C48[2]; /* 0x1C48 */ + U64 DiagRWData; /* 0x1C50 */ + U64 DiagRWAddress; /* 0x1C58 */ + U16 DiagRWControl; /* 0x1C60 */ + U16 DiagRWStatus; /* 0x1C62 */ + U32 Reserved1C64[35]; /* 0x1C64 */ + U32 Scratchpad[4]; /* 0x1CF0 */ + U32 Reserved1D00[192]; /* 0x1D00 */ + U32 DeviceAssignedRegisters[2048]; /* 0x2000 */ +} MPI3_SYSIF_REGS, MPI3_POINTER PTR_MPI3_SYSIF_REGS, + Mpi3SysIfRegs_t, MPI3_POINTER pMpi3SysIfRegs_t; + +/**** Defines for the IOCInformation register ****/ +#define MPI3_SYSIF_IOC_INFO_LOW_OFFSET (0x00000000) +#define MPI3_SYSIF_IOC_INFO_HIGH_OFFSET (0x00000004) +#define MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK (0xFF000000) +#define MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT (24) +#define MPI3_SYSIF_IOC_INFO_LOW_HCB_DISABLED (0x00000001) + +/**** Defines for the IOCConfiguration register ****/ +#define MPI3_SYSIF_IOC_CONFIG_OFFSET (0x00000014) +#define MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ (0x00F00000) +#define MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT (20) +#define MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ (0x000F0000) +#define MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT (16) +#define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_MASK (0x0000C000) +#define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NO (0x00000000) +#define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL (0x00004000) +#define MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ (0x00002000) +#define MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE (0x00000010) +#define MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC (0x00000001) + +/**** Defines for the IOCStatus register ****/ +#define MPI3_SYSIF_IOC_STATUS_OFFSET (0x0000001C) +#define MPI3_SYSIF_IOC_STATUS_RESET_HISTORY (0x00000010) +#define MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK (0x0000000C) +#define MPI3_SYSIF_IOC_STATUS_SHUTDOWN_SHIFT (0x00000002) +#define MPI3_SYSIF_IOC_STATUS_SHUTDOWN_NONE (0x00000000) +#define MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS (0x00000004) +#define MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE (0x00000008) +#define MPI3_SYSIF_IOC_STATUS_FAULT (0x00000002) +#define MPI3_SYSIF_IOC_STATUS_READY (0x00000001) + +/**** Defines for the AdminQueueNumEntries register ****/ +#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_OFFSET (0x00000024) +#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REQ_MASK (0x0FFF) +#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REPLY_OFFSET (0x00000026) +#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REPLY_MASK (0x0FFF0000) +#define MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_REPLY_SHIFT (16) + +/**** Defines for the AdminRequestQueueAddress register ****/ +#define MPI3_SYSIF_ADMIN_REQ_Q_ADDR_LOW_OFFSET (0x00000028) +#define MPI3_SYSIF_ADMIN_REQ_Q_ADDR_HIGH_OFFSET (0x0000002C) + +/**** Defines for the AdminReplyQueueAddress register ****/ +#define MPI3_SYSIF_ADMIN_REPLY_Q_ADDR_LOW_OFFSET (0x00000030) +#define MPI3_SYSIF_ADMIN_REPLY_Q_ADDR_HIGH_OFFSET (0x00000034) + +/**** Defines for the CoalesceControl register ****/ +#define MPI3_SYSIF_COALESCE_CONTROL_OFFSET (0x00000040) +#define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_MASK (0xC0000000) +#define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_NO_CHANGE (0x00000000) +#define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_DISABLE (0x40000000) +#define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_ENABLE (0xC0000000) +#define MPI3_SYSIF_COALESCE_CONTROL_VALID (0x20000000) +#define MPI3_SYSIF_COALESCE_CONTROL_MSIX_IDX_MASK (0x01FF0000) +#define MPI3_SYSIF_COALESCE_CONTROL_MSIX_IDX_SHIFT (16) +#define MPI3_SYSIF_COALESCE_CONTROL_TIMEOUT_MASK (0x0000FF00) +#define MPI3_SYSIF_COALESCE_CONTROL_TIMEOUT_SHIFT (8) +#define MPI3_SYSIF_COALESCE_CONTROL_DEPTH_MASK (0x000000FF) +#define MPI3_SYSIF_COALESCE_CONTROL_DEPTH_SHIFT (0) + +/**** Defines for the AdminRequestQueuePI register ****/ +#define MPI3_SYSIF_ADMIN_REQ_Q_PI_OFFSET (0x00001000) + +/**** Defines for the AdminReplyQueueCI register ****/ +#define MPI3_SYSIF_ADMIN_REPLY_Q_CI_OFFSET (0x00001004) + +/**** Defines for the OperationalRequestQueuePI register */ +#define MPI3_SYSIF_OPER_REQ_Q_PI_OFFSET (0x00001008) +#define MPI3_SYSIF_OPER_REQ_Q_N_PI_OFFSET(N) (MPI3_SYSIF_OPER_REQ_Q_PI_OFFSET + (((N)-1)*8)) /* N = 1, 2, 3, ..., 255 */ + +/**** Defines for the OperationalReplyQueueCI register */ +#define MPI3_SYSIF_OPER_REPLY_Q_CI_OFFSET (0x0000100C) +#define MPI3_SYSIF_OPER_REPLY_Q_N_CI_OFFSET(N) (MPI3_SYSIF_OPER_REPLY_Q_CI_OFFSET + (((N)-1)*8)) /* N = 1, 2, 3, ..., 255 */ + +/**** Defines for the WriteSequence register *****/ +#define MPI3_SYSIF_WRITE_SEQUENCE_OFFSET (0x00001C04) +#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_MASK (0x0000000F) +#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH (0x0) +#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_1ST (0xF) +#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND (0x4) +#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_3RD (0xB) +#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_4TH (0x2) +#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_5TH (0x7) +#define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_6TH (0xD) + +/**** Defines for the HostDiagnostic register *****/ +#define MPI3_SYSIF_HOST_DIAG_OFFSET (0x00001C08) +#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_MASK (0x00000700) +#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_NO_RESET (0x00000000) +#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET (0x00000100) +#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_HOST_CONTROL_BOOT_RESET (0x00000200) +#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_COMPLETE_RESET (0x00000300) +#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT (0x00000700) +#define MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS (0x00000080) +#define MPI3_SYSIF_HOST_DIAG_SECURE_BOOT (0x00000040) +#define MPI3_SYSIF_HOST_DIAG_CLEAR_INVALID_FW_IMAGE (0x00000020) +#define MPI3_SYSIF_HOST_DIAG_INVALID_FW_IMAGE (0x00000010) +#define MPI3_SYSIF_HOST_DIAG_HCBENABLE (0x00000008) +#define MPI3_SYSIF_HOST_DIAG_HCBMODE (0x00000004) +#define MPI3_SYSIF_HOST_DIAG_DIAG_RW_ENABLE (0x00000002) +#define MPI3_SYSIF_HOST_DIAG_DIAG_WRITE_ENABLE (0x00000001) + +/**** Defines for the Fault register ****/ +#define MPI3_SYSIF_FAULT_OFFSET (0x00001C10) +#define MPI3_SYSIF_FAULT_CODE_MASK (0x0000FFFF) +#define MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET (0x0000F000) +#define MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET (0x0000F001) +#define MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS (0x0000F002) +#define MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED (0x0000F003) +#define MPI3_SYSIF_FAULT_CODE_SOFT_RESET_NEEDED (0x0000F004) +#define MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED (0x0000F005) +#define MPI3_SYSIF_FAULT_CODE_TEMP_THRESHOLD_EXCEEDED (0x0000F006) + +/**** Defines for FaultCodeAdditionalInfo registers ****/ +#define MPI3_SYSIF_FAULT_INFO0_OFFSET (0x00001C14) +#define MPI3_SYSIF_FAULT_INFO1_OFFSET (0x00001C18) +#define MPI3_SYSIF_FAULT_INFO2_OFFSET (0x00001C1C) + +/**** Defines for HCBAddress register ****/ +#define MPI3_SYSIF_HCB_ADDRESS_LOW_OFFSET (0x00001C30) +#define MPI3_SYSIF_HCB_ADDRESS_HIGH_OFFSET (0x00001C34) + +/**** Defines for HCBSize register ****/ +#define MPI3_SYSIF_HCB_SIZE_OFFSET (0x00001C38) +#define MPI3_SYSIF_HCB_SIZE_SIZE_MASK (0xFFFFF000) +#define MPI3_SYSIF_HCB_SIZE_SIZE_SHIFT (12) +#define MPI3_SYSIF_HCB_SIZE_HCDW_ENABLE (0x00000001) + +/**** Defines for ReplyFreeHostIndex register ****/ +#define MPI3_SYSIF_REPLY_FREE_HOST_INDEX_OFFSET (0x00001C40) + +/**** Defines for SenseBufferFreeHostIndex register ****/ +#define MPI3_SYSIF_SENSE_BUF_FREE_HOST_INDEX_OFFSET (0x00001C44) + +/**** Defines for DiagRWData register ****/ +#define MPI3_SYSIF_DIAG_RW_DATA_LOW_OFFSET (0x00001C50) +#define MPI3_SYSIF_DIAG_RW_DATA_HIGH_OFFSET (0x00001C54) + +/**** Defines for DiagRWAddress ****/ +#define MPI3_SYSIF_DIAG_RW_ADDRESS_LOW_OFFSET (0x00001C58) +#define MPI3_SYSIF_DIAG_RW_ADDRESS_HIGH_OFFSET (0x00001C5C) + +/**** Defines for DiagRWControl register ****/ +#define MPI3_SYSIF_DIAG_RW_CONTROL_OFFSET (0x00001C60) +#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_MASK (0x00000030) +#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_1BYTE (0x00000000) +#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_2BYTES (0x00000010) +#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_4BYTES (0x00000020) +#define MPI3_SYSIF_DIAG_RW_CONTROL_LEN_8BYTES (0x00000030) +#define MPI3_SYSIF_DIAG_RW_CONTROL_RESET (0x00000004) +#define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_MASK (0x00000002) +#define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_READ (0x00000000) +#define MPI3_SYSIF_DIAG_RW_CONTROL_DIR_WRITE (0x00000002) +#define MPI3_SYSIF_DIAG_RW_CONTROL_START (0x00000001) + +/**** Defines for DiagRWStatus register ****/ +#define MPI3_SYSIF_DIAG_RW_STATUS_OFFSET (0x00001C62) +#define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_MASK (0x0000000E) +#define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_SUCCESS (0x00000000) +#define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_INV_ADDR (0x00000002) +#define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_ACC_ERR (0x00000004) +#define MPI3_SYSIF_DIAG_RW_STATUS_STATUS_PAR_ERR (0x00000006) +#define MPI3_SYSIF_DIAG_RW_STATUS_BUSY (0x00000001) + +/**** Defines for Scratchpad registers ****/ +#define MPI3_SYSIF_SCRATCHPAD0_OFFSET (0x00001CF0) +#define MPI3_SYSIF_SCRATCHPAD1_OFFSET (0x00001CF4) +#define MPI3_SYSIF_SCRATCHPAD2_OFFSET (0x00001CF8) +#define MPI3_SYSIF_SCRATCHPAD3_OFFSET (0x00001CFC) + +/**** Defines for Device Assigned registers ****/ +#define MPI3_SYSIF_DEVICE_ASSIGNED_REGS_OFFSET (0x00002000) + +/**** Default Defines for Diag Save Timeout ****/ +#define MPI3_SYSIF_DIAG_SAVE_TIMEOUT (60) /* seconds */ + +/***************************************************************************** + * Reply Descriptors * + ****************************************************************************/ + +/***************************************************************************** + * Default Reply Descriptor * + ****************************************************************************/ +typedef struct _MPI3_DEFAULT_REPLY_DESCRIPTOR +{ + U32 DescriptorTypeDependent1[2]; /* 0x00 */ + U16 RequestQueueCI; /* 0x08 */ + U16 RequestQueueID; /* 0x0A */ + U16 DescriptorTypeDependent2; /* 0x0C */ + U16 ReplyFlags; /* 0x0E */ +} MPI3_DEFAULT_REPLY_DESCRIPTOR, MPI3_POINTER PTR_MPI3_DEFAULT_REPLY_DESCRIPTOR, + Mpi3DefaultReplyDescriptor_t, MPI3_POINTER pMpi3DefaultReplyDescriptor_t; + +/**** Defines for the ReplyFlags field ****/ +#define MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK (0x0001) +#define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK (0xF000) +#define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY (0x0000) +#define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS (0x1000) +#define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_TARGET_COMMAND_BUFFER (0x2000) +#define MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS (0x3000) + +/**** Defines for the RequestQueueID field ****/ +#define MPI3_REPLY_DESCRIPT_REQUEST_QUEUE_ID_INVALID (0xFFFF) + +/***************************************************************************** + * Address Reply Descriptor * + ****************************************************************************/ +typedef struct _MPI3_ADDRESS_REPLY_DESCRIPTOR +{ + U64 ReplyFrameAddress; /* 0x00 */ + U16 RequestQueueCI; /* 0x08 */ + U16 RequestQueueID; /* 0x0A */ + U16 Reserved0C; /* 0x0C */ + U16 ReplyFlags; /* 0x0E */ +} MPI3_ADDRESS_REPLY_DESCRIPTOR, MPI3_POINTER PTR_MPI3_ADDRESS_REPLY_DESCRIPTOR, + Mpi3AddressReplyDescriptor_t, MPI3_POINTER pMpi3AddressReplyDescriptor_t; + +/***************************************************************************** + * Success Reply Descriptor * + ****************************************************************************/ +typedef struct _MPI3_SUCCESS_REPLY_DESCRIPTOR +{ + U32 Reserved00[2]; /* 0x00 */ + U16 RequestQueueCI; /* 0x08 */ + U16 RequestQueueID; /* 0x0A */ + U16 HostTag; /* 0x0C */ + U16 ReplyFlags; /* 0x0E */ +} MPI3_SUCCESS_REPLY_DESCRIPTOR, MPI3_POINTER PTR_MPI3_SUCCESS_REPLY_DESCRIPTOR, + Mpi3SuccessReplyDescriptor_t, MPI3_POINTER pMpi3SuccessReplyDescriptor_t; + +/***************************************************************************** + * Target Command Buffer Reply Descriptor * + ****************************************************************************/ +typedef struct _MPI3_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR +{ + U32 Reserved00; /* 0x00 */ + U16 InitiatorDevHandle; /* 0x04 */ + U8 PhyNum; /* 0x06 */ + U8 Reserved07; /* 0x07 */ + U16 RequestQueueCI; /* 0x08 */ + U16 RequestQueueID; /* 0x0A */ + U16 IOIndex; /* 0x0C */ + U16 ReplyFlags; /* 0x0E */ +} MPI3_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, MPI3_POINTER PTR_MPI3_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, + Mpi3TargetCommandBufferReplyDescriptor_t, MPI3_POINTER pMpi3TargetCommandBufferReplyDescriptor_t; + +/**** See Default Reply Descriptor Defines above for definitions in the ReplyFlags field ****/ + +/***************************************************************************** + * Status Reply Descriptor * + ****************************************************************************/ +typedef struct _MPI3_STATUS_REPLY_DESCRIPTOR +{ + U16 IOCStatus; /* 0x00 */ + U16 Reserved02; /* 0x02 */ + U32 IOCLogInfo; /* 0x04 */ + U16 RequestQueueCI; /* 0x08 */ + U16 RequestQueueID; /* 0x0A */ + U16 HostTag; /* 0x0C */ + U16 ReplyFlags; /* 0x0E */ +} MPI3_STATUS_REPLY_DESCRIPTOR, MPI3_POINTER PTR_MPI3_STATUS_REPLY_DESCRIPTOR, + Mpi3StatusReplyDescriptor_t, MPI3_POINTER pMpi3StatusReplyDescriptor_t; + +/**** Defines for the IOCStatus field ****/ +#define MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL (0x8000) +#define MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK (0x7FFF) + +/**** Defines for the IOCLogInfo field ****/ +#define MPI3_REPLY_DESCRIPT_STATUS_IOCLOGINFO_TYPE_MASK (0xF0000000) +#define MPI3_REPLY_DESCRIPT_STATUS_IOCLOGINFO_TYPE_NO_INFO (0x00000000) +#define MPI3_REPLY_DESCRIPT_STATUS_IOCLOGINFO_TYPE_SAS (0x30000000) +#define MPI3_REPLY_DESCRIPT_STATUS_IOCLOGINFO_DATA_MASK (0x0FFFFFFF) + +/***************************************************************************** + * Union of Reply Descriptors * + ****************************************************************************/ +typedef union _MPI3_REPLY_DESCRIPTORS_UNION +{ + MPI3_DEFAULT_REPLY_DESCRIPTOR Default; + MPI3_ADDRESS_REPLY_DESCRIPTOR AddressReply; + MPI3_SUCCESS_REPLY_DESCRIPTOR Success; + MPI3_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer; + MPI3_STATUS_REPLY_DESCRIPTOR Status; + U32 Words[4]; +} MPI3_REPLY_DESCRIPTORS_UNION, MPI3_POINTER PTR_MPI3_REPLY_DESCRIPTORS_UNION, + Mpi3ReplyDescriptorsUnion_t, MPI3_POINTER pMpi3ReplyDescriptorsUnion_t; + + +/***************************************************************************** + * Scatter Gather Elements * + ****************************************************************************/ + +/***************************************************************************** + * Common structure for Simple, Chain, and Last Chain * + * scatter gather elements * + ****************************************************************************/ +typedef struct _MPI3_SGE_COMMON +{ + U64 Address; /* 0x00 */ + U32 Length; /* 0x08 */ + U8 Reserved0C[3]; /* 0x0C */ + U8 Flags; /* 0x0F */ +} MPI3_SGE_SIMPLE, MPI3_POINTER PTR_MPI3_SGE_SIMPLE, + Mpi3SGESimple_t, MPI3_POINTER pMpi3SGESimple_t, + MPI3_SGE_CHAIN, MPI3_POINTER PTR_MPI3_SGE_CHAIN, + Mpi3SGEChain_t, MPI3_POINTER pMpi3SGEChain_t, + MPI3_SGE_LAST_CHAIN, MPI3_POINTER PTR_MPI3_SGE_LAST_CHAIN, + Mpi3SGELastChain_t, MPI3_POINTER pMpi3SGELastChain_t; + +/***************************************************************************** + * Bit Bucket scatter gather element * + ****************************************************************************/ +typedef struct _MPI3_SGE_BIT_BUCKET +{ + U64 Reserved00; /* 0x00 */ + U32 Length; /* 0x08 */ + U8 Reserved0C[3]; /* 0x0C */ + U8 Flags; /* 0x0F */ +} MPI3_SGE_BIT_BUCKET, MPI3_POINTER PTR_MPI3_SGE_BIT_BUCKET, + Mpi3SGEBitBucket_t, MPI3_POINTER pMpi3SGEBitBucket_t; + +/***************************************************************************** + * Extended EEDP scatter gather element * + ****************************************************************************/ +typedef struct _MPI3_SGE_EXTENDED_EEDP +{ + U8 UserDataSize; /* 0x00 */ + U8 Reserved01; /* 0x01 */ + U16 EEDPFlags; /* 0x02 */ + U32 SecondaryReferenceTag; /* 0x04 */ + U16 SecondaryApplicationTag; /* 0x08 */ + U16 ApplicationTagTranslationMask; /* 0x0A */ + U16 Reserved0C; /* 0x0C */ + U8 ExtendedOperation; /* 0x0E */ + U8 Flags; /* 0x0F */ +} MPI3_SGE_EXTENDED_EEDP, MPI3_POINTER PTR_MPI3_SGE_EXTENDED_EEDP, + Mpi3SGEExtendedEEDP_t, MPI3_POINTER pMpi3SGEExtendedEEDP_t; + +/***************************************************************************** + * Union of scatter gather elements * + ****************************************************************************/ +typedef union _MPI3_SGE_UNION +{ + MPI3_SGE_SIMPLE Simple; + MPI3_SGE_CHAIN Chain; + MPI3_SGE_LAST_CHAIN LastChain; + MPI3_SGE_BIT_BUCKET BitBucket; + MPI3_SGE_EXTENDED_EEDP Eedp; + U32 Words[4]; +} MPI3_SGE_UNION, MPI3_POINTER PTR_MPI3_SGE_UNION, + Mpi3SGEUnion_t, MPI3_POINTER pMpi3SGEUnion_t; + +/**** Definitions for the Flags field ****/ +#define MPI3_SGE_FLAGS_ELEMENT_TYPE_MASK (0xF0) +#define MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE (0x00) +#define MPI3_SGE_FLAGS_ELEMENT_TYPE_BIT_BUCKET (0x10) +#define MPI3_SGE_FLAGS_ELEMENT_TYPE_CHAIN (0x20) +#define MPI3_SGE_FLAGS_ELEMENT_TYPE_LAST_CHAIN (0x30) +#define MPI3_SGE_FLAGS_ELEMENT_TYPE_EXTENDED (0xF0) +#define MPI3_SGE_FLAGS_END_OF_LIST (0x08) +#define MPI3_SGE_FLAGS_END_OF_BUFFER (0x04) +#define MPI3_SGE_FLAGS_DLAS_MASK (0x03) +#define MPI3_SGE_FLAGS_DLAS_SYSTEM (0x00) +#define MPI3_SGE_FLAGS_DLAS_IOC_UDP (0x01) +#define MPI3_SGE_FLAGS_DLAS_IOC_CTL (0x02) + +/**** Definitions for the ExtendedOperation field of Extended element ****/ +#define MPI3_SGE_EXT_OPER_EEDP (0x00) + +/**** Definitions for the EEDPFlags field of Extended EEDP element ****/ +#define MPI3_EEDPFLAGS_INCR_PRI_REF_TAG (0x8000) +#define MPI3_EEDPFLAGS_INCR_SEC_REF_TAG (0x4000) +#define MPI3_EEDPFLAGS_INCR_PRI_APP_TAG (0x2000) +#define MPI3_EEDPFLAGS_INCR_SEC_APP_TAG (0x1000) +#define MPI3_EEDPFLAGS_ESC_PASSTHROUGH (0x0800) +#define MPI3_EEDPFLAGS_CHK_REF_TAG (0x0400) +#define MPI3_EEDPFLAGS_CHK_APP_TAG (0x0200) +#define MPI3_EEDPFLAGS_CHK_GUARD (0x0100) +#define MPI3_EEDPFLAGS_ESC_MODE_MASK (0x00C0) +#define MPI3_EEDPFLAGS_ESC_MODE_DO_NOT_DISABLE (0x0040) +#define MPI3_EEDPFLAGS_ESC_MODE_APPTAG_DISABLE (0x0080) +#define MPI3_EEDPFLAGS_ESC_MODE_APPTAG_REFTAG_DISABLE (0x00C0) +#define MPI3_EEDPFLAGS_HOST_GUARD_MASK (0x0030) +#define MPI3_EEDPFLAGS_HOST_GUARD_T10_CRC (0x0000) +#define MPI3_EEDPFLAGS_HOST_GUARD_IP_CHKSUM (0x0010) +#define MPI3_EEDPFLAGS_HOST_GUARD_OEM_SPECIFIC (0x0020) +#define MPI3_EEDPFLAGS_PT_REF_TAG (0x0008) +#define MPI3_EEDPFLAGS_EEDP_OP_MASK (0x0007) +#define MPI3_EEDPFLAGS_EEDP_OP_CHECK (0x0001) +#define MPI3_EEDPFLAGS_EEDP_OP_STRIP (0x0002) +#define MPI3_EEDPFLAGS_EEDP_OP_CHECK_REMOVE (0x0003) +#define MPI3_EEDPFLAGS_EEDP_OP_INSERT (0x0004) +#define MPI3_EEDPFLAGS_EEDP_OP_REPLACE (0x0006) +#define MPI3_EEDPFLAGS_EEDP_OP_CHECK_REGEN (0x0007) + +/**** Definitions for the UserDataSize field of Extended EEDP element ****/ +#define MPI3_EEDP_UDS_512 (0x01) +#define MPI3_EEDP_UDS_520 (0x02) +#define MPI3_EEDP_UDS_4080 (0x03) +#define MPI3_EEDP_UDS_4088 (0x04) +#define MPI3_EEDP_UDS_4096 (0x05) +#define MPI3_EEDP_UDS_4104 (0x06) +#define MPI3_EEDP_UDS_4160 (0x07) + +/***************************************************************************** + * Standard Message Structures * + ****************************************************************************/ + +/***************************************************************************** + * Request Message Header for all request messages * + ****************************************************************************/ +typedef struct _MPI3_REQUEST_HEADER +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 ChangeCount; /* 0x08 */ + U16 FunctionDependent; /* 0x0A */ +} MPI3_REQUEST_HEADER, MPI3_POINTER PTR_MPI3_REQUEST_HEADER, + Mpi3RequestHeader_t, MPI3_POINTER pMpi3RequestHeader_t; + +/***************************************************************************** + * Default Reply * + ****************************************************************************/ +typedef struct _MPI3_DEFAULT_REPLY +{ + U16 HostTag; /* 0x00 */ + U8 IOCUseOnly02; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 IOCUseOnly04; /* 0x04 */ + U8 IOCUseOnly06; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U16 IOCUseOnly08; /* 0x08 */ + U16 IOCStatus; /* 0x0A */ + U32 IOCLogInfo; /* 0x0C */ +} MPI3_DEFAULT_REPLY, MPI3_POINTER PTR_MPI3_DEFAULT_REPLY, + Mpi3DefaultReply_t, MPI3_POINTER pMpi3DefaultReply_t; + +/**** Defines for the HostTag field ****/ +#define MPI3_HOST_TAG_INVALID (0xFFFF) + +/**** Defines for message Function ****/ +/* I/O Controller functions */ +#define MPI3_FUNCTION_IOC_FACTS (0x01) /* IOC Facts */ +#define MPI3_FUNCTION_IOC_INIT (0x02) /* IOC Init */ +#define MPI3_FUNCTION_PORT_ENABLE (0x03) /* Port Enable */ +#define MPI3_FUNCTION_EVENT_NOTIFICATION (0x04) /* Event Notification */ +#define MPI3_FUNCTION_EVENT_ACK (0x05) /* Event Acknowledge */ +#define MPI3_FUNCTION_CI_DOWNLOAD (0x06) /* Component Image Download */ +#define MPI3_FUNCTION_CI_UPLOAD (0x07) /* Component Image Upload */ +#define MPI3_FUNCTION_IO_UNIT_CONTROL (0x08) /* IO Unit Control */ +#define MPI3_FUNCTION_PERSISTENT_EVENT_LOG (0x09) /* Persistent Event Log */ +#define MPI3_FUNCTION_MGMT_PASSTHROUGH (0x0A) /* Management Passthrough */ +#define MPI3_FUNCTION_CONFIG (0x10) /* Configuration */ + +/* SCSI Initiator I/O functions */ +#define MPI3_FUNCTION_SCSI_IO (0x20) /* SCSI IO */ +#define MPI3_FUNCTION_SCSI_TASK_MGMT (0x21) /* SCSI Task Management */ +#define MPI3_FUNCTION_SMP_PASSTHROUGH (0x22) /* SMP Passthrough */ +#define MPI3_FUNCTION_NVME_ENCAPSULATED (0x24) /* NVMe Encapsulated */ + +/* SCSI Target I/O functions */ +#define MPI3_FUNCTION_TARGET_ASSIST (0x30) /* Target Assist */ +#define MPI3_FUNCTION_TARGET_STATUS_SEND (0x31) /* Target Status Send */ +#define MPI3_FUNCTION_TARGET_MODE_ABORT (0x32) /* Target Mode Abort */ +#define MPI3_FUNCTION_TARGET_CMD_BUF_POST_BASE (0x33) /* Target Command Buffer Post Base */ +#define MPI3_FUNCTION_TARGET_CMD_BUF_POST_LIST (0x34) /* Target Command Buffer Post List */ + +/* Queue Management functions */ +#define MPI3_FUNCTION_CREATE_REQUEST_QUEUE (0x70) /* Create an operational request queue */ +#define MPI3_FUNCTION_DELETE_REQUEST_QUEUE (0x71) /* Delete an operational request queue */ +#define MPI3_FUNCTION_CREATE_REPLY_QUEUE (0x72) /* Create an operational reply queue */ +#define MPI3_FUNCTION_DELETE_REPLY_QUEUE (0x73) /* Delete an operational reply queue */ + +/* Diagnostic Tools */ +#define MPI3_FUNCTION_TOOLBOX (0x80) /* Toolbox */ +#define MPI3_FUNCTION_DIAG_BUFFER_POST (0x81) /* Post a Diagnostic Buffer to the I/O Unit */ +#define MPI3_FUNCTION_DIAG_BUFFER_MANAGE (0x82) /* Manage a Diagnostic Buffer */ +#define MPI3_FUNCTION_DIAG_BUFFER_UPLOAD (0x83) /* Upload a Diagnostic Buffer */ + +/* Miscellaneous functions */ +#define MPI3_FUNCTION_MIN_IOC_USE_ONLY (0xC0) /* Beginning of IOC Use Only range of function codes */ +#define MPI3_FUNCTION_MAX_IOC_USE_ONLY (0xEF) /* End of IOC Use Only range of function codes */ +#define MPI3_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) /* Beginning of the product-specific range of function codes */ +#define MPI3_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) /* End of the product-specific range of function codes */ + +/**** Defines for IOCStatus ****/ +#define MPI3_IOCSTATUS_LOG_INFO_AVAIL_MASK (0x8000) +#define MPI3_IOCSTATUS_LOG_INFO_AVAILABLE (0x8000) +#define MPI3_IOCSTATUS_STATUS_MASK (0x7FFF) + +/* Common IOCStatus values for all replies */ +#define MPI3_IOCSTATUS_SUCCESS (0x0000) +#define MPI3_IOCSTATUS_INVALID_FUNCTION (0x0001) +#define MPI3_IOCSTATUS_BUSY (0x0002) +#define MPI3_IOCSTATUS_INVALID_SGL (0x0003) +#define MPI3_IOCSTATUS_INTERNAL_ERROR (0x0004) +#define MPI3_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) +#define MPI3_IOCSTATUS_INVALID_FIELD (0x0007) +#define MPI3_IOCSTATUS_INVALID_STATE (0x0008) +#define MPI3_IOCSTATUS_INSUFFICIENT_POWER (0x000A) +#define MPI3_IOCSTATUS_INVALID_CHANGE_COUNT (0x000B) +#define MPI3_IOCSTATUS_ALLOWED_CMD_BLOCK (0x000C) +#define MPI3_IOCSTATUS_SUPERVISOR_ONLY (0x000D) +#define MPI3_IOCSTATUS_FAILURE (0x001F) + +/* Config IOCStatus values */ +#define MPI3_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) +#define MPI3_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) +#define MPI3_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) +#define MPI3_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) +#define MPI3_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) +#define MPI3_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) + +/* SCSI IO IOCStatus values */ +#define MPI3_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) +#define MPI3_IOCSTATUS_SCSI_TM_NOT_SUPPORTED (0x0041) +#define MPI3_IOCSTATUS_SCSI_INVALID_DEVHANDLE (0x0042) +#define MPI3_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) +#define MPI3_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) +#define MPI3_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) +#define MPI3_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) +#define MPI3_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) +#define MPI3_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) +#define MPI3_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) +#define MPI3_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A) +#define MPI3_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) +#define MPI3_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) + +/* SCSI Initiator and SCSI Target end-to-end data protection values */ +#define MPI3_IOCSTATUS_EEDP_GUARD_ERROR (0x004D) +#define MPI3_IOCSTATUS_EEDP_REF_TAG_ERROR (0x004E) +#define MPI3_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F) + +/* SCSI Target IOCStatus values */ +#define MPI3_IOCSTATUS_TARGET_INVALID_IO_INDEX (0x0062) +#define MPI3_IOCSTATUS_TARGET_ABORTED (0x0063) +#define MPI3_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064) +#define MPI3_IOCSTATUS_TARGET_NO_CONNECTION (0x0065) +#define MPI3_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A) +#define MPI3_IOCSTATUS_TARGET_DATA_OFFSET_ERROR (0x006D) +#define MPI3_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006E) +#define MPI3_IOCSTATUS_TARGET_IU_TOO_SHORT (0x006F) +#define MPI3_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT (0x0070) +#define MPI3_IOCSTATUS_TARGET_NAK_RECEIVED (0x0071) + +/* Serial Attached SCSI IOCStatus values */ +#define MPI3_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090) +#define MPI3_IOCSTATUS_SAS_SMP_DATA_OVERRUN (0x0091) + +/* Diagnostic Buffer Post/Release IOCStatus values */ +#define MPI3_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0) + +/* Component Image Upload/Download */ +#define MPI3_IOCSTATUS_CI_UNSUPPORTED (0x00B0) +#define MPI3_IOCSTATUS_CI_UPDATE_SEQUENCE (0x00B1) +#define MPI3_IOCSTATUS_CI_VALIDATION_FAILED (0x00B2) +#define MPI3_IOCSTATUS_CI_KEY_UPDATE_PENDING (0x00B3) +#define MPI3_IOCSTATUS_CI_KEY_UPDATE_NOT_POSSIBLE (0x00B4) + +/* Security values */ +#define MPI3_IOCSTATUS_SECURITY_KEY_REQUIRED (0x00C0) +#define MPI3_IOCSTATUS_SECURITY_VIOLATION (0x00C1) + +/* Request and Reply Queues related IOCStatus values */ +#define MPI3_IOCSTATUS_INVALID_QUEUE_ID (0x0F00) +#define MPI3_IOCSTATUS_INVALID_QUEUE_SIZE (0x0F01) +#define MPI3_IOCSTATUS_INVALID_MSIX_VECTOR (0x0F02) +#define MPI3_IOCSTATUS_INVALID_REPLY_QUEUE_ID (0x0F03) +#define MPI3_IOCSTATUS_INVALID_QUEUE_DELETION (0x0F04) + +/**** Defines for IOCLogInfo ****/ +#define MPI3_IOCLOGINFO_TYPE_MASK (0xF0000000) +#define MPI3_IOCLOGINFO_TYPE_SHIFT (28) +#define MPI3_IOCLOGINFO_TYPE_NONE (0x0) +#define MPI3_IOCLOGINFO_TYPE_SAS (0x3) +#define MPI3_IOCLOGINFO_LOG_DATA_MASK (0x0FFFFFFF) + +#endif /* MPI30_TRANSPORT_H */ + + diff --git a/sys/dev/mpi3mr/mpi/mpi30_type.h b/sys/dev/mpi3mr/mpi/mpi30_type.h new file mode 100644 index 000000000000..267ede701762 --- /dev/null +++ b/sys/dev/mpi3mr/mpi/mpi30_type.h @@ -0,0 +1,99 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2016-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + * + */ + +#ifndef MPI30_TYPE_H +#define MPI30_TYPE_H 1 + +/***************************************************************************** + * Define MPI3_POINTER if it has not already been defined. By default * + * MPI3_POINTER is defined to be a near pointer. MPI3_POINTER can be defined * + * as a far pointer by defining MPI3_POINTER as "far *" before this header * + * file is included. * + ****************************************************************************/ +#ifndef MPI3_POINTER +#define MPI3_POINTER * +#endif /* MPI3_POINTER */ + +/* The basic types may have already been included by mpi_type.h or mpi2_type.h */ +#if !defined(MPI_TYPE_H) && !defined(MPI2_TYPE_H) +/***************************************************************************** + * Basic Types * + ****************************************************************************/ +typedef int8_t S8; +typedef uint8_t U8; +typedef int16_t S16; +typedef uint16_t U16; +typedef int32_t S32; +typedef uint32_t U32; +typedef int64_t S64; +typedef uint64_t U64; + +/***************************************************************************** + * Structure Types * + ****************************************************************************/ +typedef struct _S64struct +{ + U32 Low; + S32 High; +} S64struct; + +typedef struct _U64struct +{ + U32 Low; + U32 High; +} U64struct; + +/***************************************************************************** + * Pointer Types * + ****************************************************************************/ +typedef S8 *PS8; +typedef U8 *PU8; +typedef S16 *PS16; +typedef U16 *PU16; +typedef S32 *PS32; +typedef U32 *PU32; +typedef S64 *PS64; +typedef U64 *PU64; +typedef S64struct *PS64struct; +typedef U64struct *PU64struct; +#endif /* MPI_TYPE_H && MPI2_TYPE_H */ + +#endif /* MPI30_TYPE_H */ diff --git a/sys/dev/mpi3mr/mpi3mr.c b/sys/dev/mpi3mr/mpi3mr.c new file mode 100644 index 000000000000..1c237d324c83 --- /dev/null +++ b/sys/dev/mpi3mr/mpi3mr.c @@ -0,0 +1,6101 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2016-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Authors: Sumit Saxena + * Chandrakanth Patil + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mpi3mr.h" +#include "mpi3mr_cam.h" +#include "mpi3mr_app.h" + +static void mpi3mr_repost_reply_buf(struct mpi3mr_softc *sc, + U64 reply_dma); +static int mpi3mr_complete_admin_cmd(struct mpi3mr_softc *sc); +static void mpi3mr_port_enable_complete(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *drvrcmd); +static void mpi3mr_flush_io(struct mpi3mr_softc *sc); +static int mpi3mr_issue_reset(struct mpi3mr_softc *sc, U16 reset_type, + U32 reset_reason); +static void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_softc *sc, U16 handle, + struct mpi3mr_drvr_cmd *cmdparam, U8 iou_rc); +static void mpi3mr_dev_rmhs_complete_iou(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *drv_cmd); +static void mpi3mr_dev_rmhs_complete_tm(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *drv_cmd); +static void mpi3mr_send_evt_ack(struct mpi3mr_softc *sc, U8 event, + struct mpi3mr_drvr_cmd *cmdparam, U32 event_ctx); +static void mpi3mr_print_fault_info(struct mpi3mr_softc *sc); +static inline void mpi3mr_set_diagsave(struct mpi3mr_softc *sc); +static const char *mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code); + +void +mpi3mr_hexdump(void *buf, int sz, int format) +{ + int i; + U32 *buf_loc = (U32 *)buf; + + for (i = 0; i < (sz / sizeof(U32)); i++) { + if ((i % format) == 0) { + if (i != 0) + printf("\n"); + printf("%08x: ", (i * 4)); + } + printf("%08x ", buf_loc[i]); + } + printf("\n"); +} + +void +init_completion(struct completion *completion) +{ + completion->done = 0; +} + +void +complete(struct completion *completion) +{ + completion->done = 1; + wakeup(complete); +} + +void wait_for_completion_timeout(struct completion *completion, + U32 timeout) +{ + U32 count = timeout * 1000; + + while ((completion->done == 0) && count) { + DELAY(1000); + count--; + } + + if (completion->done == 0) { + printf("%s: Command is timedout\n", __func__); + completion->done = 1; + } +} +void wait_for_completion_timeout_tm(struct completion *completion, + U32 timeout, struct mpi3mr_softc *sc) +{ + U32 count = timeout * 1000; + + while ((completion->done == 0) && count) { + msleep(&sc->tm_chan, &sc->mpi3mr_mtx, PRIBIO, + "TM command", 1 * hz); + count--; + } + + if (completion->done == 0) { + printf("%s: Command is timedout\n", __func__); + completion->done = 1; + } +} + + +void +poll_for_command_completion(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *cmd, U16 wait) +{ + int wait_time = wait * 1000; + while (wait_time) { + mpi3mr_complete_admin_cmd(sc); + if (cmd->state & MPI3MR_CMD_COMPLETE) + break; + DELAY(1000); + wait_time--; + } +} + +/** + * mpi3mr_trigger_snapdump - triggers firmware snapdump + * @sc: Adapter instance reference + * @reason_code: reason code for the fault. + * + * This routine will trigger the snapdump and wait for it to + * complete or timeout before it returns. + * This will be called during initilaization time faults/resets/timeouts + * before soft reset invocation. + * + * Return: None. + */ +static void +mpi3mr_trigger_snapdump(struct mpi3mr_softc *sc, U32 reason_code) +{ + U32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; + + mpi3mr_dprint(sc, MPI3MR_INFO, "snapdump triggered: reason code: %s\n", + mpi3mr_reset_rc_name(reason_code)); + + mpi3mr_set_diagsave(sc); + mpi3mr_issue_reset(sc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, + reason_code); + + do { + host_diagnostic = mpi3mr_regread(sc, MPI3_SYSIF_HOST_DIAG_OFFSET); + if (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS)) + break; + DELAY(100 * 1000); + } while (--timeout); + + return; +} + +/** + * mpi3mr_check_rh_fault_ioc - check reset history and fault + * controller + * @sc: Adapter instance reference + * @reason_code, reason code for the fault. + * + * This routine will fault the controller with + * the given reason code if it is not already in the fault or + * not asynchronosuly reset. This will be used to handle + * initilaization time faults/resets/timeout as in those cases + * immediate soft reset invocation is not required. + * + * Return: None. + */ +static void mpi3mr_check_rh_fault_ioc(struct mpi3mr_softc *sc, U32 reason_code) +{ + U32 ioc_status; + + if (sc->unrecoverable) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "controller is unrecoverable\n"); + return; + } + + ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET); + if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) || + (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) { + mpi3mr_print_fault_info(sc); + return; + } + + mpi3mr_trigger_snapdump(sc, reason_code); + + return; +} + +static void * mpi3mr_get_reply_virt_addr(struct mpi3mr_softc *sc, + bus_addr_t phys_addr) +{ + if (!phys_addr) + return NULL; + if ((phys_addr < sc->reply_buf_dma_min_address) || + (phys_addr > sc->reply_buf_dma_max_address)) + return NULL; + + return sc->reply_buf + (phys_addr - sc->reply_buf_phys); +} + +static void * mpi3mr_get_sensebuf_virt_addr(struct mpi3mr_softc *sc, + bus_addr_t phys_addr) +{ + if (!phys_addr) + return NULL; + return sc->sense_buf + (phys_addr - sc->sense_buf_phys); +} + +static void mpi3mr_repost_reply_buf(struct mpi3mr_softc *sc, + U64 reply_dma) +{ + U32 old_idx = 0; + + mtx_lock_spin(&sc->reply_free_q_lock); + old_idx = sc->reply_free_q_host_index; + sc->reply_free_q_host_index = ((sc->reply_free_q_host_index == + (sc->reply_free_q_sz - 1)) ? 0 : + (sc->reply_free_q_host_index + 1)); + sc->reply_free_q[old_idx] = reply_dma; + mpi3mr_regwrite(sc, MPI3_SYSIF_REPLY_FREE_HOST_INDEX_OFFSET, + sc->reply_free_q_host_index); + mtx_unlock_spin(&sc->reply_free_q_lock); +} + +static void mpi3mr_repost_sense_buf(struct mpi3mr_softc *sc, + U64 sense_buf_phys) +{ + U32 old_idx = 0; + + mtx_lock_spin(&sc->sense_buf_q_lock); + old_idx = sc->sense_buf_q_host_index; + sc->sense_buf_q_host_index = ((sc->sense_buf_q_host_index == + (sc->sense_buf_q_sz - 1)) ? 0 : + (sc->sense_buf_q_host_index + 1)); + sc->sense_buf_q[old_idx] = sense_buf_phys; + mpi3mr_regwrite(sc, MPI3_SYSIF_SENSE_BUF_FREE_HOST_INDEX_OFFSET, + sc->sense_buf_q_host_index); + mtx_unlock_spin(&sc->sense_buf_q_lock); + +} + +void mpi3mr_set_io_divert_for_all_vd_in_tg(struct mpi3mr_softc *sc, + struct mpi3mr_throttle_group_info *tg, U8 divert_value) +{ + struct mpi3mr_target *target; + + mtx_lock_spin(&sc->target_lock); + TAILQ_FOREACH(target, &sc->cam_sc->tgt_list, tgt_next) { + if (target->throttle_group == tg) + target->io_divert = divert_value; + } + mtx_unlock_spin(&sc->target_lock); +} + +/** + * mpi3mr_submit_admin_cmd - Submit request to admin queue + * @mrioc: Adapter reference + * @admin_req: MPI3 request + * @admin_req_sz: Request size + * + * Post the MPI3 request into admin request queue and + * inform the controller, if the queue is full return + * appropriate error. + * + * Return: 0 on success, non-zero on failure. + */ +int mpi3mr_submit_admin_cmd(struct mpi3mr_softc *sc, void *admin_req, + U16 admin_req_sz) +{ + U16 areq_pi = 0, areq_ci = 0, max_entries = 0; + int retval = 0; + U8 *areq_entry; + + mtx_lock_spin(&sc->admin_req_lock); + areq_pi = sc->admin_req_pi; + areq_ci = sc->admin_req_ci; + max_entries = sc->num_admin_reqs; + + if (sc->unrecoverable) + return -EFAULT; + + if ((areq_ci == (areq_pi + 1)) || ((!areq_ci) && + (areq_pi == (max_entries - 1)))) { + printf(IOCNAME "AdminReqQ full condition detected\n", + sc->name); + retval = -EAGAIN; + goto out; + } + areq_entry = (U8 *)sc->admin_req + (areq_pi * + MPI3MR_AREQ_FRAME_SZ); + memset(areq_entry, 0, MPI3MR_AREQ_FRAME_SZ); + memcpy(areq_entry, (U8 *)admin_req, admin_req_sz); + + if (++areq_pi == max_entries) + areq_pi = 0; + sc->admin_req_pi = areq_pi; + + mpi3mr_regwrite(sc, MPI3_SYSIF_ADMIN_REQ_Q_PI_OFFSET, sc->admin_req_pi); + +out: + mtx_unlock_spin(&sc->admin_req_lock); + return retval; +} + +/** + * mpi3mr_check_req_qfull - Check request queue is full or not + * @op_req_q: Operational reply queue info + * + * Return: true when queue full, false otherwise. + */ +static inline bool +mpi3mr_check_req_qfull(struct mpi3mr_op_req_queue *op_req_q) +{ + U16 pi, ci, max_entries; + bool is_qfull = false; + + pi = op_req_q->pi; + ci = op_req_q->ci; + max_entries = op_req_q->num_reqs; + + if ((ci == (pi + 1)) || ((!ci) && (pi == (max_entries - 1)))) + is_qfull = true; + + return is_qfull; +} + +/** + * mpi3mr_submit_io - Post IO command to firmware + * @sc: Adapter instance reference + * @op_req_q: Operational Request queue reference + * @req: MPT request data + * + * This function submits IO command to firmware. + * + * Return: Nothing + */ +int mpi3mr_submit_io(struct mpi3mr_softc *sc, + struct mpi3mr_op_req_queue *op_req_q, U8 *req) +{ + U16 pi, max_entries; + int retval = 0; + U8 *req_entry; + U16 req_sz = sc->facts.op_req_sz; + struct mpi3mr_irq_context *irq_ctx; + + mtx_lock_spin(&op_req_q->q_lock); + + pi = op_req_q->pi; + max_entries = op_req_q->num_reqs; + if (mpi3mr_check_req_qfull(op_req_q)) { + irq_ctx = &sc->irq_ctx[op_req_q->reply_qid - 1]; + mpi3mr_complete_io_cmd(sc, irq_ctx); + + if (mpi3mr_check_req_qfull(op_req_q)) { + printf(IOCNAME "OpReqQ full condition detected\n", + sc->name); + retval = -EBUSY; + goto out; + } + } + + req_entry = (U8 *)op_req_q->q_base + (pi * req_sz); + memset(req_entry, 0, req_sz); + memcpy(req_entry, req, MPI3MR_AREQ_FRAME_SZ); + if (++pi == max_entries) + pi = 0; + op_req_q->pi = pi; + + mpi3mr_atomic_inc(&sc->op_reply_q[op_req_q->reply_qid - 1].pend_ios); + + mpi3mr_regwrite(sc, MPI3_SYSIF_OPER_REQ_Q_N_PI_OFFSET(op_req_q->qid), op_req_q->pi); + if (sc->mpi3mr_debug & MPI3MR_TRACE) { + device_printf(sc->mpi3mr_dev, "IO submission: QID:%d PI:0x%x\n", op_req_q->qid, op_req_q->pi); + mpi3mr_hexdump(req_entry, MPI3MR_AREQ_FRAME_SZ, 8); + } + +out: + mtx_unlock_spin(&op_req_q->q_lock); + return retval; +} + +inline void +mpi3mr_add_sg_single(void *paddr, U8 flags, U32 length, + bus_addr_t dma_addr) +{ + Mpi3SGESimple_t *sgel = paddr; + + sgel->Flags = flags; + sgel->Length = (length); + sgel->Address = (U64)dma_addr; +} + +void mpi3mr_build_zero_len_sge(void *paddr) +{ + U8 sgl_flags = (MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | + MPI3_SGE_FLAGS_DLAS_SYSTEM | MPI3_SGE_FLAGS_END_OF_LIST); + + mpi3mr_add_sg_single(paddr, sgl_flags, 0, -1); + +} + +void mpi3mr_enable_interrupts(struct mpi3mr_softc *sc) +{ + sc->intr_enabled = 1; +} + +void mpi3mr_disable_interrupts(struct mpi3mr_softc *sc) +{ + sc->intr_enabled = 0; +} + +void +mpi3mr_memaddr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + bus_addr_t *addr; + + addr = arg; + *addr = segs[0].ds_addr; +} + +static int mpi3mr_delete_op_reply_queue(struct mpi3mr_softc *sc, U16 qid) +{ + Mpi3DeleteReplyQueueRequest_t delq_req; + struct mpi3mr_op_reply_queue *op_reply_q; + int retval = 0; + + + op_reply_q = &sc->op_reply_q[qid - 1]; + + if (!op_reply_q->qid) + { + retval = -1; + printf(IOCNAME "Issue DelRepQ: called with invalid Reply QID\n", + sc->name); + goto out; + } + + memset(&delq_req, 0, sizeof(delq_req)); + + mtx_lock(&sc->init_cmds.completion.lock); + if (sc->init_cmds.state & MPI3MR_CMD_PENDING) { + retval = -1; + printf(IOCNAME "Issue DelRepQ: Init command is in use\n", + sc->name); + mtx_unlock(&sc->init_cmds.completion.lock); + goto out; + } + + if (sc->init_cmds.state & MPI3MR_CMD_PENDING) { + retval = -1; + printf(IOCNAME "Issue DelRepQ: Init command is in use\n", + sc->name); + goto out; + } + sc->init_cmds.state = MPI3MR_CMD_PENDING; + sc->init_cmds.is_waiting = 1; + sc->init_cmds.callback = NULL; + delq_req.HostTag = MPI3MR_HOSTTAG_INITCMDS; + delq_req.Function = MPI3_FUNCTION_DELETE_REPLY_QUEUE; + delq_req.QueueID = qid; + + init_completion(&sc->init_cmds.completion); + retval = mpi3mr_submit_admin_cmd(sc, &delq_req, sizeof(delq_req)); + if (retval) { + printf(IOCNAME "Issue DelRepQ: Admin Post failed\n", + sc->name); + goto out_unlock; + } + wait_for_completion_timeout(&sc->init_cmds.completion, + (MPI3MR_INTADMCMD_TIMEOUT)); + if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { + printf(IOCNAME "Issue DelRepQ: command timed out\n", + sc->name); + mpi3mr_check_rh_fault_ioc(sc, + MPI3MR_RESET_FROM_DELREPQ_TIMEOUT); + sc->unrecoverable = 1; + + retval = -1; + goto out_unlock; + } + if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) + != MPI3_IOCSTATUS_SUCCESS ) { + printf(IOCNAME "Issue DelRepQ: Failed IOCStatus(0x%04x) " + " Loginfo(0x%08x) \n" , sc->name, + (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), + sc->init_cmds.ioc_loginfo); + retval = -1; + goto out_unlock; + } + sc->irq_ctx[qid - 1].op_reply_q = NULL; + + if (sc->op_reply_q[qid - 1].q_base_phys != 0) + bus_dmamap_unload(sc->op_reply_q[qid - 1].q_base_tag, sc->op_reply_q[qid - 1].q_base_dmamap); + if (sc->op_reply_q[qid - 1].q_base != NULL) + bus_dmamem_free(sc->op_reply_q[qid - 1].q_base_tag, sc->op_reply_q[qid - 1].q_base, sc->op_reply_q[qid - 1].q_base_dmamap); + if (sc->op_reply_q[qid - 1].q_base_tag != NULL) + bus_dma_tag_destroy(sc->op_reply_q[qid - 1].q_base_tag); + + sc->op_reply_q[qid - 1].q_base = NULL; + sc->op_reply_q[qid - 1].qid = 0; +out_unlock: + sc->init_cmds.state = MPI3MR_CMD_NOTUSED; + mtx_unlock(&sc->init_cmds.completion.lock); +out: + return retval; +} + +/** + * mpi3mr_create_op_reply_queue - create operational reply queue + * @sc: Adapter instance reference + * @qid: operational reply queue id + * + * Create operatinal reply queue by issuing MPI request + * through admin queue. + * + * Return: 0 on success, non-zero on failure. + */ +static int mpi3mr_create_op_reply_queue(struct mpi3mr_softc *sc, U16 qid) +{ + Mpi3CreateReplyQueueRequest_t create_req; + struct mpi3mr_op_reply_queue *op_reply_q; + int retval = 0; + char q_lock_name[32]; + + op_reply_q = &sc->op_reply_q[qid - 1]; + + if (op_reply_q->qid) + { + retval = -1; + printf(IOCNAME "CreateRepQ: called for duplicate qid %d\n", + sc->name, op_reply_q->qid); + return retval; + } + + op_reply_q->ci = 0; + if (pci_get_revid(sc->mpi3mr_dev) == SAS4116_CHIP_REV_A0) + op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD_A0; + else + op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD; + + op_reply_q->qsz = op_reply_q->num_replies * sc->op_reply_sz; + op_reply_q->ephase = 1; + + if (!op_reply_q->q_base) { + snprintf(q_lock_name, 32, "Reply Queue Lock[%d]", qid); + mtx_init(&op_reply_q->q_lock, q_lock_name, NULL, MTX_SPIN); + + if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ + 4, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + op_reply_q->qsz, /* maxsize */ + 1, /* nsegments */ + op_reply_q->qsz, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &op_reply_q->q_base_tag)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate Operational reply DMA tag\n"); + return (ENOMEM); + } + + if (bus_dmamem_alloc(op_reply_q->q_base_tag, (void **)&op_reply_q->q_base, + BUS_DMA_NOWAIT, &op_reply_q->q_base_dmamap)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n"); + return (ENOMEM); + } + bzero(op_reply_q->q_base, op_reply_q->qsz); + bus_dmamap_load(op_reply_q->q_base_tag, op_reply_q->q_base_dmamap, op_reply_q->q_base, op_reply_q->qsz, + mpi3mr_memaddr_cb, &op_reply_q->q_base_phys, 0); + mpi3mr_dprint(sc, MPI3MR_XINFO, "Operational Reply queue ID: %d phys addr= %#016jx virt_addr: %pa size= %d\n", + qid, (uintmax_t)op_reply_q->q_base_phys, op_reply_q->q_base, op_reply_q->qsz); + + if (!op_reply_q->q_base) + { + retval = -1; + printf(IOCNAME "CreateRepQ: memory alloc failed for qid %d\n", + sc->name, qid); + goto out; + } + } + + memset(&create_req, 0, sizeof(create_req)); + + mtx_lock(&sc->init_cmds.completion.lock); + if (sc->init_cmds.state & MPI3MR_CMD_PENDING) { + retval = -1; + printf(IOCNAME "CreateRepQ: Init command is in use\n", + sc->name); + mtx_unlock(&sc->init_cmds.completion.lock); + goto out; + } + + sc->init_cmds.state = MPI3MR_CMD_PENDING; + sc->init_cmds.is_waiting = 1; + sc->init_cmds.callback = NULL; + create_req.HostTag = MPI3MR_HOSTTAG_INITCMDS; + create_req.Function = MPI3_FUNCTION_CREATE_REPLY_QUEUE; + create_req.QueueID = qid; + create_req.Flags = MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE; + create_req.MSIxIndex = sc->irq_ctx[qid - 1].msix_index; + create_req.BaseAddress = (U64)op_reply_q->q_base_phys; + create_req.Size = op_reply_q->num_replies; + + init_completion(&sc->init_cmds.completion); + retval = mpi3mr_submit_admin_cmd(sc, &create_req, + sizeof(create_req)); + if (retval) { + printf(IOCNAME "CreateRepQ: Admin Post failed\n", + sc->name); + goto out_unlock; + } + + wait_for_completion_timeout(&sc->init_cmds.completion, + MPI3MR_INTADMCMD_TIMEOUT); + if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { + printf(IOCNAME "CreateRepQ: command timed out\n", + sc->name); + mpi3mr_check_rh_fault_ioc(sc, + MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT); + sc->unrecoverable = 1; + retval = -1; + goto out_unlock; + } + + if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) + != MPI3_IOCSTATUS_SUCCESS ) { + printf(IOCNAME "CreateRepQ: Failed IOCStatus(0x%04x) " + " Loginfo(0x%08x) \n" , sc->name, + (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), + sc->init_cmds.ioc_loginfo); + retval = -1; + goto out_unlock; + } + op_reply_q->qid = qid; + sc->irq_ctx[qid - 1].op_reply_q = op_reply_q; + +out_unlock: + sc->init_cmds.state = MPI3MR_CMD_NOTUSED; + mtx_unlock(&sc->init_cmds.completion.lock); +out: + if (retval) { + if (op_reply_q->q_base_phys != 0) + bus_dmamap_unload(op_reply_q->q_base_tag, op_reply_q->q_base_dmamap); + if (op_reply_q->q_base != NULL) + bus_dmamem_free(op_reply_q->q_base_tag, op_reply_q->q_base, op_reply_q->q_base_dmamap); + if (op_reply_q->q_base_tag != NULL) + bus_dma_tag_destroy(op_reply_q->q_base_tag); + op_reply_q->q_base = NULL; + op_reply_q->qid = 0; + } + + return retval; +} + +/** + * mpi3mr_create_op_req_queue - create operational request queue + * @sc: Adapter instance reference + * @req_qid: operational request queue id + * @reply_qid: Reply queue ID + * + * Create operatinal request queue by issuing MPI request + * through admin queue. + * + * Return: 0 on success, non-zero on failure. + */ +static int mpi3mr_create_op_req_queue(struct mpi3mr_softc *sc, U16 req_qid, U8 reply_qid) +{ + Mpi3CreateRequestQueueRequest_t create_req; + struct mpi3mr_op_req_queue *op_req_q; + int retval = 0; + char q_lock_name[32]; + + op_req_q = &sc->op_req_q[req_qid - 1]; + + if (op_req_q->qid) + { + retval = -1; + printf(IOCNAME "CreateReqQ: called for duplicate qid %d\n", + sc->name, op_req_q->qid); + return retval; + } + + op_req_q->ci = 0; + op_req_q->pi = 0; + op_req_q->num_reqs = MPI3MR_OP_REQ_Q_QD; + op_req_q->qsz = op_req_q->num_reqs * sc->facts.op_req_sz; + op_req_q->reply_qid = reply_qid; + + if (!op_req_q->q_base) { + snprintf(q_lock_name, 32, "Request Queue Lock[%d]", req_qid); + mtx_init(&op_req_q->q_lock, q_lock_name, NULL, MTX_SPIN); + + if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ + 4, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + op_req_q->qsz, /* maxsize */ + 1, /* nsegments */ + op_req_q->qsz, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &op_req_q->q_base_tag)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n"); + return (ENOMEM); + } + + if (bus_dmamem_alloc(op_req_q->q_base_tag, (void **)&op_req_q->q_base, + BUS_DMA_NOWAIT, &op_req_q->q_base_dmamap)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n"); + return (ENOMEM); + } + + bzero(op_req_q->q_base, op_req_q->qsz); + + bus_dmamap_load(op_req_q->q_base_tag, op_req_q->q_base_dmamap, op_req_q->q_base, op_req_q->qsz, + mpi3mr_memaddr_cb, &op_req_q->q_base_phys, 0); + + mpi3mr_dprint(sc, MPI3MR_XINFO, "Operational Request QID: %d phys addr= %#016jx virt addr= %pa size= %d associated Reply QID: %d\n", + req_qid, (uintmax_t)op_req_q->q_base_phys, op_req_q->q_base, op_req_q->qsz, reply_qid); + + if (!op_req_q->q_base) { + retval = -1; + printf(IOCNAME "CreateReqQ: memory alloc failed for qid %d\n", + sc->name, req_qid); + goto out; + } + } + + memset(&create_req, 0, sizeof(create_req)); + + mtx_lock(&sc->init_cmds.completion.lock); + if (sc->init_cmds.state & MPI3MR_CMD_PENDING) { + retval = -1; + printf(IOCNAME "CreateReqQ: Init command is in use\n", + sc->name); + mtx_unlock(&sc->init_cmds.completion.lock); + goto out; + } + + sc->init_cmds.state = MPI3MR_CMD_PENDING; + sc->init_cmds.is_waiting = 1; + sc->init_cmds.callback = NULL; + create_req.HostTag = MPI3MR_HOSTTAG_INITCMDS; + create_req.Function = MPI3_FUNCTION_CREATE_REQUEST_QUEUE; + create_req.QueueID = req_qid; + create_req.Flags = 0; + create_req.ReplyQueueID = reply_qid; + create_req.BaseAddress = (U64)op_req_q->q_base_phys; + create_req.Size = op_req_q->num_reqs; + + init_completion(&sc->init_cmds.completion); + retval = mpi3mr_submit_admin_cmd(sc, &create_req, + sizeof(create_req)); + if (retval) { + printf(IOCNAME "CreateReqQ: Admin Post failed\n", + sc->name); + goto out_unlock; + } + + wait_for_completion_timeout(&sc->init_cmds.completion, + (MPI3MR_INTADMCMD_TIMEOUT)); + + if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { + printf(IOCNAME "CreateReqQ: command timed out\n", + sc->name); + mpi3mr_check_rh_fault_ioc(sc, + MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT); + sc->unrecoverable = 1; + retval = -1; + goto out_unlock; + } + + if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) + != MPI3_IOCSTATUS_SUCCESS ) { + printf(IOCNAME "CreateReqQ: Failed IOCStatus(0x%04x) " + " Loginfo(0x%08x) \n" , sc->name, + (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), + sc->init_cmds.ioc_loginfo); + retval = -1; + goto out_unlock; + } + op_req_q->qid = req_qid; + +out_unlock: + sc->init_cmds.state = MPI3MR_CMD_NOTUSED; + mtx_unlock(&sc->init_cmds.completion.lock); +out: + if (retval) { + if (op_req_q->q_base_phys != 0) + bus_dmamap_unload(op_req_q->q_base_tag, op_req_q->q_base_dmamap); + if (op_req_q->q_base != NULL) + bus_dmamem_free(op_req_q->q_base_tag, op_req_q->q_base, op_req_q->q_base_dmamap); + if (op_req_q->q_base_tag != NULL) + bus_dma_tag_destroy(op_req_q->q_base_tag); + op_req_q->q_base = NULL; + op_req_q->qid = 0; + } + return retval; +} + +/** + * mpi3mr_create_op_queues - create operational queues + * @sc: Adapter instance reference + * + * Create operatinal queues(request queues and reply queues). + * Return: 0 on success, non-zero on failure. + */ +static int mpi3mr_create_op_queues(struct mpi3mr_softc *sc) +{ + int retval = 0; + U16 num_queues = 0, i = 0, qid; + + num_queues = min(sc->facts.max_op_reply_q, + sc->facts.max_op_req_q); + num_queues = min(num_queues, sc->msix_count); + + /* + * During reset set the num_queues to the number of queues + * that was set before the reset. + */ + if (sc->num_queues) + num_queues = sc->num_queues; + + mpi3mr_dprint(sc, MPI3MR_XINFO, "Trying to create %d Operational Q pairs\n", + num_queues); + + if (!sc->op_req_q) { + sc->op_req_q = malloc(sizeof(struct mpi3mr_op_req_queue) * + num_queues, M_MPI3MR, M_NOWAIT | M_ZERO); + + if (!sc->op_req_q) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to alloc memory for Request queue info\n"); + retval = -1; + goto out_failed; + } + } + + if (!sc->op_reply_q) { + sc->op_reply_q = malloc(sizeof(struct mpi3mr_op_reply_queue) * num_queues, + M_MPI3MR, M_NOWAIT | M_ZERO); + + if (!sc->op_reply_q) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to alloc memory for Reply queue info\n"); + retval = -1; + goto out_failed; + } + } + + sc->num_hosttag_op_req_q = (sc->max_host_ios + 1) / num_queues; + + /*Operational Request and reply queue ID starts with 1*/ + for (i = 0; i < num_queues; i++) { + qid = i + 1; + if (mpi3mr_create_op_reply_queue(sc, qid)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to create Reply queue %d\n", + qid); + break; + } + if (mpi3mr_create_op_req_queue(sc, qid, + sc->op_reply_q[qid - 1].qid)) { + mpi3mr_delete_op_reply_queue(sc, qid); + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to create Request queue %d\n", + qid); + break; + } + + } + + /* Not even one queue is created successfully*/ + if (i == 0) { + retval = -1; + goto out_failed; + } + + if (!sc->num_queues) { + sc->num_queues = i; + } else { + if (num_queues != i) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Number of queues (%d) post reset are not same as" + "queues allocated (%d) during driver init\n", i, num_queues); + goto out_failed; + } + } + + mpi3mr_dprint(sc, MPI3MR_INFO, "Successfully created %d Operational Queue pairs\n", + sc->num_queues); + mpi3mr_dprint(sc, MPI3MR_INFO, "Request Queue QD: %d Reply queue QD: %d\n", + sc->op_req_q[0].num_reqs, sc->op_reply_q[0].num_replies); + + return retval; +out_failed: + if (sc->op_req_q) { + free(sc->op_req_q, M_MPI3MR); + sc->op_req_q = NULL; + } + if (sc->op_reply_q) { + free(sc->op_reply_q, M_MPI3MR); + sc->op_reply_q = NULL; + } + return retval; +} + +/** + * mpi3mr_setup_admin_qpair - Setup admin queue pairs + * @sc: Adapter instance reference + * + * Allocation and setup admin queues(request queues and reply queues). + * Return: 0 on success, non-zero on failure. + */ +static int mpi3mr_setup_admin_qpair(struct mpi3mr_softc *sc) +{ + int retval = 0; + U32 num_adm_entries = 0; + + sc->admin_req_q_sz = MPI3MR_AREQQ_SIZE; + sc->num_admin_reqs = sc->admin_req_q_sz / MPI3MR_AREQ_FRAME_SZ; + sc->admin_req_ci = sc->admin_req_pi = 0; + + sc->admin_reply_q_sz = MPI3MR_AREPQ_SIZE; + sc->num_admin_replies = sc->admin_reply_q_sz/ MPI3MR_AREP_FRAME_SZ; + sc->admin_reply_ci = 0; + sc->admin_reply_ephase = 1; + + if (!sc->admin_req) { + if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ + 4, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + sc->admin_req_q_sz, /* maxsize */ + 1, /* nsegments */ + sc->admin_req_q_sz, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->admin_req_tag)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n"); + return (ENOMEM); + } + + if (bus_dmamem_alloc(sc->admin_req_tag, (void **)&sc->admin_req, + BUS_DMA_NOWAIT, &sc->admin_req_dmamap)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n"); + return (ENOMEM); + } + bzero(sc->admin_req, sc->admin_req_q_sz); + bus_dmamap_load(sc->admin_req_tag, sc->admin_req_dmamap, sc->admin_req, sc->admin_req_q_sz, + mpi3mr_memaddr_cb, &sc->admin_req_phys, 0); + mpi3mr_dprint(sc, MPI3MR_XINFO, "Admin Req queue phys addr= %#016jx size= %d\n", + (uintmax_t)sc->admin_req_phys, sc->admin_req_q_sz); + + if (!sc->admin_req) + { + retval = -1; + printf(IOCNAME "Memory alloc for AdminReqQ: failed\n", + sc->name); + goto out_failed; + } + } + + if (!sc->admin_reply) { + mtx_init(&sc->admin_reply_lock, "Admin Reply Queue Lock", NULL, MTX_SPIN); + + if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ + 4, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + sc->admin_reply_q_sz, /* maxsize */ + 1, /* nsegments */ + sc->admin_reply_q_sz, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->admin_reply_tag)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate reply DMA tag\n"); + return (ENOMEM); + } + + if (bus_dmamem_alloc(sc->admin_reply_tag, (void **)&sc->admin_reply, + BUS_DMA_NOWAIT, &sc->admin_reply_dmamap)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n"); + return (ENOMEM); + } + bzero(sc->admin_reply, sc->admin_reply_q_sz); + bus_dmamap_load(sc->admin_reply_tag, sc->admin_reply_dmamap, sc->admin_reply, sc->admin_reply_q_sz, + mpi3mr_memaddr_cb, &sc->admin_reply_phys, 0); + mpi3mr_dprint(sc, MPI3MR_XINFO, "Admin Reply queue phys addr= %#016jx size= %d\n", + (uintmax_t)sc->admin_reply_phys, sc->admin_req_q_sz); + + + if (!sc->admin_reply) + { + retval = -1; + printf(IOCNAME "Memory alloc for AdminRepQ: failed\n", + sc->name); + goto out_failed; + } + } + + num_adm_entries = (sc->num_admin_replies << 16) | + (sc->num_admin_reqs); + mpi3mr_regwrite(sc, MPI3_SYSIF_ADMIN_Q_NUM_ENTRIES_OFFSET, num_adm_entries); + mpi3mr_regwrite64(sc, MPI3_SYSIF_ADMIN_REQ_Q_ADDR_LOW_OFFSET, sc->admin_req_phys); + mpi3mr_regwrite64(sc, MPI3_SYSIF_ADMIN_REPLY_Q_ADDR_LOW_OFFSET, sc->admin_reply_phys); + mpi3mr_regwrite(sc, MPI3_SYSIF_ADMIN_REQ_Q_PI_OFFSET, sc->admin_req_pi); + mpi3mr_regwrite(sc, MPI3_SYSIF_ADMIN_REPLY_Q_CI_OFFSET, sc->admin_reply_ci); + + return retval; + +out_failed: + /* Free Admin reply*/ + if (sc->admin_reply_phys) + bus_dmamap_unload(sc->admin_reply_tag, sc->admin_reply_dmamap); + + if (sc->admin_reply != NULL) + bus_dmamem_free(sc->admin_reply_tag, sc->admin_reply, + sc->admin_reply_dmamap); + + if (sc->admin_reply_tag != NULL) + bus_dma_tag_destroy(sc->admin_reply_tag); + + /* Free Admin request*/ + if (sc->admin_req_phys) + bus_dmamap_unload(sc->admin_req_tag, sc->admin_req_dmamap); + + if (sc->admin_req != NULL) + bus_dmamem_free(sc->admin_req_tag, sc->admin_req, + sc->admin_req_dmamap); + + if (sc->admin_req_tag != NULL) + bus_dma_tag_destroy(sc->admin_req_tag); + + return retval; +} + +/** + * mpi3mr_print_fault_info - Display fault information + * @sc: Adapter instance reference + * + * Display the controller fault information if there is a + * controller fault. + * + * Return: Nothing. + */ +static void mpi3mr_print_fault_info(struct mpi3mr_softc *sc) +{ + U32 ioc_status, code, code1, code2, code3; + + ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET); + + if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) { + code = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_OFFSET) & + MPI3_SYSIF_FAULT_CODE_MASK; + code1 = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_INFO0_OFFSET); + code2 = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_INFO1_OFFSET); + code3 = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_INFO2_OFFSET); + printf(IOCNAME "fault codes 0x%04x:0x%04x:0x%04x:0x%04x\n", + sc->name, code, code1, code2, code3); + } +} + +enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_softc *sc) +{ + U32 ioc_status, ioc_control; + U8 ready, enabled; + + ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET); + ioc_control = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET); + + if(sc->unrecoverable) + return MRIOC_STATE_UNRECOVERABLE; + if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) + return MRIOC_STATE_FAULT; + + ready = (ioc_status & MPI3_SYSIF_IOC_STATUS_READY); + enabled = (ioc_control & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC); + + if (ready && enabled) + return MRIOC_STATE_READY; + if ((!ready) && (!enabled)) + return MRIOC_STATE_RESET; + if ((!ready) && (enabled)) + return MRIOC_STATE_BECOMING_READY; + + return MRIOC_STATE_RESET_REQUESTED; +} + +static inline void mpi3mr_clear_resethistory(struct mpi3mr_softc *sc) +{ + U32 ioc_status; + + ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET); + if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) + mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_STATUS_OFFSET, ioc_status); + +} + +/** + * mpi3mr_mur_ioc - Message unit Reset handler + * @sc: Adapter instance reference + * @reset_reason: Reset reason code + * + * Issue Message unit Reset to the controller and wait for it to + * be complete. + * + * Return: 0 on success, -1 on failure. + */ +static int mpi3mr_mur_ioc(struct mpi3mr_softc *sc, U32 reset_reason) +{ + U32 ioc_config, timeout, ioc_status; + int retval = -1; + + mpi3mr_dprint(sc, MPI3MR_INFO, "Issuing Message Unit Reset(MUR)\n"); + if (sc->unrecoverable) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "IOC is unrecoverable MUR not issued\n"); + return retval; + } + mpi3mr_clear_resethistory(sc); + mpi3mr_regwrite(sc, MPI3_SYSIF_SCRATCHPAD0_OFFSET, reset_reason); + ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET); + ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC; + mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET, ioc_config); + + timeout = MPI3MR_MUR_TIMEOUT * 10; + do { + ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET); + if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) { + mpi3mr_clear_resethistory(sc); + ioc_config = + mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET); + if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) || + (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) || + (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) { + retval = 0; + break; + } + } + DELAY(100 * 1000); + } while (--timeout); + + ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET); + ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET); + + mpi3mr_dprint(sc, MPI3MR_INFO, "IOC Status/Config after %s MUR is (0x%x)/(0x%x)\n", + !retval ? "successful":"failed", ioc_status, ioc_config); + return retval; +} + +/** + * mpi3mr_bring_ioc_ready - Bring controller to ready state + * @sc: Adapter instance reference + * + * Set Enable IOC bit in IOC configuration register and wait for + * the controller to become ready. + * + * Return: 0 on success, appropriate error on failure. + */ +static int mpi3mr_bring_ioc_ready(struct mpi3mr_softc *sc) +{ + U32 ioc_config, timeout; + enum mpi3mr_iocstate current_state; + + ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET); + ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC; + mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET, ioc_config); + + timeout = sc->ready_timeout * 10; + do { + current_state = mpi3mr_get_iocstate(sc); + if (current_state == MRIOC_STATE_READY) + return 0; + DELAY(100 * 1000); + } while (--timeout); + + return -1; +} + +static const struct { + enum mpi3mr_iocstate value; + char *name; +} mrioc_states[] = { + { MRIOC_STATE_READY, "ready" }, + { MRIOC_STATE_FAULT, "fault" }, + { MRIOC_STATE_RESET, "reset" }, + { MRIOC_STATE_BECOMING_READY, "becoming ready" }, + { MRIOC_STATE_RESET_REQUESTED, "reset requested" }, + { MRIOC_STATE_COUNT, "Count" }, +}; + +static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state) +{ + int i; + char *name = NULL; + + for (i = 0; i < MRIOC_STATE_COUNT; i++) { + if (mrioc_states[i].value == mrioc_state){ + name = mrioc_states[i].name; + break; + } + } + return name; +} + +/* Reset reason to name mapper structure*/ +static const struct { + enum mpi3mr_reset_reason value; + char *name; +} mpi3mr_reset_reason_codes[] = { + { MPI3MR_RESET_FROM_BRINGUP, "timeout in bringup" }, + { MPI3MR_RESET_FROM_FAULT_WATCH, "fault" }, + { MPI3MR_RESET_FROM_IOCTL, "application" }, + { MPI3MR_RESET_FROM_EH_HOS, "error handling" }, + { MPI3MR_RESET_FROM_TM_TIMEOUT, "TM timeout" }, + { MPI3MR_RESET_FROM_IOCTL_TIMEOUT, "IOCTL timeout" }, + { MPI3MR_RESET_FROM_SCSIIO_TIMEOUT, "SCSIIO timeout" }, + { MPI3MR_RESET_FROM_MUR_FAILURE, "MUR failure" }, + { MPI3MR_RESET_FROM_CTLR_CLEANUP, "timeout in controller cleanup" }, + { MPI3MR_RESET_FROM_CIACTIV_FAULT, "component image activation fault" }, + { MPI3MR_RESET_FROM_PE_TIMEOUT, "port enable timeout" }, + { MPI3MR_RESET_FROM_TSU_TIMEOUT, "time stamp update timeout" }, + { MPI3MR_RESET_FROM_DELREQQ_TIMEOUT, "delete request queue timeout" }, + { MPI3MR_RESET_FROM_DELREPQ_TIMEOUT, "delete reply queue timeout" }, + { + MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT, + "create request queue timeout" + }, + { + MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT, + "create reply queue timeout" + }, + { MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT, "IOC facts timeout" }, + { MPI3MR_RESET_FROM_IOCINIT_TIMEOUT, "IOC init timeout" }, + { MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT, "event notify timeout" }, + { MPI3MR_RESET_FROM_EVTACK_TIMEOUT, "event acknowledgment timeout" }, + { + MPI3MR_RESET_FROM_CIACTVRST_TIMER, + "component image activation timeout" + }, + { + MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT, + "get package version timeout" + }, + { + MPI3MR_RESET_FROM_PELABORT_TIMEOUT, + "persistent event log abort timeout" + }, + { MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" }, + { MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" }, + { + MPI3MR_RESET_FROM_DIAG_BUFFER_POST_TIMEOUT, + "diagnostic buffer post timeout" + }, + { MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronus reset" }, + { MPI3MR_RESET_REASON_COUNT, "Reset reason count" }, +}; + +/** + * mpi3mr_reset_rc_name - get reset reason code name + * @reason_code: reset reason code value + * + * Map reset reason to an NULL terminated ASCII string + * + * Return: Name corresponding to reset reason value or NULL. + */ +static const char *mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code) +{ + int i; + char *name = NULL; + + for (i = 0; i < MPI3MR_RESET_REASON_COUNT; i++) { + if (mpi3mr_reset_reason_codes[i].value == reason_code) { + name = mpi3mr_reset_reason_codes[i].name; + break; + } + } + return name; +} + +#define MAX_RESET_TYPE 3 +/* Reset type to name mapper structure*/ +static const struct { + U16 reset_type; + char *name; +} mpi3mr_reset_types[] = { + { MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, "soft" }, + { MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, "diag fault" }, + { MAX_RESET_TYPE, "count"} +}; + +/** + * mpi3mr_reset_type_name - get reset type name + * @reset_type: reset type value + * + * Map reset type to an NULL terminated ASCII string + * + * Return: Name corresponding to reset type value or NULL. + */ +static const char *mpi3mr_reset_type_name(U16 reset_type) +{ + int i; + char *name = NULL; + + for (i = 0; i < MAX_RESET_TYPE; i++) { + if (mpi3mr_reset_types[i].reset_type == reset_type) { + name = mpi3mr_reset_types[i].name; + break; + } + } + return name; +} + +/** + * mpi3mr_soft_reset_success - Check softreset is success or not + * @ioc_status: IOC status register value + * @ioc_config: IOC config register value + * + * Check whether the soft reset is successful or not based on + * IOC status and IOC config register values. + * + * Return: True when the soft reset is success, false otherwise. + */ +static inline bool +mpi3mr_soft_reset_success(U32 ioc_status, U32 ioc_config) +{ + if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) || + (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) || + (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) + return true; + return false; +} + +/** + * mpi3mr_diagfault_success - Check diag fault is success or not + * @sc: Adapter reference + * @ioc_status: IOC status register value + * + * Check whether the controller hit diag reset fault code. + * + * Return: True when there is diag fault, false otherwise. + */ +static inline bool mpi3mr_diagfault_success(struct mpi3mr_softc *sc, + U32 ioc_status) +{ + U32 fault; + + if (!(ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) + return false; + fault = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_OFFSET) & MPI3_SYSIF_FAULT_CODE_MASK; + if (fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) + return true; + return false; +} + +/** + * mpi3mr_issue_iocfacts - Send IOC Facts + * @sc: Adapter instance reference + * @facts_data: Cached IOC facts data + * + * Issue IOC Facts MPI request through admin queue and wait for + * the completion of it or time out. + * + * Return: 0 on success, non-zero on failures. + */ +static int mpi3mr_issue_iocfacts(struct mpi3mr_softc *sc, + Mpi3IOCFactsData_t *facts_data) +{ + Mpi3IOCFactsRequest_t iocfacts_req; + bus_dma_tag_t data_tag = NULL; + bus_dmamap_t data_map = NULL; + bus_addr_t data_phys = 0; + void *data = NULL; + U32 data_len = sizeof(*facts_data); + int retval = 0; + + U8 sgl_flags = (MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | + MPI3_SGE_FLAGS_DLAS_SYSTEM | + MPI3_SGE_FLAGS_END_OF_LIST); + + + if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ + 4, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + data_len, /* maxsize */ + 1, /* nsegments */ + data_len, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &data_tag)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n"); + return (ENOMEM); + } + + if (bus_dmamem_alloc(data_tag, (void **)&data, + BUS_DMA_NOWAIT, &data_map)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d Data DMA mem alloc failed\n", + __func__, __LINE__); + return (ENOMEM); + } + + bzero(data, data_len); + bus_dmamap_load(data_tag, data_map, data, data_len, + mpi3mr_memaddr_cb, &data_phys, 0); + mpi3mr_dprint(sc, MPI3MR_XINFO, "Func: %s line: %d IOCfacts data phys addr= %#016jx size= %d\n", + __func__, __LINE__, (uintmax_t)data_phys, data_len); + + if (!data) + { + retval = -1; + printf(IOCNAME "Memory alloc for IOCFactsData: failed\n", + sc->name); + goto out; + } + + mtx_lock(&sc->init_cmds.completion.lock); + memset(&iocfacts_req, 0, sizeof(iocfacts_req)); + + if (sc->init_cmds.state & MPI3MR_CMD_PENDING) { + retval = -1; + printf(IOCNAME "Issue IOCFacts: Init command is in use\n", + sc->name); + mtx_unlock(&sc->init_cmds.completion.lock); + goto out; + } + + sc->init_cmds.state = MPI3MR_CMD_PENDING; + sc->init_cmds.is_waiting = 1; + sc->init_cmds.callback = NULL; + iocfacts_req.HostTag = (MPI3MR_HOSTTAG_INITCMDS); + iocfacts_req.Function = MPI3_FUNCTION_IOC_FACTS; + + mpi3mr_add_sg_single(&iocfacts_req.SGL, sgl_flags, data_len, + data_phys); + + init_completion(&sc->init_cmds.completion); + + retval = mpi3mr_submit_admin_cmd(sc, &iocfacts_req, + sizeof(iocfacts_req)); + + if (retval) { + printf(IOCNAME "Issue IOCFacts: Admin Post failed\n", + sc->name); + goto out_unlock; + } + + wait_for_completion_timeout(&sc->init_cmds.completion, + (MPI3MR_INTADMCMD_TIMEOUT)); + if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { + printf(IOCNAME "Issue IOCFacts: command timed out\n", + sc->name); + mpi3mr_check_rh_fault_ioc(sc, + MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT); + sc->unrecoverable = 1; + retval = -1; + goto out_unlock; + } + + if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) + != MPI3_IOCSTATUS_SUCCESS ) { + printf(IOCNAME "Issue IOCFacts: Failed IOCStatus(0x%04x) " + " Loginfo(0x%08x) \n" , sc->name, + (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), + sc->init_cmds.ioc_loginfo); + retval = -1; + goto out_unlock; + } + + memcpy(facts_data, (U8 *)data, data_len); +out_unlock: + sc->init_cmds.state = MPI3MR_CMD_NOTUSED; + mtx_unlock(&sc->init_cmds.completion.lock); + +out: + if (data_phys != 0) + bus_dmamap_unload(data_tag, data_map); + if (data != NULL) + bus_dmamem_free(data_tag, data, data_map); + if (data_tag != NULL) + bus_dma_tag_destroy(data_tag); + return retval; +} + +/** + * mpi3mr_process_factsdata - Process IOC facts data + * @sc: Adapter instance reference + * @facts_data: Cached IOC facts data + * + * Convert IOC facts data into cpu endianness and cache it in + * the driver . + * + * Return: Nothing. + */ +static int mpi3mr_process_factsdata(struct mpi3mr_softc *sc, + Mpi3IOCFactsData_t *facts_data) +{ + int retval = 0; + U32 ioc_config, req_sz, facts_flags; + + if (le16toh(facts_data->IOCFactsDataLength) != + (sizeof(*facts_data) / 4)) { + mpi3mr_dprint(sc, MPI3MR_INFO, "IOCFacts data length mismatch " + " driver_sz(%ld) firmware_sz(%d) \n", + sizeof(*facts_data), + facts_data->IOCFactsDataLength); + } + + ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET); + req_sz = 1 << ((ioc_config & MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ) >> + MPI3_SYSIF_IOC_CONFIG_OPER_REQ_ENT_SZ_SHIFT); + + if (facts_data->IOCRequestFrameSize != (req_sz/4)) { + mpi3mr_dprint(sc, MPI3MR_INFO, "IOCFacts data reqFrameSize mismatch " + " hw_size(%d) firmware_sz(%d) \n" , req_sz/4, + facts_data->IOCRequestFrameSize); + } + + memset(&sc->facts, 0, sizeof(sc->facts)); + + facts_flags = le32toh(facts_data->Flags); + sc->facts.op_req_sz = req_sz; + sc->op_reply_sz = 1 << ((ioc_config & + MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ) >> + MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT); + + sc->facts.ioc_num = facts_data->IOCNumber; + sc->facts.who_init = facts_data->WhoInit; + sc->facts.max_msix_vectors = facts_data->MaxMSIxVectors; + sc->facts.personality = (facts_flags & + MPI3_IOCFACTS_FLAGS_PERSONALITY_MASK); + sc->facts.dma_mask = (facts_flags & + MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >> + MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT; + sc->facts.protocol_flags = facts_data->ProtocolFlags; + sc->facts.mpi_version = (facts_data->MPIVersion.Word); + sc->facts.max_reqs = (facts_data->MaxOutstandingRequests); + sc->facts.product_id = (facts_data->ProductID); + sc->facts.reply_sz = (facts_data->ReplyFrameSize) * 4; + sc->facts.exceptions = (facts_data->IOCExceptions); + sc->facts.max_perids = (facts_data->MaxPersistentID); + sc->facts.max_vds = (facts_data->MaxVDs); + sc->facts.max_hpds = (facts_data->MaxHostPDs); + sc->facts.max_advhpds = (facts_data->MaxAdvHostPDs); + sc->facts.max_raidpds = (facts_data->MaxRAIDPDs); + sc->facts.max_nvme = (facts_data->MaxNVMe); + sc->facts.max_pcieswitches = + (facts_data->MaxPCIeSwitches); + sc->facts.max_sasexpanders = + (facts_data->MaxSASExpanders); + sc->facts.max_sasinitiators = + (facts_data->MaxSASInitiators); + sc->facts.max_enclosures = (facts_data->MaxEnclosures); + sc->facts.min_devhandle = (facts_data->MinDevHandle); + sc->facts.max_devhandle = (facts_data->MaxDevHandle); + sc->facts.max_op_req_q = + (facts_data->MaxOperationalRequestQueues); + sc->facts.max_op_reply_q = + (facts_data->MaxOperationalReplyQueues); + sc->facts.ioc_capabilities = + (facts_data->IOCCapabilities); + sc->facts.fw_ver.build_num = + (facts_data->FWVersion.BuildNum); + sc->facts.fw_ver.cust_id = + (facts_data->FWVersion.CustomerID); + sc->facts.fw_ver.ph_minor = facts_data->FWVersion.PhaseMinor; + sc->facts.fw_ver.ph_major = facts_data->FWVersion.PhaseMajor; + sc->facts.fw_ver.gen_minor = facts_data->FWVersion.GenMinor; + sc->facts.fw_ver.gen_major = facts_data->FWVersion.GenMajor; + sc->max_msix_vectors = min(sc->max_msix_vectors, + sc->facts.max_msix_vectors); + sc->facts.sge_mod_mask = facts_data->SGEModifierMask; + sc->facts.sge_mod_value = facts_data->SGEModifierValue; + sc->facts.sge_mod_shift = facts_data->SGEModifierShift; + sc->facts.shutdown_timeout = + (facts_data->ShutdownTimeout); + sc->facts.max_dev_per_tg = facts_data->MaxDevicesPerThrottleGroup; + sc->facts.io_throttle_data_length = + facts_data->IOThrottleDataLength; + sc->facts.max_io_throttle_group = + facts_data->MaxIOThrottleGroup; + sc->facts.io_throttle_low = facts_data->IOThrottleLow; + sc->facts.io_throttle_high = facts_data->IOThrottleHigh; + + /*Store in 512b block count*/ + if (sc->facts.io_throttle_data_length) + sc->io_throttle_data_length = + (sc->facts.io_throttle_data_length * 2 * 4); + else + /* set the length to 1MB + 1K to disable throttle*/ + sc->io_throttle_data_length = MPI3MR_MAX_SECTORS + 2; + + sc->io_throttle_high = (sc->facts.io_throttle_high * 2 * 1024); + sc->io_throttle_low = (sc->facts.io_throttle_low * 2 * 1024); + + mpi3mr_dprint(sc, MPI3MR_INFO, "ioc_num(%d), maxopQ(%d), maxopRepQ(%d), maxdh(%d)," + "maxreqs(%d), mindh(%d) maxPDs(%d) maxvectors(%d) maxperids(%d)\n", + sc->facts.ioc_num, sc->facts.max_op_req_q, + sc->facts.max_op_reply_q, sc->facts.max_devhandle, + sc->facts.max_reqs, sc->facts.min_devhandle, + sc->facts.max_pds, sc->facts.max_msix_vectors, + sc->facts.max_perids); + mpi3mr_dprint(sc, MPI3MR_INFO, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x\n", + sc->facts.sge_mod_mask, sc->facts.sge_mod_value, + sc->facts.sge_mod_shift); + mpi3mr_dprint(sc, MPI3MR_INFO, + "max_dev_per_throttle_group(%d), max_throttle_groups(%d), io_throttle_data_len(%dKiB), io_throttle_high(%dMiB), io_throttle_low(%dMiB)\n", + sc->facts.max_dev_per_tg, sc->facts.max_io_throttle_group, + sc->facts.io_throttle_data_length * 4, + sc->facts.io_throttle_high, sc->facts.io_throttle_low); + + sc->max_host_ios = sc->facts.max_reqs - + (MPI3MR_INTERNALCMDS_RESVD + 1); + + return retval; +} + +static inline void mpi3mr_setup_reply_free_queues(struct mpi3mr_softc *sc) +{ + int i; + bus_addr_t phys_addr; + + /* initialize Reply buffer Queue */ + for (i = 0, phys_addr = sc->reply_buf_phys; + i < sc->num_reply_bufs; i++, phys_addr += sc->reply_sz) + sc->reply_free_q[i] = phys_addr; + sc->reply_free_q[i] = (0); + + /* initialize Sense Buffer Queue */ + for (i = 0, phys_addr = sc->sense_buf_phys; + i < sc->num_sense_bufs; i++, phys_addr += MPI3MR_SENSEBUF_SZ) + sc->sense_buf_q[i] = phys_addr; + sc->sense_buf_q[i] = (0); + +} + +static int mpi3mr_reply_dma_alloc(struct mpi3mr_softc *sc) +{ + U32 sz; + + sc->num_reply_bufs = sc->facts.max_reqs + MPI3MR_NUM_EVTREPLIES; + sc->reply_free_q_sz = sc->num_reply_bufs + 1; + sc->num_sense_bufs = sc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR; + sc->sense_buf_q_sz = sc->num_sense_bufs + 1; + + sz = sc->num_reply_bufs * sc->reply_sz; + + if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ + 16, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + sz, /* maxsize */ + 1, /* nsegments */ + sz, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->reply_buf_tag)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n"); + return (ENOMEM); + } + + if (bus_dmamem_alloc(sc->reply_buf_tag, (void **)&sc->reply_buf, + BUS_DMA_NOWAIT, &sc->reply_buf_dmamap)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d DMA mem alloc failed\n", + __func__, __LINE__); + return (ENOMEM); + } + + bzero(sc->reply_buf, sz); + bus_dmamap_load(sc->reply_buf_tag, sc->reply_buf_dmamap, sc->reply_buf, sz, + mpi3mr_memaddr_cb, &sc->reply_buf_phys, 0); + + sc->reply_buf_dma_min_address = sc->reply_buf_phys; + sc->reply_buf_dma_max_address = sc->reply_buf_phys + sz; + mpi3mr_dprint(sc, MPI3MR_XINFO, "reply buf (0x%p): depth(%d), frame_size(%d), " + "pool_size(%d kB), reply_buf_dma(0x%llx)\n", + sc->reply_buf, sc->num_reply_bufs, sc->reply_sz, + (sz / 1024), (unsigned long long)sc->reply_buf_phys); + + /* reply free queue, 8 byte align */ + sz = sc->reply_free_q_sz * 8; + + if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ + 8, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + sz, /* maxsize */ + 1, /* nsegments */ + sz, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->reply_free_q_tag)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate reply free queue DMA tag\n"); + return (ENOMEM); + } + + if (bus_dmamem_alloc(sc->reply_free_q_tag, (void **)&sc->reply_free_q, + BUS_DMA_NOWAIT, &sc->reply_free_q_dmamap)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d DMA mem alloc failed\n", + __func__, __LINE__); + return (ENOMEM); + } + + bzero(sc->reply_free_q, sz); + bus_dmamap_load(sc->reply_free_q_tag, sc->reply_free_q_dmamap, sc->reply_free_q, sz, + mpi3mr_memaddr_cb, &sc->reply_free_q_phys, 0); + + mpi3mr_dprint(sc, MPI3MR_XINFO, "reply_free_q (0x%p): depth(%d), frame_size(%d), " + "pool_size(%d kB), reply_free_q_dma(0x%llx)\n", + sc->reply_free_q, sc->reply_free_q_sz, 8, (sz / 1024), + (unsigned long long)sc->reply_free_q_phys); + + /* sense buffer pool, 4 byte align */ + sz = sc->num_sense_bufs * MPI3MR_SENSEBUF_SZ; + + if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ + 4, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + sz, /* maxsize */ + 1, /* nsegments */ + sz, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->sense_buf_tag)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate Sense buffer DMA tag\n"); + return (ENOMEM); + } + + if (bus_dmamem_alloc(sc->sense_buf_tag, (void **)&sc->sense_buf, + BUS_DMA_NOWAIT, &sc->sense_buf_dmamap)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d DMA mem alloc failed\n", + __func__, __LINE__); + return (ENOMEM); + } + + bzero(sc->sense_buf, sz); + bus_dmamap_load(sc->sense_buf_tag, sc->sense_buf_dmamap, sc->sense_buf, sz, + mpi3mr_memaddr_cb, &sc->sense_buf_phys, 0); + + mpi3mr_dprint(sc, MPI3MR_XINFO, "sense_buf (0x%p): depth(%d), frame_size(%d), " + "pool_size(%d kB), sense_dma(0x%llx)\n", + sc->sense_buf, sc->num_sense_bufs, MPI3MR_SENSEBUF_SZ, + (sz / 1024), (unsigned long long)sc->sense_buf_phys); + + /* sense buffer queue, 8 byte align */ + sz = sc->sense_buf_q_sz * 8; + + if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ + 8, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + sz, /* maxsize */ + 1, /* nsegments */ + sz, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->sense_buf_q_tag)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate Sense buffer Queue DMA tag\n"); + return (ENOMEM); + } + + if (bus_dmamem_alloc(sc->sense_buf_q_tag, (void **)&sc->sense_buf_q, + BUS_DMA_NOWAIT, &sc->sense_buf_q_dmamap)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d DMA mem alloc failed\n", + __func__, __LINE__); + return (ENOMEM); + } + + bzero(sc->sense_buf_q, sz); + bus_dmamap_load(sc->sense_buf_q_tag, sc->sense_buf_q_dmamap, sc->sense_buf_q, sz, + mpi3mr_memaddr_cb, &sc->sense_buf_q_phys, 0); + + mpi3mr_dprint(sc, MPI3MR_XINFO, "sense_buf_q (0x%p): depth(%d), frame_size(%d), " + "pool_size(%d kB), sense_dma(0x%llx)\n", + sc->sense_buf_q, sc->sense_buf_q_sz, 8, (sz / 1024), + (unsigned long long)sc->sense_buf_q_phys); + + return 0; +} + +static int mpi3mr_reply_alloc(struct mpi3mr_softc *sc) +{ + int retval = 0; + U32 i; + + if (sc->init_cmds.reply) + goto post_reply_sbuf; + + sc->init_cmds.reply = malloc(sc->reply_sz, + M_MPI3MR, M_NOWAIT | M_ZERO); + + if (!sc->init_cmds.reply) { + printf(IOCNAME "Cannot allocate memory for init_cmds.reply\n", + sc->name); + goto out_failed; + } + + sc->ioctl_cmds.reply = malloc(sc->reply_sz, M_MPI3MR, M_NOWAIT | M_ZERO); + if (!sc->ioctl_cmds.reply) { + printf(IOCNAME "Cannot allocate memory for ioctl_cmds.reply\n", + sc->name); + goto out_failed; + } + + sc->host_tm_cmds.reply = malloc(sc->reply_sz, M_MPI3MR, M_NOWAIT | M_ZERO); + if (!sc->host_tm_cmds.reply) { + printf(IOCNAME "Cannot allocate memory for host_tm.reply\n", + sc->name); + goto out_failed; + } + for (i=0; idev_rmhs_cmds[i].reply = malloc(sc->reply_sz, + M_MPI3MR, M_NOWAIT | M_ZERO); + if (!sc->dev_rmhs_cmds[i].reply) { + printf(IOCNAME "Cannot allocate memory for" + " dev_rmhs_cmd[%d].reply\n", + sc->name, i); + goto out_failed; + } + } + + for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) { + sc->evtack_cmds[i].reply = malloc(sc->reply_sz, + M_MPI3MR, M_NOWAIT | M_ZERO); + if (!sc->evtack_cmds[i].reply) + goto out_failed; + } + + sc->dev_handle_bitmap_sz = MPI3MR_DIV_ROUND_UP(sc->facts.max_devhandle, 8); + + sc->removepend_bitmap = malloc(sc->dev_handle_bitmap_sz, + M_MPI3MR, M_NOWAIT | M_ZERO); + if (!sc->removepend_bitmap) { + printf(IOCNAME "Cannot alloc memory for remove pend bitmap\n", + sc->name); + goto out_failed; + } + + sc->devrem_bitmap_sz = MPI3MR_DIV_ROUND_UP(MPI3MR_NUM_DEVRMCMD, 8); + sc->devrem_bitmap = malloc(sc->devrem_bitmap_sz, + M_MPI3MR, M_NOWAIT | M_ZERO); + if (!sc->devrem_bitmap) { + printf(IOCNAME "Cannot alloc memory for dev remove bitmap\n", + sc->name); + goto out_failed; + } + + sc->evtack_cmds_bitmap_sz = MPI3MR_DIV_ROUND_UP(MPI3MR_NUM_EVTACKCMD, 8); + + sc->evtack_cmds_bitmap = malloc(sc->evtack_cmds_bitmap_sz, + M_MPI3MR, M_NOWAIT | M_ZERO); + if (!sc->evtack_cmds_bitmap) + goto out_failed; + + if (mpi3mr_reply_dma_alloc(sc)) { + printf(IOCNAME "func:%s line:%d DMA memory allocation failed\n", + sc->name, __func__, __LINE__); + goto out_failed; + } + +post_reply_sbuf: + mpi3mr_setup_reply_free_queues(sc); + return retval; +out_failed: + mpi3mr_cleanup_interrupts(sc); + mpi3mr_free_mem(sc); + retval = -1; + return retval; +} + +static void +mpi3mr_print_fw_pkg_ver(struct mpi3mr_softc *sc) +{ + int retval = 0; + void *fw_pkg_ver = NULL; + bus_dma_tag_t fw_pkg_ver_tag; + bus_dmamap_t fw_pkg_ver_map; + bus_addr_t fw_pkg_ver_dma; + Mpi3CIUploadRequest_t ci_upload; + Mpi3ComponentImageHeader_t *ci_header; + U32 fw_pkg_ver_len = sizeof(*ci_header); + U8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; + + if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ + 4, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + fw_pkg_ver_len, /* maxsize */ + 1, /* nsegments */ + fw_pkg_ver_len, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &fw_pkg_ver_tag)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate fw package version request DMA tag\n"); + return; + } + + if (bus_dmamem_alloc(fw_pkg_ver_tag, (void **)&fw_pkg_ver, BUS_DMA_NOWAIT, &fw_pkg_ver_map)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d fw package version DMA mem alloc failed\n", + __func__, __LINE__); + return; + } + + bzero(fw_pkg_ver, fw_pkg_ver_len); + + bus_dmamap_load(fw_pkg_ver_tag, fw_pkg_ver_map, fw_pkg_ver, fw_pkg_ver_len, mpi3mr_memaddr_cb, &fw_pkg_ver_dma, 0); + + mpi3mr_dprint(sc, MPI3MR_XINFO, "Func: %s line: %d fw package version phys addr= %#016jx size= %d\n", + __func__, __LINE__, (uintmax_t)fw_pkg_ver_dma, fw_pkg_ver_len); + + if (!fw_pkg_ver) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Memory alloc for fw package version failed\n"); + goto out; + } + + memset(&ci_upload, 0, sizeof(ci_upload)); + mtx_lock(&sc->init_cmds.completion.lock); + if (sc->init_cmds.state & MPI3MR_CMD_PENDING) { + mpi3mr_dprint(sc, MPI3MR_INFO,"Issue CI Header Upload: command is in use\n"); + mtx_unlock(&sc->init_cmds.completion.lock); + goto out; + } + sc->init_cmds.state = MPI3MR_CMD_PENDING; + sc->init_cmds.is_waiting = 1; + sc->init_cmds.callback = NULL; + ci_upload.HostTag = htole16(MPI3MR_HOSTTAG_INITCMDS); + ci_upload.Function = MPI3_FUNCTION_CI_UPLOAD; + ci_upload.MsgFlags = MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_PRIMARY; + ci_upload.ImageOffset = MPI3_IMAGE_HEADER_SIGNATURE0_OFFSET; + ci_upload.SegmentSize = MPI3_IMAGE_HEADER_SIZE; + + mpi3mr_add_sg_single(&ci_upload.SGL, sgl_flags, fw_pkg_ver_len, + fw_pkg_ver_dma); + + init_completion(&sc->init_cmds.completion); + if ((retval = mpi3mr_submit_admin_cmd(sc, &ci_upload, sizeof(ci_upload)))) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Issue CI Header Upload: Admin Post failed\n"); + goto out_unlock; + } + wait_for_completion_timeout(&sc->init_cmds.completion, + (MPI3MR_INTADMCMD_TIMEOUT)); + if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Issue CI Header Upload: command timed out\n"); + sc->init_cmds.is_waiting = 0; + if (!(sc->init_cmds.state & MPI3MR_CMD_RESET)) + mpi3mr_check_rh_fault_ioc(sc, + MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT); + goto out_unlock; + } + if ((GET_IOC_STATUS(sc->init_cmds.ioc_status)) != MPI3_IOCSTATUS_SUCCESS) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "Issue CI Header Upload: Failed IOCStatus(0x%04x) Loginfo(0x%08x)\n", + GET_IOC_STATUS(sc->init_cmds.ioc_status), sc->init_cmds.ioc_loginfo); + goto out_unlock; + } + + ci_header = (Mpi3ComponentImageHeader_t *) fw_pkg_ver; + mpi3mr_dprint(sc, MPI3MR_XINFO, + "Issue CI Header Upload:EnvVariableOffset(0x%x) \ + HeaderSize(0x%x) Signature1(0x%x)\n", + ci_header->EnvironmentVariableOffset, + ci_header->HeaderSize, + ci_header->Signature1); + mpi3mr_dprint(sc, MPI3MR_INFO, "FW Package Version: %02d.%02d.%02d.%02d\n", + ci_header->ComponentImageVersion.GenMajor, + ci_header->ComponentImageVersion.GenMinor, + ci_header->ComponentImageVersion.PhaseMajor, + ci_header->ComponentImageVersion.PhaseMinor); +out_unlock: + sc->init_cmds.state = MPI3MR_CMD_NOTUSED; + mtx_unlock(&sc->init_cmds.completion.lock); + +out: + if (fw_pkg_ver_dma != 0) + bus_dmamap_unload(fw_pkg_ver_tag, fw_pkg_ver_map); + if (fw_pkg_ver) + bus_dmamem_free(fw_pkg_ver_tag, fw_pkg_ver, fw_pkg_ver_map); + if (fw_pkg_ver_tag) + bus_dma_tag_destroy(fw_pkg_ver_tag); + +} + +/** + * mpi3mr_issue_iocinit - Send IOC Init + * @sc: Adapter instance reference + * + * Issue IOC Init MPI request through admin queue and wait for + * the completion of it or time out. + * + * Return: 0 on success, non-zero on failures. + */ +static int mpi3mr_issue_iocinit(struct mpi3mr_softc *sc) +{ + Mpi3IOCInitRequest_t iocinit_req; + Mpi3DriverInfoLayout_t *drvr_info = NULL; + bus_dma_tag_t drvr_info_tag; + bus_dmamap_t drvr_info_map; + bus_addr_t drvr_info_phys; + U32 drvr_info_len = sizeof(*drvr_info); + int retval = 0; + struct timeval now; + uint64_t time_in_msec; + + if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ + 4, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + drvr_info_len, /* maxsize */ + 1, /* nsegments */ + drvr_info_len, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &drvr_info_tag)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n"); + return (ENOMEM); + } + + if (bus_dmamem_alloc(drvr_info_tag, (void **)&drvr_info, + BUS_DMA_NOWAIT, &drvr_info_map)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d Data DMA mem alloc failed\n", + __func__, __LINE__); + return (ENOMEM); + } + + bzero(drvr_info, drvr_info_len); + bus_dmamap_load(drvr_info_tag, drvr_info_map, drvr_info, drvr_info_len, + mpi3mr_memaddr_cb, &drvr_info_phys, 0); + mpi3mr_dprint(sc, MPI3MR_XINFO, "Func: %s line: %d IOCfacts drvr_info phys addr= %#016jx size= %d\n", + __func__, __LINE__, (uintmax_t)drvr_info_phys, drvr_info_len); + + if (!drvr_info) + { + retval = -1; + printf(IOCNAME "Memory alloc for Driver Info failed\n", + sc->name); + goto out; + } + drvr_info->InformationLength = (drvr_info_len); + strcpy(drvr_info->DriverSignature, "Broadcom"); + strcpy(drvr_info->OsName, "FreeBSD"); + strcpy(drvr_info->OsVersion, fmt_os_ver); + strcpy(drvr_info->DriverName, MPI3MR_DRIVER_NAME); + strcpy(drvr_info->DriverVersion, MPI3MR_DRIVER_VERSION); + strcpy(drvr_info->DriverReleaseDate, MPI3MR_DRIVER_RELDATE); + drvr_info->DriverCapabilities = 0; + memcpy((U8 *)&sc->driver_info, (U8 *)drvr_info, sizeof(sc->driver_info)); + + memset(&iocinit_req, 0, sizeof(iocinit_req)); + mtx_lock(&sc->init_cmds.completion.lock); + if (sc->init_cmds.state & MPI3MR_CMD_PENDING) { + retval = -1; + printf(IOCNAME "Issue IOCInit: Init command is in use\n", + sc->name); + mtx_unlock(&sc->init_cmds.completion.lock); + goto out; + } + sc->init_cmds.state = MPI3MR_CMD_PENDING; + sc->init_cmds.is_waiting = 1; + sc->init_cmds.callback = NULL; + iocinit_req.HostTag = MPI3MR_HOSTTAG_INITCMDS; + iocinit_req.Function = MPI3_FUNCTION_IOC_INIT; + iocinit_req.MPIVersion.Struct.Dev = MPI3_VERSION_DEV; + iocinit_req.MPIVersion.Struct.Unit = MPI3_VERSION_UNIT; + iocinit_req.MPIVersion.Struct.Major = MPI3_VERSION_MAJOR; + iocinit_req.MPIVersion.Struct.Minor = MPI3_VERSION_MINOR; + iocinit_req.WhoInit = MPI3_WHOINIT_HOST_DRIVER; + iocinit_req.ReplyFreeQueueDepth = sc->reply_free_q_sz; + iocinit_req.ReplyFreeQueueAddress = + sc->reply_free_q_phys; + iocinit_req.SenseBufferLength = MPI3MR_SENSEBUF_SZ; + iocinit_req.SenseBufferFreeQueueDepth = + sc->sense_buf_q_sz; + iocinit_req.SenseBufferFreeQueueAddress = + sc->sense_buf_q_phys; + iocinit_req.DriverInformationAddress = drvr_info_phys; + + getmicrotime(&now); + time_in_msec = (now.tv_sec * 1000 + now.tv_usec/1000); + iocinit_req.TimeStamp = htole64(time_in_msec); + + init_completion(&sc->init_cmds.completion); + retval = mpi3mr_submit_admin_cmd(sc, &iocinit_req, + sizeof(iocinit_req)); + + if (retval) { + printf(IOCNAME "Issue IOCInit: Admin Post failed\n", + sc->name); + goto out_unlock; + } + + wait_for_completion_timeout(&sc->init_cmds.completion, + (MPI3MR_INTADMCMD_TIMEOUT)); + if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { + printf(IOCNAME "Issue IOCInit: command timed out\n", + sc->name); + mpi3mr_check_rh_fault_ioc(sc, + MPI3MR_RESET_FROM_IOCINIT_TIMEOUT); + sc->unrecoverable = 1; + retval = -1; + goto out_unlock; + } + + if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) + != MPI3_IOCSTATUS_SUCCESS ) { + printf(IOCNAME "Issue IOCInit: Failed IOCStatus(0x%04x) " + " Loginfo(0x%08x) \n" , sc->name, + (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), + sc->init_cmds.ioc_loginfo); + retval = -1; + goto out_unlock; + } + +out_unlock: + sc->init_cmds.state = MPI3MR_CMD_NOTUSED; + mtx_unlock(&sc->init_cmds.completion.lock); + +out: + if (drvr_info_phys != 0) + bus_dmamap_unload(drvr_info_tag, drvr_info_map); + if (drvr_info != NULL) + bus_dmamem_free(drvr_info_tag, drvr_info, drvr_info_map); + if (drvr_info_tag != NULL) + bus_dma_tag_destroy(drvr_info_tag); + return retval; +} + +static void +mpi3mr_display_ioc_info(struct mpi3mr_softc *sc) +{ + int i = 0; + char personality[16]; + struct mpi3mr_compimg_ver *fwver = &sc->facts.fw_ver; + + switch (sc->facts.personality) { + case MPI3_IOCFACTS_FLAGS_PERSONALITY_EHBA: + strcpy(personality, "Enhanced HBA"); + break; + case MPI3_IOCFACTS_FLAGS_PERSONALITY_RAID_DDR: + strcpy(personality, "RAID"); + break; + default: + strcpy(personality, "Unknown"); + break; + } + + mpi3mr_dprint(sc, MPI3MR_INFO, "Current Personality: %s\n", personality); + + mpi3mr_dprint(sc, MPI3MR_INFO, "FW Version: %d.%d.%d.%d.%05d-%05d\n", + fwver->gen_major, fwver->gen_minor, fwver->ph_major, + fwver->ph_minor, fwver->cust_id, fwver->build_num); + + mpi3mr_dprint(sc, MPI3MR_INFO, "Protocol=("); + + if (sc->facts.protocol_flags & + MPI3_IOCFACTS_PROTOCOL_SCSI_INITIATOR) { + printf("Initiator"); + i++; + } + + if (sc->facts.protocol_flags & + MPI3_IOCFACTS_PROTOCOL_SCSI_TARGET) { + printf("%sTarget", i ? "," : ""); + i++; + } + + if (sc->facts.protocol_flags & + MPI3_IOCFACTS_PROTOCOL_NVME) { + printf("%sNVMe attachment", i ? "," : ""); + i++; + } + i = 0; + printf("), "); + printf("Capabilities=("); + + if (sc->facts.ioc_capabilities & + MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE) { + printf("RAID"); + i++; + } + + printf(")\n"); +} + +/** + * mpi3mr_unmask_events - Unmask events in event mask bitmap + * @sc: Adapter instance reference + * @event: MPI event ID + * + * Un mask the specific event by resetting the event_mask + * bitmap. + * + * Return: None. + */ +static void mpi3mr_unmask_events(struct mpi3mr_softc *sc, U16 event) +{ + U32 desired_event; + + if (event >= 128) + return; + + desired_event = (1 << (event % 32)); + + if (event < 32) + sc->event_masks[0] &= ~desired_event; + else if (event < 64) + sc->event_masks[1] &= ~desired_event; + else if (event < 96) + sc->event_masks[2] &= ~desired_event; + else if (event < 128) + sc->event_masks[3] &= ~desired_event; +} + +static void mpi3mr_set_events_mask(struct mpi3mr_softc *sc) +{ + int i; + for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) + sc->event_masks[i] = -1; + + mpi3mr_unmask_events(sc, MPI3_EVENT_DEVICE_ADDED); + mpi3mr_unmask_events(sc, MPI3_EVENT_DEVICE_INFO_CHANGED); + mpi3mr_unmask_events(sc, MPI3_EVENT_DEVICE_STATUS_CHANGE); + + mpi3mr_unmask_events(sc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE); + + mpi3mr_unmask_events(sc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST); + mpi3mr_unmask_events(sc, MPI3_EVENT_SAS_DISCOVERY); + mpi3mr_unmask_events(sc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR); + mpi3mr_unmask_events(sc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE); + + mpi3mr_unmask_events(sc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST); + mpi3mr_unmask_events(sc, MPI3_EVENT_PCIE_ENUMERATION); + + mpi3mr_unmask_events(sc, MPI3_EVENT_PREPARE_FOR_RESET); + mpi3mr_unmask_events(sc, MPI3_EVENT_CABLE_MGMT); + mpi3mr_unmask_events(sc, MPI3_EVENT_ENERGY_PACK_CHANGE); +} + +/** + * mpi3mr_issue_event_notification - Send event notification + * @sc: Adapter instance reference + * + * Issue event notification MPI request through admin queue and + * wait for the completion of it or time out. + * + * Return: 0 on success, non-zero on failures. + */ +int mpi3mr_issue_event_notification(struct mpi3mr_softc *sc) +{ + Mpi3EventNotificationRequest_t evtnotify_req; + int retval = 0; + U8 i; + + memset(&evtnotify_req, 0, sizeof(evtnotify_req)); + mtx_lock(&sc->init_cmds.completion.lock); + if (sc->init_cmds.state & MPI3MR_CMD_PENDING) { + retval = -1; + printf(IOCNAME "Issue EvtNotify: Init command is in use\n", + sc->name); + mtx_unlock(&sc->init_cmds.completion.lock); + goto out; + } + sc->init_cmds.state = MPI3MR_CMD_PENDING; + sc->init_cmds.is_waiting = 1; + sc->init_cmds.callback = NULL; + evtnotify_req.HostTag = (MPI3MR_HOSTTAG_INITCMDS); + evtnotify_req.Function = MPI3_FUNCTION_EVENT_NOTIFICATION; + for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) + evtnotify_req.EventMasks[i] = + (sc->event_masks[i]); + init_completion(&sc->init_cmds.completion); + retval = mpi3mr_submit_admin_cmd(sc, &evtnotify_req, + sizeof(evtnotify_req)); + if (retval) { + printf(IOCNAME "Issue EvtNotify: Admin Post failed\n", + sc->name); + goto out_unlock; + } + + poll_for_command_completion(sc, + &sc->init_cmds, + (MPI3MR_INTADMCMD_TIMEOUT)); + if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { + printf(IOCNAME "Issue EvtNotify: command timed out\n", + sc->name); + mpi3mr_check_rh_fault_ioc(sc, + MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT); + retval = -1; + goto out_unlock; + } + + if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) + != MPI3_IOCSTATUS_SUCCESS ) { + printf(IOCNAME "Issue EvtNotify: Failed IOCStatus(0x%04x) " + " Loginfo(0x%08x) \n" , sc->name, + (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), + sc->init_cmds.ioc_loginfo); + retval = -1; + goto out_unlock; + } + +out_unlock: + sc->init_cmds.state = MPI3MR_CMD_NOTUSED; + mtx_unlock(&sc->init_cmds.completion.lock); + +out: + return retval; +} + +int +mpi3mr_register_events(struct mpi3mr_softc *sc) +{ + int error; + + mpi3mr_set_events_mask(sc); + + error = mpi3mr_issue_event_notification(sc); + + if (error) { + printf(IOCNAME "Failed to issue event notification %d\n", + sc->name, error); + } + + return error; +} + +/** + * mpi3mr_process_event_ack - Process event acknowledgment + * @sc: Adapter instance reference + * @event: MPI3 event ID + * @event_ctx: Event context + * + * Send event acknowledgement through admin queue and wait for + * it to complete. + * + * Return: 0 on success, non-zero on failures. + */ +int mpi3mr_process_event_ack(struct mpi3mr_softc *sc, U8 event, + U32 event_ctx) +{ + Mpi3EventAckRequest_t evtack_req; + int retval = 0; + + memset(&evtack_req, 0, sizeof(evtack_req)); + mtx_lock(&sc->init_cmds.completion.lock); + if (sc->init_cmds.state & MPI3MR_CMD_PENDING) { + retval = -1; + printf(IOCNAME "Issue EvtAck: Init command is in use\n", + sc->name); + mtx_unlock(&sc->init_cmds.completion.lock); + goto out; + } + sc->init_cmds.state = MPI3MR_CMD_PENDING; + sc->init_cmds.is_waiting = 1; + sc->init_cmds.callback = NULL; + evtack_req.HostTag = htole16(MPI3MR_HOSTTAG_INITCMDS); + evtack_req.Function = MPI3_FUNCTION_EVENT_ACK; + evtack_req.Event = event; + evtack_req.EventContext = htole32(event_ctx); + + init_completion(&sc->init_cmds.completion); + retval = mpi3mr_submit_admin_cmd(sc, &evtack_req, + sizeof(evtack_req)); + if (retval) { + printf(IOCNAME "Issue EvtAck: Admin Post failed\n", + sc->name); + goto out_unlock; + } + + wait_for_completion_timeout(&sc->init_cmds.completion, + (MPI3MR_INTADMCMD_TIMEOUT)); + if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { + printf(IOCNAME "Issue EvtAck: command timed out\n", + sc->name); + retval = -1; + goto out_unlock; + } + + if ((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) + != MPI3_IOCSTATUS_SUCCESS ) { + printf(IOCNAME "Issue EvtAck: Failed IOCStatus(0x%04x) " + " Loginfo(0x%08x) \n" , sc->name, + (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), + sc->init_cmds.ioc_loginfo); + retval = -1; + goto out_unlock; + } + +out_unlock: + sc->init_cmds.state = MPI3MR_CMD_NOTUSED; + mtx_unlock(&sc->init_cmds.completion.lock); + +out: + return retval; +} + + +static int mpi3mr_alloc_chain_bufs(struct mpi3mr_softc *sc) +{ + int retval = 0; + U32 sz, i; + U16 num_chains; + + num_chains = sc->max_host_ios; + + sc->chain_buf_count = num_chains; + sz = sizeof(struct mpi3mr_chain) * num_chains; + + sc->chain_sgl_list = malloc(sz, M_MPI3MR, M_NOWAIT | M_ZERO); + + if (!sc->chain_sgl_list) { + printf(IOCNAME "Cannot allocate memory for chain SGL list\n", + sc->name); + retval = -1; + goto out_failed; + } + + sz = MPI3MR_CHAINSGE_SIZE; + + if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ + 4096, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + sz, /* maxsize */ + 1, /* nsegments */ + sz, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->chain_sgl_list_tag)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate Chain buffer DMA tag\n"); + return (ENOMEM); + } + + for (i = 0; i < num_chains; i++) { + if (bus_dmamem_alloc(sc->chain_sgl_list_tag, (void **)&sc->chain_sgl_list[i].buf, + BUS_DMA_NOWAIT, &sc->chain_sgl_list[i].buf_dmamap)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Func: %s line: %d DMA mem alloc failed\n", + __func__, __LINE__); + return (ENOMEM); + } + + bzero(sc->chain_sgl_list[i].buf, sz); + bus_dmamap_load(sc->chain_sgl_list_tag, sc->chain_sgl_list[i].buf_dmamap, sc->chain_sgl_list[i].buf, sz, + mpi3mr_memaddr_cb, &sc->chain_sgl_list[i].buf_phys, 0); + mpi3mr_dprint(sc, MPI3MR_XINFO, "Func: %s line: %d phys addr= %#016jx size= %d\n", + __func__, __LINE__, (uintmax_t)sc->chain_sgl_list[i].buf_phys, sz); + } + + sc->chain_bitmap_sz = MPI3MR_DIV_ROUND_UP(num_chains, 8); + + sc->chain_bitmap = malloc(sc->chain_bitmap_sz, M_MPI3MR, M_NOWAIT | M_ZERO); + if (!sc->chain_bitmap) { + mpi3mr_dprint(sc, MPI3MR_INFO, "Cannot alloc memory for chain bitmap\n"); + retval = -1; + goto out_failed; + } + return retval; + +out_failed: + for (i = 0; i < num_chains; i++) { + if (sc->chain_sgl_list[i].buf_phys != 0) + bus_dmamap_unload(sc->chain_sgl_list_tag, sc->chain_sgl_list[i].buf_dmamap); + if (sc->chain_sgl_list[i].buf != NULL) + bus_dmamem_free(sc->chain_sgl_list_tag, sc->chain_sgl_list[i].buf, sc->chain_sgl_list[i].buf_dmamap); + } + if (sc->chain_sgl_list_tag != NULL) + bus_dma_tag_destroy(sc->chain_sgl_list_tag); + return retval; +} + +static int mpi3mr_pel_alloc(struct mpi3mr_softc *sc) +{ + int retval = 0; + + if (!sc->pel_cmds.reply) { + sc->pel_cmds.reply = malloc(sc->reply_sz, M_MPI3MR, M_NOWAIT | M_ZERO); + if (!sc->pel_cmds.reply) { + printf(IOCNAME "Cannot allocate memory for pel_cmds.reply\n", + sc->name); + goto out_failed; + } + } + + if (!sc->pel_abort_cmd.reply) { + sc->pel_abort_cmd.reply = malloc(sc->reply_sz, M_MPI3MR, M_NOWAIT | M_ZERO); + if (!sc->pel_abort_cmd.reply) { + printf(IOCNAME "Cannot allocate memory for pel_abort_cmd.reply\n", + sc->name); + goto out_failed; + } + } + + if (!sc->pel_seq_number) { + sc->pel_seq_number_sz = sizeof(Mpi3PELSeq_t); + if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ + 4, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + sc->pel_seq_number_sz, /* maxsize */ + 1, /* nsegments */ + sc->pel_seq_number_sz, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->pel_seq_num_dmatag)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot create PEL seq number dma memory tag\n"); + retval = -ENOMEM; + goto out_failed; + } + + if (bus_dmamem_alloc(sc->pel_seq_num_dmatag, (void **)&sc->pel_seq_number, + BUS_DMA_NOWAIT, &sc->pel_seq_num_dmamap)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate PEL seq number kernel buffer dma memory\n"); + retval = -ENOMEM; + goto out_failed; + } + + bzero(sc->pel_seq_number, sc->pel_seq_number_sz); + + bus_dmamap_load(sc->pel_seq_num_dmatag, sc->pel_seq_num_dmamap, sc->pel_seq_number, + sc->pel_seq_number_sz, mpi3mr_memaddr_cb, &sc->pel_seq_number_dma, 0); + + if (!sc->pel_seq_number) { + printf(IOCNAME "%s:%d Cannot load PEL seq number dma memory for size: %d\n", sc->name, + __func__, __LINE__, sc->pel_seq_number_sz); + retval = -ENOMEM; + goto out_failed; + } + } + +out_failed: + return retval; +} + +/** + * mpi3mr_validate_fw_update - validate IOCFacts post adapter reset + * @sc: Adapter instance reference + * + * Return zero if the new IOCFacts is compatible with previous values + * else return appropriate error + */ +static int +mpi3mr_validate_fw_update(struct mpi3mr_softc *sc) +{ + U16 dev_handle_bitmap_sz; + U8 *removepend_bitmap; + + if (sc->facts.reply_sz > sc->reply_sz) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "Cannot increase reply size from %d to %d\n", + sc->reply_sz, sc->reply_sz); + return -EPERM; + } + + if (sc->num_io_throttle_group != sc->facts.max_io_throttle_group) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "max io throttle group doesn't match old(%d), new(%d)\n", + sc->num_io_throttle_group, + sc->facts.max_io_throttle_group); + return -EPERM; + } + + if (sc->facts.max_op_reply_q < sc->num_queues) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "Cannot reduce number of operational reply queues from %d to %d\n", + sc->num_queues, + sc->facts.max_op_reply_q); + return -EPERM; + } + + if (sc->facts.max_op_req_q < sc->num_queues) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "Cannot reduce number of operational request queues from %d to %d\n", + sc->num_queues, sc->facts.max_op_req_q); + return -EPERM; + } + + dev_handle_bitmap_sz = MPI3MR_DIV_ROUND_UP(sc->facts.max_devhandle, 8); + + if (dev_handle_bitmap_sz > sc->dev_handle_bitmap_sz) { + removepend_bitmap = realloc(sc->removepend_bitmap, + dev_handle_bitmap_sz, M_MPI3MR, M_NOWAIT); + + if (!removepend_bitmap) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "failed to increase removepend_bitmap sz from: %d to %d\n", + sc->dev_handle_bitmap_sz, dev_handle_bitmap_sz); + return -ENOMEM; + } + + memset(removepend_bitmap + sc->dev_handle_bitmap_sz, 0, + dev_handle_bitmap_sz - sc->dev_handle_bitmap_sz); + sc->removepend_bitmap = removepend_bitmap; + mpi3mr_dprint(sc, MPI3MR_INFO, + "increased dev_handle_bitmap_sz from %d to %d\n", + sc->dev_handle_bitmap_sz, dev_handle_bitmap_sz); + sc->dev_handle_bitmap_sz = dev_handle_bitmap_sz; + } + + return 0; +} + +/* + * mpi3mr_initialize_ioc - Controller initialization + * @dev: pointer to device struct + * + * This function allocates the controller wide resources and brings + * the controller to operational state + * + * Return: 0 on success and proper error codes on failure + */ +int mpi3mr_initialize_ioc(struct mpi3mr_softc *sc, U8 init_type) +{ + int retval = 0; + enum mpi3mr_iocstate ioc_state; + U64 ioc_info; + U32 ioc_status, ioc_control, i, timeout; + Mpi3IOCFactsData_t facts_data; + char str[32]; + U32 size; + + sc->cpu_count = mp_ncpus; + + ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET); + ioc_control = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET); + ioc_info = mpi3mr_regread64(sc, MPI3_SYSIF_IOC_INFO_LOW_OFFSET); + + mpi3mr_dprint(sc, MPI3MR_INFO, "SOD ioc_status: 0x%x ioc_control: 0x%x " + "ioc_info: 0x%lx\n", ioc_status, ioc_control, ioc_info); + + /*The timeout value is in 2sec unit, changing it to seconds*/ + sc->ready_timeout = + ((ioc_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >> + MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2; + + ioc_state = mpi3mr_get_iocstate(sc); + + mpi3mr_dprint(sc, MPI3MR_INFO, "IOC state: %s IOC ready timeout: %d\n", + mpi3mr_iocstate_name(ioc_state), sc->ready_timeout); + + if (ioc_state == MRIOC_STATE_BECOMING_READY || + ioc_state == MRIOC_STATE_RESET_REQUESTED) { + timeout = sc->ready_timeout * 10; + do { + DELAY(1000 * 100); + } while (--timeout); + + ioc_state = mpi3mr_get_iocstate(sc); + mpi3mr_dprint(sc, MPI3MR_INFO, + "IOC in %s state after waiting for reset time\n", + mpi3mr_iocstate_name(ioc_state)); + } + + if (ioc_state == MRIOC_STATE_READY) { + retval = mpi3mr_mur_ioc(sc, MPI3MR_RESET_FROM_BRINGUP); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to MU reset IOC, error 0x%x\n", + retval); + } + ioc_state = mpi3mr_get_iocstate(sc); + } + + if (ioc_state != MRIOC_STATE_RESET) { + mpi3mr_print_fault_info(sc); + mpi3mr_dprint(sc, MPI3MR_ERROR, "issuing soft reset to bring to reset state\n"); + retval = mpi3mr_issue_reset(sc, + MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, + MPI3MR_RESET_FROM_BRINGUP); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "%s :Failed to soft reset IOC, error 0x%d\n", + __func__, retval); + goto out_failed; + } + } + + ioc_state = mpi3mr_get_iocstate(sc); + + if (ioc_state != MRIOC_STATE_RESET) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot bring IOC to reset state\n"); + goto out_failed; + } + + retval = mpi3mr_setup_admin_qpair(sc); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to setup Admin queues, error 0x%x\n", + retval); + goto out_failed; + } + + retval = mpi3mr_bring_ioc_ready(sc); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to bring IOC ready, error 0x%x\n", + retval); + goto out_failed; + } + + if (init_type == MPI3MR_INIT_TYPE_INIT) { + retval = mpi3mr_alloc_interrupts(sc, 1); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate interrupts, error 0x%x\n", + retval); + goto out_failed; + } + + retval = mpi3mr_setup_irqs(sc); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to setup ISR, error 0x%x\n", + retval); + goto out_failed; + } + } + + mpi3mr_enable_interrupts(sc); + + if (init_type == MPI3MR_INIT_TYPE_INIT) { + mtx_init(&sc->mpi3mr_mtx, "SIM lock", NULL, MTX_DEF); + mtx_init(&sc->io_lock, "IO lock", NULL, MTX_DEF); + mtx_init(&sc->admin_req_lock, "Admin Request Queue lock", NULL, MTX_SPIN); + mtx_init(&sc->reply_free_q_lock, "Reply free Queue lock", NULL, MTX_SPIN); + mtx_init(&sc->sense_buf_q_lock, "Sense buffer Queue lock", NULL, MTX_SPIN); + mtx_init(&sc->chain_buf_lock, "Chain buffer lock", NULL, MTX_SPIN); + mtx_init(&sc->cmd_pool_lock, "Command pool lock", NULL, MTX_DEF); +// mtx_init(&sc->fwevt_lock, "Firmware Event lock", NULL, MTX_SPIN); + mtx_init(&sc->fwevt_lock, "Firmware Event lock", NULL, MTX_DEF); + mtx_init(&sc->target_lock, "Target lock", NULL, MTX_SPIN); + mtx_init(&sc->reset_mutex, "Reset lock", NULL, MTX_DEF); + + mtx_init(&sc->init_cmds.completion.lock, "Init commands lock", NULL, MTX_DEF); + sc->init_cmds.reply = NULL; + sc->init_cmds.state = MPI3MR_CMD_NOTUSED; + sc->init_cmds.dev_handle = MPI3MR_INVALID_DEV_HANDLE; + sc->init_cmds.host_tag = MPI3MR_HOSTTAG_INITCMDS; + + mtx_init(&sc->ioctl_cmds.completion.lock, "IOCTL commands lock", NULL, MTX_DEF); + sc->ioctl_cmds.reply = NULL; + sc->ioctl_cmds.state = MPI3MR_CMD_NOTUSED; + sc->ioctl_cmds.dev_handle = MPI3MR_INVALID_DEV_HANDLE; + sc->ioctl_cmds.host_tag = MPI3MR_HOSTTAG_IOCTLCMDS; + + mtx_init(&sc->pel_abort_cmd.completion.lock, "PEL Abort command lock", NULL, MTX_DEF); + sc->pel_abort_cmd.reply = NULL; + sc->pel_abort_cmd.state = MPI3MR_CMD_NOTUSED; + sc->pel_abort_cmd.dev_handle = MPI3MR_INVALID_DEV_HANDLE; + sc->pel_abort_cmd.host_tag = MPI3MR_HOSTTAG_PELABORT; + + mtx_init(&sc->host_tm_cmds.completion.lock, "TM commands lock", NULL, MTX_DEF); + sc->host_tm_cmds.reply = NULL; + sc->host_tm_cmds.state = MPI3MR_CMD_NOTUSED; + sc->host_tm_cmds.dev_handle = MPI3MR_INVALID_DEV_HANDLE; + sc->host_tm_cmds.host_tag = MPI3MR_HOSTTAG_TMS; + + TAILQ_INIT(&sc->cmd_list_head); + TAILQ_INIT(&sc->event_list); + TAILQ_INIT(&sc->delayed_rmhs_list); + TAILQ_INIT(&sc->delayed_evtack_cmds_list); + + for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { + snprintf(str, 32, "Dev REMHS commands lock[%d]", i); + mtx_init(&sc->dev_rmhs_cmds[i].completion.lock, str, NULL, MTX_DEF); + sc->dev_rmhs_cmds[i].reply = NULL; + sc->dev_rmhs_cmds[i].state = MPI3MR_CMD_NOTUSED; + sc->dev_rmhs_cmds[i].dev_handle = MPI3MR_INVALID_DEV_HANDLE; + sc->dev_rmhs_cmds[i].host_tag = MPI3MR_HOSTTAG_DEVRMCMD_MIN + + i; + } + } + + retval = mpi3mr_issue_iocfacts(sc, &facts_data); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to Issue IOC Facts, retval: 0x%x\n", + retval); + goto out_failed; + } + + retval = mpi3mr_process_factsdata(sc, &facts_data); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "IOC Facts data processing failedi, retval: 0x%x\n", + retval); + goto out_failed; + } + + sc->num_io_throttle_group = sc->facts.max_io_throttle_group; + mpi3mr_atomic_set(&sc->pend_large_data_sz, 0); + + if (init_type == MPI3MR_INIT_TYPE_RESET) { + retval = mpi3mr_validate_fw_update(sc); + if (retval) + goto out_failed; + } else { + sc->reply_sz = sc->facts.reply_sz; + } + + + mpi3mr_display_ioc_info(sc); + + retval = mpi3mr_reply_alloc(sc); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocated reply and sense buffers, retval: 0x%x\n", + retval); + goto out_failed; + } + + if (init_type == MPI3MR_INIT_TYPE_INIT) { + retval = mpi3mr_alloc_chain_bufs(sc); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocated chain buffers, retval: 0x%x\n", + retval); + goto out_failed; + } + } + + retval = mpi3mr_issue_iocinit(sc); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to Issue IOC Init, retval: 0x%x\n", + retval); + goto out_failed; + } + + mpi3mr_print_fw_pkg_ver(sc); + + sc->reply_free_q_host_index = sc->num_reply_bufs; + mpi3mr_regwrite(sc, MPI3_SYSIF_REPLY_FREE_HOST_INDEX_OFFSET, + sc->reply_free_q_host_index); + + sc->sense_buf_q_host_index = sc->num_sense_bufs; + + mpi3mr_regwrite(sc, MPI3_SYSIF_SENSE_BUF_FREE_HOST_INDEX_OFFSET, + sc->sense_buf_q_host_index); + + if (init_type == MPI3MR_INIT_TYPE_INIT) { + retval = mpi3mr_alloc_interrupts(sc, 0); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate interrupts, retval: 0x%x\n", + retval); + goto out_failed; + } + + retval = mpi3mr_setup_irqs(sc); + if (retval) { + printf(IOCNAME "Failed to setup ISR, error: 0x%x\n", + sc->name, retval); + goto out_failed; + } + + mpi3mr_enable_interrupts(sc); + + } else + mpi3mr_enable_interrupts(sc); + + retval = mpi3mr_create_op_queues(sc); + + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to create operational queues, error: %d\n", + retval); + goto out_failed; + } + + if (!sc->throttle_groups && sc->num_io_throttle_group) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "allocating memory for throttle groups\n"); + size = sizeof(struct mpi3mr_throttle_group_info); + sc->throttle_groups = (struct mpi3mr_throttle_group_info *) + malloc(sc->num_io_throttle_group * + size, M_MPI3MR, M_NOWAIT | M_ZERO); + if (!sc->throttle_groups) + goto out_failed; + } + + if (init_type == MPI3MR_INIT_TYPE_RESET) { + mpi3mr_dprint(sc, MPI3MR_INFO, "Re-register events\n"); + retval = mpi3mr_register_events(sc); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_INFO, "Failed to re-register events, retval: 0x%x\n", + retval); + goto out_failed; + } + + mpi3mr_dprint(sc, MPI3MR_INFO, "Issuing Port Enable\n"); + retval = mpi3mr_issue_port_enable(sc, 0); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_INFO, "Failed to issue port enable, retval: 0x%x\n", + retval); + goto out_failed; + } + } + retval = mpi3mr_pel_alloc(sc); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate memory for PEL, retval: 0x%x\n", + retval); + goto out_failed; + } + + return retval; + +out_failed: + retval = -1; + return retval; +} + +static void mpi3mr_port_enable_complete(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *drvrcmd) +{ + drvrcmd->state = MPI3MR_CMD_NOTUSED; + drvrcmd->callback = NULL; + printf(IOCNAME "Completing Port Enable Request\n", sc->name); + sc->mpi3mr_flags |= MPI3MR_FLAGS_PORT_ENABLE_DONE; + mpi3mr_startup_decrement(sc->cam_sc); +} + +int mpi3mr_issue_port_enable(struct mpi3mr_softc *sc, U8 async) +{ + Mpi3PortEnableRequest_t pe_req; + int retval = 0; + + memset(&pe_req, 0, sizeof(pe_req)); + mtx_lock(&sc->init_cmds.completion.lock); + if (sc->init_cmds.state & MPI3MR_CMD_PENDING) { + retval = -1; + printf(IOCNAME "Issue PortEnable: Init command is in use\n", sc->name); + mtx_unlock(&sc->init_cmds.completion.lock); + goto out; + } + + sc->init_cmds.state = MPI3MR_CMD_PENDING; + + if (async) { + sc->init_cmds.is_waiting = 0; + sc->init_cmds.callback = mpi3mr_port_enable_complete; + } else { + sc->init_cmds.is_waiting = 1; + sc->init_cmds.callback = NULL; + init_completion(&sc->init_cmds.completion); + } + pe_req.HostTag = MPI3MR_HOSTTAG_INITCMDS; + pe_req.Function = MPI3_FUNCTION_PORT_ENABLE; + + printf(IOCNAME "Sending Port Enable Request\n", sc->name); + retval = mpi3mr_submit_admin_cmd(sc, &pe_req, sizeof(pe_req)); + if (retval) { + printf(IOCNAME "Issue PortEnable: Admin Post failed\n", + sc->name); + goto out_unlock; + } + + if (!async) { + wait_for_completion_timeout(&sc->init_cmds.completion, + MPI3MR_PORTENABLE_TIMEOUT); + if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { + printf(IOCNAME "Issue PortEnable: command timed out\n", + sc->name); + retval = -1; + mpi3mr_check_rh_fault_ioc(sc, MPI3MR_RESET_FROM_PE_TIMEOUT); + goto out_unlock; + } + mpi3mr_port_enable_complete(sc, &sc->init_cmds); + } +out_unlock: + mtx_unlock(&sc->init_cmds.completion.lock); + +out: + return retval; +} + +void +mpi3mr_watchdog_thread(void *arg) +{ + struct mpi3mr_softc *sc; + enum mpi3mr_iocstate ioc_state; + U32 fault, host_diagnostic, ioc_status; + + sc = (struct mpi3mr_softc *)arg; + + mpi3mr_dprint(sc, MPI3MR_XINFO, "%s\n", __func__); + + sc->watchdog_thread_active = 1; + mtx_lock(&sc->reset_mutex); + for (;;) { + /* Sleep for 1 second and check the queue status */ + msleep(&sc->watchdog_chan, &sc->reset_mutex, PRIBIO, + "mpi3mr_watchdog", 1 * hz); + if (sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN || + (sc->unrecoverable == 1)) { + mpi3mr_dprint(sc, MPI3MR_INFO, + "Exit due to %s from %s\n", + sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN ? "Shutdown" : + "Hardware critical error", __func__); + break; + } + + if ((sc->prepare_for_reset) && + ((sc->prepare_for_reset_timeout_counter++) >= + MPI3MR_PREPARE_FOR_RESET_TIMEOUT)) { + mpi3mr_soft_reset_handler(sc, + MPI3MR_RESET_FROM_CIACTVRST_TIMER, 1); + continue; + } + + ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET); + + if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) { + mpi3mr_soft_reset_handler(sc, MPI3MR_RESET_FROM_FIRMWARE, 0); + continue; + } + + ioc_state = mpi3mr_get_iocstate(sc); + if (ioc_state == MRIOC_STATE_FAULT) { + fault = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_OFFSET) & + MPI3_SYSIF_FAULT_CODE_MASK; + + host_diagnostic = mpi3mr_regread(sc, MPI3_SYSIF_HOST_DIAG_OFFSET); + if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) { + if (!sc->diagsave_timeout) { + mpi3mr_print_fault_info(sc); + mpi3mr_dprint(sc, MPI3MR_INFO, + "diag save in progress\n"); + } + if ((sc->diagsave_timeout++) <= MPI3_SYSIF_DIAG_SAVE_TIMEOUT) + continue; + } + mpi3mr_print_fault_info(sc); + sc->diagsave_timeout = 0; + + if ((fault == MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED) || + (fault == MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED)) { + mpi3mr_dprint(sc, MPI3MR_INFO, + "Controller requires system power cycle or complete reset is needed," + "fault code: 0x%x. marking controller as unrecoverable\n", fault); + sc->unrecoverable = 1; + goto out; + } + if ((fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) + || (fault == MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS) + || (sc->reset_in_progress)) + goto out; + if (fault == MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET) + mpi3mr_soft_reset_handler(sc, + MPI3MR_RESET_FROM_CIACTIV_FAULT, 0); + else + mpi3mr_soft_reset_handler(sc, + MPI3MR_RESET_FROM_FAULT_WATCH, 0); + + } + + if (sc->reset.type == MPI3MR_TRIGGER_SOFT_RESET) { + mpi3mr_print_fault_info(sc); + mpi3mr_soft_reset_handler(sc, sc->reset.reason, 1); + } + } +out: + mtx_unlock(&sc->reset_mutex); + sc->watchdog_thread_active = 0; + mpi3mr_kproc_exit(0); +} + +static void mpi3mr_display_event_data(struct mpi3mr_softc *sc, + Mpi3EventNotificationReply_t *event_rep) +{ + char *desc = NULL; + U16 event; + + event = event_rep->Event; + + switch (event) { + case MPI3_EVENT_LOG_DATA: + desc = "Log Data"; + break; + case MPI3_EVENT_CHANGE: + desc = "Event Change"; + break; + case MPI3_EVENT_GPIO_INTERRUPT: + desc = "GPIO Interrupt"; + break; + case MPI3_EVENT_CABLE_MGMT: + desc = "Cable Management"; + break; + case MPI3_EVENT_ENERGY_PACK_CHANGE: + desc = "Energy Pack Change"; + break; + case MPI3_EVENT_DEVICE_ADDED: + { + Mpi3DevicePage0_t *event_data = + (Mpi3DevicePage0_t *)event_rep->EventData; + mpi3mr_dprint(sc, MPI3MR_EVENT, "Device Added: Dev=0x%04x Form=0x%x Perst id: 0x%x\n", + event_data->DevHandle, event_data->DeviceForm, event_data->PersistentID); + return; + } + case MPI3_EVENT_DEVICE_INFO_CHANGED: + { + Mpi3DevicePage0_t *event_data = + (Mpi3DevicePage0_t *)event_rep->EventData; + mpi3mr_dprint(sc, MPI3MR_EVENT, "Device Info Changed: Dev=0x%04x Form=0x%x\n", + event_data->DevHandle, event_data->DeviceForm); + return; + } + case MPI3_EVENT_DEVICE_STATUS_CHANGE: + { + Mpi3EventDataDeviceStatusChange_t *event_data = + (Mpi3EventDataDeviceStatusChange_t *)event_rep->EventData; + mpi3mr_dprint(sc, MPI3MR_EVENT, "Device Status Change: Dev=0x%04x RC=0x%x\n", + event_data->DevHandle, event_data->ReasonCode); + return; + } + case MPI3_EVENT_SAS_DISCOVERY: + { + Mpi3EventDataSasDiscovery_t *event_data = + (Mpi3EventDataSasDiscovery_t *)event_rep->EventData; + mpi3mr_dprint(sc, MPI3MR_EVENT, "SAS Discovery: (%s)", + (event_data->ReasonCode == MPI3_EVENT_SAS_DISC_RC_STARTED) ? + "start" : "stop"); + if (event_data->DiscoveryStatus && + (sc->mpi3mr_debug & MPI3MR_EVENT)) { + printf("discovery_status(0x%08x)", + event_data->DiscoveryStatus); + + } + + if (sc->mpi3mr_debug & MPI3MR_EVENT) + printf("\n"); + return; + } + case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE: + desc = "SAS Broadcast Primitive"; + break; + case MPI3_EVENT_SAS_NOTIFY_PRIMITIVE: + desc = "SAS Notify Primitive"; + break; + case MPI3_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: + desc = "SAS Init Device Status Change"; + break; + case MPI3_EVENT_SAS_INIT_TABLE_OVERFLOW: + desc = "SAS Init Table Overflow"; + break; + case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST: + desc = "SAS Topology Change List"; + break; + case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE: + desc = "Enclosure Device Status Change"; + break; + case MPI3_EVENT_HARD_RESET_RECEIVED: + desc = "Hard Reset Received"; + break; + case MPI3_EVENT_SAS_PHY_COUNTER: + desc = "SAS PHY Counter"; + break; + case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR: + desc = "SAS Device Discovery Error"; + break; + case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: + desc = "PCIE Topology Change List"; + break; + case MPI3_EVENT_PCIE_ENUMERATION: + { + Mpi3EventDataPcieEnumeration_t *event_data = + (Mpi3EventDataPcieEnumeration_t *)event_rep->EventData; + mpi3mr_dprint(sc, MPI3MR_EVENT, "PCIE Enumeration: (%s)", + (event_data->ReasonCode == + MPI3_EVENT_PCIE_ENUM_RC_STARTED) ? "start" : + "stop"); + if (event_data->EnumerationStatus) + mpi3mr_dprint(sc, MPI3MR_EVENT, "enumeration_status(0x%08x)", + event_data->EnumerationStatus); + if (sc->mpi3mr_debug & MPI3MR_EVENT) + printf("\n"); + return; + } + case MPI3_EVENT_PREPARE_FOR_RESET: + desc = "Prepare For Reset"; + break; + } + + if (!desc) + return; + + mpi3mr_dprint(sc, MPI3MR_EVENT, "%s\n", desc); +} + +struct mpi3mr_target * +mpi3mr_find_target_by_per_id(struct mpi3mr_cam_softc *cam_sc, + uint16_t per_id) +{ + struct mpi3mr_target *target = NULL; + + mtx_lock_spin(&cam_sc->sc->target_lock); + TAILQ_FOREACH(target, &cam_sc->tgt_list, tgt_next) { + if (target->per_id == per_id) + break; + } + + mtx_unlock_spin(&cam_sc->sc->target_lock); + return target; +} + +struct mpi3mr_target * +mpi3mr_find_target_by_dev_handle(struct mpi3mr_cam_softc *cam_sc, + uint16_t handle) +{ + struct mpi3mr_target *target = NULL; + + mtx_lock_spin(&cam_sc->sc->target_lock); + TAILQ_FOREACH(target, &cam_sc->tgt_list, tgt_next) { + if (target->dev_handle == handle) + break; + + } + mtx_unlock_spin(&cam_sc->sc->target_lock); + return target; +} + +void mpi3mr_update_device(struct mpi3mr_softc *sc, + struct mpi3mr_target *tgtdev, Mpi3DevicePage0_t *dev_pg0, + bool is_added) +{ + U16 flags = 0; + + tgtdev->per_id = (dev_pg0->PersistentID); + tgtdev->dev_handle = (dev_pg0->DevHandle); + tgtdev->dev_type = dev_pg0->DeviceForm; + tgtdev->encl_handle = (dev_pg0->EnclosureHandle); + tgtdev->parent_handle = (dev_pg0->ParentDevHandle); + tgtdev->slot = (dev_pg0->Slot); + tgtdev->qdepth = (dev_pg0->QueueDepth); + tgtdev->wwid = (dev_pg0->WWID); + + flags = (dev_pg0->Flags); + tgtdev->is_hidden = (flags & MPI3_DEVICE0_FLAGS_HIDDEN); + if (is_added == true) + tgtdev->io_throttle_enabled = + (flags & MPI3_DEVICE0_FLAGS_IO_THROTTLING_REQUIRED) ? 1 : 0; + + switch (dev_pg0->AccessStatus) { + case MPI3_DEVICE0_ASTATUS_NO_ERRORS: + case MPI3_DEVICE0_ASTATUS_PREPARE: + case MPI3_DEVICE0_ASTATUS_NEEDS_INITIALIZATION: + case MPI3_DEVICE0_ASTATUS_DEVICE_MISSING_DELAY: + break; + default: + tgtdev->is_hidden = 1; + break; + } + + switch (tgtdev->dev_type) { + case MPI3_DEVICE_DEVFORM_SAS_SATA: + { + Mpi3Device0SasSataFormat_t *sasinf = + &dev_pg0->DeviceSpecific.SasSataFormat; + U16 dev_info = (sasinf->DeviceInfo); + tgtdev->dev_spec.sassata_inf.dev_info = dev_info; + tgtdev->dev_spec.sassata_inf.sas_address = + (sasinf->SASAddress); + if ((dev_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) != + MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE) + tgtdev->is_hidden = 1; + else if (!(dev_info & (MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET | + MPI3_SAS_DEVICE_INFO_SSP_TARGET))) + tgtdev->is_hidden = 1; + break; + } + case MPI3_DEVICE_DEVFORM_PCIE: + { + Mpi3Device0PcieFormat_t *pcieinf = + &dev_pg0->DeviceSpecific.PcieFormat; + U16 dev_info = (pcieinf->DeviceInfo); + + tgtdev->q_depth = dev_pg0->QueueDepth; + tgtdev->dev_spec.pcie_inf.dev_info = dev_info; + tgtdev->dev_spec.pcie_inf.capb = + (pcieinf->Capabilities); + tgtdev->dev_spec.pcie_inf.mdts = MPI3MR_DEFAULT_MDTS; + if (dev_pg0->AccessStatus == MPI3_DEVICE0_ASTATUS_NO_ERRORS) { + tgtdev->dev_spec.pcie_inf.mdts = + (pcieinf->MaximumDataTransferSize); + tgtdev->dev_spec.pcie_inf.pgsz = pcieinf->PageSize; + tgtdev->dev_spec.pcie_inf.reset_to = + pcieinf->ControllerResetTO; + tgtdev->dev_spec.pcie_inf.abort_to = + pcieinf->NVMeAbortTO; + } + if (tgtdev->dev_spec.pcie_inf.mdts > (1024 * 1024)) + tgtdev->dev_spec.pcie_inf.mdts = (1024 * 1024); + + if (((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) != + MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) && + ((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) != + MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_SCSI_DEVICE)) + tgtdev->is_hidden = 1; + + break; + } + case MPI3_DEVICE_DEVFORM_VD: + { + Mpi3Device0VdFormat_t *vdinf = + &dev_pg0->DeviceSpecific.VdFormat; + struct mpi3mr_throttle_group_info *tg = NULL; + + tgtdev->dev_spec.vol_inf.state = vdinf->VdState; + if (vdinf->VdState == MPI3_DEVICE0_VD_STATE_OFFLINE) + tgtdev->is_hidden = 1; + tgtdev->dev_spec.vol_inf.tg_id = vdinf->IOThrottleGroup; + tgtdev->dev_spec.vol_inf.tg_high = + vdinf->IOThrottleGroupHigh * 2048; + tgtdev->dev_spec.vol_inf.tg_low = + vdinf->IOThrottleGroupLow * 2048; + if (vdinf->IOThrottleGroup < sc->num_io_throttle_group) { + tg = sc->throttle_groups + vdinf->IOThrottleGroup; + tg->id = vdinf->IOThrottleGroup; + tg->high = tgtdev->dev_spec.vol_inf.tg_high; + tg->low = tgtdev->dev_spec.vol_inf.tg_low; + if (is_added == true) + tg->fw_qd = tgtdev->q_depth; + tg->modified_qd = tgtdev->q_depth; + } + tgtdev->dev_spec.vol_inf.tg = tg; + tgtdev->throttle_group = tg; + break; + } + default: + goto out; + } + +out: + return; +} + +int mpi3mr_create_device(struct mpi3mr_softc *sc, + Mpi3DevicePage0_t *dev_pg0) +{ + int retval = 0; + struct mpi3mr_target *target = NULL; + U16 per_id = 0; + + per_id = dev_pg0->PersistentID; + + mtx_lock_spin(&sc->target_lock); + TAILQ_FOREACH(target, &sc->cam_sc->tgt_list, tgt_next) { + if (target->per_id == per_id) { + target->state = MPI3MR_DEV_CREATED; + break; + } + } + mtx_unlock_spin(&sc->target_lock); + + if (target) { + mpi3mr_update_device(sc, target, dev_pg0, true); + } else { + target = malloc(sizeof(*target), M_MPI3MR, + M_NOWAIT | M_ZERO); + + if (target == NULL) { + retval = -1; + goto out; + } + + target->exposed_to_os = 0; + mpi3mr_update_device(sc, target, dev_pg0, true); + mtx_lock_spin(&sc->target_lock); + TAILQ_INSERT_TAIL(&sc->cam_sc->tgt_list, target, tgt_next); + target->state = MPI3MR_DEV_CREATED; + mtx_unlock_spin(&sc->target_lock); + } +out: + return retval; +} + +/** + * mpi3mr_dev_rmhs_complete_iou - Device removal IOUC completion + * @sc: Adapter instance reference + * @drv_cmd: Internal command tracker + * + * Issues a target reset TM to the firmware from the device + * removal TM pend list or retry the removal handshake sequence + * based on the IOU control request IOC status. + * + * Return: Nothing + */ +static void mpi3mr_dev_rmhs_complete_iou(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *drv_cmd) +{ + U16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN; + struct delayed_dev_rmhs_node *delayed_dev_rmhs = NULL; + + mpi3mr_dprint(sc, MPI3MR_EVENT, + "%s :dev_rmhs_iouctrl_complete:handle(0x%04x), ioc_status(0x%04x), loginfo(0x%08x)\n", + __func__, drv_cmd->dev_handle, drv_cmd->ioc_status, + drv_cmd->ioc_loginfo); + if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) { + if (drv_cmd->retry_count < MPI3MR_DEVRMHS_RETRYCOUNT) { + drv_cmd->retry_count++; + mpi3mr_dprint(sc, MPI3MR_EVENT, + "%s :dev_rmhs_iouctrl_complete: handle(0x%04x)retrying handshake retry=%d\n", + __func__, drv_cmd->dev_handle, + drv_cmd->retry_count); + mpi3mr_dev_rmhs_send_tm(sc, drv_cmd->dev_handle, + drv_cmd, drv_cmd->iou_rc); + return; + } + mpi3mr_dprint(sc, MPI3MR_ERROR, + "%s :dev removal handshake failed after all retries: handle(0x%04x)\n", + __func__, drv_cmd->dev_handle); + } else { + mpi3mr_dprint(sc, MPI3MR_INFO, + "%s :dev removal handshake completed successfully: handle(0x%04x)\n", + __func__, drv_cmd->dev_handle); + mpi3mr_clear_bit(drv_cmd->dev_handle, sc->removepend_bitmap); + } + + if (!TAILQ_EMPTY(&sc->delayed_rmhs_list)) { + delayed_dev_rmhs = TAILQ_FIRST(&sc->delayed_rmhs_list); + drv_cmd->dev_handle = delayed_dev_rmhs->handle; + drv_cmd->retry_count = 0; + drv_cmd->iou_rc = delayed_dev_rmhs->iou_rc; + mpi3mr_dprint(sc, MPI3MR_EVENT, + "%s :dev_rmhs_iouctrl_complete: processing delayed TM: handle(0x%04x)\n", + __func__, drv_cmd->dev_handle); + mpi3mr_dev_rmhs_send_tm(sc, drv_cmd->dev_handle, drv_cmd, + drv_cmd->iou_rc); + TAILQ_REMOVE(&sc->delayed_rmhs_list, delayed_dev_rmhs, list); + free(delayed_dev_rmhs, M_MPI3MR); + return; + } + drv_cmd->state = MPI3MR_CMD_NOTUSED; + drv_cmd->callback = NULL; + drv_cmd->retry_count = 0; + drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE; + mpi3mr_clear_bit(cmd_idx, sc->devrem_bitmap); +} + +/** + * mpi3mr_dev_rmhs_complete_tm - Device removal TM completion + * @sc: Adapter instance reference + * @drv_cmd: Internal command tracker + * + * Issues a target reset TM to the firmware from the device + * removal TM pend list or issue IO Unit control request as + * part of device removal or hidden acknowledgment handshake. + * + * Return: Nothing + */ +static void mpi3mr_dev_rmhs_complete_tm(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *drv_cmd) +{ + Mpi3IoUnitControlRequest_t iou_ctrl; + U16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN; + Mpi3SCSITaskMgmtReply_t *tm_reply = NULL; + int retval; + + if (drv_cmd->state & MPI3MR_CMD_REPLYVALID) + tm_reply = (Mpi3SCSITaskMgmtReply_t *)drv_cmd->reply; + + if (tm_reply) + printf(IOCNAME + "dev_rmhs_tr_complete:handle(0x%04x), ioc_status(0x%04x), loginfo(0x%08x), term_count(%d)\n", + sc->name, drv_cmd->dev_handle, drv_cmd->ioc_status, + drv_cmd->ioc_loginfo, + le32toh(tm_reply->TerminationCount)); + + printf(IOCNAME "Issuing IOU CTL: handle(0x%04x) dev_rmhs idx(%d)\n", + sc->name, drv_cmd->dev_handle, cmd_idx); + + memset(&iou_ctrl, 0, sizeof(iou_ctrl)); + + drv_cmd->state = MPI3MR_CMD_PENDING; + drv_cmd->is_waiting = 0; + drv_cmd->callback = mpi3mr_dev_rmhs_complete_iou; + iou_ctrl.Operation = drv_cmd->iou_rc; + iou_ctrl.Param16[0] = htole16(drv_cmd->dev_handle); + iou_ctrl.HostTag = htole16(drv_cmd->host_tag); + iou_ctrl.Function = MPI3_FUNCTION_IO_UNIT_CONTROL; + + retval = mpi3mr_submit_admin_cmd(sc, &iou_ctrl, sizeof(iou_ctrl)); + if (retval) { + printf(IOCNAME "Issue DevRmHsTMIOUCTL: Admin post failed\n", + sc->name); + goto out_failed; + } + + return; +out_failed: + drv_cmd->state = MPI3MR_CMD_NOTUSED; + drv_cmd->callback = NULL; + drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE; + drv_cmd->retry_count = 0; + mpi3mr_clear_bit(cmd_idx, sc->devrem_bitmap); +} + +/** + * mpi3mr_dev_rmhs_send_tm - Issue TM for device removal + * @sc: Adapter instance reference + * @handle: Device handle + * @cmdparam: Internal command tracker + * @iou_rc: IO Unit reason code + * + * Issues a target reset TM to the firmware or add it to a pend + * list as part of device removal or hidden acknowledgment + * handshake. + * + * Return: Nothing + */ +static void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_softc *sc, U16 handle, + struct mpi3mr_drvr_cmd *cmdparam, U8 iou_rc) +{ + Mpi3SCSITaskMgmtRequest_t tm_req; + int retval = 0; + U16 cmd_idx = MPI3MR_NUM_DEVRMCMD; + U8 retrycount = 5; + struct mpi3mr_drvr_cmd *drv_cmd = cmdparam; + struct delayed_dev_rmhs_node *delayed_dev_rmhs = NULL; + struct mpi3mr_target *tgtdev = NULL; + + mtx_lock_spin(&sc->target_lock); + TAILQ_FOREACH(tgtdev, &sc->cam_sc->tgt_list, tgt_next) { + if ((tgtdev->dev_handle == handle) && + (iou_rc == MPI3_CTRL_OP_REMOVE_DEVICE)) { + tgtdev->state = MPI3MR_DEV_REMOVE_HS_STARTED; + break; + } + } + mtx_unlock_spin(&sc->target_lock); + + if (drv_cmd) + goto issue_cmd; + do { + cmd_idx = mpi3mr_find_first_zero_bit(sc->devrem_bitmap, + MPI3MR_NUM_DEVRMCMD); + if (cmd_idx < MPI3MR_NUM_DEVRMCMD) { + if (!mpi3mr_test_and_set_bit(cmd_idx, sc->devrem_bitmap)) + break; + cmd_idx = MPI3MR_NUM_DEVRMCMD; + } + } while (retrycount--); + + if (cmd_idx >= MPI3MR_NUM_DEVRMCMD) { + delayed_dev_rmhs = malloc(sizeof(*delayed_dev_rmhs),M_MPI3MR, + M_ZERO|M_NOWAIT); + + if (!delayed_dev_rmhs) + return; + delayed_dev_rmhs->handle = handle; + delayed_dev_rmhs->iou_rc = iou_rc; + TAILQ_INSERT_TAIL(&(sc->delayed_rmhs_list), delayed_dev_rmhs, list); + mpi3mr_dprint(sc, MPI3MR_EVENT, "%s :DevRmHs: tr:handle(0x%04x) is postponed\n", + __func__, handle); + + + return; + } + drv_cmd = &sc->dev_rmhs_cmds[cmd_idx]; + +issue_cmd: + cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN; + mpi3mr_dprint(sc, MPI3MR_EVENT, + "%s :Issuing TR TM: for devhandle 0x%04x with dev_rmhs %d\n", + __func__, handle, cmd_idx); + + memset(&tm_req, 0, sizeof(tm_req)); + if (drv_cmd->state & MPI3MR_CMD_PENDING) { + mpi3mr_dprint(sc, MPI3MR_EVENT, "%s :Issue TM: Command is in use\n", __func__); + goto out; + } + drv_cmd->state = MPI3MR_CMD_PENDING; + drv_cmd->is_waiting = 0; + drv_cmd->callback = mpi3mr_dev_rmhs_complete_tm; + drv_cmd->dev_handle = handle; + drv_cmd->iou_rc = iou_rc; + tm_req.DevHandle = htole16(handle); + tm_req.TaskType = MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET; + tm_req.HostTag = htole16(drv_cmd->host_tag); + tm_req.TaskHostTag = htole16(MPI3MR_HOSTTAG_INVALID); + tm_req.Function = MPI3_FUNCTION_SCSI_TASK_MGMT; + + mpi3mr_set_bit(handle, sc->removepend_bitmap); + retval = mpi3mr_submit_admin_cmd(sc, &tm_req, sizeof(tm_req)); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "%s :Issue DevRmHsTM: Admin Post failed\n", + __func__); + goto out_failed; + } +out: + return; +out_failed: + drv_cmd->state = MPI3MR_CMD_NOTUSED; + drv_cmd->callback = NULL; + drv_cmd->dev_handle = MPI3MR_INVALID_DEV_HANDLE; + drv_cmd->retry_count = 0; + mpi3mr_clear_bit(cmd_idx, sc->devrem_bitmap); +} + +/** + * mpi3mr_complete_evt_ack - Event ack request completion + * @sc: Adapter instance reference + * @drv_cmd: Internal command tracker + * + * This is the completion handler for non blocking event + * acknowledgment sent to the firmware and this will issue any + * pending event acknowledgment request. + * + * Return: Nothing + */ +static void mpi3mr_complete_evt_ack(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *drv_cmd) +{ + U16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN; + struct delayed_evtack_node *delayed_evtack = NULL; + + if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) { + mpi3mr_dprint(sc, MPI3MR_EVENT, + "%s: Failed IOCStatus(0x%04x) Loginfo(0x%08x)\n", __func__, + (drv_cmd->ioc_status & MPI3_IOCSTATUS_STATUS_MASK), + drv_cmd->ioc_loginfo); + } + + if (!TAILQ_EMPTY(&sc->delayed_evtack_cmds_list)) { + delayed_evtack = TAILQ_FIRST(&sc->delayed_evtack_cmds_list); + mpi3mr_dprint(sc, MPI3MR_EVENT, + "%s: processing delayed event ack for event %d\n", + __func__, delayed_evtack->event); + mpi3mr_send_evt_ack(sc, delayed_evtack->event, drv_cmd, + delayed_evtack->event_ctx); + TAILQ_REMOVE(&sc->delayed_evtack_cmds_list, delayed_evtack, list); + free(delayed_evtack, M_MPI3MR); + return; + } + drv_cmd->state = MPI3MR_CMD_NOTUSED; + drv_cmd->callback = NULL; + mpi3mr_clear_bit(cmd_idx, sc->evtack_cmds_bitmap); +} + +/** + * mpi3mr_send_evt_ack - Issue event acknwoledgment request + * @sc: Adapter instance reference + * @event: MPI3 event id + * @cmdparam: Internal command tracker + * @event_ctx: Event context + * + * Issues event acknowledgment request to the firmware if there + * is a free command to send the event ack else it to a pend + * list so that it will be processed on a completion of a prior + * event acknowledgment . + * + * Return: Nothing + */ +static void mpi3mr_send_evt_ack(struct mpi3mr_softc *sc, U8 event, + struct mpi3mr_drvr_cmd *cmdparam, U32 event_ctx) +{ + Mpi3EventAckRequest_t evtack_req; + int retval = 0; + U8 retrycount = 5; + U16 cmd_idx = MPI3MR_NUM_EVTACKCMD; + struct mpi3mr_drvr_cmd *drv_cmd = cmdparam; + struct delayed_evtack_node *delayed_evtack = NULL; + + if (drv_cmd) + goto issue_cmd; + do { + cmd_idx = mpi3mr_find_first_zero_bit(sc->evtack_cmds_bitmap, + MPI3MR_NUM_EVTACKCMD); + if (cmd_idx < MPI3MR_NUM_EVTACKCMD) { + if (!mpi3mr_test_and_set_bit(cmd_idx, + sc->evtack_cmds_bitmap)) + break; + cmd_idx = MPI3MR_NUM_EVTACKCMD; + } + } while (retrycount--); + + if (cmd_idx >= MPI3MR_NUM_EVTACKCMD) { + delayed_evtack = malloc(sizeof(*delayed_evtack),M_MPI3MR, + M_ZERO | M_NOWAIT); + if (!delayed_evtack) + return; + delayed_evtack->event = event; + delayed_evtack->event_ctx = event_ctx; + TAILQ_INSERT_TAIL(&(sc->delayed_evtack_cmds_list), delayed_evtack, list); + mpi3mr_dprint(sc, MPI3MR_EVENT, "%s : Event ack for event:%d is postponed\n", + __func__, event); + return; + } + drv_cmd = &sc->evtack_cmds[cmd_idx]; + +issue_cmd: + cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN; + + memset(&evtack_req, 0, sizeof(evtack_req)); + if (drv_cmd->state & MPI3MR_CMD_PENDING) { + mpi3mr_dprint(sc, MPI3MR_EVENT, "%s: Command is in use\n", __func__); + goto out; + } + drv_cmd->state = MPI3MR_CMD_PENDING; + drv_cmd->is_waiting = 0; + drv_cmd->callback = mpi3mr_complete_evt_ack; + evtack_req.HostTag = htole16(drv_cmd->host_tag); + evtack_req.Function = MPI3_FUNCTION_EVENT_ACK; + evtack_req.Event = event; + evtack_req.EventContext = htole32(event_ctx); + retval = mpi3mr_submit_admin_cmd(sc, &evtack_req, + sizeof(evtack_req)); + + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "%s: Admin Post failed\n", __func__); + goto out_failed; + } +out: + return; +out_failed: + drv_cmd->state = MPI3MR_CMD_NOTUSED; + drv_cmd->callback = NULL; + mpi3mr_clear_bit(cmd_idx, sc->evtack_cmds_bitmap); +} + +/* + * mpi3mr_pcietopochg_evt_th - PCIETopologyChange evt tophalf + * @sc: Adapter instance reference + * @event_reply: Event data + * + * Checks for the reason code and based on that either block I/O + * to device, or unblock I/O to the device, or start the device + * removal handshake with reason as remove with the firmware for + * PCIe devices. + * + * Return: Nothing + */ +static void mpi3mr_pcietopochg_evt_th(struct mpi3mr_softc *sc, + Mpi3EventNotificationReply_t *event_reply) +{ + Mpi3EventDataPcieTopologyChangeList_t *topo_evt = + (Mpi3EventDataPcieTopologyChangeList_t *) event_reply->EventData; + int i; + U16 handle; + U8 reason_code; + struct mpi3mr_target *tgtdev = NULL; + + for (i = 0; i < topo_evt->NumEntries; i++) { + handle = le16toh(topo_evt->PortEntry[i].AttachedDevHandle); + if (!handle) + continue; + reason_code = topo_evt->PortEntry[i].PortStatus; + tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, handle); + switch (reason_code) { + case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING: + if (tgtdev) { + tgtdev->dev_removed = 1; + tgtdev->dev_removedelay = 0; + mpi3mr_atomic_set(&tgtdev->block_io, 0); + } + mpi3mr_dev_rmhs_send_tm(sc, handle, NULL, + MPI3_CTRL_OP_REMOVE_DEVICE); + break; + case MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING: + if (tgtdev) { + tgtdev->dev_removedelay = 1; + mpi3mr_atomic_inc(&tgtdev->block_io); + } + break; + case MPI3_EVENT_PCIE_TOPO_PS_RESPONDING: + if (tgtdev && + tgtdev->dev_removedelay) { + tgtdev->dev_removedelay = 0; + if (mpi3mr_atomic_read(&tgtdev->block_io) > 0) + mpi3mr_atomic_dec(&tgtdev->block_io); + } + break; + case MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED: + default: + break; + } + } +} + +/** + * mpi3mr_sastopochg_evt_th - SASTopologyChange evt tophalf + * @sc: Adapter instance reference + * @event_reply: Event data + * + * Checks for the reason code and based on that either block I/O + * to device, or unblock I/O to the device, or start the device + * removal handshake with reason as remove with the firmware for + * SAS/SATA devices. + * + * Return: Nothing + */ +static void mpi3mr_sastopochg_evt_th(struct mpi3mr_softc *sc, + Mpi3EventNotificationReply_t *event_reply) +{ + Mpi3EventDataSasTopologyChangeList_t *topo_evt = + (Mpi3EventDataSasTopologyChangeList_t *)event_reply->EventData; + int i; + U16 handle; + U8 reason_code; + struct mpi3mr_target *tgtdev = NULL; + + for (i = 0; i < topo_evt->NumEntries; i++) { + handle = le16toh(topo_evt->PhyEntry[i].AttachedDevHandle); + if (!handle) + continue; + reason_code = topo_evt->PhyEntry[i].Status & + MPI3_EVENT_SAS_TOPO_PHY_RC_MASK; + tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, handle); + switch (reason_code) { + case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING: + if (tgtdev) { + tgtdev->dev_removed = 1; + tgtdev->dev_removedelay = 0; + mpi3mr_atomic_set(&tgtdev->block_io, 0); + } + mpi3mr_dev_rmhs_send_tm(sc, handle, NULL, + MPI3_CTRL_OP_REMOVE_DEVICE); + break; + case MPI3_EVENT_SAS_TOPO_PHY_RC_DELAY_NOT_RESPONDING: + if (tgtdev) { + tgtdev->dev_removedelay = 1; + mpi3mr_atomic_inc(&tgtdev->block_io); + } + break; + case MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING: + if (tgtdev && + tgtdev->dev_removedelay) { + tgtdev->dev_removedelay = 0; + if (mpi3mr_atomic_read(&tgtdev->block_io) > 0) + mpi3mr_atomic_dec(&tgtdev->block_io); + } + case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED: + default: + break; + } + } + +} +/** + * mpi3mr_devstatuschg_evt_th - DeviceStatusChange evt tophalf + * @sc: Adapter instance reference + * @event_reply: Event data + * + * Checks for the reason code and based on that either block I/O + * to device, or unblock I/O to the device, or start the device + * removal handshake with reason as remove/hide acknowledgment + * with the firmware. + * + * Return: Nothing + */ +static void mpi3mr_devstatuschg_evt_th(struct mpi3mr_softc *sc, + Mpi3EventNotificationReply_t *event_reply) +{ + U16 dev_handle = 0; + U8 ublock = 0, block = 0, hide = 0, uhide = 0, delete = 0, remove = 0; + struct mpi3mr_target *tgtdev = NULL; + Mpi3EventDataDeviceStatusChange_t *evtdata = + (Mpi3EventDataDeviceStatusChange_t *) event_reply->EventData; + + dev_handle = le16toh(evtdata->DevHandle); + + switch (evtdata->ReasonCode) { + case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_STRT: + case MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_STRT: + block = 1; + break; + case MPI3_EVENT_DEV_STAT_RC_HIDDEN: + delete = 1; + hide = 1; + break; + case MPI3_EVENT_DEV_STAT_RC_NOT_HIDDEN: + uhide = 1; + break; + case MPI3_EVENT_DEV_STAT_RC_VD_NOT_RESPONDING: + delete = 1; + remove = 1; + break; + case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_CMP: + case MPI3_EVENT_DEV_STAT_RC_INT_IT_NEXUS_RESET_CMP: + ublock = 1; + break; + default: + break; + } + + tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, dev_handle); + + if (!tgtdev) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "%s :target with dev_handle:0x%x not found\n", + __func__, dev_handle); + return; + } + + if (block) + mpi3mr_atomic_inc(&tgtdev->block_io); + + if (hide) + tgtdev->is_hidden = hide; + + if (uhide) { + tgtdev->is_hidden = 0; + tgtdev->dev_removed = 0; + } + + if (delete) + tgtdev->dev_removed = 1; + + if (ublock) { + if (mpi3mr_atomic_read(&tgtdev->block_io) > 0) + mpi3mr_atomic_dec(&tgtdev->block_io); + } + + if (remove) { + mpi3mr_dev_rmhs_send_tm(sc, dev_handle, NULL, + MPI3_CTRL_OP_REMOVE_DEVICE); + } + if (hide) + mpi3mr_dev_rmhs_send_tm(sc, dev_handle, NULL, + MPI3_CTRL_OP_HIDDEN_ACK); +} + +/** + * mpi3mr_preparereset_evt_th - Prepareforreset evt tophalf + * @sc: Adapter instance reference + * @event_reply: Event data + * + * Blocks and unblocks host level I/O based on the reason code + * + * Return: Nothing + */ +static void mpi3mr_preparereset_evt_th(struct mpi3mr_softc *sc, + Mpi3EventNotificationReply_t *event_reply) +{ + Mpi3EventDataPrepareForReset_t *evtdata = + (Mpi3EventDataPrepareForReset_t *)event_reply->EventData; + + if (evtdata->ReasonCode == MPI3_EVENT_PREPARE_RESET_RC_START) { + mpi3mr_dprint(sc, MPI3MR_EVENT, "%s :Recieved PrepForReset Event with RC=START\n", + __func__); + if (sc->prepare_for_reset) + return; + sc->prepare_for_reset = 1; + sc->prepare_for_reset_timeout_counter = 0; + } else if (evtdata->ReasonCode == MPI3_EVENT_PREPARE_RESET_RC_ABORT) { + mpi3mr_dprint(sc, MPI3MR_EVENT, "%s :Recieved PrepForReset Event with RC=ABORT\n", + __func__); + sc->prepare_for_reset = 0; + sc->prepare_for_reset_timeout_counter = 0; + } + if ((event_reply->MsgFlags & MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK) + == MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED) + mpi3mr_send_evt_ack(sc, event_reply->Event, NULL, + le32toh(event_reply->EventContext)); +} + +/** + * mpi3mr_energypackchg_evt_th - Energypackchange evt tophalf + * @sc: Adapter instance reference + * @event_reply: Event data + * + * Identifies the new shutdown timeout value and update. + * + * Return: Nothing + */ +static void mpi3mr_energypackchg_evt_th(struct mpi3mr_softc *sc, + Mpi3EventNotificationReply_t *event_reply) +{ + Mpi3EventDataEnergyPackChange_t *evtdata = + (Mpi3EventDataEnergyPackChange_t *)event_reply->EventData; + U16 shutdown_timeout = le16toh(evtdata->ShutdownTimeout); + + if (shutdown_timeout <= 0) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "%s :Invalid Shutdown Timeout received = %d\n", + __func__, shutdown_timeout); + return; + } + + mpi3mr_dprint(sc, MPI3MR_EVENT, + "%s :Previous Shutdown Timeout Value = %d New Shutdown Timeout Value = %d\n", + __func__, sc->facts.shutdown_timeout, shutdown_timeout); + sc->facts.shutdown_timeout = shutdown_timeout; +} + +/** + * mpi3mr_cablemgmt_evt_th - Cable mgmt evt tophalf + * @sc: Adapter instance reference + * @event_reply: Event data + * + * Displays Cable manegemt event details. + * + * Return: Nothing + */ +static void mpi3mr_cablemgmt_evt_th(struct mpi3mr_softc *sc, + Mpi3EventNotificationReply_t *event_reply) +{ + Mpi3EventDataCableManagement_t *evtdata = + (Mpi3EventDataCableManagement_t *)event_reply->EventData; + + switch (evtdata->Status) { + case MPI3_EVENT_CABLE_MGMT_STATUS_INSUFFICIENT_POWER: + { + mpi3mr_dprint(sc, MPI3MR_INFO, "An active cable with ReceptacleID %d cannot be powered.\n" + "Devices connected to this cable are not detected.\n" + "This cable requires %d mW of power.\n", + evtdata->ReceptacleID, + le32toh(evtdata->ActiveCablePowerRequirement)); + break; + } + case MPI3_EVENT_CABLE_MGMT_STATUS_DEGRADED: + { + mpi3mr_dprint(sc, MPI3MR_INFO, "A cable with ReceptacleID %d is not running at optimal speed\n", + evtdata->ReceptacleID); + break; + } + default: + break; + } +} + +/** + * mpi3mr_process_events - Event's toph-half handler + * @sc: Adapter instance reference + * @event_reply: Event data + * + * Top half of event processing. + * + * Return: Nothing + */ +static void mpi3mr_process_events(struct mpi3mr_softc *sc, + uintptr_t data, Mpi3EventNotificationReply_t *event_reply) +{ + U16 evt_type; + bool ack_req = 0, process_evt_bh = 0; + struct mpi3mr_fw_event_work *fw_event; + U16 sz; + + if (sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN) + goto out; + + if ((event_reply->MsgFlags & MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK) + == MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED) + ack_req = 1; + + evt_type = event_reply->Event; + + switch (evt_type) { + case MPI3_EVENT_DEVICE_ADDED: + { + Mpi3DevicePage0_t *dev_pg0 = + (Mpi3DevicePage0_t *) event_reply->EventData; + if (mpi3mr_create_device(sc, dev_pg0)) + mpi3mr_dprint(sc, MPI3MR_ERROR, + "%s :Failed to add device in the device add event\n", + __func__); + else + process_evt_bh = 1; + break; + } + + case MPI3_EVENT_DEVICE_STATUS_CHANGE: + { + process_evt_bh = 1; + mpi3mr_devstatuschg_evt_th(sc, event_reply); + break; + } + case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST: + { + process_evt_bh = 1; + mpi3mr_sastopochg_evt_th(sc, event_reply); + break; + } + case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: + { + process_evt_bh = 1; + mpi3mr_pcietopochg_evt_th(sc, event_reply); + break; + } + case MPI3_EVENT_PREPARE_FOR_RESET: + { + mpi3mr_preparereset_evt_th(sc, event_reply); + ack_req = 0; + break; + } + case MPI3_EVENT_DEVICE_INFO_CHANGED: + case MPI3_EVENT_LOG_DATA: + { + process_evt_bh = 1; + break; + } + case MPI3_EVENT_ENERGY_PACK_CHANGE: + { + mpi3mr_energypackchg_evt_th(sc, event_reply); + break; + } + case MPI3_EVENT_CABLE_MGMT: + { + mpi3mr_cablemgmt_evt_th(sc, event_reply); + break; + } + + case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE: + case MPI3_EVENT_SAS_DISCOVERY: + case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR: + case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE: + case MPI3_EVENT_PCIE_ENUMERATION: + break; + default: + mpi3mr_dprint(sc, MPI3MR_INFO, "%s :Event 0x%02x is not handled by driver\n", + __func__, evt_type); + break; + } + + if (process_evt_bh || ack_req) { + fw_event = malloc(sizeof(struct mpi3mr_fw_event_work), M_MPI3MR, + M_ZERO|M_NOWAIT); + + if (!fw_event) { + printf("%s: allocate failed for fw_event\n", __func__); + return; + } + + sz = le16toh(event_reply->EventDataLength) * 4; + fw_event->event_data = malloc(sz, M_MPI3MR, M_ZERO|M_NOWAIT); + + if (!fw_event->event_data) { + printf("%s: allocate failed for event_data\n", __func__); + free(fw_event, M_MPI3MR); + return; + } + + bcopy(event_reply->EventData, fw_event->event_data, sz); + fw_event->event = event_reply->Event; + if ((event_reply->Event == MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST || + event_reply->Event == MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST || + event_reply->Event == MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE ) && + sc->track_mapping_events) + sc->pending_map_events++; + + /* + * Events should be processed after Port enable is completed. + */ + if ((event_reply->Event == MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST || + event_reply->Event == MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST ) && + !(sc->mpi3mr_flags & MPI3MR_FLAGS_PORT_ENABLE_DONE)) + mpi3mr_startup_increment(sc->cam_sc); + + fw_event->send_ack = ack_req; + fw_event->event_context = le32toh(event_reply->EventContext); + fw_event->event_data_size = sz; + fw_event->process_event = process_evt_bh; + + mtx_lock(&sc->fwevt_lock); + TAILQ_INSERT_TAIL(&sc->cam_sc->ev_queue, fw_event, ev_link); + taskqueue_enqueue(sc->cam_sc->ev_tq, &sc->cam_sc->ev_task); + mtx_unlock(&sc->fwevt_lock); + + } +out: + return; +} + +static void mpi3mr_handle_events(struct mpi3mr_softc *sc, uintptr_t data, + Mpi3DefaultReply_t *def_reply) +{ + Mpi3EventNotificationReply_t *event_reply = + (Mpi3EventNotificationReply_t *)def_reply; + + sc->change_count = event_reply->IOCChangeCount; + mpi3mr_display_event_data(sc, event_reply); + + mpi3mr_process_events(sc, data, event_reply); +} + +static void mpi3mr_process_admin_reply_desc(struct mpi3mr_softc *sc, + Mpi3DefaultReplyDescriptor_t *reply_desc, U64 *reply_dma) +{ + U16 reply_desc_type, host_tag = 0, idx; + U16 ioc_status = MPI3_IOCSTATUS_SUCCESS; + U32 ioc_loginfo = 0; + Mpi3StatusReplyDescriptor_t *status_desc; + Mpi3AddressReplyDescriptor_t *addr_desc; + Mpi3SuccessReplyDescriptor_t *success_desc; + Mpi3DefaultReply_t *def_reply = NULL; + struct mpi3mr_drvr_cmd *cmdptr = NULL; + Mpi3SCSIIOReply_t *scsi_reply; + U8 *sense_buf = NULL; + + *reply_dma = 0; + reply_desc_type = reply_desc->ReplyFlags & + MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK; + switch (reply_desc_type) { + case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS: + status_desc = (Mpi3StatusReplyDescriptor_t *)reply_desc; + host_tag = status_desc->HostTag; + ioc_status = status_desc->IOCStatus; + if (ioc_status & + MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) + ioc_loginfo = status_desc->IOCLogInfo; + ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; + break; + case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY: + addr_desc = (Mpi3AddressReplyDescriptor_t *)reply_desc; + *reply_dma = addr_desc->ReplyFrameAddress; + def_reply = mpi3mr_get_reply_virt_addr(sc, *reply_dma); + if (def_reply == NULL) + goto out; + host_tag = def_reply->HostTag; + ioc_status = def_reply->IOCStatus; + if (ioc_status & + MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) + ioc_loginfo = def_reply->IOCLogInfo; + ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; + if (def_reply->Function == MPI3_FUNCTION_SCSI_IO) { + scsi_reply = (Mpi3SCSIIOReply_t *)def_reply; + sense_buf = mpi3mr_get_sensebuf_virt_addr(sc, + scsi_reply->SenseDataBufferAddress); + } + break; + case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS: + success_desc = (Mpi3SuccessReplyDescriptor_t *)reply_desc; + host_tag = success_desc->HostTag; + break; + default: + break; + } + switch (host_tag) { + case MPI3MR_HOSTTAG_INITCMDS: + cmdptr = &sc->init_cmds; + break; + case MPI3MR_HOSTTAG_IOCTLCMDS: + cmdptr = &sc->ioctl_cmds; + break; + case MPI3MR_HOSTTAG_TMS: + cmdptr = &sc->host_tm_cmds; + wakeup((void *)&sc->tm_chan); + break; + case MPI3MR_HOSTTAG_PELABORT: + cmdptr = &sc->pel_abort_cmd; + break; + case MPI3MR_HOSTTAG_PELWAIT: + cmdptr = &sc->pel_cmds; + break; + case MPI3MR_HOSTTAG_INVALID: + if (def_reply && def_reply->Function == + MPI3_FUNCTION_EVENT_NOTIFICATION) + mpi3mr_handle_events(sc, *reply_dma ,def_reply); + default: + break; + } + + if (host_tag >= MPI3MR_HOSTTAG_DEVRMCMD_MIN && + host_tag <= MPI3MR_HOSTTAG_DEVRMCMD_MAX ) { + idx = host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN; + cmdptr = &sc->dev_rmhs_cmds[idx]; + } + + if (host_tag >= MPI3MR_HOSTTAG_EVTACKCMD_MIN && + host_tag <= MPI3MR_HOSTTAG_EVTACKCMD_MAX) { + idx = host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN; + cmdptr = &sc->evtack_cmds[idx]; + } + + if (cmdptr) { + if (cmdptr->state & MPI3MR_CMD_PENDING) { + cmdptr->state |= MPI3MR_CMD_COMPLETE; + cmdptr->ioc_loginfo = ioc_loginfo; + cmdptr->ioc_status = ioc_status; + cmdptr->state &= ~MPI3MR_CMD_PENDING; + if (def_reply) { + cmdptr->state |= MPI3MR_CMD_REPLYVALID; + memcpy((U8 *)cmdptr->reply, (U8 *)def_reply, + sc->reply_sz); + } + if (sense_buf && cmdptr->sensebuf) { + cmdptr->is_senseprst = 1; + memcpy(cmdptr->sensebuf, sense_buf, + MPI3MR_SENSEBUF_SZ); + } + if (cmdptr->is_waiting) { + complete(&cmdptr->completion); + cmdptr->is_waiting = 0; + } else if (cmdptr->callback) + cmdptr->callback(sc, cmdptr); + } + } +out: + if (sense_buf != NULL) + mpi3mr_repost_sense_buf(sc, + scsi_reply->SenseDataBufferAddress); + return; +} + +/* + * mpi3mr_complete_admin_cmd: ISR routine for admin commands + * @sc: Adapter's soft instance + * + * This function processes admin command completions. + */ +static int mpi3mr_complete_admin_cmd(struct mpi3mr_softc *sc) +{ + U32 exp_phase = sc->admin_reply_ephase; + U32 adm_reply_ci = sc->admin_reply_ci; + U32 num_adm_reply = 0; + U64 reply_dma = 0; + Mpi3DefaultReplyDescriptor_t *reply_desc; + + mtx_lock_spin(&sc->admin_reply_lock); + if (sc->admin_in_use == false) { + sc->admin_in_use = true; + mtx_unlock_spin(&sc->admin_reply_lock); + } else { + mtx_unlock_spin(&sc->admin_reply_lock); + return 0; + } + + reply_desc = (Mpi3DefaultReplyDescriptor_t *)sc->admin_reply + + adm_reply_ci; + + if ((reply_desc->ReplyFlags & + MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) { + mtx_lock_spin(&sc->admin_reply_lock); + sc->admin_in_use = false; + mtx_unlock_spin(&sc->admin_reply_lock); + return 0; + } + + do { + sc->admin_req_ci = reply_desc->RequestQueueCI; + mpi3mr_process_admin_reply_desc(sc, reply_desc, &reply_dma); + if (reply_dma) + mpi3mr_repost_reply_buf(sc, reply_dma); + num_adm_reply++; + if (++adm_reply_ci == sc->num_admin_replies) { + adm_reply_ci = 0; + exp_phase ^= 1; + } + reply_desc = + (Mpi3DefaultReplyDescriptor_t *)sc->admin_reply + + adm_reply_ci; + if ((reply_desc->ReplyFlags & + MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) + break; + } while (1); + + mpi3mr_regwrite(sc, MPI3_SYSIF_ADMIN_REPLY_Q_CI_OFFSET, adm_reply_ci); + sc->admin_reply_ci = adm_reply_ci; + sc->admin_reply_ephase = exp_phase; + mtx_lock_spin(&sc->admin_reply_lock); + sc->admin_in_use = false; + mtx_unlock_spin(&sc->admin_reply_lock); + return num_adm_reply; +} + +static void +mpi3mr_cmd_done(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cmd) +{ + mpi3mr_unmap_request(sc, cmd); + + mtx_lock(&sc->mpi3mr_mtx); + if (cmd->callout_owner) { + callout_stop(&cmd->callout); + cmd->callout_owner = false; + } + + if (sc->unrecoverable) + mpi3mr_set_ccbstatus(cmd->ccb, CAM_DEV_NOT_THERE); + + xpt_done(cmd->ccb); + cmd->ccb = NULL; + mtx_unlock(&sc->mpi3mr_mtx); + mpi3mr_release_command(cmd); +} + +void mpi3mr_process_op_reply_desc(struct mpi3mr_softc *sc, + Mpi3DefaultReplyDescriptor_t *reply_desc, U64 *reply_dma) +{ + U16 reply_desc_type, host_tag = 0; + U16 ioc_status = MPI3_IOCSTATUS_SUCCESS; + U32 ioc_loginfo = 0; + Mpi3StatusReplyDescriptor_t *status_desc = NULL; + Mpi3AddressReplyDescriptor_t *addr_desc = NULL; + Mpi3SuccessReplyDescriptor_t *success_desc = NULL; + Mpi3SCSIIOReply_t *scsi_reply = NULL; + U8 *sense_buf = NULL; + U8 scsi_state = 0, scsi_status = 0, sense_state = 0; + U32 xfer_count = 0, sense_count =0, resp_data = 0; + struct mpi3mr_cmd *cm = NULL; + union ccb *ccb; + struct ccb_scsiio *csio; + struct mpi3mr_cam_softc *cam_sc; + U32 target_id; + U8 *scsi_cdb; + struct mpi3mr_target *target = NULL; + U32 ioc_pend_data_len = 0, tg_pend_data_len = 0, data_len_blks = 0; + struct mpi3mr_throttle_group_info *tg = NULL; + U8 throttle_enabled_dev = 0; + static int ratelimit; + + *reply_dma = 0; + reply_desc_type = reply_desc->ReplyFlags & + MPI3_REPLY_DESCRIPT_FLAGS_TYPE_MASK; + switch (reply_desc_type) { + case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_STATUS: + status_desc = (Mpi3StatusReplyDescriptor_t *)reply_desc; + host_tag = status_desc->HostTag; + ioc_status = status_desc->IOCStatus; + if (ioc_status & + MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) + ioc_loginfo = status_desc->IOCLogInfo; + ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; + break; + case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY: + addr_desc = (Mpi3AddressReplyDescriptor_t *)reply_desc; + *reply_dma = addr_desc->ReplyFrameAddress; + scsi_reply = mpi3mr_get_reply_virt_addr(sc, + *reply_dma); + if (scsi_reply == NULL) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "scsi_reply is NULL, " + "this shouldn't happen, reply_desc: %p\n", + reply_desc); + goto out; + } + + host_tag = scsi_reply->HostTag; + ioc_status = scsi_reply->IOCStatus; + scsi_status = scsi_reply->SCSIStatus; + scsi_state = scsi_reply->SCSIState; + sense_state = (scsi_state & MPI3_SCSI_STATE_SENSE_MASK); + xfer_count = scsi_reply->TransferCount; + sense_count = scsi_reply->SenseCount; + resp_data = scsi_reply->ResponseData; + sense_buf = mpi3mr_get_sensebuf_virt_addr(sc, + scsi_reply->SenseDataBufferAddress); + if (ioc_status & + MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) + ioc_loginfo = scsi_reply->IOCLogInfo; + ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; + if (sense_state == MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY) + mpi3mr_dprint(sc, MPI3MR_ERROR, "Ran out of sense buffers\n"); + + break; + case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS: + success_desc = (Mpi3SuccessReplyDescriptor_t *)reply_desc; + host_tag = success_desc->HostTag; + + default: + break; + } + + cm = sc->cmd_list[host_tag]; + + if (cm->state == MPI3MR_CMD_STATE_FREE) + goto out; + + cam_sc = sc->cam_sc; + ccb = cm->ccb; + csio = &ccb->csio; + target_id = csio->ccb_h.target_id; + + scsi_cdb = scsiio_cdb_ptr(csio); + + target = mpi3mr_find_target_by_per_id(cam_sc, target_id); + if (sc->iot_enable) { + data_len_blks = csio->dxfer_len >> 9; + + if (target) { + tg = target->throttle_group; + throttle_enabled_dev = + target->io_throttle_enabled; + } + + if ((data_len_blks >= sc->io_throttle_data_length) && + throttle_enabled_dev) { + mpi3mr_atomic_sub(&sc->pend_large_data_sz, data_len_blks); + ioc_pend_data_len = mpi3mr_atomic_read( + &sc->pend_large_data_sz); + if (tg) { + mpi3mr_atomic_sub(&tg->pend_large_data_sz, + data_len_blks); + tg_pend_data_len = mpi3mr_atomic_read(&tg->pend_large_data_sz); + if (ratelimit % 1000) { + mpi3mr_dprint(sc, MPI3MR_IOT, + "large vd_io completion persist_id(%d), handle(0x%04x), data_len(%d)," + "ioc_pending(%d), tg_pending(%d), ioc_low(%d), tg_low(%d)\n", + target->per_id, + target->dev_handle, + data_len_blks, ioc_pend_data_len, + tg_pend_data_len, + sc->io_throttle_low, + tg->low); + ratelimit++; + } + if (tg->io_divert && ((ioc_pend_data_len <= + sc->io_throttle_low) && + (tg_pend_data_len <= tg->low))) { + tg->io_divert = 0; + mpi3mr_dprint(sc, MPI3MR_IOT, + "VD: Coming out of divert perst_id(%d) tg_id(%d)\n", + target->per_id, tg->id); + mpi3mr_set_io_divert_for_all_vd_in_tg( + sc, tg, 0); + } + } else { + if (ratelimit % 1000) { + mpi3mr_dprint(sc, MPI3MR_IOT, + "large pd_io completion persist_id(%d), handle(0x%04x), data_len(%d), ioc_pending(%d), ioc_low(%d)\n", + target->per_id, + target->dev_handle, + data_len_blks, ioc_pend_data_len, + sc->io_throttle_low); + ratelimit++; + } + + if (ioc_pend_data_len <= sc->io_throttle_low) { + target->io_divert = 0; + mpi3mr_dprint(sc, MPI3MR_IOT, + "PD: Coming out of divert perst_id(%d)\n", + target->per_id); + } + } + + } else if (target->io_divert) { + ioc_pend_data_len = mpi3mr_atomic_read(&sc->pend_large_data_sz); + if (!tg) { + if (ratelimit % 1000) { + mpi3mr_dprint(sc, MPI3MR_IOT, + "pd_io completion persist_id(%d), handle(0x%04x), data_len(%d), ioc_pending(%d), ioc_low(%d)\n", + target->per_id, + target->dev_handle, + data_len_blks, ioc_pend_data_len, + sc->io_throttle_low); + ratelimit++; + } + + if ( ioc_pend_data_len <= sc->io_throttle_low) { + mpi3mr_dprint(sc, MPI3MR_IOT, + "PD: Coming out of divert perst_id(%d)\n", + target->per_id); + target->io_divert = 0; + } + + } else if (ioc_pend_data_len <= sc->io_throttle_low) { + tg_pend_data_len = mpi3mr_atomic_read(&tg->pend_large_data_sz); + if (ratelimit % 1000) { + mpi3mr_dprint(sc, MPI3MR_IOT, + "vd_io completion persist_id(%d), handle(0x%04x), data_len(%d)," + "ioc_pending(%d), tg_pending(%d), ioc_low(%d), tg_low(%d)\n", + target->per_id, + target->dev_handle, + data_len_blks, ioc_pend_data_len, + tg_pend_data_len, + sc->io_throttle_low, + tg->low); + ratelimit++; + } + if (tg->io_divert && (tg_pend_data_len <= tg->low)) { + tg->io_divert = 0; + mpi3mr_dprint(sc, MPI3MR_IOT, + "VD: Coming out of divert perst_id(%d) tg_id(%d)\n", + target->per_id, tg->id); + mpi3mr_set_io_divert_for_all_vd_in_tg( + sc, tg, 0); + } + + } + } + } + + if (success_desc) { + mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP); + goto out_success; + } + + if (ioc_status == MPI3_IOCSTATUS_SCSI_DATA_UNDERRUN + && xfer_count == 0 && (scsi_status == MPI3_SCSI_STATUS_BUSY || + scsi_status == MPI3_SCSI_STATUS_RESERVATION_CONFLICT || + scsi_status == MPI3_SCSI_STATUS_TASK_SET_FULL)) + ioc_status = MPI3_IOCSTATUS_SUCCESS; + + if ((sense_state == MPI3_SCSI_STATE_SENSE_VALID) && sense_count + && sense_buf) { + int sense_len, returned_sense_len; + + returned_sense_len = min(le32toh(sense_count), + sizeof(struct scsi_sense_data)); + if (returned_sense_len < csio->sense_len) + csio->sense_resid = csio->sense_len - + returned_sense_len; + else + csio->sense_resid = 0; + + sense_len = min(returned_sense_len, + csio->sense_len - csio->sense_resid); + bzero(&csio->sense_data, sizeof(csio->sense_data)); + bcopy(sense_buf, &csio->sense_data, sense_len); + ccb->ccb_h.status |= CAM_AUTOSNS_VALID; + } + + switch (ioc_status) { + case MPI3_IOCSTATUS_BUSY: + case MPI3_IOCSTATUS_INSUFFICIENT_RESOURCES: + mpi3mr_set_ccbstatus(ccb, CAM_REQUEUE_REQ); + break; + case MPI3_IOCSTATUS_SCSI_DEVICE_NOT_THERE: + /* + * If devinfo is 0 this will be a volume. In that case don't + * tell CAM that the volume is not there. We want volumes to + * be enumerated until they are deleted/removed, not just + * failed. + */ + if (cm->targ->devinfo == 0) + mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP); + else + mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); + break; + case MPI3_IOCSTATUS_SCSI_TASK_TERMINATED: + case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED: + case MPI3_IOCSTATUS_SCSI_EXT_TERMINATED: + mpi3mr_set_ccbstatus(ccb, CAM_SCSI_BUSY); + mpi3mr_dprint(sc, MPI3MR_TRACE, + "func: %s line:%d tgt %u Hosttag %u loginfo %x\n", + __func__, __LINE__, + target_id, cm->hosttag, + le32toh(scsi_reply->IOCLogInfo)); + mpi3mr_dprint(sc, MPI3MR_TRACE, + "SCSIStatus %x SCSIState %x xfercount %u\n", + scsi_reply->SCSIStatus, scsi_reply->SCSIState, + le32toh(xfer_count)); + break; + case MPI3_IOCSTATUS_SCSI_DATA_OVERRUN: + /* resid is ignored for this condition */ + csio->resid = 0; + mpi3mr_set_ccbstatus(ccb, CAM_DATA_RUN_ERR); + break; + case MPI3_IOCSTATUS_SCSI_DATA_UNDERRUN: + csio->resid = cm->length - le32toh(xfer_count); + case MPI3_IOCSTATUS_SCSI_RECOVERED_ERROR: + case MPI3_IOCSTATUS_SUCCESS: + if ((scsi_reply->IOCStatus & MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK) == + MPI3_IOCSTATUS_SCSI_RECOVERED_ERROR) + mpi3mr_dprint(sc, MPI3MR_XINFO, "func: %s line: %d recovered error\n", __func__, __LINE__); + + /* Completion failed at the transport level. */ + if (scsi_reply->SCSIState & (MPI3_SCSI_STATE_NO_SCSI_STATUS | + MPI3_SCSI_STATE_TERMINATED)) { + mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); + break; + } + + /* In a modern packetized environment, an autosense failure + * implies that there's not much else that can be done to + * recover the command. + */ + if (scsi_reply->SCSIState & MPI3_SCSI_STATE_SENSE_VALID) { + mpi3mr_set_ccbstatus(ccb, CAM_AUTOSENSE_FAIL); + break; + } + + /* + * Intentionally override the normal SCSI status reporting + * for these two cases. These are likely to happen in a + * multi-initiator environment, and we want to make sure that + * CAM retries these commands rather than fail them. + */ + if ((scsi_reply->SCSIStatus == MPI3_SCSI_STATUS_COMMAND_TERMINATED) || + (scsi_reply->SCSIStatus == MPI3_SCSI_STATUS_TASK_ABORTED)) { + mpi3mr_set_ccbstatus(ccb, CAM_REQ_ABORTED); + break; + } + + /* Handle normal status and sense */ + csio->scsi_status = scsi_reply->SCSIStatus; + if (scsi_reply->SCSIStatus == MPI3_SCSI_STATUS_GOOD) + mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP); + else + mpi3mr_set_ccbstatus(ccb, CAM_SCSI_STATUS_ERROR); + + if (scsi_reply->SCSIState & MPI3_SCSI_STATE_SENSE_VALID) { + int sense_len, returned_sense_len; + + returned_sense_len = min(le32toh(scsi_reply->SenseCount), + sizeof(struct scsi_sense_data)); + if (returned_sense_len < csio->sense_len) + csio->sense_resid = csio->sense_len - + returned_sense_len; + else + csio->sense_resid = 0; + + sense_len = min(returned_sense_len, + csio->sense_len - csio->sense_resid); + bzero(&csio->sense_data, sizeof(csio->sense_data)); + bcopy(cm->sense, &csio->sense_data, sense_len); + ccb->ccb_h.status |= CAM_AUTOSNS_VALID; + } + + break; + case MPI3_IOCSTATUS_INVALID_SGL: + mpi3mr_set_ccbstatus(ccb, CAM_UNREC_HBA_ERROR); + break; + case MPI3_IOCSTATUS_EEDP_GUARD_ERROR: + case MPI3_IOCSTATUS_EEDP_REF_TAG_ERROR: + case MPI3_IOCSTATUS_EEDP_APP_TAG_ERROR: + case MPI3_IOCSTATUS_SCSI_PROTOCOL_ERROR: + case MPI3_IOCSTATUS_INVALID_FUNCTION: + case MPI3_IOCSTATUS_INTERNAL_ERROR: + case MPI3_IOCSTATUS_INVALID_FIELD: + case MPI3_IOCSTATUS_INVALID_STATE: + case MPI3_IOCSTATUS_SCSI_IO_DATA_ERROR: + case MPI3_IOCSTATUS_SCSI_TASK_MGMT_FAILED: + case MPI3_IOCSTATUS_INSUFFICIENT_POWER: + case MPI3_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: + default: + csio->resid = cm->length; + mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); + break; + } + +out_success: + if (mpi3mr_get_ccbstatus(ccb) != CAM_REQ_CMP) { + ccb->ccb_h.status |= CAM_DEV_QFRZN; + xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); + } + + mpi3mr_atomic_dec(&cm->targ->outstanding); + mpi3mr_cmd_done(sc, cm); + mpi3mr_dprint(sc, MPI3MR_TRACE, "Completion IO path :" + " cdb[0]: %x targetid: 0x%x SMID: %x ioc_status: 0x%x ioc_loginfo: 0x%x scsi_status: 0x%x " + "scsi_state: 0x%x response_data: 0x%x\n", scsi_cdb[0], target_id, host_tag, + ioc_status, ioc_loginfo, scsi_status, scsi_state, resp_data); + mpi3mr_atomic_dec(&sc->fw_outstanding); +out: + + if (sense_buf) + mpi3mr_repost_sense_buf(sc, + scsi_reply->SenseDataBufferAddress); + return; +} + +/* + * mpi3mr_complete_io_cmd: ISR routine for IO commands + * @sc: Adapter's soft instance + * @irq_ctx: Driver's internal per IRQ structure + * + * This function processes IO command completions. + */ +int mpi3mr_complete_io_cmd(struct mpi3mr_softc *sc, + struct mpi3mr_irq_context *irq_ctx) +{ + struct mpi3mr_op_reply_queue *op_reply_q = irq_ctx->op_reply_q; + U32 exp_phase = op_reply_q->ephase; + U32 reply_ci = op_reply_q->ci; + U32 num_op_replies = 0; + U64 reply_dma = 0; + Mpi3DefaultReplyDescriptor_t *reply_desc; + U16 req_qid = 0; + + mtx_lock_spin(&op_reply_q->q_lock); + if (op_reply_q->in_use == false) { + op_reply_q->in_use = true; + mtx_unlock_spin(&op_reply_q->q_lock); + } else { + mtx_unlock_spin(&op_reply_q->q_lock); + return 0; + } + + reply_desc = (Mpi3DefaultReplyDescriptor_t *)op_reply_q->q_base + reply_ci; + mpi3mr_dprint(sc, MPI3MR_TRACE, "[QID:%d]:reply_desc: (%pa) reply_ci: %x" + " reply_desc->ReplyFlags: 0x%x\n" + "reply_q_base_phys: %#016jx reply_q_base: (%pa) exp_phase: %x\n", + op_reply_q->qid, reply_desc, reply_ci, reply_desc->ReplyFlags, op_reply_q->q_base_phys, + op_reply_q->q_base, exp_phase); + + if (((reply_desc->ReplyFlags & + MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) || !op_reply_q->qid) { + mtx_lock_spin(&op_reply_q->q_lock); + op_reply_q->in_use = false; + mtx_unlock_spin(&op_reply_q->q_lock); + return 0; + } + + do { + req_qid = reply_desc->RequestQueueID; + sc->op_req_q[req_qid - 1].ci = + reply_desc->RequestQueueCI; + + mpi3mr_process_op_reply_desc(sc, reply_desc, &reply_dma); + mpi3mr_atomic_dec(&op_reply_q->pend_ios); + if (reply_dma) + mpi3mr_repost_reply_buf(sc, reply_dma); + num_op_replies++; + if (++reply_ci == op_reply_q->num_replies) { + reply_ci = 0; + exp_phase ^= 1; + } + reply_desc = + (Mpi3DefaultReplyDescriptor_t *)op_reply_q->q_base + reply_ci; + if ((reply_desc->ReplyFlags & + MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) + break; + } while (1); + + + mpi3mr_regwrite(sc, MPI3_SYSIF_OPER_REPLY_Q_N_CI_OFFSET(op_reply_q->qid), reply_ci); + op_reply_q->ci = reply_ci; + op_reply_q->ephase = exp_phase; + mtx_lock_spin(&op_reply_q->q_lock); + op_reply_q->in_use = false; + mtx_unlock_spin(&op_reply_q->q_lock); + return num_op_replies; +} + +/* + * mpi3mr_isr: Primary ISR function + * privdata: Driver's internal per IRQ structure + * + * This is driver's primary ISR function which is being called whenever any admin/IO + * command completion. + */ +void mpi3mr_isr(void *privdata) +{ + struct mpi3mr_irq_context *irq_ctx = (struct mpi3mr_irq_context *)privdata; + struct mpi3mr_softc *sc = irq_ctx->sc; + U16 msi_idx; + + if (!irq_ctx) + return; + + msi_idx = irq_ctx->msix_index; + + if (!sc->intr_enabled) + return; + + if (!msi_idx) + mpi3mr_complete_admin_cmd(sc); + + if (irq_ctx->op_reply_q && irq_ctx->op_reply_q->qid) { + mpi3mr_complete_io_cmd(sc, irq_ctx); + } +} + +/* + * mpi3mr_alloc_requests - Allocates host commands + * @sc: Adapter reference + * + * This function allocates controller supported host commands + * + * Return: 0 on success and proper error codes on failure + */ +int +mpi3mr_alloc_requests(struct mpi3mr_softc *sc) +{ + struct mpi3mr_cmd *cmd; + int i, j, nsegs, ret; + + nsegs = MPI3MR_SG_DEPTH; + ret = bus_dma_tag_create( sc->mpi3mr_parent_dmat, /* parent */ + 1, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MAXPHYS,/* maxsize */ + nsegs, /* nsegments */ + MAXPHYS,/* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ + busdma_lock_mutex, /* lockfunc */ + &sc->io_lock, /* lockarg */ + &sc->buffer_dmat); + if (ret) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate buffer DMA tag ret: %d\n", ret); + return (ENOMEM); + } + + /* + * sc->cmd_list is an array of struct mpi3mr_cmd pointers. + * Allocate the dynamic array first and then allocate individual + * commands. + */ + sc->cmd_list = malloc(sizeof(struct mpi3mr_cmd *) * sc->max_host_ios, + M_MPI3MR, M_NOWAIT | M_ZERO); + + if (!sc->cmd_list) { + device_printf(sc->mpi3mr_dev, "Cannot alloc memory for mpt_cmd_list.\n"); + return (ENOMEM); + } + + for (i = 0; i < sc->max_host_ios; i++) { + sc->cmd_list[i] = malloc(sizeof(struct mpi3mr_cmd), + M_MPI3MR, M_NOWAIT | M_ZERO); + if (!sc->cmd_list[i]) { + for (j = 0; j < i; j++) + free(sc->cmd_list[j], M_MPI3MR); + free(sc->cmd_list, M_MPI3MR); + sc->cmd_list = NULL; + return (ENOMEM); + } + } + + for (i = 1; i < sc->max_host_ios; i++) { + cmd = sc->cmd_list[i]; + cmd->hosttag = i; + cmd->sc = sc; + cmd->state = MPI3MR_CMD_STATE_BUSY; + callout_init_mtx(&cmd->callout, &sc->mpi3mr_mtx, 0); + cmd->ccb = NULL; + TAILQ_INSERT_TAIL(&(sc->cmd_list_head), cmd, next); + if (bus_dmamap_create(sc->buffer_dmat, 0, &cmd->dmamap)) + return ENOMEM; + } + return (0); +} + +/* + * mpi3mr_get_command: Get a coomand structure from free command pool + * @sc: Adapter soft instance + * Return: MPT command reference + * + * This function returns an MPT command to the caller. + */ +struct mpi3mr_cmd * +mpi3mr_get_command(struct mpi3mr_softc *sc) +{ + struct mpi3mr_cmd *cmd = NULL; + + mtx_lock(&sc->cmd_pool_lock); + if (!TAILQ_EMPTY(&sc->cmd_list_head)) { + cmd = TAILQ_FIRST(&sc->cmd_list_head); + TAILQ_REMOVE(&sc->cmd_list_head, cmd, next); + } else { + goto out; + } + + mpi3mr_dprint(sc, MPI3MR_TRACE, "Get command SMID: 0x%x\n", cmd->hosttag); + + memset((uint8_t *)&cmd->io_request, 0, MPI3MR_AREQ_FRAME_SZ); + cmd->data_dir = 0; + cmd->ccb = NULL; + cmd->targ = NULL; + cmd->max_segs = 0; + cmd->lun = 0; + cmd->state = MPI3MR_CMD_STATE_BUSY; + cmd->data = NULL; + cmd->length = 0; + cmd->out_len = 0; +out: + mtx_unlock(&sc->cmd_pool_lock); + return cmd; +} + +/* + * mpi3mr_release_command: Return a cmd to free command pool + * input: Command packet for return to free command pool + * + * This function returns an MPT command to the free command list. + */ +void +mpi3mr_release_command(struct mpi3mr_cmd *cmd) +{ + struct mpi3mr_softc *sc = cmd->sc; + + mtx_lock(&sc->cmd_pool_lock); + TAILQ_INSERT_HEAD(&(sc->cmd_list_head), cmd, next); + cmd->state = MPI3MR_CMD_STATE_FREE; + cmd->req_qidx = 0; + mpi3mr_dprint(sc, MPI3MR_TRACE, "Release command SMID: 0x%x\n", cmd->hosttag); + mtx_unlock(&sc->cmd_pool_lock); + + return; +} + + /** + * mpi3mr_free_ioctl_dma_memory - free memory for ioctl dma + * @sc: Adapter instance reference + * + * Free the DMA memory allocated for IOCTL handling purpose. + * + * Return: None + */ +static void mpi3mr_free_ioctl_dma_memory(struct mpi3mr_softc *sc) +{ + U16 i; + struct dma_memory_desc *mem_desc; + + for (i=0; iioctl_sge[i]; + if (mem_desc->addr && mem_desc->dma_addr) { + bus_dmamap_unload(mem_desc->tag, mem_desc->dmamap); + bus_dmamem_free(mem_desc->tag, mem_desc->addr, mem_desc->dmamap); + mem_desc->addr = NULL; + if (mem_desc->tag != NULL) + bus_dma_tag_destroy(mem_desc->tag); + } + } + + mem_desc = &sc->ioctl_chain_sge; + if (mem_desc->addr && mem_desc->dma_addr) { + bus_dmamap_unload(mem_desc->tag, mem_desc->dmamap); + bus_dmamem_free(mem_desc->tag, mem_desc->addr, mem_desc->dmamap); + mem_desc->addr = NULL; + if (mem_desc->tag != NULL) + bus_dma_tag_destroy(mem_desc->tag); + } + + mem_desc = &sc->ioctl_resp_sge; + if (mem_desc->addr && mem_desc->dma_addr) { + bus_dmamap_unload(mem_desc->tag, mem_desc->dmamap); + bus_dmamem_free(mem_desc->tag, mem_desc->addr, mem_desc->dmamap); + mem_desc->addr = NULL; + if (mem_desc->tag != NULL) + bus_dma_tag_destroy(mem_desc->tag); + } + + sc->ioctl_sges_allocated = false; +} + +/** + * mpi3mr_alloc_ioctl_dma_memory - Alloc memory for ioctl dma + * @sc: Adapter instance reference + * + * This function allocates dmaable memory required to handle the + * application issued MPI3 IOCTL requests. + * + * Return: None + */ +void mpi3mr_alloc_ioctl_dma_memory(struct mpi3mr_softc *sc) +{ + struct dma_memory_desc *mem_desc; + U16 i; + + for (i=0; iioctl_sge[i]; + mem_desc->size = MPI3MR_IOCTL_SGE_SIZE; + + if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ + 4, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + mem_desc->size, /* maxsize */ + 1, /* nsegments */ + mem_desc->size, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &mem_desc->tag)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n"); + goto out_failed; + } + + if (bus_dmamem_alloc(mem_desc->tag, (void **)&mem_desc->addr, + BUS_DMA_NOWAIT, &mem_desc->dmamap)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n"); + goto out_failed; + } + bzero(mem_desc->addr, mem_desc->size); + bus_dmamap_load(mem_desc->tag, mem_desc->dmamap, mem_desc->addr, mem_desc->size, + mpi3mr_memaddr_cb, &mem_desc->dma_addr, 0); + + if (!mem_desc->addr) + goto out_failed; + } + + mem_desc = &sc->ioctl_chain_sge; + mem_desc->size = MPI3MR_4K_PGSZ; + if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ + 4, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + mem_desc->size, /* maxsize */ + 1, /* nsegments */ + mem_desc->size, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &mem_desc->tag)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n"); + goto out_failed; + } + + if (bus_dmamem_alloc(mem_desc->tag, (void **)&mem_desc->addr, + BUS_DMA_NOWAIT, &mem_desc->dmamap)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n"); + goto out_failed; + } + bzero(mem_desc->addr, mem_desc->size); + bus_dmamap_load(mem_desc->tag, mem_desc->dmamap, mem_desc->addr, mem_desc->size, + mpi3mr_memaddr_cb, &mem_desc->dma_addr, 0); + + if (!mem_desc->addr) + goto out_failed; + + mem_desc = &sc->ioctl_resp_sge; + mem_desc->size = MPI3MR_4K_PGSZ; + if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ + 4, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + mem_desc->size, /* maxsize */ + 1, /* nsegments */ + mem_desc->size, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &mem_desc->tag)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate request DMA tag\n"); + goto out_failed; + } + + if (bus_dmamem_alloc(mem_desc->tag, (void **)&mem_desc->addr, + BUS_DMA_NOWAIT, &mem_desc->dmamap)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate replies memory\n"); + goto out_failed; + } + bzero(mem_desc->addr, mem_desc->size); + bus_dmamap_load(mem_desc->tag, mem_desc->dmamap, mem_desc->addr, mem_desc->size, + mpi3mr_memaddr_cb, &mem_desc->dma_addr, 0); + + if (!mem_desc->addr) + goto out_failed; + + sc->ioctl_sges_allocated = true; + + return; +out_failed: + printf("cannot allocate DMA memory for the mpt commands" + " from the applications, application interface for MPT command is disabled\n"); + mpi3mr_free_ioctl_dma_memory(sc); +} + +void +mpi3mr_destory_mtx(struct mpi3mr_softc *sc) +{ + int i; + struct mpi3mr_op_req_queue *op_req_q; + struct mpi3mr_op_reply_queue *op_reply_q; + + if (sc->admin_reply) { + if (mtx_initialized(&sc->admin_reply_lock)) + mtx_destroy(&sc->admin_reply_lock); + } + + if (sc->op_reply_q) { + for(i = 0; i < sc->num_queues; i++) { + op_reply_q = sc->op_reply_q + i; + if (mtx_initialized(&op_reply_q->q_lock)) + mtx_destroy(&op_reply_q->q_lock); + } + } + + if (sc->op_req_q) { + for(i = 0; i < sc->num_queues; i++) { + op_req_q = sc->op_req_q + i; + if (mtx_initialized(&op_req_q->q_lock)) + mtx_destroy(&op_req_q->q_lock); + } + } + + if (mtx_initialized(&sc->init_cmds.completion.lock)) + mtx_destroy(&sc->init_cmds.completion.lock); + + if (mtx_initialized(&sc->ioctl_cmds.completion.lock)) + mtx_destroy(&sc->ioctl_cmds.completion.lock); + + if (mtx_initialized(&sc->host_tm_cmds.completion.lock)) + mtx_destroy(&sc->host_tm_cmds.completion.lock); + + for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { + if (mtx_initialized(&sc->dev_rmhs_cmds[i].completion.lock)) + mtx_destroy(&sc->dev_rmhs_cmds[i].completion.lock); + } + + if (mtx_initialized(&sc->reset_mutex)) + mtx_destroy(&sc->reset_mutex); + + if (mtx_initialized(&sc->target_lock)) + mtx_destroy(&sc->target_lock); + + if (mtx_initialized(&sc->fwevt_lock)) + mtx_destroy(&sc->fwevt_lock); + + if (mtx_initialized(&sc->cmd_pool_lock)) + mtx_destroy(&sc->cmd_pool_lock); + + if (mtx_initialized(&sc->reply_free_q_lock)) + mtx_destroy(&sc->reply_free_q_lock); + + if (mtx_initialized(&sc->sense_buf_q_lock)) + mtx_destroy(&sc->sense_buf_q_lock); + + if (mtx_initialized(&sc->chain_buf_lock)) + mtx_destroy(&sc->chain_buf_lock); + + if (mtx_initialized(&sc->admin_req_lock)) + mtx_destroy(&sc->admin_req_lock); + + if (mtx_initialized(&sc->mpi3mr_mtx)) + mtx_destroy(&sc->mpi3mr_mtx); +} + +/** + * mpi3mr_free_mem - Freeup adapter level data structures + * @sc: Adapter reference + * + * Return: Nothing. + */ +void +mpi3mr_free_mem(struct mpi3mr_softc *sc) +{ + int i; + struct mpi3mr_op_req_queue *op_req_q; + struct mpi3mr_op_reply_queue *op_reply_q; + struct mpi3mr_irq_context *irq_ctx; + + if (sc->cmd_list) { + for (i = 0; i < sc->max_host_ios; i++) { + free(sc->cmd_list[i], M_MPI3MR); + } + free(sc->cmd_list, M_MPI3MR); + sc->cmd_list = NULL; + } + + if (sc->pel_seq_number && sc->pel_seq_number_dma) { + bus_dmamap_unload(sc->pel_seq_num_dmatag, sc->pel_seq_num_dmamap); + bus_dmamem_free(sc->pel_seq_num_dmatag, sc->pel_seq_number, sc->pel_seq_num_dmamap); + sc->pel_seq_number = NULL; + if (sc->pel_seq_num_dmatag != NULL) + bus_dma_tag_destroy(sc->pel_seq_num_dmatag); + } + + if (sc->throttle_groups) { + free(sc->throttle_groups, M_MPI3MR); + sc->throttle_groups = NULL; + } + + /* Free up operational queues*/ + if (sc->op_req_q) { + for (i = 0; i < sc->num_queues; i++) { + op_req_q = sc->op_req_q + i; + if (op_req_q->q_base && op_req_q->q_base_phys) { + bus_dmamap_unload(op_req_q->q_base_tag, op_req_q->q_base_dmamap); + bus_dmamem_free(op_req_q->q_base_tag, op_req_q->q_base, op_req_q->q_base_dmamap); + op_req_q->q_base = NULL; + if (op_req_q->q_base_tag != NULL) + bus_dma_tag_destroy(op_req_q->q_base_tag); + } + } + free(sc->op_req_q, M_MPI3MR); + sc->op_req_q = NULL; + } + + if (sc->op_reply_q) { + for (i = 0; i < sc->num_queues; i++) { + op_reply_q = sc->op_reply_q + i; + if (op_reply_q->q_base && op_reply_q->q_base_phys) { + bus_dmamap_unload(op_reply_q->q_base_tag, op_reply_q->q_base_dmamap); + bus_dmamem_free(op_reply_q->q_base_tag, op_reply_q->q_base, op_reply_q->q_base_dmamap); + op_reply_q->q_base = NULL; + if (op_reply_q->q_base_tag != NULL) + bus_dma_tag_destroy(op_reply_q->q_base_tag); + } + } + free(sc->op_reply_q, M_MPI3MR); + sc->op_reply_q = NULL; + } + + /* Free up chain buffers*/ + if (sc->chain_sgl_list) { + for (i = 0; i < sc->chain_buf_count; i++) { + if (sc->chain_sgl_list[i].buf && sc->chain_sgl_list[i].buf_phys) { + bus_dmamap_unload(sc->chain_sgl_list_tag, sc->chain_sgl_list[i].buf_dmamap); + bus_dmamem_free(sc->chain_sgl_list_tag, sc->chain_sgl_list[i].buf, + sc->chain_sgl_list[i].buf_dmamap); + sc->chain_sgl_list[i].buf = NULL; + } + } + if (sc->chain_sgl_list_tag != NULL) + bus_dma_tag_destroy(sc->chain_sgl_list_tag); + free(sc->chain_sgl_list, M_MPI3MR); + sc->chain_sgl_list = NULL; + } + + if (sc->chain_bitmap) { + free(sc->chain_bitmap, M_MPI3MR); + sc->chain_bitmap = NULL; + } + + for (i = 0; i < sc->msix_count; i++) { + irq_ctx = sc->irq_ctx + i; + if (irq_ctx) + irq_ctx->op_reply_q = NULL; + } + + /* Free reply_buf_tag */ + if (sc->reply_buf && sc->reply_buf_phys) { + bus_dmamap_unload(sc->reply_buf_tag, sc->reply_buf_dmamap); + bus_dmamem_free(sc->reply_buf_tag, sc->reply_buf, + sc->reply_buf_dmamap); + sc->reply_buf = NULL; + if (sc->reply_buf_tag != NULL) + bus_dma_tag_destroy(sc->reply_buf_tag); + } + + /* Free reply_free_q_tag */ + if (sc->reply_free_q && sc->reply_free_q_phys) { + bus_dmamap_unload(sc->reply_free_q_tag, sc->reply_free_q_dmamap); + bus_dmamem_free(sc->reply_free_q_tag, sc->reply_free_q, + sc->reply_free_q_dmamap); + sc->reply_free_q = NULL; + if (sc->reply_free_q_tag != NULL) + bus_dma_tag_destroy(sc->reply_free_q_tag); + } + + /* Free sense_buf_tag */ + if (sc->sense_buf && sc->sense_buf_phys) { + bus_dmamap_unload(sc->sense_buf_tag, sc->sense_buf_dmamap); + bus_dmamem_free(sc->sense_buf_tag, sc->sense_buf, + sc->sense_buf_dmamap); + sc->sense_buf = NULL; + if (sc->sense_buf_tag != NULL) + bus_dma_tag_destroy(sc->sense_buf_tag); + } + + /* Free sense_buf_q_tag */ + if (sc->sense_buf_q && sc->sense_buf_q_phys) { + bus_dmamap_unload(sc->sense_buf_q_tag, sc->sense_buf_q_dmamap); + bus_dmamem_free(sc->sense_buf_q_tag, sc->sense_buf_q, + sc->sense_buf_q_dmamap); + sc->sense_buf_q = NULL; + if (sc->sense_buf_q_tag != NULL) + bus_dma_tag_destroy(sc->sense_buf_q_tag); + } + + /* Free up internal(non-IO) commands*/ + if (sc->init_cmds.reply) { + free(sc->init_cmds.reply, M_MPI3MR); + sc->init_cmds.reply = NULL; + } + + if (sc->ioctl_cmds.reply) { + free(sc->ioctl_cmds.reply, M_MPI3MR); + sc->ioctl_cmds.reply = NULL; + } + + if (sc->pel_cmds.reply) { + free(sc->pel_cmds.reply, M_MPI3MR); + sc->pel_cmds.reply = NULL; + } + + if (sc->pel_abort_cmd.reply) { + free(sc->pel_abort_cmd.reply, M_MPI3MR); + sc->pel_abort_cmd.reply = NULL; + } + + if (sc->host_tm_cmds.reply) { + free(sc->host_tm_cmds.reply, M_MPI3MR); + sc->host_tm_cmds.reply = NULL; + } + + if (sc->log_data_buffer) { + free(sc->log_data_buffer, M_MPI3MR); + sc->log_data_buffer = NULL; + } + + for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { + if (sc->dev_rmhs_cmds[i].reply) { + free(sc->dev_rmhs_cmds[i].reply, M_MPI3MR); + sc->dev_rmhs_cmds[i].reply = NULL; + } + } + + for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) { + if (sc->evtack_cmds[i].reply) { + free(sc->evtack_cmds[i].reply, M_MPI3MR); + sc->evtack_cmds[i].reply = NULL; + } + } + + if (sc->removepend_bitmap) { + free(sc->removepend_bitmap, M_MPI3MR); + sc->removepend_bitmap = NULL; + } + + if (sc->devrem_bitmap) { + free(sc->devrem_bitmap, M_MPI3MR); + sc->devrem_bitmap = NULL; + } + + if (sc->evtack_cmds_bitmap) { + free(sc->evtack_cmds_bitmap, M_MPI3MR); + sc->evtack_cmds_bitmap = NULL; + } + + /* Free Admin reply*/ + if (sc->admin_reply && sc->admin_reply_phys) { + bus_dmamap_unload(sc->admin_reply_tag, sc->admin_reply_dmamap); + bus_dmamem_free(sc->admin_reply_tag, sc->admin_reply, + sc->admin_reply_dmamap); + sc->admin_reply = NULL; + if (sc->admin_reply_tag != NULL) + bus_dma_tag_destroy(sc->admin_reply_tag); + } + + /* Free Admin request*/ + if (sc->admin_req && sc->admin_req_phys) { + bus_dmamap_unload(sc->admin_req_tag, sc->admin_req_dmamap); + bus_dmamem_free(sc->admin_req_tag, sc->admin_req, + sc->admin_req_dmamap); + sc->admin_req = NULL; + if (sc->admin_req_tag != NULL) + bus_dma_tag_destroy(sc->admin_req_tag); + } + mpi3mr_free_ioctl_dma_memory(sc); + +} + +/** + * mpi3mr_drv_cmd_comp_reset - Flush a internal driver command + * @sc: Adapter instance reference + * @cmdptr: Internal command tracker + * + * Complete an internal driver commands with state indicating it + * is completed due to reset. + * + * Return: Nothing. + */ +static inline void mpi3mr_drv_cmd_comp_reset(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *cmdptr) +{ + if (cmdptr->state & MPI3MR_CMD_PENDING) { + cmdptr->state |= MPI3MR_CMD_RESET; + cmdptr->state &= ~MPI3MR_CMD_PENDING; + if (cmdptr->is_waiting) { + complete(&cmdptr->completion); + cmdptr->is_waiting = 0; + } else if (cmdptr->callback) + cmdptr->callback(sc, cmdptr); + } +} + +/** + * mpi3mr_flush_drv_cmds - Flush internal driver commands + * @sc: Adapter instance reference + * + * Flush all internal driver commands post reset + * + * Return: Nothing. + */ +static void mpi3mr_flush_drv_cmds(struct mpi3mr_softc *sc) +{ + int i = 0; + struct mpi3mr_drvr_cmd *cmdptr; + + cmdptr = &sc->init_cmds; + mpi3mr_drv_cmd_comp_reset(sc, cmdptr); + + cmdptr = &sc->ioctl_cmds; + mpi3mr_drv_cmd_comp_reset(sc, cmdptr); + + cmdptr = &sc->host_tm_cmds; + mpi3mr_drv_cmd_comp_reset(sc, cmdptr); + + for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { + cmdptr = &sc->dev_rmhs_cmds[i]; + mpi3mr_drv_cmd_comp_reset(sc, cmdptr); + } + + for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) { + cmdptr = &sc->evtack_cmds[i]; + mpi3mr_drv_cmd_comp_reset(sc, cmdptr); + } + + cmdptr = &sc->pel_cmds; + mpi3mr_drv_cmd_comp_reset(sc, cmdptr); + + cmdptr = &sc->pel_abort_cmd; + mpi3mr_drv_cmd_comp_reset(sc, cmdptr); +} + + +/** + * mpi3mr_memset_buffers - memset memory for a controller + * @sc: Adapter instance reference + * + * clear all the memory allocated for a controller, typically + * called post reset to reuse the memory allocated during the + * controller init. + * + * Return: Nothing. + */ +static void mpi3mr_memset_buffers(struct mpi3mr_softc *sc) +{ + U16 i; + struct mpi3mr_throttle_group_info *tg; + + memset(sc->admin_req, 0, sc->admin_req_q_sz); + memset(sc->admin_reply, 0, sc->admin_reply_q_sz); + + memset(sc->init_cmds.reply, 0, sc->reply_sz); + memset(sc->ioctl_cmds.reply, 0, sc->reply_sz); + memset(sc->host_tm_cmds.reply, 0, sc->reply_sz); + memset(sc->pel_cmds.reply, 0, sc->reply_sz); + memset(sc->pel_abort_cmd.reply, 0, sc->reply_sz); + for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) + memset(sc->dev_rmhs_cmds[i].reply, 0, sc->reply_sz); + for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) + memset(sc->evtack_cmds[i].reply, 0, sc->reply_sz); + memset(sc->removepend_bitmap, 0, sc->dev_handle_bitmap_sz); + memset(sc->devrem_bitmap, 0, sc->devrem_bitmap_sz); + memset(sc->evtack_cmds_bitmap, 0, sc->evtack_cmds_bitmap_sz); + + for (i = 0; i < sc->num_queues; i++) { + sc->op_reply_q[i].qid = 0; + sc->op_reply_q[i].ci = 0; + sc->op_reply_q[i].num_replies = 0; + sc->op_reply_q[i].ephase = 0; + mpi3mr_atomic_set(&sc->op_reply_q[i].pend_ios, 0); + memset(sc->op_reply_q[i].q_base, 0, sc->op_reply_q[i].qsz); + + sc->op_req_q[i].ci = 0; + sc->op_req_q[i].pi = 0; + sc->op_req_q[i].num_reqs = 0; + sc->op_req_q[i].qid = 0; + sc->op_req_q[i].reply_qid = 0; + memset(sc->op_req_q[i].q_base, 0, sc->op_req_q[i].qsz); + } + + mpi3mr_atomic_set(&sc->pend_large_data_sz, 0); + if (sc->throttle_groups) { + tg = sc->throttle_groups; + for (i = 0; i < sc->num_io_throttle_group; i++, tg++) { + tg->id = 0; + tg->fw_qd = 0; + tg->modified_qd = 0; + tg->io_divert= 0; + tg->high = 0; + tg->low = 0; + mpi3mr_atomic_set(&tg->pend_large_data_sz, 0); + } + } +} + +/** + * mpi3mr_invalidate_devhandles -Invalidate device handles + * @sc: Adapter instance reference + * + * Invalidate the device handles in the target device structures + * . Called post reset prior to reinitializing the controller. + * + * Return: Nothing. + */ +static void mpi3mr_invalidate_devhandles(struct mpi3mr_softc *sc) +{ + struct mpi3mr_target *target = NULL; + + mtx_lock_spin(&sc->target_lock); + TAILQ_FOREACH(target, &sc->cam_sc->tgt_list, tgt_next) { + if (target) { + target->dev_handle = MPI3MR_INVALID_DEV_HANDLE; + target->io_throttle_enabled = 0; + target->io_divert = 0; + target->throttle_group = NULL; + } + } + mtx_unlock_spin(&sc->target_lock); +} + +/** + * mpi3mr_rfresh_tgtdevs - Refresh target device exposure + * @sc: Adapter instance reference + * + * This is executed post controller reset to identify any + * missing devices during reset and remove from the upper layers + * or expose any newly detected device to the upper layers. + * + * Return: Nothing. + */ + +static void mpi3mr_rfresh_tgtdevs(struct mpi3mr_softc *sc) +{ + struct mpi3mr_target *target = NULL; + struct mpi3mr_target *target_temp = NULL; + + TAILQ_FOREACH_SAFE(target, &sc->cam_sc->tgt_list, tgt_next, target_temp) { + if (target->dev_handle == MPI3MR_INVALID_DEV_HANDLE) { + if (target->exposed_to_os) + mpi3mr_remove_device_from_os(sc, target->dev_handle); + mpi3mr_remove_device_from_list(sc, target, true); + } + } + + TAILQ_FOREACH(target, &sc->cam_sc->tgt_list, tgt_next) { + if ((target->dev_handle != MPI3MR_INVALID_DEV_HANDLE) && + !target->is_hidden && !target->exposed_to_os) { + mpi3mr_add_device(sc, target->per_id); + } + } + +} + +static void mpi3mr_flush_io(struct mpi3mr_softc *sc) +{ + int i; + struct mpi3mr_cmd *cmd = NULL; + union ccb *ccb = NULL; + + for (i = 0; i < sc->max_host_ios; i++) { + cmd = sc->cmd_list[i]; + + if (cmd && cmd->ccb) { + if (cmd->callout_owner) { + ccb = (union ccb *)(cmd->ccb); + ccb->ccb_h.status = CAM_SCSI_BUS_RESET; + mpi3mr_cmd_done(sc, cmd); + } else { + cmd->ccb = NULL; + mpi3mr_release_command(cmd); + } + } + } +} +/** + * mpi3mr_clear_reset_history - Clear reset history + * @sc: Adapter instance reference + * + * Write the reset history bit in IOC Status to clear the bit, + * if it is already set. + * + * Return: Nothing. + */ +static inline void mpi3mr_clear_reset_history(struct mpi3mr_softc *sc) +{ + U32 ioc_status; + + ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET); + if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) + mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_STATUS_OFFSET, ioc_status); +} + +/** + * mpi3mr_set_diagsave - Set diag save bit for snapdump + * @sc: Adapter reference + * + * Set diag save bit in IOC configuration register to enable + * snapdump. + * + * Return: Nothing. + */ +static inline void mpi3mr_set_diagsave(struct mpi3mr_softc *sc) +{ + U32 ioc_config; + + ioc_config = + mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET); + ioc_config |= MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE; + mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET, ioc_config); +} + +/** + * mpi3mr_issue_reset - Issue reset to the controller + * @sc: Adapter reference + * @reset_type: Reset type + * @reset_reason: Reset reason code + * + * Unlock the host diagnostic registers and write the specific + * reset type to that, wait for reset acknowledgement from the + * controller, if the reset is not successful retry for the + * predefined number of times. + * + * Return: 0 on success, non-zero on failure. + */ +static int mpi3mr_issue_reset(struct mpi3mr_softc *sc, U16 reset_type, + U32 reset_reason) +{ + int retval = -1; + U8 unlock_retry_count = 0; + U32 host_diagnostic, ioc_status, ioc_config; + U32 timeout = MPI3MR_RESET_ACK_TIMEOUT * 10; + + if ((reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) && + (reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT)) + return retval; + if (sc->unrecoverable) + return retval; + + if (reset_reason == MPI3MR_RESET_FROM_FIRMWARE) { + retval = 0; + return retval; + } + + mpi3mr_dprint(sc, MPI3MR_INFO, "%s reset due to %s(0x%x)\n", + mpi3mr_reset_type_name(reset_type), + mpi3mr_reset_rc_name(reset_reason), reset_reason); + + mpi3mr_clear_reset_history(sc); + do { + mpi3mr_dprint(sc, MPI3MR_INFO, + "Write magic sequence to unlock host diag register (retry=%d)\n", + ++unlock_retry_count); + if (unlock_retry_count >= MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "%s reset failed! due to host diag register unlock failure" + "host_diagnostic(0x%08x)\n", mpi3mr_reset_type_name(reset_type), + host_diagnostic); + sc->unrecoverable = 1; + return retval; + } + + mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET, + MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH); + mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET, + MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_1ST); + mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET, + MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND); + mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET, + MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_3RD); + mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET, + MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_4TH); + mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET, + MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_5TH); + mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET, + MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_6TH); + + DELAY(1000); /* delay in usec */ + host_diagnostic = mpi3mr_regread(sc, MPI3_SYSIF_HOST_DIAG_OFFSET); + mpi3mr_dprint(sc, MPI3MR_INFO, + "wrote magic sequence: retry_count(%d), host_diagnostic(0x%08x)\n", + unlock_retry_count, host_diagnostic); + } while (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_DIAG_WRITE_ENABLE)); + + mpi3mr_regwrite(sc, MPI3_SYSIF_SCRATCHPAD0_OFFSET, reset_reason); + mpi3mr_regwrite(sc, MPI3_SYSIF_HOST_DIAG_OFFSET, host_diagnostic | reset_type); + + if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) { + do { + ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET); + if (ioc_status & + MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) { + ioc_config = + mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET); + if (mpi3mr_soft_reset_success(ioc_status, + ioc_config)) { + mpi3mr_clear_reset_history(sc); + retval = 0; + break; + } + } + DELAY(100 * 1000); + } while (--timeout); + } else if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT) { + do { + ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET); + if (mpi3mr_diagfault_success(sc, ioc_status)) { + retval = 0; + break; + } + DELAY(100 * 1000); + } while (--timeout); + } + + mpi3mr_regwrite(sc, MPI3_SYSIF_WRITE_SEQUENCE_OFFSET, + MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND); + + ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET); + ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET); + + mpi3mr_dprint(sc, MPI3MR_INFO, + "IOC Status/Config after %s reset is (0x%x)/(0x%x)\n", + !retval ? "successful":"failed", ioc_status, + ioc_config); + + if (retval) + sc->unrecoverable = 1; + + return retval; +} + +inline void mpi3mr_cleanup_event_taskq(struct mpi3mr_softc *sc) +{ + mtx_lock(&sc->fwevt_lock); + taskqueue_drain(sc->cam_sc->ev_tq, &sc->cam_sc->ev_task); + taskqueue_block(sc->cam_sc->ev_tq); + mtx_unlock(&sc->fwevt_lock); + return; +} + +/** + * mpi3mr_soft_reset_handler - Reset the controller + * @sc: Adapter instance reference + * @reset_reason: Reset reason code + * @snapdump: snapdump enable/disbale bit + * + * This is an handler for recovering controller by issuing soft + * reset or diag fault reset. This is a blocking function and + * when one reset is executed if any other resets they will be + * blocked. All IOCTLs/IO will be blocked during the reset. If + * controller reset is successful then the controller will be + * reinitalized, otherwise the controller will be marked as not + * recoverable + * + * Return: 0 on success, non-zero on failure. + */ +int mpi3mr_soft_reset_handler(struct mpi3mr_softc *sc, + U32 reset_reason, bool snapdump) +{ + int retval = 0, i = 0; + enum mpi3mr_iocstate ioc_state; + + mpi3mr_dprint(sc, MPI3MR_INFO, "soft reset invoked: reason code: %s\n", + mpi3mr_reset_rc_name(reset_reason)); + + if ((reset_reason == MPI3MR_RESET_FROM_IOCTL) && + (sc->reset.ioctl_reset_snapdump != true)) + snapdump = false; + + mpi3mr_dprint(sc, MPI3MR_INFO, + "soft_reset_handler: wait if diag save is in progress\n"); + while (sc->diagsave_timeout) + DELAY(1000 * 1000); + + ioc_state = mpi3mr_get_iocstate(sc); + if (ioc_state == MRIOC_STATE_UNRECOVERABLE) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "controller is in unrecoverable state, exit\n"); + sc->reset.type = MPI3MR_NO_RESET; + sc->reset.reason = MPI3MR_DEFAULT_RESET_REASON; + sc->reset.status = -1; + sc->reset.ioctl_reset_snapdump = false; + return -1; + } + + if (sc->reset_in_progress) { + mpi3mr_dprint(sc, MPI3MR_INFO, "reset is already in progress, exit\n"); + return -1; + } + + /* Pause IOs, drain and block the event taskqueue */ + xpt_freeze_simq(sc->cam_sc->sim, 1); + + mpi3mr_cleanup_event_taskq(sc); + + sc->reset_in_progress = 1; + sc->block_ioctls = 1; + + while (mpi3mr_atomic_read(&sc->pend_ioctls) && (i < PEND_IOCTLS_COMP_WAIT_TIME)) { + ioc_state = mpi3mr_get_iocstate(sc); + if (ioc_state == MRIOC_STATE_FAULT) + break; + i++; + if (!(i % 5)) { + mpi3mr_dprint(sc, MPI3MR_INFO, + "[%2ds]waiting for IOCTL to be finished from %s\n", i, __func__); + } + DELAY(1000 * 1000); + } + + if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) && + (reset_reason != MPI3MR_RESET_FROM_FIRMWARE) && + (reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) { + + mpi3mr_dprint(sc, MPI3MR_INFO, "Turn off events prior to reset\n"); + + for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) + sc->event_masks[i] = -1; + mpi3mr_issue_event_notification(sc); + } + + mpi3mr_disable_interrupts(sc); + + if (snapdump) + mpi3mr_trigger_snapdump(sc, reset_reason); + + retval = mpi3mr_issue_reset(sc, + MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, reset_reason); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to issue soft reset to the ioc\n"); + goto out; + } + + mpi3mr_flush_drv_cmds(sc); + mpi3mr_flush_io(sc); + mpi3mr_invalidate_devhandles(sc); + mpi3mr_memset_buffers(sc); + + if (sc->prepare_for_reset) { + sc->prepare_for_reset = 0; + sc->prepare_for_reset_timeout_counter = 0; + } + + retval = mpi3mr_initialize_ioc(sc, MPI3MR_INIT_TYPE_RESET); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "reinit after soft reset failed: reason %d\n", + reset_reason); + goto out; + } + + DELAY((1000 * 1000) * 10); +out: + if (!retval) { + sc->diagsave_timeout = 0; + sc->reset_in_progress = 0; + mpi3mr_rfresh_tgtdevs(sc); + sc->ts_update_counter = 0; + sc->block_ioctls = 0; + sc->pel_abort_requested = 0; + if (sc->pel_wait_pend) { + sc->pel_cmds.retry_count = 0; + mpi3mr_issue_pel_wait(sc, &sc->pel_cmds); + mpi3mr_app_send_aen(sc); + } + } else { + mpi3mr_issue_reset(sc, + MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); + sc->unrecoverable = 1; + sc->reset_in_progress = 0; + } + + mpi3mr_dprint(sc, MPI3MR_INFO, "Soft Reset: %s\n", ((retval == 0) ? "SUCCESS" : "FAILED")); + + taskqueue_unblock(sc->cam_sc->ev_tq); + xpt_release_simq(sc->cam_sc->sim, 1); + + sc->reset.type = MPI3MR_NO_RESET; + sc->reset.reason = MPI3MR_DEFAULT_RESET_REASON; + sc->reset.status = retval; + sc->reset.ioctl_reset_snapdump = false; + + return retval; +} + +/** + * mpi3mr_issue_ioc_shutdown - shutdown controller + * @sc: Adapter instance reference + * + * Send shutodwn notification to the controller and wait for the + * shutdown_timeout for it to be completed. + * + * Return: Nothing. + */ +static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_softc *sc) +{ + U32 ioc_config, ioc_status; + U8 retval = 1, retry = 0; + U32 timeout = MPI3MR_DEFAULT_SHUTDOWN_TIME * 10; + + mpi3mr_dprint(sc, MPI3MR_INFO, "sending shutdown notification\n"); + if (sc->unrecoverable) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "controller is unrecoverable, shutdown not issued\n"); + return; + } + ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET); + if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) + == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "shutdown already in progress\n"); + return; + } + + ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET); + ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL; + ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ; + + mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET, ioc_config); + + if (sc->facts.shutdown_timeout) + timeout = sc->facts.shutdown_timeout * 10; + + do { + ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET); + if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) + == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE) { + retval = 0; + break; + } + + if (sc->unrecoverable) + break; + + if ((ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) { + mpi3mr_print_fault_info(sc); + + if (retry >= MPI3MR_MAX_SHUTDOWN_RETRY_COUNT) + break; + + if (mpi3mr_issue_reset(sc, + MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, + MPI3MR_RESET_FROM_CTLR_CLEANUP)) + break; + + ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET); + ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL; + ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ; + + mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET, ioc_config); + + if (sc->facts.shutdown_timeout) + timeout = sc->facts.shutdown_timeout * 10; + + retry++; + } + + DELAY(100 * 1000); + + } while (--timeout); + + ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET); + ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET); + + if (retval) { + if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK) + == MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS) + mpi3mr_dprint(sc, MPI3MR_ERROR, + "shutdown still in progress after timeout\n"); + } + + mpi3mr_dprint(sc, MPI3MR_INFO, + "ioc_status/ioc_config after %s shutdown is (0x%x)/(0x%x)\n", + (!retval)?"successful":"failed", ioc_status, + ioc_config); +} + +/** + * mpi3mr_cleanup_ioc - Cleanup controller + * @sc: Adapter instance reference + + * controller cleanup handler, Message unit reset or soft reset + * and shutdown notification is issued to the controller. + * + * Return: Nothing. + */ +void mpi3mr_cleanup_ioc(struct mpi3mr_softc *sc) +{ + enum mpi3mr_iocstate ioc_state; + + mpi3mr_dprint(sc, MPI3MR_INFO, "cleaning up the controller\n"); + mpi3mr_disable_interrupts(sc); + + ioc_state = mpi3mr_get_iocstate(sc); + + if ((!sc->unrecoverable) && (!sc->reset_in_progress) && + (ioc_state == MRIOC_STATE_READY)) { + if (mpi3mr_mur_ioc(sc, + MPI3MR_RESET_FROM_CTLR_CLEANUP)) + mpi3mr_issue_reset(sc, + MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, + MPI3MR_RESET_FROM_MUR_FAILURE); + mpi3mr_issue_ioc_shutdown(sc); + } + + mpi3mr_dprint(sc, MPI3MR_INFO, "controller cleanup completed\n"); +} diff --git a/sys/dev/mpi3mr/mpi3mr.h b/sys/dev/mpi3mr/mpi3mr.h new file mode 100644 index 000000000000..bb5cc8ab0372 --- /dev/null +++ b/sys/dev/mpi3mr/mpi3mr.h @@ -0,0 +1,997 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2020-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Authors: Sumit Saxena + * Chandrakanth Patil + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + */ + +#ifndef _MPI3MRVAR_H +#define _MPI3MRVAR_H + +#include +__FBSDID("$FreeBSD$"); +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "mpi/mpi30_api.h" + +#define MPI3MR_DRIVER_VERSION "8.6.0.2.0" +#define MPI3MR_DRIVER_RELDATE "17th May 2023" + +#define MPI3MR_DRIVER_NAME "mpi3mr" + +#define MPI3MR_NAME_LENGTH 32 +#define IOCNAME "%s: " + +#define SAS4116_CHIP_REV_A0 0 +#define SAS4116_CHIP_REV_B0 1 + +#define MPI3MR_SG_DEPTH (MPI3MR_4K_PGSZ/sizeof(Mpi3SGESimple_t)) +#define MPI3MR_MAX_SECTORS 2048 +#define MPI3MR_MAX_CMDS_LUN 7 +#define MPI3MR_MAX_CDB_LENGTH 16 +#define MPI3MR_MAX_LUN 16895 + +#define MPI3MR_SATA_QDEPTH 32 +#define MPI3MR_SAS_QDEPTH 64 +#define MPI3MR_RAID_QDEPTH 128 +#define MPI3MR_NVME_QDEPTH 128 + +#define MPI3MR_4K_PGSZ 4096 +#define MPI3MR_AREQQ_SIZE (2 * MPI3MR_4K_PGSZ) +#define MPI3MR_AREPQ_SIZE (4 * MPI3MR_4K_PGSZ) +#define MPI3MR_AREQ_FRAME_SZ 128 +#define MPI3MR_AREP_FRAME_SZ 16 + +#define MPI3MR_OPREQQ_SIZE (8 * MPI3MR_4K_PGSZ) +#define MPI3MR_OPREPQ_SIZE (4 * MPI3MR_4K_PGSZ) + +/* Operational queue management definitions */ +#define MPI3MR_OP_REQ_Q_QD 512 +#define MPI3MR_OP_REP_Q_QD 1024 +#define MPI3MR_OP_REP_Q_QD_A0 4096 + +#define MPI3MR_CHAINSGE_SIZE MPI3MR_4K_PGSZ + +#define MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST \ + (MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | MPI3_SGE_FLAGS_DLAS_SYSTEM | \ + MPI3_SGE_FLAGS_END_OF_LIST) + +#define MPI3MR_HOSTTAG_INVALID 0xFFFF +#define MPI3MR_HOSTTAG_INITCMDS 1 +#define MPI3MR_HOSTTAG_IOCTLCMDS 2 +#define MPI3MR_HOSTTAG_PELABORT 3 +#define MPI3MR_HOSTTAG_PELWAIT 4 +#define MPI3MR_HOSTTAG_TMS 5 + +#define MAX_MGMT_ADAPTERS 8 +#define MPI3MR_WAIT_BEFORE_CTRL_RESET 5 + + +struct mpi3mr_mgmt_info { + uint16_t count; + struct mpi3mr_softc *sc_ptr[MAX_MGMT_ADAPTERS]; + int max_index; +}; + +extern char fmt_os_ver[16]; + +#define MPI3MR_OS_VERSION(raw_os_ver, fmt_os_ver) sprintf(raw_os_ver, "%d", __FreeBSD_version); \ + sprintf(fmt_os_ver, "%c%c.%c%c.%c%c%c",\ + raw_os_ver[0], raw_os_ver[1], raw_os_ver[2],\ + raw_os_ver[3], raw_os_ver[4], raw_os_ver[5],\ + raw_os_ver[6]); +#define MPI3MR_NUM_DEVRMCMD 1 +#define MPI3MR_HOSTTAG_DEVRMCMD_MIN (MPI3MR_HOSTTAG_TMS + 1) +#define MPI3MR_HOSTTAG_DEVRMCMD_MAX (MPI3MR_HOSTTAG_DEVRMCMD_MIN + \ + MPI3MR_NUM_DEVRMCMD - 1) +#define MPI3MR_INTERNALCMDS_RESVD MPI3MR_HOSTTAG_DEVRMCMD_MAX + +#define MPI3MR_NUM_EVTACKCMD 4 +#define MPI3MR_HOSTTAG_EVTACKCMD_MIN (MPI3MR_HOSTTAG_DEVRMCMD_MAX + 1) +#define MPI3MR_HOSTTAG_EVTACKCMD_MAX (MPI3MR_HOSTTAG_EVTACKCMD_MIN + \ + MPI3MR_NUM_EVTACKCMD - 1) + +/* command/controller interaction timeout definitions in seconds */ +#define MPI3MR_INTADMCMD_TIMEOUT 60 +#define MPI3MR_PORTENABLE_TIMEOUT 300 +#define MPI3MR_ABORTTM_TIMEOUT 60 +#define MPI3MR_RESETTM_TIMEOUT 60 +#define MPI3MR_TSUPDATE_INTERVAL 900 +#define MPI3MR_DEFAULT_SHUTDOWN_TIME 120 +#define MPI3MR_RAID_ERRREC_RESET_TIMEOUT 180 +#define MPI3MR_RESET_HOST_IOWAIT_TIMEOUT 5 +#define MPI3MR_PREPARE_FOR_RESET_TIMEOUT 180 +#define MPI3MR_RESET_ACK_TIMEOUT 30 +#define MPI3MR_MUR_TIMEOUT 120 + +#define MPI3MR_CMD_NOTUSED 0x8000 +#define MPI3MR_CMD_COMPLETE 0x0001 +#define MPI3MR_CMD_PENDING 0x0002 +#define MPI3MR_CMD_REPLYVALID 0x0004 +#define MPI3MR_CMD_RESET 0x0008 + +#define MPI3MR_NUM_EVTREPLIES 64 +#define MPI3MR_SENSEBUF_SZ 256 +#define MPI3MR_SENSEBUF_FACTOR 3 +#define MPI3MR_CHAINBUF_FACTOR 3 + +#define MPT3SAS_HOSTPGSZ_4KEXP 12 + +#define MPI3MR_INVALID_DEV_HANDLE 0xFFFF + +/* Controller Reset related definitions */ +#define MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT 5 +#define MPI3MR_MAX_SHUTDOWN_RETRY_COUNT 2 + +/* ResponseCode values */ +#define MPI3MR_RI_MASK_RESPCODE (0x000000FF) +#define MPI3MR_RSP_TM_COMPLETE 0x00 +#define MPI3MR_RSP_INVALID_FRAME 0x02 +#define MPI3MR_RSP_TM_NOT_SUPPORTED 0x04 +#define MPI3MR_RSP_TM_FAILED 0x05 +#define MPI3MR_RSP_TM_SUCCEEDED 0x08 +#define MPI3MR_RSP_TM_INVALID_LUN 0x09 +#define MPI3MR_RSP_TM_OVERLAPPED_TAG 0x0A +#define MPI3MR_RSP_IO_QUEUED_ON_IOC \ + MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC + +/* Definitions for the controller security status*/ +#define MPI3MR_CTLR_SECURITY_STATUS_MASK 0x0C +#define MPI3MR_CTLR_SECURE_DBG_STATUS_MASK 0x02 + +#define MPI3MR_INVALID_DEVICE 0x00 +#define MPI3MR_CONFIG_SECURE_DEVICE 0x04 +#define MPI3MR_HARD_SECURE_DEVICE 0x08 +#define MPI3MR_TAMPERED_DEVICE 0x0C + +#define MPI3MR_DEFAULT_MDTS (128 * 1024) +#define MPI3MR_DEFAULT_PGSZEXP (12) +#define MPI3MR_MAX_IOCTL_TRANSFER_SIZE (1024 * 1024) + +#define MPI3MR_DEVRMHS_RETRYCOUNT 3 +#define MPI3MR_PELCMDS_RETRYCOUNT 3 + +#define MPI3MR_PERIODIC_DELAY 1 /* 1 second heartbeat/watchdog check */ + +struct completion { + unsigned int done; + struct mtx lock; +}; + +typedef union { + volatile unsigned int val; + unsigned int val_rdonly; +} mpi3mr_atomic_t; + +#define mpi3mr_atomic_read(v) atomic_load_acq_int(&(v)->val) +#define mpi3mr_atomic_set(v,i) atomic_store_rel_int(&(v)->val, i) +#define mpi3mr_atomic_dec(v) atomic_subtract_int(&(v)->val, 1) +#define mpi3mr_atomic_inc(v) atomic_add_int(&(v)->val, 1) +#define mpi3mr_atomic_add(v, u) atomic_add_int(&(v)->val, u) +#define mpi3mr_atomic_sub(v, u) atomic_subtract_int(&(v)->val, u) + +/* IOCTL data transfer sge*/ +#define MPI3MR_NUM_IOCTL_SGE 256 +#define MPI3MR_IOCTL_SGE_SIZE (8 * 1024) + +struct dma_memory_desc { + U32 size; + void *addr; + bus_dma_tag_t tag; + bus_dmamap_t dmamap; + bus_addr_t dma_addr; +}; + +enum mpi3mr_iocstate { + MRIOC_STATE_READY = 1, + MRIOC_STATE_RESET, + MRIOC_STATE_FAULT, + MRIOC_STATE_BECOMING_READY, + MRIOC_STATE_RESET_REQUESTED, + MRIOC_STATE_UNRECOVERABLE, + MRIOC_STATE_COUNT, +}; + +/* Init type definitions */ +enum mpi3mr_init_type { + MPI3MR_INIT_TYPE_INIT = 0, + MPI3MR_INIT_TYPE_RESET, + MPI3MR_INIT_TYPE_RESUME, +}; + +/* Reset reason code definitions*/ +enum mpi3mr_reset_reason { + MPI3MR_RESET_FROM_BRINGUP = 1, + MPI3MR_RESET_FROM_FAULT_WATCH = 2, + MPI3MR_RESET_FROM_IOCTL = 3, + MPI3MR_RESET_FROM_EH_HOS = 4, + MPI3MR_RESET_FROM_TM_TIMEOUT = 5, + MPI3MR_RESET_FROM_IOCTL_TIMEOUT = 6, + MPI3MR_RESET_FROM_MUR_FAILURE = 7, + MPI3MR_RESET_FROM_CTLR_CLEANUP = 8, + MPI3MR_RESET_FROM_CIACTIV_FAULT = 9, + MPI3MR_RESET_FROM_PE_TIMEOUT = 10, + MPI3MR_RESET_FROM_TSU_TIMEOUT = 11, + MPI3MR_RESET_FROM_DELREQQ_TIMEOUT = 12, + MPI3MR_RESET_FROM_DELREPQ_TIMEOUT = 13, + MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT = 14, + MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT = 15, + MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT = 16, + MPI3MR_RESET_FROM_IOCINIT_TIMEOUT = 17, + MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT = 18, + MPI3MR_RESET_FROM_EVTACK_TIMEOUT = 19, + MPI3MR_RESET_FROM_CIACTVRST_TIMER = 20, + MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT = 21, + MPI3MR_RESET_FROM_PELABORT_TIMEOUT = 22, + MPI3MR_RESET_FROM_SYSFS = 23, + MPI3MR_RESET_FROM_SYSFS_TIMEOUT = 24, + MPI3MR_RESET_FROM_DIAG_BUFFER_POST_TIMEOUT = 25, + MPI3MR_RESET_FROM_SCSIIO_TIMEOUT = 26, + MPI3MR_RESET_FROM_FIRMWARE = 27, + MPI3MR_DEFAULT_RESET_REASON = 28, + MPI3MR_RESET_REASON_COUNT, +}; + +struct mpi3mr_compimg_ver +{ + U16 build_num; + U16 cust_id; + U8 ph_minor; + U8 ph_major; + U8 gen_minor; + U8 gen_major; +}; + +struct mpi3mr_ioc_facts +{ + U32 ioc_capabilities; + struct mpi3mr_compimg_ver fw_ver; + U32 mpi_version; + U16 max_reqs; + U16 product_id; + U16 op_req_sz; + U16 reply_sz; + U16 exceptions; + U16 max_perids; + U16 max_pds; + U16 max_sasexpanders; + U16 max_sasinitiators; + U16 max_enclosures; + U16 max_pcieswitches; + U16 max_nvme; + U16 max_vds; + U16 max_hpds; + U16 max_advhpds; + U16 max_raidpds; + U16 min_devhandle; + U16 max_devhandle; + U16 max_op_req_q; + U16 max_op_reply_q; + U16 shutdown_timeout; + U8 ioc_num; + U8 who_init; + U16 max_msix_vectors; + U8 personality; + U8 dma_mask; + U8 protocol_flags; + U8 sge_mod_mask; + U8 sge_mod_value; + U8 sge_mod_shift; + U8 max_dev_per_tg; + U16 max_io_throttle_group; + U16 io_throttle_data_length; + U16 io_throttle_low; + U16 io_throttle_high; +}; + +struct mpi3mr_op_req_queue { + U16 ci; + U16 pi; + U16 num_reqs; + U8 qid; + U8 reply_qid; + U32 qsz; + void *q_base; + bus_dma_tag_t q_base_tag; + bus_dmamap_t q_base_dmamap; + bus_addr_t q_base_phys; + struct mtx q_lock; +}; + +struct mpi3mr_op_reply_queue { + U16 ci; + U8 ephase; + U8 qid; + U16 num_replies; + U32 qsz; + bus_dma_tag_t q_base_tag; + bus_dmamap_t q_base_dmamap; + void *q_base; + bus_addr_t q_base_phys; + mpi3mr_atomic_t pend_ios; + bool in_use; + struct mtx q_lock; +}; + +struct irq_info { + MPI3_REPLY_DESCRIPTORS_UNION *post_queue; + bus_dma_tag_t buffer_dmat; + struct resource *irq; + void *intrhand; + int irq_rid; +}; + +struct mpi3mr_irq_context { + struct mpi3mr_softc *sc; + U16 msix_index; + struct mpi3mr_op_reply_queue *op_reply_q; + char name[MPI3MR_NAME_LENGTH]; + struct irq_info irq_info; +}; + +MALLOC_DECLARE(M_MPI3MR); +SYSCTL_DECL(_hw_mpi3mr); + +typedef struct mpi3mr_drvr_cmd DRVR_CMD; +typedef void (*DRVR_CMD_CALLBACK)(struct mpi3mr_softc *mrioc, DRVR_CMD *drvrcmd); +struct mpi3mr_drvr_cmd { + struct mtx lock; + struct completion completion; + void *reply; + U8 *sensebuf; + U8 iou_rc; + U16 state; + U16 dev_handle; + U16 ioc_status; + U32 ioc_loginfo; + U8 is_waiting; + U8 is_senseprst; + U8 retry_count; + U16 host_tag; + DRVR_CMD_CALLBACK callback; +}; + +struct mpi3mr_cmd; +typedef void mpi3mr_evt_callback_t(struct mpi3mr_softc *, uintptr_t, + Mpi3EventNotificationReply_t *reply); +typedef void mpi3mr_cmd_callback_t(struct mpi3mr_softc *, + struct mpi3mr_cmd *cmd); + +#define MPI3MR_IOVEC_COUNT 2 + +enum mpi3mr_data_xfer_direction { + MPI3MR_READ = 1, + MPI3MR_WRITE, +}; + +enum mpi3mr_cmd_state { + MPI3MR_CMD_STATE_FREE = 1, + MPI3MR_CMD_STATE_BUSY, + MPI3MR_CMD_STATE_IN_QUEUE, + MPI3MR_CMD_STATE_IN_TM, +}; + +enum mpi3mr_target_state { + MPI3MR_DEV_CREATED = 1, + MPI3MR_DEV_REMOVE_HS_STARTED = 2, + MPI3MR_DEV_DELETED = 3, +}; + +struct mpi3mr_cmd { + TAILQ_ENTRY(mpi3mr_cmd) next; + struct mpi3mr_softc *sc; + union ccb *ccb; + void *data; + u_int length; + u_int out_len; + struct uio uio; + struct iovec iovec[MPI3MR_IOVEC_COUNT]; + u_int max_segs; + struct mpi3mr_target *targ; + u_int lun; + u_int data_dir; + u_int state; + bus_dmamap_t dmamap; + struct scsi_sense_data *sense; + struct callout callout; + bool callout_owner; + mpi3mr_cmd_callback_t *timeout_handler; + U16 hosttag; + U8 req_qidx; + Mpi3SCSIIORequest_t io_request; + int error_code; +}; + +struct mpi3mr_chain { + bus_dmamap_t buf_dmamap; + void *buf; + bus_addr_t buf_phys; +}; + +struct mpi3mr_event_handle { + TAILQ_ENTRY(mpi3mr_event_handle) eh_list; + mpi3mr_evt_callback_t *callback; + void *data; + uint8_t mask[16]; +}; + +struct mpi3mr_fw_event_work { + U16 event; + void *event_data; + TAILQ_ENTRY(mpi3mr_fw_event_work) ev_link; + U8 send_ack; + U8 process_event; + U32 event_context; + U16 event_data_size; +}; + +/** + * struct delayed_dev_rmhs_node - Delayed device removal node + * + * @list: list head + * @handle: Device handle + * @iou_rc: IO Unit Control Reason Code + */ +struct delayed_dev_rmhs_node { + TAILQ_ENTRY(delayed_dev_rmhs_node) list; + U16 handle; + U8 iou_rc; +}; + +/** + * struct delayed_evtack_node - Delayed event ack node + * + * @list: list head + * @event: MPI3 event ID + * @event_ctx: Event context + */ +struct delayed_evtack_node { + TAILQ_ENTRY(delayed_evtack_node) list; + U8 event; + U32 event_ctx; +}; + +/* Reset types */ +enum reset_type { + MPI3MR_NO_RESET, + MPI3MR_TRIGGER_SOFT_RESET, +}; + +struct mpi3mr_reset { + u_int type; + U32 reason; + int status; + bool ioctl_reset_snapdump; +}; + +struct mpi3mr_softc { + device_t mpi3mr_dev; + struct cdev *mpi3mr_cdev; + u_int mpi3mr_flags; +#define MPI3MR_FLAGS_SHUTDOWN (1 << 0) +#define MPI3MR_FLAGS_DIAGRESET (1 << 1) +#define MPI3MR_FLAGS_ATTACH_DONE (1 << 2) +#define MPI3MR_FLAGS_PORT_ENABLE_DONE (1 << 3) + U8 id; + int cpu_count; + char name[MPI3MR_NAME_LENGTH]; + char driver_name[MPI3MR_NAME_LENGTH]; + int bars; + int dma_mask; + u_int mpi3mr_debug; + struct mpi3mr_reset reset; + int max_msix_vectors; + int msix_count; + bool msix_enable; + int io_cmds_highwater; + int max_chains; + uint32_t chain_frame_size; + struct sysctl_ctx_list sysctl_ctx; + struct sysctl_oid *sysctl_tree; + char fw_version[16]; + char msg_version[8]; + struct mpi3mr_chain *chains; + struct callout periodic; + struct callout device_check_callout; + + struct mpi3mr_cam_softc *cam_sc; + struct mpi3mr_cmd **cmd_list; + TAILQ_HEAD(, mpi3mr_cmd) cmd_list_head; + struct mtx cmd_pool_lock; + + struct resource *mpi3mr_regs_resource; + bus_space_handle_t mpi3mr_bhandle; + bus_space_tag_t mpi3mr_btag; + int mpi3mr_regs_rid; + + bus_dma_tag_t mpi3mr_parent_dmat; + bus_dma_tag_t buffer_dmat; + + int num_reqs; + int num_replies; + int num_chains; + + TAILQ_HEAD(, mpi3mr_event_handle) event_list; + struct mpi3mr_event_handle *mpi3mr_log_eh; + struct intr_config_hook mpi3mr_ich; + + struct mtx mpi3mr_mtx; + struct mtx io_lock; + U8 intr_enabled; + TAILQ_HEAD(, delayed_dev_rmhs_node) delayed_rmhs_list; + TAILQ_HEAD(, delayed_evtack_node) delayed_evtack_cmds_list; + + U16 num_admin_reqs; + U32 admin_req_q_sz; + U16 admin_req_pi; + U16 admin_req_ci; + bus_dma_tag_t admin_req_tag; + bus_dmamap_t admin_req_dmamap; + bus_addr_t admin_req_phys; + U8 *admin_req; + struct mtx admin_req_lock; + + U16 num_admin_replies; + U32 admin_reply_q_sz; + U16 admin_reply_ci; + U8 admin_reply_ephase; + bus_dma_tag_t admin_reply_tag; + bus_dmamap_t admin_reply_dmamap; + bus_addr_t admin_reply_phys; + U8 *admin_reply; + struct mtx admin_reply_lock; + bool admin_in_use; + + U32 num_reply_bufs; + bus_dma_tag_t reply_buf_tag; + bus_dmamap_t reply_buf_dmamap; + bus_addr_t reply_buf_phys; + U8 *reply_buf; + bus_addr_t reply_buf_dma_max_address; + bus_addr_t reply_buf_dma_min_address; + + U16 reply_free_q_sz; + bus_dma_tag_t reply_free_q_tag; + bus_dmamap_t reply_free_q_dmamap; + bus_addr_t reply_free_q_phys; + U64 *reply_free_q; + struct mtx reply_free_q_lock; + U32 reply_free_q_host_index; + + U32 num_sense_bufs; + bus_dma_tag_t sense_buf_tag; + bus_dmamap_t sense_buf_dmamap; + bus_addr_t sense_buf_phys; + U8 *sense_buf; + + U16 sense_buf_q_sz; + bus_dma_tag_t sense_buf_q_tag; + bus_dmamap_t sense_buf_q_dmamap; + bus_addr_t sense_buf_q_phys; + U64 *sense_buf_q; + struct mtx sense_buf_q_lock; + U32 sense_buf_q_host_index; + + void *nvme_encap_prp_list; + bus_addr_t nvme_encap_prp_list_dma; + bus_dma_tag_t nvme_encap_prp_list_dmatag; + bus_dmamap_t nvme_encap_prp_list_dma_dmamap; + U32 nvme_encap_prp_sz; + + U32 ready_timeout; + + struct mpi3mr_irq_context *irq_ctx; + + U16 num_queues; /* Number of request/reply queues */ + struct mpi3mr_op_req_queue *op_req_q; + struct mpi3mr_op_reply_queue *op_reply_q; + U16 num_hosttag_op_req_q; + + struct mpi3mr_drvr_cmd init_cmds; + struct mpi3mr_ioc_facts facts; + U16 reply_sz; + U16 op_reply_sz; + + U32 event_masks[MPI3_EVENT_NOTIFY_EVENTMASK_WORDS]; + + char fwevt_worker_name[MPI3MR_NAME_LENGTH]; + struct workqueue_struct *fwevt_worker_thread; + struct mtx fwevt_lock; + struct mtx target_lock; + + U16 max_host_ios; + bus_dma_tag_t chain_sgl_list_tag; + struct mpi3mr_chain *chain_sgl_list; + U16 chain_bitmap_sz; + void *chain_bitmap; + struct mtx chain_buf_lock; + U16 chain_buf_count; + + struct mpi3mr_drvr_cmd ioctl_cmds; + struct mpi3mr_drvr_cmd host_tm_cmds; + struct mpi3mr_drvr_cmd dev_rmhs_cmds[MPI3MR_NUM_DEVRMCMD]; + struct mpi3mr_drvr_cmd evtack_cmds[MPI3MR_NUM_EVTACKCMD]; + + U16 devrem_bitmap_sz; + void *devrem_bitmap; + + U16 dev_handle_bitmap_sz; + void *removepend_bitmap; + + U16 evtack_cmds_bitmap_sz; + void *evtack_cmds_bitmap; + + U32 ts_update_counter; + U8 reset_in_progress; + U8 unrecoverable; + U8 block_ioctls; + U8 in_prep_ciactv_rst; + U16 prep_ciactv_rst_counter; + struct mtx reset_mutex; + + U8 prepare_for_reset; + U16 prepare_for_reset_timeout_counter; + + U16 diagsave_timeout; + int logging_level; + U16 flush_io_count; + + Mpi3DriverInfoLayout_t driver_info; + + U16 change_count; + + U8 *log_data_buffer; + U16 log_data_buffer_index; + U16 log_data_entry_size; + + U8 pel_wait_pend; + U8 pel_abort_requested; + U8 pel_class; + U16 pel_locale; + + struct mpi3mr_drvr_cmd pel_cmds; + struct mpi3mr_drvr_cmd pel_abort_cmd; + U32 newest_seqnum; + void *pel_seq_number; + bus_addr_t pel_seq_number_dma; + bus_dma_tag_t pel_seq_num_dmatag; + bus_dmamap_t pel_seq_num_dmamap; + U32 pel_seq_number_sz; + + struct selinfo mpi3mr_select; + U32 mpi3mr_poll_waiting; + U32 mpi3mr_aen_triggered; + + U16 wait_for_port_enable; + U16 track_mapping_events; + U16 pending_map_events; + mpi3mr_atomic_t fw_outstanding; + mpi3mr_atomic_t pend_ioctls; + struct proc *watchdog_thread; + void *watchdog_chan; + void *tm_chan; + u_int8_t remove_in_progress; + u_int8_t watchdog_thread_active; + u_int8_t do_timedout_reset; + bool allow_ios; + bool secure_ctrl; + mpi3mr_atomic_t pend_large_data_sz; + + u_int32_t io_throttle_data_length; + u_int32_t io_throttle_high; + u_int32_t io_throttle_low; + u_int16_t num_io_throttle_group; + u_int iot_enable; + struct mpi3mr_throttle_group_info *throttle_groups; + + struct dma_memory_desc ioctl_sge[MPI3MR_NUM_IOCTL_SGE]; + struct dma_memory_desc ioctl_chain_sge; + struct dma_memory_desc ioctl_resp_sge; + bool ioctl_sges_allocated; +}; + +static __inline uint64_t +mpi3mr_regread64(struct mpi3mr_softc *sc, uint32_t offset) +{ + return bus_space_read_8(sc->mpi3mr_btag, sc->mpi3mr_bhandle, offset); +} + +static __inline void +mpi3mr_regwrite64(struct mpi3mr_softc *sc, uint32_t offset, uint64_t val) +{ + bus_space_write_8(sc->mpi3mr_btag, sc->mpi3mr_bhandle, offset, val); +} + +static __inline uint32_t +mpi3mr_regread(struct mpi3mr_softc *sc, uint32_t offset) +{ + return bus_space_read_4(sc->mpi3mr_btag, sc->mpi3mr_bhandle, offset); +} + +static __inline void +mpi3mr_regwrite(struct mpi3mr_softc *sc, uint32_t offset, uint32_t val) +{ + bus_space_write_4(sc->mpi3mr_btag, sc->mpi3mr_bhandle, offset, val); +} + +#define MPI3MR_INFO (1 << 0) /* Basic info */ +#define MPI3MR_FAULT (1 << 1) /* Hardware faults */ +#define MPI3MR_EVENT (1 << 2) /* Event data from the controller */ +#define MPI3MR_LOG (1 << 3) /* Log data from the controller */ +#define MPI3MR_RECOVERY (1 << 4) /* Command error recovery tracing */ +#define MPI3MR_ERROR (1 << 5) /* Fatal driver/OS APIs failure */ +#define MPI3MR_XINFO (1 << 6) /* Additional info logs*/ +#define MPI3MR_TRACE (1 << 7) /* Trace functions */ +#define MPI3MR_IOT (1 << 8) /* IO throttling related debugs */ +#define MPI3MR_DEBUG_TM (1 << 9) /* Task management related debugs */ +#define MPI3MR_DEBUG_IOCTL (1 << 10) /* IOCTL related debugs */ + +#define mpi3mr_printf(sc, args...) \ + device_printf((sc)->mpi3mr_dev, ##args) + +#define mpi3mr_print_field(sc, msg, args...) \ + printf("\t" msg, ##args) + +#define mpi3mr_vprintf(sc, args...) \ +do { \ + if (bootverbose) \ + mpi3mr_printf(sc, ##args); \ +} while (0) + +#define mpi3mr_dprint(sc, level, msg, args...) \ +do { \ + if ((sc)->mpi3mr_debug & (level)) \ + device_printf((sc)->mpi3mr_dev, msg, ##args); \ +} while (0) + +#define MPI3MR_PRINTFIELD_START(sc, tag...) \ + mpi3mr_printf((sc), ##tag); \ + mpi3mr_print_field((sc), ":\n") +#define MPI3MR_PRINTFIELD_END(sc, tag) \ + mpi3mr_printf((sc), tag "\n") +#define MPI3MR_PRINTFIELD(sc, facts, attr, fmt) \ + mpi3mr_print_field((sc), #attr ": " #fmt "\n", (facts)->attr) + +#define mpi3mr_kproc_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg) \ + kproc_create(func, farg, proc_ptr, flags, stackpgs, fmtstr, arg) +#define mpi3mr_kproc_exit(arg) kproc_exit(arg) + +#if defined(CAM_PRIORITY_XPT) +#define MPI3MR_PRIORITY_XPT CAM_PRIORITY_XPT +#else +#define MPI3MR_PRIORITY_XPT 5 +#endif + +static __inline void +mpi3mr_clear_bit(int b, volatile void *p) +{ + atomic_clear_int(((volatile int *)p) + (b >> 5), 1 << (b & 0x1f)); +} + +static __inline void +mpi3mr_set_bit(int b, volatile void *p) +{ + atomic_set_int(((volatile int *)p) + (b >> 5), 1 << (b & 0x1f)); +} + +static __inline int +mpi3mr_test_bit(int b, volatile void *p) +{ + return ((volatile int *)p)[b >> 5] & (1 << (b & 0x1f)); +} + +static __inline int +mpi3mr_test_and_set_bit(int b, volatile void *p) +{ + int ret = ((volatile int *)p)[b >> 5] & (1 << (b & 0x1f)); + + atomic_set_int(((volatile int *)p) + (b >> 5), 1 << (b & 0x1f)); + return ret; +} + +static __inline int +mpi3mr_find_first_zero_bit(void *p, int bit_count) +{ + int i, sz, j=0; + U8 *loc; + + sz = bit_count % 8 ? (bit_count / 8 + 1) : (bit_count / 8); + loc = malloc(sz, M_MPI3MR, M_NOWAIT | M_ZERO); + + memcpy(loc, p, sz); + + for (i = 0; i < sz; i++) { + j = 0; + while (j < 8) { + if (!((loc[i] >> j) & 0x1)) + goto out; + j++; + } + } +out: + free(loc, M_MPI3MR); + return (i + j); +} + +#define MPI3MR_DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) + +void +init_completion(struct completion *completion); + +void +complete(struct completion *completion); + +void wait_for_completion_timeout(struct completion *completion, + U32 timeout); +void wait_for_completion_timeout_tm(struct completion *completion, + U32 timeout, struct mpi3mr_softc *sc); +void mpi3mr_add_sg_single(void *paddr, U8 flags, U32 length, + bus_addr_t dma_addr); +void mpi3mr_enable_interrupts(struct mpi3mr_softc *sc); +void mpi3mr_disable_interrupts(struct mpi3mr_softc *sc); +void mpi3mr_memaddr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error); +int mpi3mr_submit_admin_cmd(struct mpi3mr_softc *mrioc, void *admin_req, + U16 admin_req_sz); +int mpi3mr_submit_io(struct mpi3mr_softc *mrioc, + struct mpi3mr_op_req_queue *op_req_q, U8 *req); +int +mpi3mr_alloc_interrupts(struct mpi3mr_softc *sc, U16 setup_one); + +void mpi3mr_cleanup_ioc(struct mpi3mr_softc *sc); +int mpi3mr_initialize_ioc(struct mpi3mr_softc *sc, U8 reason); +void mpi3mr_build_zero_len_sge(void *paddr); +int mpi3mr_issue_event_notification(struct mpi3mr_softc *sc); +int +mpi3mr_register_events(struct mpi3mr_softc *sc); +void mpi3mr_process_op_reply_desc(struct mpi3mr_softc *sc, + Mpi3DefaultReplyDescriptor_t *reply_desc, U64 *reply_dma); +struct mpi3mr_cmd * +mpi3mr_get_command(struct mpi3mr_softc *sc); +void +mpi3mr_release_command(struct mpi3mr_cmd *cmd); +int +mpi3mr_complete_io_cmd(struct mpi3mr_softc *sc, + struct mpi3mr_irq_context *irq_context); +int +mpi3mr_cam_detach(struct mpi3mr_softc *sc); +int +mpi3mr_cam_attach(struct mpi3mr_softc *sc); +struct mpi3mr_target * +mpi3mr_find_target_by_per_id(struct mpi3mr_cam_softc *cam_sc, + uint16_t per_id); +struct mpi3mr_target * +mpi3mr_find_target_by_dev_handle(struct mpi3mr_cam_softc *cam_sc, + uint16_t dev_handle); +int mpi3mr_create_device(struct mpi3mr_softc *sc, + Mpi3DevicePage0_t *dev_pg0); +void +mpi3mr_unmap_request(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cmd); +void +init_completion(struct completion *completion); +void +complete(struct completion *completion); +void wait_for_completion_timeout(struct completion *completion, + U32 timeout); +void +poll_for_command_completion(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *cmd, U16 wait); +int +mpi3mr_alloc_requests(struct mpi3mr_softc *sc); +void +mpi3mr_watchdog(void *arg); +int mpi3mr_issue_port_enable(struct mpi3mr_softc *mrioc, U8 async); +void +mpi3mr_isr(void *privdata); +int +mpi3mr_alloc_msix_queues(struct mpi3mr_softc *sc); +void +mpi3mr_destory_mtx(struct mpi3mr_softc *sc); +void +mpi3mr_free_mem(struct mpi3mr_softc *sc); +void +mpi3mr_cleanup_interrupts(struct mpi3mr_softc *sc); +int mpi3mr_setup_irqs(struct mpi3mr_softc *sc); +void mpi3mr_cleanup_event_taskq(struct mpi3mr_softc *sc); +void +mpi3mr_hexdump(void *buf, int sz, int format); +int mpi3mr_soft_reset_handler(struct mpi3mr_softc *sc, + U32 reset_reason, bool snapdump); +void +mpi3mrsas_release_simq_reinit(struct mpi3mr_cam_softc *cam_sc); +void +mpi3mr_watchdog_thread(void *arg); +void mpi3mr_add_device(struct mpi3mr_softc *sc, U16 per_id); +int mpi3mr_remove_device(struct mpi3mr_softc *sc, U16 handle); +int +mpi3mrsas_register_events(struct mpi3mr_softc *sc); +int mpi3mr_process_event_ack(struct mpi3mr_softc *sc, U8 event, + U32 event_ctx); +int mpi3mr_remove_device_from_os(struct mpi3mr_softc *sc, U16 handle); +void mpi3mr_remove_device_from_list(struct mpi3mr_softc *sc, struct mpi3mr_target *target, + bool must_delete); +void mpi3mr_update_device(struct mpi3mr_softc *mrioc, + struct mpi3mr_target *tgtdev, Mpi3DevicePage0_t *dev_pg0, bool is_added); +void mpi3mr_app_save_logdata(struct mpi3mr_softc *sc, char *event_data, U16 event_data_size); +void mpi3mr_set_io_divert_for_all_vd_in_tg(struct mpi3mr_softc *sc, + struct mpi3mr_throttle_group_info *tg, U8 divert_value); +enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_softc *sc); +void mpi3mr_poll_pend_io_completions(struct mpi3mr_softc *sc); +void int_to_lun(unsigned int lun, U8 *req_lun); +void trigger_reset_from_watchdog(struct mpi3mr_softc *sc, U8 reset_type, U32 reset_reason); +void mpi3mr_alloc_ioctl_dma_memory(struct mpi3mr_softc *sc); +#endif /*MPI3MR_H_INCLUDED*/ diff --git a/sys/dev/mpi3mr/mpi3mr_app.c b/sys/dev/mpi3mr/mpi3mr_app.c new file mode 100644 index 000000000000..0cf25b968283 --- /dev/null +++ b/sys/dev/mpi3mr/mpi3mr_app.c @@ -0,0 +1,2206 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2020-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Authors: Sumit Saxena + * Chandrakanth Patil + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include "mpi3mr_cam.h" +#include "mpi3mr_app.h" +#include "mpi3mr.h" + +static d_open_t mpi3mr_open; +static d_close_t mpi3mr_close; +static d_ioctl_t mpi3mr_ioctl; +static d_poll_t mpi3mr_poll; + +static struct cdevsw mpi3mr_cdevsw = { + .d_version = D_VERSION, + .d_flags = 0, + .d_open = mpi3mr_open, + .d_close = mpi3mr_close, + .d_ioctl = mpi3mr_ioctl, + .d_poll = mpi3mr_poll, + .d_name = "mpi3mr", +}; + +static int +mpi3mr_open(struct cdev *dev, int flags, int fmt, struct thread *td) +{ + + return (0); +} + +static int +mpi3mr_close(struct cdev *dev, int flags, int fmt, struct thread *td) +{ + + return (0); +} + +/* + * mpi3mr_app_attach - Char device registration + * @sc: Adapter reference + * + * This function does char device registration. + * + * Return: 0 on success and proper error codes on failure + */ +int +mpi3mr_app_attach(struct mpi3mr_softc *sc) +{ + + /* Create a /dev entry for Avenger controller */ + sc->mpi3mr_cdev = make_dev(&mpi3mr_cdevsw, device_get_unit(sc->mpi3mr_dev), + UID_ROOT, GID_OPERATOR, 0640, "mpi3mr%d", + device_get_unit(sc->mpi3mr_dev)); + + if (sc->mpi3mr_cdev == NULL) + return (ENOMEM); + + sc->mpi3mr_cdev->si_drv1 = sc; + + /* Assign controller instance to mgmt_info structure */ + if (device_get_unit(sc->mpi3mr_dev) == 0) + memset(&mpi3mr_mgmt_info, 0, sizeof(mpi3mr_mgmt_info)); + mpi3mr_mgmt_info.count++; + mpi3mr_mgmt_info.sc_ptr[mpi3mr_mgmt_info.max_index] = sc; + mpi3mr_mgmt_info.max_index++; + + return (0); +} + +void +mpi3mr_app_detach(struct mpi3mr_softc *sc) +{ + U8 i = 0; + + if (sc->mpi3mr_cdev == NULL) + return; + + destroy_dev(sc->mpi3mr_cdev); + for (i = 0; i < mpi3mr_mgmt_info.max_index; i++) { + if (mpi3mr_mgmt_info.sc_ptr[i] == sc) { + mpi3mr_mgmt_info.count--; + mpi3mr_mgmt_info.sc_ptr[i] = NULL; + break; + } + } + return; +} + +static int +mpi3mr_poll(struct cdev *dev, int poll_events, struct thread *td) +{ + int revents = 0; + struct mpi3mr_softc *sc = NULL; + sc = dev->si_drv1; + + if ((poll_events & (POLLIN | POLLRDNORM)) && + (sc->mpi3mr_aen_triggered)) + revents |= poll_events & (POLLIN | POLLRDNORM); + + if (revents == 0) { + if (poll_events & (POLLIN | POLLRDNORM)) { + sc->mpi3mr_poll_waiting = 1; + selrecord(td, &sc->mpi3mr_select); + } + } + return revents; +} + +/** + * mpi3mr_app_get_adp_instancs - Get Adapter instance + * @mrioc_id: Adapter ID + * + * This fucnction searches the Adapter reference with mrioc_id + * upon found, returns the adapter reference otherwise returns + * the NULL + * + * Return: Adapter reference on success and NULL on failure + */ +static struct mpi3mr_softc * +mpi3mr_app_get_adp_instance(U8 mrioc_id) +{ + struct mpi3mr_softc *sc = NULL; + + if (mrioc_id >= mpi3mr_mgmt_info.max_index) + return NULL; + + sc = mpi3mr_mgmt_info.sc_ptr[mrioc_id]; + return sc; +} + +static int +mpi3mr_app_construct_nvme_sgl(struct mpi3mr_softc *sc, + Mpi3NVMeEncapsulatedRequest_t *nvme_encap_request, + struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers, U8 bufcnt) +{ + struct mpi3mr_nvme_pt_sge *nvme_sgl; + U64 sgl_dma; + U8 count; + U16 available_sges = 0, i; + U32 sge_element_size = sizeof(struct mpi3mr_nvme_pt_sge); + size_t length = 0; + struct mpi3mr_ioctl_mpt_dma_buffer *dma_buff = dma_buffers; + U64 sgemod_mask = ((U64)((sc->facts.sge_mod_mask) << + sc->facts.sge_mod_shift) << 32); + U64 sgemod_val = ((U64)(sc->facts.sge_mod_value) << + sc->facts.sge_mod_shift) << 32; + + U32 size; + + nvme_sgl = (struct mpi3mr_nvme_pt_sge *) + ((U8 *)(nvme_encap_request->Command) + MPI3MR_NVME_CMD_SGL_OFFSET); + + /* + * Not all commands require a data transfer. If no data, just return + * without constructing any SGL. + */ + for (count = 0; count < bufcnt; count++, dma_buff++) { + if ((dma_buff->data_dir == MPI3MR_APP_DDI) || + (dma_buff->data_dir == MPI3MR_APP_DDO)) { + length = dma_buff->kern_buf_len; + break; + } + } + if (!length || !dma_buff->num_dma_desc) + return 0; + + if (dma_buff->num_dma_desc == 1) { + available_sges = 1; + goto build_sges; + } + sgl_dma = (U64)sc->ioctl_chain_sge.dma_addr; + + if (sgl_dma & sgemod_mask) { + printf(IOCNAME "NVMe SGL address collides with SGEModifier\n",sc->name); + return -1; + } + + sgl_dma &= ~sgemod_mask; + sgl_dma |= sgemod_val; + + memset(sc->ioctl_chain_sge.addr, 0, sc->ioctl_chain_sge.size); + available_sges = sc->ioctl_chain_sge.size / sge_element_size; + if (available_sges < dma_buff->num_dma_desc) + return -1; + memset(nvme_sgl, 0, sizeof(struct mpi3mr_nvme_pt_sge)); + nvme_sgl->base_addr = sgl_dma; + size = dma_buff->num_dma_desc * sizeof(struct mpi3mr_nvme_pt_sge); + nvme_sgl->length = htole32(size); + nvme_sgl->type = MPI3MR_NVMESGL_LAST_SEGMENT; + + nvme_sgl = (struct mpi3mr_nvme_pt_sge *) sc->ioctl_chain_sge.addr; + +build_sges: + for (i = 0; i < dma_buff->num_dma_desc; i++) { + sgl_dma = htole64(dma_buff->dma_desc[i].dma_addr); + if (sgl_dma & sgemod_mask) { + printf("%s: SGL address collides with SGE modifier\n", + __func__); + return -1; + } + + sgl_dma &= ~sgemod_mask; + sgl_dma |= sgemod_val; + + nvme_sgl->base_addr = sgl_dma; + nvme_sgl->length = htole32(dma_buff->dma_desc[i].size); + nvme_sgl->type = MPI3MR_NVMESGL_DATA_SEGMENT; + nvme_sgl++; + available_sges--; + } + + return 0; +} + +static int +mpi3mr_app_build_nvme_prp(struct mpi3mr_softc *sc, + Mpi3NVMeEncapsulatedRequest_t *nvme_encap_request, + struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers, U8 bufcnt) +{ + int prp_size = MPI3MR_NVME_PRP_SIZE; + U64 *prp_entry, *prp1_entry, *prp2_entry; + U64 *prp_page; + bus_addr_t prp_entry_dma, prp_page_dma, dma_addr; + U32 offset, entry_len, dev_pgsz; + U32 page_mask_result, page_mask; + size_t length = 0, desc_len; + U8 count; + struct mpi3mr_ioctl_mpt_dma_buffer *dma_buff = dma_buffers; + U64 sgemod_mask = ((U64)((sc->facts.sge_mod_mask) << + sc->facts.sge_mod_shift) << 32); + U64 sgemod_val = ((U64)(sc->facts.sge_mod_value) << + sc->facts.sge_mod_shift) << 32; + U16 dev_handle = nvme_encap_request->DevHandle; + struct mpi3mr_target *tgtdev; + U16 desc_count = 0; + + tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, dev_handle); + if (!tgtdev) { + printf(IOCNAME "EncapNVMe Error: Invalid DevHandle 0x%02x\n", sc->name, + dev_handle); + return -1; + } + if (tgtdev->dev_spec.pcie_inf.pgsz == 0) { + printf(IOCNAME "%s: NVME device page size is zero for handle 0x%04x\n", + sc->name, __func__, dev_handle); + return -1; + } + dev_pgsz = 1 << (tgtdev->dev_spec.pcie_inf.pgsz); + + page_mask = dev_pgsz - 1; + + if (dev_pgsz > MPI3MR_IOCTL_SGE_SIZE){ + printf("%s: NVMe device page size(%d) is greater than ioctl data sge size(%d) for handle 0x%04x\n", + __func__, dev_pgsz, MPI3MR_IOCTL_SGE_SIZE, dev_handle); + return -1; + } + + if (MPI3MR_IOCTL_SGE_SIZE % dev_pgsz){ + printf("%s: ioctl data sge size(%d) is not a multiple of NVMe device page size(%d) for handle 0x%04x\n", + __func__, MPI3MR_IOCTL_SGE_SIZE, dev_pgsz, dev_handle); + return -1; + } + + /* + * Not all commands require a data transfer. If no data, just return + * without constructing any PRP. + */ + for (count = 0; count < bufcnt; count++, dma_buff++) { + if ((dma_buff->data_dir == MPI3MR_APP_DDI) || + (dma_buff->data_dir == MPI3MR_APP_DDO)) { + length = dma_buff->kern_buf_len; + break; + } + } + if (!length || !dma_buff->num_dma_desc) + return 0; + + for (count = 0; count < dma_buff->num_dma_desc; count++) { + dma_addr = dma_buff->dma_desc[count].dma_addr; + if (dma_addr & page_mask) { + printf("%s:dma_addr 0x%lu is not aligned with page size 0x%x\n", + __func__, dma_addr, dev_pgsz); + return -1; + } + } + + dma_addr = dma_buff->dma_desc[0].dma_addr; + desc_len = dma_buff->dma_desc[0].size; + + sc->nvme_encap_prp_sz = 0; + if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ + 4, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + dev_pgsz, /* maxsize */ + 1, /* nsegments */ + dev_pgsz, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->nvme_encap_prp_list_dmatag)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot create ioctl NVME kernel buffer dma tag\n"); + return (ENOMEM); + } + + if (bus_dmamem_alloc(sc->nvme_encap_prp_list_dmatag, (void **)&sc->nvme_encap_prp_list, + BUS_DMA_NOWAIT, &sc->nvme_encap_prp_list_dma_dmamap)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate ioctl NVME dma memory\n"); + return (ENOMEM); + } + + bzero(sc->nvme_encap_prp_list, dev_pgsz); + bus_dmamap_load(sc->nvme_encap_prp_list_dmatag, sc->nvme_encap_prp_list_dma_dmamap, + sc->nvme_encap_prp_list, dev_pgsz, mpi3mr_memaddr_cb, &sc->nvme_encap_prp_list_dma, + 0); + + if (!sc->nvme_encap_prp_list) { + printf(IOCNAME "%s:%d Cannot load ioctl NVME dma memory for size: %d\n", sc->name, + __func__, __LINE__, dev_pgsz); + goto err_out; + } + sc->nvme_encap_prp_sz = dev_pgsz; + + /* + * Set pointers to PRP1 and PRP2, which are in the NVMe command. + * PRP1 is located at a 24 byte offset from the start of the NVMe + * command. Then set the current PRP entry pointer to PRP1. + */ + prp1_entry = (U64 *)((U8 *)(nvme_encap_request->Command) + MPI3MR_NVME_CMD_PRP1_OFFSET); + prp2_entry = (U64 *)((U8 *)(nvme_encap_request->Command) + MPI3MR_NVME_CMD_PRP2_OFFSET); + prp_entry = prp1_entry; + /* + * For the PRP entries, use the specially allocated buffer of + * contiguous memory. + */ + prp_page = sc->nvme_encap_prp_list; + prp_page_dma = sc->nvme_encap_prp_list_dma; + + /* + * Check if we are within 1 entry of a page boundary we don't + * want our first entry to be a PRP List entry. + */ + page_mask_result = (uintptr_t)((U8 *)prp_page + prp_size) & page_mask; + if (!page_mask_result) { + printf(IOCNAME "PRP Page is not page aligned\n", sc->name); + goto err_out; + } + + /* + * Set PRP physical pointer, which initially points to the current PRP + * DMA memory page. + */ + prp_entry_dma = prp_page_dma; + + + /* Loop while the length is not zero. */ + while (length) { + page_mask_result = (prp_entry_dma + prp_size) & page_mask; + if (!page_mask_result && (length > dev_pgsz)) { + printf(IOCNAME "Single PRP page is not sufficient\n", sc->name); + goto err_out; + } + + /* Need to handle if entry will be part of a page. */ + offset = dma_addr & page_mask; + entry_len = dev_pgsz - offset; + + if (prp_entry == prp1_entry) { + /* + * Must fill in the first PRP pointer (PRP1) before + * moving on. + */ + *prp1_entry = dma_addr; + if (*prp1_entry & sgemod_mask) { + printf(IOCNAME "PRP1 address collides with SGEModifier\n", sc->name); + goto err_out; + } + *prp1_entry &= ~sgemod_mask; + *prp1_entry |= sgemod_val; + + /* + * Now point to the second PRP entry within the + * command (PRP2). + */ + prp_entry = prp2_entry; + } else if (prp_entry == prp2_entry) { + /* + * Should the PRP2 entry be a PRP List pointer or just + * a regular PRP pointer? If there is more than one + * more page of data, must use a PRP List pointer. + */ + if (length > dev_pgsz) { + /* + * PRP2 will contain a PRP List pointer because + * more PRP's are needed with this command. The + * list will start at the beginning of the + * contiguous buffer. + */ + *prp2_entry = prp_entry_dma; + if (*prp2_entry & sgemod_mask) { + printf(IOCNAME "PRP list address collides with SGEModifier\n", sc->name); + goto err_out; + } + *prp2_entry &= ~sgemod_mask; + *prp2_entry |= sgemod_val; + + /* + * The next PRP Entry will be the start of the + * first PRP List. + */ + prp_entry = prp_page; + continue; + } else { + /* + * After this, the PRP Entries are complete. + * This command uses 2 PRP's and no PRP list. + */ + *prp2_entry = dma_addr; + if (*prp2_entry & sgemod_mask) { + printf(IOCNAME "PRP2 address collides with SGEModifier\n", sc->name); + goto err_out; + } + *prp2_entry &= ~sgemod_mask; + *prp2_entry |= sgemod_val; + } + } else { + /* + * Put entry in list and bump the addresses. + * + * After PRP1 and PRP2 are filled in, this will fill in + * all remaining PRP entries in a PRP List, one per + * each time through the loop. + */ + *prp_entry = dma_addr; + if (*prp_entry & sgemod_mask) { + printf(IOCNAME "PRP address collides with SGEModifier\n", sc->name); + goto err_out; + } + *prp_entry &= ~sgemod_mask; + *prp_entry |= sgemod_val; + prp_entry++; + prp_entry_dma += prp_size; + } + + /* Decrement length accounting for last partial page. */ + if (entry_len >= length) + length = 0; + else { + if (entry_len <= desc_len) { + dma_addr += entry_len; + desc_len -= entry_len; + } + if (!desc_len) { + if ((++desc_count) >= + dma_buff->num_dma_desc) { + printf("%s: Invalid len %ld while building PRP\n", + __func__, length); + goto err_out; + } + dma_addr = + dma_buff->dma_desc[desc_count].dma_addr; + desc_len = + dma_buff->dma_desc[desc_count].size; + } + length -= entry_len; + } + } + return 0; +err_out: + if (sc->nvme_encap_prp_list && sc->nvme_encap_prp_list_dma) { + bus_dmamap_unload(sc->nvme_encap_prp_list_dmatag, sc->nvme_encap_prp_list_dma_dmamap); + bus_dmamem_free(sc->nvme_encap_prp_list_dmatag, sc->nvme_encap_prp_list, sc->nvme_encap_prp_list_dma_dmamap); + bus_dma_tag_destroy(sc->nvme_encap_prp_list_dmatag); + sc->nvme_encap_prp_list = NULL; + } + return -1; +} + + /** ++ * mpi3mr_map_data_buffer_dma - build dma descriptors for data ++ * buffers ++ * @sc: Adapter instance reference ++ * @dma_buff: buffer map descriptor ++ * @desc_count: Number of already consumed dma descriptors ++ * ++ * This function computes how many pre-allocated DMA descriptors ++ * are required for the given data buffer and if those number of ++ * descriptors are free, then setup the mapping of the scattered ++ * DMA address to the given data buffer, if the data direction ++ * of the buffer is DATA_OUT then the actual data is copied to ++ * the DMA buffers ++ * ++ * Return: 0 on success, -1 on failure ++ */ +static int mpi3mr_map_data_buffer_dma(struct mpi3mr_softc *sc, + struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers, + U8 desc_count) +{ + U16 i, needed_desc = (dma_buffers->kern_buf_len / MPI3MR_IOCTL_SGE_SIZE); + U32 buf_len = dma_buffers->kern_buf_len, copied_len = 0; + + if (dma_buffers->kern_buf_len % MPI3MR_IOCTL_SGE_SIZE) + needed_desc++; + + if ((needed_desc + desc_count) > MPI3MR_NUM_IOCTL_SGE) { + printf("%s: DMA descriptor mapping error %d:%d:%d\n", + __func__, needed_desc, desc_count, MPI3MR_NUM_IOCTL_SGE); + return -1; + } + + dma_buffers->dma_desc = malloc(sizeof(*dma_buffers->dma_desc) * needed_desc, + M_MPI3MR, M_NOWAIT | M_ZERO); + if (!dma_buffers->dma_desc) + return -1; + + for (i = 0; i < needed_desc; i++, desc_count++) { + + dma_buffers->dma_desc[i].addr = sc->ioctl_sge[desc_count].addr; + dma_buffers->dma_desc[i].dma_addr = sc->ioctl_sge[desc_count].dma_addr; + + if (buf_len < sc->ioctl_sge[desc_count].size) + dma_buffers->dma_desc[i].size = buf_len; + else + dma_buffers->dma_desc[i].size = sc->ioctl_sge[desc_count].size; + + buf_len -= dma_buffers->dma_desc[i].size; + memset(dma_buffers->dma_desc[i].addr, 0, sc->ioctl_sge[desc_count].size); + + if (dma_buffers->data_dir == MPI3MR_APP_DDO) { + copyin(((U8 *)dma_buffers->user_buf + copied_len), + dma_buffers->dma_desc[i].addr, + dma_buffers->dma_desc[i].size); + copied_len += dma_buffers->dma_desc[i].size; + } + } + + dma_buffers->num_dma_desc = needed_desc; + + return 0; +} + +static unsigned int +mpi3mr_app_get_nvme_data_fmt(Mpi3NVMeEncapsulatedRequest_t *nvme_encap_request) +{ + U8 format = 0; + + format = ((nvme_encap_request->Command[0] & 0xc000) >> 14); + return format; +} + +static inline U16 mpi3mr_total_num_ioctl_sges(struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers, + U8 bufcnt) +{ + U16 i, sge_count = 0; + for (i=0; i < bufcnt; i++, dma_buffers++) { + if ((dma_buffers->data_dir == MPI3MR_APP_DDN) || + dma_buffers->kern_buf) + continue; + sge_count += dma_buffers->num_dma_desc; + if (!dma_buffers->num_dma_desc) + sge_count++; + } + return sge_count; +} + +static int +mpi3mr_app_construct_sgl(struct mpi3mr_softc *sc, U8 *mpi_request, U32 sgl_offset, + struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers, + U8 bufcnt, U8 is_rmc, U8 is_rmr, U8 num_datasges) +{ + U8 *sgl = (mpi_request + sgl_offset), count = 0; + Mpi3RequestHeader_t *mpi_header = (Mpi3RequestHeader_t *)mpi_request; + Mpi3MgmtPassthroughRequest_t *rmgmt_req = + (Mpi3MgmtPassthroughRequest_t *)mpi_request; + struct mpi3mr_ioctl_mpt_dma_buffer *dma_buff = dma_buffers; + U8 flag, sgl_flags, sgl_flags_eob, sgl_flags_last, last_chain_sgl_flags; + U16 available_sges, i, sges_needed; + U32 sge_element_size = sizeof(struct _MPI3_SGE_COMMON); + bool chain_used = false; + + sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | + MPI3_SGE_FLAGS_DLAS_SYSTEM ; + sgl_flags_eob = sgl_flags | MPI3_SGE_FLAGS_END_OF_BUFFER; + sgl_flags_last = sgl_flags_eob | MPI3_SGE_FLAGS_END_OF_LIST; + last_chain_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_LAST_CHAIN | + MPI3_SGE_FLAGS_DLAS_SYSTEM; + + sges_needed = mpi3mr_total_num_ioctl_sges(dma_buffers, bufcnt); + + if (is_rmc) { + mpi3mr_add_sg_single(&rmgmt_req->CommandSGL, + sgl_flags_last, dma_buff->kern_buf_len, + dma_buff->kern_buf_dma); + sgl = (U8 *) dma_buff->kern_buf + dma_buff->user_buf_len; + available_sges = (dma_buff->kern_buf_len - + dma_buff->user_buf_len) / sge_element_size; + if (sges_needed > available_sges) + return -1; + chain_used = true; + dma_buff++; + count++; + if (is_rmr) { + mpi3mr_add_sg_single(&rmgmt_req->ResponseSGL, + sgl_flags_last, dma_buff->kern_buf_len, + dma_buff->kern_buf_dma); + dma_buff++; + count++; + } else + mpi3mr_build_zero_len_sge( + &rmgmt_req->ResponseSGL); + if (num_datasges) { + i = 0; + goto build_sges; + } + } else { + if (sgl_offset >= MPI3MR_AREQ_FRAME_SZ) + return -1; + available_sges = (MPI3MR_AREQ_FRAME_SZ - sgl_offset) / + sge_element_size; + if (!available_sges) + return -1; + } + + if (!num_datasges) { + mpi3mr_build_zero_len_sge(sgl); + return 0; + } + + if (mpi_header->Function == MPI3_FUNCTION_SMP_PASSTHROUGH) { + if ((sges_needed > 2) || (sges_needed > available_sges)) + return -1; + for (; count < bufcnt; count++, dma_buff++) { + if ((dma_buff->data_dir == MPI3MR_APP_DDN) || + !dma_buff->num_dma_desc) + continue; + mpi3mr_add_sg_single(sgl, sgl_flags_last, + dma_buff->dma_desc[0].size, + dma_buff->dma_desc[0].dma_addr); + sgl += sge_element_size; + } + return 0; + } + i = 0; + +build_sges: + for (; count < bufcnt; count++, dma_buff++) { + if (dma_buff->data_dir == MPI3MR_APP_DDN) + continue; + if (!dma_buff->num_dma_desc) { + if (chain_used && !available_sges) + return -1; + if (!chain_used && (available_sges == 1) && + (sges_needed > 1)) + goto setup_chain; + flag = sgl_flags_eob; + if (num_datasges == 1) + flag = sgl_flags_last; + mpi3mr_add_sg_single(sgl, flag, 0, 0); + sgl += sge_element_size; + available_sges--; + sges_needed--; + num_datasges--; + continue; + } + for (; i < dma_buff->num_dma_desc; i++) { + if (chain_used && !available_sges) + return -1; + if (!chain_used && (available_sges == 1) && + (sges_needed > 1)) + goto setup_chain; + flag = sgl_flags; + if (i == (dma_buff->num_dma_desc - 1)) { + if (num_datasges == 1) + flag = sgl_flags_last; + else + flag = sgl_flags_eob; + } + + mpi3mr_add_sg_single(sgl, flag, + dma_buff->dma_desc[i].size, + dma_buff->dma_desc[i].dma_addr); + sgl += sge_element_size; + available_sges--; + sges_needed--; + } + num_datasges--; + i = 0; + } + return 0; + +setup_chain: + available_sges = sc->ioctl_chain_sge.size / sge_element_size; + if (sges_needed > available_sges) + return -1; + mpi3mr_add_sg_single(sgl, last_chain_sgl_flags, + (sges_needed * sge_element_size), sc->ioctl_chain_sge.dma_addr); + memset(sc->ioctl_chain_sge.addr, 0, sc->ioctl_chain_sge.size); + sgl = (U8 *)sc->ioctl_chain_sge.addr; + chain_used = true; + goto build_sges; +} + + +/** + * mpi3mr_app_mptcmds - MPI Pass through IOCTL handler + * @dev: char device + * @cmd: IOCTL command + * @arg: User data payload buffer for the IOCTL + * @flag: flags + * @thread: threads + * + * This function is the top level handler for MPI Pass through + * IOCTL, this does basic validation of the input data buffers, + * identifies the given buffer types and MPI command, allocates + * DMAable memory for user given buffers, construstcs SGL + * properly and passes the command to the firmware. + * + * Once the MPI command is completed the driver copies the data + * if any and reply, sense information to user provided buffers. + * If the command is timed out then issues controller reset + * prior to returning. + * + * Return: 0 on success and proper error codes on failure + */ +static long +mpi3mr_app_mptcmds(struct cdev *dev, u_long cmd, void *uarg, + int flag, struct thread *td) +{ + long rval = EINVAL; + U8 count, bufcnt = 0, is_rmcb = 0, is_rmrb = 0, din_cnt = 0, dout_cnt = 0; + U8 invalid_be = 0, erb_offset = 0xFF, mpirep_offset = 0xFF; + U16 desc_count = 0; + U8 nvme_fmt = 0; + U32 tmplen = 0, erbsz = MPI3MR_SENSEBUF_SZ, din_sz = 0, dout_sz = 0; + U8 *kern_erb = NULL; + U8 *mpi_request = NULL; + Mpi3RequestHeader_t *mpi_header = NULL; + Mpi3PELReqActionGetCount_t *pel = NULL; + Mpi3StatusReplyDescriptor_t *status_desc = NULL; + struct mpi3mr_softc *sc = NULL; + struct mpi3mr_ioctl_buf_entry_list *buffer_list = NULL; + struct mpi3mr_buf_entry *buf_entries = NULL; + struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers = NULL, *dma_buff = NULL; + struct mpi3mr_ioctl_mpirepbuf *mpirepbuf = NULL; + struct mpi3mr_ioctl_mptcmd *karg = (struct mpi3mr_ioctl_mptcmd *)uarg; + + + sc = mpi3mr_app_get_adp_instance(karg->mrioc_id); + if (!sc) + return ENODEV; + + if (!sc->ioctl_sges_allocated) { + printf("%s: DMA memory was not allocated\n", __func__); + return ENOMEM; + } + + if (karg->timeout < MPI3MR_IOCTL_DEFAULT_TIMEOUT) + karg->timeout = MPI3MR_IOCTL_DEFAULT_TIMEOUT; + + if (!karg->mpi_msg_size || !karg->buf_entry_list_size) { + printf(IOCNAME "%s:%d Invalid IOCTL parameters passed\n", sc->name, + __func__, __LINE__); + return rval; + } + if ((karg->mpi_msg_size * 4) > MPI3MR_AREQ_FRAME_SZ) { + printf(IOCNAME "%s:%d Invalid IOCTL parameters passed\n", sc->name, + __func__, __LINE__); + return rval; + } + + mpi_request = malloc(MPI3MR_AREQ_FRAME_SZ, M_MPI3MR, M_NOWAIT | M_ZERO); + if (!mpi_request) { + printf(IOCNAME "%s: memory allocation failed for mpi_request\n", sc->name, + __func__); + return ENOMEM; + } + + mpi_header = (Mpi3RequestHeader_t *)mpi_request; + pel = (Mpi3PELReqActionGetCount_t *)mpi_request; + if (copyin(karg->mpi_msg_buf, mpi_request, (karg->mpi_msg_size * 4))) { + printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, + __FILE__, __LINE__, __func__); + rval = EFAULT; + goto out; + } + + buffer_list = malloc(karg->buf_entry_list_size, M_MPI3MR, M_NOWAIT | M_ZERO); + if (!buffer_list) { + printf(IOCNAME "%s: memory allocation failed for buffer_list\n", sc->name, + __func__); + rval = ENOMEM; + goto out; + } + if (copyin(karg->buf_entry_list, buffer_list, karg->buf_entry_list_size)) { + printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, + __FILE__, __LINE__, __func__); + rval = EFAULT; + goto out; + } + if (!buffer_list->num_of_buf_entries) { + printf(IOCNAME "%s:%d Invalid IOCTL parameters passed\n", sc->name, + __func__, __LINE__); + rval = EINVAL; + goto out; + } + bufcnt = buffer_list->num_of_buf_entries; + dma_buffers = malloc((sizeof(*dma_buffers) * bufcnt), M_MPI3MR, M_NOWAIT | M_ZERO); + if (!dma_buffers) { + printf(IOCNAME "%s: memory allocation failed for dma_buffers\n", sc->name, + __func__); + rval = ENOMEM; + goto out; + } + buf_entries = buffer_list->buf_entry; + dma_buff = dma_buffers; + for (count = 0; count < bufcnt; count++, buf_entries++, dma_buff++) { + memset(dma_buff, 0, sizeof(*dma_buff)); + dma_buff->user_buf = buf_entries->buffer; + dma_buff->user_buf_len = buf_entries->buf_len; + + switch (buf_entries->buf_type) { + case MPI3MR_IOCTL_BUFTYPE_RAIDMGMT_CMD: + is_rmcb = 1; + if ((count != 0) || !buf_entries->buf_len) + invalid_be = 1; + dma_buff->data_dir = MPI3MR_APP_DDO; + break; + case MPI3MR_IOCTL_BUFTYPE_RAIDMGMT_RESP: + is_rmrb = 1; + if (count != 1 || !is_rmcb || !buf_entries->buf_len) + invalid_be = 1; + dma_buff->data_dir = MPI3MR_APP_DDI; + break; + case MPI3MR_IOCTL_BUFTYPE_DATA_IN: + din_sz = dma_buff->user_buf_len; + din_cnt++; + if ((din_cnt > 1) && !is_rmcb) + invalid_be = 1; + dma_buff->data_dir = MPI3MR_APP_DDI; + break; + case MPI3MR_IOCTL_BUFTYPE_DATA_OUT: + dout_sz = dma_buff->user_buf_len; + dout_cnt++; + if ((dout_cnt > 1) && !is_rmcb) + invalid_be = 1; + dma_buff->data_dir = MPI3MR_APP_DDO; + break; + case MPI3MR_IOCTL_BUFTYPE_MPI_REPLY: + mpirep_offset = count; + dma_buff->data_dir = MPI3MR_APP_DDN; + if (!buf_entries->buf_len) + invalid_be = 1; + break; + case MPI3MR_IOCTL_BUFTYPE_ERR_RESPONSE: + erb_offset = count; + dma_buff->data_dir = MPI3MR_APP_DDN; + if (!buf_entries->buf_len) + invalid_be = 1; + break; + default: + invalid_be = 1; + break; + } + if (invalid_be) + break; + } + if (invalid_be) { + printf(IOCNAME "%s:%d Invalid IOCTL parameters passed\n", sc->name, + __func__, __LINE__); + rval = EINVAL; + goto out; + } + + if (is_rmcb && ((din_sz + dout_sz) > MPI3MR_MAX_IOCTL_TRANSFER_SIZE)) { + printf("%s:%d: invalid data transfer size passed for function 0x%x" + "din_sz = %d, dout_size = %d\n", __func__, __LINE__, + mpi_header->Function, din_sz, dout_sz); + rval = EINVAL; + goto out; + } + + if ((din_sz > MPI3MR_MAX_IOCTL_TRANSFER_SIZE) || + (dout_sz > MPI3MR_MAX_IOCTL_TRANSFER_SIZE)) { + printf("%s:%d: invalid data transfer size passed for function 0x%x" + "din_size=%d dout_size=%d\n", __func__, __LINE__, + mpi_header->Function, din_sz, dout_sz); + rval = EINVAL; + goto out; + } + + if (mpi_header->Function == MPI3_FUNCTION_SMP_PASSTHROUGH) { + if ((din_sz > MPI3MR_IOCTL_SGE_SIZE) || + (dout_sz > MPI3MR_IOCTL_SGE_SIZE)) { + printf("%s:%d: invalid message size passed:%d:%d:%d:%d\n", + __func__, __LINE__, din_cnt, dout_cnt, din_sz, dout_sz); + rval = EINVAL; + goto out; + } + } + + dma_buff = dma_buffers; + for (count = 0; count < bufcnt; count++, dma_buff++) { + + dma_buff->kern_buf_len = dma_buff->user_buf_len; + + if (is_rmcb && !count) { + dma_buff->kern_buf = sc->ioctl_chain_sge.addr; + dma_buff->kern_buf_len = sc->ioctl_chain_sge.size; + dma_buff->kern_buf_dma = sc->ioctl_chain_sge.dma_addr; + dma_buff->dma_desc = NULL; + dma_buff->num_dma_desc = 0; + memset(dma_buff->kern_buf, 0, dma_buff->kern_buf_len); + tmplen = min(dma_buff->kern_buf_len, dma_buff->user_buf_len); + if (copyin(dma_buff->user_buf, dma_buff->kern_buf, tmplen)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "failure at %s() line: %d", + __func__, __LINE__); + rval = EFAULT; + goto out; + } + } else if (is_rmrb && (count == 1)) { + dma_buff->kern_buf = sc->ioctl_resp_sge.addr; + dma_buff->kern_buf_len = sc->ioctl_resp_sge.size; + dma_buff->kern_buf_dma = sc->ioctl_resp_sge.dma_addr; + dma_buff->dma_desc = NULL; + dma_buff->num_dma_desc = 0; + memset(dma_buff->kern_buf, 0, dma_buff->kern_buf_len); + tmplen = min(dma_buff->kern_buf_len, dma_buff->user_buf_len); + dma_buff->kern_buf_len = tmplen; + } else { + if (!dma_buff->kern_buf_len) + continue; + if (mpi3mr_map_data_buffer_dma(sc, dma_buff, desc_count)) { + rval = ENOMEM; + mpi3mr_dprint(sc, MPI3MR_ERROR, "mapping data buffers failed" + "at %s() line: %d\n", __func__, __LINE__); + goto out; + } + desc_count += dma_buff->num_dma_desc; + } + } + + if (erb_offset != 0xFF) { + kern_erb = malloc(erbsz, M_MPI3MR, M_NOWAIT | M_ZERO); + if (!kern_erb) { + printf(IOCNAME "%s:%d Cannot allocate memory for sense buffer\n", sc->name, + __func__, __LINE__); + rval = ENOMEM; + goto out; + } + } + + if (sc->ioctl_cmds.state & MPI3MR_CMD_PENDING) { + printf(IOCNAME "Issue IOCTL: Ioctl command is in use/previous command is pending\n", + sc->name); + rval = EAGAIN; + goto out; + } + + if (sc->unrecoverable) { + printf(IOCNAME "Issue IOCTL: controller is in unrecoverable state\n", sc->name); + rval = EFAULT; + goto out; + } + + if (sc->reset_in_progress) { + printf(IOCNAME "Issue IOCTL: reset in progress\n", sc->name); + rval = EAGAIN; + goto out; + } + if (sc->block_ioctls) { + printf(IOCNAME "Issue IOCTL: IOCTLs are blocked\n", sc->name); + rval = EAGAIN; + goto out; + } + + if (mpi_header->Function != MPI3_FUNCTION_NVME_ENCAPSULATED) { + if (mpi3mr_app_construct_sgl(sc, mpi_request, (karg->mpi_msg_size * 4), dma_buffers, + bufcnt, is_rmcb, is_rmrb, (dout_cnt + din_cnt))) { + printf(IOCNAME "Issue IOCTL: sgl build failed\n", sc->name); + rval = EAGAIN; + goto out; + } + + } else { + nvme_fmt = mpi3mr_app_get_nvme_data_fmt( + (Mpi3NVMeEncapsulatedRequest_t *)mpi_request); + if (nvme_fmt == MPI3MR_NVME_DATA_FORMAT_PRP) { + if (mpi3mr_app_build_nvme_prp(sc, + (Mpi3NVMeEncapsulatedRequest_t *) mpi_request, + dma_buffers, bufcnt)) { + rval = ENOMEM; + goto out; + } + } else if (nvme_fmt == MPI3MR_NVME_DATA_FORMAT_SGL1 || + nvme_fmt == MPI3MR_NVME_DATA_FORMAT_SGL2) { + if (mpi3mr_app_construct_nvme_sgl(sc, (Mpi3NVMeEncapsulatedRequest_t *) mpi_request, + dma_buffers, bufcnt)) { + rval = EINVAL; + goto out; + } + } else { + printf(IOCNAME "%s: Invalid NVMe Command Format\n", sc->name, + __func__); + rval = EINVAL; + goto out; + } + } + + sc->ioctl_cmds.state = MPI3MR_CMD_PENDING; + sc->ioctl_cmds.is_waiting = 1; + sc->ioctl_cmds.callback = NULL; + sc->ioctl_cmds.is_senseprst = 0; + sc->ioctl_cmds.sensebuf = kern_erb; + memset((sc->ioctl_cmds.reply), 0, sc->reply_sz); + mpi_header->HostTag = MPI3MR_HOSTTAG_IOCTLCMDS; + init_completion(&sc->ioctl_cmds.completion); + rval = mpi3mr_submit_admin_cmd(sc, mpi_request, MPI3MR_AREQ_FRAME_SZ); + if (rval) { + printf(IOCNAME "Issue IOCTL: Admin Post failed\n", sc->name); + goto out_failed; + } + wait_for_completion_timeout(&sc->ioctl_cmds.completion, karg->timeout); + + if (!(sc->ioctl_cmds.state & MPI3MR_CMD_COMPLETE)) { + sc->ioctl_cmds.is_waiting = 0; + printf(IOCNAME "Issue IOCTL: command timed out\n", sc->name); + rval = EAGAIN; + if (sc->ioctl_cmds.state & MPI3MR_CMD_RESET) + goto out_failed; + + sc->reset.type = MPI3MR_TRIGGER_SOFT_RESET; + sc->reset.reason = MPI3MR_RESET_FROM_IOCTL_TIMEOUT; + goto out_failed; + } + + if (sc->nvme_encap_prp_list && sc->nvme_encap_prp_list_dma) { + bus_dmamap_unload(sc->nvme_encap_prp_list_dmatag, sc->nvme_encap_prp_list_dma_dmamap); + bus_dmamem_free(sc->nvme_encap_prp_list_dmatag, sc->nvme_encap_prp_list, sc->nvme_encap_prp_list_dma_dmamap); + bus_dma_tag_destroy(sc->nvme_encap_prp_list_dmatag); + sc->nvme_encap_prp_list = NULL; + } + + if (((sc->ioctl_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) + != MPI3_IOCSTATUS_SUCCESS) && + (sc->mpi3mr_debug & MPI3MR_DEBUG_IOCTL)) { + printf(IOCNAME "Issue IOCTL: Failed IOCStatus(0x%04x) Loginfo(0x%08x)\n", sc->name, + (sc->ioctl_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), + sc->ioctl_cmds.ioc_loginfo); + } + + if ((mpirep_offset != 0xFF) && + dma_buffers[mpirep_offset].user_buf_len) { + dma_buff = &dma_buffers[mpirep_offset]; + dma_buff->kern_buf_len = (sizeof(*mpirepbuf) - 1 + + sc->reply_sz); + mpirepbuf = malloc(dma_buff->kern_buf_len, M_MPI3MR, M_NOWAIT | M_ZERO); + + if (!mpirepbuf) { + printf(IOCNAME "%s: failed obtaining a memory for mpi reply\n", sc->name, + __func__); + rval = ENOMEM; + goto out_failed; + } + if (sc->ioctl_cmds.state & MPI3MR_CMD_REPLYVALID) { + mpirepbuf->mpirep_type = + MPI3MR_IOCTL_MPI_REPLY_BUFTYPE_ADDRESS; + memcpy(mpirepbuf->repbuf, sc->ioctl_cmds.reply, sc->reply_sz); + } else { + mpirepbuf->mpirep_type = + MPI3MR_IOCTL_MPI_REPLY_BUFTYPE_STATUS; + status_desc = (Mpi3StatusReplyDescriptor_t *) + mpirepbuf->repbuf; + status_desc->IOCStatus = sc->ioctl_cmds.ioc_status; + status_desc->IOCLogInfo = sc->ioctl_cmds.ioc_loginfo; + } + tmplen = min(dma_buff->kern_buf_len, dma_buff->user_buf_len); + if (copyout(mpirepbuf, dma_buff->user_buf, tmplen)) { + printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, + __FILE__, __LINE__, __func__); + rval = EFAULT; + goto out_failed; + } + } + + if (erb_offset != 0xFF && sc->ioctl_cmds.sensebuf && + sc->ioctl_cmds.is_senseprst) { + dma_buff = &dma_buffers[erb_offset]; + tmplen = min(erbsz, dma_buff->user_buf_len); + if (copyout(kern_erb, dma_buff->user_buf, tmplen)) { + printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, + __FILE__, __LINE__, __func__); + rval = EFAULT; + goto out_failed; + } + } + + dma_buff = dma_buffers; + for (count = 0; count < bufcnt; count++, dma_buff++) { + if ((count == 1) && is_rmrb) { + if (copyout(dma_buff->kern_buf, dma_buff->user_buf,dma_buff->kern_buf_len)) { + printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, + __FILE__, __LINE__, __func__); + rval = EFAULT; + goto out_failed; + } + } else if (dma_buff->data_dir == MPI3MR_APP_DDI) { + tmplen = 0; + for (desc_count = 0; desc_count < dma_buff->num_dma_desc; desc_count++) { + if (copyout(dma_buff->dma_desc[desc_count].addr, + (U8 *)dma_buff->user_buf+tmplen, + dma_buff->dma_desc[desc_count].size)) { + printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, + __FILE__, __LINE__, __func__); + rval = EFAULT; + goto out_failed; + } + tmplen += dma_buff->dma_desc[desc_count].size; + } + } + } + + if ((pel->Function == MPI3_FUNCTION_PERSISTENT_EVENT_LOG) && + (pel->Action == MPI3_PEL_ACTION_GET_COUNT)) + sc->mpi3mr_aen_triggered = 0; + +out_failed: + sc->ioctl_cmds.is_senseprst = 0; + sc->ioctl_cmds.sensebuf = NULL; + sc->ioctl_cmds.state = MPI3MR_CMD_NOTUSED; +out: + if (kern_erb) + free(kern_erb, M_MPI3MR); + if (buffer_list) + free(buffer_list, M_MPI3MR); + if (mpi_request) + free(mpi_request, M_MPI3MR); + if (dma_buffers) { + dma_buff = dma_buffers; + for (count = 0; count < bufcnt; count++, dma_buff++) { + free(dma_buff->dma_desc, M_MPI3MR); + } + free(dma_buffers, M_MPI3MR); + } + if (mpirepbuf) + free(mpirepbuf, M_MPI3MR); + return rval; +} + +/** + * mpi3mr_soft_reset_from_app - Trigger controller reset + * @sc: Adapter instance reference + * + * This function triggers the controller reset from the + * watchdog context and wait for it to complete. It will + * come out of wait upon completion or timeout exaustion. + * + * Return: 0 on success and proper error codes on failure + */ +static long +mpi3mr_soft_reset_from_app(struct mpi3mr_softc *sc) +{ + + U32 timeout; + + /* if reset is not in progress, trigger soft reset from watchdog context */ + if (!sc->reset_in_progress) { + sc->reset.type = MPI3MR_TRIGGER_SOFT_RESET; + sc->reset.reason = MPI3MR_RESET_FROM_IOCTL; + + /* Wait for soft reset to start */ + timeout = 50; + while (timeout--) { + if (sc->reset_in_progress == 1) + break; + DELAY(100 * 1000); + } + if (!timeout) + return EFAULT; + } + + /* Wait for soft reset to complete */ + int i = 0; + timeout = sc->ready_timeout; + while (timeout--) { + if (sc->reset_in_progress == 0) + break; + i++; + if (!(i % 5)) { + mpi3mr_dprint(sc, MPI3MR_INFO, + "[%2ds]waiting for controller reset to be finished from %s\n", i, __func__); + } + DELAY(1000 * 1000); + } + + /* + * In case of soft reset failure or not completed within stipulated time, + * fail back to application. + */ + if ((!timeout || sc->reset.status)) + return EFAULT; + + return 0; +} + + +/** + * mpi3mr_adp_reset - Issue controller reset + * @sc: Adapter instance reference + * @data_out_buf: User buffer with reset type + * @data_out_sz: length of the user buffer. + * + * This function identifies the user provided reset type and + * issues approporiate reset to the controller and wait for that + * to complete and reinitialize the controller and then returns. + * + * Return: 0 on success and proper error codes on failure + */ +static long +mpi3mr_adp_reset(struct mpi3mr_softc *sc, + void *data_out_buf, U32 data_out_sz) +{ + long rval = EINVAL; + struct mpi3mr_ioctl_adpreset adpreset; + + memset(&adpreset, 0, sizeof(adpreset)); + + if (data_out_sz != sizeof(adpreset)) { + printf(IOCNAME "Invalid user adpreset buffer size %s() line: %d\n", sc->name, + __func__, __LINE__); + goto out; + } + + if (copyin(data_out_buf, &adpreset, sizeof(adpreset))) { + printf(IOCNAME "failure at %s() line:%d\n", sc->name, + __func__, __LINE__); + rval = EFAULT; + goto out; + } + + switch (adpreset.reset_type) { + case MPI3MR_IOCTL_ADPRESET_SOFT: + sc->reset.ioctl_reset_snapdump = false; + break; + case MPI3MR_IOCTL_ADPRESET_DIAG_FAULT: + sc->reset.ioctl_reset_snapdump = true; + break; + default: + printf(IOCNAME "Unknown reset_type(0x%x) issued\n", sc->name, + adpreset.reset_type); + goto out; + } + rval = mpi3mr_soft_reset_from_app(sc); + if (rval) + printf(IOCNAME "reset handler returned error (0x%lx) for reset type 0x%x\n", + sc->name, rval, adpreset.reset_type); + +out: + return rval; +} + +void +mpi3mr_app_send_aen(struct mpi3mr_softc *sc) +{ + sc->mpi3mr_aen_triggered = 1; + if (sc->mpi3mr_poll_waiting) { + selwakeup(&sc->mpi3mr_select); + sc->mpi3mr_poll_waiting = 0; + } + return; +} + +void +mpi3mr_pel_wait_complete(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *drvr_cmd) +{ + U8 retry = 0; + Mpi3PELReply_t *pel_reply = NULL; + mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); + + if (drvr_cmd->state & MPI3MR_CMD_RESET) + goto cleanup_drvrcmd; + + if (!(drvr_cmd->state & MPI3MR_CMD_REPLYVALID)) { + printf(IOCNAME "%s: PELGetSeqNum Failed, No Reply\n", sc->name, __func__); + goto out_failed; + } + pel_reply = (Mpi3PELReply_t *)drvr_cmd->reply; + + if (((GET_IOC_STATUS(drvr_cmd->ioc_status)) != MPI3_IOCSTATUS_SUCCESS) + || ((le16toh(pel_reply->PELogStatus) != MPI3_PEL_STATUS_SUCCESS) + && (le16toh(pel_reply->PELogStatus) != MPI3_PEL_STATUS_ABORTED))){ + printf(IOCNAME "%s: PELGetSeqNum Failed, IOCStatus(0x%04x) Loginfo(0x%08x) PEL_LogStatus(0x%04x)\n", + sc->name, __func__, GET_IOC_STATUS(drvr_cmd->ioc_status), + drvr_cmd->ioc_loginfo, le16toh(pel_reply->PELogStatus)); + retry = 1; + } + + if (retry) { + if (drvr_cmd->retry_count < MPI3MR_PELCMDS_RETRYCOUNT) { + drvr_cmd->retry_count++; + printf(IOCNAME "%s : PELWaitretry=%d\n", sc->name, + __func__, drvr_cmd->retry_count); + mpi3mr_issue_pel_wait(sc, drvr_cmd); + return; + } + + printf(IOCNAME "%s :PELWait failed after all retries\n", sc->name, + __func__); + goto out_failed; + } + + mpi3mr_app_send_aen(sc); + + if (!sc->pel_abort_requested) { + sc->pel_cmds.retry_count = 0; + mpi3mr_send_pel_getseq(sc, &sc->pel_cmds); + } + + return; +out_failed: + sc->pel_wait_pend = 0; +cleanup_drvrcmd: + drvr_cmd->state = MPI3MR_CMD_NOTUSED; + drvr_cmd->callback = NULL; + drvr_cmd->retry_count = 0; +} + +void +mpi3mr_issue_pel_wait(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *drvr_cmd) +{ + U8 retry_count = 0; + Mpi3PELReqActionWait_t pel_wait; + mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); + + sc->pel_abort_requested = 0; + + memset(&pel_wait, 0, sizeof(pel_wait)); + drvr_cmd->state = MPI3MR_CMD_PENDING; + drvr_cmd->is_waiting = 0; + drvr_cmd->callback = mpi3mr_pel_wait_complete; + drvr_cmd->ioc_status = 0; + drvr_cmd->ioc_loginfo = 0; + pel_wait.HostTag = htole16(MPI3MR_HOSTTAG_PELWAIT); + pel_wait.Function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; + pel_wait.Action = MPI3_PEL_ACTION_WAIT; + pel_wait.StartingSequenceNumber = htole32(sc->newest_seqnum); + pel_wait.Locale = htole16(sc->pel_locale); + pel_wait.Class = htole16(sc->pel_class); + pel_wait.WaitTime = MPI3_PEL_WAITTIME_INFINITE_WAIT; + printf(IOCNAME "Issuing PELWait: seqnum %u class %u locale 0x%08x\n", + sc->name, sc->newest_seqnum, sc->pel_class, sc->pel_locale); +retry_pel_wait: + if (mpi3mr_submit_admin_cmd(sc, &pel_wait, sizeof(pel_wait))) { + printf(IOCNAME "%s: Issue PELWait IOCTL: Admin Post failed\n", sc->name, __func__); + if (retry_count < MPI3MR_PELCMDS_RETRYCOUNT) { + retry_count++; + goto retry_pel_wait; + } + goto out_failed; + } + return; +out_failed: + drvr_cmd->state = MPI3MR_CMD_NOTUSED; + drvr_cmd->callback = NULL; + drvr_cmd->retry_count = 0; + sc->pel_wait_pend = 0; + return; +} + +void +mpi3mr_send_pel_getseq(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *drvr_cmd) +{ + U8 retry_count = 0; + U8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; + Mpi3PELReqActionGetSequenceNumbers_t pel_getseq_req; + + memset(&pel_getseq_req, 0, sizeof(pel_getseq_req)); + sc->pel_cmds.state = MPI3MR_CMD_PENDING; + sc->pel_cmds.is_waiting = 0; + sc->pel_cmds.ioc_status = 0; + sc->pel_cmds.ioc_loginfo = 0; + sc->pel_cmds.callback = mpi3mr_pel_getseq_complete; + pel_getseq_req.HostTag = htole16(MPI3MR_HOSTTAG_PELWAIT); + pel_getseq_req.Function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; + pel_getseq_req.Action = MPI3_PEL_ACTION_GET_SEQNUM; + mpi3mr_add_sg_single(&pel_getseq_req.SGL, sgl_flags, + sc->pel_seq_number_sz, sc->pel_seq_number_dma); + +retry_pel_getseq: + if (mpi3mr_submit_admin_cmd(sc, &pel_getseq_req, sizeof(pel_getseq_req))) { + printf(IOCNAME "%s: Issuing PEL GetSeq IOCTL: Admin Post failed\n", sc->name, __func__); + if (retry_count < MPI3MR_PELCMDS_RETRYCOUNT) { + retry_count++; + goto retry_pel_getseq; + } + goto out_failed; + } + return; +out_failed: + drvr_cmd->state = MPI3MR_CMD_NOTUSED; + drvr_cmd->callback = NULL; + drvr_cmd->retry_count = 0; + sc->pel_wait_pend = 0; +} + +void +mpi3mr_pel_getseq_complete(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *drvr_cmd) +{ + U8 retry = 0; + Mpi3PELReply_t *pel_reply = NULL; + Mpi3PELSeq_t *pel_seq_num = (Mpi3PELSeq_t *)sc->pel_seq_number; + mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); + + if (drvr_cmd->state & MPI3MR_CMD_RESET) + goto cleanup_drvrcmd; + + if (!(drvr_cmd->state & MPI3MR_CMD_REPLYVALID)) { + printf(IOCNAME "%s: PELGetSeqNum Failed, No Reply\n", sc->name, __func__); + goto out_failed; + } + pel_reply = (Mpi3PELReply_t *)drvr_cmd->reply; + + if (((GET_IOC_STATUS(drvr_cmd->ioc_status)) != MPI3_IOCSTATUS_SUCCESS) + || (le16toh(pel_reply->PELogStatus) != MPI3_PEL_STATUS_SUCCESS)){ + printf(IOCNAME "%s: PELGetSeqNum Failed, IOCStatus(0x%04x) Loginfo(0x%08x) PEL_LogStatus(0x%04x)\n", + sc->name, __func__, GET_IOC_STATUS(drvr_cmd->ioc_status), + drvr_cmd->ioc_loginfo, le16toh(pel_reply->PELogStatus)); + retry = 1; + } + + if (retry) { + if (drvr_cmd->retry_count < MPI3MR_PELCMDS_RETRYCOUNT) { + drvr_cmd->retry_count++; + printf(IOCNAME "%s : PELGetSeqNUM retry=%d\n", sc->name, + __func__, drvr_cmd->retry_count); + mpi3mr_send_pel_getseq(sc, drvr_cmd); + return; + } + printf(IOCNAME "%s :PELGetSeqNUM failed after all retries\n", + sc->name, __func__); + goto out_failed; + } + + sc->newest_seqnum = le32toh(pel_seq_num->Newest) + 1; + drvr_cmd->retry_count = 0; + mpi3mr_issue_pel_wait(sc, drvr_cmd); + return; +out_failed: + sc->pel_wait_pend = 0; +cleanup_drvrcmd: + drvr_cmd->state = MPI3MR_CMD_NOTUSED; + drvr_cmd->callback = NULL; + drvr_cmd->retry_count = 0; +} + +static int +mpi3mr_pel_getseq(struct mpi3mr_softc *sc) +{ + int rval = 0; + U8 sgl_flags = 0; + Mpi3PELReqActionGetSequenceNumbers_t pel_getseq_req; + mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); + + if (sc->reset_in_progress || sc->block_ioctls) { + printf(IOCNAME "%s: IOCTL failed: reset in progress: %u ioctls blocked: %u\n", + sc->name, __func__, sc->reset_in_progress, sc->block_ioctls); + return -1; + } + + memset(&pel_getseq_req, 0, sizeof(pel_getseq_req)); + sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; + sc->pel_cmds.state = MPI3MR_CMD_PENDING; + sc->pel_cmds.is_waiting = 0; + sc->pel_cmds.retry_count = 0; + sc->pel_cmds.ioc_status = 0; + sc->pel_cmds.ioc_loginfo = 0; + sc->pel_cmds.callback = mpi3mr_pel_getseq_complete; + pel_getseq_req.HostTag = htole16(MPI3MR_HOSTTAG_PELWAIT); + pel_getseq_req.Function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; + pel_getseq_req.Action = MPI3_PEL_ACTION_GET_SEQNUM; + mpi3mr_add_sg_single(&pel_getseq_req.SGL, sgl_flags, + sc->pel_seq_number_sz, sc->pel_seq_number_dma); + + if ((rval = mpi3mr_submit_admin_cmd(sc, &pel_getseq_req, sizeof(pel_getseq_req)))) + printf(IOCNAME "%s: Issue IOCTL: Admin Post failed\n", sc->name, __func__); + + return rval; +} + +int +mpi3mr_pel_abort(struct mpi3mr_softc *sc) +{ + int retval = 0; + U16 pel_log_status; + Mpi3PELReqActionAbort_t pel_abort_req; + Mpi3PELReply_t *pel_reply = NULL; + + if (sc->reset_in_progress || sc->block_ioctls) { + printf(IOCNAME "%s: IOCTL failed: reset in progress: %u ioctls blocked: %u\n", + sc->name, __func__, sc->reset_in_progress, sc->block_ioctls); + return -1; + } + + memset(&pel_abort_req, 0, sizeof(pel_abort_req)); + + mtx_lock(&sc->pel_abort_cmd.completion.lock); + if (sc->pel_abort_cmd.state & MPI3MR_CMD_PENDING) { + printf(IOCNAME "%s: PEL Abort command is in use\n", sc->name, __func__); + mtx_unlock(&sc->pel_abort_cmd.completion.lock); + return -1; + } + + sc->pel_abort_cmd.state = MPI3MR_CMD_PENDING; + sc->pel_abort_cmd.is_waiting = 1; + sc->pel_abort_cmd.callback = NULL; + pel_abort_req.HostTag = htole16(MPI3MR_HOSTTAG_PELABORT); + pel_abort_req.Function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; + pel_abort_req.Action = MPI3_PEL_ACTION_ABORT; + pel_abort_req.AbortHostTag = htole16(MPI3MR_HOSTTAG_PELWAIT); + + sc->pel_abort_requested = 1; + + init_completion(&sc->pel_abort_cmd.completion); + retval = mpi3mr_submit_admin_cmd(sc, &pel_abort_req, sizeof(pel_abort_req)); + if (retval) { + printf(IOCNAME "%s: Issue IOCTL: Admin Post failed\n", sc->name, __func__); + sc->pel_abort_requested = 0; + retval = -1; + goto out_unlock; + } + wait_for_completion_timeout(&sc->pel_abort_cmd.completion, MPI3MR_INTADMCMD_TIMEOUT); + + if (!(sc->pel_abort_cmd.state & MPI3MR_CMD_COMPLETE)) { + printf(IOCNAME "%s: PEL Abort command timedout\n",sc->name, __func__); + sc->pel_abort_cmd.is_waiting = 0; + retval = -1; + sc->reset.type = MPI3MR_TRIGGER_SOFT_RESET; + sc->reset.reason = MPI3MR_RESET_FROM_PELABORT_TIMEOUT; + goto out_unlock; + } + if (((GET_IOC_STATUS(sc->pel_abort_cmd.ioc_status)) != MPI3_IOCSTATUS_SUCCESS) + || (!(sc->pel_abort_cmd.state & MPI3MR_CMD_REPLYVALID))) { + printf(IOCNAME "%s: PEL Abort command failed, ioc_status(0x%04x) log_info(0x%08x)\n", + sc->name, __func__, GET_IOC_STATUS(sc->pel_abort_cmd.ioc_status), + sc->pel_abort_cmd.ioc_loginfo); + retval = -1; + goto out_unlock; + } + + pel_reply = (Mpi3PELReply_t *)sc->pel_abort_cmd.reply; + pel_log_status = le16toh(pel_reply->PELogStatus); + if (pel_log_status != MPI3_PEL_STATUS_SUCCESS) { + printf(IOCNAME "%s: PEL abort command failed, pel_status(0x%04x)\n", + sc->name, __func__, pel_log_status); + retval = -1; + } + +out_unlock: + mtx_unlock(&sc->pel_abort_cmd.completion.lock); + sc->pel_abort_cmd.state = MPI3MR_CMD_NOTUSED; + return retval; +} + +/** + * mpi3mr_pel_enable - Handler for PEL enable + * @sc: Adapter instance reference + * @data_out_buf: User buffer containing PEL enable data + * @data_out_sz: length of the user buffer. + * + * This function is the handler for PEL enable driver IOCTL. + * Validates the application given class and locale and if + * requires aborts the existing PEL wait request and/or issues + * new PEL wait request to the firmware and returns. + * + * Return: 0 on success and proper error codes on failure. + */ +static long +mpi3mr_pel_enable(struct mpi3mr_softc *sc, + void *data_out_buf, U32 data_out_sz) +{ + long rval = EINVAL; + U8 tmp_class; + U16 tmp_locale; + struct mpi3mr_ioctl_pel_enable pel_enable; + mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); + + + if ((data_out_sz != sizeof(pel_enable) || + (pel_enable.pel_class > MPI3_PEL_CLASS_FAULT))) { + printf(IOCNAME "%s: Invalid user pel_enable buffer size %u\n", + sc->name, __func__, data_out_sz); + goto out; + } + memset(&pel_enable, 0, sizeof(pel_enable)); + if (copyin(data_out_buf, &pel_enable, sizeof(pel_enable))) { + printf(IOCNAME "failure at %s() line:%d\n", sc->name, + __func__, __LINE__); + rval = EFAULT; + goto out; + } + if (pel_enable.pel_class > MPI3_PEL_CLASS_FAULT) { + printf(IOCNAME "%s: out of range class %d\n", + sc->name, __func__, pel_enable.pel_class); + goto out; + } + + if (sc->pel_wait_pend) { + if ((sc->pel_class <= pel_enable.pel_class) && + !((sc->pel_locale & pel_enable.pel_locale) ^ + pel_enable.pel_locale)) { + rval = 0; + goto out; + } else { + pel_enable.pel_locale |= sc->pel_locale; + if (sc->pel_class < pel_enable.pel_class) + pel_enable.pel_class = sc->pel_class; + + if (mpi3mr_pel_abort(sc)) { + printf(IOCNAME "%s: pel_abort failed, status(%ld)\n", + sc->name, __func__, rval); + goto out; + } + } + } + + tmp_class = sc->pel_class; + tmp_locale = sc->pel_locale; + sc->pel_class = pel_enable.pel_class; + sc->pel_locale = pel_enable.pel_locale; + sc->pel_wait_pend = 1; + + if ((rval = mpi3mr_pel_getseq(sc))) { + sc->pel_class = tmp_class; + sc->pel_locale = tmp_locale; + sc->pel_wait_pend = 0; + printf(IOCNAME "%s: pel get sequence number failed, status(%ld)\n", + sc->name, __func__, rval); + } + +out: + return rval; +} + +void +mpi3mr_app_save_logdata(struct mpi3mr_softc *sc, char *event_data, + U16 event_data_size) +{ + struct mpi3mr_log_data_entry *entry; + U32 index = sc->log_data_buffer_index, sz; + + if (!(sc->log_data_buffer)) + return; + + entry = (struct mpi3mr_log_data_entry *) + (sc->log_data_buffer + (index * sc->log_data_entry_size)); + entry->valid_entry = 1; + sz = min(sc->log_data_entry_size, event_data_size); + memcpy(entry->data, event_data, sz); + sc->log_data_buffer_index = + ((++index) % MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES); + mpi3mr_app_send_aen(sc); +} + +/** + * mpi3mr_get_logdata - Handler for get log data + * @sc: Adapter instance reference + * @data_in_buf: User buffer to copy the logdata entries + * @data_in_sz: length of the user buffer. + * + * This function copies the log data entries to the user buffer + * when log caching is enabled in the driver. + * + * Return: 0 on success and proper error codes on failure + */ +static long +mpi3mr_get_logdata(struct mpi3mr_softc *sc, + void *data_in_buf, U32 data_in_sz) +{ + long rval = EINVAL; + U16 num_entries = 0; + U16 entry_sz = sc->log_data_entry_size; + + if ((!sc->log_data_buffer) || (data_in_sz < entry_sz)) + return rval; + + num_entries = data_in_sz / entry_sz; + if (num_entries > MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES) + num_entries = MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES; + + if ((rval = copyout(sc->log_data_buffer, data_in_buf, (num_entries * entry_sz)))) { + printf(IOCNAME "%s: copy to user failed\n", sc->name, __func__); + rval = EFAULT; + } + + return rval; +} + +/** + * mpi3mr_logdata_enable - Handler for log data enable + * @sc: Adapter instance reference + * @data_in_buf: User buffer to copy the max logdata entry count + * @data_in_sz: length of the user buffer. + * + * This function enables log data caching in the driver if not + * already enabled and return the maximum number of log data + * entries that can be cached in the driver. + * + * Return: 0 on success and proper error codes on failure + */ +static long +mpi3mr_logdata_enable(struct mpi3mr_softc *sc, + void *data_in_buf, U32 data_in_sz) +{ + long rval = EINVAL; + struct mpi3mr_ioctl_logdata_enable logdata_enable; + + if (data_in_sz < sizeof(logdata_enable)) + return rval; + + if (sc->log_data_buffer) + goto copy_data; + + sc->log_data_entry_size = (sc->reply_sz - (sizeof(Mpi3EventNotificationReply_t) - 4)) + + MPI3MR_IOCTL_LOGDATA_ENTRY_HEADER_SZ; + + sc->log_data_buffer = malloc((MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES * sc->log_data_entry_size), + M_MPI3MR, M_NOWAIT | M_ZERO); + if (!sc->log_data_buffer) { + printf(IOCNAME "%s log data buffer memory allocation failed\n", sc->name, __func__); + return ENOMEM; + } + + sc->log_data_buffer_index = 0; + +copy_data: + memset(&logdata_enable, 0, sizeof(logdata_enable)); + logdata_enable.max_entries = MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES; + + if ((rval = copyout(&logdata_enable, data_in_buf, sizeof(logdata_enable)))) { + printf(IOCNAME "%s: copy to user failed\n", sc->name, __func__); + rval = EFAULT; + } + + return rval; +} + +/** + * mpi3mr_get_change_count - Get topology change count + * @sc: Adapter instance reference + * @data_in_buf: User buffer to copy the change count + * @data_in_sz: length of the user buffer. + * + * This function copies the toplogy change count provided by the + * driver in events and cached in the driver to the user + * provided buffer for the specific controller. + * + * Return: 0 on success and proper error codes on failure + */ +static long +mpi3mr_get_change_count(struct mpi3mr_softc *sc, + void *data_in_buf, U32 data_in_sz) +{ + long rval = EINVAL; + struct mpi3mr_ioctl_chgcnt chg_count; + memset(&chg_count, 0, sizeof(chg_count)); + + chg_count.change_count = sc->change_count; + if (data_in_sz >= sizeof(chg_count)) { + if ((rval = copyout(&chg_count, data_in_buf, sizeof(chg_count)))) { + printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, __FILE__, + __LINE__, __func__); + rval = EFAULT; + } + } + return rval; +} + +/** + * mpi3mr_get_alltgtinfo - Get all targets information + * @sc: Adapter instance reference + * @data_in_buf: User buffer to copy the target information + * @data_in_sz: length of the user buffer. + * + * This function copies the driver managed target devices device + * handle, persistent ID, bus ID and taret ID to the user + * provided buffer for the specific controller. This function + * also provides the number of devices managed by the driver for + * the specific controller. + * + * Return: 0 on success and proper error codes on failure + */ +static long +mpi3mr_get_alltgtinfo(struct mpi3mr_softc *sc, + void *data_in_buf, U32 data_in_sz) +{ + long rval = EINVAL; + U8 get_count = 0; + U16 i = 0, num_devices = 0; + U32 min_entrylen = 0, kern_entrylen = 0, user_entrylen = 0; + struct mpi3mr_target *tgtdev = NULL; + struct mpi3mr_device_map_info *devmap_info = NULL; + struct mpi3mr_cam_softc *cam_sc = sc->cam_sc; + struct mpi3mr_ioctl_all_tgtinfo *all_tgtinfo = (struct mpi3mr_ioctl_all_tgtinfo *)data_in_buf; + + if (data_in_sz < sizeof(uint32_t)) { + printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, __FILE__, + __LINE__, __func__); + goto out; + } + if (data_in_sz == sizeof(uint32_t)) + get_count = 1; + + if (TAILQ_EMPTY(&cam_sc->tgt_list)) { + get_count = 1; + goto copy_usrbuf; + } + + mtx_lock_spin(&cam_sc->sc->target_lock); + TAILQ_FOREACH(tgtdev, &cam_sc->tgt_list, tgt_next) { + num_devices++; + } + mtx_unlock_spin(&cam_sc->sc->target_lock); + + if (get_count) + goto copy_usrbuf; + + kern_entrylen = num_devices * sizeof(*devmap_info); + + devmap_info = malloc(kern_entrylen, M_MPI3MR, M_NOWAIT | M_ZERO); + if (!devmap_info) { + printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, __FILE__, + __LINE__, __func__); + rval = ENOMEM; + goto out; + } + memset((U8*)devmap_info, 0xFF, kern_entrylen); + + mtx_lock_spin(&cam_sc->sc->target_lock); + TAILQ_FOREACH(tgtdev, &cam_sc->tgt_list, tgt_next) { + if (i < num_devices) { + devmap_info[i].handle = tgtdev->dev_handle; + devmap_info[i].per_id = tgtdev->per_id; + /*n + * For hidden/ugood device the target_id and bus_id should be 0xFFFFFFFF and 0xFF + */ + if (!tgtdev->exposed_to_os) { + devmap_info[i].target_id = 0xFFFFFFFF; + devmap_info[i].bus_id = 0xFF; + } else { + devmap_info[i].target_id = tgtdev->tid; + devmap_info[i].bus_id = 0; + } + i++; + } + } + num_devices = i; + mtx_unlock_spin(&cam_sc->sc->target_lock); + +copy_usrbuf: + if (copyout(&num_devices, &all_tgtinfo->num_devices, sizeof(num_devices))) { + printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, __FILE__, + __LINE__, __func__); + rval = EFAULT; + goto out; + } + user_entrylen = (data_in_sz - sizeof(uint32_t))/sizeof(*devmap_info); + user_entrylen *= sizeof(*devmap_info); + min_entrylen = min(user_entrylen, kern_entrylen); + if (min_entrylen && (copyout(devmap_info, &all_tgtinfo->dmi, min_entrylen))) { + printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, + __FILE__, __LINE__, __func__); + rval = EFAULT; + goto out; + } + rval = 0; +out: + if (devmap_info) + free(devmap_info, M_MPI3MR); + + return rval; +} + +/** + * mpi3mr_get_tgtinfo - Get specific target information + * @sc: Adapter instance reference + * @karg: driver ponter to users payload buffer + * + * This function copies the driver managed specific target device + * info like handle, persistent ID, bus ID and taret ID to the user + * provided buffer for the specific controller. + * + * Return: 0 on success and proper error codes on failure + */ +static long +mpi3mr_get_tgtinfo(struct mpi3mr_softc *sc, + struct mpi3mr_ioctl_drvcmd *karg) +{ + long rval = EINVAL; + struct mpi3mr_target *tgtdev = NULL; + struct mpi3mr_ioctl_tgtinfo tgtinfo; + + memset(&tgtinfo, 0, sizeof(tgtinfo)); + + if ((karg->data_out_size != sizeof(struct mpi3mr_ioctl_tgtinfo)) || + (karg->data_in_size != sizeof(struct mpi3mr_ioctl_tgtinfo))) { + printf(IOCNAME "Invalid user tgtinfo buffer size %s() line: %d\n", sc->name, + __func__, __LINE__); + goto out; + } + + if (copyin(karg->data_out_buf, &tgtinfo, sizeof(tgtinfo))) { + printf(IOCNAME "failure at %s() line:%d\n", sc->name, + __func__, __LINE__); + rval = EFAULT; + goto out; + } + + if ((tgtinfo.bus_id != 0xFF) && (tgtinfo.target_id != 0xFFFFFFFF)) { + if ((tgtinfo.persistent_id != 0xFFFF) || + (tgtinfo.dev_handle != 0xFFFF)) + goto out; + tgtdev = mpi3mr_find_target_by_per_id(sc->cam_sc, tgtinfo.target_id); + } else if (tgtinfo.persistent_id != 0xFFFF) { + if ((tgtinfo.bus_id != 0xFF) || + (tgtinfo.dev_handle !=0xFFFF) || + (tgtinfo.target_id != 0xFFFFFFFF)) + goto out; + tgtdev = mpi3mr_find_target_by_per_id(sc->cam_sc, tgtinfo.persistent_id); + } else if (tgtinfo.dev_handle !=0xFFFF) { + if ((tgtinfo.bus_id != 0xFF) || + (tgtinfo.target_id != 0xFFFFFFFF) || + (tgtinfo.persistent_id != 0xFFFF)) + goto out; + tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, tgtinfo.dev_handle); + } + if (!tgtdev) + goto out; + + tgtinfo.target_id = tgtdev->per_id; + tgtinfo.bus_id = 0; + tgtinfo.dev_handle = tgtdev->dev_handle; + tgtinfo.persistent_id = tgtdev->per_id; + tgtinfo.seq_num = 0; + + if (copyout(&tgtinfo, karg->data_in_buf, sizeof(tgtinfo))) { + printf(IOCNAME "failure at %s() line:%d\n", sc->name, + __func__, __LINE__); + rval = EFAULT; + } + +out: + return rval; +} + +/** + * mpi3mr_get_pciinfo - Get PCI info IOCTL handler + * @sc: Adapter instance reference + * @data_in_buf: User buffer to hold adapter information + * @data_in_sz: length of the user buffer. + * + * This function provides the PCI spec information for the + * given controller + * + * Return: 0 on success and proper error codes on failure + */ +static long +mpi3mr_get_pciinfo(struct mpi3mr_softc *sc, + void *data_in_buf, U32 data_in_sz) +{ + long rval = EINVAL; + U8 i; + struct mpi3mr_ioctl_pciinfo pciinfo; + memset(&pciinfo, 0, sizeof(pciinfo)); + + for (i = 0; i < 64; i++) + pciinfo.config_space[i] = pci_read_config(sc->mpi3mr_dev, (i * 4), 4); + + if (data_in_sz >= sizeof(pciinfo)) { + if ((rval = copyout(&pciinfo, data_in_buf, sizeof(pciinfo)))) { + printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, + __FILE__, __LINE__, __func__); + rval = EFAULT; + } + } + return rval; +} + +/** + * mpi3mr_get_adpinfo - Get adapter info IOCTL handler + * @sc: Adapter instance reference + * @data_in_buf: User buffer to hold adapter information + * @data_in_sz: length of the user buffer. + * + * This function provides adapter information for the given + * controller + * + * Return: 0 on success and proper error codes on failure + */ +static long +mpi3mr_get_adpinfo(struct mpi3mr_softc *sc, + void *data_in_buf, U32 data_in_sz) +{ + long rval = EINVAL; + struct mpi3mr_ioctl_adpinfo adpinfo; + enum mpi3mr_iocstate ioc_state; + memset(&adpinfo, 0, sizeof(adpinfo)); + + adpinfo.adp_type = MPI3MR_IOCTL_ADPTYPE_AVGFAMILY; + adpinfo.pci_dev_id = pci_get_device(sc->mpi3mr_dev); + adpinfo.pci_dev_hw_rev = pci_read_config(sc->mpi3mr_dev, PCIR_REVID, 1); + adpinfo.pci_subsys_dev_id = pci_get_subdevice(sc->mpi3mr_dev); + adpinfo.pci_subsys_ven_id = pci_get_subvendor(sc->mpi3mr_dev); + adpinfo.pci_bus = pci_get_bus(sc->mpi3mr_dev);; + adpinfo.pci_dev = pci_get_slot(sc->mpi3mr_dev); + adpinfo.pci_func = pci_get_function(sc->mpi3mr_dev); + adpinfo.pci_seg_id = pci_get_domain(sc->mpi3mr_dev); + adpinfo.ioctl_ver = MPI3MR_IOCTL_VERSION; + memcpy((U8 *)&adpinfo.driver_info, (U8 *)&sc->driver_info, sizeof(adpinfo.driver_info)); + + ioc_state = mpi3mr_get_iocstate(sc); + + if (ioc_state == MRIOC_STATE_UNRECOVERABLE) + adpinfo.adp_state = MPI3MR_IOCTL_ADP_STATE_UNRECOVERABLE; + else if (sc->reset_in_progress || sc->block_ioctls) + adpinfo.adp_state = MPI3MR_IOCTL_ADP_STATE_IN_RESET; + else if (ioc_state == MRIOC_STATE_FAULT) + adpinfo.adp_state = MPI3MR_IOCTL_ADP_STATE_FAULT; + else + adpinfo.adp_state = MPI3MR_IOCTL_ADP_STATE_OPERATIONAL; + + if (data_in_sz >= sizeof(adpinfo)) { + if ((rval = copyout(&adpinfo, data_in_buf, sizeof(adpinfo)))) { + printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, + __FILE__, __LINE__, __func__); + rval = EFAULT; + } + } + return rval; +} +/** + * mpi3mr_app_drvrcmds - Driver IOCTL handler + * @dev: char device + * @cmd: IOCTL command + * @arg: User data payload buffer for the IOCTL + * @flag: flags + * @thread: threads + * + * This function is the top level handler for driver commands, + * this does basic validation of the buffer and identifies the + * opcode and switches to correct sub handler. + * + * Return: 0 on success and proper error codes on failure + */ + +static int +mpi3mr_app_drvrcmds(struct cdev *dev, u_long cmd, + void *uarg, int flag, struct thread *td) +{ + long rval = EINVAL; + struct mpi3mr_softc *sc = NULL; + struct mpi3mr_ioctl_drvcmd *karg = (struct mpi3mr_ioctl_drvcmd *)uarg; + + sc = mpi3mr_app_get_adp_instance(karg->mrioc_id); + if (!sc) + return ENODEV; + + mtx_lock(&sc->ioctl_cmds.completion.lock); + switch (karg->opcode) { + case MPI3MR_DRVRIOCTL_OPCODE_ADPINFO: + rval = mpi3mr_get_adpinfo(sc, karg->data_in_buf, karg->data_in_size); + break; + case MPI3MR_DRVRIOCTL_OPCODE_GETPCIINFO: + rval = mpi3mr_get_pciinfo(sc, karg->data_in_buf, karg->data_in_size); + break; + case MPI3MR_DRVRIOCTL_OPCODE_TGTDEVINFO: + rval = mpi3mr_get_tgtinfo(sc, karg); + break; + case MPI3MR_DRVRIOCTL_OPCODE_ALLTGTDEVINFO: + rval = mpi3mr_get_alltgtinfo(sc, karg->data_in_buf, karg->data_in_size); + break; + case MPI3MR_DRVRIOCTL_OPCODE_GETCHGCNT: + rval = mpi3mr_get_change_count(sc, karg->data_in_buf, karg->data_in_size); + break; + case MPI3MR_DRVRIOCTL_OPCODE_LOGDATAENABLE: + rval = mpi3mr_logdata_enable(sc, karg->data_in_buf, karg->data_in_size); + break; + case MPI3MR_DRVRIOCTL_OPCODE_GETLOGDATA: + rval = mpi3mr_get_logdata(sc, karg->data_in_buf, karg->data_in_size); + break; + case MPI3MR_DRVRIOCTL_OPCODE_PELENABLE: + rval = mpi3mr_pel_enable(sc, karg->data_out_buf, karg->data_out_size); + break; + case MPI3MR_DRVRIOCTL_OPCODE_ADPRESET: + rval = mpi3mr_adp_reset(sc, karg->data_out_buf, karg->data_out_size); + break; + case MPI3MR_DRVRIOCTL_OPCODE_UNKNOWN: + default: + printf("Unsupported drvr ioctl opcode 0x%x\n", karg->opcode); + break; + } + mtx_unlock(&sc->ioctl_cmds.completion.lock); + return rval; +} +/** + * mpi3mr_ioctl - IOCTL Handler + * @dev: char device + * @cmd: IOCTL command + * @arg: User data payload buffer for the IOCTL + * @flag: flags + * @thread: threads + * + * This is the IOCTL entry point which checks the command type and + * executes proper sub handler specific for the command. + * + * Return: 0 on success and proper error codes on failure + */ +static int +mpi3mr_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) +{ + int rval = EINVAL; + + struct mpi3mr_softc *sc = NULL; + struct mpi3mr_ioctl_drvcmd *karg = (struct mpi3mr_ioctl_drvcmd *)arg; + + sc = mpi3mr_app_get_adp_instance(karg->mrioc_id); + + if (!sc) + return ENODEV; + + mpi3mr_atomic_inc(&sc->pend_ioctls); + + + if (sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN) { + mpi3mr_dprint(sc, MPI3MR_INFO, + "Return back IOCTL, shutdown is in progress\n"); + mpi3mr_atomic_dec(&sc->pend_ioctls); + return ENODEV; + } + + switch (cmd) { + case MPI3MRDRVCMD: + rval = mpi3mr_app_drvrcmds(dev, cmd, arg, flag, td); + break; + case MPI3MRMPTCMD: + mtx_lock(&sc->ioctl_cmds.completion.lock); + rval = mpi3mr_app_mptcmds(dev, cmd, arg, flag, td); + mtx_unlock(&sc->ioctl_cmds.completion.lock); + break; + default: + printf("%s:Unsupported ioctl cmd (0x%08lx)\n", MPI3MR_DRIVER_NAME, cmd); + break; + } + + mpi3mr_atomic_dec(&sc->pend_ioctls); + + return rval; +} diff --git a/sys/dev/mpi3mr/mpi3mr_app.h b/sys/dev/mpi3mr/mpi3mr_app.h new file mode 100644 index 000000000000..fa52db051003 --- /dev/null +++ b/sys/dev/mpi3mr/mpi3mr_app.h @@ -0,0 +1,292 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2020-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Authors: Sumit Saxena + * Chandrakanth Patil + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + */ + +#include "mpi3mr.h" + +#ifndef _MPI3MR_APP_H_ +#define _MPI3MR_APP_H_ + +#define MPI3MR_IOCTL_ADPTYPE_AVGFAMILY 1 +#define MPI3MR_IOCTL_VERSION 0x06 + +#define MPI3MRDRVCMD _IOWR('B', 1, struct mpi3mr_ioctl_drvcmd) +#define MPI3MRMPTCMD _IOWR('B', 2, struct mpi3mr_ioctl_mptcmd) + +#define MPI3MR_IOCTL_DEFAULT_TIMEOUT (10) +#define PEND_IOCTLS_COMP_WAIT_TIME (10) + +#define MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES 400 +#define MPI3MR_IOCTL_LOGDATA_ENTRY_HEADER_SZ 0x5 + +#define GET_IOC_STATUS(ioc_status) \ + ioc_status & MPI3_IOCSTATUS_STATUS_MASK + +/* Encapsulated NVMe command definitions */ +#define MPI3MR_NVME_PRP_SIZE 8 +#define MPI3MR_NVME_CMD_PRP1_OFFSET 24 +#define MPI3MR_NVME_CMD_PRP2_OFFSET 32 +#define MPI3MR_NVME_CMD_SGL_OFFSET 24 +#define MPI3MR_NVME_DATA_FORMAT_PRP 0 +#define MPI3MR_NVME_DATA_FORMAT_SGL1 1 +#define MPI3MR_NVME_DATA_FORMAT_SGL2 2 + +#define MPI3MR_NVMESGL_DATA_SEGMENT 0x00 +#define MPI3MR_NVMESGL_LAST_SEGMENT 0x03 + +int mpi3mr_app_attach(struct mpi3mr_softc *); +void mpi3mr_app_detach(struct mpi3mr_softc *); +static struct mpi3mr_mgmt_info mpi3mr_mgmt_info; + +enum mpi3mr_ioctl_adp_state { + MPI3MR_IOCTL_ADP_STATE_UNKNOWN = 0, + MPI3MR_IOCTL_ADP_STATE_OPERATIONAL = 1, + MPI3MR_IOCTL_ADP_STATE_FAULT = 2, + MPI3MR_IOCTL_ADP_STATE_IN_RESET = 3, + MPI3MR_IOCTL_ADP_STATE_UNRECOVERABLE = 4, +}; + +enum mpi3mr_ioctl_data_dir { + MPI3MR_APP_DDN, + MPI3MR_APP_DDI, + MPI3MR_APP_DDO, +}; + +enum mpi3mr_ioctl_drvcmds_opcode { + MPI3MR_DRVRIOCTL_OPCODE_UNKNOWN = 0, + MPI3MR_DRVRIOCTL_OPCODE_ADPINFO = 1, + MPI3MR_DRVRIOCTL_OPCODE_ADPRESET = 2, + MPI3MR_DRVRIOCTL_OPCODE_TGTDEVINFO = 3, + MPI3MR_DRVRIOCTL_OPCODE_ALLTGTDEVINFO = 4, + MPI3MR_DRVRIOCTL_OPCODE_GETCHGCNT = 5, + MPI3MR_DRVRIOCTL_OPCODE_LOGDATAENABLE = 6, + MPI3MR_DRVRIOCTL_OPCODE_PELENABLE = 7, + MPI3MR_DRVRIOCTL_OPCODE_GETLOGDATA = 8, + MPI3MR_DRVRIOCTL_OPCODE_GETPCIINFO = 100, +}; + +enum mpi3mr_ioctl_mpibuffer_type { + MPI3MR_IOCTL_BUFTYPE_UNKNOWN, + MPI3MR_IOCTL_BUFTYPE_RAIDMGMT_CMD, + MPI3MR_IOCTL_BUFTYPE_RAIDMGMT_RESP, + MPI3MR_IOCTL_BUFTYPE_DATA_IN, + MPI3MR_IOCTL_BUFTYPE_DATA_OUT, + MPI3MR_IOCTL_BUFTYPE_MPI_REPLY, + MPI3MR_IOCTL_BUFTYPE_ERR_RESPONSE, +}; + +enum mpi3mr_ioctl_mpireply_type { + MPI3MR_IOCTL_MPI_REPLY_BUFTYPE_UNKNOWN, + MPI3MR_IOCTL_MPI_REPLY_BUFTYPE_STATUS, + MPI3MR_IOCTL_MPI_REPLY_BUFTYPE_ADDRESS, +}; + +enum mpi3mr_ioctl_reset_type { + MPI3MR_IOCTL_ADPRESET_UNKNOWN, + MPI3MR_IOCTL_ADPRESET_SOFT, + MPI3MR_IOCTL_ADPRESET_DIAG_FAULT, +}; + +struct mpi3mr_ioctl_drvcmd { + U8 mrioc_id; + U8 opcode; + U16 rsvd1; + U32 rsvd2; + void *data_in_buf; + void *data_out_buf; + U32 data_in_size; + U32 data_out_size; +}; + +struct mpi3mr_ioctl_adpinfo { + U32 adp_type; + U32 rsvd1; + U32 pci_dev_id; + U32 pci_dev_hw_rev; + U32 pci_subsys_dev_id; + U32 pci_subsys_ven_id; + U32 pci_dev:5; + U32 pci_func:3; + U32 pci_bus:8; + U32 rsvd2:16; + U32 pci_seg_id; + U32 ioctl_ver; + U8 adp_state; + U8 rsvd3; + U16 rsvd4; + U32 rsvd5[2]; + Mpi3DriverInfoLayout_t driver_info; +}; + +struct mpi3mr_ioctl_pciinfo { + U32 config_space[64]; +}; + +struct mpi3mr_ioctl_tgtinfo { + U32 target_id; + U8 bus_id; + U8 rsvd1; + U16 rsvd2; + U16 dev_handle; + U16 persistent_id; + U32 seq_num; +}; + +struct mpi3mr_device_map_info { + U16 handle; + U16 per_id; + U32 target_id; + U8 bus_id; + U8 rsvd1; + U16 rsvd2; +}; + +struct mpi3mr_ioctl_all_tgtinfo { + U16 num_devices; + U16 rsvd1; + U32 rsvd2; + struct mpi3mr_device_map_info dmi[1]; +}; + +struct mpi3mr_ioctl_chgcnt { + U16 change_count; + U16 rsvd; +}; + +struct mpi3mr_ioctl_adpreset { + U8 reset_type; + U8 rsvd1; + U16 rsvd2; +}; + +struct mpi3mr_ioctl_mptcmd { + U8 mrioc_id; + U8 rsvd1; + U16 timeout; + U16 rsvd2; + U16 mpi_msg_size; + void *mpi_msg_buf; + void *buf_entry_list; + U32 buf_entry_list_size; +}; + +struct mpi3mr_buf_entry { + U8 buf_type; + U8 rsvd1; + U16 rsvd2; + U32 buf_len; + void *buffer; +}; + +struct mpi3mr_ioctl_buf_entry_list { + U8 num_of_buf_entries; + U8 rsvd1; + U16 rsvd2; + U32 rsvd3; + struct mpi3mr_buf_entry buf_entry[1]; +}; + +struct mpi3mr_ioctl_mpt_dma_buffer { + void *user_buf; + void *kern_buf; + U32 user_buf_len; + U32 kern_buf_len; + bus_addr_t kern_buf_dma; + bus_dma_tag_t kern_buf_dmatag; + bus_dmamap_t kern_buf_dmamap; + U8 data_dir; + U16 num_dma_desc; + struct dma_memory_desc *dma_desc; +}; + +struct mpi3mr_ioctl_mpirepbuf { + U8 mpirep_type; + U8 rsvd1; + U16 rsvd2; + U8 repbuf[1]; +}; + +struct mpi3mr_nvme_pt_sge { + U64 base_addr; + U32 length; + U16 rsvd; + U8 rsvd1; + U8 sub_type:4; + U8 type:4; +}; + +struct mpi3mr_log_data_entry { + U8 valid_entry; + U8 rsvd1; + U16 rsvd2; + U8 data[1]; +}; + +struct mpi3mr_ioctl_logdata_enable { + U16 max_entries; + U16 rsvd; +}; + +struct mpi3mr_ioctl_pel_enable { + U16 pel_locale; + U8 pel_class; + U8 rsvd; +}; + +int +mpi3mr_pel_abort(struct mpi3mr_softc *sc); +void +mpi3mr_pel_getseq_complete(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *drvr_cmd); +void +mpi3mr_issue_pel_wait(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *drvr_cmd); +void +mpi3mr_pel_wait_complete(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *drvr_cmd); +void +mpi3mr_send_pel_getseq(struct mpi3mr_softc *sc, + struct mpi3mr_drvr_cmd *drvr_cmd); +void +mpi3mr_app_send_aen(struct mpi3mr_softc *sc); + +#endif /* !_MPI3MR_API_H_ */ diff --git a/sys/dev/mpi3mr/mpi3mr_cam.c b/sys/dev/mpi3mr/mpi3mr_cam.c new file mode 100644 index 000000000000..245e4d9d3737 --- /dev/null +++ b/sys/dev/mpi3mr/mpi3mr_cam.c @@ -0,0 +1,2222 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2020-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Authors: Sumit Saxena + * Chandrakanth Patil + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "mpi/mpi30_api.h" +#include "mpi3mr_cam.h" +#include "mpi3mr.h" +#include /* XXX for pcpu.h */ +#include /* XXX for PCPU_GET */ + +#define smp_processor_id() PCPU_GET(cpuid) + +static int +mpi3mr_map_request(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cm); +void +mpi3mr_release_simq_reinit(struct mpi3mr_cam_softc *cam_sc); +static void +mpi3mr_freeup_events(struct mpi3mr_softc *sc); + +extern int +mpi3mr_register_events(struct mpi3mr_softc *sc); +extern void mpi3mr_add_sg_single(void *paddr, U8 flags, U32 length, + bus_addr_t dma_addr); +extern void mpi3mr_build_zero_len_sge(void *paddr); + +static U32 event_count; + +static void mpi3mr_prepare_sgls(void *arg, + bus_dma_segment_t *segs, int nsegs, int error) +{ + struct mpi3mr_softc *sc; + struct mpi3mr_cmd *cm; + u_int i; + bus_addr_t chain_dma; + void *chain; + U8 *sg_local; + U32 chain_length; + int sges_left; + U32 sges_in_segment; + U8 simple_sgl_flags; + U8 simple_sgl_flags_last; + U8 last_chain_sgl_flags; + struct mpi3mr_chain *chain_req; + Mpi3SCSIIORequest_t *scsiio_req; + + cm = (struct mpi3mr_cmd *)arg; + sc = cm->sc; + scsiio_req = (Mpi3SCSIIORequest_t *) &cm->io_request; + + if (error) { + cm->error_code = error; + device_printf(sc->mpi3mr_dev, "%s: error=%d\n",__func__, error); + if (error == EFBIG) { + cm->ccb->ccb_h.status = CAM_REQ_TOO_BIG; + return; + } + } + + if (cm->data_dir == MPI3MR_READ) + bus_dmamap_sync(sc->buffer_dmat, cm->dmamap, + BUS_DMASYNC_PREREAD); + if (cm->data_dir == MPI3MR_WRITE) + bus_dmamap_sync(sc->buffer_dmat, cm->dmamap, + BUS_DMASYNC_PREWRITE); + if (nsegs > MPI3MR_SG_DEPTH) { + device_printf(sc->mpi3mr_dev, "SGE count is too large or 0.\n"); + return; + } + + simple_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | + MPI3_SGE_FLAGS_DLAS_SYSTEM; + simple_sgl_flags_last = simple_sgl_flags | + MPI3_SGE_FLAGS_END_OF_LIST; + last_chain_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_LAST_CHAIN | + MPI3_SGE_FLAGS_DLAS_SYSTEM; + + sg_local = (U8 *)&scsiio_req->SGL; + + if (!scsiio_req->DataLength) { + mpi3mr_build_zero_len_sge(sg_local); + return; + } + + sges_left = nsegs; + + if (sges_left < 0) { + printf("scsi_dma_map failed: request for %d bytes!\n", + scsiio_req->DataLength); + return; + } + if (sges_left > MPI3MR_SG_DEPTH) { + printf("scsi_dma_map returned unsupported sge count %d!\n", + sges_left); + return; + } + + sges_in_segment = (sc->facts.op_req_sz - + offsetof(Mpi3SCSIIORequest_t, SGL))/sizeof(Mpi3SGESimple_t); + + i = 0; + + mpi3mr_dprint(sc, MPI3MR_TRACE, "SGE count: %d IO size: %d\n", + nsegs, scsiio_req->DataLength); + + if (sges_left <= sges_in_segment) + goto fill_in_last_segment; + + /* fill in main message segment when there is a chain following */ + while (sges_in_segment > 1) { + mpi3mr_add_sg_single(sg_local, simple_sgl_flags, + segs[i].ds_len, segs[i].ds_addr); + sg_local += sizeof(Mpi3SGESimple_t); + sges_left--; + sges_in_segment--; + i++; + } + + chain_req = &sc->chain_sgl_list[cm->hosttag]; + + chain = chain_req->buf; + chain_dma = chain_req->buf_phys; + memset(chain_req->buf, 0, PAGE_SIZE); + sges_in_segment = sges_left; + chain_length = sges_in_segment * sizeof(Mpi3SGESimple_t); + + mpi3mr_add_sg_single(sg_local, last_chain_sgl_flags, + chain_length, chain_dma); + + sg_local = chain; + +fill_in_last_segment: + while (sges_left > 0) { + if (sges_left == 1) + mpi3mr_add_sg_single(sg_local, + simple_sgl_flags_last, segs[i].ds_len, + segs[i].ds_addr); + else + mpi3mr_add_sg_single(sg_local, simple_sgl_flags, + segs[i].ds_len, segs[i].ds_addr); + sg_local += sizeof(Mpi3SGESimple_t); + sges_left--; + i++; + } + + return; +} + +int +mpi3mr_map_request(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cm) +{ + u_int32_t retcode = 0; + + if (cm->data != NULL) { + mtx_lock(&sc->io_lock); + /* Map data buffer into bus space */ + retcode = bus_dmamap_load_ccb(sc->buffer_dmat, cm->dmamap, + cm->ccb, mpi3mr_prepare_sgls, cm, 0); + mtx_unlock(&sc->io_lock); + if (retcode) + device_printf(sc->mpi3mr_dev, "bus_dmamap_load(): retcode = %d\n", retcode); + if (retcode == EINPROGRESS) { + device_printf(sc->mpi3mr_dev, "request load in progress\n"); + xpt_freeze_simq(sc->cam_sc->sim, 1); + } + } + if (cm->error_code) + return cm->error_code; + if (retcode) + mpi3mr_set_ccbstatus(cm->ccb, CAM_REQ_INVALID); + + return (retcode); +} + +void +mpi3mr_unmap_request(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cmd) +{ + if (cmd->data != NULL) { + if (cmd->data_dir == MPI3MR_READ) + bus_dmamap_sync(sc->buffer_dmat, cmd->dmamap, BUS_DMASYNC_POSTREAD); + if (cmd->data_dir == MPI3MR_WRITE) + bus_dmamap_sync(sc->buffer_dmat, cmd->dmamap, BUS_DMASYNC_POSTWRITE); + mtx_lock(&sc->io_lock); + bus_dmamap_unload(sc->buffer_dmat, cmd->dmamap); + mtx_unlock(&sc->io_lock); + } +} + +/** + * mpi3mr_allow_unmap_to_fw - Whether an unmap is allowed to fw + * @sc: Adapter instance reference + * @ccb: SCSI Command reference + * + * The controller hardware cannot handle certain unmap commands + * for NVMe drives, this routine checks those and return true + * and completes the SCSI command with proper status and sense + * data. + * + * Return: TRUE for allowed unmap, FALSE otherwise. + */ +static bool mpi3mr_allow_unmap_to_fw(struct mpi3mr_softc *sc, + union ccb *ccb) +{ + struct ccb_scsiio *csio; + uint16_t param_list_len, block_desc_len, trunc_param_len = 0; + + csio = &ccb->csio; + param_list_len = (uint16_t) ((scsiio_cdb_ptr(csio)[7] << 8) | scsiio_cdb_ptr(csio)[8]); + + switch(pci_get_revid(sc->mpi3mr_dev)) { + case SAS4116_CHIP_REV_A0: + if (!param_list_len) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "%s: CDB received with zero parameter length\n", + __func__); + mpi3mr_print_cdb(ccb); + mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP); + xpt_done(ccb); + return false; + } + + if (param_list_len < 24) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "%s: CDB received with invalid param_list_len: %d\n", + __func__, param_list_len); + mpi3mr_print_cdb(ccb); + scsi_set_sense_data(&ccb->csio.sense_data, + /*sense_format*/ SSD_TYPE_FIXED, + /*current_error*/ 1, + /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, + /*asc*/ 0x1A, + /*ascq*/ 0x00, + /*extra args*/ SSD_ELEM_NONE); + ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; + ccb->ccb_h.status = + CAM_SCSI_STATUS_ERROR | + CAM_AUTOSNS_VALID; + return false; + } + + if (param_list_len != csio->dxfer_len) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "%s: CDB received with param_list_len: %d bufflen: %d\n", + __func__, param_list_len, csio->dxfer_len); + mpi3mr_print_cdb(ccb); + scsi_set_sense_data(&ccb->csio.sense_data, + /*sense_format*/ SSD_TYPE_FIXED, + /*current_error*/ 1, + /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, + /*asc*/ 0x1A, + /*ascq*/ 0x00, + /*extra args*/ SSD_ELEM_NONE); + ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; + ccb->ccb_h.status = + CAM_SCSI_STATUS_ERROR | + CAM_AUTOSNS_VALID; + xpt_done(ccb); + return false; + } + + block_desc_len = (uint16_t) (csio->data_ptr[2] << 8 | csio->data_ptr[3]); + + if (block_desc_len < 16) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "%s: Invalid descriptor length in param list: %d\n", + __func__, block_desc_len); + mpi3mr_print_cdb(ccb); + scsi_set_sense_data(&ccb->csio.sense_data, + /*sense_format*/ SSD_TYPE_FIXED, + /*current_error*/ 1, + /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, + /*asc*/ 0x26, + /*ascq*/ 0x00, + /*extra args*/ SSD_ELEM_NONE); + ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; + ccb->ccb_h.status = + CAM_SCSI_STATUS_ERROR | + CAM_AUTOSNS_VALID; + xpt_done(ccb); + return false; + } + + if (param_list_len > (block_desc_len + 8)) { + mpi3mr_print_cdb(ccb); + mpi3mr_dprint(sc, MPI3MR_INFO, + "%s: Truncating param_list_len(%d) to block_desc_len+8(%d)\n", + __func__, param_list_len, (block_desc_len + 8)); + param_list_len = block_desc_len + 8; + scsiio_cdb_ptr(csio)[7] = (param_list_len >> 8) | 0xff; + scsiio_cdb_ptr(csio)[8] = param_list_len | 0xff; + mpi3mr_print_cdb(ccb); + } + break; + + case SAS4116_CHIP_REV_B0: + if ((param_list_len > 24) && ((param_list_len - 8) & 0xF)) { + trunc_param_len -= (param_list_len - 8) & 0xF; + mpi3mr_print_cdb(ccb); + mpi3mr_dprint(sc, MPI3MR_INFO, + "%s: Truncating param_list_len from (%d) to (%d)\n", + __func__, param_list_len, trunc_param_len); + scsiio_cdb_ptr(csio)[7] = (param_list_len >> 8) | 0xff; + scsiio_cdb_ptr(csio)[8] = param_list_len | 0xff; + mpi3mr_print_cdb(ccb); + } + break; + } + + return true; +} + +/** + * mpi3mr_tm_response_name - get TM response as a string + * @resp_code: TM response code + * + * Convert known task management response code as a readable + * string. + * + * Return: response code string. + */ +static const char* mpi3mr_tm_response_name(U8 resp_code) +{ + char *desc; + + switch (resp_code) { + case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE: + desc = "task management request completed"; + break; + case MPI3_SCSITASKMGMT_RSPCODE_INVALID_FRAME: + desc = "invalid frame"; + break; + case MPI3_SCSITASKMGMT_RSPCODE_TM_FUNCTION_NOT_SUPPORTED: + desc = "task management request not supported"; + break; + case MPI3_SCSITASKMGMT_RSPCODE_TM_FAILED: + desc = "task management request failed"; + break; + case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED: + desc = "task management request succeeded"; + break; + case MPI3_SCSITASKMGMT_RSPCODE_TM_INVALID_LUN: + desc = "invalid LUN"; + break; + case MPI3_SCSITASKMGMT_RSPCODE_TM_OVERLAPPED_TAG: + desc = "overlapped tag attempted"; + break; + case MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC: + desc = "task queued, however not sent to target"; + break; + case MPI3_SCSITASKMGMT_RSPCODE_TM_NVME_DENIED: + desc = "task management request denied by NVMe device"; + break; + default: + desc = "unknown"; + break; + } + + return desc; +} + +void mpi3mr_poll_pend_io_completions(struct mpi3mr_softc *sc) +{ + int i; + int num_of_reply_queues = sc->num_queues; + struct mpi3mr_irq_context *irq_ctx; + + for (i = 0; i < num_of_reply_queues; i++) { + irq_ctx = &sc->irq_ctx[i]; + mpi3mr_complete_io_cmd(sc, irq_ctx); + } +} + +void +trigger_reset_from_watchdog(struct mpi3mr_softc *sc, U8 reset_type, U32 reset_reason) +{ + if (sc->reset_in_progress) { + mpi3mr_dprint(sc, MPI3MR_INFO, "Another reset is in progress, no need to trigger the reset\n"); + return; + } + sc->reset.type = reset_type; + sc->reset.reason = reset_reason; + + return; +} + +/** + * mpi3mr_issue_tm - Issue Task Management request + * @sc: Adapter instance reference + * @tm_type: Task Management type + * @handle: Device handle + * @lun: lun ID + * @htag: Host tag of the TM request + * @timeout: TM timeout value + * @drv_cmd: Internal command tracker + * @resp_code: Response code place holder + * @cmd: Timed out command reference + * + * Issues a Task Management Request to the controller for a + * specified target, lun and command and wait for its completion + * and check TM response. Recover the TM if it timed out by + * issuing controller reset. + * + * Return: 0 on success, non-zero on errors + */ +static int +mpi3mr_issue_tm(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cmd, + U8 tm_type, unsigned long timeout) +{ + int retval = 0; + MPI3_SCSI_TASK_MGMT_REQUEST tm_req; + MPI3_SCSI_TASK_MGMT_REPLY *tm_reply = NULL; + struct mpi3mr_drvr_cmd *drv_cmd = NULL; + struct mpi3mr_target *tgtdev = NULL; + struct mpi3mr_op_req_queue *op_req_q = NULL; + union ccb *ccb; + U8 resp_code; + + + if (sc->unrecoverable) { + mpi3mr_dprint(sc, MPI3MR_INFO, + "Controller is in unrecoverable state!! TM not required\n"); + return retval; + } + if (sc->reset_in_progress) { + mpi3mr_dprint(sc, MPI3MR_INFO, + "controller reset in progress!! TM not required\n"); + return retval; + } + + if (!cmd->ccb) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "SCSIIO command timed-out with NULL ccb\n"); + return retval; + } + ccb = cmd->ccb; + + tgtdev = cmd->targ; + if (tgtdev == NULL) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Device does not exist target ID:0x%x," + "TM is not required\n", ccb->ccb_h.target_id); + return retval; + } + if (tgtdev->dev_removed == 1) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Device(0x%x) is removed, TM is not required\n", + ccb->ccb_h.target_id); + return retval; + } + + drv_cmd = &sc->host_tm_cmds; + mtx_lock(&drv_cmd->lock); + + memset(&tm_req, 0, sizeof(tm_req)); + tm_req.DevHandle = htole16(tgtdev->dev_handle); + tm_req.TaskType = tm_type; + tm_req.HostTag = htole16(MPI3MR_HOSTTAG_TMS); + int_to_lun(ccb->ccb_h.target_lun, tm_req.LUN); + tm_req.Function = MPI3_FUNCTION_SCSI_TASK_MGMT; + drv_cmd->state = MPI3MR_CMD_PENDING; + drv_cmd->is_waiting = 1; + drv_cmd->callback = NULL; + + if (ccb) { + if (tm_type == MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { + op_req_q = &sc->op_req_q[cmd->req_qidx]; + tm_req.TaskHostTag = htole16(cmd->hosttag); + tm_req.TaskRequestQueueID = htole16(op_req_q->qid); + } + } + + if (tgtdev) + mpi3mr_atomic_inc(&tgtdev->block_io); + + if (tgtdev && (tgtdev->dev_type == MPI3_DEVICE_DEVFORM_PCIE)) { + if ((tm_type == MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK) + && tgtdev->dev_spec.pcie_inf.abort_to) + timeout = tgtdev->dev_spec.pcie_inf.abort_to; + else if ((tm_type == MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET) + && tgtdev->dev_spec.pcie_inf.reset_to) + timeout = tgtdev->dev_spec.pcie_inf.reset_to; + } + + sc->tm_chan = (void *)&drv_cmd; + + mpi3mr_dprint(sc, MPI3MR_DEBUG_TM, + "posting task management request: type(%d), handle(0x%04x)\n", + tm_type, tgtdev->dev_handle); + + init_completion(&drv_cmd->completion); + retval = mpi3mr_submit_admin_cmd(sc, &tm_req, sizeof(tm_req)); + if (retval) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "posting task management request is failed\n"); + retval = -1; + goto out_unlock; + } + wait_for_completion_timeout_tm(&drv_cmd->completion, timeout, sc); + + if (!(drv_cmd->state & MPI3MR_CMD_COMPLETE)) { + drv_cmd->is_waiting = 0; + retval = -1; + if (!(drv_cmd->state & MPI3MR_CMD_RESET)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "task management request timed out after %ld seconds\n", timeout); + if (sc->mpi3mr_debug & MPI3MR_DEBUG_TM) { + mpi3mr_dprint(sc, MPI3MR_INFO, "tm_request dump\n"); + mpi3mr_hexdump(&tm_req, sizeof(tm_req), 8); + } + trigger_reset_from_watchdog(sc, MPI3MR_TRIGGER_SOFT_RESET, MPI3MR_RESET_FROM_TM_TIMEOUT); + retval = ETIMEDOUT; + } + goto out_unlock; + } + + if (!(drv_cmd->state & MPI3MR_CMD_REPLYVALID)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "invalid task management reply message\n"); + retval = -1; + goto out_unlock; + } + tm_reply = (MPI3_SCSI_TASK_MGMT_REPLY *)drv_cmd->reply; + + switch (drv_cmd->ioc_status) { + case MPI3_IOCSTATUS_SUCCESS: + resp_code = tm_reply->ResponseData & MPI3MR_RI_MASK_RESPCODE; + break; + case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED: + resp_code = MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE; + break; + default: + mpi3mr_dprint(sc, MPI3MR_ERROR, + "task management request to handle(0x%04x) is failed with ioc_status(0x%04x) log_info(0x%08x)\n", + tgtdev->dev_handle, drv_cmd->ioc_status, drv_cmd->ioc_loginfo); + retval = -1; + goto out_unlock; + } + + switch (resp_code) { + case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED: + case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE: + break; + case MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC: + if (tm_type != MPI3_SCSITASKMGMT_TASKTYPE_QUERY_TASK) + retval = -1; + break; + default: + retval = -1; + break; + } + + mpi3mr_dprint(sc, MPI3MR_DEBUG_TM, + "task management request type(%d) completed for handle(0x%04x) with ioc_status(0x%04x), log_info(0x%08x)" + "termination_count(%u), response:%s(0x%x)\n", tm_type, tgtdev->dev_handle, drv_cmd->ioc_status, drv_cmd->ioc_loginfo, + tm_reply->TerminationCount, mpi3mr_tm_response_name(resp_code), resp_code); + + if (retval) + goto out_unlock; + + mpi3mr_disable_interrupts(sc); + mpi3mr_poll_pend_io_completions(sc); + mpi3mr_enable_interrupts(sc); + mpi3mr_poll_pend_io_completions(sc); + + switch (tm_type) { + case MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK: + if (cmd->state == MPI3MR_CMD_STATE_IN_TM) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "%s: task abort returned success from firmware but corresponding CCB (%p) was not terminated" + "marking task abort failed!\n", sc->name, cmd->ccb); + retval = -1; + } + break; + case MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET: + if (mpi3mr_atomic_read(&tgtdev->outstanding)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "%s: target reset returned success from firmware but IOs are still pending on the target (%p)" + "marking target reset failed!\n", + sc->name, tgtdev); + retval = -1; + } + break; + default: + break; + } + +out_unlock: + drv_cmd->state = MPI3MR_CMD_NOTUSED; + mtx_unlock(&drv_cmd->lock); + if (tgtdev && mpi3mr_atomic_read(&tgtdev->block_io) > 0) + mpi3mr_atomic_dec(&tgtdev->block_io); + + return retval; +} + +/** + * mpi3mr_task_abort- Abort error handling callback + * @cmd: Timed out command reference + * + * Issue Abort Task Management if the command is in LLD scope + * and verify if it is aborted successfully and return status + * accordingly. + * + * Return: SUCCESS of successful abort the SCSI command else FAILED + */ +static int mpi3mr_task_abort(struct mpi3mr_cmd *cmd) +{ + int retval = 0; + struct mpi3mr_softc *sc; + union ccb *ccb; + + sc = cmd->sc; + + if (!cmd->ccb) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "SCSIIO command timed-out with NULL ccb\n"); + return retval; + } + ccb = cmd->ccb; + + mpi3mr_dprint(sc, MPI3MR_INFO, + "attempting abort task for ccb(%p)\n", ccb); + + mpi3mr_print_cdb(ccb); + + if (cmd->state != MPI3MR_CMD_STATE_BUSY) { + mpi3mr_dprint(sc, MPI3MR_INFO, + "%s: ccb is not in driver scope, abort task is not required\n", + sc->name); + return retval; + } + cmd->state = MPI3MR_CMD_STATE_IN_TM; + + retval = mpi3mr_issue_tm(sc, cmd, MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK, MPI3MR_ABORTTM_TIMEOUT); + + mpi3mr_dprint(sc, MPI3MR_INFO, + "abort task is %s for ccb(%p)\n", ((retval == 0) ? "SUCCESS" : "FAILED"), ccb); + + return retval; +} + +/** + * mpi3mr_target_reset - Target reset error handling callback + * @cmd: Timed out command reference + * + * Issue Target reset Task Management and verify the SCSI commands are + * terminated successfully and return status accordingly. + * + * Return: SUCCESS of successful termination of the SCSI commands else + * FAILED + */ +static int mpi3mr_target_reset(struct mpi3mr_cmd *cmd) +{ + int retval = 0; + struct mpi3mr_softc *sc; + struct mpi3mr_target *target; + + sc = cmd->sc; + + target = cmd->targ; + if (target == NULL) { + mpi3mr_dprint(sc, MPI3MR_XINFO, "Device does not exist for target:0x%p," + "target reset is not required\n", target); + return retval; + } + + mpi3mr_dprint(sc, MPI3MR_INFO, + "attempting target reset on target(%d)\n", target->per_id); + + + if (mpi3mr_atomic_read(&target->outstanding)) { + mpi3mr_dprint(sc, MPI3MR_INFO, + "no outstanding IOs on the target(%d)," + " target reset not required.\n", target->per_id); + return retval; + } + + retval = mpi3mr_issue_tm(sc, cmd, MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET, MPI3MR_RESETTM_TIMEOUT); + + mpi3mr_dprint(sc, MPI3MR_INFO, + "target reset is %s for target(%d)\n", ((retval == 0) ? "SUCCESS" : "FAILED"), + target->per_id); + + return retval; +} + +/** + * mpi3mr_get_fw_pending_ios - Calculate pending I/O count + * @sc: Adapter instance reference + * + * Calculate the pending I/Os for the controller and return. + * + * Return: Number of pending I/Os + */ +static inline int mpi3mr_get_fw_pending_ios(struct mpi3mr_softc *sc) +{ + U16 i, pend_ios = 0; + + for (i = 0; i < sc->num_queues; i++) + pend_ios += mpi3mr_atomic_read(&sc->op_reply_q[i].pend_ios); + return pend_ios; +} + +/** + * mpi3mr_wait_for_host_io - block for I/Os to complete + * @sc: Adapter instance reference + * @timeout: time out in seconds + * + * Waits for pending I/Os for the given adapter to complete or + * to hit the timeout. + * + * Return: Nothing + */ +static int mpi3mr_wait_for_host_io(struct mpi3mr_softc *sc, U32 timeout) +{ + enum mpi3mr_iocstate iocstate; + + iocstate = mpi3mr_get_iocstate(sc); + if (iocstate != MRIOC_STATE_READY) { + mpi3mr_dprint(sc, MPI3MR_XINFO, "%s :Controller is in NON-READY state! Proceed with Reset\n", __func__); + return -1; + } + + if (!mpi3mr_get_fw_pending_ios(sc)) + return 0; + + mpi3mr_dprint(sc, MPI3MR_INFO, + "%s :Waiting for %d seconds prior to reset for %d pending I/Os to complete\n", + __func__, timeout, mpi3mr_get_fw_pending_ios(sc)); + + int i; + for (i = 0; i < timeout; i++) { + if (!mpi3mr_get_fw_pending_ios(sc)) { + mpi3mr_dprint(sc, MPI3MR_INFO, "%s :All pending I/Os got completed while waiting! Reset not required\n", __func__); + return 0; + + } + iocstate = mpi3mr_get_iocstate(sc); + if (iocstate != MRIOC_STATE_READY) { + mpi3mr_dprint(sc, MPI3MR_XINFO, "%s :Controller state becomes NON-READY while waiting! dont wait further" + "Proceed with Reset\n", __func__); + return -1; + } + DELAY(1000 * 1000); + } + + mpi3mr_dprint(sc, MPI3MR_INFO, "%s :Pending I/Os after wait exaust is %d! Proceed with Reset\n", __func__, + mpi3mr_get_fw_pending_ios(sc)); + + return -1; +} + +static void +mpi3mr_scsiio_timeout(void *data) +{ + int retval = 0; + struct mpi3mr_softc *sc; + struct mpi3mr_cmd *cmd; + struct mpi3mr_target *targ_dev = NULL; + + if (!data) + return; + + cmd = (struct mpi3mr_cmd *)data; + sc = cmd->sc; + + if (cmd->ccb == NULL) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "SCSIIO command timed-out with NULL ccb\n"); + return; + } + + /* + * TMs are not supported for IO timeouts on VD/LD, so directly issue controller reset + * with max timeout for outstanding IOs to complete is 180sec. + */ + targ_dev = cmd->targ; + if (targ_dev && (targ_dev->dev_type == MPI3_DEVICE_DEVFORM_VD)) { + if (mpi3mr_wait_for_host_io(sc, MPI3MR_RAID_ERRREC_RESET_TIMEOUT)) + trigger_reset_from_watchdog(sc, MPI3MR_TRIGGER_SOFT_RESET, MPI3MR_RESET_FROM_SCSIIO_TIMEOUT); + return; + } + + /* Issue task abort to recover the timed out IO */ + retval = mpi3mr_task_abort(cmd); + if (!retval || (retval == ETIMEDOUT)) + return; + + /* + * task abort has failed to recover the timed out IO, + * try with the target reset + */ + retval = mpi3mr_target_reset(cmd); + if (!retval || (retval == ETIMEDOUT)) + return; + + /* + * task abort and target reset has failed. So issue Controller reset(soft reset) + * through OCR thread context + */ + trigger_reset_from_watchdog(sc, MPI3MR_TRIGGER_SOFT_RESET, MPI3MR_RESET_FROM_SCSIIO_TIMEOUT); + + return; +} + +void int_to_lun(unsigned int lun, U8 *req_lun) +{ + int i; + + memset(req_lun, 0, sizeof(*req_lun)); + + for (i = 0; i < sizeof(lun); i += 2) { + req_lun[i] = (lun >> 8) & 0xFF; + req_lun[i+1] = lun & 0xFF; + lun = lun >> 16; + } + +} + +static U16 get_req_queue_index(struct mpi3mr_softc *sc) +{ + U16 i = 0, reply_q_index = 0, reply_q_pend_ios = 0; + + reply_q_pend_ios = mpi3mr_atomic_read(&sc->op_reply_q[0].pend_ios); + for (i = 0; i < sc->num_queues; i++) { + if (reply_q_pend_ios > mpi3mr_atomic_read(&sc->op_reply_q[i].pend_ios)) { + reply_q_pend_ios = mpi3mr_atomic_read(&sc->op_reply_q[i].pend_ios); + reply_q_index = i; + } + } + + return reply_q_index; +} + +static void +mpi3mr_action_scsiio(struct mpi3mr_cam_softc *cam_sc, union ccb *ccb) +{ + Mpi3SCSIIORequest_t *req = NULL; + struct ccb_scsiio *csio; + struct mpi3mr_softc *sc; + struct mpi3mr_target *targ; + struct mpi3mr_cmd *cm; + uint8_t scsi_opcode, queue_idx; + uint32_t mpi_control; + struct mpi3mr_op_req_queue *opreqq = NULL; + U32 data_len_blks = 0; + U32 tracked_io_sz = 0; + U32 ioc_pend_data_len = 0, tg_pend_data_len = 0; + struct mpi3mr_throttle_group_info *tg = NULL; + static int ratelimit; + + sc = cam_sc->sc; + mtx_assert(&sc->mpi3mr_mtx, MA_OWNED); + + if (sc->unrecoverable) { + mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); + xpt_done(ccb); + return; + } + + csio = &ccb->csio; + KASSERT(csio->ccb_h.target_id < cam_sc->maxtargets, + ("Target %d out of bounds in XPT_SCSI_IO\n", + csio->ccb_h.target_id)); + + scsi_opcode = scsiio_cdb_ptr(csio)[0]; + + if ((sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN) && + !((scsi_opcode == SYNCHRONIZE_CACHE) || + (scsi_opcode == START_STOP_UNIT))) { + mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP); + xpt_done(ccb); + return; + } + + targ = mpi3mr_find_target_by_per_id(cam_sc, csio->ccb_h.target_id); + if (targ == NULL) { + mpi3mr_dprint(sc, MPI3MR_XINFO, "Device with target ID: 0x%x does not exist\n", + csio->ccb_h.target_id); + mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); + xpt_done(ccb); + return; + } + + if (targ && targ->is_hidden) { + mpi3mr_dprint(sc, MPI3MR_XINFO, "Device with target ID: 0x%x is hidden\n", + csio->ccb_h.target_id); + mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); + xpt_done(ccb); + return; + } + + if (targ->dev_removed == 1) { + mpi3mr_dprint(sc, MPI3MR_XINFO, "Device with target ID: 0x%x is removed\n", csio->ccb_h.target_id); + mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); + xpt_done(ccb); + return; + } + + if (targ->dev_handle == 0x0) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "%s NULL handle for target 0x%x\n", + __func__, csio->ccb_h.target_id); + mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); + xpt_done(ccb); + return; + } + + if (mpi3mr_atomic_read(&targ->block_io) || + (sc->reset_in_progress == 1) || (sc->prepare_for_reset == 1)) { + mpi3mr_dprint(sc, MPI3MR_TRACE, "%s target is busy target_id: 0x%x\n", + __func__, csio->ccb_h.target_id); + mpi3mr_set_ccbstatus(ccb, CAM_REQUEUE_REQ); + xpt_done(ccb); + return; + } + + /* + * Sometimes, it is possible to get a command that is not "In + * Progress" and was actually aborted by the upper layer. Check for + * this here and complete the command without error. + */ + if (mpi3mr_get_ccbstatus(ccb) != CAM_REQ_INPROG) { + mpi3mr_dprint(sc, MPI3MR_TRACE, "%s Command is not in progress for " + "target %u\n", __func__, csio->ccb_h.target_id); + xpt_done(ccb); + return; + } + /* + * If devinfo is 0 this will be a volume. In that case don't tell CAM + * that the volume has timed out. We want volumes to be enumerated + * until they are deleted/removed, not just failed. + */ + if (targ->flags & MPI3MRSAS_TARGET_INREMOVAL) { + if (targ->devinfo == 0) + mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP); + else + mpi3mr_set_ccbstatus(ccb, CAM_SEL_TIMEOUT); + xpt_done(ccb); + return; + } + + if ((scsi_opcode == UNMAP) && + (pci_get_device(sc->mpi3mr_dev) == MPI3_MFGPAGE_DEVID_SAS4116) && + (targ->dev_type == MPI3_DEVICE_DEVFORM_PCIE) && + (mpi3mr_allow_unmap_to_fw(sc, ccb) == false)) + return; + + cm = mpi3mr_get_command(sc); + if (cm == NULL || (sc->mpi3mr_flags & MPI3MR_FLAGS_DIAGRESET)) { + if (cm != NULL) { + mpi3mr_release_command(cm); + } + if ((cam_sc->flags & MPI3MRSAS_QUEUE_FROZEN) == 0) { + xpt_freeze_simq(cam_sc->sim, 1); + cam_sc->flags |= MPI3MRSAS_QUEUE_FROZEN; + } + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + ccb->ccb_h.status |= CAM_REQUEUE_REQ; + xpt_done(ccb); + return; + } + + switch (csio->ccb_h.flags & CAM_DIR_MASK) { + case CAM_DIR_IN: + mpi_control = MPI3_SCSIIO_FLAGS_DATADIRECTION_READ; + cm->data_dir = MPI3MR_READ; + break; + case CAM_DIR_OUT: + mpi_control = MPI3_SCSIIO_FLAGS_DATADIRECTION_WRITE; + cm->data_dir = MPI3MR_WRITE; + break; + case CAM_DIR_NONE: + default: + mpi_control = MPI3_SCSIIO_FLAGS_DATADIRECTION_NO_DATA_TRANSFER; + break; + } + + if (csio->cdb_len > 16) + mpi_control |= MPI3_SCSIIO_FLAGS_CDB_GREATER_THAN_16; + + req = (Mpi3SCSIIORequest_t *)&cm->io_request; + bzero(req, sizeof(*req)); + req->Function = MPI3_FUNCTION_SCSI_IO; + req->HostTag = cm->hosttag; + req->DataLength = htole32(csio->dxfer_len); + req->DevHandle = htole16(targ->dev_handle); + + /* + * It looks like the hardware doesn't require an explicit tag + * number for each transaction. SAM Task Management not supported + * at the moment. + */ + switch (csio->tag_action) { + case MSG_HEAD_OF_Q_TAG: + mpi_control |= MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_HEADOFQ; + break; + case MSG_ORDERED_Q_TAG: + mpi_control |= MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_ORDEREDQ; + break; + case MSG_ACA_TASK: + mpi_control |= MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_ACAQ; + break; + case CAM_TAG_ACTION_NONE: + case MSG_SIMPLE_Q_TAG: + default: + mpi_control |= MPI3_SCSIIO_FLAGS_TASKATTRIBUTE_SIMPLEQ; + break; + } + + req->Flags = htole32(mpi_control); + + if (csio->ccb_h.flags & CAM_CDB_POINTER) + bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len); + else { + KASSERT(csio->cdb_len <= IOCDBLEN, + ("cdb_len %d is greater than IOCDBLEN but CAM_CDB_POINTER " + "is not set", csio->cdb_len)); + bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len); + } + + cm->length = csio->dxfer_len; + cm->targ = targ; + int_to_lun(csio->ccb_h.target_lun, req->LUN); + cm->ccb = ccb; + csio->ccb_h.qos.sim_data = sbinuptime(); + queue_idx = get_req_queue_index(sc); + cm->req_qidx = queue_idx; + + mpi3mr_dprint(sc, MPI3MR_TRACE, "[QID:%d]: func: %s line:%d CDB: 0x%x targetid: %x SMID: 0x%x\n", + (queue_idx + 1), __func__, __LINE__, scsi_opcode, csio->ccb_h.target_id, cm->hosttag); + + ccb->ccb_h.status |= CAM_SIM_QUEUED; + + switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) { + case CAM_DATA_PADDR: + case CAM_DATA_SG_PADDR: + device_printf(sc->mpi3mr_dev, "%s: physical addresses not supported\n", + __func__); + mpi3mr_release_command(cm); + ccb->ccb_h.status = CAM_REQ_INVALID; + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + xpt_done(ccb); + return; + case CAM_DATA_SG: + device_printf(sc->mpi3mr_dev, "%s: scatter gather is not supported\n", + __func__); + mpi3mr_release_command(cm); + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + return; + case CAM_DATA_VADDR: + case CAM_DATA_BIO: + if (csio->dxfer_len > (MPI3MR_SG_DEPTH * MPI3MR_4K_PGSZ)) { + mpi3mr_release_command(cm); + ccb->ccb_h.status = CAM_REQ_TOO_BIG; + xpt_done(ccb); + return; + } + cm->length = csio->dxfer_len; + if (cm->length) + cm->data = csio->data_ptr; + break; + default: + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + return; + } + + /* Prepare SGEs */ + if (mpi3mr_map_request(sc, cm)) { + mpi3mr_release_command(cm); + xpt_done(ccb); + printf("func: %s line: %d Build SGLs failed\n", __func__, __LINE__); + return; + } + + opreqq = &sc->op_req_q[queue_idx]; + + if (sc->iot_enable) { + data_len_blks = csio->dxfer_len >> 9; + + if ((data_len_blks >= sc->io_throttle_data_length) && + targ->io_throttle_enabled) { + tracked_io_sz = data_len_blks; + tg = targ->throttle_group; + if (tg) { + mpi3mr_atomic_add(&sc->pend_large_data_sz, data_len_blks); + mpi3mr_atomic_add(&tg->pend_large_data_sz, data_len_blks); + + ioc_pend_data_len = mpi3mr_atomic_read(&sc->pend_large_data_sz); + tg_pend_data_len = mpi3mr_atomic_read(&tg->pend_large_data_sz); + + if (ratelimit % 1000) { + mpi3mr_dprint(sc, MPI3MR_IOT, + "large vd_io persist_id(%d), handle(0x%04x), data_len(%d)," + "ioc_pending(%d), tg_pending(%d), ioc_high(%d), tg_high(%d)\n", + targ->per_id, targ->dev_handle, + data_len_blks, ioc_pend_data_len, + tg_pend_data_len, sc->io_throttle_high, + tg->high); + ratelimit++; + } + + if (!tg->io_divert && ((ioc_pend_data_len >= + sc->io_throttle_high) || + (tg_pend_data_len >= tg->high))) { + tg->io_divert = 1; + mpi3mr_dprint(sc, MPI3MR_IOT, + "VD: Setting divert flag for tg_id(%d), persist_id(%d)\n", + tg->id, targ->per_id); + if (sc->mpi3mr_debug | MPI3MR_IOT) + mpi3mr_print_cdb(ccb); + mpi3mr_set_io_divert_for_all_vd_in_tg(sc, + tg, 1); + } + } else { + mpi3mr_atomic_add(&sc->pend_large_data_sz, data_len_blks); + ioc_pend_data_len = mpi3mr_atomic_read(&sc->pend_large_data_sz); + if (ratelimit % 1000) { + mpi3mr_dprint(sc, MPI3MR_IOT, + "large pd_io persist_id(%d), handle(0x%04x), data_len(%d), ioc_pending(%d), ioc_high(%d)\n", + targ->per_id, targ->dev_handle, + data_len_blks, ioc_pend_data_len, + sc->io_throttle_high); + ratelimit++; + } + + if (ioc_pend_data_len >= sc->io_throttle_high) { + targ->io_divert = 1; + mpi3mr_dprint(sc, MPI3MR_IOT, + "PD: Setting divert flag for persist_id(%d)\n", + targ->per_id); + if (sc->mpi3mr_debug | MPI3MR_IOT) + mpi3mr_print_cdb(ccb); + } + } + } + + if (targ->io_divert) { + req->MsgFlags |= MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE; + mpi_control |= MPI3_SCSIIO_FLAGS_DIVERT_REASON_IO_THROTTLING; + } + } + req->Flags = htole32(mpi_control); + + if (mpi3mr_submit_io(sc, opreqq, + (U8 *)&cm->io_request)) { + mpi3mr_release_command(cm); + if (tracked_io_sz) { + mpi3mr_atomic_sub(&sc->pend_large_data_sz, tracked_io_sz); + if (tg) + mpi3mr_atomic_sub(&tg->pend_large_data_sz, tracked_io_sz); + } + mpi3mr_set_ccbstatus(ccb, CAM_RESRC_UNAVAIL); + xpt_done(ccb); + } else { + callout_reset_sbt(&cm->callout, SBT_1S * 90 , 0, + mpi3mr_scsiio_timeout, cm, 0); + mpi3mr_atomic_inc(&sc->fw_outstanding); + mpi3mr_atomic_inc(&targ->outstanding); + if (mpi3mr_atomic_read(&sc->fw_outstanding) > sc->io_cmds_highwater) + sc->io_cmds_highwater++; + } + + cm->callout_owner = true; + return; +} + +static void +mpi3mr_cam_poll(struct cam_sim *sim) +{ + struct mpi3mr_cam_softc *cam_sc; + struct mpi3mr_irq_context *irq_ctx; + struct mpi3mr_softc *sc; + int i; + + cam_sc = cam_sim_softc(sim); + sc = cam_sc->sc; + + mpi3mr_dprint(cam_sc->sc, MPI3MR_TRACE, "func: %s line: %d is called\n", + __func__, __LINE__); + + for (i = 0; i < sc->num_queues; i++) { + irq_ctx = sc->irq_ctx + i; + if (irq_ctx->op_reply_q->qid) { + mpi3mr_complete_io_cmd(sc, irq_ctx); + } + } +} + +static void +mpi3mr_cam_action(struct cam_sim *sim, union ccb *ccb) +{ + struct mpi3mr_cam_softc *cam_sc; + struct mpi3mr_target *targ; + + cam_sc = cam_sim_softc(sim); + + mpi3mr_dprint(cam_sc->sc, MPI3MR_TRACE, "ccb func_code 0x%x target id: 0x%x\n", + ccb->ccb_h.func_code, ccb->ccb_h.target_id); + + mtx_assert(&cam_sc->sc->mpi3mr_mtx, MA_OWNED); + + switch (ccb->ccb_h.func_code) { + case XPT_PATH_INQ: + { + struct ccb_pathinq *cpi = &ccb->cpi; + + cpi->version_num = 1; + cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; + cpi->target_sprt = 0; + cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED | PIM_NOSCAN; + cpi->hba_eng_cnt = 0; + cpi->max_target = cam_sc->maxtargets - 1; + cpi->max_lun = 0; + + /* + * initiator_id is set here to an ID outside the set of valid + * target IDs (including volumes). + */ + cpi->initiator_id = cam_sc->maxtargets; + strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); + strlcpy(cpi->hba_vid, "Broadcom", HBA_IDLEN); + strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); + cpi->unit_number = cam_sim_unit(sim); + cpi->bus_id = cam_sim_bus(sim); + /* + * XXXSLM-I think this needs to change based on config page or + * something instead of hardcoded to 150000. + */ + cpi->base_transfer_speed = 150000; + cpi->transport = XPORT_SAS; + cpi->transport_version = 0; + cpi->protocol = PROTO_SCSI; + cpi->protocol_version = SCSI_REV_SPC; + + targ = mpi3mr_find_target_by_per_id(cam_sc, ccb->ccb_h.target_id); + + if (targ && (targ->dev_type == MPI3_DEVICE_DEVFORM_PCIE) && + ((targ->dev_spec.pcie_inf.dev_info & + MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) == + MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE)) { + cpi->maxio = targ->dev_spec.pcie_inf.mdts; + mpi3mr_dprint(cam_sc->sc, MPI3MR_XINFO, + "PCI device target_id: %u max io size: %u\n", + ccb->ccb_h.target_id, cpi->maxio); + } else { + cpi->maxio = PAGE_SIZE * (MPI3MR_SG_DEPTH - 1); + } + mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP); + break; + } + case XPT_GET_TRAN_SETTINGS: + { + struct ccb_trans_settings *cts; + struct ccb_trans_settings_sas *sas; + struct ccb_trans_settings_scsi *scsi; + + cts = &ccb->cts; + sas = &cts->xport_specific.sas; + scsi = &cts->proto_specific.scsi; + + KASSERT(cts->ccb_h.target_id < cam_sc->maxtargets, + ("Target %d out of bounds in XPT_GET_TRAN_SETTINGS\n", + cts->ccb_h.target_id)); + targ = mpi3mr_find_target_by_per_id(cam_sc, cts->ccb_h.target_id); + + if (targ == NULL) { + mpi3mr_dprint(cam_sc->sc, MPI3MR_TRACE, "Device with target ID: 0x%x does not exist\n", + cts->ccb_h.target_id); + mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); + break; + } + + if ((targ->dev_handle == 0x0) || (targ->dev_removed == 1)) { + mpi3mr_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); + break; + } + + cts->protocol_version = SCSI_REV_SPC2; + cts->transport = XPORT_SAS; + cts->transport_version = 0; + + sas->valid = CTS_SAS_VALID_SPEED; + + switch (targ->link_rate) { + case 0x08: + sas->bitrate = 150000; + break; + case 0x09: + sas->bitrate = 300000; + break; + case 0x0a: + sas->bitrate = 600000; + break; + case 0x0b: + sas->bitrate = 1200000; + break; + default: + sas->valid = 0; + } + + cts->protocol = PROTO_SCSI; + scsi->valid = CTS_SCSI_VALID_TQ; + scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; + + mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP); + break; + } + case XPT_CALC_GEOMETRY: + cam_calc_geometry(&ccb->ccg, /*extended*/1); + mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP); + break; + case XPT_RESET_DEV: + mpi3mr_dprint(cam_sc->sc, MPI3MR_INFO, "mpi3mr_action " + "XPT_RESET_DEV\n"); + return; + case XPT_RESET_BUS: + case XPT_ABORT: + case XPT_TERM_IO: + mpi3mr_dprint(cam_sc->sc, MPI3MR_INFO, "mpi3mr_action faking success " + "for abort or reset\n"); + mpi3mr_set_ccbstatus(ccb, CAM_REQ_CMP); + break; + case XPT_SCSI_IO: + mpi3mr_action_scsiio(cam_sc, ccb); + return; + default: + mpi3mr_set_ccbstatus(ccb, CAM_FUNC_NOTAVAIL); + break; + } + xpt_done(ccb); +} + +void +mpi3mr_startup_increment(struct mpi3mr_cam_softc *cam_sc) +{ + if ((cam_sc->flags & MPI3MRSAS_IN_STARTUP) != 0) { + if (cam_sc->startup_refcount++ == 0) { + /* just starting, freeze the simq */ + mpi3mr_dprint(cam_sc->sc, MPI3MR_XINFO, + "%s freezing simq\n", __func__); + xpt_hold_boot(); + } + mpi3mr_dprint(cam_sc->sc, MPI3MR_XINFO, "%s refcount %u\n", __func__, + cam_sc->startup_refcount); + } +} + +void +mpi3mr_release_simq_reinit(struct mpi3mr_cam_softc *cam_sc) +{ + if (cam_sc->flags & MPI3MRSAS_QUEUE_FROZEN) { + cam_sc->flags &= ~MPI3MRSAS_QUEUE_FROZEN; + xpt_release_simq(cam_sc->sim, 1); + mpi3mr_dprint(cam_sc->sc, MPI3MR_INFO, "Unfreezing SIM queue\n"); + } +} + +void +mpi3mr_rescan_target(struct mpi3mr_softc *sc, struct mpi3mr_target *targ) +{ + struct mpi3mr_cam_softc *cam_sc = sc->cam_sc; + path_id_t pathid; + target_id_t targetid; + union ccb *ccb; + + pathid = cam_sim_path(cam_sc->sim); + if (targ == NULL) + targetid = CAM_TARGET_WILDCARD; + else + targetid = targ->per_id; + + /* + * Allocate a CCB and schedule a rescan. + */ + ccb = xpt_alloc_ccb_nowait(); + if (ccb == NULL) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "unable to alloc CCB for rescan\n"); + return; + } + + if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid, targetid, + CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "unable to create path for rescan\n"); + xpt_free_ccb(ccb); + return; + } + + if (targetid == CAM_TARGET_WILDCARD) + ccb->ccb_h.func_code = XPT_SCAN_BUS; + else + ccb->ccb_h.func_code = XPT_SCAN_TGT; + + mpi3mr_dprint(sc, MPI3MR_EVENT, "%s target id 0x%x\n", __func__, targetid); + xpt_rescan(ccb); +} + +void +mpi3mr_startup_decrement(struct mpi3mr_cam_softc *cam_sc) +{ + if ((cam_sc->flags & MPI3MRSAS_IN_STARTUP) != 0) { + if (--cam_sc->startup_refcount == 0) { + /* finished all discovery-related actions, release + * the simq and rescan for the latest topology. + */ + mpi3mr_dprint(cam_sc->sc, MPI3MR_XINFO, + "%s releasing simq\n", __func__); + cam_sc->flags &= ~MPI3MRSAS_IN_STARTUP; + xpt_release_simq(cam_sc->sim, 1); + xpt_release_boot(); + } + mpi3mr_dprint(cam_sc->sc, MPI3MR_XINFO, "%s refcount %u\n", __func__, + cam_sc->startup_refcount); + } +} + +static void +mpi3mr_fw_event_free(struct mpi3mr_softc *sc, struct mpi3mr_fw_event_work *fw_event) +{ + if (!fw_event) + return; + + if (fw_event->event_data != NULL) { + free(fw_event->event_data, M_MPI3MR); + fw_event->event_data = NULL; + } + + free(fw_event, M_MPI3MR); + fw_event = NULL; +} + +static void +mpi3mr_freeup_events(struct mpi3mr_softc *sc) +{ + struct mpi3mr_fw_event_work *fw_event = NULL; + mtx_lock(&sc->mpi3mr_mtx); + while ((fw_event = TAILQ_FIRST(&sc->cam_sc->ev_queue)) != NULL) { + TAILQ_REMOVE(&sc->cam_sc->ev_queue, fw_event, ev_link); + mpi3mr_fw_event_free(sc, fw_event); + } + mtx_unlock(&sc->mpi3mr_mtx); +} + +static void +mpi3mr_sastopochg_evt_debug(struct mpi3mr_softc *sc, + Mpi3EventDataSasTopologyChangeList_t *event_data) +{ + int i; + U16 handle; + U8 reason_code, phy_number; + char *status_str = NULL; + U8 link_rate, prev_link_rate; + + switch (event_data->ExpStatus) { + case MPI3_EVENT_SAS_TOPO_ES_NOT_RESPONDING: + status_str = "remove"; + break; + case MPI3_EVENT_SAS_TOPO_ES_RESPONDING: + status_str = "responding"; + break; + case MPI3_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING: + status_str = "remove delay"; + break; + case MPI3_EVENT_SAS_TOPO_ES_NO_EXPANDER: + status_str = "direct attached"; + break; + default: + status_str = "unknown status"; + break; + } + + mpi3mr_dprint(sc, MPI3MR_INFO, "%s :sas topology change: (%s)\n", + __func__, status_str); + mpi3mr_dprint(sc, MPI3MR_INFO, + "%s :\texpander_handle(0x%04x), enclosure_handle(0x%04x) " + "start_phy(%02d), num_entries(%d)\n", __func__, + (event_data->ExpanderDevHandle), + (event_data->EnclosureHandle), + event_data->StartPhyNum, event_data->NumEntries); + for (i = 0; i < event_data->NumEntries; i++) { + handle = (event_data->PhyEntry[i].AttachedDevHandle); + if (!handle) + continue; + phy_number = event_data->StartPhyNum + i; + reason_code = event_data->PhyEntry[i].Status & + MPI3_EVENT_SAS_TOPO_PHY_RC_MASK; + switch (reason_code) { + case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING: + status_str = "target remove"; + break; + case MPI3_EVENT_SAS_TOPO_PHY_RC_DELAY_NOT_RESPONDING: + status_str = "delay target remove"; + break; + case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED: + status_str = "link rate change"; + break; + case MPI3_EVENT_SAS_TOPO_PHY_RC_NO_CHANGE: + status_str = "target responding"; + break; + default: + status_str = "unknown"; + break; + } + link_rate = event_data->PhyEntry[i].LinkRate >> 4; + prev_link_rate = event_data->PhyEntry[i].LinkRate & 0xF; + mpi3mr_dprint(sc, MPI3MR_INFO, "%s :\tphy(%02d), attached_handle(0x%04x): %s:" + " link rate: new(0x%02x), old(0x%02x)\n", __func__, + phy_number, handle, status_str, link_rate, prev_link_rate); + } +} + +static void +mpi3mr_process_sastopochg_evt(struct mpi3mr_softc *sc, struct mpi3mr_fw_event_work *fwevt) +{ + + Mpi3EventDataSasTopologyChangeList_t *event_data = + (Mpi3EventDataSasTopologyChangeList_t *)fwevt->event_data; + int i; + U16 handle; + U8 reason_code, link_rate; + struct mpi3mr_target *target = NULL; + + + mpi3mr_sastopochg_evt_debug(sc, event_data); + + for (i = 0; i < event_data->NumEntries; i++) { + handle = le16toh(event_data->PhyEntry[i].AttachedDevHandle); + link_rate = event_data->PhyEntry[i].LinkRate >> 4; + + if (!handle) + continue; + target = mpi3mr_find_target_by_dev_handle(sc->cam_sc, handle); + + if (!target) + continue; + + target->link_rate = link_rate; + reason_code = event_data->PhyEntry[i].Status & + MPI3_EVENT_SAS_TOPO_PHY_RC_MASK; + + switch (reason_code) { + case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING: + if (target->exposed_to_os) + mpi3mr_remove_device_from_os(sc, target->dev_handle); + mpi3mr_remove_device_from_list(sc, target, false); + break; + case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED: + break; + default: + break; + } + } + + /* + * refcount was incremented for this event in + * mpi3mr_evt_handler. Decrement it here because the event has + * been processed. + */ + mpi3mr_startup_decrement(sc->cam_sc); + return; +} + +static inline void +mpi3mr_logdata_evt_bh(struct mpi3mr_softc *sc, + struct mpi3mr_fw_event_work *fwevt) +{ + mpi3mr_app_save_logdata(sc, fwevt->event_data, + fwevt->event_data_size); +} + +static void +mpi3mr_pcietopochg_evt_debug(struct mpi3mr_softc *sc, + Mpi3EventDataPcieTopologyChangeList_t *event_data) +{ + int i; + U16 handle; + U16 reason_code; + U8 port_number; + char *status_str = NULL; + U8 link_rate, prev_link_rate; + + switch (event_data->SwitchStatus) { + case MPI3_EVENT_PCIE_TOPO_SS_NOT_RESPONDING: + status_str = "remove"; + break; + case MPI3_EVENT_PCIE_TOPO_SS_RESPONDING: + status_str = "responding"; + break; + case MPI3_EVENT_PCIE_TOPO_SS_DELAY_NOT_RESPONDING: + status_str = "remove delay"; + break; + case MPI3_EVENT_PCIE_TOPO_SS_NO_PCIE_SWITCH: + status_str = "direct attached"; + break; + default: + status_str = "unknown status"; + break; + } + mpi3mr_dprint(sc, MPI3MR_INFO, "%s :pcie topology change: (%s)\n", + __func__, status_str); + mpi3mr_dprint(sc, MPI3MR_INFO, + "%s :\tswitch_handle(0x%04x), enclosure_handle(0x%04x)" + "start_port(%02d), num_entries(%d)\n", __func__, + le16toh(event_data->SwitchDevHandle), + le16toh(event_data->EnclosureHandle), + event_data->StartPortNum, event_data->NumEntries); + for (i = 0; i < event_data->NumEntries; i++) { + handle = + le16toh(event_data->PortEntry[i].AttachedDevHandle); + if (!handle) + continue; + port_number = event_data->StartPortNum + i; + reason_code = event_data->PortEntry[i].PortStatus; + switch (reason_code) { + case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING: + status_str = "target remove"; + break; + case MPI3_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING: + status_str = "delay target remove"; + break; + case MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED: + status_str = "link rate change"; + break; + case MPI3_EVENT_PCIE_TOPO_PS_NO_CHANGE: + status_str = "target responding"; + break; + default: + status_str = "unknown"; + break; + } + link_rate = event_data->PortEntry[i].CurrentPortInfo & + MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK; + prev_link_rate = event_data->PortEntry[i].PreviousPortInfo & + MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK; + mpi3mr_dprint(sc, MPI3MR_INFO, "%s :\tport(%02d), attached_handle(0x%04x): %s:" + " link rate: new(0x%02x), old(0x%02x)\n", __func__, + port_number, handle, status_str, link_rate, prev_link_rate); + } +} + +static void mpi3mr_process_pcietopochg_evt(struct mpi3mr_softc *sc, + struct mpi3mr_fw_event_work *fwevt) +{ + Mpi3EventDataPcieTopologyChangeList_t *event_data = + (Mpi3EventDataPcieTopologyChangeList_t *)fwevt->event_data; + int i; + U16 handle; + U8 reason_code, link_rate; + struct mpi3mr_target *target = NULL; + + + mpi3mr_pcietopochg_evt_debug(sc, event_data); + + for (i = 0; i < event_data->NumEntries; i++) { + handle = + le16toh(event_data->PortEntry[i].AttachedDevHandle); + if (!handle) + continue; + target = mpi3mr_find_target_by_dev_handle(sc->cam_sc, handle); + if (!target) + continue; + + link_rate = event_data->PortEntry[i].CurrentPortInfo & + MPI3_EVENT_PCIE_TOPO_PI_RATE_MASK; + target->link_rate = link_rate; + + reason_code = event_data->PortEntry[i].PortStatus; + + switch (reason_code) { + case MPI3_EVENT_PCIE_TOPO_PS_NOT_RESPONDING: + if (target->exposed_to_os) + mpi3mr_remove_device_from_os(sc, target->dev_handle); + mpi3mr_remove_device_from_list(sc, target, false); + break; + case MPI3_EVENT_PCIE_TOPO_PS_PORT_CHANGED: + break; + default: + break; + } + } + + /* + * refcount was incremented for this event in + * mpi3mr_evt_handler. Decrement it here because the event has + * been processed. + */ + mpi3mr_startup_decrement(sc->cam_sc); + return; +} + +void mpi3mr_add_device(struct mpi3mr_softc *sc, U16 per_id) +{ + struct mpi3mr_target *target; + + mpi3mr_dprint(sc, MPI3MR_EVENT, + "Adding device(persistent id: 0x%x)\n", per_id); + + mpi3mr_startup_increment(sc->cam_sc); + target = mpi3mr_find_target_by_per_id(sc->cam_sc, per_id); + + if (!target) { + mpi3mr_dprint(sc, MPI3MR_INFO, "Not available in driver's" + "internal target list, persistent_id: %d\n", + per_id); + goto out; + } + + if (target->is_hidden) { + mpi3mr_dprint(sc, MPI3MR_EVENT, "Target is hidden, persistent_id: %d\n", + per_id); + goto out; + } + + if (!target->exposed_to_os && !sc->reset_in_progress) { + mpi3mr_rescan_target(sc, target); + mpi3mr_dprint(sc, MPI3MR_INFO, + "Added device persistent_id: %d dev_handle: %d\n", per_id, target->dev_handle); + target->exposed_to_os = 1; + } + +out: + mpi3mr_startup_decrement(sc->cam_sc); +} + +int mpi3mr_remove_device_from_os(struct mpi3mr_softc *sc, U16 handle) +{ + U32 i = 0; + int retval = 0; + struct mpi3mr_target *target; + + mpi3mr_dprint(sc, MPI3MR_EVENT, + "Removing Device (dev_handle: %d)\n", handle); + + target = mpi3mr_find_target_by_dev_handle(sc->cam_sc, handle); + + if (!target) { + mpi3mr_dprint(sc, MPI3MR_INFO, + "Device (persistent_id: %d dev_handle: %d) is already removed from driver's list\n", + target->per_id, handle); + mpi3mr_rescan_target(sc, NULL); + retval = -1; + goto out; + } + + target->flags |= MPI3MRSAS_TARGET_INREMOVAL; + + while (mpi3mr_atomic_read(&target->outstanding) && (i < 30)) { + i++; + if (!(i % 2)) { + mpi3mr_dprint(sc, MPI3MR_INFO, + "[%2d]waiting for " + "waiting for outstanding commands to complete on target: %d\n", + i, target->per_id); + } + DELAY(1000 * 1000); + } + + if (target->exposed_to_os && !sc->reset_in_progress) { + mpi3mr_rescan_target(sc, target); + mpi3mr_dprint(sc, MPI3MR_INFO, + "Removed device(persistent_id: %d dev_handle: %d)\n", target->per_id, handle); + target->exposed_to_os = 0; + } + + target->flags &= ~MPI3MRSAS_TARGET_INREMOVAL; +out: + return retval; +} + +void mpi3mr_remove_device_from_list(struct mpi3mr_softc *sc, + struct mpi3mr_target *target, bool must_delete) +{ + mtx_lock_spin(&sc->target_lock); + if ((target->state == MPI3MR_DEV_REMOVE_HS_STARTED) || + (must_delete == true)) { + TAILQ_REMOVE(&sc->cam_sc->tgt_list, target, tgt_next); + target->state = MPI3MR_DEV_DELETED; + } + mtx_unlock_spin(&sc->target_lock); + + if (target->state == MPI3MR_DEV_DELETED) { + free(target, M_MPI3MR); + target = NULL; + } + + return; +} + +/** + * mpi3mr_devstatuschg_evt_bh - DevStatusChange evt bottomhalf + * @sc: Adapter instance reference + * @fwevt: Firmware event + * + * Process Device Status Change event and based on device's new + * information, either expose the device to the upper layers, or + * remove the device from upper layers. + * + * Return: Nothing. + */ +static void mpi3mr_devstatuschg_evt_bh(struct mpi3mr_softc *sc, + struct mpi3mr_fw_event_work *fwevt) +{ + U16 dev_handle = 0; + U8 uhide = 0, delete = 0, cleanup = 0; + struct mpi3mr_target *tgtdev = NULL; + Mpi3EventDataDeviceStatusChange_t *evtdata = + (Mpi3EventDataDeviceStatusChange_t *)fwevt->event_data; + + + + dev_handle = le16toh(evtdata->DevHandle); + mpi3mr_dprint(sc, MPI3MR_INFO, + "%s :device status change: handle(0x%04x): reason code(0x%x)\n", + __func__, dev_handle, evtdata->ReasonCode); + switch (evtdata->ReasonCode) { + case MPI3_EVENT_DEV_STAT_RC_HIDDEN: + delete = 1; + break; + case MPI3_EVENT_DEV_STAT_RC_NOT_HIDDEN: + uhide = 1; + break; + case MPI3_EVENT_DEV_STAT_RC_VD_NOT_RESPONDING: + delete = 1; + cleanup = 1; + break; + default: + mpi3mr_dprint(sc, MPI3MR_INFO, "%s :Unhandled reason code(0x%x)\n", __func__, + evtdata->ReasonCode); + break; + } + + tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, dev_handle); + if (!tgtdev) + return; + + if (uhide) { + if (!tgtdev->exposed_to_os) + mpi3mr_add_device(sc, tgtdev->per_id); + } + + if (delete) + mpi3mr_remove_device_from_os(sc, dev_handle); + + if (cleanup) + mpi3mr_remove_device_from_list(sc, tgtdev, false); +} + +/** + * mpi3mr_devinfochg_evt_bh - DeviceInfoChange evt bottomhalf + * @sc: Adapter instance reference + * @dev_pg0: New device page0 + * + * Process Device Info Change event and based on device's new + * information, either expose the device to the upper layers, or + * remove the device from upper layers or update the details of + * the device. + * + * Return: Nothing. + */ +static void mpi3mr_devinfochg_evt_bh(struct mpi3mr_softc *sc, + Mpi3DevicePage0_t *dev_pg0) +{ + struct mpi3mr_target *tgtdev = NULL; + U16 dev_handle = 0, perst_id = 0; + + perst_id = le16toh(dev_pg0->PersistentID); + dev_handle = le16toh(dev_pg0->DevHandle); + mpi3mr_dprint(sc, MPI3MR_INFO, + "%s :Device info change: handle(0x%04x): persist_id(0x%x)\n", + __func__, dev_handle, perst_id); + tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, dev_handle); + if (!tgtdev) + return; + + mpi3mr_update_device(sc, tgtdev, dev_pg0, false); + if (!tgtdev->is_hidden && !tgtdev->exposed_to_os) + mpi3mr_add_device(sc, perst_id); + + if (tgtdev->is_hidden && tgtdev->exposed_to_os) + mpi3mr_remove_device_from_os(sc, tgtdev->dev_handle); +} + +static void +mpi3mr_fw_work(struct mpi3mr_softc *sc, struct mpi3mr_fw_event_work *fw_event) +{ + if (sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN) + goto out; + + if (!fw_event->process_event) + goto evt_ack; + + mpi3mr_dprint(sc, MPI3MR_EVENT, "(%d)->(%s) Working on Event: [%x]\n", + event_count++, __func__, fw_event->event); + + switch (fw_event->event) { + case MPI3_EVENT_DEVICE_ADDED: + { + Mpi3DevicePage0_t *dev_pg0 = + (Mpi3DevicePage0_t *) fw_event->event_data; + mpi3mr_add_device(sc, dev_pg0->PersistentID); + break; + } + case MPI3_EVENT_DEVICE_INFO_CHANGED: + { + mpi3mr_devinfochg_evt_bh(sc, + (Mpi3DevicePage0_t *) fw_event->event_data); + break; + } + case MPI3_EVENT_DEVICE_STATUS_CHANGE: + { + mpi3mr_devstatuschg_evt_bh(sc, fw_event); + break; + } + case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST: + { + mpi3mr_process_sastopochg_evt(sc, fw_event); + break; + } + case MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: + { + mpi3mr_process_pcietopochg_evt(sc, fw_event); + break; + } + case MPI3_EVENT_LOG_DATA: + { + mpi3mr_logdata_evt_bh(sc, fw_event); + break; + } + default: + mpi3mr_dprint(sc, MPI3MR_TRACE,"Unhandled event 0x%0X\n", + fw_event->event); + break; + + } + +evt_ack: + if (fw_event->send_ack) { + mpi3mr_dprint(sc, MPI3MR_EVENT,"Process event ACK for event 0x%0X\n", + fw_event->event); + mpi3mr_process_event_ack(sc, fw_event->event, + fw_event->event_context); + } + +out: + mpi3mr_dprint(sc, MPI3MR_EVENT, "(%d)->(%s) Event Free: [%x]\n", event_count, + __func__, fw_event->event); + + mpi3mr_fw_event_free(sc, fw_event); +} + +void +mpi3mr_firmware_event_work(void *arg, int pending) +{ + struct mpi3mr_fw_event_work *fw_event; + struct mpi3mr_softc *sc; + + sc = (struct mpi3mr_softc *)arg; + + mtx_lock(&sc->fwevt_lock); + while ((fw_event = TAILQ_FIRST(&sc->cam_sc->ev_queue)) != NULL) { + TAILQ_REMOVE(&sc->cam_sc->ev_queue, fw_event, ev_link); + mtx_unlock(&sc->fwevt_lock); + mpi3mr_fw_work(sc, fw_event); + mtx_lock(&sc->fwevt_lock); + } + mtx_unlock(&sc->fwevt_lock); +} + + +/* + * mpi3mr_cam_attach - CAM layer registration + * @sc: Adapter reference + * + * This function does simq allocation, cam registration, xpt_bus registration, + * event taskqueue initialization and async event handler registration. + * + * Return: 0 on success and proper error codes on failure + */ +int +mpi3mr_cam_attach(struct mpi3mr_softc *sc) +{ + struct mpi3mr_cam_softc *cam_sc; + cam_status status; + int unit, error = 0, reqs; + + mpi3mr_dprint(sc, MPI3MR_XINFO, "Starting CAM Attach\n"); + + cam_sc = malloc(sizeof(struct mpi3mr_cam_softc), M_MPI3MR, M_WAITOK|M_ZERO); + if (!cam_sc) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "Failed to allocate memory for controller CAM instance\n"); + return (ENOMEM); + } + + cam_sc->maxtargets = sc->facts.max_perids + 1; + + TAILQ_INIT(&cam_sc->tgt_list); + + sc->cam_sc = cam_sc; + cam_sc->sc = sc; + + reqs = sc->max_host_ios; + + if ((cam_sc->devq = cam_simq_alloc(reqs)) == NULL) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate SIMQ\n"); + error = ENOMEM; + goto out; + } + + unit = device_get_unit(sc->mpi3mr_dev); + cam_sc->sim = cam_sim_alloc(mpi3mr_cam_action, mpi3mr_cam_poll, "mpi3mr", cam_sc, + unit, &sc->mpi3mr_mtx, reqs, reqs, cam_sc->devq); + if (cam_sc->sim == NULL) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate SIM\n"); + error = EINVAL; + goto out; + } + + TAILQ_INIT(&cam_sc->ev_queue); + + /* Initialize taskqueue for Event Handling */ + TASK_INIT(&cam_sc->ev_task, 0, mpi3mr_firmware_event_work, sc); + cam_sc->ev_tq = taskqueue_create("mpi3mr_taskq", M_NOWAIT | M_ZERO, + taskqueue_thread_enqueue, &cam_sc->ev_tq); + taskqueue_start_threads(&cam_sc->ev_tq, 1, PRIBIO, "%s taskq", + device_get_nameunit(sc->mpi3mr_dev)); + + mtx_lock(&sc->mpi3mr_mtx); + + /* + * XXX There should be a bus for every port on the adapter, but since + * we're just going to fake the topology for now, we'll pretend that + * everything is just a target on a single bus. + */ + if ((error = xpt_bus_register(cam_sc->sim, sc->mpi3mr_dev, 0)) != 0) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "Error 0x%x registering SCSI bus\n", error); + mtx_unlock(&sc->mpi3mr_mtx); + goto out; + } + + /* + * Assume that discovery events will start right away. + * + * Hold off boot until discovery is complete. + */ + cam_sc->flags |= MPI3MRSAS_IN_STARTUP | MPI3MRSAS_IN_DISCOVERY; + sc->cam_sc->startup_refcount = 0; + mpi3mr_startup_increment(cam_sc); + + callout_init(&cam_sc->discovery_callout, 1 /*mpsafe*/); + + /* + * Register for async events so we can determine the EEDP + * capabilities of devices. + */ + status = xpt_create_path(&cam_sc->path, /*periph*/NULL, + cam_sim_path(sc->cam_sc->sim), CAM_TARGET_WILDCARD, + CAM_LUN_WILDCARD); + if (status != CAM_REQ_CMP) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "Error 0x%x creating sim path\n", status); + cam_sc->path = NULL; + } + + if (status != CAM_REQ_CMP) { + /* + * EEDP use is the exception, not the rule. + * Warn the user, but do not fail to attach. + */ + mpi3mr_dprint(sc, MPI3MR_INFO, "EEDP capabilities disabled.\n"); + } + + mtx_unlock(&sc->mpi3mr_mtx); + + error = mpi3mr_register_events(sc); + +out: + mpi3mr_dprint(sc, MPI3MR_XINFO, "%s Exiting CAM attach, error: 0x%x n", __func__, error); + return (error); +} + +int +mpi3mr_cam_detach(struct mpi3mr_softc *sc) +{ + struct mpi3mr_cam_softc *cam_sc; + struct mpi3mr_target *target; + + mpi3mr_dprint(sc, MPI3MR_XINFO, "%s, Starting CAM detach\n", __func__); + if (sc->cam_sc == NULL) + return (0); + + cam_sc = sc->cam_sc; + + mpi3mr_freeup_events(sc); + + /* + * Drain and free the event handling taskqueue with the lock + * unheld so that any parallel processing tasks drain properly + * without deadlocking. + */ + if (cam_sc->ev_tq != NULL) + taskqueue_free(cam_sc->ev_tq); + + mtx_lock(&sc->mpi3mr_mtx); + + while (cam_sc->startup_refcount != 0) + mpi3mr_startup_decrement(cam_sc); + + /* Deregister our async handler */ + if (cam_sc->path != NULL) { + xpt_free_path(cam_sc->path); + cam_sc->path = NULL; + } + + if (cam_sc->flags & MPI3MRSAS_IN_STARTUP) + xpt_release_simq(cam_sc->sim, 1); + + if (cam_sc->sim != NULL) { + xpt_bus_deregister(cam_sim_path(cam_sc->sim)); + cam_sim_free(cam_sc->sim, FALSE); + } + + mtx_unlock(&sc->mpi3mr_mtx); + + if (cam_sc->devq != NULL) + cam_simq_free(cam_sc->devq); + +get_target: + mtx_lock_spin(&sc->target_lock); + TAILQ_FOREACH(target, &cam_sc->tgt_list, tgt_next) { + TAILQ_REMOVE(&sc->cam_sc->tgt_list, target, tgt_next); + mtx_unlock_spin(&sc->target_lock); + goto out_tgt_free; + } + mtx_unlock_spin(&sc->target_lock); +out_tgt_free: + if (target) { + free(target, M_MPI3MR); + target = NULL; + goto get_target; + } + + free(cam_sc, M_MPI3MR); + sc->cam_sc = NULL; + + mpi3mr_dprint(sc, MPI3MR_XINFO, "%s, Exiting CAM detach\n", __func__); + return (0); +} diff --git a/sys/dev/mpi3mr/mpi3mr_cam.h b/sys/dev/mpi3mr/mpi3mr_cam.h new file mode 100644 index 000000000000..4f3ce47751e9 --- /dev/null +++ b/sys/dev/mpi3mr/mpi3mr_cam.h @@ -0,0 +1,199 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2020-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Authors: Sumit Saxena + * Chandrakanth Patil + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + */ +#include "mpi3mr.h" + +struct mpi3mr_fw_event_work; + +struct mpi3mr_throttle_group_info { + U8 io_divert; + U16 fw_qd; + U16 modified_qd; + U16 id; + U32 high; + U32 low; + mpi3mr_atomic_t pend_large_data_sz; +}; + +struct mpi3mr_tgt_dev_sassata { + U64 sas_address; + U16 dev_info; +}; + +struct mpi3mr_tgt_dev_pcie { + U32 mdts; + U16 capb; + U8 pgsz; + U8 abort_to; + U8 reset_to; + U16 dev_info; +}; + +struct mpi3mr_tgt_dev_volume { + U8 state; + U16 tg_id; + U32 tg_high; + U32 tg_low; + struct mpi3mr_throttle_group_info *tg; +}; + +typedef union _mpi3mr_form_spec_inf { + struct mpi3mr_tgt_dev_sassata sassata_inf; + struct mpi3mr_tgt_dev_pcie pcie_inf; + struct mpi3mr_tgt_dev_volume vol_inf; +} mpi3mr_form_spec_inf; + +struct mpi3mr_target { + uint16_t dev_handle; + uint16_t slot; + uint16_t per_id; + uint8_t dev_type; + volatile uint8_t is_hidden; + volatile uint8_t dev_removed; + U8 dev_removedelay; + mpi3mr_atomic_t block_io; + uint8_t exposed_to_os; + uint16_t qdepth; + uint64_t wwid; + mpi3mr_form_spec_inf dev_spec; + uint16_t tid; + uint16_t exp_dev_handle; + uint16_t phy_num; + uint64_t sasaddr; + uint16_t parent_handle; + uint64_t parent_sasaddr; + uint32_t parent_devinfo; + mpi3mr_atomic_t outstanding; + uint8_t scsi_req_desc_type; + TAILQ_ENTRY(mpi3mr_target) tgt_next; + uint16_t handle; + uint8_t link_rate; + uint8_t encl_level_valid; + uint8_t encl_level; + char connector_name[4]; + uint64_t devname; + uint32_t devinfo; + uint16_t encl_handle; + uint16_t encl_slot; + uint8_t flags; +#define MPI3MRSAS_TARGET_INREMOVAL (1 << 3) + uint8_t io_throttle_enabled; + uint8_t io_divert; + struct mpi3mr_throttle_group_info *throttle_group; + uint64_t q_depth; + enum mpi3mr_target_state state; +}; + +struct mpi3mr_cam_softc { + struct mpi3mr_softc *sc; + u_int flags; +#define MPI3MRSAS_IN_DISCOVERY (1 << 0) +#define MPI3MRSAS_IN_STARTUP (1 << 1) +#define MPI3MRSAS_DISCOVERY_TIMEOUT_PENDING (1 << 2) +#define MPI3MRSAS_QUEUE_FROZEN (1 << 3) +#define MPI3MRSAS_SHUTDOWN (1 << 4) + u_int maxtargets; + struct cam_devq *devq; + struct cam_sim *sim; + struct cam_path *path; + struct intr_config_hook sas_ich; + struct callout discovery_callout; + struct mpi3mr_event_handle *mpi3mr_eh; + + u_int startup_refcount; + struct proc *sysctl_proc; + struct taskqueue *ev_tq; + struct task ev_task; + TAILQ_HEAD(, mpi3mr_fw_event_work) ev_queue; + TAILQ_HEAD(, mpi3mr_target) tgt_list; +}; + +MALLOC_DECLARE(M_MPI3MRSAS); + +static __inline void +mpi3mr_set_ccbstatus(union ccb *ccb, int status) +{ + ccb->ccb_h.status &= ~CAM_STATUS_MASK; + ccb->ccb_h.status |= status; +} + +static __inline int +mpi3mr_get_ccbstatus(union ccb *ccb) +{ + return (ccb->ccb_h.status & CAM_STATUS_MASK); +} + +static __inline void mpi3mr_print_cdb(union ccb *ccb) +{ + struct ccb_scsiio *csio; + struct mpi3mr_cam_softc *cam_sc; + struct cam_sim *sim; + int i; + + sim = xpt_path_sim(ccb->ccb_h.path); + cam_sc = cam_sim_softc(sim); + + csio = &ccb->csio; + + mpi3mr_dprint(cam_sc->sc, MPI3MR_INFO, "tgtID: %d CDB: ", csio->ccb_h.target_id); + for (i = 0; i < csio->cdb_len; i++) + printf("%x ", csio->cdb_io.cdb_bytes[i]); + + printf("\n"); +} + +void mpi3mr_rescan_target(struct mpi3mr_softc *sc, struct mpi3mr_target *targ); +void mpi3mr_discovery_end(struct mpi3mr_cam_softc *sassc); +void mpi3mr_prepare_for_tm(struct mpi3mr_softc *sc, struct mpi3mr_cmd *tm, + struct mpi3mr_target *target, lun_id_t lun_id); +void mpi3mr_startup_increment(struct mpi3mr_cam_softc *sassc); +void mpi3mr_startup_decrement(struct mpi3mr_cam_softc *sassc); + +void mpi3mr_firmware_event_work(void *arg, int pending); +int mpi3mr_check_id(struct mpi3mr_cam_softc *sassc, int id); +int +mpi3mr_cam_attach(struct mpi3mr_softc *sc); +int +mpi3mr_cam_detach(struct mpi3mr_softc *sc); +void +mpi3mr_evt_handler(struct mpi3mr_softc *sc, uintptr_t data, + MPI3_EVENT_NOTIFICATION_REPLY *event); diff --git a/sys/dev/mpi3mr/mpi3mr_pci.c b/sys/dev/mpi3mr/mpi3mr_pci.c new file mode 100644 index 000000000000..d7278e5549e7 --- /dev/null +++ b/sys/dev/mpi3mr/mpi3mr_pci.c @@ -0,0 +1,698 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2020-2023, Broadcom Inc. All rights reserved. + * Support: + * + * Authors: Sumit Saxena + * Chandrakanth Patil + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of the Broadcom Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies,either expressed or implied, of the FreeBSD Project. + * + * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 + * + * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD + */ + +#include "mpi3mr.h" +#include "mpi3mr_cam.h" +#include "mpi3mr_app.h" + +static int sc_ids; +static int mpi3mr_pci_probe(device_t); +static int mpi3mr_pci_attach(device_t); +static int mpi3mr_pci_detach(device_t); +static int mpi3mr_pci_suspend(device_t); +static int mpi3mr_pci_resume(device_t); +static int mpi3mr_setup_resources(struct mpi3mr_softc *sc); +static void mpi3mr_release_resources(struct mpi3mr_softc *); +static void mpi3mr_teardown_irqs(struct mpi3mr_softc *sc); + +extern void mpi3mr_watchdog_thread(void *arg); + +static device_method_t mpi3mr_methods[] = { + DEVMETHOD(device_probe, mpi3mr_pci_probe), + DEVMETHOD(device_attach, mpi3mr_pci_attach), + DEVMETHOD(device_detach, mpi3mr_pci_detach), + DEVMETHOD(device_suspend, mpi3mr_pci_suspend), + DEVMETHOD(device_resume, mpi3mr_pci_resume), + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_driver_added, bus_generic_driver_added), + { 0, 0 } +}; + +char fmt_os_ver[16]; + +SYSCTL_NODE(_hw, OID_AUTO, mpi3mr, CTLFLAG_RD, 0, "MPI3MR Driver Parameters"); +MALLOC_DEFINE(M_MPI3MR, "mpi3mrbuf", "Buffers for the MPI3MR driver"); + +static driver_t mpi3mr_pci_driver = { + "mpi3mr", + mpi3mr_methods, + sizeof(struct mpi3mr_softc) +}; + +struct mpi3mr_ident { + uint16_t vendor; + uint16_t device; + uint16_t subvendor; + uint16_t subdevice; + u_int flags; + const char *desc; +} mpi3mr_identifiers[] = { + { MPI3_MFGPAGE_VENDORID_BROADCOM, MPI3_MFGPAGE_DEVID_SAS4116, + 0xffff, 0xffff, 0, "Broadcom MPIMR 3.0 controller" }, +}; + +DRIVER_MODULE(mpi3mr, pci, mpi3mr_pci_driver, 0, 0); +MODULE_PNP_INFO("U16:vendor;U16:device;U16:subvendor;U16:subdevice;D:#", pci, + mpi3mr, mpi3mr_identifiers, nitems(mpi3mr_identifiers) - 1); + +MODULE_DEPEND(mpi3mr, cam, 1, 1, 1); + +/* + * mpi3mr_setup_sysctl: setup sysctl values for mpi3mr + * input: Adapter instance soft state + * + * Setup sysctl entries for mpi3mr driver. + */ +static void +mpi3mr_setup_sysctl(struct mpi3mr_softc *sc) +{ + struct sysctl_ctx_list *sysctl_ctx = NULL; + struct sysctl_oid *sysctl_tree = NULL; + char tmpstr[80], tmpstr2[80]; + + /* + * Setup the sysctl variable so the user can change the debug level + * on the fly. + */ + snprintf(tmpstr, sizeof(tmpstr), "MPI3MR controller %d", + device_get_unit(sc->mpi3mr_dev)); + snprintf(tmpstr2, sizeof(tmpstr2), "%d", device_get_unit(sc->mpi3mr_dev)); + + sysctl_ctx = device_get_sysctl_ctx(sc->mpi3mr_dev); + if (sysctl_ctx != NULL) + sysctl_tree = device_get_sysctl_tree(sc->mpi3mr_dev); + + if (sysctl_tree == NULL) { + sysctl_ctx_init(&sc->sysctl_ctx); + sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_hw_mpi3mr), OID_AUTO, tmpstr2, + CTLFLAG_RD, 0, tmpstr); + if (sc->sysctl_tree == NULL) + return; + sysctl_ctx = &sc->sysctl_ctx; + sysctl_tree = sc->sysctl_tree; + } + + SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "driver_version", CTLFLAG_RD, MPI3MR_DRIVER_VERSION, + strlen(MPI3MR_DRIVER_VERSION), "driver version"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "fw_outstanding", CTLFLAG_RD, + &sc->fw_outstanding.val_rdonly, 0, "FW outstanding commands"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "io_cmds_highwater", CTLFLAG_RD, + &sc->io_cmds_highwater, 0, "Max FW outstanding commands"); + + SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "mpi3mr_debug", CTLFLAG_RW, &sc->mpi3mr_debug, 0, + "Driver debug level"); + SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "reset", CTLFLAG_RW, &sc->reset.type, 0, + "Soft reset(1)/Diag reset(2)"); + SYSCTL_ADD_UINT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "iot_enable", CTLFLAG_RW, &sc->iot_enable, 0, + "IO throttling enable at driver level(for debug purpose)"); +} + +/* + * mpi3mr_get_tunables: get tunable parameters. + * input: Adapter instance soft state + * + * Get tunable parameters. This will help to debug driver at boot time. + */ +static void +mpi3mr_get_tunables(struct mpi3mr_softc *sc) +{ + char tmpstr[80]; + + sc->mpi3mr_debug = + (MPI3MR_ERROR | MPI3MR_INFO | MPI3MR_FAULT); + + sc->reset_in_progress = 0; + sc->reset.type = 0; + sc->iot_enable = 1; + /* + * Grab the global variables. + */ + TUNABLE_INT_FETCH("hw.mpi3mr.debug_level", &sc->mpi3mr_debug); + TUNABLE_INT_FETCH("hw.mpi3mr.ctrl_reset", &sc->reset.type); + TUNABLE_INT_FETCH("hw.mpi3mr.iot_enable", &sc->iot_enable); + + /* Grab the unit-instance variables */ + snprintf(tmpstr, sizeof(tmpstr), "dev.mpi3mr.%d.debug_level", + device_get_unit(sc->mpi3mr_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->mpi3mr_debug); + + snprintf(tmpstr, sizeof(tmpstr), "dev.mpi3mr.%d.reset", + device_get_unit(sc->mpi3mr_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->reset.type); + + snprintf(tmpstr, sizeof(tmpstr), "dev.mpi3mr.%d.iot_enable", + device_get_unit(sc->mpi3mr_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->iot_enable); +} + +static struct mpi3mr_ident * +mpi3mr_find_ident(device_t dev) +{ + struct mpi3mr_ident *m; + + for (m = mpi3mr_identifiers; m->vendor != 0; m++) { + if (m->vendor != pci_get_vendor(dev)) + continue; + if (m->device != pci_get_device(dev)) + continue; + if ((m->subvendor != 0xffff) && + (m->subvendor != pci_get_subvendor(dev))) + continue; + if ((m->subdevice != 0xffff) && + (m->subdevice != pci_get_subdevice(dev))) + continue; + return (m); + } + + return (NULL); +} + +static int +mpi3mr_pci_probe(device_t dev) +{ + static u_int8_t first_ctrl = 1; + struct mpi3mr_ident *id; + char raw_os_ver[16]; + + if ((id = mpi3mr_find_ident(dev)) != NULL) { + if (first_ctrl) { + first_ctrl = 0; + MPI3MR_OS_VERSION(raw_os_ver, fmt_os_ver); + printf("mpi3mr: Loading Broadcom mpi3mr driver version: %s OS version: %s\n", + MPI3MR_DRIVER_VERSION, fmt_os_ver); + } + device_set_desc(dev, id->desc); + device_set_desc(dev, id->desc); + return (BUS_PROBE_DEFAULT); + } + return (ENXIO); +} + +static void +mpi3mr_release_resources(struct mpi3mr_softc *sc) +{ + if (sc->mpi3mr_parent_dmat != NULL) { + bus_dma_tag_destroy(sc->mpi3mr_parent_dmat); + } + + if (sc->mpi3mr_regs_resource != NULL) { + bus_release_resource(sc->mpi3mr_dev, SYS_RES_MEMORY, + sc->mpi3mr_regs_rid, sc->mpi3mr_regs_resource); + } +} + +static int mpi3mr_setup_resources(struct mpi3mr_softc *sc) +{ + int i; + device_t dev = sc->mpi3mr_dev; + + pci_enable_busmaster(dev); + + for (i = 0; i < PCI_MAXMAPS_0; i++) { + sc->mpi3mr_regs_rid = PCIR_BAR(i); + + if ((sc->mpi3mr_regs_resource = bus_alloc_resource_any(dev, + SYS_RES_MEMORY, &sc->mpi3mr_regs_rid, RF_ACTIVE)) != NULL) + break; + } + + if (sc->mpi3mr_regs_resource == NULL) { + mpi3mr_printf(sc, "Cannot allocate PCI registers\n"); + return (ENXIO); + } + + sc->mpi3mr_btag = rman_get_bustag(sc->mpi3mr_regs_resource); + sc->mpi3mr_bhandle = rman_get_bushandle(sc->mpi3mr_regs_resource); + + /* Allocate the parent DMA tag */ + if (bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ + 1, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ + BUS_SPACE_UNRESTRICTED, /* nsegments */ + BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->mpi3mr_parent_dmat)) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate parent DMA tag\n"); + return (ENOMEM); + } + + sc->max_msix_vectors = pci_msix_count(dev); + + return 0; +} + +static int +mpi3mr_startup(struct mpi3mr_softc *sc) +{ + sc->mpi3mr_flags &= ~MPI3MR_FLAGS_PORT_ENABLE_DONE; + mpi3mr_issue_port_enable(sc, 1); + return (0); +} + +/* Run through any late-start handlers. */ +static void +mpi3mr_ich_startup(void *arg) +{ + struct mpi3mr_softc *sc; + + sc = (struct mpi3mr_softc *)arg; + mpi3mr_dprint(sc, MPI3MR_XINFO, "%s entry\n", __func__); + + mtx_lock(&sc->mpi3mr_mtx); + + mpi3mr_startup(sc); + mtx_unlock(&sc->mpi3mr_mtx); + + mpi3mr_dprint(sc, MPI3MR_XINFO, "disestablish config intrhook\n"); + config_intrhook_disestablish(&sc->mpi3mr_ich); + sc->mpi3mr_ich.ich_arg = NULL; + + mpi3mr_dprint(sc, MPI3MR_XINFO, "%s exit\n", __func__); +} + +/** + * mpi3mr_ctrl_security_status -Check controller secure status + * @pdev: PCI device instance + * + * Read the Device Serial Number capability from PCI config + * space and decide whether the controller is secure or not. + * + * Return: 0 on success, non-zero on failure. + */ +static int +mpi3mr_ctrl_security_status(device_t dev) +{ + int dev_serial_num, retval = 0; + uint32_t cap_data, ctrl_status, debug_status; + /* Check if Device serial number extended capability is supported */ + if (pci_find_extcap(dev, PCIZ_SERNUM, &dev_serial_num) != 0) { + device_printf(dev, + "PCIZ_SERNUM is not supported\n"); + return -1; + } + + cap_data = pci_read_config(dev, dev_serial_num + 4, 4); + + debug_status = cap_data & MPI3MR_CTLR_SECURE_DBG_STATUS_MASK; + ctrl_status = cap_data & MPI3MR_CTLR_SECURITY_STATUS_MASK; + + switch (ctrl_status) { + case MPI3MR_INVALID_DEVICE: + device_printf(dev, + "Invalid (Non secure) controller is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n", + pci_get_device(dev), pci_get_subvendor(dev), + pci_get_subdevice(dev)); + retval = -1; + break; + case MPI3MR_CONFIG_SECURE_DEVICE: + if (!debug_status) + device_printf(dev, "Config secure controller is detected\n"); + break; + case MPI3MR_HARD_SECURE_DEVICE: + device_printf(dev, "Hard secure controller is detected\n"); + break; + case MPI3MR_TAMPERED_DEVICE: + device_printf(dev, + "Tampered (Non secure) controller is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n", + pci_get_device(dev), pci_get_subvendor(dev), + pci_get_subdevice(dev)); + retval = -1; + break; + default: + retval = -1; + break; + } + + if (!retval && debug_status) { + device_printf(dev, + "Secure Debug (Non secure) controller is detected: DID: 0x%x: SVID: 0x%x: SDID: 0x%x\n", + pci_get_device(dev), pci_get_subvendor(dev), + pci_get_subdevice(dev)); + retval = -1; + } + + return retval; +} +/* + * mpi3mr_pci_attach - PCI entry point + * @dev: pointer to device struct + * + * This function does the setup of PCI and registers, allocates controller resources, + * initializes mutexes, linked lists and registers interrupts, CAM and initializes + * the controller. + * + * Return: 0 on success and proper error codes on failure + */ +static int +mpi3mr_pci_attach(device_t dev) +{ + struct mpi3mr_softc *sc; + int error; + + sc = device_get_softc(dev); + bzero(sc, sizeof(*sc)); + sc->mpi3mr_dev = dev; + + /* Don't load driver for Non-Secure controllers */ + if (mpi3mr_ctrl_security_status(dev)) { + sc->secure_ctrl = false; + return 0; + } + + sc->secure_ctrl = true; + + if ((error = mpi3mr_setup_resources(sc)) != 0) + goto load_failed; + + sc->id = sc_ids++; + mpi3mr_atomic_set(&sc->fw_outstanding, 0); + mpi3mr_atomic_set(&sc->pend_ioctls, 0); + sc->admin_req = NULL; + sc->admin_reply = NULL; + sprintf(sc->driver_name, "%s", MPI3MR_DRIVER_NAME); + sprintf(sc->name, "%s%d", sc->driver_name, sc->id); + + sc->mpi3mr_dev = dev; + mpi3mr_get_tunables(sc); + + if ((error = mpi3mr_initialize_ioc(sc, MPI3MR_INIT_TYPE_INIT)) != 0) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "FW initialization failed\n"); + goto load_failed; + } + + if ((error = mpi3mr_alloc_requests(sc)) != 0) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Command frames allocation failed\n"); + goto load_failed; + } + + if ((error = mpi3mr_cam_attach(sc)) != 0) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "CAM attach failed\n"); + goto load_failed; + } + + error = mpi3mr_kproc_create(mpi3mr_watchdog_thread, sc, + &sc->watchdog_thread, 0, 0, "mpi3mr_watchdog%d", + device_get_unit(sc->mpi3mr_dev)); + if (error) { + device_printf(sc->mpi3mr_dev, "Error %d starting OCR thread\n", error); + goto load_failed; + } + + sc->mpi3mr_ich.ich_func = mpi3mr_ich_startup; + sc->mpi3mr_ich.ich_arg = sc; + if (config_intrhook_establish(&sc->mpi3mr_ich) != 0) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "Cannot establish MPI3MR ICH config hook\n"); + error = EINVAL; + } + + mpi3mr_dprint(sc, MPI3MR_INFO, "allocating ioctl dma buffers\n"); + mpi3mr_alloc_ioctl_dma_memory(sc); + + if ((error = mpi3mr_app_attach(sc)) != 0) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "APP/IOCTL attach failed\n"); + goto load_failed; + } + + mpi3mr_setup_sysctl(sc); + + return 0; + +load_failed: + mpi3mr_cleanup_interrupts(sc); + mpi3mr_free_mem(sc); + mpi3mr_app_detach(sc); + mpi3mr_cam_detach(sc); + mpi3mr_destory_mtx(sc); + mpi3mr_release_resources(sc); + return error; +} + +void mpi3mr_cleanup_interrupts(struct mpi3mr_softc *sc) +{ + mpi3mr_disable_interrupts(sc); + + mpi3mr_teardown_irqs(sc); + + if (sc->irq_ctx) { + free(sc->irq_ctx, M_MPI3MR); + sc->irq_ctx = NULL; + } + + if (sc->msix_enable) + pci_release_msi(sc->mpi3mr_dev); + + sc->msix_count = 0; + +} + +int mpi3mr_setup_irqs(struct mpi3mr_softc *sc) +{ + device_t dev; + int error; + int i, rid, initial_rid; + struct mpi3mr_irq_context *irq_ctx; + struct irq_info *irq_info; + + dev = sc->mpi3mr_dev; + error = -1; + + if (sc->msix_enable) + initial_rid = 1; + else + initial_rid = 0; + + for (i = 0; i < sc->msix_count; i++) { + irq_ctx = &sc->irq_ctx[i]; + irq_ctx->msix_index = i; + irq_ctx->sc = sc; + irq_info = &irq_ctx->irq_info; + rid = i + initial_rid; + irq_info->irq_rid = rid; + irq_info->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &irq_info->irq_rid, RF_ACTIVE); + if (irq_info->irq == NULL) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "Cannot allocate interrupt RID %d\n", rid); + sc->msix_count = i; + break; + } + error = bus_setup_intr(dev, irq_info->irq, + INTR_MPSAFE | INTR_TYPE_CAM, NULL, mpi3mr_isr, + irq_ctx, &irq_info->intrhand); + if (error) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "Cannot setup interrupt RID %d\n", rid); + sc->msix_count = i; + break; + } + } + + mpi3mr_dprint(sc, MPI3MR_INFO, "Set up %d MSI-x interrupts\n", sc->msix_count); + + return (error); + +} + +static void +mpi3mr_teardown_irqs(struct mpi3mr_softc *sc) +{ + struct irq_info *irq_info; + int i; + + for (i = 0; i < sc->msix_count; i++) { + irq_info = &sc->irq_ctx[i].irq_info; + if (irq_info->irq != NULL) { + bus_teardown_intr(sc->mpi3mr_dev, irq_info->irq, + irq_info->intrhand); + bus_release_resource(sc->mpi3mr_dev, SYS_RES_IRQ, + irq_info->irq_rid, irq_info->irq); + } + } + +} + +/* + * Allocate, but don't assign interrupts early. Doing it before requesting + * the IOCFacts message informs the firmware that we want to do MSI-X + * multiqueue. We might not use all of the available messages, but there's + * no reason to re-alloc if we don't. + */ +int +mpi3mr_alloc_interrupts(struct mpi3mr_softc *sc, U16 setup_one) +{ + int error, msgs; + U16 num_queues; + + error = 0; + msgs = 0; + + mpi3mr_cleanup_interrupts(sc); + + if (setup_one) { + msgs = 1; + } else { + msgs = min(sc->max_msix_vectors, sc->cpu_count); + num_queues = min(sc->facts.max_op_reply_q, sc->facts.max_op_req_q); + msgs = min(msgs, num_queues); + + mpi3mr_dprint(sc, MPI3MR_INFO, "Supported MSI-x count: %d " + " CPU count: %d Requested MSI-x count: %d\n", + sc->max_msix_vectors, + sc->cpu_count, msgs); + } + + if (msgs != 0) { + error = pci_alloc_msix(sc->mpi3mr_dev, &msgs); + if (error) { + mpi3mr_dprint(sc, MPI3MR_ERROR, + "Could not allocate MSI-x interrupts Error: %x\n", error); + goto out_failed; + } else + sc->msix_enable = 1; + } + + sc->msix_count = msgs; + sc->irq_ctx = malloc(sizeof(struct mpi3mr_irq_context) * msgs, + M_MPI3MR, M_NOWAIT | M_ZERO); + + if (!sc->irq_ctx) { + mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot alloc memory for interrupt info\n"); + error = -1; + goto out_failed; + } + + mpi3mr_dprint(sc, MPI3MR_XINFO, "Allocated %d MSI-x interrupts\n", msgs); + + return error; +out_failed: + mpi3mr_cleanup_interrupts(sc); + return (error); +} + +static int +mpi3mr_pci_detach(device_t dev) +{ + struct mpi3mr_softc *sc; + int i = 0; + + sc = device_get_softc(dev); + + if (!sc->secure_ctrl) + return 0; + + sc->mpi3mr_flags |= MPI3MR_FLAGS_SHUTDOWN; + + if (sc->sysctl_tree != NULL) + sysctl_ctx_free(&sc->sysctl_ctx); + + if (sc->watchdog_thread_active) + wakeup(&sc->watchdog_chan); + + while (sc->reset_in_progress && (i < PEND_IOCTLS_COMP_WAIT_TIME)) { + i++; + if (!(i % 5)) { + mpi3mr_dprint(sc, MPI3MR_INFO, + "[%2d]waiting for reset to be finished from %s\n", i, __func__); + } + pause("mpi3mr_shutdown", hz); + } + + i = 0; + while (sc->watchdog_thread_active && (i < 180)) { + i++; + if (!(i % 5)) { + mpi3mr_dprint(sc, MPI3MR_INFO, + "[%2d]waiting for " + "mpi3mr_reset thread to quit reset %d\n", i, + sc->watchdog_thread_active); + } + pause("mpi3mr_shutdown", hz); + } + + i = 0; + while (mpi3mr_atomic_read(&sc->pend_ioctls) && (i < 180)) { + i++; + if (!(i % 5)) { + mpi3mr_dprint(sc, MPI3MR_INFO, + "[%2d]waiting for IOCTL to be finished from %s\n", i, __func__); + } + pause("mpi3mr_shutdown", hz); + } + + mpi3mr_cleanup_ioc(sc); + mpi3mr_cleanup_event_taskq(sc); + mpi3mr_app_detach(sc); + mpi3mr_cam_detach(sc); + mpi3mr_cleanup_interrupts(sc); + mpi3mr_destory_mtx(sc); + mpi3mr_free_mem(sc); + mpi3mr_release_resources(sc); + sc_ids--; + return (0); +} + +static int +mpi3mr_pci_suspend(device_t dev) +{ + return (EINVAL); +} + +static int +mpi3mr_pci_resume(device_t dev) +{ + return (EINVAL); +} diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 340d6f61a2b6..54c98491228f 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -1,909 +1,915 @@ # $FreeBSD$ SYSDIR?=${SRCTOP}/sys .include "${SYSDIR}/conf/kern.opts.mk" SUBDIR_PARALLEL= # Modules that include binary-only blobs of microcode should be selectable by # MK_SOURCELESS_UCODE option (see below). .include "${SYSDIR}/conf/config.mk" .if defined(MODULES_OVERRIDE) && !defined(ALL_MODULES) SUBDIR=${MODULES_OVERRIDE} .else SUBDIR= \ ${_3dfx} \ ${_3dfx_linux} \ ${_aac} \ ${_aacraid} \ accf_data \ accf_dns \ accf_http \ acl_nfs4 \ acl_posix1e \ ${_acpi} \ ae \ ${_aesni} \ age \ ${_agp} \ ahci \ aic7xxx \ alc \ ale \ alq \ ${_amd_ecc_inject} \ ${_amdgpio} \ ${_amdsbwd} \ ${_amdsmn} \ ${_amdtemp} \ ${_aout} \ ${_arcmsr} \ ${_allwinner} \ ${_armv8crypto} \ ${_asmc} \ ata \ ath \ ath_dfs \ ath_hal \ ath_hal_ar5210 \ ath_hal_ar5211 \ ath_hal_ar5212 \ ath_hal_ar5416 \ ath_hal_ar9300 \ ath_main \ ath_rate \ ath_pci \ ${_autofs} \ axgbe \ backlight \ ${_bce} \ ${_bcm283x_clkman} \ ${_bcm283x_pwm} \ bfe \ bge \ bhnd \ ${_bxe} \ ${_bios} \ ${_blake2} \ ${_bnxt} \ bridgestp \ bwi \ bwn \ ${_bytgpio} \ ${_chvgpio} \ cam \ ${_cardbus} \ ${_carp} \ cas \ ${_cbb} \ cc \ ${_ccp} \ cd9660 \ cd9660_iconv \ ${_cfi} \ ${_chromebook_platform} \ ${_ciss} \ ${_coretemp} \ ${_cpsw} \ ${_cpuctl} \ ${_cpufreq} \ ${_crypto} \ ${_cryptodev} \ ctl \ ${_cxgb} \ ${_cxgbe} \ dc \ dcons \ dcons_crom \ ${_dpaa2} \ ${_dpdk_lpm4} \ ${_dpdk_lpm6} \ ${_dpms} \ dummynet \ ${_dwwdt} \ ${_e6000sw} \ ${_efirt} \ ${_em} \ ${_ena} \ ${_enic} \ ${_enetc} \ ${_et} \ evdev \ ${_exca} \ ext2fs \ fdc \ fdescfs \ ${_felix} \ ${_ffec} \ ${_fib_dxr} \ filemon \ firewire \ firmware \ flash \ ${_ftgpio} \ ${_ftwd} \ fusefs \ ${_fxp} \ gem \ geom \ ${_glxiic} \ ${_glxsb} \ gpio \ ${_gve} \ hid \ hifn \ ${_hpt27xx} \ ${_hptiop} \ ${_hptmv} \ ${_hptnr} \ ${_hptrr} \ hwpmc \ ${_hyperv} \ i2c \ ${_iavf} \ ${_ibcore} \ ${_ichwd} \ ${_ice} \ ${_ice_ddp} \ ${_irdma} \ ${_ida} \ if_bridge \ ${_if_cgem} \ if_disc \ if_edsc \ ${_if_enc} \ if_epair \ ${_if_gif} \ ${_if_gre} \ ${_if_me} \ if_infiniband \ if_lagg \ if_ovpn \ ${_if_stf} \ if_tuntap \ if_vlan \ if_vxlan \ ${_if_wg} \ iflib \ ${_igc} \ imgact_binmisc \ ${_intelspi} \ ${_io} \ ${_ioat} \ ${_ipoib} \ ipdivert \ ${_ipfilter} \ ${_ipfw} \ ipfw_nat \ ${_ipfw_nat64} \ ${_ipfw_nptv6} \ ${_ipfw_pmod} \ ${_ipmi} \ ip6_mroute_mod \ ip_mroute_mod \ ${_ips} \ ${_ipsec} \ ${_ipw} \ ${_ipwfw} \ ${_isci} \ ${_iser} \ isp \ ${_ispfw} \ ${_itwd} \ ${_iwi} \ ${_iwifw} \ ${_iwlwifi} \ ${_iwlwififw} \ ${_iwm} \ ${_iwmfw} \ ${_iwn} \ ${_iwnfw} \ ${_ix} \ ${_ixv} \ ${_ixl} \ jme \ kbdmux \ kgssapi \ kgssapi_krb5 \ khelp \ krpc \ ksyms \ le \ lge \ libalias \ libiconv \ libmchain \ lindebugfs \ linuxkpi \ linuxkpi_hdmi \ linuxkpi_wlan \ ${_lio} \ lpt \ ${_mac_biba} \ ${_mac_bsdextended} \ ${_mac_ddb} \ ${_mac_ifoff} \ ${_mac_lomac} \ ${_mac_mls} \ ${_mac_none} \ ${_mac_ntpd} \ ${_mac_partition} \ ${_mac_pimd} \ ${_mac_portacl} \ ${_mac_priority} \ ${_mac_seeotheruids} \ ${_mac_stub} \ ${_mac_test} \ ${_mac_veriexec} \ ${_mac_veriexec_sha1} \ ${_mac_veriexec_sha256} \ ${_mac_veriexec_sha384} \ ${_mac_veriexec_sha512} \ ${_malo} \ ${_mana} \ md \ mdio \ ${_mgb} \ mem \ mfi \ mii \ mlx \ mlxfw \ ${_mlx4} \ ${_mlx4ib} \ ${_mlx4en} \ ${_mlx5} \ ${_mlx5en} \ ${_mlx5ib} \ mmc \ mmcsd \ + ${_mpi3mr} \ ${_mpr} \ ${_mps} \ mpt \ mqueue \ mrsas \ msdosfs \ msdosfs_iconv \ msk \ ${_mthca} \ mvs \ mwl \ ${_mwlfw} \ mxge \ my \ ${_nctgpio} \ ${_neta} \ netlink \ ${_netgraph} \ ${_nfe} \ nfscl \ nfscommon \ nfsd \ nfslockd \ nfssvc \ nlsysevent \ nge \ nmdm \ nullfs \ ${_ntb} \ ${_nvd} \ ${_nvdimm} \ ${_nvme} \ ${_nvram} \ oce \ ${_ocs_fc} \ ${_ossl} \ otus \ ${_otusfw} \ ow \ ${_padlock} \ ${_padlock_rng} \ ${_pchtherm} \ ${_pcfclock} \ ${_pf} \ ${_pflog} \ ${_pfsync} \ plip \ ${_pms} \ ppbus \ ppc \ ppi \ pps \ procfs \ proto \ pseudofs \ ${_pst} \ pty \ puc \ pwm \ ${_qat} \ ${_qatfw} \ ${_qat_c2xxx} \ ${_qat_c2xxxfw} \ ${_qlxge} \ ${_qlxgb} \ ${_qlxgbe} \ ${_qlnx} \ ral \ ${_ralfw} \ ${_random_fortuna} \ ${_random_other} \ rc4 \ ${_rdma} \ ${_rdrand_rng} \ re \ rl \ ${_rockchip} \ rtsx \ ${_rtw88} \ ${_rtw88fw} \ rtwn \ rtwn_pci \ rtwn_usb \ ${_rtwnfw} \ ${_s3} \ ${_safe} \ safexcel \ ${_sbni} \ scc \ ${_sctp} \ sdhci \ ${_sdhci_acpi} \ ${_sdhci_fdt} \ sdhci_pci \ sdio \ sem \ send \ ${_sfxge} \ sge \ ${_sgx} \ ${_sgx_linux} \ siftr \ siis \ sis \ sk \ ${_smartpqi} \ smbfs \ snp \ sound \ ${_speaker} \ spi \ ${_splash} \ ste \ stge \ ${_sume} \ ${_superio} \ ${_p2sb} \ sym \ ${_syscons} \ sysvipc \ tarfs \ tcp \ ${_ti} \ tmpfs \ ${_toecore} \ ${_tpm} \ tws \ uart \ udf \ udf_iconv \ ufs \ uinput \ unionfs \ usb \ ${_vesa} \ virtio \ vge \ ${_viawd} \ videomode \ vkbd \ ${_vmd} \ ${_vmm} \ ${_vmware} \ vr \ vte \ ${_wbwd} \ ${_wdatwd} \ wlan \ wlan_acl \ wlan_amrr \ wlan_ccmp \ wlan_rssadapt \ wlan_tkip \ wlan_wep \ wlan_xauth \ ${_wpi} \ ${_wpifw} \ ${_x86bios} \ xdr \ xl \ xz \ zlib .if ${MK_AUTOFS} != "no" || defined(ALL_MODULES) _autofs= autofs .endif .if ${MK_DTRACE} != "no" || defined(ALL_MODULES) .if ${KERN_OPTS:MKDTRACE_HOOKS} SUBDIR+= dtrace .endif SUBDIR+= opensolaris .endif # Requires bus_space_read_8 .if ${MACHINE_ARCH} != "i386" _bnxt= bnxt .endif .if ${MK_CRYPT} != "no" || defined(ALL_MODULES) .if exists(${SRCTOP}/sys/opencrypto) _crypto= crypto _cryptodev= cryptodev _random_fortuna=random_fortuna _random_other= random_other .endif .endif .if ${MK_CUSE} != "no" || defined(ALL_MODULES) SUBDIR+= cuse .endif .if ${MK_EFI} != "no" .if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "amd64" _efirt= efirt .endif .endif .if (${MK_INET_SUPPORT} != "no" || ${MK_INET6_SUPPORT} != "no") || \ defined(ALL_MODULES) _carp= carp _toecore= toecore _if_enc= if_enc _if_gif= if_gif _if_gre= if_gre .if ${MK_CRYPT} != "no" || defined(ALL_MODULES) _if_wg= if_wg .endif _ipfw_pmod= ipfw_pmod .if ${KERN_OPTS:MIPSEC_SUPPORT} && !${KERN_OPTS:MIPSEC} _ipsec= ipsec .endif .if ${KERN_OPTS:MSCTP_SUPPORT} || ${KERN_OPTS:MSCTP} _sctp= sctp .endif .endif .if (${MK_INET_SUPPORT} != "no" && ${MK_INET6_SUPPORT} != "no") || \ defined(ALL_MODULES) _if_stf= if_stf .endif .if ${MK_INET_SUPPORT} != "no" || defined(ALL_MODULES) _if_me= if_me _ipfw= ipfw .if ${MK_INET6_SUPPORT} != "no" || defined(ALL_MODULES) _ipfw_nat64= ipfw_nat64 .endif .endif .if ${MK_INET6_SUPPORT} != "no" || defined(ALL_MODULES) _ipfw_nptv6= ipfw_nptv6 .endif .if ${MK_IPFILTER} != "no" || defined(ALL_MODULES) _ipfilter= ipfilter .endif .if ${MK_INET_SUPPORT} != "no" && ${KERN_OPTS:MFIB_ALGO} _dpdk_lpm4= dpdk_lpm4 _fib_dxr= fib_dxr .endif .if ${MK_INET6_SUPPORT} != "no" && ${KERN_OPTS:MFIB_ALGO} _dpdk_lpm6= dpdk_lpm6 .endif .if ${MK_ISCSI} != "no" || defined(ALL_MODULES) SUBDIR+= cfiscsi SUBDIR+= iscsi .endif .if !empty(OPT_FDT) SUBDIR+= fdt .endif # Linuxulator .if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "amd64" || \ ${MACHINE_CPUARCH} == "i386" SUBDIR+= linprocfs SUBDIR+= linsysfs .endif .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" SUBDIR+= linux .endif .if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "amd64" SUBDIR+= linux64 SUBDIR+= linux_common .endif .if ${MACHINE_CPUARCH} != "arm" .if ${MK_OFED} != "no" || defined(ALL_MODULES) _ibcore= ibcore _ipoib= ipoib _iser= iser _mthca= mthca _rdma= rdma .endif .endif .if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "amd64" || \ ${MACHINE_CPUARCH} == "i386" || ${MACHINE_ARCH:Mpowerpc64*} != "" _ipmi= ipmi _mlx4= mlx4 _mlx5= mlx5 .if (${MK_INET_SUPPORT} != "no" && ${MK_INET6_SUPPORT} != "no") || \ defined(ALL_MODULES) _mlx4en= mlx4en _mlx5en= mlx5en .endif .if ${MK_OFED} != "no" || defined(ALL_MODULES) _mlx4ib= mlx4ib _mlx5ib= mlx5ib .endif .endif .if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "amd64" || \ ${MACHINE_CPUARCH} == "i386" _ena= ena _gve= gve _iwlwifi= iwlwifi .if ${MK_SOURCELESS_UCODE} != "no" _iwlwififw= iwlwififw .endif _ossl= ossl _rtw88= rtw88 .if ${MK_SOURCELESS_UCODE} != "no" _rtw88fw= rtw88fw .endif _vmware= vmware .endif # MAC framework .if ${KERN_OPTS:MMAC} || defined(ALL_MODULES) _mac_biba= mac_biba _mac_bsdextended= mac_bsdextended .if ${KERN_OPTS:MDDB} || defined(ALL_MODULES) _mac_ddb= mac_ddb .endif _mac_ifoff= mac_ifoff _mac_lomac= mac_lomac _mac_mls= mac_mls _mac_none= mac_none _mac_ntpd= mac_ntpd _mac_partition= mac_partition _mac_pimd= mac_pimd _mac_portacl= mac_portacl _mac_priority= mac_priority _mac_seeotheruids= mac_seeotheruids _mac_stub= mac_stub _mac_test= mac_test .if ${MK_VERIEXEC} != "no" || defined(ALL_MODULES) _mac_veriexec= mac_veriexec _mac_veriexec_sha1= mac_veriexec_sha1 _mac_veriexec_sha256= mac_veriexec_sha256 _mac_veriexec_sha384= mac_veriexec_sha384 _mac_veriexec_sha512= mac_veriexec_sha512 .endif .endif .if ${MK_NETGRAPH} != "no" || defined(ALL_MODULES) _netgraph= netgraph .endif .if (${MK_PF} != "no" && (${MK_INET_SUPPORT} != "no" || \ ${MK_INET6_SUPPORT} != "no")) || defined(ALL_MODULES) _pf= pf _pflog= pflog .if ${MK_INET_SUPPORT} != "no" _pfsync= pfsync .endif .endif .if ${MK_SOURCELESS_UCODE} != "no" _bce= bce _fxp= fxp _ispfw= ispfw _ti= ti _mwlfw= mwlfw _otusfw= otusfw _ralfw= ralfw _rtwnfw= rtwnfw .endif .if ${MK_SOURCELESS_UCODE} != "no" && ${MACHINE_CPUARCH} != "arm" && \ ${MACHINE_ARCH} != "powerpc" && ${MACHINE_ARCH} != "powerpcspe" && \ ${MACHINE_CPUARCH} != "riscv" _cxgbe= cxgbe .endif +# This has only been tested on amd64 and arm64 +.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "arm64" +_mpi3mr=mpi3mr +.endif + .if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "arm64" || ${MACHINE_ARCH:Mpowerpc64*} _ice= ice .if ${MK_SOURCELESS_UCODE} != "no" _ice_ddp= ice_ddp .endif .if ${MK_OFED} != "no" || defined(ALL_MODULES) .if ${MK_INET_SUPPORT} != "no" && ${MK_INET6_SUPPORT} != "no" _irdma= irdma .endif .endif .endif .if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm" || \ ${MACHINE_CPUARCH} == "riscv" .if !empty(OPT_FDT) _if_cgem= if_cgem .endif .endif # These rely on 64bit atomics .if ${MACHINE_ARCH} != "powerpc" && ${MACHINE_ARCH} != "powerpcspe" _mps= mps _mpr= mpr .endif .if ${MK_TESTS} != "no" || defined(ALL_MODULES) SUBDIR+= ktest SUBDIR+= tests .endif .if ${MK_ZFS} != "no" || defined(ALL_MODULES) SUBDIR+= zfs .endif .if ${MK_SOURCELESS_UCODE} != "no" _cxgb= cxgb .endif .if ${MACHINE_CPUARCH} == "aarch64" _armv8crypto= armv8crypto _dpaa2= dpaa2 _em= em _hyperv= hyperv .if !empty(OPT_FDT) _allwinner= allwinner _dwwdt= dwwdt _enetc= enetc _felix= felix _rockchip= rockchip .endif .endif .if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm" .if !empty(OPT_FDT) _sdhci_fdt= sdhci_fdt .endif _e6000sw= e6000sw _neta= neta .endif .if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" _agp= agp .if ${MACHINE_CPUARCH} == "i386" || !empty(COMPAT_FREEBSD32_ENABLED) _aout= aout .endif _bios= bios .if ${MK_SOURCELESS_UCODE} != "no" _bxe= bxe .endif _cardbus= cardbus _cbb= cbb _cpuctl= cpuctl _cpufreq= cpufreq _dpms= dpms _em= em _et= et _ftgpio= ftgpio _ftwd= ftwd _exca= exca _igc= igc _io= io _itwd= itwd _ix= ix _ixv= ixv .if ${MK_SOURCELESS_UCODE} != "no" _lio= lio .endif _mana= mana _mgb= mgb _nctgpio= nctgpio _ntb= ntb _ocs_fc= ocs_fc _p2sb= p2sb _qat_c2xxx= qat_c2xxx _qat_c2xxxfw= qat_c2xxxfw _safe= safe _speaker= speaker _splash= splash _syscons= syscons _wbwd= wbwd _wdatwd= wdatwd _aac= aac _aacraid= aacraid _acpi= acpi .if ${MK_CRYPT} != "no" || defined(ALL_MODULES) _aesni= aesni .endif _amd_ecc_inject=amd_ecc_inject _amdsbwd= amdsbwd _amdsmn= amdsmn _amdtemp= amdtemp _arcmsr= arcmsr _asmc= asmc .if ${MK_CRYPT} != "no" || defined(ALL_MODULES) _blake2= blake2 .endif _bytgpio= bytgpio _chvgpio= chvgpio _ciss= ciss _chromebook_platform= chromebook_platform _coretemp= coretemp .if ${MK_SOURCELESS_HOST} != "no" && empty(KCSAN_ENABLED) _hpt27xx= hpt27xx .endif _hptiop= hptiop .if ${MK_SOURCELESS_HOST} != "no" && empty(KCSAN_ENABLED) _hptmv= hptmv _hptnr= hptnr _hptrr= hptrr .endif _hyperv= hyperv _ichwd= ichwd _ida= ida _intelspi= intelspi _ips= ips _isci= isci _ipw= ipw _iwi= iwi _iwm= iwm _iwn= iwn .if ${MK_SOURCELESS_UCODE} != "no" _ipwfw= ipwfw _iwifw= iwifw _iwmfw= iwmfw _iwnfw= iwnfw .endif _nfe= nfe _nvd= nvd _nvme= nvme _nvram= nvram .if ${MK_CRYPT} != "no" || defined(ALL_MODULES) _padlock= padlock _padlock_rng= padlock_rng _rdrand_rng= rdrand_rng .endif _pchtherm = pchtherm _s3= s3 _sdhci_acpi= sdhci_acpi _superio= superio _tpm= tpm _vesa= vesa _viawd= viawd _vmd= vmd _wpi= wpi .if ${MK_SOURCELESS_UCODE} != "no" _wpifw= wpifw .endif _x86bios= x86bios .endif .if ${MACHINE_CPUARCH} == "amd64" _amdgpio= amdgpio _ccp= ccp _enic= enic _iavf= iavf _ioat= ioat _ixl= ixl _nvdimm= nvdimm _pms= pms _qat= qat .if ${MK_SOURCELESS_UCODE} != "no" _qatfw= qatfw .endif _qlxge= qlxge _qlxgb= qlxgb _sume= sume .if ${MK_SOURCELESS_UCODE} != "no" _qlxgbe= qlxgbe _qlnx= qlnx .endif _sfxge= sfxge _sgx= sgx _sgx_linux= sgx_linux _smartpqi= smartpqi _p2sb= p2sb .if ${MK_BHYVE} != "no" || defined(ALL_MODULES) .if ${KERN_OPTS:MSMP} _vmm= vmm .endif .endif .endif .if ${MACHINE_CPUARCH} == "i386" # XXX some of these can move to the general case when de-i386'ed # XXX some of these can move now, but are untested on other architectures. _3dfx= 3dfx _3dfx_linux= 3dfx_linux _glxiic= glxiic _glxsb= glxsb _pcfclock= pcfclock _pst= pst _sbni= sbni .endif .if ${MACHINE_ARCH} == "armv7" _cfi= cfi _cpsw= cpsw .endif .if ${MACHINE_CPUARCH} == "powerpc" _aacraid= aacraid _agp= agp _an= an _cardbus= cardbus _cbb= cbb _cfi= cfi _cpufreq= cpufreq _exca= exca _ffec= ffec _nvd= nvd _nvme= nvme .endif .if ${MACHINE_ARCH:Mpowerpc64*} != "" _ixl= ixl _nvram= opal_nvram .endif .if ${MACHINE_CPUARCH} == "powerpc" && ${MACHINE_ARCH} != "powerpcspe" # Don't build powermac_nvram for powerpcspe, it's never supported. _nvram+= powermac_nvram .endif .if ${MACHINE_CPUARCH} == "arm" || ${MACHINE_CPUARCH} == "aarch64" _bcm283x_clkman= bcm283x_clkman _bcm283x_pwm= bcm283x_pwm .endif .if !(${COMPILER_TYPE} == "clang" && ${COMPILER_VERSION} < 110000) # LLVM 10 crashes when building if_malo_pci.c, fixed in LLVM11: # https://bugs.llvm.org/show_bug.cgi?id=44351 _malo= malo .endif SUBDIR+=${MODULES_EXTRA} .for reject in ${WITHOUT_MODULES} SUBDIR:= ${SUBDIR:N${reject}} .endfor .endif # MODULES_OVERRIDE -- Keep last # Calling kldxref(8) for each module is expensive. .if !defined(NO_XREF) .MAKEFLAGS+= -DNO_XREF afterinstall: .PHONY @if type kldxref >/dev/null 2>&1; then \ ${ECHO} ${KLDXREF_CMD} ${DESTDIR}${KMODDIR}; \ ${KLDXREF_CMD} ${DESTDIR}${KMODDIR}; \ fi .endif SUBDIR:= ${SUBDIR:u:O} .include diff --git a/sys/modules/mpi3mr/Makefile b/sys/modules/mpi3mr/Makefile new file mode 100644 index 000000000000..45b641f828c0 --- /dev/null +++ b/sys/modules/mpi3mr/Makefile @@ -0,0 +1,13 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/dev/mpi3mr + +KMOD= mpi3mr +SRCS= mpi3mr_pci.c mpi3mr.c mpi3mr_cam.c mpi3mr_app.c +SRCS+= opt_cam.h +SRCS+= device_if.h bus_if.h pci_if.h + +.include + +CWARNFLAGS.mpi3mr_sas.c= ${NO_WUNNEEDED_INTERNAL_DECL} +CWARNFLAGS.mpi3mr_mapping.c= ${NO_WSOMETIMES_UNINITIALIZED}