Add tri-mode support (SAS/SATA/PCIe).

This includes NVMe device support and adds support for the following adapters:
    SAS 3408
    SAS 3416
    SAS 3508
    SAS 3516
    SAS 3616
    SAS 3708
    SAS 3716

Reviewed by:    ken, scottl, asomers, mav
Approved by:	ken, scottl, mav
MFC after:      2 weeks
Relnotes:	yes
Differential Revision: https://reviews.freebsd.org/D10095
This commit is contained in:
Stephen McConnell 2017-05-17 21:33:37 +00:00
parent 0044ecde83
commit 67feec5045
21 changed files with 3610 additions and 215 deletions

View File

@ -1,8 +1,8 @@
.\"
.\" Copyright (c) 2010 Spectra Logic Corporation
.\" Copyright (c) 2014 LSI Corp
.\" Copyright (c) 2016 Avago Technologies
.\" Copyright (c) 2016 Broadcom Ltd.
.\" Copyright (c) 2017 Avago Technologies
.\" Copyright (c) 2017 Broadcom Ltd.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@ -38,12 +38,12 @@
.\" $Id$
.\" $FreeBSD$
.\"
.Dd July 6, 2016
.Dd May 17, 2017
.Dt MPR 4
.Os
.Sh NAME
.Nm mpr
.Nd "LSI Fusion-MPT 3 IT/IR 12Gb/s Serial Attached SCSI/SATA driver"
.Nd "LSI Fusion-MPT 3/3.5 IT/IR 12Gb/s Serial Attached SCSI/SATA/PCIe driver"
.Sh SYNOPSIS
To compile this driver into the kernel, place these lines in the kernel
configuration file:
@ -62,8 +62,8 @@ mpr_load="YES"
The
.Nm
driver provides support for Broadcom Ltd./Avago Tech (LSI)
Fusion-MPT 3 IT/IR
.Tn SAS
Fusion-MPT 3/3.5 IT/IR
.Tn SAS/PCIe
controllers.
.Sh HARDWARE
These controllers are supported by the
@ -81,6 +81,24 @@ Broadcom Ltd./Avago Tech (LSI) SAS 3108 (8 Port SAS)
Broadcom Ltd./Avago Tech (LSI) SAS 3216 (16 Port SAS)
.It
Broadcom Ltd./Avago Tech (LSI) SAS 3224 (24 Port SAS)
.It
Broadcom Ltd./Avago Tech (LSI) SAS 3316 (16 Port SAS)
.It
Broadcom Ltd./Avago Tech (LSI) SAS 3324 (24 Port SAS)
.It
Broadcom Ltd./Avago Tech (LSI) SAS 3408 (8 Port SAS/PCIe)
.It
Broadcom Ltd./Avago Tech (LSI) SAS 3416 (16 Port SAS/PCIe)
.It
Broadcom Ltd./Avago Tech (LSI) SAS 3508 (8 Port SAS/PCIe)
.It
Broadcom Ltd./Avago Tech (LSI) SAS 3516 (16 Port SAS/PCIe)
.It
Broadcom Ltd./Avago Tech (LSI) SAS 3616 (16 Port SAS/PCIe)
.It
Broadcom Ltd./Avago Tech (LSI) SAS 3708 (8 Port SAS/PCIe)
.It
Broadcom Ltd./Avago Tech (LSI) SAS 3716 (16 Port SAS/PCIe)
.El
.Sh CONFIGURATION
In all tunable descriptions below, X represents the adapter number.
@ -156,6 +174,24 @@ dev.mpr.X.io_cmds_active
.Xr sysctl 8
variable.
.Pp
The current number of free PRP pages is stored in the
dev.mpr.X.prp_pages_free
.Xr sysctl 8
variable.
PRP pages are used by NVMe devices for I/O transfers, much like Scatter/Gather
lists.
.Pp
The lowest number of free PRP pages seen since boot is stored in the
dev.mpr.X.prp_pages_free_lowwater
.Xr sysctl 8
variable.
.Pp
The number of times that PRP page allocations have failed since boot is
stored in the
dev.mpr.X.prp_page_alloc_fail
.Xr sysctl 8
variable.
.Pp
To set the maximum number of pages that will be used per I/O for all adapters,
set this tunable in
.Xr loader.conf 5 :
@ -229,13 +265,13 @@ Send SSU to HDDs, but not to SSDs.
Send SSU to both HDDs and SSDs.
.El
.Pp
To control the feature for a specific adapter, set this tunable value in
To control this feature for a specific adapter, set this tunable value in
.Xr loader.conf 5 :
.Bd -literal -offset indent
dev.mpr.X.enable_ssu
.Ed
.Pp
The same set of values are valid when setting this tunable for all adapters.
The same set of values are valid as when setting this tunable for all adapters.
.Pp
SATA disks that take several seconds to spin up and fail the SATA Identify
command might not be discovered by the driver.
@ -261,6 +297,45 @@ dev.mpr.X.spinup_wait_time=NNNN
tunable.
NNNN is the number of seconds to wait for SATA devices to spin up when they fail
the initial SATA Identify command.
.Pp
The driver can map devices discovered by the adapter so that target IDs
corresponding to a specific device persist across resets and reboots.
In some cases it is possible for devices to lose their mapped IDs due to
unexpected behavior from certain hardware, such as some types of enclosures.
To overcome this problem, a tunable is provided that will force the driver to
map devices using the Phy number associated with the device.
This feature is not recommended if the topology includes multiple
enclosures/expanders.
If multiple enclosures/expanders are present in the topology, Phy numbers are
repeated, causing all devices at these Phy numbers except the first device to
fail enumeration.
To control this feature for all adapters, set the
.Bd -literal -offset indent
hw.mpr.use_phy_num
.Ed
.Pp
tunable in
.Xr loader.conf 5
to one of these values:
.Bl -tag -width 6n -offset indent
.It -1
Only use Phy numbers to map devices and bypass the driver's mapping logic.
.It 0
Never use Phy numbers to map devices.
.It 1
Use Phy numbers to map devices, but only if the driver's mapping logic fails
to map the device that is being enumerated.
This is the default value.
.El
.Pp
To control this feature for a specific adapter, set this tunable value in
.Xr loader.conf 5 :
.Bd -literal -offset indent
dev.mpr.X.use_phy_num
.Ed
.Pp
The same set of values are valid as when setting this tunable for all adapters.
.Pp
.Sh DEBUGGING
To enable debugging prints from the
.Nm

View File

@ -44,7 +44,7 @@
* scatter/gather formats.
* Creation Date: June 21, 2006
*
* mpi2.h Version: 02.00.42
* mpi2.h Version: 02.00.46
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@ -132,7 +132,8 @@
* Bumped MPI2_HEADER_VERSION_UNIT.
* 03-16-15 02.00.37 Updated for MPI v2.6.
* Bumped MPI2_HEADER_VERSION_UNIT.
* Added Scratchpad registers to
* Added Scratchpad registers and
* AtomicRequestDescriptorPost register to
* MPI2_SYSTEM_INTERFACE_REGS.
* Added MPI2_DIAG_SBR_RELOAD.
* Added MPI2_IOCSTATUS_INSUFFICIENT_POWER.
@ -142,6 +143,14 @@
* Added V7 HostDiagnostic register defines
* 12-15-15 02.00.41 Bumped MPI_HEADER_VERSION_UNIT
* 01-01-16 02.00.42 Bumped MPI_HEADER_VERSION_UNIT
* 04-05-16 02.00.43 Modified MPI26_DIAG_BOOT_DEVICE_SELECT defines
* to be unique within first 32 characters.
* Removed AHCI support.
* Removed SOP support.
* Bumped MPI2_HEADER_VERSION_UNIT.
* 04-10-16 02.00.44 Bumped MPI2_HEADER_VERSION_UNIT.
* 07-06-16 02.00.45 Bumped MPI2_HEADER_VERSION_UNIT.
* 09-02-16 02.00.46 Bumped MPI2_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
*/
@ -185,7 +194,7 @@
/* Unit and Dev versioning for this MPI header set */
#define MPI2_HEADER_VERSION_UNIT (0x2A)
#define MPI2_HEADER_VERSION_UNIT (0x2E)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
@ -245,7 +254,8 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS
U32 Scratchpad[4]; /* 0xB0 */
U32 RequestDescriptorPostLow; /* 0xC0 */
U32 RequestDescriptorPostHigh; /* 0xC4 */
U32 Reserved7[14]; /* 0xC8 */
U32 AtomicRequestDescriptorPost;/* 0xC8 */ /* MPI v2.6 and later; reserved in earlier versions */
U32 Reserved7[13]; /* 0xCC */
} MPI2_SYSTEM_INTERFACE_REGS, MPI2_POINTER PTR_MPI2_SYSTEM_INTERFACE_REGS,
Mpi2SystemInterfaceRegs_t, MPI2_POINTER pMpi2SystemInterfaceRegs_t;
@ -293,10 +303,11 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS
#define MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW (0x00000800)
/* Defines for V7A/V7R HostDiagnostic Register */
#define MPI26_DIAG_BOOT_DEVICE_SELECT_FLASH64 (0x00000000)
#define MPI26_DIAG_BOOT_DEVICE_SELECT_HCDW64 (0x00000800)
#define MPI26_DIAG_BOOT_DEVICE_SELECT_FLASH32 (0x00001000)
#define MPI26_DIAG_BOOT_DEVICE_SELECT_HCDW32 (0x00001800)
#define MPI26_DIAG_BOOT_DEVICE_SEL_64FLASH (0x00000000)
#define MPI26_DIAG_BOOT_DEVICE_SEL_64HCDW (0x00000800)
#define MPI26_DIAG_BOOT_DEVICE_SEL_32FLASH (0x00001000)
#define MPI26_DIAG_BOOT_DEVICE_SEL_32HCDW (0x00001800)
#define MPI2_DIAG_CLEAR_FLASH_BAD_SIG (0x00000400)
#define MPI2_DIAG_FORCE_HCB_ON_RESET (0x00000200)
#define MPI2_DIAG_HCB_MODE (0x00000100)
@ -379,6 +390,7 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS
*/
#define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET (0x000000C0)
#define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET (0x000000C4)
#define MPI26_ATOMIC_REQUEST_DESCRIPTOR_POST_OFFSET (0x000000C8)
/* Hard Reset delay timings */
@ -415,6 +427,7 @@ typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR
#define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE (0x08)
#define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR (0x0A)
#define MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO (0x0C)
#define MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED (0x10)
#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01)
@ -482,6 +495,14 @@ typedef MPI2_SCSI_IO_REQUEST_DESCRIPTOR
MPI2_POINTER pMpi25FastPathSCSIIORequestDescriptor_t;
/* PCIe Encapsulated Request Descriptor */
typedef MPI2_SCSI_IO_REQUEST_DESCRIPTOR
MPI26_PCIE_ENCAPSULATED_REQUEST_DESCRIPTOR,
MPI2_POINTER PTR_MPI26_PCIE_ENCAPSULATED_REQUEST_DESCRIPTOR,
Mpi26PCIeEncapsulatedRequestDescriptor_t,
MPI2_POINTER pMpi26PCIeEncapsulatedRequestDescriptor_t;
/* union of Request Descriptors */
typedef union _MPI2_REQUEST_DESCRIPTOR_UNION
{
@ -491,11 +512,35 @@ typedef union _MPI2_REQUEST_DESCRIPTOR_UNION
MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget;
MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator;
MPI25_FP_SCSI_IO_REQUEST_DESCRIPTOR FastPathSCSIIO;
MPI26_PCIE_ENCAPSULATED_REQUEST_DESCRIPTOR PCIeEncapsulated;
U64 Words;
} MPI2_REQUEST_DESCRIPTOR_UNION, MPI2_POINTER PTR_MPI2_REQUEST_DESCRIPTOR_UNION,
Mpi2RequestDescriptorUnion_t, MPI2_POINTER pMpi2RequestDescriptorUnion_t;
/* Atomic Request Descriptors */
/*
* All Atomic Request Descriptors have the same format, so the following
* structure is used for all Atomic Request Descriptors:
* Atomic Default Request Descriptor
* Atomic High Priority Request Descriptor
* Atomic SCSI IO Request Descriptor
* Atomic SCSI Target Request Descriptor
* Atomic RAID Accelerator Request Descriptor
* Atomic Fast Path SCSI IO Request Descriptor
* Atomic PCIe Encapsulated Request Descriptor
*/
/* Atomic Request Descriptor */
typedef struct _MPI26_ATOMIC_REQUEST_DESCRIPTOR
{
U8 RequestFlags; /* 0x00 */
U8 MSIxIndex; /* 0x01 */
U16 SMID; /* 0x02 */
} MPI26_ATOMIC_REQUEST_DESCRIPTOR,
MPI2_POINTER PTR_MPI26_ATOMIC_REQUEST_DESCRIPTOR,
Mpi26AtomicRequestDescriptor_t, MPI2_POINTER pMpi26AtomicRequestDescriptor_t;
/* for the RequestFlags field, use the same defines as MPI2_DEFAULT_REQUEST_DESCRIPTOR */
@ -520,6 +565,7 @@ typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR
#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER (0x03)
#define MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS (0x05)
#define MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS (0x06)
#define MPI26_RPY_DESCRIPT_FLAGS_PCIE_ENCAPSULATED_SUCCESS (0x08)
#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F)
/* values for marking a reply descriptor as unused */
@ -607,6 +653,14 @@ typedef MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR
MPI2_POINTER pMpi25FastPathSCSIIOSuccessReplyDescriptor_t;
/* PCIe Encapsulated Success Reply Descriptor */
typedef MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR
MPI26_PCIE_ENCAPSULATED_SUCCESS_REPLY_DESCRIPTOR,
MPI2_POINTER PTR_MPI26_PCIE_ENCAPSULATED_SUCCESS_REPLY_DESCRIPTOR,
Mpi26PCIeEncapsulatedSuccessReplyDescriptor_t,
MPI2_POINTER pMpi26PCIeEncapsulatedSuccessReplyDescriptor_t;
/* union of Reply Descriptors */
typedef union _MPI2_REPLY_DESCRIPTORS_UNION
{
@ -617,6 +671,7 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION
MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer;
MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess;
MPI25_FP_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR FastPathSCSIIOSuccess;
MPI26_PCIE_ENCAPSULATED_SUCCESS_REPLY_DESCRIPTOR PCIeEncapsulatedSuccess;
U64 Words;
} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION,
Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t;
@ -659,6 +714,7 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION
#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) /* Host Based Discovery Action */
#define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30) /* Power Management Control */
#define MPI2_FUNCTION_SEND_HOST_MESSAGE (0x31) /* Send Host Message */
#define MPI2_FUNCTION_NVME_ENCAPSULATED (0x33) /* NVMe Encapsulated (MPI v2.6) */
#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) /* beginning of product-specific range */
#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) /* end of product-specific range */
@ -1232,6 +1288,8 @@ typedef union _MPI25_SGE_IO_UNION
#define MPI26_IEEE_SGE_FLAGS_NSF_MASK (0x1C)
#define MPI26_IEEE_SGE_FLAGS_NSF_MPI_IEEE (0x00)
#define MPI26_IEEE_SGE_FLAGS_NSF_NVME_PRP (0x08)
#define MPI26_IEEE_SGE_FLAGS_NSF_NVME_SGL (0x10)
/* Data Location Address Space */

View File

@ -42,7 +42,7 @@
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
* mpi2_cnfg.h Version: 02.00.35
* mpi2_cnfg.h Version: 02.00.39
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@ -223,9 +223,38 @@
* Flags field to IO Unit Page 7.
* Added IO Unit Page 11.
* Added new SAS Phy Event codes
* Added PCIe configuration pages.
* 03-19-15 02.00.32 Fixed PCIe Link Config page structure names to be
* unique in first 32 characters.
* 05-25-15 02.00.33 Added more defines for the BiosOptions field of
* MPI2_CONFIG_PAGE_BIOS_1.
* 08-25-15 02.00.34 Added PCIe Device Page 2 SGL format capability.
* 12-18-15 02.00.35 Added SATADeviceWaitTime to SAS IO Unit Page 4.
* 01-21-16 02.00.36 Added/modified MPI2_MFGPAGE_DEVID_SAS defines.
* Added Link field to PCIe Link Pages
* Added EnclosureLevel and ConnectorName to PCIe
* Device Page 0.
* Added define for PCIE IoUnit page 1 max rate shift.
* Added comment for reserved ExtPageTypes.
* Added SAS 4 22.5 gbs speed support.
* Added PCIe 4 16.0 GT/sec speec support.
* Removed AHCI support.
* Removed SOP support.
* Added NegotiatedLinkRate and NegotiatedPortWidth to
* PCIe device page 0.
* 04-10-16 02.00.37 Fixed MPI2_MFGPAGE_DEVID_SAS3616/3708 defines
* 07-01-16 02.00.38 Added Manufacturing page 7 Connector types.
* Changed declaration of ConnectorName in PCIe DevicePage0
* to match SAS DevicePage 0.
* Added SATADeviceWaitTime to IO Unit Page 11.
* Added MPI26_MFGPAGE_DEVID_SAS4008
* Added x16 PCIe width to IO Unit Page 7
* Added LINKFLAGS to control SRIS in PCIe IO Unit page 1
* phy data.
* Added InitStatus to PCIe IO Unit Page 1 header.
* 09-01-16 02.00.39 Added MPI26_CONFIG_PAGE_ENCLOSURE_0 and related defines.
* Added MPI26_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE and
* MPI26_ENCLOS_PGAD_FORM_HANDLE page address formats.
* --------------------------------------------------------------------------
*/
@ -310,6 +339,12 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION
#define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18)
#define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19)
#define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING (0x1A)
#define MPI2_CONFIG_EXTPAGETYPE_PCIE_IO_UNIT (0x1B) /* MPI v2.6 and later */
#define MPI2_CONFIG_EXTPAGETYPE_PCIE_SWITCH (0x1C) /* MPI v2.6 and later */
#define MPI2_CONFIG_EXTPAGETYPE_PCIE_DEVICE (0x1D) /* MPI v2.6 and later */
#define MPI2_CONFIG_EXTPAGETYPE_PCIE_LINK (0x1E) /* MPI v2.6 and later */
/* Product specific reserved values 0xE0 - 0xEF */
/* Vendor specific reserved values 0xF0 - 0xFF */
/*****************************************************************************
@ -377,6 +412,12 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION
#define MPI2_SAS_ENCLOS_PGAD_HANDLE_MASK (0x0000FFFF)
/* Enclosure PageAddress format */
#define MPI26_ENCLOS_PGAD_FORM_MASK (0xF0000000)
#define MPI26_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE (0x00000000)
#define MPI26_ENCLOS_PGAD_FORM_HANDLE (0x10000000)
#define MPI26_ENCLOS_PGAD_HANDLE_MASK (0x0000FFFF)
/* RAID Configuration PageAddress format */
#define MPI2_RAID_PGAD_FORM_MASK (0xF0000000)
@ -403,6 +444,33 @@ typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION
#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF)
/* PCIe Switch PageAddress format */
#define MPI26_PCIE_SWITCH_PGAD_FORM_MASK (0xF0000000)
#define MPI26_PCIE_SWITCH_PGAD_FORM_GET_NEXT_HNDL (0x00000000)
#define MPI26_PCIE_SWITCH_PGAD_FORM_HNDL_PORTNUM (0x10000000)
#define MPI26_PCIE_SWITCH_EXPAND_PGAD_FORM_HNDL (0x20000000)
#define MPI26_PCIE_SWITCH_PGAD_HANDLE_MASK (0x0000FFFF)
#define MPI26_PCIE_SWITCH_PGAD_PORTNUM_MASK (0x00FF0000)
#define MPI26_PCIE_SWITCH_PGAD_PORTNUM_SHIFT (16)
/* PCIe Device PageAddress format */
#define MPI26_PCIE_DEVICE_PGAD_FORM_MASK (0xF0000000)
#define MPI26_PCIE_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000)
#define MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE (0x20000000)
#define MPI26_PCIE_DEVICE_PGAD_HANDLE_MASK (0x0000FFFF)
/* PCIe Link PageAddress format */
#define MPI26_PCIE_LINK_PGAD_FORM_MASK (0xF0000000)
#define MPI26_PCIE_LINK_PGAD_FORM_GET_NEXT_LINK (0x00000000)
#define MPI26_PCIE_LINK_PGAD_FORM_LINK_NUM (0x10000000)
#define MPI26_PCIE_DEVICE_PGAD_LINKNUM_MASK (0x000000FF)
/****************************************************************************
* Configuration messages
****************************************************************************/
@ -518,6 +586,20 @@ typedef struct _MPI2_CONFIG_REPLY
#define MPI26_MFGPAGE_DEVID_SAS3324_3 (0x00C2)
#define MPI26_MFGPAGE_DEVID_SAS3324_4 (0x00C3)
#define MPI26_MFGPAGE_DEVID_SAS3516 (0x00AA)
#define MPI26_MFGPAGE_DEVID_SAS3516_1 (0x00AB)
#define MPI26_MFGPAGE_DEVID_SAS3416 (0x00AC)
#define MPI26_MFGPAGE_DEVID_SAS3508 (0x00AD)
#define MPI26_MFGPAGE_DEVID_SAS3508_1 (0x00AE)
#define MPI26_MFGPAGE_DEVID_SAS3408 (0x00AF)
#define MPI26_MFGPAGE_DEVID_SAS3716 (0x00D0)
#define MPI26_MFGPAGE_DEVID_SAS3616 (0x00D1)
#define MPI26_MFGPAGE_DEVID_SAS3708 (0x00D2)
#define MPI26_MFGPAGE_DEVID_SAS4008 (0x00A1)
/* Manufacturing Page 0 */
typedef struct _MPI2_CONFIG_PAGE_MAN_0
@ -755,6 +837,12 @@ typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO
#define MPI2_MANPAGE7_PINOUT_SFF_8644_8X (0x0B)
#define MPI2_MANPAGE7_PINOUT_SFF_8644_16X (0x0C)
#define MPI2_MANPAGE7_PINOUT_SFF_8436 (0x0D)
#define MPI2_MANPAGE7_PINOUT_SFF_8088_A (0x0E)
#define MPI2_MANPAGE7_PINOUT_SFF_8643_16i (0x0F)
#define MPI2_MANPAGE7_PINOUT_SFF_8654_4i (0x10)
#define MPI2_MANPAGE7_PINOUT_SFF_8654_8i (0x11)
#define MPI2_MANPAGE7_PINOUT_SFF_8611_4i (0x12)
#define MPI2_MANPAGE7_PINOUT_SFF_8611_8i (0x13)
/* defines for the Location field */
#define MPI2_MANPAGE7_LOCATION_UNKNOWN (0x01)
@ -1017,11 +1105,13 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7
#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X2 (0x02)
#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X4 (0x04)
#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X8 (0x08)
#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X16 (0x10)
/* defines for IO Unit Page 7 PCIeSpeed field */
#define MPI2_IOUNITPAGE7_PCIE_SPEED_2_5_GBPS (0x00)
#define MPI2_IOUNITPAGE7_PCIE_SPEED_5_0_GBPS (0x01)
#define MPI2_IOUNITPAGE7_PCIE_SPEED_8_0_GBPS (0x02)
#define MPI2_IOUNITPAGE7_PCIE_SPEED_16_0_GBPS (0x03)
/* defines for IO Unit Page 7 ProcessorState field */
#define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F)
@ -1079,6 +1169,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7
/* defines for IO Unit Page 7 Flags field */
#define MPI2_IOUNITPAGE7_FLAG_CABLE_POWER_EXC (0x01)
/* IO Unit Page 8 */
#define MPI2_IOUNIT8_NUM_THRESHOLDS (4)
@ -1228,7 +1319,7 @@ typedef struct _MPI26_CONFIG_PAGE_IO_UNIT_11
U32 Reserved3; /* 0x1C */
U32 Reserved4; /* 0x20 */
U8 BootDeviceWaitTime; /* 0x24 */
U8 Reserved5; /* 0x25 */
U8 SATADeviceWaitTime; /* 0x25 */
U16 Reserved6; /* 0x26 */
U8 NumPhys; /* 0x28 */
U8 PEInitialSpinupDelay; /* 0x29 */
@ -1249,9 +1340,6 @@ typedef struct _MPI26_CONFIG_PAGE_IO_UNIT_11
/****************************************************************************
* IOC Config Pages
****************************************************************************/
@ -1968,6 +2056,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1
#define MPI2_SAS_NEG_LINK_RATE_3_0 (0x09)
#define MPI2_SAS_NEG_LINK_RATE_6_0 (0x0A)
#define MPI25_SAS_NEG_LINK_RATE_12_0 (0x0B)
#define MPI26_SAS_NEG_LINK_RATE_22_5 (0x0C)
/* values for AttachedPhyInfo fields */
@ -2035,12 +2124,14 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1
#define MPI2_SAS_PRATE_MAX_RATE_3_0 (0x90)
#define MPI2_SAS_PRATE_MAX_RATE_6_0 (0xA0)
#define MPI25_SAS_PRATE_MAX_RATE_12_0 (0xB0)
#define MPI26_SAS_PRATE_MAX_RATE_22_5 (0xC0)
#define MPI2_SAS_PRATE_MIN_RATE_MASK (0x0F)
#define MPI2_SAS_PRATE_MIN_RATE_NOT_PROGRAMMABLE (0x00)
#define MPI2_SAS_PRATE_MIN_RATE_1_5 (0x08)
#define MPI2_SAS_PRATE_MIN_RATE_3_0 (0x09)
#define MPI2_SAS_PRATE_MIN_RATE_6_0 (0x0A)
#define MPI25_SAS_PRATE_MIN_RATE_12_0 (0x0B)
#define MPI26_SAS_PRATE_MIN_RATE_22_5 (0x0C)
/* values for SAS HwLinkRate fields */
@ -2049,11 +2140,13 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1
#define MPI2_SAS_HWRATE_MAX_RATE_3_0 (0x90)
#define MPI2_SAS_HWRATE_MAX_RATE_6_0 (0xA0)
#define MPI25_SAS_HWRATE_MAX_RATE_12_0 (0xB0)
#define MPI26_SAS_HWRATE_MAX_RATE_22_5 (0xC0)
#define MPI2_SAS_HWRATE_MIN_RATE_MASK (0x0F)
#define MPI2_SAS_HWRATE_MIN_RATE_1_5 (0x08)
#define MPI2_SAS_HWRATE_MIN_RATE_3_0 (0x09)
#define MPI2_SAS_HWRATE_MIN_RATE_6_0 (0x0A)
#define MPI25_SAS_HWRATE_MIN_RATE_12_0 (0x0B)
#define MPI26_SAS_HWRATE_MIN_RATE_22_5 (0x0C)
@ -2227,11 +2320,13 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1
#define MPI2_SASIOUNIT1_MAX_RATE_3_0 (0x90)
#define MPI2_SASIOUNIT1_MAX_RATE_6_0 (0xA0)
#define MPI25_SASIOUNIT1_MAX_RATE_12_0 (0xB0)
#define MPI26_SASIOUNIT1_MAX_RATE_22_5 (0xC0)
#define MPI2_SASIOUNIT1_MIN_RATE_MASK (0x0F)
#define MPI2_SASIOUNIT1_MIN_RATE_1_5 (0x08)
#define MPI2_SASIOUNIT1_MIN_RATE_3_0 (0x09)
#define MPI2_SASIOUNIT1_MIN_RATE_6_0 (0x0A)
#define MPI25_SASIOUNIT1_MIN_RATE_12_0 (0x0B)
#define MPI26_SASIOUNIT1_MIN_RATE_22_5 (0x0C)
/* see mpi2_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */
@ -2718,7 +2813,6 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0
#define MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID (0x0002)
#define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001)
/* SAS Device Page 1 */
typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_1
@ -2885,7 +2979,6 @@ typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG
#define MPI2_SASPHY3_EVENT_CODE_HOTPLUG_TIMEOUT (0xD0)
#define MPI2_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE (0xD1)
#define MPI2_SASPHY3_EVENT_CODE_RX_AIP (0xD2)
/* Following codes are product specific and in MPI v2.6 and later */
#define MPI2_SASPHY3_EVENT_CODE_LCARB_WAIT_TIME (0xD3)
#define MPI2_SASPHY3_EVENT_CODE_RCVD_CONN_RESP_WAIT_TIME (0xD4)
@ -2898,7 +2991,6 @@ typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG
#define MPI2_SASPHY3_EVENT_CODE_SATA_RX_START_RECEIVE (0xDB)
#define MPI2_SASPHY3_EVENT_CODE_SMP_RX_START_RECEIVE (0xDC)
/* values for the CounterType field */
#define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING (0x00)
#define MPI2_SASPHY3_COUNTER_TYPE_SATURATING (0x01)
@ -2989,7 +3081,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_PORT_0
* SAS Enclosure Config Pages
****************************************************************************/
/* SAS Enclosure Page 0 */
/* SAS Enclosure Page 0, Enclosure Page 0 */
typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0
{
@ -3007,7 +3099,10 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0
U32 Reserved4; /* 0x24 */
} MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0,
MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0,
Mpi2SasEnclosurePage0_t, MPI2_POINTER pMpi2SasEnclosurePage0_t;
Mpi2SasEnclosurePage0_t, MPI2_POINTER pMpi2SasEnclosurePage0_t,
MPI26_CONFIG_PAGE_ENCLOSURE_0,
MPI2_POINTER PTR_MPI26_CONFIG_PAGE_ENCLOSURE_0,
Mpi26EnclosurePage0_t, MPI2_POINTER pMpi26EnclosurePage0_t;
#define MPI2_SASENCLOSURE0_PAGEVERSION (0x04)
@ -3021,6 +3116,17 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0
#define MPI2_SAS_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0004)
#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_GPIO (0x0005)
#define MPI26_ENCLOSURE0_PAGEVERSION (0x04)
/* Values for Enclosure Page 0 Flags field */
#define MPI26_ENCLS0_FLAGS_ENCL_LEVEL_VALID (0x0010)
#define MPI26_ENCLS0_FLAGS_MNG_MASK (0x000F)
#define MPI26_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000)
#define MPI26_ENCLS0_FLAGS_MNG_IOC_SES (0x0001)
#define MPI26_ENCLS0_FLAGS_MNG_IOC_SGPIO (0x0002)
#define MPI26_ENCLS0_FLAGS_MNG_EXP_SGPIO (0x0003)
#define MPI26_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0004)
#define MPI26_ENCLS0_FLAGS_MNG_IOC_GPIO (0x0005)
/****************************************************************************
* Log Config Page
@ -3300,5 +3406,424 @@ typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS
/* PageVersion should be provided by product-specific code */
/****************************************************************************
* values for fields used by several types of PCIe Config Pages
****************************************************************************/
/* values for NegotiatedLinkRates fields */
#define MPI26_PCIE_NEG_LINK_RATE_MASK_PHYSICAL (0x0F)
/* link rates used for Negotiated Physical Link Rate */
#define MPI26_PCIE_NEG_LINK_RATE_UNKNOWN (0x00)
#define MPI26_PCIE_NEG_LINK_RATE_PHY_DISABLED (0x01)
#define MPI26_PCIE_NEG_LINK_RATE_2_5 (0x02)
#define MPI26_PCIE_NEG_LINK_RATE_5_0 (0x03)
#define MPI26_PCIE_NEG_LINK_RATE_8_0 (0x04)
#define MPI26_PCIE_NEG_LINK_RATE_16_0 (0x05)
/****************************************************************************
* PCIe IO Unit Config Pages (MPI v2.6 and later)
****************************************************************************/
/* PCIe IO Unit Page 0 */
typedef struct _MPI26_PCIE_IO_UNIT0_PHY_DATA
{
U8 Link; /* 0x00 */
U8 LinkFlags; /* 0x01 */
U8 PhyFlags; /* 0x02 */
U8 NegotiatedLinkRate; /* 0x03 */
U32 ControllerPhyDeviceInfo;/* 0x04 */
U16 AttachedDevHandle; /* 0x08 */
U16 ControllerDevHandle; /* 0x0A */
U32 EnumerationStatus; /* 0x0C */
U32 Reserved1; /* 0x10 */
} MPI26_PCIE_IO_UNIT0_PHY_DATA, MPI2_POINTER PTR_MPI26_PCIE_IO_UNIT0_PHY_DATA,
Mpi26PCIeIOUnit0PhyData_t, MPI2_POINTER pMpi26PCIeIOUnit0PhyData_t;
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
* one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI26_PCIE_IOUNIT0_PHY_MAX
#define MPI26_PCIE_IOUNIT0_PHY_MAX (1)
#endif
typedef struct _MPI26_CONFIG_PAGE_PIOUNIT_0
{
MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
U32 Reserved1; /* 0x08 */
U8 NumPhys; /* 0x0C */
U8 InitStatus; /* 0x0D */
U16 Reserved3; /* 0x0E */
MPI26_PCIE_IO_UNIT0_PHY_DATA PhyData[MPI26_PCIE_IOUNIT0_PHY_MAX]; /* 0x10 */
} MPI26_CONFIG_PAGE_PIOUNIT_0,
MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PIOUNIT_0,
Mpi26PCIeIOUnitPage0_t, MPI2_POINTER pMpi26PCIeIOUnitPage0_t;
#define MPI26_PCIEIOUNITPAGE0_PAGEVERSION (0x00)
/* values for PCIe IO Unit Page 0 LinkFlags */
#define MPI26_PCIEIOUNIT0_LINKFLAGS_ENUMERATION_IN_PROGRESS (0x08)
/* values for PCIe IO Unit Page 0 PhyFlags */
#define MPI26_PCIEIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08)
/* use MPI26_PCIE_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
/* see mpi2_pci.h for values for PCIe IO Unit Page 0 ControllerPhyDeviceInfo values */
/* values for PCIe IO Unit Page 0 EnumerationStatus */
#define MPI26_PCIEIOUNIT0_ES_MAX_SWITCHES_EXCEEDED (0x40000000)
#define MPI26_PCIEIOUNIT0_ES_MAX_DEVICES_EXCEEDED (0x20000000)
/* PCIe IO Unit Page 1 */
typedef struct _MPI26_PCIE_IO_UNIT1_PHY_DATA
{
U8 Link; /* 0x00 */
U8 LinkFlags; /* 0x01 */
U8 PhyFlags; /* 0x02 */
U8 MaxMinLinkRate; /* 0x03 */
U32 ControllerPhyDeviceInfo; /* 0x04 */
U32 Reserved1; /* 0x08 */
} MPI26_PCIE_IO_UNIT1_PHY_DATA, MPI2_POINTER PTR_MPI26_PCIE_IO_UNIT1_PHY_DATA,
Mpi26PCIeIOUnit1PhyData_t, MPI2_POINTER pMpi26PCIeIOUnit1PhyData_t;
/* values for LinkFlags */
#define MPI26_PCIEIOUNIT1_LINKFLAGS_DIS_SRIS (0x00)
#define MPI26_PCIEIOUNIT1_LINKFLAGS_EN_SRIS (0x01)
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
* one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI26_PCIE_IOUNIT1_PHY_MAX
#define MPI26_PCIE_IOUNIT1_PHY_MAX (1)
#endif
typedef struct _MPI26_CONFIG_PAGE_PIOUNIT_1
{
MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
U16 ControlFlags; /* 0x08 */
U16 Reserved; /* 0x0A */
U16 AdditionalControlFlags; /* 0x0C */
U16 NVMeMaxQueueDepth; /* 0x0E */
U8 NumPhys; /* 0x10 */
U8 Reserved1; /* 0x11 */
U16 Reserved2; /* 0x12 */
MPI26_PCIE_IO_UNIT1_PHY_DATA PhyData[MPI26_PCIE_IOUNIT1_PHY_MAX];/* 0x14 */
} MPI26_CONFIG_PAGE_PIOUNIT_1,
MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PIOUNIT_1,
Mpi26PCIeIOUnitPage1_t, MPI2_POINTER pMpi26PCIeIOUnitPage1_t;
#define MPI26_PCIEIOUNITPAGE1_PAGEVERSION (0x00)
/* values for PCIe IO Unit Page 1 PhyFlags */
#define MPI26_PCIEIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08)
#define MPI26_PCIEIOUNIT1_PHYFLAGS_ENDPOINT_ONLY (0x01)
/* values for PCIe IO Unit Page 1 MaxMinLinkRate */
#define MPI26_PCIEIOUNIT1_MAX_RATE_MASK (0xF0)
#define MPI26_PCIEIOUNIT1_MAX_RATE_SHIFT (4)
#define MPI26_PCIEIOUNIT1_MAX_RATE_2_5 (0x20)
#define MPI26_PCIEIOUNIT1_MAX_RATE_5_0 (0x30)
#define MPI26_PCIEIOUNIT1_MAX_RATE_8_0 (0x40)
#define MPI26_PCIEIOUNIT1_MAX_RATE_16_0 (0x50)
/* see mpi2_pci.h for values for PCIe IO Unit Page 0 ControllerPhyDeviceInfo values */
/****************************************************************************
* PCIe Switch Config Pages (MPI v2.6 and later)
****************************************************************************/
/* PCIe Switch Page 0 */
typedef struct _MPI26_CONFIG_PAGE_PSWITCH_0
{
MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
U8 PhysicalPort; /* 0x08 */
U8 Reserved1; /* 0x09 */
U16 Reserved2; /* 0x0A */
U16 DevHandle; /* 0x0C */
U16 ParentDevHandle; /* 0x0E */
U8 NumPorts; /* 0x10 */
U8 PCIeLevel; /* 0x11 */
U16 Reserved3; /* 0x12 */
U32 Reserved4; /* 0x14 */
U32 Reserved5; /* 0x18 */
U32 Reserved6; /* 0x1C */
} MPI26_CONFIG_PAGE_PSWITCH_0, MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PSWITCH_0,
Mpi26PCIeSwitchPage0_t, MPI2_POINTER pMpi26PCIeSwitchPage0_t;
#define MPI26_PCIESWITCH0_PAGEVERSION (0x00)
/* PCIe Switch Page 1 */
typedef struct _MPI26_CONFIG_PAGE_PSWITCH_1
{
MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
U8 PhysicalPort; /* 0x08 */
U8 Reserved1; /* 0x09 */
U16 Reserved2; /* 0x0A */
U8 NumPorts; /* 0x0C */
U8 PortNum; /* 0x0D */
U16 AttachedDevHandle; /* 0x0E */
U16 SwitchDevHandle; /* 0x10 */
U8 NegotiatedPortWidth; /* 0x12 */
U8 NegotiatedLinkRate; /* 0x13 */
U32 Reserved4; /* 0x14 */
U32 Reserved5; /* 0x18 */
} MPI26_CONFIG_PAGE_PSWITCH_1, MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PSWITCH_1,
Mpi26PCIeSwitchPage1_t, MPI2_POINTER pMpi26PCIeSwitchPage1_t;
#define MPI26_PCIESWITCH1_PAGEVERSION (0x00)
/* use MPI26_PCIE_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
/****************************************************************************
* PCIe Device Config Pages (MPI v2.6 and later)
****************************************************************************/
/* PCIe Device Page 0 */
typedef struct _MPI26_CONFIG_PAGE_PCIEDEV_0
{
MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
U16 Slot; /* 0x08 */
U16 EnclosureHandle; /* 0x0A */
U64 WWID; /* 0x0C */
U16 ParentDevHandle; /* 0x14 */
U8 PortNum; /* 0x16 */
U8 AccessStatus; /* 0x17 */
U16 DevHandle; /* 0x18 */
U8 PhysicalPort; /* 0x1A */
U8 Reserved1; /* 0x1B */
U32 DeviceInfo; /* 0x1C */
U32 Flags; /* 0x20 */
U8 SupportedLinkRates; /* 0x24 */
U8 MaxPortWidth; /* 0x25 */
U8 NegotiatedPortWidth; /* 0x26 */
U8 NegotiatedLinkRate; /* 0x27 */
U8 EnclosureLevel; /* 0x28 */
U8 Reserved2; /* 0x29 */
U16 Reserved3; /* 0x2A */
U8 ConnectorName[4]; /* 0x2C */
U32 Reserved4; /* 0x30 */
U32 Reserved5; /* 0x34 */
} MPI26_CONFIG_PAGE_PCIEDEV_0, MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PCIEDEV_0,
Mpi26PCIeDevicePage0_t, MPI2_POINTER pMpi26PCIeDevicePage0_t;
#define MPI26_PCIEDEVICE0_PAGEVERSION (0x01)
/* values for PCIe Device Page 0 AccessStatus field */
#define MPI26_PCIEDEV0_ASTATUS_NO_ERRORS (0x00)
#define MPI26_PCIEDEV0_ASTATUS_NEEDS_INITIALIZATION (0x04)
#define MPI26_PCIEDEV0_ASTATUS_CAPABILITY_FAILED (0x02)
#define MPI26_PCIEDEV0_ASTATUS_DEVICE_BLOCKED (0x07)
#define MPI26_PCIEDEV0_ASTATUS_MEMORY_SPACE_ACCESS_FAILED (0x08)
#define MPI26_PCIEDEV0_ASTATUS_UNSUPPORTED_DEVICE (0x09)
#define MPI26_PCIEDEV0_ASTATUS_MSIX_REQUIRED (0x0A)
#define MPI26_PCIEDEV0_ASTATUS_UNKNOWN (0x10)
#define MPI26_PCIEDEV0_ASTATUS_NVME_READY_TIMEOUT (0x30)
#define MPI26_PCIEDEV0_ASTATUS_NVME_DEVCFG_UNSUPPORTED (0x31)
#define MPI26_PCIEDEV0_ASTATUS_NVME_IDENTIFY_FAILED (0x32)
#define MPI26_PCIEDEV0_ASTATUS_NVME_QCONFIG_FAILED (0x33)
#define MPI26_PCIEDEV0_ASTATUS_NVME_QCREATION_FAILED (0x34)
#define MPI26_PCIEDEV0_ASTATUS_NVME_EVENTCFG_FAILED (0x35)
#define MPI26_PCIEDEV0_ASTATUS_NVME_GET_FEATURE_STAT_FAILED (0x36)
#define MPI26_PCIEDEV0_ASTATUS_NVME_IDLE_TIMEOUT (0x37)
#define MPI26_PCIEDEV0_ASTATUS_NVME_FAILURE_STATUS (0x38)
#define MPI26_PCIEDEV0_ASTATUS_INIT_FAIL_MAX (0x3F)
/* see mpi2_pci.h for the MPI26_PCIE_DEVINFO_ defines used for the DeviceInfo field */
/* values for PCIe Device Page 0 Flags field */
#define MPI26_PCIEDEV0_FLAGS_UNAUTHORIZED_DEVICE (0x8000)
#define MPI26_PCIEDEV0_FLAGS_ENABLED_FAST_PATH (0x4000)
#define MPI26_PCIEDEV0_FLAGS_FAST_PATH_CAPABLE (0x2000)
#define MPI26_PCIEDEV0_FLAGS_ASYNCHRONOUS_NOTIFICATION (0x0400)
#define MPI26_PCIEDEV0_FLAGS_ATA_SW_PRESERVATION (0x0200)
#define MPI26_PCIEDEV0_FLAGS_UNSUPPORTED_DEVICE (0x0100)
#define MPI26_PCIEDEV0_FLAGS_ATA_48BIT_LBA_SUPPORTED (0x0080)
#define MPI26_PCIEDEV0_FLAGS_ATA_SMART_SUPPORTED (0x0040)
#define MPI26_PCIEDEV0_FLAGS_ATA_NCQ_SUPPORTED (0x0020)
#define MPI26_PCIEDEV0_FLAGS_ATA_FUA_SUPPORTED (0x0010)
#define MPI26_PCIEDEV0_FLAGS_ENCL_LEVEL_VALID (0x0002)
#define MPI26_PCIEDEV0_FLAGS_DEVICE_PRESENT (0x0001)
/* values for PCIe Device Page 0 SupportedLinkRates field */
#define MPI26_PCIEDEV0_LINK_RATE_16_0_SUPPORTED (0x08)
#define MPI26_PCIEDEV0_LINK_RATE_8_0_SUPPORTED (0x04)
#define MPI26_PCIEDEV0_LINK_RATE_5_0_SUPPORTED (0x02)
#define MPI26_PCIEDEV0_LINK_RATE_2_5_SUPPORTED (0x01)
/* use MPI26_PCIE_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
/* PCIe Device Page 2 */
typedef struct _MPI26_CONFIG_PAGE_PCIEDEV_2
{
MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
U16 DevHandle; /* 0x08 */
U16 Reserved1; /* 0x0A */
U32 MaximumDataTransferSize;/* 0x0C */
U32 Capabilities; /* 0x10 */
U32 Reserved2; /* 0x14 */
} MPI26_CONFIG_PAGE_PCIEDEV_2, MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PCIEDEV_2,
Mpi26PCIeDevicePage2_t, MPI2_POINTER pMpi26PCIeDevicePage2_t;
#define MPI26_PCIEDEVICE2_PAGEVERSION (0x00)
/* defines for PCIe Device Page 2 Capabilities field */
#define MPI26_PCIEDEV2_CAP_SGL_FORMAT (0x00000004)
#define MPI26_PCIEDEV2_CAP_BIT_BUCKET_SUPPORT (0x00000002)
#define MPI26_PCIEDEV2_CAP_SGL_SUPPORT (0x00000001)
/****************************************************************************
* PCIe Link Config Pages (MPI v2.6 and later)
****************************************************************************/
/* PCIe Link Page 1 */
typedef struct _MPI26_CONFIG_PAGE_PCIELINK_1
{
MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
U8 Link; /* 0x08 */
U8 Reserved1; /* 0x09 */
U16 Reserved2; /* 0x0A */
U32 CorrectableErrorCount; /* 0x0C */
U16 NonFatalErrorCount; /* 0x10 */
U16 Reserved3; /* 0x12 */
U16 FatalErrorCount; /* 0x14 */
U16 Reserved4; /* 0x16 */
} MPI26_CONFIG_PAGE_PCIELINK_1, MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PCIELINK_1,
Mpi26PcieLinkPage1_t, MPI2_POINTER pMpi26PcieLinkPage1_t;
#define MPI26_PCIELINK1_PAGEVERSION (0x00)
/* PCIe Link Page 2 */
typedef struct _MPI26_PCIELINK2_LINK_EVENT
{
U8 LinkEventCode; /* 0x00 */
U8 Reserved1; /* 0x01 */
U16 Reserved2; /* 0x02 */
U32 LinkEventInfo; /* 0x04 */
} MPI26_PCIELINK2_LINK_EVENT, MPI2_POINTER PTR_MPI26_PCIELINK2_LINK_EVENT,
Mpi26PcieLink2LinkEvent_t, MPI2_POINTER pMpi26PcieLink2LinkEvent_t;
/* use MPI26_PCIELINK3_EVTCODE_ for the LinkEventCode field */
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
* one and check the value returned for NumLinkEvents at runtime.
*/
#ifndef MPI26_PCIELINK2_LINK_EVENT_MAX
#define MPI26_PCIELINK2_LINK_EVENT_MAX (1)
#endif
typedef struct _MPI26_CONFIG_PAGE_PCIELINK_2
{
MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
U8 Link; /* 0x08 */
U8 Reserved1; /* 0x09 */
U16 Reserved2; /* 0x0A */
U8 NumLinkEvents; /* 0x0C */
U8 Reserved3; /* 0x0D */
U16 Reserved4; /* 0x0E */
MPI26_PCIELINK2_LINK_EVENT LinkEvent[MPI26_PCIELINK2_LINK_EVENT_MAX]; /* 0x10 */
} MPI26_CONFIG_PAGE_PCIELINK_2, MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PCIELINK_2,
Mpi26PcieLinkPage2_t, MPI2_POINTER pMpi26PcieLinkPage2_t;
#define MPI26_PCIELINK2_PAGEVERSION (0x00)
/* PCIe Link Page 3 */
typedef struct _MPI26_PCIELINK3_LINK_EVENT_CONFIG
{
U8 LinkEventCode; /* 0x00 */
U8 Reserved1; /* 0x01 */
U16 Reserved2; /* 0x02 */
U8 CounterType; /* 0x04 */
U8 ThresholdWindow; /* 0x05 */
U8 TimeUnits; /* 0x06 */
U8 Reserved3; /* 0x07 */
U32 EventThreshold; /* 0x08 */
U16 ThresholdFlags; /* 0x0C */
U16 Reserved4; /* 0x0E */
} MPI26_PCIELINK3_LINK_EVENT_CONFIG, MPI2_POINTER PTR_MPI26_PCIELINK3_LINK_EVENT_CONFIG,
Mpi26PcieLink3LinkEventConfig_t, MPI2_POINTER pMpi26PcieLink3LinkEventConfig_t;
/* values for LinkEventCode field */
#define MPI26_PCIELINK3_EVTCODE_NO_EVENT (0x00)
#define MPI26_PCIELINK3_EVTCODE_CORRECTABLE_ERROR_RECEIVED (0x01)
#define MPI26_PCIELINK3_EVTCODE_NON_FATAL_ERROR_RECEIVED (0x02)
#define MPI26_PCIELINK3_EVTCODE_FATAL_ERROR_RECEIVED (0x03)
#define MPI26_PCIELINK3_EVTCODE_DATA_LINK_ERROR_DETECTED (0x04)
#define MPI26_PCIELINK3_EVTCODE_TRANSACTION_LAYER_ERROR_DETECTED (0x05)
#define MPI26_PCIELINK3_EVTCODE_TLP_ECRC_ERROR_DETECTED (0x06)
#define MPI26_PCIELINK3_EVTCODE_POISONED_TLP (0x07)
#define MPI26_PCIELINK3_EVTCODE_RECEIVED_NAK_DLLP (0x08)
#define MPI26_PCIELINK3_EVTCODE_SENT_NAK_DLLP (0x09)
#define MPI26_PCIELINK3_EVTCODE_LTSSM_RECOVERY_STATE (0x0A)
#define MPI26_PCIELINK3_EVTCODE_LTSSM_RXL0S_STATE (0x0B)
#define MPI26_PCIELINK3_EVTCODE_LTSSM_TXL0S_STATE (0x0C)
#define MPI26_PCIELINK3_EVTCODE_LTSSM_L1_STATE (0x0D)
#define MPI26_PCIELINK3_EVTCODE_LTSSM_DISABLED_STATE (0x0E)
#define MPI26_PCIELINK3_EVTCODE_LTSSM_HOT_RESET_STATE (0x0F)
#define MPI26_PCIELINK3_EVTCODE_SYSTEM_ERROR (0x10)
#define MPI26_PCIELINK3_EVTCODE_DECODE_ERROR (0x11)
#define MPI26_PCIELINK3_EVTCODE_DISPARITY_ERROR (0x12)
/* values for the CounterType field */
#define MPI26_PCIELINK3_COUNTER_TYPE_WRAPPING (0x00)
#define MPI26_PCIELINK3_COUNTER_TYPE_SATURATING (0x01)
#define MPI26_PCIELINK3_COUNTER_TYPE_PEAK_VALUE (0x02)
/* values for the TimeUnits field */
#define MPI26_PCIELINK3_TM_UNITS_10_MICROSECONDS (0x00)
#define MPI26_PCIELINK3_TM_UNITS_100_MICROSECONDS (0x01)
#define MPI26_PCIELINK3_TM_UNITS_1_MILLISECOND (0x02)
#define MPI26_PCIELINK3_TM_UNITS_10_MILLISECONDS (0x03)
/* values for the ThresholdFlags field */
#define MPI26_PCIELINK3_TFLAGS_EVENT_NOTIFY (0x0001)
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
* one and check the value returned for NumLinkEvents at runtime.
*/
#ifndef MPI26_PCIELINK3_LINK_EVENT_MAX
#define MPI26_PCIELINK3_LINK_EVENT_MAX (1)
#endif
typedef struct _MPI26_CONFIG_PAGE_PCIELINK_3
{
MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
U8 Link; /* 0x08 */
U8 Reserved1; /* 0x09 */
U16 Reserved2; /* 0x0A */
U8 NumLinkEvents; /* 0x0C */
U8 Reserved3; /* 0x0D */
U16 Reserved4; /* 0x0E */
MPI26_PCIELINK3_LINK_EVENT_CONFIG LinkEventConfig[MPI26_PCIELINK3_LINK_EVENT_MAX]; /* 0x10 */
} MPI26_CONFIG_PAGE_PCIELINK_3, MPI2_POINTER PTR_MPI26_CONFIG_PAGE_PCIELINK_3,
Mpi26PcieLinkPage3_t, MPI2_POINTER pMpi26PcieLinkPage3_t;
#define MPI26_PCIELINK3_PAGEVERSION (0x00)
#endif

View File

@ -42,7 +42,7 @@
* Title: MPI Host Based Discovery messages and structures
* Creation Date: October 21, 2009
*
* mpi2_hbd.h Version: 02.00.03
* mpi2_hbd.h Version: 02.00.04
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@ -59,6 +59,7 @@
* HBD Action request, replaced by AdditionalInfo field.
* 11-18-11 02.00.02 Incorporating additions for MPI v2.5.
* 11-18-14 02.00.03 Updated copyright information.
* 02-17-16 02.00.04 Added SAS 4 22.5 gbs speed support.
* --------------------------------------------------------------------------
*/
@ -129,6 +130,7 @@ typedef struct _MPI2_HBD_ACTION_REQUEST
#define MPI2_HBD_MAX_RATE_3_0 (0x09)
#define MPI2_HBD_MAX_RATE_6_0 (0x0A)
#define MPI25_HBD_MAX_RATE_12_0 (0x0B)
#define MPI26_HBD_MAX_RATE_22_5 (0x0C)
/* Host Based Discovery Action Reply Message */

View File

@ -41,24 +41,25 @@
All rights reserved.
---------------------------------------
Header Set Release Version: 02.00.42
Header Set Release Date: 01-04-16
Header Set Release Version: 02.00.46
Header Set Release Date: 09-07-16
---------------------------------------
Filename Current version Prior version
---------- --------------- -------------
mpi2.h 02.00.42 02.00.41
mpi2_cnfg.h 02.00.35 02.00.34
mpi2_init.h 02.00.20 02.00.19
mpi2_ioc.h 02.00.27 02.00.27
mpi2.h 02.00.46 02.00.45
mpi2_cnfg.h 02.00.39 02.00.38
mpi2_init.h 02.00.21 02.00.21
mpi2_ioc.h 02.00.30 02.00.29
mpi2_raid.h 02.00.11 02.00.11
mpi2_sas.h 02.00.10 02.00.10
mpi2_targ.h 02.00.09 02.00.09
mpi2_tool.h 02.00.13 02.00.13
mpi2_tool.h 02.00.14 02.00.13
mpi2_type.h 02.00.01 02.00.01
mpi2_ra.h 02.00.01 02.00.01
mpi2_hbd.h 02.00.03 02.00.03
mpi2_history.txt 02.00.41 02.00.40
mpi2_hbd.h 02.00.04 02.00.04
mpi2_pci.h 02.00.02 02.00.02
mpi2_history.txt 02.00.43 02.00.43
* Date Version Description
@ -141,7 +142,8 @@ mpi2.h
* Bumped MPI2_HEADER_VERSION_UNIT.
* 03-16-15 02.00.37 Updated for MPI v2.6.
* Bumped MPI2_HEADER_VERSION_UNIT.
* Added Scratchpad registers to
* Added Scratchpad registers and
* AtomicRequestDescriptorPost register to
* MPI2_SYSTEM_INTERFACE_REGS.
* Added MPI2_DIAG_SBR_RELOAD.
* Added MPI2_IOCSTATUS_INSUFFICIENT_POWER.
@ -151,6 +153,14 @@ mpi2.h
* Added V7 HostDiagnostic register defines
* 12-15-15 02.00.41 Bumped MPI_HEADER_VERSION_UNIT
* 01-04-16 02.00.42 Bumped MPI_HEADER_VERSION_UNIT
* 04-05-16 02.00.43 Modified MPI26_DIAG_BOOT_DEVICE_SELECT defines
* to be unique within first 32 characters.
* Removed AHCI support.
* Removed SOP support.
* Bumped MPI2_HEADER_VERSION_UNIT.
* 04-10-16 02.00.44 Bumped MPI2_HEADER_VERSION_UNIT.
* 07-06-16 02.00.45 Bumped MPI2_HEADER_VERSION_UNIT.
* 09-02-16 02.00.46 Bumped MPI2_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
mpi2_cnfg.h
@ -323,9 +333,38 @@ mpi2_cnfg.h
* Flags field to IO Unit Page 7.
* Added IO Unit Page 11.
* Added new SAS Phy Event codes
* Added PCIe configuration pages.
* 03-19-15 02.00.32 Fixed PCIe Link Config page structure names to be
* unique in first 32 characters.
* 05-25-15 02.00.33 Added more defines for the BiosOptions field of
* MPI2_CONFIG_PAGE_BIOS_1.
* 08-25-15 02.00.34 Added PCIe Device Page 2 SGL format capability.
* 12-18-15 02.00.35 Added SATADeviceWaitTime to SAS IO Unit Page 4.
* 01-21-16 02.00.36 Added/modified MPI2_MFGPAGE_DEVID_SAS defines.
* Added Link field to PCIe Link Pages
* Added EnclosureLevel and ConnectorName to PCIe
* Device Page 0.
* Added define for PCIE IoUnit page 1 max rate shift.
* Added comment for reserved ExtPageTypes.
* Added SAS 4 22.5 gbs speed support.
* Added PCIe 4 16.0 GT/sec speec support.
* Removed AHCI support.
* Removed SOP support.
* Added NegotiatedLinkRate and NegotiatedPortWidth to
* PCIe device page 0.
* 04-10-16 02.00.37 Fixed MPI2_MFGPAGE_DEVID_SAS3616/3708 defines
* 07-01-16 02.00.38 Added Manufacturing page 7 Connector types.
* Changed declaration of ConnectorName in PCIe DevicePage0
* to match SAS DevicePage 0.
* Added SATADeviceWaitTime to IO Unit Page 11.
* Added MPI26_MFGPAGE_DEVID_SAS4008
* Added x16 PCIe width to IO Unit Page 7
* Added LINKFLAGS to control SRIS in PCIe IO Unit page 1
* phy data.
* Added InitStatus to PCIe IO Unit Page 1 header.
* 09-01-16 02.00.39 Added MPI26_CONFIG_PAGE_ENCLOSURE_0 and related defines.
* Added MPI26_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE and
* MPI26_ENCLOS_PGAD_FORM_HANDLE page address formats.
* --------------------------------------------------------------------------
mpi2_init.h
@ -365,6 +404,8 @@ mpi2_init.h
* 08-26-15 02.00.18 Added SCSITASKMGMT_MSGFLAGS for Target Reset.
* 12-18-15 02.00.19 Added EEDPObservedValue added to SCSI IO Reply message.
* 01-04-16 02.00.20 Modified EEDP reported values in SCSI IO Reply message.
* 01-21-16 02.00.21 Modified MPI26_SCSITASKMGMT_MSGFLAGS_PCIE* defines to
* be unique within first 32 characters.
* --------------------------------------------------------------------------
mpi2_ioc.h
@ -491,9 +532,30 @@ mpi2_ioc.h
* MPI26_EVENT_DATA_PCIE_LINK_COUNTER.
* Added MPI26_CTRL_OP_SHUTDOWN.
* Added MPI26_CTRL_OP_LINK_CLEAR_ERROR_LOG
* Added MPI26_FW_HEADER_PID_FAMILY_3324_SAS
* Added MPI26_FW_HEADER_PID_FAMILY_3324_SAS and
* MPI26_FW_HEADER_PID_FAMILY_3516_SAS.
* 08-25-15 02.00.27 Added IC ARCH Class based signature defines.
* --------------------------------------------------------------------------
* Added MPI26_EVENT_PCIE_ENUM_ES_RESOURCES_EXHAUSTED event.
* Added ConigurationFlags field to IOCInit message to
* support NVMe SGL format control.
* Added PCIe SRIOV support.
* 02-17-16 02.00.28 Added SAS 4 22.5 gbs speed support.
* Added PCIe 4 16.0 GT/sec speec support.
* Removed AHCI support.
* Removed SOP support.
* 07-01-16 02.00.29 Added Archclass for 4008 product.
* Added IOCException MPI2_IOCFACTS_EXCEPT_PCIE_DISABLED.
* 08-23-16 02.00.30 Added new defines for the ImageType field of FWDownload
* Request Message.
* Added new defines for the ImageType field of FWUpload
* Request Message.
* Added new values for the RegionType field in the Layout
* Data sections of the FLASH Layout Extended Image Data.
* Added new defines for the ReasonCode field of
* Active Cable Exception Event.
* Added MPI2_EVENT_ENCL_DEVICE_STATUS_CHANGE and
* MPI26_EVENT_DATA_ENCL_DEV_STATUS_CHANGE.
* --------------------------------------------------------------------------
mpi2_raid.h
* 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
@ -581,6 +643,8 @@ mpi2_tool.h
* 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info.
* 01-08-14 02.00.12 Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC.
* 11-18-14 02.00.13 Updated copyright information.
* 08-25-16 02.00.14 Added new values for the Flags field of Toolbox Clean
* Tool Request Message.
* --------------------------------------------------------------------------
mpi2_type.h
@ -599,24 +663,33 @@ mpi2_hbd.h
* HBD Action request, replaced by AdditionalInfo field.
* 11-18-11 02.00.02 Incorporating additions for MPI v2.5.
* 11-18-14 02.00.03 Updated copyright information.
* 02-17-16 02.00.04 Added SAS 4 22.5 gbs speed support.
* --------------------------------------------------------------------------
mpi2_pci.h
* 03-16-15 02.00.00 Initial version.
* 02-17-16 02.00.01 Removed AHCI support.
* Removed SOP support.
* 07-01-16 02.00.02 Added MPI26_NVME_FLAGS_FORCE_ADMIN_ERR_RESP to
* NVME Encapsulated Request.
* --------------------------------------------------------------------------
mpi2_history.txt Parts list history
Filename 02.00.42
---------- --------
mpi2.h 02.00.42
mpi2_cnfg.h 02.00.35
mpi2_init.h 02.00.20
mpi2_ioc.h 02.00.27
mpi2_raid.h 02.00.11
mpi2_sas.h 02.00.10
mpi2_targ.h 02.00.09
mpi2_tool.h 02.00.13
mpi2_type.h 02.00.01
mpi2_ra.h 02.00.01
mpi2_hbd.h 02.00.03
Filename 02.00.46 02.00.45 02.00.44 02.00.43 02.00.42
---------- -------- -------- -------- -------- --------
mpi2.h 02.00.46 02.00.45 02.00.44 02.00.43 02.00.42
mpi2_cnfg.h 02.00.39 02.00.38 02.00.37 02.00.36 02.00.35
mpi2_init.h 02.00.21 02.00.21 02.00.21 02.00.21 02.00.20
mpi2_ioc.h 02.00.30 02.00.29 02.00.28 02.00.28 02.00.27
mpi2_raid.h 02.00.11 02.00.11 02.00.11 02.00.11 02.00.11
mpi2_sas.h 02.00.10 02.00.10 02.00.10 02.00.10 02.00.10
mpi2_targ.h 02.00.09 02.00.09 02.00.09 02.00.09 02.00.09
mpi2_tool.h 02.00.14 02.00.13 02.00.13 02.00.13 02.00.13
mpi2_type.h 02.00.01 02.00.01 02.00.01 02.00.01 02.00.01
mpi2_ra.h 02.00.01 02.00.01 02.00.01 02.00.01 02.00.01
mpi2_hbd.h 02.00.04 02.00.04 02.00.04 02.00.04 02.00.03
mpi2_pci.h 02.00.02 02.00.02 02.00.01 02.00.01 02.00.00
Filename 02.00.41 02.00.40 02.00.39 02.00.38 02.00.37 02.00.36
---------- -------- -------- -------- -------- -------- --------
@ -631,6 +704,7 @@ mpi2_tool.h 02.00.13 02.00.13 02.00.13 02.00.13 02.00.13 02.00.13
mpi2_type.h 02.00.01 02.00.01 02.00.01 02.00.01 02.00.01 02.00.01
mpi2_ra.h 02.00.01 02.00.01 02.00.01 02.00.01 02.00.01 02.00.01
mpi2_hbd.h 02.00.03 02.00.03 02.00.03 02.00.03 02.00.03 02.00.03
mpi2_pci.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
Filename 02.00.35 02.00.34 02.00.33 02.00.32 02.00.31 02.00.30
---------- -------- -------- -------- -------- -------- --------

View File

@ -42,7 +42,7 @@
* Title: MPI SCSI initiator mode messages and structures
* Creation Date: June 23, 2006
*
* mpi2_init.h Version: 02.00.20
* mpi2_init.h Version: 02.00.21
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@ -62,7 +62,7 @@
* 05-21-08 02.00.05 Fixed typo in name of Mpi2SepRequest_t.
* 10-02-08 02.00.06 Removed Untagged and No Disconnect values from SCSI IO
* Control field Task Attribute flags.
* Moved LUN field defines to mpi2.h becasue they are
* Moved LUN field defines to mpi2.h because they are
* common to many structures.
* 05-06-09 02.00.07 Changed task management type of Query Unit Attention to
* Query Asynchronous Event.
@ -90,6 +90,8 @@
* 08-26-15 02.00.18 Added SCSITASKMGMT_MSGFLAGS for Target Reset.
* 12-18-15 02.00.19 Added EEDPObservedValue added to SCSI IO Reply message.
* 01-04-16 02.00.20 Modified EEDP reported values in SCSI IO Reply message.
* 01-21-16 02.00.21 Modified MPI26_SCSITASKMGMT_MSGFLAGS_PCIE* defines to
* be unique within first 32 characters.
* --------------------------------------------------------------------------
*/
@ -491,12 +493,13 @@ typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST
#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION (MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT)
/* MsgFlags bits */
#define MPI2_SCSITASKMGMT_MSGFLAGS_MASK_TARGET_RESET (0x18)
#define MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET (0x00)
#define MPI2_SCSITASKMGMT_MSGFLAGS_MASK_TARGET_RESET (0x18)
#define MPI26_SCSITASKMGMT_MSGFLAGS_HOT_RESET_PCIE (0x00)
#define MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET (0x00)
#define MPI2_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x01)
#define MPI2_SCSITASKMGMT_MSGFLAGS_NEXUS_RESET_SRST (0x08)
#define MPI2_SCSITASKMGMT_MSGFLAGS_SAS_HARD_LINK_RESET (0x10)
#define MPI2_SCSITASKMGMT_MSGFLAGS_NEXUS_RESET_SRST (0x08)
#define MPI2_SCSITASKMGMT_MSGFLAGS_SAS_HARD_LINK_RESET (0x10)
#define MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE (0x18)
/* SCSI Task Management Reply Message */

View File

@ -42,7 +42,7 @@
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: October 11, 2006
*
* mpi2_ioc.h Version: 02.00.27
* mpi2_ioc.h Version: 02.00.30
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
@ -177,9 +177,29 @@
* MPI26_EVENT_DATA_PCIE_LINK_COUNTER.
* Added MPI26_CTRL_OP_SHUTDOWN.
* Added MPI26_CTRL_OP_LINK_CLEAR_ERROR_LOG
* Added MPI26_FW_HEADER_PID_FAMILY_3324_SAS
* 08-25-15 02.00.27 Added IC ARCH Class based signature defines
*
* Added MPI26_FW_HEADER_PID_FAMILY_3324_SAS and
* MPI26_FW_HEADER_PID_FAMILY_3516_SAS.
* 08-25-15 02.00.27 Added IC ARCH Class based signature defines.
* Added MPI26_EVENT_PCIE_ENUM_ES_RESOURCES_EXHAUSTED event.
* Added ConigurationFlags field to IOCInit message to
* support NVMe SGL format control.
* Added PCIe SRIOV support.
* 02-17-16 02.00.28 Added SAS 4 22.5 gbs speed support.
* Added PCIe 4 16.0 GT/sec speec support.
* Removed AHCI support.
* Removed SOP support.
* 07-01-16 02.00.29 Added Archclass for 4008 product.
* Added IOCException MPI2_IOCFACTS_EXCEPT_PCIE_DISABLED
* 08-23-16 02.00.30 Added new defines for the ImageType field of FWDownload
* Request Message.
* Added new defines for the ImageType field of FWUpload
* Request Message.
* Added new values for the RegionType field in the Layout
* Data sections of the FLASH Layout Extended Image Data.
* Added new defines for the ReasonCode field of
* Active Cable Exception Event.
* Added MPI2_EVENT_ENCL_DEVICE_STATUS_CHANGE and
* MPI26_EVENT_DATA_ENCL_DEV_STATUS_CHANGE.
* --------------------------------------------------------------------------
*/
@ -251,6 +271,9 @@ typedef struct _MPI2_IOC_INIT_REQUEST
#define MPI2_IOCINIT_HDRVERSION_DEV_MASK (0x00FF)
#define MPI2_IOCINIT_HDRVERSION_DEV_SHIFT (0)
/* ConfigurationFlags */
#define MPI26_IOCINIT_CFGFLAGS_NVME_SGL_FORMAT (0x0001)
/* minimum depth for a Reply Descriptor Post Queue */
#define MPI2_RDPQ_DEPTH_MIN (16)
@ -363,6 +386,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY
#define MPI2_IOCFACTS_HDRVERSION_DEV_SHIFT (0)
/* IOCExceptions */
#define MPI2_IOCFACTS_EXCEPT_PCIE_DISABLED (0x0400)
#define MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE (0x0200)
#define MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX (0x0100)
@ -383,6 +407,8 @@ typedef struct _MPI2_IOC_FACTS_REPLY
/* ProductID field uses MPI2_FW_HEADER_PID_ */
/* IOCCapabilities */
#define MPI26_IOCFACTS_CAPABILITY_PCIE_SRIOV (0x00100000)
#define MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ (0x00080000)
#define MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE (0x00040000)
#define MPI25_IOCFACTS_CAPABILITY_FAST_PATH_CAPABLE (0x00020000)
#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000)
@ -400,6 +426,7 @@ typedef struct _MPI2_IOC_FACTS_REPLY
#define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004)
/* ProtocolFlags */
#define MPI2_IOCFACTS_PROTOCOL_NVME_DEVICES (0x0008) /* MPI v2.6 and later */
#define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR (0x0002)
#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001)
@ -452,6 +479,7 @@ typedef struct _MPI2_PORT_FACTS_REPLY
#define MPI2_PORTFACTS_PORTTYPE_ISCSI (0x20)
#define MPI2_PORTFACTS_PORTTYPE_SAS_PHYSICAL (0x30)
#define MPI2_PORTFACTS_PORTTYPE_SAS_VIRTUAL (0x31)
#define MPI2_PORTFACTS_PORTTYPE_TRI_MODE (0x40) /* MPI v2.6 and later */
/****************************************************************************
@ -564,6 +592,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY
#define MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW (0x0019)
#define MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST (0x001C)
#define MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE (0x001D)
#define MPI2_EVENT_ENCL_DEVICE_STATUS_CHANGE (0x001D) /* MPI v2.6 and later */
#define MPI2_EVENT_IR_VOLUME (0x001E)
#define MPI2_EVENT_IR_PHYSICAL_DISK (0x001F)
#define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST (0x0020)
@ -576,6 +605,10 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY
#define MPI2_EVENT_TEMP_THRESHOLD (0x0027)
#define MPI2_EVENT_HOST_MESSAGE (0x0028)
#define MPI2_EVENT_POWER_PERFORMANCE_CHANGE (0x0029)
#define MPI2_EVENT_PCIE_DEVICE_STATUS_CHANGE (0x0030) /* MPI v2.6 and later */
#define MPI2_EVENT_PCIE_ENUMERATION (0x0031) /* MPI v2.6 and later */
#define MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST (0x0032) /* MPI v2.6 and later */
#define MPI2_EVENT_PCIE_LINK_COUNTER (0x0033) /* MPI v2.6 and later */
#define MPI2_EVENT_ACTIVE_CABLE_EXCEPTION (0x0034) /* MPI v2.6 and later */
#define MPI2_EVENT_MIN_PRODUCT_SPECIFIC (0x006E)
#define MPI2_EVENT_MAX_PRODUCT_SPECIFIC (0x007F)
@ -688,11 +721,9 @@ typedef struct _MPI26_EVENT_DATA_ACTIVE_CABLE_EXCEPT
MPI2_POINTER pMpi26EventDataActiveCableExcept_t;
/* defines for ReasonCode field */
#define MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER (0x00)
#define MPI26_EVENT_ACTIVE_CABLE_PRESENT (0x01)
#define MPI26_EVENT_ACTIVE_CABLE_DEGRADED (0x02)
#define MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER (0x00)
#define MPI26_EVENT_ACTIVE_CABLE_PRESENT (0x01)
#define MPI26_EVENT_ACTIVE_CABLE_DEGRADED (0x02)
/* Hard Reset Received Event data */
@ -1048,6 +1079,7 @@ typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST
#define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0 (0x09)
#define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A)
#define MPI25_EVENT_SAS_TOPO_LR_RATE_12_0 (0x0B)
#define MPI26_EVENT_SAS_TOPO_LR_RATE_22_5 (0x0C)
/* values for the PhyStatus field */
#define MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT (0x80)
@ -1075,12 +1107,19 @@ typedef struct _MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE
} MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE,
MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE,
Mpi2EventDataSasEnclDevStatusChange_t,
MPI2_POINTER pMpi2EventDataSasEnclDevStatusChange_t;
MPI2_POINTER pMpi2EventDataSasEnclDevStatusChange_t,
MPI26_EVENT_DATA_ENCL_DEV_STATUS_CHANGE,
MPI2_POINTER PTR_MPI26_EVENT_DATA_ENCL_DEV_STATUS_CHANGE,
Mpi26EventDataEnclDevStatusChange_t,
MPI2_POINTER pMpi26EventDataEnclDevStatusChange_t;
/* SAS Enclosure Device Status Change event ReasonCode values */
#define MPI2_EVENT_SAS_ENCL_RC_ADDED (0x01)
#define MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING (0x02)
/* Enclosure Device Status Change event ReasonCode values */
#define MPI26_EVENT_ENCL_RC_ADDED (0x01)
#define MPI26_EVENT_ENCL_RC_NOT_RESPONDING (0x02)
/* SAS PHY Counter Event data */
@ -1168,6 +1207,167 @@ typedef struct _MPI2_EVENT_DATA_HBD_PHY
#define MPI2_EVENT_HBD_DT_SAS (0x01)
/* PCIe Device Status Change Event data (MPI v2.6 and later) */
typedef struct _MPI26_EVENT_DATA_PCIE_DEVICE_STATUS_CHANGE
{
U16 TaskTag; /* 0x00 */
U8 ReasonCode; /* 0x02 */
U8 PhysicalPort; /* 0x03 */
U8 ASC; /* 0x04 */
U8 ASCQ; /* 0x05 */
U16 DevHandle; /* 0x06 */
U32 Reserved2; /* 0x08 */
U64 WWID; /* 0x0C */
U8 LUN[8]; /* 0x14 */
} MPI26_EVENT_DATA_PCIE_DEVICE_STATUS_CHANGE,
MPI2_POINTER PTR_MPI26_EVENT_DATA_PCIE_DEVICE_STATUS_CHANGE,
Mpi26EventDataPCIeDeviceStatusChange_t,
MPI2_POINTER pMpi26EventDataPCIeDeviceStatusChange_t;
/* PCIe Device Status Change Event data ReasonCode values */
#define MPI26_EVENT_PCIDEV_STAT_RC_SMART_DATA (0x05)
#define MPI26_EVENT_PCIDEV_STAT_RC_UNSUPPORTED (0x07)
#define MPI26_EVENT_PCIDEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08)
#define MPI26_EVENT_PCIDEV_STAT_RC_TASK_ABORT_INTERNAL (0x09)
#define MPI26_EVENT_PCIDEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A)
#define MPI26_EVENT_PCIDEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B)
#define MPI26_EVENT_PCIDEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C)
#define MPI26_EVENT_PCIDEV_STAT_RC_ASYNC_NOTIFICATION (0x0D)
#define MPI26_EVENT_PCIDEV_STAT_RC_CMP_INTERNAL_DEV_RESET (0x0E)
#define MPI26_EVENT_PCIDEV_STAT_RC_CMP_TASK_ABORT_INTERNAL (0x0F)
#define MPI26_EVENT_PCIDEV_STAT_RC_DEV_INIT_FAILURE (0x10)
/* PCIe Enumeration Event data (MPI v2.6 and later) */
typedef struct _MPI26_EVENT_DATA_PCIE_ENUMERATION
{
U8 Flags; /* 0x00 */
U8 ReasonCode; /* 0x01 */
U8 PhysicalPort; /* 0x02 */
U8 Reserved1; /* 0x03 */
U32 EnumerationStatus; /* 0x04 */
} MPI26_EVENT_DATA_PCIE_ENUMERATION,
MPI2_POINTER PTR_MPI26_EVENT_DATA_PCIE_ENUMERATION,
Mpi26EventDataPCIeEnumeration_t,
MPI2_POINTER pMpi26EventDataPCIeEnumeration_t;
/* PCIe Enumeration Event data Flags values */
#define MPI26_EVENT_PCIE_ENUM_DEVICE_CHANGE (0x02)
#define MPI26_EVENT_PCIE_ENUM_IN_PROGRESS (0x01)
/* PCIe Enumeration Event data ReasonCode values */
#define MPI26_EVENT_PCIE_ENUM_RC_STARTED (0x01)
#define MPI26_EVENT_PCIE_ENUM_RC_COMPLETED (0x02)
/* PCIe Enumeration Event data EnumerationStatus values */
#define MPI26_EVENT_PCIE_ENUM_ES_MAX_SWITCHES_EXCEED (0x40000000)
#define MPI26_EVENT_PCIE_ENUM_ES_MAX_DEVICES_EXCEED (0x20000000)
#define MPI26_EVENT_PCIE_ENUM_ES_RESOURCES_EXHAUSTED (0x10000000)
/* PCIe Topology Change List Event data (MPI v2.6 and later) */
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
* one and check NumEntries at runtime.
*/
#ifndef MPI26_EVENT_PCIE_TOPO_PORT_COUNT
#define MPI26_EVENT_PCIE_TOPO_PORT_COUNT (1)
#endif
typedef struct _MPI26_EVENT_PCIE_TOPO_PORT_ENTRY
{
U16 AttachedDevHandle; /* 0x00 */
U8 PortStatus; /* 0x02 */
U8 Reserved1; /* 0x03 */
U8 CurrentPortInfo; /* 0x04 */
U8 Reserved2; /* 0x05 */
U8 PreviousPortInfo; /* 0x06 */
U8 Reserved3; /* 0x07 */
} MPI26_EVENT_PCIE_TOPO_PORT_ENTRY,
MPI2_POINTER PTR_MPI26_EVENT_PCIE_TOPO_PORT_ENTRY,
Mpi26EventPCIeTopoPortEntry_t,
MPI2_POINTER pMpi26EventPCIeTopoPortEntry_t;
/* PCIe Topology Change List Event data PortStatus values */
#define MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED (0x01)
#define MPI26_EVENT_PCIE_TOPO_PS_NOT_RESPONDING (0x02)
#define MPI26_EVENT_PCIE_TOPO_PS_PORT_CHANGED (0x03)
#define MPI26_EVENT_PCIE_TOPO_PS_NO_CHANGE (0x04)
#define MPI26_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING (0x05)
/* PCIe Topology Change List Event data defines for CurrentPortInfo and PreviousPortInfo */
#define MPI26_EVENT_PCIE_TOPO_PI_LANE_MASK (0xF0)
#define MPI26_EVENT_PCIE_TOPO_PI_LANES_UNKNOWN (0x00)
#define MPI26_EVENT_PCIE_TOPO_PI_1_LANE (0x10)
#define MPI26_EVENT_PCIE_TOPO_PI_2_LANES (0x20)
#define MPI26_EVENT_PCIE_TOPO_PI_4_LANES (0x30)
#define MPI26_EVENT_PCIE_TOPO_PI_8_LANES (0x40)
#define MPI26_EVENT_PCIE_TOPO_PI_RATE_MASK (0x0F)
#define MPI26_EVENT_PCIE_TOPO_PI_RATE_UNKNOWN (0x00)
#define MPI26_EVENT_PCIE_TOPO_PI_RATE_DISABLED (0x01)
#define MPI26_EVENT_PCIE_TOPO_PI_RATE_2_5 (0x02)
#define MPI26_EVENT_PCIE_TOPO_PI_RATE_5_0 (0x03)
#define MPI26_EVENT_PCIE_TOPO_PI_RATE_8_0 (0x04)
#define MPI26_EVENT_PCIE_TOPO_PI_RATE_16_0 (0x05)
typedef struct _MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST
{
U16 EnclosureHandle; /* 0x00 */
U16 SwitchDevHandle; /* 0x02 */
U8 NumPorts; /* 0x04 */
U8 Reserved1; /* 0x05 */
U16 Reserved2; /* 0x06 */
U8 NumEntries; /* 0x08 */
U8 StartPortNum; /* 0x09 */
U8 SwitchStatus; /* 0x0A */
U8 PhysicalPort; /* 0x0B */
MPI26_EVENT_PCIE_TOPO_PORT_ENTRY PortEntry[MPI26_EVENT_PCIE_TOPO_PORT_COUNT]; /* 0x0C */
} MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST,
MPI2_POINTER PTR_MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST,
Mpi26EventDataPCIeTopologyChangeList_t,
MPI2_POINTER pMpi26EventDataPCIeTopologyChangeList_t;
/* PCIe Topology Change List Event data SwitchStatus values */
#define MPI26_EVENT_PCIE_TOPO_SS_NO_PCIE_SWITCH (0x00)
#define MPI26_EVENT_PCIE_TOPO_SS_ADDED (0x01)
#define MPI26_EVENT_PCIE_TOPO_SS_NOT_RESPONDING (0x02)
#define MPI26_EVENT_PCIE_TOPO_SS_RESPONDING (0x03)
#define MPI26_EVENT_PCIE_TOPO_SS_DELAY_NOT_RESPONDING (0x04)
/* PCIe Link Counter Event data (MPI v2.6 and later) */
typedef struct _MPI26_EVENT_DATA_PCIE_LINK_COUNTER
{
U64 TimeStamp; /* 0x00 */
U32 Reserved1; /* 0x08 */
U8 LinkEventCode; /* 0x0C */
U8 LinkNum; /* 0x0D */
U16 Reserved2; /* 0x0E */
U32 LinkEventInfo; /* 0x10 */
U8 CounterType; /* 0x14 */
U8 ThresholdWindow; /* 0x15 */
U8 TimeUnits; /* 0x16 */
U8 Reserved3; /* 0x17 */
U32 EventThreshold; /* 0x18 */
U16 ThresholdFlags; /* 0x1C */
U16 Reserved4; /* 0x1E */
} MPI26_EVENT_DATA_PCIE_LINK_COUNTER,
MPI2_POINTER PTR_MPI26_EVENT_DATA_PCIE_LINK_COUNTER,
Mpi26EventDataPcieLinkCounter_t, MPI2_POINTER pMpi26EventDataPcieLinkCounter_t;
/* use MPI26_PCIELINK3_EVTCODE_ values from mpi2_cnfg.h for the LinkEventCode field */
/* use MPI26_PCIELINK3_COUNTER_TYPE_ values from mpi2_cnfg.h for the CounterType field */
/* use MPI26_PCIELINK3_TIME_UNITS_ values from mpi2_cnfg.h for the TimeUnits field */
/* use MPI26_PCIELINK3_TFLAGS_ values from mpi2_cnfg.h for the ThresholdFlags field */
/****************************************************************************
* EventAck message
****************************************************************************/
@ -1293,6 +1493,13 @@ typedef struct _MPI2_FW_DOWNLOAD_REQUEST
#define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE (0x0A)
#define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B)
#define MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY (0x0C) /* MPI v2.5 and newer */
#define MPI2_FW_DOWNLOAD_ITYPE_SBR (0x0E)
#define MPI2_FW_DOWNLOAD_ITYPE_SBR_BACKUP (0x0F)
#define MPI2_FW_DOWNLOAD_ITYPE_HIIM (0x10)
#define MPI2_FW_DOWNLOAD_ITYPE_HIIA (0x11)
#define MPI2_FW_DOWNLOAD_ITYPE_CTLR (0x12)
#define MPI2_FW_DOWNLOAD_ITYPE_IMR_FIRMWARE (0x13)
#define MPI2_FW_DOWNLOAD_ITYPE_MR_NVDATA (0x14)
#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0)
/* MPI v2.0 FWDownload TransactionContext Element */
@ -1386,6 +1593,13 @@ typedef struct _MPI2_FW_UPLOAD_REQUEST
#define MPI2_FW_UPLOAD_ITYPE_COMPLETE (0x0A)
#define MPI2_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B)
#define MPI2_FW_UPLOAD_ITYPE_CBB_BACKUP (0x0D)
#define MPI2_FW_UPLOAD_ITYPE_SBR (0x0E)
#define MPI2_FW_UPLOAD_ITYPE_SBR_BACKUP (0x0F)
#define MPI2_FW_UPLOAD_ITYPE_HIIM (0x10)
#define MPI2_FW_UPLOAD_ITYPE_HIIA (0x11)
#define MPI2_FW_UPLOAD_ITYPE_CTLR (0x12)
#define MPI2_FW_UPLOAD_ITYPE_IMR_FIRMWARE (0x13)
#define MPI2_FW_UPLOAD_ITYPE_MR_NVDATA (0x14)
/* MPI v2.0 FWUpload TransactionContext Element */
typedef struct _MPI2_FW_UPLOAD_TCSGE
@ -1509,8 +1723,10 @@ typedef struct _MPI2_FW_IMAGE_HEADER
#define MPI26_FW_HEADER_SIGNATURE0_ARC_0 (0x5A)
#define MPI26_FW_HEADER_SIGNATURE0_ARC_1 (0x00)
#define MPI26_FW_HEADER_SIGNATURE0_ARC_2 (0x01)
#define MPI26_FW_HEADER_SIGNATURE0_ARC_3 (0x02)
#define MPI26_FW_HEADER_SIGNATURE0 (MPI26_FW_HEADER_SIGNATURE0_BASE+MPI26_FW_HEADER_SIGNATURE0_ARC_0) // legacy (0x5AEAA55A)
#define MPI26_FW_HEADER_SIGNATURE0_3516 (MPI26_FW_HEADER_SIGNATURE0_BASE+MPI26_FW_HEADER_SIGNATURE0_ARC_1)
#define MPI26_FW_HEADER_SIGNATURE0_4008 (MPI26_FW_HEADER_SIGNATURE0_BASE+MPI26_FW_HEADER_SIGNATURE0_ARC_3)
/* Signature1 field */
#define MPI2_FW_HEADER_SIGNATURE1_OFFSET (0x08)
@ -1665,7 +1881,13 @@ typedef struct _MPI2_FLASH_LAYOUT_DATA
#define MPI2_FLASH_REGION_COMMON_BOOT_BLOCK (0x0A)
#define MPI2_FLASH_REGION_INIT (MPI2_FLASH_REGION_COMMON_BOOT_BLOCK) /* older name */
#define MPI2_FLASH_REGION_CBB_BACKUP (0x0D)
#define MPI2_FLASH_REGION_SBR (0x0E)
#define MPI2_FLASH_REGION_SBR_BACKUP (0x0F)
#define MPI2_FLASH_REGION_HIIM (0x10)
#define MPI2_FLASH_REGION_HIIA (0x11)
#define MPI2_FLASH_REGION_CTLR (0x12)
#define MPI2_FLASH_REGION_IMR_FIRMWARE (0x13)
#define MPI2_FLASH_REGION_MR_NVDATA (0x14)
/* ImageRevision */
#define MPI2_FLASH_LAYOUT_IMAGE_REVISION (0x00)
@ -1960,6 +2182,8 @@ typedef struct _MPI26_IOUNIT_CONTROL_REQUEST
#define MPI26_CTRL_OP_DEV_ENABLE_PERSIST_CONNECTION (0x17)
#define MPI26_CTRL_OP_DEV_DISABLE_PERSIST_CONNECTION (0x18)
#define MPI26_CTRL_OP_DEV_CLOSE_PERSIST_CONNECTION (0x19)
#define MPI26_CTRL_OP_ENABLE_NVME_SGL_FORMAT (0x1A)
#define MPI26_CTRL_OP_DISABLE_NVME_SGL_FORMAT (0x1B)
#define MPI26_CTRL_OP_PRODUCT_SPECIFIC_MIN (0x80)
/* values for the PrimFlags field */

151
sys/dev/mpr/mpi/mpi2_pci.h Executable file
View File

@ -0,0 +1,151 @@
/*-
* Copyright (c) 2012-2015 LSI Corp.
* Copyright (c) 2013-2016 Avago Technologies
* All rights reserved.
*
* 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 author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
*
* $FreeBSD$
*/
/*
* Copyright (c) 2000-2015 LSI Corporation.
* Copyright (c) 2013-2016 Avago Technologies
* All rights reserved.
*
*
* Name: mpi2_pci.h
* Title: MPI PCIe Attached Devices structures and definitions.
* Creation Date: October 9, 2012
*
* mpi2_pci.h Version: 02.00.02
*
* NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
* prefix are for use only on MPI v2.5 products, and must not be used
* with MPI v2.0 products. Unless otherwise noted, names beginning with
* MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products.
*
* Version History
* ---------------
*
* Date Version Description
* -------- -------- ------------------------------------------------------
* 03-16-15 02.00.00 Initial version.
* 02-17-16 02.00.01 Removed AHCI support.
* Removed SOP support.
* 07-01-16 02.00.02 Added MPI26_NVME_FLAGS_FORCE_ADMIN_ERR_RESP to
* NVME Encapsulated Request.
* --------------------------------------------------------------------------
*/
#ifndef MPI2_PCI_H
#define MPI2_PCI_H
/*
* Values for the PCIe DeviceInfo field used in PCIe Device Status Change Event
* data and PCIe Configuration pages.
*/
#define MPI26_PCIE_DEVINFO_DIRECT_ATTACH (0x00000010)
#define MPI26_PCIE_DEVINFO_MASK_DEVICE_TYPE (0x0000000F)
#define MPI26_PCIE_DEVINFO_NO_DEVICE (0x00000000)
#define MPI26_PCIE_DEVINFO_PCI_SWITCH (0x00000001)
#define MPI26_PCIE_DEVINFO_NVME (0x00000003)
/****************************************************************************
* NVMe Encapsulated message
****************************************************************************/
/* NVME Encapsulated Request Message */
typedef struct _MPI26_NVME_ENCAPSULATED_REQUEST
{
U16 DevHandle; /* 0x00 */
U8 ChainOffset; /* 0x02 */
U8 Function; /* 0x03 */
U16 EncapsulatedCommandLength; /* 0x04 */
U8 Reserved1; /* 0x06 */
U8 MsgFlags; /* 0x07 */
U8 VP_ID; /* 0x08 */
U8 VF_ID; /* 0x09 */
U16 Reserved2; /* 0x0A */
U32 Reserved3; /* 0x0C */
U64 ErrorResponseBaseAddress; /* 0x10 */
U16 ErrorResponseAllocationLength; /* 0x18 */
U16 Flags; /* 0x1A */
U32 DataLength; /* 0x1C */
U8 NVMe_Command[4]; /* 0x20 */ /* variable length */
} MPI26_NVME_ENCAPSULATED_REQUEST, MPI2_POINTER PTR_MPI26_NVME_ENCAPSULATED_REQUEST,
Mpi26NVMeEncapsulatedRequest_t, MPI2_POINTER pMpi26NVMeEncapsulatedRequest_t;
/* defines for the Flags field */
#define MPI26_NVME_FLAGS_FORCE_ADMIN_ERR_RESP (0x0020)
/* Submission Queue Type*/
#define MPI26_NVME_FLAGS_SUBMISSIONQ_MASK (0x0010)
#define MPI26_NVME_FLAGS_SUBMISSIONQ_IO (0x0000)
#define MPI26_NVME_FLAGS_SUBMISSIONQ_ADMIN (0x0010)
/* Error Response Address Space */
#define MPI26_NVME_FLAGS_MASK_ERROR_RSP_ADDR (0x000C)
#define MPI26_NVME_FLAGS_SYSTEM_RSP_ADDR (0x0000)
#define MPI26_NVME_FLAGS_IOCPLB_RSP_ADDR (0x0008)
#define MPI26_NVME_FLAGS_IOCPLBNTA_RSP_ADDR (0x000C)
/* Data Direction*/
#define MPI26_NVME_FLAGS_DATADIRECTION_MASK (0x0003)
#define MPI26_NVME_FLAGS_NODATATRANSFER (0x0000)
#define MPI26_NVME_FLAGS_WRITE (0x0001)
#define MPI26_NVME_FLAGS_READ (0x0002)
#define MPI26_NVME_FLAGS_BIDIRECTIONAL (0x0003)
/* NVMe Encapuslated Reply Message */
typedef struct _MPI26_NVME_ENCAPSULATED_ERROR_REPLY
{
U16 DevHandle; /* 0x00 */
U8 MsgLength; /* 0x02 */
U8 Function; /* 0x03 */
U16 EncapsulatedCommandLength; /* 0x04 */
U8 Reserved1; /* 0x06 */
U8 MsgFlags; /* 0x07 */
U8 VP_ID; /* 0x08 */
U8 VF_ID; /* 0x09 */
U16 Reserved2; /* 0x0A */
U16 Reserved3; /* 0x0C */
U16 IOCStatus; /* 0x0E */
U32 IOCLogInfo; /* 0x10 */
U16 ErrorResponseCount; /* 0x14 */
U16 Reserved4; /* 0x16 */
} MPI26_NVME_ENCAPSULATED_ERROR_REPLY,
MPI2_POINTER PTR_MPI26_NVME_ENCAPSULATED_ERROR_REPLY,
Mpi26NVMeEncapsulatedErrorReply_t,
MPI2_POINTER pMpi26NVMeEncapsulatedErrorReply_t;
#endif

View File

@ -42,7 +42,7 @@
* Title: MPI diagnostic tool structures and definitions
* Creation Date: March 26, 2007
*
* mpi2_tool.h Version: 02.00.13
* mpi2_tool.h Version: 02.00.14
*
* Version History
* ---------------
@ -71,6 +71,8 @@
* 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info.
* 01-08-14 02.00.12 Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC.
* 11-18-14 02.00.13 Updated copyright information.
* 08-25-16 02.00.14 Added new values for the Flags field of Toolbox Clean
* Tool Request Message.
* --------------------------------------------------------------------------
*/
@ -145,6 +147,16 @@ typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST
#define MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC (0x04000000)
#define MPI2_TOOLBOX_CLEAN_MEGARAID (0x02000000)
#define MPI2_TOOLBOX_CLEAN_INITIALIZATION (0x01000000)
#define MPI2_TOOLBOX_CLEAN_SBR (0x00800000)
#define MPI2_TOOLBOX_CLEAN_SBR_BACKUP (0x00400000)
#define MPI2_TOOLBOX_CLEAN_HIIM (0x00200000)
#define MPI2_TOOLBOX_CLEAN_HIIA (0x00100000)
#define MPI2_TOOLBOX_CLEAN_CTLR (0x00080000)
#define MPI2_TOOLBOX_CLEAN_IMR_FIRMWARE (0x00040000)
#define MPI2_TOOLBOX_CLEAN_MR_NVDATA (0x00020000)
#define MPI2_TOOLBOX_CLEAN_RESERVED_5_16 (0x0001FFE0)
#define MPI2_TOOLBOX_CLEAN_ALL_BUT_MPB (0x00000010)
#define MPI2_TOOLBOX_CLEAN_ENTIRE_FLASH (0x00000008)
#define MPI2_TOOLBOX_CLEAN_FLASH (0x00000004)
#define MPI2_TOOLBOX_CLEAN_SEEPROM (0x00000002)
#define MPI2_TOOLBOX_CLEAN_NVSRAM (0x00000001)

View File

@ -63,18 +63,21 @@ __FBSDID("$FreeBSD$");
#include <dev/pci/pcivar.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/scsi/scsi_all.h>
#include <dev/mpr/mpi/mpi2_type.h>
#include <dev/mpr/mpi/mpi2.h>
#include <dev/mpr/mpi/mpi2_ioc.h>
#include <dev/mpr/mpi/mpi2_sas.h>
#include <dev/mpr/mpi/mpi2_pci.h>
#include <dev/mpr/mpi/mpi2_cnfg.h>
#include <dev/mpr/mpi/mpi2_init.h>
#include <dev/mpr/mpi/mpi2_tool.h>
#include <dev/mpr/mpr_ioctl.h>
#include <dev/mpr/mprvar.h>
#include <dev/mpr/mpr_table.h>
#include <dev/mpr/mpr_sas.h>
static int mpr_diag_reset(struct mpr_softc *sc, int sleep_flag);
static int mpr_init_queues(struct mpr_softc *sc);
@ -87,6 +90,7 @@ static int mpr_send_iocinit(struct mpr_softc *sc);
static int mpr_alloc_queues(struct mpr_softc *sc);
static int mpr_alloc_replies(struct mpr_softc *sc);
static int mpr_alloc_requests(struct mpr_softc *sc);
static int mpr_alloc_nvme_prp_pages(struct mpr_softc *sc);
static int mpr_attach_log(struct mpr_softc *sc);
static __inline void mpr_complete_command(struct mpr_softc *sc,
struct mpr_command *cm);
@ -110,7 +114,7 @@ static char mpt2_reset_magic[] = { 0x00, 0x0f, 0x04, 0x0b, 0x02, 0x07, 0x0d };
/*
* Added this union to smoothly convert le64toh cm->cm_desc.Words.
* Compiler only supports unint64_t to be passed as an argument.
* Compiler only supports uint64_t to be passed as an argument.
* Otherwise it will through this error:
* "aggregate value used where an integer was expected"
*/
@ -120,7 +124,7 @@ typedef union _reply_descriptor {
u32 low;
u32 high;
} u;
}reply_descriptor,address_descriptor;
} reply_descriptor, request_descriptor;
/* Rate limit chain-fail messages to 1 per minute */
static struct timeval mpr_chainfail_interval = { 60, 0 };
@ -311,7 +315,6 @@ mpr_transition_ready(struct mpr_softc *sc)
if (error)
device_printf(sc->mpr_dev, "Cannot transition IOC to ready\n");
return (error);
}
@ -392,7 +395,8 @@ mpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t attaching)
mpr_printf(sc, "IOCCapabilities: %b\n", sc->facts->IOCCapabilities,
"\20" "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf"
"\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR"
"\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc");
"\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc"
"\22FastPath" "\23RDPQArray" "\24AtomicReqDesc" "\25PCIeSRIOV");
/*
* If the chip doesn't support event replay then a hard reset will be
@ -480,12 +484,15 @@ mpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t attaching)
enabled = TRUE;
/*
* Set flag if EEDP is supported and if TLR is supported.
* Set flags for some supported items.
*/
if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP)
sc->eedp_enabled = TRUE;
if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR)
sc->control_TLR = TRUE;
if (sc->facts->IOCCapabilities &
MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ)
sc->atomic_desc_capable = TRUE;
/*
* Size the queues. Since the reply queues always need one free
@ -501,6 +508,7 @@ mpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t attaching)
TAILQ_INIT(&sc->req_list);
TAILQ_INIT(&sc->high_priority_req_list);
TAILQ_INIT(&sc->chain_list);
TAILQ_INIT(&sc->prp_page_list);
TAILQ_INIT(&sc->tm_list);
}
@ -634,6 +642,14 @@ mpr_iocfacts_free(struct mpr_softc *sc)
if (sc->sense_dmat != NULL)
bus_dma_tag_destroy(sc->sense_dmat);
if (sc->prp_page_busaddr != 0)
bus_dmamap_unload(sc->prp_page_dmat, sc->prp_page_map);
if (sc->prp_pages != NULL)
bus_dmamem_free(sc->prp_page_dmat, sc->prp_pages,
sc->prp_page_map);
if (sc->prp_page_dmat != NULL)
bus_dma_tag_destroy(sc->prp_page_dmat);
if (sc->reply_busaddr != 0)
bus_dmamap_unload(sc->reply_dmat, sc->reply_map);
if (sc->reply_frames != NULL)
@ -651,6 +667,8 @@ mpr_iocfacts_free(struct mpr_softc *sc)
if (sc->chains != NULL)
free(sc->chains, M_MPR);
if (sc->prps != NULL)
free(sc->prps, M_MPR);
if (sc->commands != NULL) {
for (i = 1; i < sc->num_reqs; i++) {
cm = &sc->commands[i];
@ -804,7 +822,7 @@ mpr_wait_db_ack(struct mpr_softc *sc, int timeout, int sleep_flag)
count++;
} while (--cntdn);
out:
out:
mpr_dprint(sc, MPR_FAULT, "%s: failed due to timeout count(%d), "
"int_status(%x)!\n", __func__, count, int_status);
return (ETIMEDOUT);
@ -959,7 +977,7 @@ mpr_request_sync(struct mpr_softc *sc, void *req, MPI2_DEFAULT_REPLY *reply,
static void
mpr_enqueue_request(struct mpr_softc *sc, struct mpr_command *cm)
{
reply_descriptor rd;
request_descriptor rd;
MPR_FUNCTRACE(sc);
mpr_dprint(sc, MPR_TRACE, "SMID %u cm %p ccb %p\n",
@ -972,14 +990,19 @@ mpr_enqueue_request(struct mpr_softc *sc, struct mpr_command *cm)
if (++sc->io_cmds_active > sc->io_cmds_highwater)
sc->io_cmds_highwater++;
rd.u.low = cm->cm_desc.Words.Low;
rd.u.high = cm->cm_desc.Words.High;
rd.word = htole64(rd.word);
/* TODO-We may need to make below regwrite atomic */
mpr_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET,
rd.u.low);
mpr_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET,
rd.u.high);
if (sc->atomic_desc_capable) {
rd.u.low = cm->cm_desc.Words.Low;
mpr_regwrite(sc, MPI26_ATOMIC_REQUEST_DESCRIPTOR_POST_OFFSET,
rd.u.low);
} else {
rd.u.low = cm->cm_desc.Words.Low;
rd.u.high = cm->cm_desc.Words.High;
rd.word = htole64(rd.word);
mpr_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET,
rd.u.low);
mpr_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET,
rd.u.high);
}
}
/*
@ -1047,6 +1070,7 @@ mpr_send_iocinit(struct mpr_softc *sc)
time_in_msec = (now.tv_sec * 1000 + now.tv_usec/1000);
init.TimeStamp.High = htole32((time_in_msec >> 32) & 0xFFFFFFFF);
init.TimeStamp.Low = htole32(time_in_msec & 0xFFFFFFFF);
init.HostPageSize = HOST_PAGE_SIZE_4K;
error = mpr_request_sync(sc, &init, &reply, req_sz, reply_sz, 5);
if ((reply.IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS)
@ -1276,6 +1300,16 @@ mpr_alloc_requests(struct mpr_softc *sc)
sc->chain_free_lowwater++;
}
/*
* Allocate NVMe PRP Pages for NVMe SGL support only if the FW supports
* these devices.
*/
if ((sc->facts->MsgVersion >= MPI2_VERSION_02_06) &&
(sc->facts->ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_NVME_DEVICES)) {
if (mpr_alloc_nvme_prp_pages(sc) == ENOMEM)
return (ENOMEM);
}
/* XXX Need to pick a more precise value */
nsegs = (MAXPHYS / PAGE_SIZE) + 1;
if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */
@ -1316,15 +1350,17 @@ mpr_alloc_requests(struct mpr_softc *sc)
cm->cm_desc.Default.SMID = i;
cm->cm_sc = sc;
TAILQ_INIT(&cm->cm_chain_list);
TAILQ_INIT(&cm->cm_prp_page_list);
callout_init_mtx(&cm->cm_callout, &sc->mpr_mtx, 0);
/* XXX Is a failure here a critical problem? */
if (bus_dmamap_create(sc->buffer_dmat, 0, &cm->cm_dmamap) == 0)
if (bus_dmamap_create(sc->buffer_dmat, 0, &cm->cm_dmamap)
== 0) {
if (i <= sc->facts->HighPriorityCredit)
mpr_free_high_priority_command(sc, cm);
else
mpr_free_command(sc, cm);
else {
} else {
panic("failed to allocate command %d\n", i);
sc->num_reqs = i;
break;
@ -1334,6 +1370,86 @@ mpr_alloc_requests(struct mpr_softc *sc)
return (0);
}
/*
* Allocate contiguous buffers for PCIe NVMe devices for building native PRPs,
* which are scatter/gather lists for NVMe devices.
*
* This buffer must be contiguous due to the nature of how NVMe PRPs are built
* and translated by FW.
*
* returns ENOMEM if memory could not be allocated, otherwise returns 0.
*/
static int
mpr_alloc_nvme_prp_pages(struct mpr_softc *sc)
{
int PRPs_per_page, PRPs_required, pages_required;
int rsize, i;
struct mpr_prp_page *prp_page;
/*
* Assuming a MAX_IO_SIZE of 1MB and a PAGE_SIZE of 4k, the max number
* of PRPs (NVMe's Scatter/Gather Element) needed per I/O is:
* MAX_IO_SIZE / PAGE_SIZE = 256
*
* 1 PRP entry in main frame for PRP list pointer still leaves 255 PRPs
* required for the remainder of the 1MB I/O. 512 PRPs can fit into one
* page (4096 / 8 = 512), so only one page is required for each I/O.
*
* Each of these buffers will need to be contiguous. For simplicity,
* only one buffer is allocated here, which has all of the space
* required for the NVMe Queue Depth. If there are problems allocating
* this one buffer, this function will need to change to allocate
* individual, contiguous NVME_QDEPTH buffers.
*
* The real calculation will use the real max io size. Above is just an
* example.
*
*/
PRPs_required = sc->maxio / PAGE_SIZE;
PRPs_per_page = (PAGE_SIZE / PRP_ENTRY_SIZE) - 1;
pages_required = (PRPs_required / PRPs_per_page) + 1;
sc->prp_buffer_size = PAGE_SIZE * pages_required;
rsize = sc->prp_buffer_size * NVME_QDEPTH;
if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */
4, 0, /* algnmnt, boundary */
BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
rsize, /* maxsize */
1, /* nsegments */
rsize, /* maxsegsize */
0, /* flags */
NULL, NULL, /* lockfunc, lockarg */
&sc->prp_page_dmat)) {
device_printf(sc->mpr_dev, "Cannot allocate NVMe PRP DMA "
"tag\n");
return (ENOMEM);
}
if (bus_dmamem_alloc(sc->prp_page_dmat, (void **)&sc->prp_pages,
BUS_DMA_NOWAIT, &sc->prp_page_map)) {
device_printf(sc->mpr_dev, "Cannot allocate NVMe PRP memory\n");
return (ENOMEM);
}
bzero(sc->prp_pages, rsize);
bus_dmamap_load(sc->prp_page_dmat, sc->prp_page_map, sc->prp_pages,
rsize, mpr_memaddr_cb, &sc->prp_page_busaddr, 0);
sc->prps = malloc(sizeof(struct mpr_prp_page) * NVME_QDEPTH, M_MPR,
M_WAITOK | M_ZERO);
for (i = 0; i < NVME_QDEPTH; i++) {
prp_page = &sc->prps[i];
prp_page->prp_page = (uint64_t *)(sc->prp_pages +
i * sc->prp_buffer_size);
prp_page->prp_page_busaddr = (uint64_t)(sc->prp_page_busaddr +
i * sc->prp_buffer_size);
mpr_free_prp_page(sc, prp_page);
sc->prp_pages_free_lowwater++;
}
return (0);
}
static int
mpr_init_queues(struct mpr_softc *sc)
{
@ -1352,8 +1468,10 @@ mpr_init_queues(struct mpr_softc *sc)
/*
* Initialize all of the free queue entries.
*/
for (i = 0; i < sc->fqdepth; i++)
sc->free_queue[i] = sc->reply_busaddr + (i * sc->facts->ReplyFrameSize * 4);
for (i = 0; i < sc->fqdepth; i++) {
sc->free_queue[i] = sc->reply_busaddr +
(i * sc->facts->ReplyFrameSize * 4);
}
sc->replyfreeindex = sc->num_replies;
return (0);
@ -1520,6 +1638,18 @@ mpr_setup_sysctl(struct mpr_softc *sc)
SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
OID_AUTO, "use_phy_num", CTLFLAG_RD, &sc->use_phynum, 0,
"Use the phy number for enumeration");
SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
OID_AUTO, "prp_pages_free", CTLFLAG_RD,
&sc->prp_pages_free, 0, "number of free PRP pages");
SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
OID_AUTO, "prp_pages_free_lowwater", CTLFLAG_RD,
&sc->prp_pages_free_lowwater, 0,"lowest number of free PRP pages");
SYSCTL_ADD_UQUAD(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
OID_AUTO, "prp_page_alloc_fail", CTLFLAG_RD,
&sc->prp_page_alloc_fail, "PRP page allocation failures");
}
int
@ -1912,6 +2042,7 @@ mpr_intr_locked(void *data)
switch (flags) {
case MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS:
case MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS:
case MPI26_RPY_DESCRIPT_FLAGS_PCIE_ENCAPSULATED_SUCCESS:
cm = &sc->commands[le16toh(desc->SCSIIOSuccess.SMID)];
cm->cm_reply = NULL;
break;
@ -2200,6 +2331,519 @@ mpr_deregister_events(struct mpr_softc *sc, struct mpr_event_handle *handle)
return (mpr_update_events(sc, NULL, NULL));
}
/**
* mpr_build_nvme_prp - This function is called for NVMe end devices to build a
* native SGL (NVMe PRP). The native SGL is built starting in the first PRP entry
* of the NVMe message (PRP1). If the data buffer is small enough to be described
* entirely using PRP1, then PRP2 is not used. If needed, PRP2 is used to
* describe a larger data buffer. If the data buffer is too large to describe
* using the two PRP entriess inside the NVMe message, then PRP1 describes the
* first data memory segment, and PRP2 contains a pointer to a PRP list located
* elsewhere in memory to describe the remaining data memory segments. The PRP
* list will be contiguous.
* The native SGL for NVMe devices is a Physical Region Page (PRP). A PRP
* consists of a list of PRP entries to describe a number of noncontigous
* physical memory segments as a single memory buffer, just as a SGL does. Note
* however, that this function is only used by the IOCTL call, so the memory
* given will be guaranteed to be contiguous. There is no need to translate
* non-contiguous SGL into a PRP in this case. All PRPs will describe contiguous
* space that is one page size each.
*
* Each NVMe message contains two PRP entries. The first (PRP1) either contains
* a PRP list pointer or a PRP element, depending upon the command. PRP2 contains
* the second PRP element if the memory being described fits within 2 PRP
* entries, or a PRP list pointer if the PRP spans more than two entries.
*
* A PRP list pointer contains the address of a PRP list, structured as a linear
* array of PRP entries. Each PRP entry in this list describes a segment of
* physical memory.
*
* Each 64-bit PRP entry comprises an address and an offset field. The address
* always points to the beginning of a PAGE_SIZE physical memory page, and the
* offset describes where within that page the memory segment begins. Only the
* first element in a PRP list may contain a non-zero offest, implying that all
* memory segments following the first begin at the start of a PAGE_SIZE page.
*
* Each PRP element normally describes a chunck of PAGE_SIZE physical memory,
* with exceptions for the first and last elements in the list. If the memory
* being described by the list begins at a non-zero offset within the first page,
* then the first PRP element will contain a non-zero offset indicating where the
* region begins within the page. The last memory segment may end before the end
* of the PAGE_SIZE segment, depending upon the overall size of the memory being
* described by the PRP list.
*
* Since PRP entries lack any indication of size, the overall data buffer length
* is used to determine where the end of the data memory buffer is located, and
* how many PRP entries are required to describe it.
*
* Returns nothing.
*/
void
mpr_build_nvme_prp(struct mpr_softc *sc, struct mpr_command *cm,
Mpi26NVMeEncapsulatedRequest_t *nvme_encap_request, void *data,
uint32_t data_in_sz, uint32_t data_out_sz)
{
int prp_size = PRP_ENTRY_SIZE;
uint64_t *prp_entry, *prp1_entry, *prp2_entry;
uint64_t *prp_entry_phys, *prp_page, *prp_page_phys;
uint32_t offset, entry_len, page_mask_result, page_mask;
bus_addr_t paddr;
size_t length;
struct mpr_prp_page *prp_page_info = NULL;
/*
* Not all commands require a data transfer. If no data, just return
* without constructing any PRP.
*/
if (!data_in_sz && !data_out_sz)
return;
/*
* 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 = (uint64_t *)(nvme_encap_request->NVMe_Command +
NVME_CMD_PRP1_OFFSET);
prp2_entry = (uint64_t *)(nvme_encap_request->NVMe_Command +
NVME_CMD_PRP2_OFFSET);
prp_entry = prp1_entry;
/*
* For the PRP entries, use the specially allocated buffer of
* contiguous memory. PRP Page allocation failures should not happen
* because there should be enough PRP page buffers to account for the
* possible NVMe QDepth.
*/
prp_page_info = mpr_alloc_prp_page(sc);
KASSERT(prp_page_info != NULL, ("%s: There are no PRP Pages left to be "
"used for building a native NVMe SGL.\n", __func__));
prp_page = (uint64_t *)prp_page_info->prp_page;
prp_page_phys = (uint64_t *)(uintptr_t)prp_page_info->prp_page_busaddr;
/*
* Insert the allocated PRP page into the command's PRP page list. This
* will be freed when the command is freed.
*/
TAILQ_INSERT_TAIL(&cm->cm_prp_page_list, prp_page_info, prp_page_link);
/*
* 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 = PAGE_SIZE - 1;
page_mask_result = (uintptr_t)((uint8_t *)prp_page + prp_size) &
page_mask;
if (!page_mask_result)
{
/* Bump up to next page boundary. */
prp_page = (uint64_t *)((uint8_t *)prp_page + prp_size);
prp_page_phys = (uint64_t *)((uint8_t *)prp_page_phys +
prp_size);
}
/*
* Set PRP physical pointer, which initially points to the current PRP
* DMA memory page.
*/
prp_entry_phys = prp_page_phys;
/* Get physical address and length of the data buffer. */
paddr = (bus_addr_t)data;
if (data_in_sz)
length = data_in_sz;
else
length = data_out_sz;
/* Loop while the length is not zero. */
while (length)
{
/*
* Check if we need to put a list pointer here if we are at page
* boundary - prp_size (8 bytes).
*/
page_mask_result = (uintptr_t)((uint8_t *)prp_entry_phys +
prp_size) & page_mask;
if (!page_mask_result)
{
/*
* This is the last entry in a PRP List, so we need to
* put a PRP list pointer here. What this does is:
* - bump the current memory pointer to the next
* address, which will be the next full page.
* - set the PRP Entry to point to that page. This is
* now the PRP List pointer.
* - bump the PRP Entry pointer the start of the next
* page. Since all of this PRP memory is contiguous,
* no need to get a new page - it's just the next
* address.
*/
prp_entry_phys++;
*prp_entry =
htole64((uint64_t)(uintptr_t)prp_entry_phys);
prp_entry++;
}
/* Need to handle if entry will be part of a page. */
offset = (uint32_t)paddr & page_mask;
entry_len = PAGE_SIZE - offset;
if (prp_entry == prp1_entry)
{
/*
* Must fill in the first PRP pointer (PRP1) before
* moving on.
*/
*prp1_entry = htole64((uint64_t)paddr);
/*
* 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 > PAGE_SIZE)
{
/*
* 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 =
htole64(
(uint64_t)(uintptr_t)prp_entry_phys);
/*
* The next PRP Entry will be the start of the
* first PRP List.
*/
prp_entry = prp_page;
}
else
{
/*
* After this, the PRP Entries are complete.
* This command uses 2 PRP's and no PRP list.
*/
*prp2_entry = htole64((uint64_t)paddr);
}
}
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 = htole64((uint64_t)paddr);
prp_entry++;
prp_entry_phys++;
}
/*
* Bump the phys address of the command's data buffer by the
* entry_len.
*/
paddr += entry_len;
/* Decrement length accounting for last partial page. */
if (entry_len > length)
length = 0;
else
length -= entry_len;
}
}
/*
* mpr_check_pcie_native_sgl - This function is called for PCIe end devices to
* determine if the driver needs to build a native SGL. If so, that native SGL
* is built in the contiguous buffers allocated especially for PCIe SGL
* creation. If the driver will not build a native SGL, return TRUE and a
* normal IEEE SGL will be built. Currently this routine supports NVMe devices
* only.
*
* Returns FALSE (0) if native SGL was built, TRUE (1) if no SGL was built.
*/
static int
mpr_check_pcie_native_sgl(struct mpr_softc *sc, struct mpr_command *cm,
bus_dma_segment_t *segs, int segs_left)
{
uint32_t i, sge_dwords, length, offset, entry_len;
uint32_t num_entries, buff_len = 0, sges_in_segment;
uint32_t page_mask, page_mask_result, *curr_buff;
uint32_t *ptr_sgl, *ptr_first_sgl, first_page_offset;
uint32_t first_page_data_size, end_residual;
uint64_t *msg_phys;
bus_addr_t paddr;
int build_native_sgl = 0, first_prp_entry;
int prp_size = PRP_ENTRY_SIZE;
Mpi25IeeeSgeChain64_t *main_chain_element = NULL;
struct mpr_prp_page *prp_page_info = NULL;
mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
/*
* Add up the sizes of each segment length to get the total transfer
* size, which will be checked against the Maximum Data Transfer Size.
* If the data transfer length exceeds the MDTS for this device, just
* return 1 so a normal IEEE SGL will be built. F/W will break the I/O
* up into multiple I/O's. [nvme_mdts = 0 means unlimited]
*/
for (i = 0; i < segs_left; i++)
buff_len += htole32(segs[i].ds_len);
if ((cm->cm_targ->MDTS > 0) && (buff_len > cm->cm_targ->MDTS))
return 1;
/* Create page_mask (to get offset within page) */
page_mask = PAGE_SIZE - 1;
/*
* Check if the number of elements exceeds the max number that can be
* put in the main message frame (H/W can only translate an SGL that
* is contained entirely in the main message frame).
*/
sges_in_segment = (sc->facts->IOCRequestFrameSize -
offsetof(Mpi25SCSIIORequest_t, SGL)) / sizeof(MPI25_SGE_IO_UNION);
if (segs_left > sges_in_segment)
build_native_sgl = 1;
else
{
/*
* NVMe uses one PRP for each physical page (or part of physical
* page).
* if 4 pages or less then IEEE is OK
* if > 5 pages then we need to build a native SGL
* if > 4 and <= 5 pages, then check the physical address of
* the first SG entry, then if this first size in the page
* is >= the residual beyond 4 pages then use IEEE,
* otherwise use native SGL
*/
if (buff_len > (PAGE_SIZE * 5))
build_native_sgl = 1;
else if ((buff_len > (PAGE_SIZE * 4)) &&
(buff_len <= (PAGE_SIZE * 5)) )
{
msg_phys = (uint64_t *)segs[0].ds_addr;
first_page_offset =
((uint32_t)(uint64_t)(uintptr_t)msg_phys &
page_mask);
first_page_data_size = PAGE_SIZE - first_page_offset;
end_residual = buff_len % PAGE_SIZE;
/*
* If offset into first page pushes the end of the data
* beyond end of the 5th page, we need the extra PRP
* list.
*/
if (first_page_data_size < end_residual)
build_native_sgl = 1;
/*
* Check if first SG entry size is < residual beyond 4
* pages.
*/
if (htole32(segs[0].ds_len) <
(buff_len - (PAGE_SIZE * 4)))
build_native_sgl = 1;
}
}
/* check if native SGL is needed */
if (!build_native_sgl)
return 1;
/*
* Native SGL is needed.
* Put a chain element in main message frame that points to the first
* chain buffer.
*
* NOTE: The ChainOffset field must be 0 when using a chain pointer to
* a native SGL.
*/
/* Set main message chain element pointer */
main_chain_element = (pMpi25IeeeSgeChain64_t)cm->cm_sge;
/*
* For NVMe the chain element needs to be the 2nd SGL entry in the main
* message.
*/
main_chain_element = (Mpi25IeeeSgeChain64_t *)
((uint8_t *)main_chain_element + sizeof(MPI25_IEEE_SGE_CHAIN64));
/*
* For the PRP entries, use the specially allocated buffer of
* contiguous memory. PRP Page allocation failures should not happen
* because there should be enough PRP page buffers to account for the
* possible NVMe QDepth.
*/
prp_page_info = mpr_alloc_prp_page(sc);
KASSERT(prp_page_info != NULL, ("%s: There are no PRP Pages left to be "
"used for building a native NVMe SGL.\n", __func__));
curr_buff = (uint32_t *)prp_page_info->prp_page;
msg_phys = (uint64_t *)(uintptr_t)prp_page_info->prp_page_busaddr;
/*
* Insert the allocated PRP page into the command's PRP page list. This
* will be freed when the command is freed.
*/
TAILQ_INSERT_TAIL(&cm->cm_prp_page_list, prp_page_info, prp_page_link);
/*
* 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)((uint8_t *)curr_buff + prp_size) &
page_mask;
if (!page_mask_result) {
/* Bump up to next page boundary. */
curr_buff = (uint32_t *)((uint8_t *)curr_buff + prp_size);
msg_phys = (uint64_t *)((uint8_t *)msg_phys + prp_size);
}
/* Fill in the chain element and make it an NVMe segment type. */
main_chain_element->Address.High =
htole32((uint32_t)((uint64_t)(uintptr_t)msg_phys >> 32));
main_chain_element->Address.Low =
htole32((uint32_t)(uintptr_t)msg_phys);
main_chain_element->NextChainOffset = 0;
main_chain_element->Flags = MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT |
MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
MPI26_IEEE_SGE_FLAGS_NSF_NVME_PRP;
/* Set SGL pointer to start of contiguous PCIe buffer. */
ptr_sgl = curr_buff;
sge_dwords = 2;
num_entries = 0;
/*
* NVMe has a very convoluted PRP format. One PRP is required for each
* page or partial page. We need to split up OS SG entries if they are
* longer than one page or cross a page boundary. We also have to insert
* a PRP list pointer entry as the last entry in each physical page of
* the PRP list.
*
* NOTE: The first PRP "entry" is actually placed in the first SGL entry
* in the main message in IEEE 64 format. The 2nd entry in the main
* message is the chain element, and the rest of the PRP entries are
* built in the contiguous PCIe buffer.
*/
first_prp_entry = 1;
ptr_first_sgl = (uint32_t *)cm->cm_sge;
for (i = 0; i < segs_left; i++) {
/* Get physical address and length of this SG entry. */
paddr = segs[i].ds_addr;
length = segs[i].ds_len;
/*
* Check whether a given SGE buffer lies on a non-PAGED
* boundary if this is not the first page. If so, this is not
* expected so have FW build the SGL.
*/
if (i) {
if ((uint32_t)paddr & page_mask) {
mpr_dprint(sc, MPR_ERROR, "Unaligned SGE while "
"building NVMe PRPs, low address is 0x%x\n",
(uint32_t)paddr);
return 1;
}
}
/* Apart from last SGE, if any other SGE boundary is not page
* aligned then it means that hole exists. Existence of hole
* leads to data corruption. So fallback to IEEE SGEs.
*/
if (i != (segs_left - 1)) {
if (((uint32_t)paddr + length) & page_mask) {
mpr_dprint(sc, MPR_ERROR, "Unaligned SGE "
"boundary while building NVMe PRPs, low "
"address: 0x%x and length: %u\n",
(uint32_t)paddr, length);
return 1;
}
}
/* Loop while the length is not zero. */
while (length) {
/*
* Check if we need to put a list pointer here if we are
* at page boundary - prp_size.
*/
page_mask_result = (uintptr_t)((uint8_t *)ptr_sgl +
prp_size) & page_mask;
if (!page_mask_result) {
/*
* Need to put a PRP list pointer here.
*/
msg_phys = (uint64_t *)((uint8_t *)msg_phys +
prp_size);
*ptr_sgl = htole32((uintptr_t)msg_phys);
*(ptr_sgl+1) = htole32((uint64_t)(uintptr_t)
msg_phys >> 32);
ptr_sgl += sge_dwords;
num_entries++;
}
/* Need to handle if entry will be part of a page. */
offset = (uint32_t)paddr & page_mask;
entry_len = PAGE_SIZE - offset;
if (first_prp_entry) {
/*
* Put IEEE entry in first SGE in main message.
* (Simple element, System addr, not end of
* list.)
*/
*ptr_first_sgl = htole32((uint32_t)paddr);
*(ptr_first_sgl + 1) =
htole32((uint32_t)((uint64_t)paddr >> 32));
*(ptr_first_sgl + 2) = htole32(entry_len);
*(ptr_first_sgl + 3) = 0;
/* No longer the first PRP entry. */
first_prp_entry = 0;
} else {
/* Put entry in list. */
*ptr_sgl = htole32((uint32_t)paddr);
*(ptr_sgl + 1) =
htole32((uint32_t)((uint64_t)paddr >> 32));
/* Bump ptr_sgl, msg_phys, and num_entries. */
ptr_sgl += sge_dwords;
msg_phys = (uint64_t *)((uint8_t *)msg_phys +
prp_size);
num_entries++;
}
/* Bump the phys address by the entry_len. */
paddr += entry_len;
/* Decrement length accounting for last partial page. */
if (entry_len > length)
length = 0;
else
length -= entry_len;
}
}
/* Set chain element Length. */
main_chain_element->Length = htole32(num_entries * prp_size);
/* Return 0, indicating we built a native SGL. */
return 0;
}
/*
* Add a chain element as the next SGE for the specified command.
* Reset cm_sge and cm_sgesize to indicate all the available space. Chains are
@ -2540,6 +3184,13 @@ mpr_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
} else
dir = BUS_DMASYNC_PREREAD;
/* Check if a native SG list is needed for an NVMe PCIe device. */
if (cm->cm_targ && cm->cm_targ->is_nvme &&
mpr_check_pcie_native_sgl(sc, cm, segs, nsegs) == 0) {
/* A native SG list was built, skip to end. */
goto out;
}
for (i = 0; i < nsegs; i++) {
if ((cm->cm_flags & MPR_CM_FLAGS_SMP_PASS) && (i != 0)) {
sflags &= ~MPI2_SGE_FLAGS_DIRECTION;
@ -2557,6 +3208,7 @@ mpr_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
}
}
out:
bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir);
mpr_enqueue_request(sc, cm);

View File

@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <dev/mpr/mpi/mpi2.h>
#include <dev/mpr/mpi/mpi2_ioc.h>
#include <dev/mpr/mpi/mpi2_sas.h>
#include <dev/mpr/mpi/mpi2_pci.h>
#include <dev/mpr/mpi/mpi2_cnfg.h>
#include <dev/mpr/mpi/mpi2_init.h>
#include <dev/mpr/mpi/mpi2_tool.h>
@ -91,7 +92,7 @@ mpr_config_get_ioc_pg8(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply,
request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
request->Header.PageNumber = 8;
request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
request->Header.PageLength = request->Header.PageVersion = 0;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
cm->cm_data = NULL;
error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
@ -137,7 +138,7 @@ mpr_config_get_ioc_pg8(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply,
request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
request->Header.PageNumber = 8;
request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
request->Header.PageVersion = mpi_reply->Header.PageVersion;
request->Header.PageLength = mpi_reply->Header.PageLength;
cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
cm->cm_sge = &request->PageBufferSGE;
@ -221,7 +222,7 @@ mpr_config_get_iounit_pg8(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply,
request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
request->Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
request->Header.PageNumber = 8;
request->Header.PageVersion = MPI2_IOUNITPAGE8_PAGEVERSION;
request->Header.PageLength = request->Header.PageVersion = 0;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
cm->cm_data = NULL;
error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
@ -267,7 +268,7 @@ mpr_config_get_iounit_pg8(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply,
request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
request->Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
request->Header.PageNumber = 8;
request->Header.PageVersion = MPI2_IOUNITPAGE8_PAGEVERSION;
request->Header.PageVersion = mpi_reply->Header.PageVersion;
request->Header.PageLength = mpi_reply->Header.PageLength;
cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
cm->cm_sge = &request->PageBufferSGE;
@ -387,7 +388,7 @@ mpr_config_get_dpm_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply,
request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
request->Header.PageNumber = 0;
request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
request->ExtPageLength = request->Header.PageVersion = 0;
request->PageAddress = sc->max_dpm_entries <<
MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
@ -436,7 +437,7 @@ mpr_config_get_dpm_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply,
request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
request->Header.PageNumber = 0;
request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
request->Header.PageVersion = mpi_reply->Header.PageVersion;
request->PageAddress = sc->max_dpm_entries <<
MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
request->ExtPageLength = mpi_reply->ExtPageLength;
@ -522,7 +523,7 @@ int mpr_config_set_dpm_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply,
request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
request->Header.PageNumber = 0;
request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
request->ExtPageLength = request->Header.PageVersion = 0;
/* We can remove below two lines ????*/
request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
request->PageAddress |= htole16(entry_idx);
@ -572,7 +573,7 @@ int mpr_config_set_dpm_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply,
request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
request->Header.PageNumber = 0;
request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
request->Header.PageVersion = mpi_reply->Header.PageVersion;
request->ExtPageLength = mpi_reply->ExtPageLength;
request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
request->PageAddress |= htole16(entry_idx);
@ -660,7 +661,7 @@ mpr_config_get_sas_device_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t
request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
request->Header.PageNumber = 0;
request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
request->ExtPageLength = request->Header.PageVersion = 0;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
cm->cm_data = NULL;
error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
@ -707,7 +708,7 @@ mpr_config_get_sas_device_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t
request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
request->Header.PageNumber = 0;
request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
request->Header.PageVersion = mpi_reply->Header.PageVersion;
request->ExtPageLength = mpi_reply->ExtPageLength;
request->PageAddress = htole32(form | handle);
cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
@ -758,6 +759,276 @@ mpr_config_get_sas_device_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t
return (error);
}
/**
* mpr_config_get_pcie_device_pg0 - obtain PCIe device page 0
* @sc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* @form: GET_NEXT_HANDLE or HANDLE
* @handle: device handle
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpr_config_get_pcie_device_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t
*mpi_reply, Mpi26PCIeDevicePage0_t *config_page, u32 form, u16 handle)
{
MPI2_CONFIG_REQUEST *request;
MPI2_CONFIG_REPLY *reply;
struct mpr_command *cm;
Mpi26PCIeDevicePage0_t *page = NULL;
int error = 0;
u16 ioc_status;
mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
if ((cm = mpr_alloc_command(sc)) == NULL) {
printf("%s: command alloc failed @ line %d\n", __func__,
__LINE__);
error = EBUSY;
goto out;
}
request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
bzero(request, sizeof(MPI2_CONFIG_REQUEST));
request->Function = MPI2_FUNCTION_CONFIG;
request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_PCIE_DEVICE;
request->Header.PageNumber = 0;
request->ExtPageLength = request->Header.PageVersion = 0;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
cm->cm_data = NULL;
error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
if (error || (reply == NULL)) {
/* FIXME */
/*
* If the request returns an error then we need to do a diag
* reset
*/
printf("%s: request for header completed with error %d",
__func__, error);
error = ENXIO;
goto out;
}
ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
/* FIXME */
/*
* If the request returns an error then we need to do a diag
* reset
*/
printf("%s: header read with error; iocstatus = 0x%x\n",
__func__, ioc_status);
error = ENXIO;
goto out;
}
/* We have to do free and alloc for the reply-free and reply-post
* counters to match - Need to review the reply FIFO handling.
*/
mpr_free_command(sc, cm);
if ((cm = mpr_alloc_command(sc)) == NULL) {
printf("%s: command alloc failed @ line %d\n", __func__,
__LINE__);
error = EBUSY;
goto out;
}
request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
bzero(request, sizeof(MPI2_CONFIG_REQUEST));
request->Function = MPI2_FUNCTION_CONFIG;
request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_PCIE_DEVICE;
request->Header.PageNumber = 0;
request->Header.PageVersion = mpi_reply->Header.PageVersion;
request->ExtPageLength = mpi_reply->ExtPageLength;
request->PageAddress = htole32(form | handle);
cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
cm->cm_sge = &request->PageBufferSGE;
cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
page = malloc(cm->cm_length, M_MPR, M_ZERO | M_NOWAIT);
if (!page) {
printf("%s: page alloc failed\n", __func__);
error = ENOMEM;
goto out;
}
cm->cm_data = page;
error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
if (error || (reply == NULL)) {
/* FIXME */
/*
* If the request returns an error then we need to do a diag
* reset
*/
printf("%s: request for page completed with error %d",
__func__, error);
error = ENXIO;
goto out;
}
ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
/* FIXME */
/*
* If the request returns an error then we need to do a diag
* reset
*/
printf("%s: page read with error; iocstatus = 0x%x\n",
__func__, ioc_status);
error = ENXIO;
goto out;
}
bcopy(page, config_page, MIN(cm->cm_length,
sizeof(Mpi26PCIeDevicePage0_t)));
out:
free(page, M_MPR);
if (cm)
mpr_free_command(sc, cm);
return (error);
}
/**
* mpr_config_get_pcie_device_pg2 - obtain PCIe device page 2
* @sc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
* @config_page: contents of the config page
* @form: GET_NEXT_HANDLE or HANDLE
* @handle: device handle
* Context: sleep.
*
* Returns 0 for success, non-zero for failure.
*/
int
mpr_config_get_pcie_device_pg2(struct mpr_softc *sc, Mpi2ConfigReply_t
*mpi_reply, Mpi26PCIeDevicePage2_t *config_page, u32 form, u16 handle)
{
MPI2_CONFIG_REQUEST *request;
MPI2_CONFIG_REPLY *reply;
struct mpr_command *cm;
Mpi26PCIeDevicePage2_t *page = NULL;
int error = 0;
u16 ioc_status;
mpr_dprint(sc, MPR_TRACE, "%s\n", __func__);
if ((cm = mpr_alloc_command(sc)) == NULL) {
printf("%s: command alloc failed @ line %d\n", __func__,
__LINE__);
error = EBUSY;
goto out;
}
request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
bzero(request, sizeof(MPI2_CONFIG_REQUEST));
request->Function = MPI2_FUNCTION_CONFIG;
request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_PCIE_DEVICE;
request->Header.PageNumber = 2;
request->ExtPageLength = request->Header.PageVersion = 0;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
cm->cm_data = NULL;
error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
if (error || (reply == NULL)) {
/* FIXME */
/*
* If the request returns an error then we need to do a diag
* reset
*/
printf("%s: request for header completed with error %d",
__func__, error);
error = ENXIO;
goto out;
}
ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
/* FIXME */
/*
* If the request returns an error then we need to do a diag
* reset
*/
printf("%s: header read with error; iocstatus = 0x%x\n",
__func__, ioc_status);
error = ENXIO;
goto out;
}
/* We have to do free and alloc for the reply-free and reply-post
* counters to match - Need to review the reply FIFO handling.
*/
mpr_free_command(sc, cm);
if ((cm = mpr_alloc_command(sc)) == NULL) {
printf("%s: command alloc failed @ line %d\n", __func__,
__LINE__);
error = EBUSY;
goto out;
}
request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
bzero(request, sizeof(MPI2_CONFIG_REQUEST));
request->Function = MPI2_FUNCTION_CONFIG;
request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_PCIE_DEVICE;
request->Header.PageNumber = 2;
request->Header.PageVersion = mpi_reply->Header.PageVersion;
request->ExtPageLength = mpi_reply->ExtPageLength;
request->PageAddress = htole32(form | handle);
cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
cm->cm_sge = &request->PageBufferSGE;
cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
cm->cm_flags = MPR_CM_FLAGS_SGE_SIMPLE | MPR_CM_FLAGS_DATAIN;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
page = malloc(cm->cm_length, M_MPR, M_ZERO | M_NOWAIT);
if (!page) {
printf("%s: page alloc failed\n", __func__);
error = ENOMEM;
goto out;
}
cm->cm_data = page;
error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
if (error || (reply == NULL)) {
/* FIXME */
/*
* If the request returns an error then we need to do a diag
* reset
*/
printf("%s: request for page completed with error %d",
__func__, error);
error = ENXIO;
goto out;
}
ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
/* FIXME */
/*
* If the request returns an error then we need to do a diag
* reset
*/
printf("%s: page read with error; iocstatus = 0x%x\n",
__func__, ioc_status);
error = ENXIO;
goto out;
}
bcopy(page, config_page, MIN(cm->cm_length,
sizeof(Mpi26PCIeDevicePage2_t)));
out:
free(page, M_MPR);
if (cm)
mpr_free_command(sc, cm);
return (error);
}
/**
* mpr_config_get_bios_pg3 - obtain BIOS page 3
* @sc: per adapter object
@ -792,7 +1063,7 @@ mpr_config_get_bios_pg3(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply,
request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
request->Header.PageNumber = 3;
request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
request->Header.PageLength = request->Header.PageVersion = 0;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
cm->cm_data = NULL;
error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
@ -838,7 +1109,7 @@ mpr_config_get_bios_pg3(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply,
request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
request->Header.PageNumber = 3;
request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
request->Header.PageVersion = mpi_reply->Header.PageVersion;
request->Header.PageLength = mpi_reply->Header.PageLength;
cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
cm->cm_sge = &request->PageBufferSGE;
@ -922,7 +1193,7 @@ mpr_config_get_raid_volume_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t
request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
request->Header.PageNumber = 0;
request->Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION;
request->Header.PageLength = request->Header.PageVersion = 0;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
cm->cm_data = NULL;
@ -1051,7 +1322,7 @@ mpr_config_get_raid_volume_pg1(struct mpr_softc *sc, Mpi2ConfigReply_t
request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
request->Header.PageNumber = 1;
request->Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION;
request->Header.PageLength = request->Header.PageVersion = 0;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
cm->cm_data = NULL;
error = mpr_wait_command(sc, cm, 60, CAN_SLEEP);
@ -1208,7 +1479,7 @@ mpr_config_get_raid_pd_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t *mpi_reply,
request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
request->Header.PageNumber = 0;
request->Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION;
request->Header.PageLength = request->Header.PageVersion = 0;
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
cm->cm_data = NULL;

View File

@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <dev/mpr/mpi/mpi2.h>
#include <dev/mpr/mpi/mpi2_ioc.h>
#include <dev/mpr/mpi/mpi2_sas.h>
#include <dev/mpr/mpi/mpi2_pci.h>
#include <dev/mpr/mpi/mpi2_cnfg.h>
#include <dev/mpr/mpi/mpi2_init.h>
#include <dev/mpr/mpi/mpi2_tool.h>
@ -675,6 +676,55 @@ _mapping_add_to_removal_table(struct mpr_softc *sc, u16 handle,
}
/**
* _mapping_inc_missing_count
* @sc: per adapter object
* @map_idx: index into the mapping table for the device that is missing
*
* Increment the missing count in the mapping table for a SAS, SATA, or PCIe
* device that is not responding. If Persitent Mapping is used, increment the
* DPM entry as well. Also, add this device to the removal table for possible
* removal if a new device is added.
*
* Returns nothing.
*/
static void
_mapping_inc_missing_count(struct mpr_softc *sc, u32 map_idx)
{
u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
struct dev_mapping_table *mt_entry;
Mpi2DriverMap0Entry_t *dpm_entry;
if (map_idx == MPR_MAPTABLE_BAD_IDX) {
mpr_dprint(sc, MPR_INFO, "%s: device is already removed from "
"mapping table\n", __func__);
return;
}
mt_entry = &sc->mapping_table[map_idx];
if (!mt_entry->init_complete) {
if (mt_entry->missing_count < MPR_MAX_MISSING_COUNT)
mt_entry->missing_count++;
else
mt_entry->init_complete = 1;
}
if (!mt_entry->missing_count)
mt_entry->missing_count++;
_mapping_add_to_removal_table(sc, mt_entry->dev_handle, 0);
mt_entry->dev_handle = 0;
if (((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) &&
sc->is_dpm_enable && !mt_entry->init_complete &&
mt_entry->dpm_entry_num != MPR_DPM_BAD_IDX) {
dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
dpm_entry += mt_entry->dpm_entry_num;
dpm_entry->MappingInformation = mt_entry->missing_count;
sc->dpm_flush_entry[mt_entry->dpm_entry_num] = 1;
}
mt_entry->init_complete = 1;
}
/**
* _mapping_update_missing_count - Update missing count for a device
* @sc: per adapter object
@ -689,12 +739,9 @@ static void
_mapping_update_missing_count(struct mpr_softc *sc,
struct _map_topology_change *topo_change)
{
u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
u8 entry;
struct _map_phy_change *phy_change;
u32 map_idx;
struct dev_mapping_table *mt_entry;
Mpi2DriverMap0Entry_t *dpm_entry;
for (entry = 0; entry < topo_change->num_entries; entry++) {
phy_change = &topo_change->phy_details[entry];
@ -704,35 +751,37 @@ _mapping_update_missing_count(struct mpr_softc *sc,
map_idx = _mapping_get_mt_idx_from_handle(sc, phy_change->
dev_handle);
phy_change->is_processed = 1;
if (map_idx == MPR_MAPTABLE_BAD_IDX) {
printf("%s: device is already removed from mapping "
"table\n", __func__);
continue;
}
mt_entry = &sc->mapping_table[map_idx];
if (!mt_entry->init_complete) {
if (mt_entry->missing_count < MPR_MAX_MISSING_COUNT)
mt_entry->missing_count++;
else
mt_entry->init_complete = 1;
}
if (!mt_entry->missing_count)
mt_entry->missing_count++;
_mapping_add_to_removal_table(sc, mt_entry->dev_handle, 0);
mt_entry->dev_handle = 0;
_mapping_inc_missing_count(sc, map_idx);
}
}
if (((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) &&
sc->is_dpm_enable && !mt_entry->init_complete &&
mt_entry->dpm_entry_num != MPR_DPM_BAD_IDX) {
dpm_entry =
(Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
dpm_entry += mt_entry->dpm_entry_num;
dpm_entry->MappingInformation = mt_entry->missing_count;
sc->dpm_flush_entry[mt_entry->dpm_entry_num] = 1;
}
mt_entry->init_complete = 1;
/**
* _mapping_update_pcie_missing_count - Update missing count for a PCIe device
* @sc: per adapter object
* @topo_change: Topology change event entry
*
* Search through the PCIe topology change list and if any device is found not
* responding it's associated map table entry and DPM entry is updated
*
* Returns nothing.
*/
static void
_mapping_update_pcie_missing_count(struct mpr_softc *sc,
struct _map_pcie_topology_change *topo_change)
{
u8 entry;
struct _map_port_change *port_change;
u32 map_idx;
for (entry = 0; entry < topo_change->num_entries; entry++) {
port_change = &topo_change->port_details[entry];
if (!port_change->dev_handle || (port_change->reason !=
MPI26_EVENT_PCIE_TOPO_PS_NOT_RESPONDING))
continue;
map_idx = _mapping_get_mt_idx_from_handle(sc, port_change->
dev_handle);
port_change->is_processed = 1;
_mapping_inc_missing_count(sc, map_idx);
}
}
@ -940,7 +989,7 @@ _mapping_get_dev_info(struct mpr_softc *sc,
phy_change->physical_id = sas_address;
phy_change->slot = le16toh(sas_device_pg0.Slot);
phy_change->device_info = le32toh(sas_device_pg0.DeviceInfo);
phy_change->device_info = device_info;
if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
@ -990,12 +1039,118 @@ _mapping_get_dev_info(struct mpr_softc *sc,
break;
}
}
/* Found space in enclosure for mapping entry */
mt_entry = &sc->mapping_table[map_idx];
for (index = map_idx; index < (et_entry->num_slots
+ map_idx); index++, mt_entry++) {
mt_entry->device_info = MPR_DEV_RESERVED;
mt_entry->physical_id = et_entry->enclosure_id;
mt_entry->phy_bits = et_entry->phy_bits;
mt_entry->missing_count = 0;
}
}
}
}
/**
* _mapping_get_pcie_dev_info -get information about newly added PCIe devices
* @sc: per adapter object
* @topo_change: Topology change event entry
*
* Searches through the PCIe topology change event list and issues PCIe device
* pg0 requests for the newly added PCIe device. If the device is in an
* enclosure, search for available space in the enclosure mapping table for the
* device and reserve that space.
*
* Returns nothing
*/
static void
_mapping_get_pcie_dev_info(struct mpr_softc *sc,
struct _map_pcie_topology_change *topo_change)
{
u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
Mpi2ConfigReply_t mpi_reply;
Mpi26PCIeDevicePage0_t pcie_device_pg0;
u8 entry, enc_idx, port_idx;
u32 map_idx, index;
struct _map_port_change *port_change, *tmp_port_change;
uint64_t pcie_wwid;
struct enc_mapping_table *et_entry;
struct dev_mapping_table *mt_entry;
u8 add_code = MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED;
for (entry = 0; entry < topo_change->num_entries; entry++) {
port_change = &topo_change->port_details[entry];
if (port_change->is_processed || !port_change->dev_handle ||
port_change->reason != MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED)
continue;
if (mpr_config_get_pcie_device_pg0(sc, &mpi_reply,
&pcie_device_pg0, MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE,
port_change->dev_handle)) {
port_change->is_processed = 1;
continue;
}
pcie_wwid = pcie_device_pg0.WWID.High;
pcie_wwid = (pcie_wwid << 32) | pcie_device_pg0.WWID.Low;
port_change->physical_id = pcie_wwid;
port_change->slot = le16toh(pcie_device_pg0.Slot);
port_change->device_info = le32toh(pcie_device_pg0.DeviceInfo);
if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
enc_idx = _mapping_get_enc_idx_from_handle(sc,
topo_change->enc_handle);
if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
port_change->is_processed = 1;
mpr_dprint(sc, MPR_MAPPING, "%s: failed to add "
"the device with handle 0x%04x because the "
"enclosure is not in the mapping table\n",
__func__, port_change->dev_handle);
continue;
}
if (!(port_change->device_info &
MPI26_PCIE_DEVINFO_NVME)) {
port_change->is_processed = 1;
continue;
}
et_entry = &sc->enclosure_table[enc_idx];
if (et_entry->start_index != MPR_MAPTABLE_BAD_IDX)
continue;
if (!topo_change->switch_dev_handle) {
map_idx = sc->num_rsvd_entries;
et_entry->start_index = map_idx;
} else {
map_idx = _mapping_find_enc_map_space(sc,
et_entry);
et_entry->start_index = map_idx;
if (et_entry->start_index ==
MPR_MAPTABLE_BAD_IDX) {
port_change->is_processed = 1;
for (port_idx = 0; port_idx <
topo_change->num_entries;
port_idx++) {
tmp_port_change =
&topo_change->port_details
[port_idx];
if (tmp_port_change->reason ==
add_code)
tmp_port_change->
is_processed = 1;
}
break;
}
}
/* Found space in enclosure for mapping entry */
mt_entry = &sc->mapping_table[map_idx];
for (index = map_idx; index < (et_entry->num_slots
+ map_idx); index++, mt_entry++) {
mt_entry->device_info = MPR_DEV_RESERVED;
mt_entry->physical_id = et_entry->enclosure_id;
mt_entry->phy_bits = et_entry->phy_bits;
mt_entry->missing_count = 0;
}
}
}
@ -1106,8 +1261,8 @@ _mapping_clear_removed_entries(struct mpr_softc *sc)
* @sc: per adapter object
* @topo_change: Topology change event entry
*
* Search through the topology change event list and updates map table,
* enclosure table and DPM pages for for the newly added devices.
* Search through the topology change event list and update map table,
* enclosure table and DPM pages for the newly added devices.
*
* Returns nothing
*/
@ -1144,10 +1299,10 @@ _mapping_add_new_device(struct mpr_softc *sc,
(sc, topo_change->enc_handle);
if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
phy_change->is_processed = 1;
printf("%s: failed to add the device with "
"handle 0x%04x because the enclosure is "
"not in the mapping table\n", __func__,
phy_change->dev_handle);
mpr_dprint(sc, MPR_ERROR, "%s: failed to add "
"the device with handle 0x%04x because the "
"enclosure is not in the mapping table\n",
__func__, phy_change->dev_handle);
continue;
}
et_entry = &sc->enclosure_table[enc_idx];
@ -1157,10 +1312,11 @@ _mapping_add_new_device(struct mpr_softc *sc,
sc->mt_add_device_failed = 1;
continue;
}
printf("%s: failed to add the device with "
"handle 0x%04x because there is no free "
"space available in the mapping table\n",
__func__, phy_change->dev_handle);
mpr_dprint(sc, MPR_INFO, "%s: failed to add "
"the device with handle 0x%04x because "
"there is no free space available in the "
"mapping table\n", __func__,
phy_change->dev_handle);
continue;
}
map_idx = et_entry->start_index + phy_change->slot -
@ -1268,10 +1424,11 @@ _mapping_add_new_device(struct mpr_softc *sc,
sc->mt_add_device_failed = 1;
continue;
}
printf("%s: failed to add the device with "
"handle 0x%04x because there is no free "
"space available in the mapping table\n",
__func__, phy_change->dev_handle);
mpr_dprint(sc, MPR_INFO, "%s: failed to add "
"the device with handle 0x%04x because "
"there is no free space available in the "
"mapping table\n", __func__,
phy_change->dev_handle);
continue;
}
if (sc->is_dpm_enable) {
@ -1314,14 +1471,13 @@ _mapping_add_new_device(struct mpr_softc *sc,
sc->dpm_flush_entry[dpm_idx] = 1;
phy_change->is_processed = 1;
} else if (dpm_idx == MPR_DPM_BAD_IDX) {
phy_change->is_processed = 1;
mpr_dprint(sc, MPR_INFO, "%s: "
"failed to add the device "
"with handle 0x%04x to "
"persistent table because "
"there is no free space "
"available\n", __func__,
phy_change->dev_handle);
phy_change->is_processed = 1;
mpr_dprint(sc, MPR_INFO, "%s: failed "
"to add the device with handle "
"0x%04x to persistent table "
"because there is no free space "
"available\n", __func__,
phy_change->dev_handle);
}
}
mt_entry->init_complete = 1;
@ -1333,6 +1489,241 @@ _mapping_add_new_device(struct mpr_softc *sc,
_mapping_clear_removed_entries(sc);
}
/**
* _mapping_add_new_pcie_device -Add the new PCIe device into mapping table
* @sc: per adapter object
* @topo_change: Topology change event entry
*
* Search through the PCIe topology change event list and update map table,
* enclosure table and DPM pages for the newly added devices.
*
* Returns nothing
*/
static void
_mapping_add_new_pcie_device(struct mpr_softc *sc,
struct _map_pcie_topology_change *topo_change)
{
u8 enc_idx, missing_cnt, is_removed = 0;
u16 dpm_idx;
u32 search_idx, map_idx;
u32 entry;
struct dev_mapping_table *mt_entry;
struct enc_mapping_table *et_entry;
struct _map_port_change *port_change;
u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
Mpi2DriverMap0Entry_t *dpm_entry;
uint64_t temp64_var;
u8 map_shift = MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
u8 hdr_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER);
u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs);
for (entry = 0; entry < topo_change->num_entries; entry++) {
port_change = &topo_change->port_details[entry];
if (port_change->is_processed)
continue;
if (port_change->reason != MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED ||
!port_change->dev_handle) {
port_change->is_processed = 1;
continue;
}
if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
enc_idx = _mapping_get_enc_idx_from_handle
(sc, topo_change->enc_handle);
if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
port_change->is_processed = 1;
mpr_dprint(sc, MPR_ERROR, "%s: failed to add "
"the device with handle 0x%04x because the "
"enclosure is not in the mapping table\n",
__func__, port_change->dev_handle);
continue;
}
et_entry = &sc->enclosure_table[enc_idx];
if (et_entry->start_index == MPR_MAPTABLE_BAD_IDX) {
port_change->is_processed = 1;
if (!sc->mt_full_retry) {
sc->mt_add_device_failed = 1;
continue;
}
mpr_dprint(sc, MPR_INFO, "%s: failed to add "
"the device with handle 0x%04x because "
"there is no free space available in the "
"mapping table\n", __func__,
port_change->dev_handle);
continue;
}
map_idx = et_entry->start_index + port_change->slot -
et_entry->start_slot;
mt_entry = &sc->mapping_table[map_idx];
mt_entry->physical_id = port_change->physical_id;
mt_entry->channel = 0;
mt_entry->id = map_idx;
mt_entry->dev_handle = port_change->dev_handle;
mt_entry->missing_count = 0;
mt_entry->dpm_entry_num = et_entry->dpm_entry_num;
mt_entry->device_info = port_change->device_info |
(MPR_DEV_RESERVED | MPR_MAP_IN_USE);
if (sc->is_dpm_enable) {
dpm_idx = et_entry->dpm_entry_num;
if (dpm_idx == MPR_DPM_BAD_IDX)
dpm_idx = _mapping_get_dpm_idx_from_id
(sc, et_entry->enclosure_id,
et_entry->phy_bits);
if (dpm_idx == MPR_DPM_BAD_IDX) {
dpm_idx = _mapping_get_free_dpm_idx(sc);
if (dpm_idx != MPR_DPM_BAD_IDX) {
dpm_entry =
(Mpi2DriverMap0Entry_t *)
((u8 *) sc->dpm_pg0 +
hdr_sz);
dpm_entry += dpm_idx;
dpm_entry->
PhysicalIdentifier.Low =
(0xFFFFFFFF &
et_entry->enclosure_id);
dpm_entry->
PhysicalIdentifier.High =
( et_entry->enclosure_id
>> 32);
dpm_entry->DeviceIndex =
(U16)et_entry->start_index;
dpm_entry->MappingInformation =
et_entry->num_slots;
dpm_entry->MappingInformation
<<= map_shift;
dpm_entry->PhysicalBitsMapping
= et_entry->phy_bits;
et_entry->dpm_entry_num =
dpm_idx;
/* FIXME Do I need to set the dpm_idxin mt_entry too */
sc->dpm_entry_used[dpm_idx] = 1;
sc->dpm_flush_entry[dpm_idx] =
1;
port_change->is_processed = 1;
} else {
port_change->is_processed = 1;
mpr_dprint(sc, MPR_INFO, "%s: "
"failed to add the device "
"with handle 0x%04x to "
"persistent table because "
"there is no free space "
"available\n", __func__,
port_change->dev_handle);
}
} else {
et_entry->dpm_entry_num = dpm_idx;
mt_entry->dpm_entry_num = dpm_idx;
}
}
/* FIXME Why not mt_entry too? */
et_entry->init_complete = 1;
} else if ((ioc_pg8_flags &
MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
map_idx = _mapping_get_mt_idx_from_id
(sc, port_change->physical_id);
if (map_idx == MPR_MAPTABLE_BAD_IDX) {
search_idx = sc->num_rsvd_entries;
if (topo_change->switch_dev_handle)
search_idx += max_num_phy_ids;
map_idx = _mapping_get_free_mt_idx(sc,
search_idx);
}
if (map_idx == MPR_MAPTABLE_BAD_IDX) {
map_idx = _mapping_get_high_missing_mt_idx(sc);
if (map_idx != MPR_MAPTABLE_BAD_IDX) {
mt_entry = &sc->mapping_table[map_idx];
if (mt_entry->dev_handle) {
_mapping_add_to_removal_table
(sc, mt_entry->dev_handle,
0);
is_removed = 1;
}
mt_entry->init_complete = 0;
}
}
if (map_idx != MPR_MAPTABLE_BAD_IDX) {
mt_entry = &sc->mapping_table[map_idx];
mt_entry->physical_id =
port_change->physical_id;
mt_entry->channel = 0;
mt_entry->id = map_idx;
mt_entry->dev_handle = port_change->dev_handle;
mt_entry->missing_count = 0;
mt_entry->device_info =
port_change->device_info |
(MPR_DEV_RESERVED | MPR_MAP_IN_USE);
} else {
port_change->is_processed = 1;
if (!sc->mt_full_retry) {
sc->mt_add_device_failed = 1;
continue;
}
mpr_dprint(sc, MPR_INFO, "%s: failed to add "
"the device with handle 0x%04x because "
"there is no free space available in the "
"mapping table\n", __func__,
port_change->dev_handle);
continue;
}
if (sc->is_dpm_enable) {
if (mt_entry->dpm_entry_num !=
MPR_DPM_BAD_IDX) {
dpm_idx = mt_entry->dpm_entry_num;
dpm_entry = (Mpi2DriverMap0Entry_t *)
((u8 *)sc->dpm_pg0 + hdr_sz);
dpm_entry += dpm_idx;
missing_cnt = dpm_entry->
MappingInformation &
MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
temp64_var = dpm_entry->
PhysicalIdentifier.High;
temp64_var = (temp64_var << 32) |
dpm_entry->PhysicalIdentifier.Low;
if ((mt_entry->physical_id ==
temp64_var) && !missing_cnt)
mt_entry->init_complete = 1;
} else {
dpm_idx = _mapping_get_free_dpm_idx(sc);
mt_entry->init_complete = 0;
}
if (dpm_idx != MPR_DPM_BAD_IDX &&
!mt_entry->init_complete) {
mt_entry->init_complete = 1;
mt_entry->dpm_entry_num = dpm_idx;
dpm_entry = (Mpi2DriverMap0Entry_t *)
((u8 *)sc->dpm_pg0 + hdr_sz);
dpm_entry += dpm_idx;
dpm_entry->PhysicalIdentifier.Low =
(0xFFFFFFFF &
mt_entry->physical_id);
dpm_entry->PhysicalIdentifier.High =
(mt_entry->physical_id >> 32);
dpm_entry->DeviceIndex = (U16) map_idx;
dpm_entry->MappingInformation = 0;
dpm_entry->PhysicalBitsMapping = 0;
sc->dpm_entry_used[dpm_idx] = 1;
sc->dpm_flush_entry[dpm_idx] = 1;
port_change->is_processed = 1;
} else if (dpm_idx == MPR_DPM_BAD_IDX) {
port_change->is_processed = 1;
mpr_dprint(sc, MPR_INFO, "%s: failed "
"to add the device with handle "
"0x%04x to persistent table "
"because there is no free space "
"available\n", __func__,
port_change->dev_handle);
}
}
mt_entry->init_complete = 1;
}
port_change->is_processed = 1;
}
if (is_removed)
_mapping_clear_removed_entries(sc);
}
/**
* _mapping_flush_dpm_pages -Flush the DPM pages to NVRAM
* @sc: per adapter object
@ -2072,6 +2463,56 @@ mpr_mapping_topology_change_event(struct mpr_softc *sc,
sc->pending_map_events--;
}
/**
* mpr_mapping_pcie_topology_change_event - handle PCIe topology change events
* @sc: per adapter object
* @event_data: event data payload
*
* Returns nothing.
*/
void
mpr_mapping_pcie_topology_change_event(struct mpr_softc *sc,
Mpi26EventDataPCIeTopologyChangeList_t *event_data)
{
struct _map_pcie_topology_change topo_change;
struct _map_port_change *port_change;
Mpi26EventPCIeTopoPortEntry_t *event_port_change;
u8 i, num_entries;
topo_change.switch_dev_handle = le16toh(event_data->SwitchDevHandle);
topo_change.enc_handle = le16toh(event_data->EnclosureHandle);
num_entries = event_data->NumEntries;
topo_change.num_entries = num_entries;
topo_change.start_port_num = event_data->StartPortNum;
topo_change.num_ports = event_data->NumPorts;
topo_change.switch_status = event_data->SwitchStatus;
event_port_change = event_data->PortEntry;
topo_change.port_details = NULL;
if (!num_entries)
goto out;
port_change = malloc(sizeof(struct _map_port_change) * num_entries,
M_MPR, M_NOWAIT|M_ZERO);
topo_change.port_details = port_change;
if (!port_change)
goto out;
for (i = 0; i < num_entries; i++, event_port_change++, port_change++) {
port_change->dev_handle = le16toh(event_port_change->
AttachedDevHandle);
port_change->reason = event_port_change->PortStatus;
}
_mapping_update_pcie_missing_count(sc, &topo_change);
_mapping_get_pcie_dev_info(sc, &topo_change);
_mapping_clear_removed_entries(sc);
_mapping_add_new_pcie_device(sc, &topo_change);
out:
free(topo_change.port_details, M_MPR);
_mapping_flush_dpm_pages(sc);
if (sc->pending_map_events)
sc->pending_map_events--;
}
/**
* _mapping_check_update_ir_mt_idx - Check and update IR map table index
* @sc: per adapter object

View File

@ -53,9 +53,36 @@ struct _map_phy_change {
};
/**
* struct _map_topology_change - entries to be removed from mapping table
* @dpm_entry_num: index of this device in device persistent map table
* struct _map_port_change - PCIe Port entries received in PCIe Topology change
* list event
* @physical_id: WWID of the device attached to the associated port
* @device_info: bitfield provides detailed info about the device
* @MDTS: Maximum Data Transfer Size for the device
* @dev_handle: device handle for the device pointed by this entry
* @slot: slot ID
* @is_processed: Flag to indicate whether this entry is processed or not
*/
struct _map_port_change {
uint64_t physical_id;
uint32_t device_info;
uint32_t MDTS;
uint16_t dev_handle;
uint16_t slot;
uint8_t reason;
uint8_t is_processed;
uint8_t reserved[2];
};
/**
* struct _map_topology_change - SAS/SATA entries to be removed from mapping
* table
* @enc_handle: enclosure handle where this device is located
* @exp_handle: expander handle where this device is located
* @num_entries: number of entries in the SAS Topology Change List event
* @start_phy_num: PHY number of the first PHY in the event data
* @num_phys: number of PHYs in the expander where this device is located
* @exp_status: status for the expander where this device is located
* @phy_details: more details about each PHY in the event data
*/
struct _map_topology_change {
uint16_t enc_handle;
@ -67,6 +94,26 @@ struct _map_topology_change {
struct _map_phy_change *phy_details;
};
/**
* struct _map_pcie_topology_change - PCIe entries to be removed from mapping
* table
* @enc_handle: enclosure handle where this device is located
* @switch_dev_handle: PCIe switch device handle where this device is located
* @num_entries: number of entries in the PCIe Topology Change List event
* @start_port_num: port number of the first port in the event data
* @num_ports: number of ports in the PCIe switch device
* @switch_status: status for the PCIe switch where this device is located
* @port_details: more details about each Port in the event data
*/
struct _map_pcie_topology_change {
uint16_t enc_handle;
uint16_t switch_dev_handle;
uint8_t num_entries;
uint8_t start_port_num;
uint8_t num_ports;
uint8_t switch_status;
struct _map_port_change *port_details;
};
extern int
mprsas_get_sas_address_for_sata_disk(struct mpr_softc *ioc,

View File

@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <dev/mpr/mpi/mpi2_ioc.h>
#include <dev/mpr/mpi/mpi2_cnfg.h>
#include <dev/mpr/mpi/mpi2_tool.h>
#include <dev/mpr/mpi/mpi2_pci.h>
#include <sys/queue.h>
#include <sys/kthread.h>
@ -110,6 +111,10 @@ struct mpr_ident {
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3108_5" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3108_6" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3216,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3216" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3224,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3224" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_1,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3316_1" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3316_2,
@ -118,10 +123,24 @@ struct mpr_ident {
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3324_1" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3324_2,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3324_2" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3216,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3216" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3224,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3224" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3408,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3408" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3416,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3416" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3508,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3508" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3508_1,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3508_1" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3516,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3516" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3516_1,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3516_1" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3616,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3616" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3708,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3708" },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI26_MFGPAGE_DEVID_SAS3716,
0xffff, 0xffff, 0, "Avago Technologies (LSI) SAS3716" },
{ 0, 0, 0, 0, 0, NULL }
};
@ -164,7 +183,7 @@ mpr_pci_attach(device_t dev)
{
struct mpr_softc *sc;
struct mpr_ident *m;
int error;
int error, i;
sc = device_get_softc(dev);
bzero(sc, sizeof(*sc));
@ -175,13 +194,32 @@ mpr_pci_attach(device_t dev)
/* Twiddle basic PCI config bits for a sanity check */
pci_enable_busmaster(dev);
/* Allocate the System Interface Register Set */
sc->mpr_regs_rid = PCIR_BAR(1);
if ((sc->mpr_regs_resource = bus_alloc_resource_any(dev,
SYS_RES_MEMORY, &sc->mpr_regs_rid, RF_ACTIVE)) == NULL) {
/* Set flag if this is a Gen3.5 IOC */
if ((m->device == MPI26_MFGPAGE_DEVID_SAS3508) ||
(m->device == MPI26_MFGPAGE_DEVID_SAS3508_1) ||
(m->device == MPI26_MFGPAGE_DEVID_SAS3408) ||
(m->device == MPI26_MFGPAGE_DEVID_SAS3516) ||
(m->device == MPI26_MFGPAGE_DEVID_SAS3516_1) ||
(m->device == MPI26_MFGPAGE_DEVID_SAS3416) ||
(m->device == MPI26_MFGPAGE_DEVID_SAS3716) ||
(m->device == MPI26_MFGPAGE_DEVID_SAS3616) ||
(m->device == MPI26_MFGPAGE_DEVID_SAS3708)) {
sc->mpr_flags |= MPR_FLAGS_GEN35_IOC;
}
for (i = 0; i < PCI_MAXMAPS_0; i++) {
sc->mpr_regs_rid = PCIR_BAR(i);
if ((sc->mpr_regs_resource = bus_alloc_resource_any(dev,
SYS_RES_MEMORY, &sc->mpr_regs_rid, RF_ACTIVE)) != NULL)
break;
}
if (sc->mpr_regs_resource == NULL) {
mpr_printf(sc, "Cannot allocate PCI registers\n");
return (ENXIO);
}
sc->mpr_btag = rman_get_bustag(sc->mpr_regs_resource);
sc->mpr_bhandle = rman_get_bushandle(sc->mpr_regs_resource);

View File

@ -72,10 +72,13 @@ __FBSDID("$FreeBSD$");
#include <cam/scsi/smp_all.h>
#endif
#include <dev/nvme/nvme.h>
#include <dev/mpr/mpi/mpi2_type.h>
#include <dev/mpr/mpi/mpi2.h>
#include <dev/mpr/mpi/mpi2_ioc.h>
#include <dev/mpr/mpi/mpi2_sas.h>
#include <dev/mpr/mpi/mpi2_pci.h>
#include <dev/mpr/mpi/mpi2_cnfg.h>
#include <dev/mpr/mpi/mpi2_init.h>
#include <dev/mpr/mpi/mpi2_tool.h>
@ -477,13 +480,13 @@ mprsas_prepare_volume_remove(struct mprsas_softc *sassc, uint16_t handle)
}
/*
* The MPT3 firmware performs debounce on the link to avoid transient link
* errors and false removals. When it does decide that link has been lost
* and a device needs to go away, it expects that the host will perform a
* target reset and then an op remove. The reset has the side-effect of
* aborting any outstanding requests for the device, which is required for
* the op-remove to succeed. It's not clear if the host should check for
* the device coming back alive after the reset.
* The firmware performs debounce on the link to avoid transient link errors
* and false removals. When it does decide that link has been lost and a
* device needs to go away, it expects that the host will perform a target reset
* and then an op remove. The reset has the side-effect of aborting any
* outstanding requests for the device, which is required for the op-remove to
* succeed. It's not clear if the host should check for the device coming back
* alive after the reset.
*/
void
mprsas_prepare_remove(struct mprsas_softc *sassc, uint16_t handle)
@ -705,7 +708,14 @@ mprsas_register_events(struct mpr_softc *sc)
setbit(events, MPI2_EVENT_IR_PHYSICAL_DISK);
setbit(events, MPI2_EVENT_IR_OPERATION_STATUS);
setbit(events, MPI2_EVENT_TEMP_THRESHOLD);
setbit(events, MPI2_EVENT_ACTIVE_CABLE_EXCEPTION);
if (sc->facts->MsgVersion >= MPI2_VERSION_02_06) {
setbit(events, MPI2_EVENT_ACTIVE_CABLE_EXCEPTION);
if (sc->mpr_flags & MPR_FLAGS_GEN35_IOC) {
setbit(events, MPI2_EVENT_PCIE_DEVICE_STATUS_CHANGE);
setbit(events, MPI2_EVENT_PCIE_ENUMERATION);
setbit(events, MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST);
}
}
mpr_register_events(sc, events, mprsas_evt_handler, NULL,
&sc->sassc->mprsas_eh);
@ -1018,6 +1028,7 @@ mprsas_action(struct cam_sim *sim, union ccb *ccb)
if ((sc->max_io_pages > 0) && (sc->max_io_pages * PAGE_SIZE <
cpi->maxio))
cpi->maxio = sc->max_io_pages * PAGE_SIZE;
sc->maxio = cpi->maxio;
mprsas_set_ccbstatus(ccb, CAM_REQ_CMP);
break;
}
@ -1636,7 +1647,7 @@ mprsas_scsiio_timeout(void *data)
targ->timeouts++;
mprsas_log_command(cm, MPR_ERROR, "command timeout %d cm %p target "
"%u, handle(0x%04x)\n", cm->cm_ccb->ccb_h.timeout, cm, targ->tid,
"%u, handle(0x%04x)\n", cm->cm_ccb->ccb_h.timeout, cm, targ->tid,
targ->handle);
if (targ->encl_level_valid) {
mpr_dprint(sc, MPR_ERROR, "At enclosure level %d, slot %d, "
@ -1680,6 +1691,160 @@ mprsas_scsiio_timeout(void *data)
}
}
/**
* mprsas_build_nvme_unmap - Build Native NVMe DSM command equivalent
* to SCSI Unmap.
* Return 0 - for success,
* 1 - to immediately return back the command with success status to CAM
* negative value - to fallback to firmware path i.e. issue scsi unmap
* to FW without any translation.
*/
static int
mprsas_build_nvme_unmap(struct mpr_softc *sc, struct mpr_command *cm,
union ccb *ccb, struct mprsas_target *targ)
{
Mpi26NVMeEncapsulatedRequest_t *req = NULL;
struct ccb_scsiio *csio;
struct unmap_parm_list *plist;
struct nvme_dsm_range *nvme_dsm_ranges = NULL;
struct nvme_command *c;
int i, res;
uint16_t ndesc, list_len, data_length;
struct mpr_prp_page *prp_page_info;
uint64_t nvme_dsm_ranges_dma_handle;
csio = &ccb->csio;
#if __FreeBSD_version >= 1100103
list_len = (scsiio_cdb_ptr(csio)[7] << 8 | scsiio_cdb_ptr(csio)[8]);
#else
if (csio->ccb_h.flags & CAM_CDB_POINTER) {
list_len = (ccb->csio.cdb_io.cdb_ptr[7] << 8 |
ccb->csio.cdb_io.cdb_ptr[8]);
} else {
list_len = (ccb->csio.cdb_io.cdb_bytes[7] << 8 |
ccb->csio.cdb_io.cdb_bytes[8]);
}
#endif
if (!list_len) {
mpr_dprint(sc, MPR_ERROR, "Parameter list length is Zero\n");
return -EINVAL;
}
plist = malloc(csio->dxfer_len, M_MPR, M_ZERO|M_NOWAIT);
if (!plist) {
mpr_dprint(sc, MPR_ERROR, "Unable to allocate memory to "
"save UNMAP data\n");
return -ENOMEM;
}
/* Copy SCSI unmap data to a local buffer */
bcopy(csio->data_ptr, plist, csio->dxfer_len);
/* return back the unmap command to CAM with success status,
* if number of descripts is zero.
*/
ndesc = be16toh(plist->unmap_blk_desc_data_len) >> 4;
if (!ndesc) {
mpr_dprint(sc, MPR_XINFO, "Number of descriptors in "
"UNMAP cmd is Zero\n");
res = 1;
goto out;
}
data_length = ndesc * sizeof(struct nvme_dsm_range);
if (data_length > targ->MDTS) {
mpr_dprint(sc, MPR_ERROR, "data length: %d is greater than "
"Device's MDTS: %d\n", data_length, targ->MDTS);
res = -EINVAL;
goto out;
}
prp_page_info = mpr_alloc_prp_page(sc);
KASSERT(prp_page_info != NULL, ("%s: There is no PRP Page for "
"UNMAP command.\n", __func__));
/*
* Insert the allocated PRP page into the command's PRP page list. This
* will be freed when the command is freed.
*/
TAILQ_INSERT_TAIL(&cm->cm_prp_page_list, prp_page_info, prp_page_link);
nvme_dsm_ranges = (struct nvme_dsm_range *)prp_page_info->prp_page;
nvme_dsm_ranges_dma_handle = prp_page_info->prp_page_busaddr;
bzero(nvme_dsm_ranges, data_length);
/* Convert SCSI unmap's descriptor data to NVMe DSM specific Range data
* for each descriptors contained in SCSI UNMAP data.
*/
for (i = 0; i < ndesc; i++) {
nvme_dsm_ranges[i].length =
htole32(be32toh(plist->desc[i].nlb));
nvme_dsm_ranges[i].starting_lba =
htole64(be64toh(plist->desc[i].slba));
nvme_dsm_ranges[i].attributes = 0;
}
/* Build MPI2.6's NVMe Encapsulated Request Message */
req = (Mpi26NVMeEncapsulatedRequest_t *)cm->cm_req;
bzero(req, sizeof(*req));
req->DevHandle = htole16(targ->handle);
req->Function = MPI2_FUNCTION_NVME_ENCAPSULATED;
req->Flags = MPI26_NVME_FLAGS_WRITE;
req->ErrorResponseBaseAddress.High =
htole32((uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32));
req->ErrorResponseBaseAddress.Low =
htole32(cm->cm_sense_busaddr);
req->ErrorResponseAllocationLength =
htole16(sizeof(struct nvme_completion));
req->EncapsulatedCommandLength =
htole16(sizeof(struct nvme_command));
req->DataLength = htole32(data_length);
/* Build NVMe DSM command */
c = (struct nvme_command *) req->NVMe_Command;
c->opc = NVME_OPC_DATASET_MANAGEMENT;
c->nsid = htole32(csio->ccb_h.target_lun + 1);
c->cdw10 = htole32(ndesc - 1);
c->cdw11 = htole32(NVME_DSM_ATTR_DEALLOCATE);
cm->cm_length = data_length;
cm->cm_data = NULL;
cm->cm_complete = mprsas_scsiio_complete;
cm->cm_complete_data = ccb;
cm->cm_targ = targ;
cm->cm_lun = csio->ccb_h.target_lun;
cm->cm_ccb = ccb;
cm->cm_desc.Default.RequestFlags =
MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED;
#if __FreeBSD_version >= 1000029
callout_reset_sbt(&cm->cm_callout, SBT_1MS * ccb->ccb_h.timeout, 0,
mprsas_scsiio_timeout, cm, 0);
#else //__FreeBSD_version < 1000029
callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000,
mprsas_scsiio_timeout, cm);
#endif //__FreeBSD_version >= 1000029
targ->issued++;
targ->outstanding++;
TAILQ_INSERT_TAIL(&targ->commands, cm, cm_link);
ccb->ccb_h.status |= CAM_SIM_QUEUED;
mprsas_log_command(cm, MPR_XINFO, "%s cm %p ccb %p outstanding %u\n",
__func__, cm, ccb, targ->outstanding);
mpr_build_nvme_prp(sc, cm, req, (void *)nvme_dsm_ranges_dma_handle, 0,
data_length);
mpr_map_command(sc, cm);
out:
free(plist, M_MPR);
return 0;
}
static void
mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb)
{
@ -1689,9 +1854,10 @@ mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb)
struct mprsas_target *targ;
struct mprsas_lun *lun;
struct mpr_command *cm;
uint8_t i, lba_byte, *ref_tag_addr;
uint8_t i, lba_byte, *ref_tag_addr, scsi_opcode;
uint16_t eedp_flags;
uint32_t mpi_control;
int rc;
sc = sassc->sc;
MPR_FUNCTRACE(sc);
@ -1777,6 +1943,30 @@ mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb)
return;
}
/* For NVME device's issue UNMAP command directly to NVME drives by
* constructing equivalent native NVMe DataSetManagement command.
*/
#if __FreeBSD_version >= 1100103
scsi_opcode = scsiio_cdb_ptr(csio)[0];
#else
if (csio->ccb_h.flags & CAM_CDB_POINTER)
scsi_opcode = csio->cdb_io.cdb_ptr[0];
else
scsi_opcode = csio->cdb_io.cdb_bytes[0];
#endif
if (scsi_opcode == UNMAP &&
targ->is_nvme &&
(csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) {
rc = mprsas_build_nvme_unmap(sc, cm, ccb, targ);
if (rc == 1) { /* return command to CAM with success status */
mpr_free_command(sc, cm);
mprsas_set_ccbstatus(ccb, CAM_REQ_CMP);
xpt_done(ccb);
return;
} else if (!rc) /* Issued NVMe Encapsulated Request Message */
return;
}
req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req;
bzero(req, sizeof(*req));
req->DevHandle = htole16(targ->handle);
@ -1849,8 +2039,8 @@ mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb)
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));
("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);
}
req->IoFlags = htole16(csio->cdb_len);
@ -1874,6 +2064,10 @@ mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb)
eedp_flags |= (MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD);
if (sc->mpr_flags & MPR_FLAGS_GEN35_IOC) {
eedp_flags |=
MPI25_SCSIIO_EEDPFLAGS_APPTAG_DISABLE_MODE;
}
req->EEDPFlags = htole16(eedp_flags);
/*
@ -1933,11 +2127,15 @@ mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb)
req->IoFlags |= MPI25_SCSIIO_IOFLAGS_FAST_PATH;
cm->cm_desc.FastPathSCSIIO.RequestFlags =
MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
cm->cm_desc.FastPathSCSIIO.DevHandle = htole16(targ->handle);
if (!sc->atomic_desc_capable) {
cm->cm_desc.FastPathSCSIIO.DevHandle =
htole16(targ->handle);
}
} else {
cm->cm_desc.SCSIIO.RequestFlags =
MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
cm->cm_desc.SCSIIO.DevHandle = htole16(targ->handle);
if (!sc->atomic_desc_capable)
cm->cm_desc.SCSIIO.DevHandle = htole16(targ->handle);
}
#if __FreeBSD_version >= 1000029
@ -2160,6 +2358,200 @@ mpr_sc_failed_io_info(struct mpr_softc *sc, struct ccb_scsiio *csio,
}
}
/** mprsas_nvme_trans_status_code
*
* Convert Native NVMe command error status to
* equivalent SCSI error status.
*
* Returns appropriate scsi_status
*/
static u8
mprsas_nvme_trans_status_code(struct nvme_status nvme_status,
struct mpr_command *cm)
{
u8 status = MPI2_SCSI_STATUS_GOOD;
int skey, asc, ascq;
union ccb *ccb = cm->cm_complete_data;
int returned_sense_len;
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_ILLEGAL_REQUEST;
asc = SCSI_ASC_NO_SENSE;
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
switch (nvme_status.sct) {
case NVME_SCT_GENERIC:
switch (nvme_status.sc) {
case NVME_SC_SUCCESS:
status = MPI2_SCSI_STATUS_GOOD;
skey = SSD_KEY_NO_SENSE;
asc = SCSI_ASC_NO_SENSE;
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case NVME_SC_INVALID_OPCODE:
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_ILLEGAL_REQUEST;
asc = SCSI_ASC_ILLEGAL_COMMAND;
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case NVME_SC_INVALID_FIELD:
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_ILLEGAL_REQUEST;
asc = SCSI_ASC_INVALID_CDB;
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case NVME_SC_DATA_TRANSFER_ERROR:
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_MEDIUM_ERROR;
asc = SCSI_ASC_NO_SENSE;
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case NVME_SC_ABORTED_POWER_LOSS:
status = MPI2_SCSI_STATUS_TASK_ABORTED;
skey = SSD_KEY_ABORTED_COMMAND;
asc = SCSI_ASC_WARNING;
ascq = SCSI_ASCQ_POWER_LOSS_EXPECTED;
break;
case NVME_SC_INTERNAL_DEVICE_ERROR:
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_HARDWARE_ERROR;
asc = SCSI_ASC_INTERNAL_TARGET_FAILURE;
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case NVME_SC_ABORTED_BY_REQUEST:
case NVME_SC_ABORTED_SQ_DELETION:
case NVME_SC_ABORTED_FAILED_FUSED:
case NVME_SC_ABORTED_MISSING_FUSED:
status = MPI2_SCSI_STATUS_TASK_ABORTED;
skey = SSD_KEY_ABORTED_COMMAND;
asc = SCSI_ASC_NO_SENSE;
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case NVME_SC_INVALID_NAMESPACE_OR_FORMAT:
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_ILLEGAL_REQUEST;
asc = SCSI_ASC_ACCESS_DENIED_INVALID_LUN_ID;
ascq = SCSI_ASCQ_INVALID_LUN_ID;
break;
case NVME_SC_LBA_OUT_OF_RANGE:
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_ILLEGAL_REQUEST;
asc = SCSI_ASC_ILLEGAL_BLOCK;
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case NVME_SC_CAPACITY_EXCEEDED:
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_MEDIUM_ERROR;
asc = SCSI_ASC_NO_SENSE;
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case NVME_SC_NAMESPACE_NOT_READY:
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_NOT_READY;
asc = SCSI_ASC_LUN_NOT_READY;
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
}
break;
case NVME_SCT_COMMAND_SPECIFIC:
switch (nvme_status.sc) {
case NVME_SC_INVALID_FORMAT:
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_ILLEGAL_REQUEST;
asc = SCSI_ASC_FORMAT_COMMAND_FAILED;
ascq = SCSI_ASCQ_FORMAT_COMMAND_FAILED;
break;
case NVME_SC_CONFLICTING_ATTRIBUTES:
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_ILLEGAL_REQUEST;
asc = SCSI_ASC_INVALID_CDB;
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
}
break;
case NVME_SCT_MEDIA_ERROR:
switch (nvme_status.sc) {
case NVME_SC_WRITE_FAULTS:
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_MEDIUM_ERROR;
asc = SCSI_ASC_PERIPHERAL_DEV_WRITE_FAULT;
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case NVME_SC_UNRECOVERED_READ_ERROR:
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_MEDIUM_ERROR;
asc = SCSI_ASC_UNRECOVERED_READ_ERROR;
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case NVME_SC_GUARD_CHECK_ERROR:
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_MEDIUM_ERROR;
asc = SCSI_ASC_LOG_BLOCK_GUARD_CHECK_FAILED;
ascq = SCSI_ASCQ_LOG_BLOCK_GUARD_CHECK_FAILED;
break;
case NVME_SC_APPLICATION_TAG_CHECK_ERROR:
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_MEDIUM_ERROR;
asc = SCSI_ASC_LOG_BLOCK_APPTAG_CHECK_FAILED;
ascq = SCSI_ASCQ_LOG_BLOCK_APPTAG_CHECK_FAILED;
break;
case NVME_SC_REFERENCE_TAG_CHECK_ERROR:
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_MEDIUM_ERROR;
asc = SCSI_ASC_LOG_BLOCK_REFTAG_CHECK_FAILED;
ascq = SCSI_ASCQ_LOG_BLOCK_REFTAG_CHECK_FAILED;
break;
case NVME_SC_COMPARE_FAILURE:
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_MISCOMPARE;
asc = SCSI_ASC_MISCOMPARE_DURING_VERIFY;
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case NVME_SC_ACCESS_DENIED:
status = MPI2_SCSI_STATUS_CHECK_CONDITION;
skey = SSD_KEY_ILLEGAL_REQUEST;
asc = SCSI_ASC_ACCESS_DENIED_INVALID_LUN_ID;
ascq = SCSI_ASCQ_INVALID_LUN_ID;
break;
}
break;
}
returned_sense_len = sizeof(struct scsi_sense_data);
if (returned_sense_len < ccb->csio.sense_len)
ccb->csio.sense_resid = ccb->csio.sense_len -
returned_sense_len;
else
ccb->csio.sense_resid = 0;
scsi_set_sense_data(&ccb->csio.sense_data, SSD_TYPE_FIXED,
1, skey, asc, ascq, SSD_ELEM_NONE);
ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
return status;
}
/** mprsas_complete_nvme_unmap
*
* Complete native NVMe command issued using NVMe Encapsulated
* Request Message.
*/
static u8
mprsas_complete_nvme_unmap(struct mpr_softc *sc, struct mpr_command *cm)
{
Mpi26NVMeEncapsulatedErrorReply_t *mpi_reply;
struct nvme_completion *nvme_completion = NULL;
u8 scsi_status = MPI2_SCSI_STATUS_GOOD;
mpi_reply =(Mpi26NVMeEncapsulatedErrorReply_t *)cm->cm_reply;
if (le16toh(mpi_reply->ErrorResponseCount)){
nvme_completion = (struct nvme_completion *)cm->cm_sense;
scsi_status = mprsas_nvme_trans_status_code(
nvme_completion->status, cm);
}
return scsi_status;
}
static void
mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm)
{
@ -2168,7 +2560,7 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm)
struct ccb_scsiio *csio;
struct mprsas_softc *sassc;
struct scsi_vpd_supported_page_list *vpd_list = NULL;
u8 *TLR_bits, TLR_on;
u8 *TLR_bits, TLR_on, *scsi_cdb;
int dir = 0, i;
u16 alloc_len;
struct mprsas_target *target;
@ -2266,6 +2658,20 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm)
}
}
/*
* Point to the SCSI CDB, which is dependent on the CAM_CDB_POINTER
* flag, and use it in a few places in the rest of this function for
* convenience. Use the macro if available.
*/
#if __FreeBSD_version >= 1100103
scsi_cdb = scsiio_cdb_ptr(csio);
#else
if (csio->ccb_h.flags & CAM_CDB_POINTER)
scsi_cdb = csio->cdb_io.cdb_ptr;
else
scsi_cdb = csio->cdb_io.cdb_bytes;
#endif
/*
* If this is a Start Stop Unit command and it was issued by the driver
* during shutdown, decrement the refcount to account for all of the
@ -2273,7 +2679,7 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm)
* shutdown completes, meaning SSU_refcount will be 0 after SSU_started
* is TRUE.
*/
if (sc->SSU_started && (csio->cdb_io.cdb_bytes[0] == START_STOP_UNIT)) {
if (sc->SSU_started && (scsi_cdb[0] == START_STOP_UNIT)) {
mpr_dprint(sc, MPR_INFO, "Decrementing SSU count.\n");
sc->SSU_refcount--;
}
@ -2314,6 +2720,14 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm)
return;
}
target = &sassc->targets[target_id];
if (scsi_cdb[0] == UNMAP &&
target->is_nvme &&
(csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) {
rep->SCSIStatus = mprsas_complete_nvme_unmap(sc, cm);
csio->scsi_status = rep->SCSIStatus;
}
mprsas_log_command(cm, MPR_XINFO,
"ioc %x scsi %x state %x xfer %u\n",
le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState,
@ -2325,7 +2739,6 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm)
/* FALLTHROUGH */
case MPI2_IOCSTATUS_SUCCESS:
case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
if ((le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) ==
MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR)
mprsas_log_command(cm, MPR_XINFO, "recovered error\n");
@ -2403,9 +2816,9 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm)
* controller, turn the TLR_bits value ON if page 0x90 is
* supported.
*/
if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) &&
(csio->cdb_io.cdb_bytes[1] & SI_EVPD) &&
(csio->cdb_io.cdb_bytes[2] == SVPD_SUPPORTED_PAGE_LIST) &&
if ((scsi_cdb[0] == INQUIRY) &&
(scsi_cdb[1] & SI_EVPD) &&
(scsi_cdb[2] == SVPD_SUPPORTED_PAGE_LIST) &&
((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) &&
(csio->data_ptr != NULL) &&
((csio->data_ptr[0] & 0x1f) == T_SEQUENTIAL) &&
@ -2417,8 +2830,7 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm)
TLR_bits = &sc->mapping_table[target_id].TLR_bits;
*TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON;
alloc_len = ((u16)csio->cdb_io.cdb_bytes[3] << 8) +
csio->cdb_io.cdb_bytes[4];
alloc_len = ((u16)scsi_cdb[3] << 8) + scsi_cdb[4];
alloc_len -= csio->resid;
for (i = 0; i < MIN(vpd_list->length, alloc_len); i++) {
if (vpd_list->list[i] == 0x90) {
@ -2433,7 +2845,7 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm)
* a SCSI StartStopUnit command will be sent to it when the
* driver is being shutdown.
*/
if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) &&
if ((scsi_cdb[0] == INQUIRY) &&
(csio->data_ptr != NULL) &&
((csio->data_ptr[0] & 0x1f) == T_DIRECT) &&
(sc->mapping_table[target_id].device_info &
@ -2524,7 +2936,14 @@ mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm)
rep->SCSIStatus, rep->SCSIState,
le32toh(rep->TransferCount));
csio->resid = cm->cm_length;
mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
if (scsi_cdb[0] == UNMAP &&
target->is_nvme &&
(csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR)
mprsas_set_ccbstatus(ccb, CAM_REQ_CMP);
else
mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR);
break;
}

View File

@ -83,6 +83,8 @@ struct mprsas_target {
uint8_t scsi_req_desc_type;
uint8_t stop_at_shutdown;
uint8_t supports_SSU;
uint8_t is_nvme;
uint32_t MDTS;
};
struct mprsas_softc {

View File

@ -71,6 +71,7 @@ __FBSDID("$FreeBSD$");
#include <dev/mpr/mpi/mpi2.h>
#include <dev/mpr/mpi/mpi2_ioc.h>
#include <dev/mpr/mpi/mpi2_sas.h>
#include <dev/mpr/mpi/mpi2_pci.h>
#include <dev/mpr/mpi/mpi2_cnfg.h>
#include <dev/mpr/mpi/mpi2_init.h>
#include <dev/mpr/mpi/mpi2_raid.h>
@ -116,6 +117,8 @@ static void mprsas_fw_work(struct mpr_softc *sc,
static void mprsas_fw_event_free(struct mpr_softc *,
struct mpr_fw_event_work *);
static int mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate);
static int mprsas_add_pcie_device(struct mpr_softc *sc, u16 handle,
u8 linkrate);
static int mprsas_get_sata_identify(struct mpr_softc *sc, u16 handle,
Mpi2SataPassthroughReply_t *mpi_reply, char *id_buffer, int sz,
u32 devinfo);
@ -156,6 +159,7 @@ mprsas_evt_handler(struct mpr_softc *sc, uintptr_t data,
bcopy(event->EventData, fw_event->event_data, sz);
fw_event->event = event->Event;
if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
event->Event == MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST ||
event->Event == MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE ||
event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) &&
sc->track_mapping_events)
@ -167,13 +171,13 @@ mprsas_evt_handler(struct mpr_softc *sc, uintptr_t data,
* events are processed.
*/
if ((event->Event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
event->Event == MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST ||
event->Event == MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST) &&
sc->wait_for_port_enable)
mprsas_startup_increment(sc->sassc);
TAILQ_INSERT_TAIL(&sc->sassc->ev_queue, fw_event, ev_link);
taskqueue_enqueue(sc->sassc->ev_tq, &sc->sassc->ev_task);
}
static void
@ -205,7 +209,7 @@ mprsas_fw_work(struct mpr_softc *sc, struct mpr_fw_event_work *fw_event)
{
MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data;
MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy;
int i;
uint8_t i;
data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *)
fw_event->event_data;
@ -674,6 +678,60 @@ mprsas_fw_work(struct mpr_softc *sc, struct mpr_fw_event_work *fw_event)
}
break;
}
case MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST:
{
MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST *data;
MPI26_EVENT_PCIE_TOPO_PORT_ENTRY *port_entry;
uint8_t i, link_rate;
uint16_t handle;
data = (MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST *)
fw_event->event_data;
mpr_mapping_pcie_topology_change_event(sc,
fw_event->event_data);
for (i = 0; i < data->NumEntries; i++) {
port_entry = &data->PortEntry[i];
handle = le16toh(port_entry->AttachedDevHandle);
link_rate = port_entry->CurrentPortInfo &
MPI26_EVENT_PCIE_TOPO_PI_RATE_MASK;
switch (port_entry->PortStatus) {
case MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED:
if (link_rate <
MPI26_EVENT_PCIE_TOPO_PI_RATE_2_5) {
mpr_dprint(sc, MPR_ERROR, "%s: Cannot "
"add PCIe device with handle 0x%x "
"with unknown link rate.\n",
__func__, handle);
break;
}
if (mprsas_add_pcie_device(sc, handle,
link_rate)) {
mpr_dprint(sc, MPR_ERROR, "%s: failed "
"to add PCIe device with handle "
"0x%x\n", __func__, handle);
mprsas_prepare_remove(sassc, handle);
}
break;
case MPI26_EVENT_PCIE_TOPO_PS_NOT_RESPONDING:
mprsas_prepare_remove(sassc, handle);
break;
case MPI26_EVENT_PCIE_TOPO_PS_PORT_CHANGED:
case MPI26_EVENT_PCIE_TOPO_PS_NO_CHANGE:
case MPI26_EVENT_PCIE_TOPO_PS_DELAY_NOT_RESPONDING:
default:
break;
}
}
/*
* refcount was incremented for this event in
* mprsas_evt_handler. Decrement it here because the event has
* been processed.
*/
mprsas_startup_decrement(sassc);
break;
}
case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
default:
@ -703,7 +761,8 @@ mprsas_firmware_event_work(void *arg, int pending)
}
static int
mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate){
mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate)
{
char devstring[80];
struct mprsas_softc *sassc;
struct mprsas_target *targ;
@ -779,8 +838,8 @@ mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate){
if (sc->use_phynum != -1)
id = mpr_mapping_get_sas_id(sc, sas_address, handle);
if (id == MPR_MAP_BAD_ID) {
if ((sc->use_phynum == 0)
|| ((id = config_page.PhyNum) > sassc->maxtargets)) {
if ((sc->use_phynum == 0) ||
((id = config_page.PhyNum) > sassc->maxtargets)) {
mpr_dprint(sc, MPR_INFO, "failure at %s:%d/%s()! "
"Could not get ID for device with handle 0x%04x\n",
__FILE__, __LINE__, __func__, handle);
@ -827,8 +886,10 @@ mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate){
if (is_SATA_SSD) {
targ->flags = MPR_TARGET_IS_SATA_SSD;
}
if (le16toh(config_page.Flags) &
MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) {
if ((le16toh(config_page.Flags) &
MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) &&
(le16toh(config_page.Flags) &
MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE)) {
targ->scsi_req_desc_type =
MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
}
@ -908,7 +969,7 @@ mprsas_add_device(struct mpr_softc *sc, u16 handle, u8 linkrate){
mprsas_startup_decrement(sassc);
return (error);
}
int
mprsas_get_sas_address_for_sata_disk(struct mpr_softc *sc,
u64 *sas_address, u16 handle, u32 device_info, u8 *is_SATA_SSD)
@ -1139,6 +1200,141 @@ mprsas_ata_id_timeout(void *data)
wakeup(cm);
}
static int
mprsas_add_pcie_device(struct mpr_softc *sc, u16 handle, u8 linkrate)
{
char devstring[80];
struct mprsas_softc *sassc;
struct mprsas_target *targ;
Mpi2ConfigReply_t mpi_reply;
Mpi26PCIeDevicePage0_t config_page;
Mpi26PCIeDevicePage2_t config_page2;
uint64_t pcie_wwid, parent_wwid = 0;
u32 device_info, parent_devinfo = 0;
unsigned int id;
int error = 0;
struct mprsas_lun *lun;
sassc = sc->sassc;
mprsas_startup_increment(sassc);
if ((mpr_config_get_pcie_device_pg0(sc, &mpi_reply, &config_page,
MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE, handle))) {
printf("%s: error reading PCIe device page0\n", __func__);
error = ENXIO;
goto out;
}
device_info = le32toh(config_page.DeviceInfo);
if (((device_info & MPI26_PCIE_DEVINFO_PCI_SWITCH) == 0)
&& (le16toh(config_page.ParentDevHandle) != 0)) {
Mpi2ConfigReply_t tmp_mpi_reply;
Mpi26PCIeDevicePage0_t parent_config_page;
if ((mpr_config_get_pcie_device_pg0(sc, &tmp_mpi_reply,
&parent_config_page, MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE,
le16toh(config_page.ParentDevHandle)))) {
printf("%s: error reading PCIe device %#x page0\n",
__func__, le16toh(config_page.ParentDevHandle));
} else {
parent_wwid = parent_config_page.WWID.High;
parent_wwid = (parent_wwid << 32) |
parent_config_page.WWID.Low;
parent_devinfo = le32toh(parent_config_page.DeviceInfo);
}
}
/* TODO Check proper endianness */
pcie_wwid = config_page.WWID.High;
pcie_wwid = (pcie_wwid << 32) | config_page.WWID.Low;
mpr_dprint(sc, MPR_INFO, "PCIe WWID from PCIe device page0 = %jx\n",
pcie_wwid);
if ((mpr_config_get_pcie_device_pg2(sc, &mpi_reply, &config_page2,
MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE, handle))) {
printf("%s: error reading PCIe device page2\n", __func__);
error = ENXIO;
goto out;
}
id = mpr_mapping_get_sas_id(sc, pcie_wwid, handle);
if (id == MPR_MAP_BAD_ID) {
printf("failure at %s:%d/%s()! Could not get ID for device "
"with handle 0x%04x\n", __FILE__, __LINE__, __func__,
handle);
error = ENXIO;
goto out;
}
if (mprsas_check_id(sassc, id) != 0) {
device_printf(sc->mpr_dev, "Excluding target id %d\n", id);
error = ENXIO;
goto out;
}
mpr_dprint(sc, MPR_MAPPING, "WWID from PCIe device page0 = %jx\n",
pcie_wwid);
targ = &sassc->targets[id];
targ->devinfo = device_info;
targ->encl_handle = le16toh(config_page.EnclosureHandle);
targ->encl_slot = le16toh(config_page.Slot);
targ->encl_level = config_page.EnclosureLevel;
targ->connector_name[0] = ((char *)&config_page.ConnectorName)[0];
targ->connector_name[1] = ((char *)&config_page.ConnectorName)[1];
targ->connector_name[2] = ((char *)&config_page.ConnectorName)[2];
targ->connector_name[3] = ((char *)&config_page.ConnectorName)[3];
targ->is_nvme = device_info & MPI26_PCIE_DEVINFO_NVME;
targ->MDTS = config_page2.MaximumDataTransferSize;
/*
* Assume always TRUE for encl_level_valid because there is no valid
* flag for PCIe.
*/
targ->encl_level_valid = TRUE;
targ->handle = handle;
targ->parent_handle = le16toh(config_page.ParentDevHandle);
targ->sasaddr = mpr_to_u64(&config_page.WWID);
targ->parent_sasaddr = le64toh(parent_wwid);
targ->parent_devinfo = parent_devinfo;
targ->tid = id;
targ->linkrate = linkrate;
targ->flags = 0;
if ((le16toh(config_page.Flags) &
MPI26_PCIEDEV0_FLAGS_ENABLED_FAST_PATH) &&
(le16toh(config_page.Flags) &
MPI26_PCIEDEV0_FLAGS_FAST_PATH_CAPABLE)) {
targ->scsi_req_desc_type =
MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
}
TAILQ_INIT(&targ->commands);
TAILQ_INIT(&targ->timedout_commands);
while (!SLIST_EMPTY(&targ->luns)) {
lun = SLIST_FIRST(&targ->luns);
SLIST_REMOVE_HEAD(&targ->luns, lun_link);
free(lun, M_MPR);
}
SLIST_INIT(&targ->luns);
mpr_describe_devinfo(targ->devinfo, devstring, 80);
mpr_dprint(sc, (MPR_INFO|MPR_MAPPING), "Found PCIe device <%s> <%s> "
"handle<0x%04x> enclosureHandle<0x%04x> slot %d\n", devstring,
mpr_describe_table(mpr_pcie_linkrate_names, targ->linkrate),
targ->handle, targ->encl_handle, targ->encl_slot);
if (targ->encl_level_valid) {
mpr_dprint(sc, (MPR_INFO|MPR_MAPPING), "At enclosure level %d "
"and connector name (%4s)\n", targ->encl_level,
targ->connector_name);
}
#if ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000039)) || \
(__FreeBSD_version < 902502)
if ((sassc->flags & MPRSAS_IN_STARTUP) == 0)
#endif
mprsas_rescan_target(sc, targ);
mpr_dprint(sc, MPR_MAPPING, "Target id 0x%x added\n", targ->tid);
out:
mprsas_startup_decrement(sassc);
return (error);
}
static int
mprsas_volume_add(struct mpr_softc *sc, u16 handle)
{
@ -1235,8 +1431,8 @@ mprsas_SSU_to_SATA_devices(struct mpr_softc *sc)
if (target->stop_at_shutdown) {
ccb = xpt_alloc_ccb_nowait();
if (ccb == NULL) {
mpr_dprint(sc, MPR_FAULT, "Unable to alloc CCB to stop "
"unit.\n");
mpr_dprint(sc, MPR_FAULT, "Unable to alloc CCB "
"to stop unit.\n");
return;
}

View File

@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
#include <dev/mpr/mpi/mpi2_cnfg.h>
#include <dev/mpr/mpi/mpi2_init.h>
#include <dev/mpr/mpi/mpi2_tool.h>
#include <dev/mpr/mpi/mpi2_pci.h>
#include <dev/mpr/mpr_ioctl.h>
#include <dev/mpr/mprvar.h>
#include <dev/mpr/mpr_table.h>
@ -74,6 +75,7 @@ mpr_describe_table(struct mpr_table_lookup *table, u_int code)
return(table[i+1].string);
}
//SLM-Add new PCIe info to all of these tables
struct mpr_table_lookup mpr_event_names[] = {
{"LogData", 0x01},
{"StateChange", 0x02},
@ -100,6 +102,10 @@ struct mpr_table_lookup mpr_event_names[] = {
{"TempThreshold", 0x27},
{"HostMessage", 0x28},
{"PowerPerformanceChange", 0x29},
{"PCIeDeviceStatusChange", 0x30},
{"PCIeEnumeration", 0x31},
{"PCIeTopologyChangeList", 0x32},
{"PCIeLinkCounter", 0x33},
{"CableEvent", 0x34},
{NULL, 0},
{"Unknown Event", 0}
@ -192,6 +198,16 @@ struct mpr_table_lookup mpr_sasdev_reason[] = {
{"Unknown", 0x00}
};
struct mpr_table_lookup mpr_pcie_linkrate_names[] = {
{"Port disabled", 0x01},
{"2.5GT/sec", 0x02},
{"5.0GT/sec", 0x03},
{"8.0GT/sec", 0x04},
{"16.0GT/sec", 0x05},
{NULL, 0},
{"LinkRate Unknown", 0x00}
};
void
mpr_describe_devinfo(uint32_t devinfo, char *string, int len)
{
@ -321,6 +337,7 @@ _mpr_print_evt_sas(struct mpr_softc *sc, MPI2_EVENT_NOTIFICATION_REPLY *event)
"\40MaxEnclosures");
break;
}
//SLM-add for PCIE EVENT too
case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
{
MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data;

View File

@ -40,6 +40,7 @@ void mpr_describe_devinfo(uint32_t devinfo, char *string, int len);
extern struct mpr_table_lookup mpr_event_names[];
extern struct mpr_table_lookup mpr_phystatus_names[];
extern struct mpr_table_lookup mpr_linkrate_names[];
extern struct mpr_table_lookup mpr_pcie_linkrate_names[];
void _mpr_print_iocfacts(struct mpr_softc *, MPI2_IOC_FACTS_REPLY *);
void _mpr_print_portfacts(struct mpr_softc *, MPI2_PORT_FACTS_REPLY *);

View File

@ -99,6 +99,7 @@ __FBSDID("$FreeBSD$");
#include <dev/mpr/mpi/mpi2_cnfg.h>
#include <dev/mpr/mpi/mpi2_init.h>
#include <dev/mpr/mpi/mpi2_tool.h>
#include <dev/mpr/mpi/mpi2_pci.h>
#include <dev/mpr/mpr_ioctl.h>
#include <dev/mpr/mprvar.h>
#include <dev/mpr/mpr_table.h>
@ -747,6 +748,8 @@ mpr_user_pass_thru(struct mpr_softc *sc, mpr_pass_thru_t *data)
{
MPI2_REQUEST_HEADER *hdr, tmphdr;
MPI2_DEFAULT_REPLY *rpl;
Mpi26NVMeEncapsulatedErrorReply_t *nvme_error_reply = NULL;
Mpi26NVMeEncapsulatedRequest_t *nvme_encap_request = NULL;
struct mpr_command *cm = NULL;
int i, err = 0, dir = 0, sz;
uint8_t tool, function = 0;
@ -923,8 +926,8 @@ mpr_user_pass_thru(struct mpr_softc *sc, mpr_pass_thru_t *data)
cm->cm_data, data->DataSize);
}
if (err != 0)
mpr_dprint(sc, MPR_FAULT, "%s: failed to copy "
"IOCTL data from user space\n", __func__);
mpr_dprint(sc, MPR_FAULT, "%s: failed to copy IOCTL "
"data from user space\n", __func__);
}
/*
* Set this flag only if processing a command that does not need an
@ -946,6 +949,35 @@ mpr_user_pass_thru(struct mpr_softc *sc, mpr_pass_thru_t *data)
}
cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
if (function == MPI2_FUNCTION_NVME_ENCAPSULATED) {
nvme_encap_request =
(Mpi26NVMeEncapsulatedRequest_t *)cm->cm_req;
cm->cm_desc.Default.RequestFlags =
MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED;
/*
* Get the Physical Address of the sense buffer.
* Save the user's Error Response buffer address and use that
* field to hold the sense buffer address.
* Clear the internal sense buffer, which will potentially hold
* the Completion Queue Entry on return, or 0 if no Entry.
* Build the PRPs and set direction bits.
* Send the request.
*/
cm->nvme_error_response =
(uint64_t *)(uintptr_t)(((uint64_t)nvme_encap_request->
ErrorResponseBaseAddress.High << 32) |
(uint64_t)nvme_encap_request->
ErrorResponseBaseAddress.Low);
nvme_encap_request->ErrorResponseBaseAddress.High =
htole32((uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32));
nvme_encap_request->ErrorResponseBaseAddress.Low =
htole32(cm->cm_sense_busaddr);
memset(cm->cm_sense, 0, NVME_ERROR_RESPONSE_SIZE);
mpr_build_nvme_prp(sc, cm, nvme_encap_request, cm->cm_data,
data->DataSize, data->DataOutSize);
}
/*
* Set up Sense buffer and SGL offset for IO passthru. SCSI IO request
* uses SCSI IO or Fast Path SCSI IO descriptor.
@ -994,15 +1026,19 @@ mpr_user_pass_thru(struct mpr_softc *sc, mpr_pass_thru_t *data)
MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO) {
cm->cm_desc.FastPathSCSIIO.RequestFlags =
MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO;
cm->cm_desc.FastPathSCSIIO.DevHandle =
scsi_io_req->DevHandle;
if (!sc->atomic_desc_capable) {
cm->cm_desc.FastPathSCSIIO.DevHandle =
scsi_io_req->DevHandle;
}
scsi_io_req->IoFlags |=
MPI25_SCSIIO_IOFLAGS_FAST_PATH;
} else {
cm->cm_desc.SCSIIO.RequestFlags =
MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
cm->cm_desc.SCSIIO.DevHandle =
scsi_io_req->DevHandle;
if (!sc->atomic_desc_capable) {
cm->cm_desc.SCSIIO.DevHandle =
scsi_io_req->DevHandle;
}
}
/*
@ -1079,6 +1115,38 @@ mpr_user_pass_thru(struct mpr_softc *sc, mpr_pass_thru_t *data)
mpr_lock(sc);
}
}
/*
* Copy out the NVMe Error Reponse to user. The Error Response
* buffer is given by the user, but a sense buffer is used to
* get that data from the IOC. The user's
* ErrorResponseBaseAddress is saved in the
* 'nvme_error_response' field before the command because that
* field is set to a sense buffer. When the command is
* complete, the Error Response data from the IOC is copied to
* that user address after it is checked for validity.
* Also note that 'sense' buffers are not defined for
* NVMe commands. Sense terminalogy is only used here so that
* the same IOCTL structure and sense buffers can be used for
* NVMe.
*/
if (function == MPI2_FUNCTION_NVME_ENCAPSULATED) {
if (cm->nvme_error_response == NULL) {
mpr_dprint(sc, MPR_INFO, "NVMe Error Response "
"buffer is NULL. Response data will not be "
"returned.\n");
mpr_unlock(sc);
goto RetFreeUnlocked;
}
nvme_error_reply =
(Mpi26NVMeEncapsulatedErrorReply_t *)cm->cm_reply;
sz = MIN(le32toh(nvme_error_reply->ErrorResponseCount),
NVME_ERROR_RESPONSE_SIZE);
mpr_unlock(sc);
copyout(cm->cm_sense, cm->nvme_error_response, sz);
mpr_lock(sc);
}
}
mpr_unlock(sc);
@ -2068,7 +2136,7 @@ mpr_user_btdh(struct mpr_softc *sc, mpr_btdh_mapping_t *data)
return (EINVAL);
if (target > sc->max_devices) {
mpr_dprint(sc, MPR_FAULT, "Target ID is out of range "
mpr_dprint(sc, MPR_XINFO, "Target ID is out of range "
"for Bus/Target to DevHandle mapping.");
return (EINVAL);
}

View File

@ -33,7 +33,7 @@
#ifndef _MPRVAR_H
#define _MPRVAR_H
#define MPR_DRIVER_VERSION "15.01.00.00-fbsd"
#define MPR_DRIVER_VERSION "15.02.00.00-fbsd"
#define MPR_DB_MAX_WAIT 2500
@ -50,6 +50,17 @@
#define MPR_DEFAULT_CHAIN_SEG_SIZE 8
#define MPR_MAX_CHAIN_ELEMENT_SIZE 16
/*
* PCIe NVMe Specific defines
*/
//SLM-for now just use the same value as a SAS disk
#define NVME_QDEPTH MPR_REQ_FRAMES
#define PRP_ENTRY_SIZE 8
#define NVME_CMD_PRP1_OFFSET 24 /* PRP1 offset in NVMe cmd */
#define NVME_CMD_PRP2_OFFSET 32 /* PRP2 offset in NVMe cmd */
#define NVME_ERROR_RESPONSE_SIZE 16 /* Max NVME Error Response */
#define HOST_PAGE_SIZE_4K 12
#define MPR_FUNCTRACE(sc) \
mpr_dprint((sc), MPR_TRACE, "%s\n", __func__)
@ -184,6 +195,12 @@ struct mpr_chain {
uint64_t chain_busaddr;
};
struct mpr_prp_page {
TAILQ_ENTRY(mpr_prp_page) prp_page_link;
uint64_t *prp_page;
uint64_t prp_page_busaddr;
};
/*
* This needs to be at least 2 to support SMP passthrough.
*/
@ -229,9 +246,11 @@ struct mpr_command {
#define MPR_CM_STATE_TIMEDOUT 2
bus_dmamap_t cm_dmamap;
struct scsi_sense_data *cm_sense;
uint64_t *nvme_error_response;
TAILQ_HEAD(, mpr_chain) cm_chain_list;
TAILQ_HEAD(, mpr_prp_page) cm_prp_page_list;
uint32_t cm_req_busaddr;
uint32_t cm_sense_busaddr;
bus_addr_t cm_sense_busaddr;
struct callout cm_callout;
};
@ -257,27 +276,35 @@ struct mpr_softc {
#define MPR_FLAGS_SHUTDOWN (1 << 3)
#define MPR_FLAGS_DIAGRESET (1 << 4)
#define MPR_FLAGS_ATTACH_DONE (1 << 5)
#define MPR_FLAGS_GEN35_IOC (1 << 6)
u_int mpr_debug;
u_int disable_msix;
u_int disable_msi;
u_int atomic_desc_capable;
int tm_cmds_active;
int io_cmds_active;
int io_cmds_highwater;
int chain_free;
int max_chains;
int max_io_pages;
u_int maxio;
int chain_free_lowwater;
uint32_t chain_frame_size;
uint16_t chain_seg_size;
int prp_buffer_size;
int prp_pages_free;
int prp_pages_free_lowwater;
u_int enable_ssu;
int spinup_wait_time;
int use_phynum;
uint64_t chain_alloc_fail;
uint64_t prp_page_alloc_fail;
struct sysctl_ctx_list sysctl_ctx;
struct sysctl_oid *sysctl_tree;
char fw_version[16];
struct mpr_command *commands;
struct mpr_chain *chains;
struct mpr_prp_page *prps;
struct callout periodic;
struct mprsas_softc *sassc;
@ -285,6 +312,7 @@ struct mpr_softc {
TAILQ_HEAD(, mpr_command) req_list;
TAILQ_HEAD(, mpr_command) high_priority_req_list;
TAILQ_HEAD(, mpr_chain) chain_list;
TAILQ_HEAD(, mpr_prp_page) prp_page_list;
TAILQ_HEAD(, mpr_command) tm_list;
int replypostindex;
int replyfreeindex;
@ -333,6 +361,11 @@ struct mpr_softc {
bus_dma_tag_t chain_dmat;
bus_dmamap_t chain_map;
uint8_t *prp_pages;
bus_addr_t prp_page_busaddr;
bus_dma_tag_t prp_page_dmat;
bus_dmamap_t prp_page_map;
MPI2_REPLY_DESCRIPTORS_UNION *post_queue;
bus_addr_t post_busaddr;
uint32_t *free_queue;
@ -471,10 +504,33 @@ mpr_free_chain(struct mpr_softc *sc, struct mpr_chain *chain)
TAILQ_INSERT_TAIL(&sc->chain_list, chain, chain_link);
}
static __inline struct mpr_prp_page *
mpr_alloc_prp_page(struct mpr_softc *sc)
{
struct mpr_prp_page *prp_page;
if ((prp_page = TAILQ_FIRST(&sc->prp_page_list)) != NULL) {
TAILQ_REMOVE(&sc->prp_page_list, prp_page, prp_page_link);
sc->prp_pages_free--;
if (sc->prp_pages_free < sc->prp_pages_free_lowwater)
sc->prp_pages_free_lowwater = sc->prp_pages_free;
} else
sc->prp_page_alloc_fail++;
return (prp_page);
}
static __inline void
mpr_free_prp_page(struct mpr_softc *sc, struct mpr_prp_page *prp_page)
{
sc->prp_pages_free++;
TAILQ_INSERT_TAIL(&sc->prp_page_list, prp_page, prp_page_link);
}
static __inline void
mpr_free_command(struct mpr_softc *sc, struct mpr_command *cm)
{
struct mpr_chain *chain, *chain_temp;
struct mpr_prp_page *prp_page, *prp_page_temp;
if (cm->cm_reply != NULL)
mpr_free_reply(sc, cm->cm_reply_data);
@ -497,6 +553,11 @@ mpr_free_command(struct mpr_softc *sc, struct mpr_command *cm)
TAILQ_REMOVE(&cm->cm_chain_list, chain, chain_link);
mpr_free_chain(sc, chain);
}
TAILQ_FOREACH_SAFE(prp_page, &cm->cm_prp_page_list, prp_page_link,
prp_page_temp) {
TAILQ_REMOVE(&cm->cm_prp_page_list, prp_page, prp_page_link);
mpr_free_prp_page(sc, prp_page);
}
TAILQ_INSERT_TAIL(&sc->req_list, cm, cm_link);
}
@ -510,7 +571,8 @@ mpr_alloc_command(struct mpr_softc *sc)
return (NULL);
TAILQ_REMOVE(&sc->req_list, cm, cm_link);
KASSERT(cm->cm_state == MPR_CM_STATE_FREE, ("mpr: Allocating busy command\n"));
KASSERT(cm->cm_state == MPR_CM_STATE_FREE, ("mpr: Allocating busy "
"command\n"));
cm->cm_state = MPR_CM_STATE_BUSY;
return (cm);
}
@ -547,7 +609,8 @@ mpr_alloc_high_priority_command(struct mpr_softc *sc)
return (NULL);
TAILQ_REMOVE(&sc->high_priority_req_list, cm, cm_link);
KASSERT(cm->cm_state == MPR_CM_STATE_FREE, ("mpr: Allocating busy command\n"));
KASSERT(cm->cm_state == MPR_CM_STATE_FREE, ("mpr: Allocating busy "
"command\n"));
cm->cm_state = MPR_CM_STATE_BUSY;
return (cm);
}
@ -653,6 +716,9 @@ int mpr_register_events(struct mpr_softc *, uint8_t *, mpr_evt_callback_t *,
int mpr_restart(struct mpr_softc *);
int mpr_update_events(struct mpr_softc *, struct mpr_event_handle *, uint8_t *);
int mpr_deregister_events(struct mpr_softc *, struct mpr_event_handle *);
void mpr_build_nvme_prp(struct mpr_softc *sc, struct mpr_command *cm,
Mpi26NVMeEncapsulatedRequest_t *nvme_encap_request, void *data,
uint32_t data_in_sz, uint32_t data_out_sz);
int mpr_push_sge(struct mpr_command *, MPI2_SGE_SIMPLE64 *, size_t, int);
int mpr_push_ieee_sge(struct mpr_command *, void *, int);
int mpr_add_dmaseg(struct mpr_command *, vm_paddr_t, size_t, u_int, int);
@ -682,6 +748,10 @@ int mpr_config_get_iounit_pg8(struct mpr_softc *sc,
Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page);
int mpr_config_get_sas_device_pg0(struct mpr_softc *, Mpi2ConfigReply_t *,
Mpi2SasDevicePage0_t *, u32 , u16 );
int mpr_config_get_pcie_device_pg0(struct mpr_softc *sc, Mpi2ConfigReply_t
*mpi_reply, Mpi26PCIeDevicePage0_t *config_page, u32 form, u16 handle);
int mpr_config_get_pcie_device_pg2(struct mpr_softc *sc, Mpi2ConfigReply_t
*mpi_reply, Mpi26PCIeDevicePage2_t *config_page, u32 form, u16 handle);
int mpr_config_get_dpm_pg0(struct mpr_softc *, Mpi2ConfigReply_t *,
Mpi2DriverMappingPage0_t *, u16 );
int mpr_config_get_raid_volume_pg1(struct mpr_softc *sc,
@ -702,6 +772,8 @@ void mpr_base_static_config_pages(struct mpr_softc *sc);
int mpr_mapping_initialize(struct mpr_softc *);
void mpr_mapping_topology_change_event(struct mpr_softc *,
Mpi2EventDataSasTopologyChangeList_t *);
void mpr_mapping_pcie_topology_change_event(struct mpr_softc *sc,
Mpi26EventDataPCIeTopologyChangeList_t *event_data);
int mpr_mapping_is_reinit_required(struct mpr_softc *);
void mpr_mapping_free_memory(struct mpr_softc *sc);
int mpr_config_set_dpm_pg0(struct mpr_softc *, Mpi2ConfigReply_t *,
@ -769,5 +841,52 @@ SYSCTL_DECL(_hw_mpr);
#define CAM_PRIORITY_NORMAL CAM_PRIORITY_NONE
#endif
/* Definitions for SCSI unmap translation to NVMe DSM command */
/* UNMAP block descriptor structure */
struct unmap_blk_desc {
uint64_t slba;
uint32_t nlb;
uint32_t resv;
};
/* UNMAP command's data */
struct unmap_parm_list {
uint16_t unmap_data_len;
uint16_t unmap_blk_desc_data_len;
uint32_t resv;
struct unmap_blk_desc desc[0];
};
/* SCSI ADDITIONAL SENSE Codes */
#define FIXED_SENSE_DATA 0x70
#define SCSI_ASC_NO_SENSE 0x00
#define SCSI_ASC_PERIPHERAL_DEV_WRITE_FAULT 0x03
#define SCSI_ASC_LUN_NOT_READY 0x04
#define SCSI_ASC_WARNING 0x0B
#define SCSI_ASC_LOG_BLOCK_GUARD_CHECK_FAILED 0x10
#define SCSI_ASC_LOG_BLOCK_APPTAG_CHECK_FAILED 0x10
#define SCSI_ASC_LOG_BLOCK_REFTAG_CHECK_FAILED 0x10
#define SCSI_ASC_UNRECOVERED_READ_ERROR 0x11
#define SCSI_ASC_MISCOMPARE_DURING_VERIFY 0x1D
#define SCSI_ASC_ACCESS_DENIED_INVALID_LUN_ID 0x20
#define SCSI_ASC_ILLEGAL_COMMAND 0x20
#define SCSI_ASC_ILLEGAL_BLOCK 0x21
#define SCSI_ASC_INVALID_CDB 0x24
#define SCSI_ASC_INVALID_LUN 0x25
#define SCSI_ASC_INVALID_PARAMETER 0x26
#define SCSI_ASC_FORMAT_COMMAND_FAILED 0x31
#define SCSI_ASC_INTERNAL_TARGET_FAILURE 0x44
/* SCSI ADDITIONAL SENSE Code Qualifiers */
#define SCSI_ASCQ_CAUSE_NOT_REPORTABLE 0x00
#define SCSI_ASCQ_FORMAT_COMMAND_FAILED 0x01
#define SCSI_ASCQ_LOG_BLOCK_GUARD_CHECK_FAILED 0x01
#define SCSI_ASCQ_LOG_BLOCK_APPTAG_CHECK_FAILED 0x02
#define SCSI_ASCQ_LOG_BLOCK_REFTAG_CHECK_FAILED 0x03
#define SCSI_ASCQ_FORMAT_IN_PROGRESS 0x04
#define SCSI_ASCQ_POWER_LOSS_EXPECTED 0x08
#define SCSI_ASCQ_INVALID_LUN_ID 0x09
#endif