summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsbruno <sbruno@FreeBSD.org>2016-04-05 20:34:20 +0000
committersbruno <sbruno@FreeBSD.org>2016-04-05 20:34:20 +0000
commit48324f1236db770786d27c165325e97d864335df (patch)
tree7da5b0479ed235e16f29e6149d1820fb72bbbb6a
parentec0d763b35ddfe982d7db44b3a1b0ba72d77a464 (diff)
downloadFreeBSD-src-48324f1236db770786d27c165325e97d864335df.zip
FreeBSD-src-48324f1236db770786d27c165325e97d864335df.tar.gz
MFC 290102
- Include usr.sbin/mpsutil for management of mps(4) and mpr(4) utilities. - Thanks to scottl and bapt for making this happen. Submitted by: bapt scottl Reviewed by: kbowling Relnotes: yes Differential Revision: https://reviews.freebsd.org/D5529
-rw-r--r--usr.sbin/Makefile1
-rw-r--r--usr.sbin/mpsutil/Makefile21
-rw-r--r--usr.sbin/mpsutil/mpr_ioctl.h388
-rw-r--r--usr.sbin/mpsutil/mps_cmd.c731
-rw-r--r--usr.sbin/mpsutil/mps_flash.c237
-rw-r--r--usr.sbin/mpsutil/mps_ioctl.h387
-rw-r--r--usr.sbin/mpsutil/mps_show.c772
-rw-r--r--usr.sbin/mpsutil/mpsutil.8165
-rw-r--r--usr.sbin/mpsutil/mpsutil.c207
-rw-r--r--usr.sbin/mpsutil/mpsutil.h147
10 files changed, 3056 insertions, 0 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
index c6d4b6e..f76bb01 100644
--- a/usr.sbin/Makefile
+++ b/usr.sbin/Makefile
@@ -46,6 +46,7 @@ SUBDIR= adduser \
mlxcontrol \
mountd \
mount_smbfs \
+ mpsutil \
mptutil \
mtest \
${_mtree} \
diff --git a/usr.sbin/mpsutil/Makefile b/usr.sbin/mpsutil/Makefile
new file mode 100644
index 0000000..e170029
--- /dev/null
+++ b/usr.sbin/mpsutil/Makefile
@@ -0,0 +1,21 @@
+# $FreeBSD$
+
+PROG= mpsutil
+SRCS= mps_cmd.c mps_flash.c mps_show.c mpsutil.c
+MAN= mpsutil.8
+
+WARNS?= 3
+
+#LIBADD= cam util
+LINKS= ${BINDIR}/mpsutil ${BINDIR}/mprutil
+MLINKS= mpsutil.8 mprutil.8
+
+CFLAGS+= -I${.CURDIR}/../../sys -I. -DUSE_MPT_IOCTLS
+
+
+# Here be dragons
+.ifdef DEBUG
+CFLAGS+= -DDEBUG
+.endif
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/mpsutil/mpr_ioctl.h b/usr.sbin/mpsutil/mpr_ioctl.h
new file mode 100644
index 0000000..82627b9
--- /dev/null
+++ b/usr.sbin/mpsutil/mpr_ioctl.h
@@ -0,0 +1,388 @@
+/*-
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * 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.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD userland interface
+ *
+ * $FreeBSD$
+ */
+/*-
+ * Copyright (c) 2011-2014 LSI Corp.
+ * 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.
+ *
+ * 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.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MPR_IOCTL_H_
+#define _MPR_IOCTL_H_
+
+#include <dev/mpr/mpi/mpi2_type.h>
+#include <dev/mpr/mpi/mpi2.h>
+#include <dev/mpr/mpi/mpi2_cnfg.h>
+#include <dev/mpr/mpi/mpi2_sas.h>
+
+/*
+ * For the read header requests, the header should include the page
+ * type or extended page type, page number, and page version. The
+ * buffer and length are unused. The completed header is returned in
+ * the 'header' member.
+ *
+ * For the read page and write page requests, 'buf' should point to a
+ * buffer of 'len' bytes which holds the entire page (including the
+ * header).
+ *
+ * All requests specify the page address in 'page_address'.
+ */
+struct mpr_cfg_page_req {
+ MPI2_CONFIG_PAGE_HEADER header;
+ uint32_t page_address;
+ void *buf;
+ int len;
+ uint16_t ioc_status;
+};
+
+struct mpr_ext_cfg_page_req {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER header;
+ uint32_t page_address;
+ void *buf;
+ int len;
+ uint16_t ioc_status;
+};
+
+struct mpr_raid_action {
+ uint8_t action;
+ uint8_t volume_bus;
+ uint8_t volume_id;
+ uint8_t phys_disk_num;
+ uint32_t action_data_word;
+ void *buf;
+ int len;
+ uint32_t volume_status;
+ uint32_t action_data[4];
+ uint16_t action_status;
+ uint16_t ioc_status;
+ uint8_t write;
+};
+
+struct mpr_usr_command {
+ void *req;
+ uint32_t req_len;
+ void *rpl;
+ uint32_t rpl_len;
+ void *buf;
+ int len;
+ uint32_t flags;
+};
+
+typedef struct mpr_pci_bits
+{
+ union {
+ struct {
+ uint32_t DeviceNumber :5;
+ uint32_t FunctionNumber :3;
+ uint32_t BusNumber :24;
+ } bits;
+ uint32_t AsDWORD;
+ } u;
+ uint32_t PciSegmentId;
+} mpr_pci_bits_t;
+
+/*
+ * The following is the MPRIOCTL_GET_ADAPTER_DATA data structure. This data
+ * structure is setup so that we hopefully are properly aligned for both
+ * 32-bit and 64-bit mode applications.
+ *
+ * Adapter Type - Value = 6 = SCSI Protocol through SAS-3 adapter
+ *
+ * MPI Port Number - The PCI Function number for this device
+ *
+ * PCI Device HW Id - The PCI device number for this device
+ *
+ */
+#define MPRIOCTL_ADAPTER_TYPE_SAS3 6
+typedef struct mpr_adapter_data
+{
+ uint32_t StructureLength;
+ uint32_t AdapterType;
+ uint32_t MpiPortNumber;
+ uint32_t PCIDeviceHwId;
+ uint32_t PCIDeviceHwRev;
+ uint32_t SubSystemId;
+ uint32_t SubsystemVendorId;
+ uint32_t Reserved1;
+ uint32_t MpiFirmwareVersion;
+ uint32_t BiosVersion;
+ uint8_t DriverVersion[32];
+ uint8_t Reserved2;
+ uint8_t ScsiId;
+ uint16_t Reserved3;
+ mpr_pci_bits_t PciInformation;
+} mpr_adapter_data_t;
+
+
+typedef struct mpr_update_flash
+{
+ uint64_t PtrBuffer;
+ uint32_t ImageChecksum;
+ uint32_t ImageOffset;
+ uint32_t ImageSize;
+ uint32_t ImageType;
+} mpr_update_flash_t;
+
+
+#define MPR_PASS_THRU_DIRECTION_NONE 0
+#define MPR_PASS_THRU_DIRECTION_READ 1
+#define MPR_PASS_THRU_DIRECTION_WRITE 2
+#define MPR_PASS_THRU_DIRECTION_BOTH 3
+
+typedef struct mpr_pass_thru
+{
+ uint64_t PtrRequest;
+ uint64_t PtrReply;
+ uint64_t PtrData;
+ uint32_t RequestSize;
+ uint32_t ReplySize;
+ uint32_t DataSize;
+ uint32_t DataDirection;
+ uint64_t PtrDataOut;
+ uint32_t DataOutSize;
+ uint32_t Timeout;
+} mpr_pass_thru_t;
+
+
+/*
+ * Event queue defines
+ */
+#define MPR_EVENT_QUEUE_SIZE (50) /* Max Events stored in driver */
+#define MPR_MAX_EVENT_DATA_LENGTH (48) /* Size of each event in Dwords */
+
+typedef struct mpr_event_query
+{
+ uint16_t Entries;
+ uint16_t Reserved;
+ uint32_t Types[4];
+} mpr_event_query_t;
+
+typedef struct mpr_event_enable
+{
+ uint32_t Types[4];
+} mpr_event_enable_t;
+
+/*
+ * Event record entry for ioctl.
+ */
+typedef struct mpr_event_entry
+{
+ uint32_t Type;
+ uint32_t Number;
+ uint32_t Data[MPR_MAX_EVENT_DATA_LENGTH];
+} mpr_event_entry_t;
+
+typedef struct mpr_event_report
+{
+ uint32_t Size;
+ uint64_t PtrEvents;
+} mpr_event_report_t;
+
+
+typedef struct mpr_pci_info
+{
+ uint32_t BusNumber;
+ uint8_t DeviceNumber;
+ uint8_t FunctionNumber;
+ uint16_t InterruptVector;
+ uint8_t PciHeader[256];
+} mpr_pci_info_t;
+
+
+typedef struct mpr_diag_action
+{
+ uint32_t Action;
+ uint32_t Length;
+ uint64_t PtrDiagAction;
+ uint32_t ReturnCode;
+} mpr_diag_action_t;
+
+#define MPR_FW_DIAGNOSTIC_UID_NOT_FOUND (0xFF)
+
+#define MPR_FW_DIAG_NEW (0x806E6577)
+
+#define MPR_FW_DIAG_TYPE_REGISTER (0x00000001)
+#define MPR_FW_DIAG_TYPE_UNREGISTER (0x00000002)
+#define MPR_FW_DIAG_TYPE_QUERY (0x00000003)
+#define MPR_FW_DIAG_TYPE_READ_BUFFER (0x00000004)
+#define MPR_FW_DIAG_TYPE_RELEASE (0x00000005)
+
+#define MPR_FW_DIAG_INVALID_UID (0x00000000)
+
+#define MPR_DIAG_SUCCESS 0
+#define MPR_DIAG_FAILURE 1
+
+#define MPR_FW_DIAG_ERROR_SUCCESS (0x00000000)
+#define MPR_FW_DIAG_ERROR_FAILURE (0x00000001)
+#define MPR_FW_DIAG_ERROR_INVALID_PARAMETER (0x00000002)
+#define MPR_FW_DIAG_ERROR_POST_FAILED (0x00000010)
+#define MPR_FW_DIAG_ERROR_INVALID_UID (0x00000011)
+#define MPR_FW_DIAG_ERROR_RELEASE_FAILED (0x00000012)
+#define MPR_FW_DIAG_ERROR_NO_BUFFER (0x00000013)
+#define MPR_FW_DIAG_ERROR_ALREADY_RELEASED (0x00000014)
+
+
+typedef struct mpr_fw_diag_register
+{
+ uint8_t ExtendedType;
+ uint8_t BufferType;
+ uint16_t ApplicationFlags;
+ uint32_t DiagnosticFlags;
+ uint32_t ProductSpecific[23];
+ uint32_t RequestedBufferSize;
+ uint32_t UniqueId;
+} mpr_fw_diag_register_t;
+
+typedef struct mpr_fw_diag_unregister
+{
+ uint32_t UniqueId;
+} mpr_fw_diag_unregister_t;
+
+#define MPR_FW_DIAG_FLAG_APP_OWNED (0x0001)
+#define MPR_FW_DIAG_FLAG_BUFFER_VALID (0x0002)
+#define MPR_FW_DIAG_FLAG_FW_BUFFER_ACCESS (0x0004)
+
+typedef struct mpr_fw_diag_query
+{
+ uint8_t ExtendedType;
+ uint8_t BufferType;
+ uint16_t ApplicationFlags;
+ uint32_t DiagnosticFlags;
+ uint32_t ProductSpecific[23];
+ uint32_t TotalBufferSize;
+ uint32_t DriverAddedBufferSize;
+ uint32_t UniqueId;
+} mpr_fw_diag_query_t;
+
+typedef struct mpr_fw_diag_release
+{
+ uint32_t UniqueId;
+} mpr_fw_diag_release_t;
+
+#define MPR_FW_DIAG_FLAG_REREGISTER (0x0001)
+#define MPR_FW_DIAG_FLAG_FORCE_RELEASE (0x0002)
+
+typedef struct mpr_diag_read_buffer
+{
+ uint8_t Status;
+ uint8_t Reserved;
+ uint16_t Flags;
+ uint32_t StartingOffset;
+ uint32_t BytesToRead;
+ uint32_t UniqueId;
+ uint64_t PtrDataBuffer;
+} mpr_diag_read_buffer_t;
+
+/*
+ * Register Access
+ */
+#define REG_IO_READ 1
+#define REG_IO_WRITE 2
+#define REG_MEM_READ 3
+#define REG_MEM_WRITE 4
+
+typedef struct mpr_reg_access
+{
+ uint32_t Command;
+ uint32_t RegOffset;
+ uint32_t RegData;
+} mpr_reg_access_t;
+
+typedef struct mpr_btdh_mapping
+{
+ uint16_t TargetID;
+ uint16_t Bus;
+ uint16_t DevHandle;
+ uint16_t Reserved;
+} mpr_btdh_mapping_t;
+
+#define MPRIO_MPR_COMMAND_FLAG_VERBOSE 0x01
+#define MPRIO_MPR_COMMAND_FLAG_DEBUG 0x02
+#define MPRIO_READ_CFG_HEADER _IOWR('M', 200, struct mpr_cfg_page_req)
+#define MPRIO_READ_CFG_PAGE _IOWR('M', 201, struct mpr_cfg_page_req)
+#define MPRIO_READ_EXT_CFG_HEADER _IOWR('M', 202, struct mpr_ext_cfg_page_req)
+#define MPRIO_READ_EXT_CFG_PAGE _IOWR('M', 203, struct mpr_ext_cfg_page_req)
+#define MPRIO_WRITE_CFG_PAGE _IOWR('M', 204, struct mpr_cfg_page_req)
+#define MPRIO_RAID_ACTION _IOWR('M', 205, struct mpr_raid_action)
+#define MPRIO_MPR_COMMAND _IOWR('M', 210, struct mpr_usr_command)
+
+#ifndef MPTIOCTL
+#define MPTIOCTL ('I')
+#define MPTIOCTL_GET_ADAPTER_DATA _IOWR(MPTIOCTL, 1,\
+ struct mpr_adapter_data)
+#define MPTIOCTL_UPDATE_FLASH _IOWR(MPTIOCTL, 2,\
+ struct mpr_update_flash)
+#define MPTIOCTL_RESET_ADAPTER _IO(MPTIOCTL, 3)
+#define MPTIOCTL_PASS_THRU _IOWR(MPTIOCTL, 4,\
+ struct mpr_pass_thru)
+#define MPTIOCTL_EVENT_QUERY _IOWR(MPTIOCTL, 5,\
+ struct mpr_event_query)
+#define MPTIOCTL_EVENT_ENABLE _IOWR(MPTIOCTL, 6,\
+ struct mpr_event_enable)
+#define MPTIOCTL_EVENT_REPORT _IOWR(MPTIOCTL, 7,\
+ struct mpr_event_report)
+#define MPTIOCTL_GET_PCI_INFO _IOWR(MPTIOCTL, 8,\
+ struct mpr_pci_info)
+#define MPTIOCTL_DIAG_ACTION _IOWR(MPTIOCTL, 9,\
+ struct mpr_diag_action)
+#define MPTIOCTL_REG_ACCESS _IOWR(MPTIOCTL, 10,\
+ struct mpr_reg_access)
+#define MPTIOCTL_BTDH_MAPPING _IOWR(MPTIOCTL, 11,\
+ struct mpr_btdh_mapping)
+#endif
+
+#endif /* !_MPR_IOCTL_H_ */
diff --git a/usr.sbin/mpsutil/mps_cmd.c b/usr.sbin/mpsutil/mps_cmd.c
new file mode 100644
index 0000000..24ed74e
--- /dev/null
+++ b/usr.sbin/mpsutil/mps_cmd.c
@@ -0,0 +1,731 @@
+/*-
+ * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
+ *
+ * Copyright (c) 2015 Netflix, Inc.
+ * All rights reserved.
+ * Written by: Scott Long <scottl@freebsd.org>
+ *
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#if 0
+#include <sys/mps_ioctl.h>
+#else
+#include "mps_ioctl.h"
+#include "mpr_ioctl.h"
+#endif
+#include <sys/sysctl.h>
+#include <sys/uio.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mpsutil.h"
+
+#ifndef USE_MPT_IOCTLS
+#define USE_MPT_IOCTLS
+#endif
+
+static const char *mps_ioc_status_codes[] = {
+ "Success", /* 0x0000 */
+ "Invalid function",
+ "Busy",
+ "Invalid scatter-gather list",
+ "Internal error",
+ "Reserved",
+ "Insufficient resources",
+ "Invalid field",
+ "Invalid state", /* 0x0008 */
+ "Operation state not supported",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x0010 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x0018 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Invalid configuration action", /* 0x0020 */
+ "Invalid configuration type",
+ "Invalid configuration page",
+ "Invalid configuration data",
+ "No configuration defaults",
+ "Unable to commit configuration change",
+ NULL,
+ NULL,
+ NULL, /* 0x0028 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x0030 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x0038 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Recovered SCSI error", /* 0x0040 */
+ "Invalid SCSI bus",
+ "Invalid SCSI target ID",
+ "SCSI device not there",
+ "SCSI data overrun",
+ "SCSI data underrun",
+ "SCSI I/O error",
+ "SCSI protocol error",
+ "SCSI task terminated", /* 0x0048 */
+ "SCSI residual mismatch",
+ "SCSI task management failed",
+ "SCSI I/O controller terminated",
+ "SCSI external controller terminated",
+ "EEDP guard error",
+ "EEDP reference tag error",
+ "EEDP application tag error",
+ NULL, /* 0x0050 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x0058 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "SCSI target priority I/O", /* 0x0060 */
+ "Invalid SCSI target port",
+ "Invalid SCSI target I/O index",
+ "SCSI target aborted",
+ "No connection retryable",
+ "No connection",
+ "FC aborted",
+ "Invalid FC receive ID",
+ "FC did invalid", /* 0x0068 */
+ "FC node logged out",
+ "Transfer count mismatch",
+ "STS data not set",
+ "FC exchange canceled",
+ "Data offset error",
+ "Too much write data",
+ "IU too short",
+ "ACK NAK timeout", /* 0x0070 */
+ "NAK received",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x0078 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "LAN device not found", /* 0x0080 */
+ "LAN device failure",
+ "LAN transmit error",
+ "LAN transmit aborted",
+ "LAN receive error",
+ "LAN receive aborted",
+ "LAN partial packet",
+ "LAN canceled",
+ NULL, /* 0x0088 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "SAS SMP request failed", /* 0x0090 */
+ "SAS SMP data overrun",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Inband aborted", /* 0x0098 */
+ "No inband connection",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Diagnostic released", /* 0x00A0 */
+};
+
+struct mprs_pass_thru {
+ uint64_t PtrRequest;
+ uint64_t PtrReply;
+ uint64_t PtrData;
+ uint32_t RequestSize;
+ uint32_t ReplySize;
+ uint32_t DataSize;
+ uint32_t DataDirection;
+ uint64_t PtrDataOut;
+ uint32_t DataOutSize;
+ uint32_t Timeout;
+};
+
+struct mprs_btdh_mapping {
+ uint16_t TargetID;
+ uint16_t Bus;
+ uint16_t DevHandle;
+ uint16_t Reserved;
+};
+
+const char *
+mps_ioc_status(U16 IOCStatus)
+{
+ static char buffer[16];
+
+ IOCStatus &= MPI2_IOCSTATUS_MASK;
+ if (IOCStatus < sizeof(mps_ioc_status_codes) / sizeof(char *) &&
+ mps_ioc_status_codes[IOCStatus] != NULL)
+ return (mps_ioc_status_codes[IOCStatus]);
+ snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus);
+ return (buffer);
+}
+
+#ifdef USE_MPT_IOCTLS
+int
+mps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus, uint16_t *target)
+{
+ int error;
+ struct mprs_btdh_mapping map;
+
+ map.Bus = *bus;
+ map.TargetID = *target;
+ map.DevHandle = *devhandle;
+
+ if ((error = ioctl(fd, MPTIOCTL_BTDH_MAPPING, &map)) != 0) {
+ error = errno;
+ warn("Failed to map bus/target/device");
+ return (error);
+ }
+
+ *bus = map.Bus;
+ *target = map.TargetID;
+ *devhandle = map.DevHandle;
+
+ return (0);
+}
+
+int
+mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
+ MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
+{
+ MPI2_CONFIG_REQUEST req;
+ MPI2_CONFIG_REPLY reply;
+
+ bzero(&req, sizeof(req));
+ req.Function = MPI2_FUNCTION_CONFIG;
+ req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ req.Header.PageType = PageType;
+ req.Header.PageNumber = PageNumber;
+ req.PageAddress = PageAddress;
+
+ if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
+ NULL, 0, NULL, 0, 30))
+ return (errno);
+
+ if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
+ if (IOCStatus != NULL)
+ *IOCStatus = reply.IOCStatus;
+ return (EIO);
+ }
+ if (header == NULL)
+ return (EINVAL);
+ *header = reply.Header;
+ return (0);
+}
+
+int
+mps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber, U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *ExtPageLength, U16 *IOCStatus)
+{
+ MPI2_CONFIG_REQUEST req;
+ MPI2_CONFIG_REPLY reply;
+
+ bzero(&req, sizeof(req));
+ req.Function = MPI2_FUNCTION_CONFIG;
+ req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ req.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ req.ExtPageType = ExtPageType;
+ req.Header.PageNumber = PageNumber;
+ req.PageAddress = PageAddress;
+
+ if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
+ NULL, 0, NULL, 0, 30))
+ return (errno);
+
+ if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
+ if (IOCStatus != NULL)
+ *IOCStatus = reply.IOCStatus;
+ return (EIO);
+ }
+ if ((header == NULL) || (ExtPageLength == NULL))
+ return (EINVAL);
+ *header = reply.Header;
+ *ExtPageLength = reply.ExtPageLength;
+ return (0);
+}
+
+void *
+mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
+ U16 *IOCStatus)
+{
+ MPI2_CONFIG_REQUEST req;
+ MPI2_CONFIG_PAGE_HEADER header;
+ MPI2_CONFIG_REPLY reply;
+ void *buf;
+ int error, len;
+
+ bzero(&header, sizeof(header));
+ error = mps_read_config_page_header(fd, PageType, PageNumber,
+ PageAddress, &header, IOCStatus);
+ if (error) {
+ errno = error;
+ return (NULL);
+ }
+
+ bzero(&req, sizeof(req));
+ req.Function = MPI2_FUNCTION_CONFIG;
+ req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ req.PageAddress = PageAddress;
+ req.Header = header;
+ req.Header.PageLength = reply.Header.PageLength;
+ if (reply.Header.PageLength == 0)
+ req.Header.PageLength = 4;
+
+ len = req.Header.PageLength * 4;
+ buf = malloc(len);
+ if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
+ buf, len, NULL, 0, 30)) {
+ error = errno;
+ free(buf);
+ errno = error;
+ return (NULL);
+ }
+ if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
+ if (IOCStatus != NULL)
+ *IOCStatus = reply.IOCStatus;
+ else
+ warnx("Reading config page failed: 0x%x %s",
+ reply.IOCStatus, mps_ioc_status(reply.IOCStatus));
+ free(buf);
+ errno = EIO;
+ return (NULL);
+ }
+ return (buf);
+}
+
+void *
+mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
+ U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
+{
+ MPI2_CONFIG_REQUEST req;
+ MPI2_CONFIG_PAGE_HEADER header;
+ MPI2_CONFIG_REPLY reply;
+ U16 pagelen;
+ void *buf;
+ int error, len;
+
+ if (IOCStatus != NULL)
+ *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
+ bzero(&header, sizeof(header));
+ error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber,
+ PageAddress, &header, &pagelen, IOCStatus);
+ if (error) {
+ errno = error;
+ return (NULL);
+ }
+
+ bzero(&req, sizeof(req));
+ req.Function = MPI2_FUNCTION_CONFIG;
+ req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ req.PageAddress = PageAddress;
+ req.Header = header;
+ if (pagelen == 0)
+ pagelen = 4;
+ req.ExtPageLength = pagelen;
+ req.ExtPageType = ExtPageType;
+
+ len = pagelen * 4;
+ buf = malloc(len);
+ if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
+ buf, len, NULL, 0, 30)) {
+ error = errno;
+ free(buf);
+ errno = error;
+ return (NULL);
+ }
+ if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
+ if (IOCStatus != NULL)
+ *IOCStatus = reply.IOCStatus;
+ else
+ warnx("Reading extended config page failed: %s",
+ mps_ioc_status(reply.IOCStatus));
+ free(buf);
+ errno = EIO;
+ return (NULL);
+ }
+ return (buf);
+}
+
+int
+mps_firmware_send(int fd, unsigned char *fw, uint32_t len, bool bios)
+{
+ MPI2_FW_DOWNLOAD_REQUEST req;
+ MPI2_FW_DOWNLOAD_REPLY reply;
+
+ bzero(&req, sizeof(req));
+ bzero(&reply, sizeof(reply));
+ req.Function = MPI2_FUNCTION_FW_DOWNLOAD;
+ req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
+ req.TotalImageSize = len;
+ req.MsgFlags = MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT;
+
+ if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
+ fw, len, 0)) {
+ return (-1);
+ }
+ return (0);
+}
+
+int
+mps_firmware_get(int fd, unsigned char **firmware, bool bios)
+{
+ MPI2_FW_UPLOAD_REQUEST req;
+ MPI2_FW_UPLOAD_REPLY reply;
+ int size;
+
+ *firmware = NULL;
+ bzero(&req, sizeof(req));
+ bzero(&reply, sizeof(reply));
+ req.Function = MPI2_FUNCTION_FW_UPLOAD;
+ req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
+
+ if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
+ NULL, 0, 0)) {
+ return (-1);
+ }
+ if (reply.ActualImageSize == 0) {
+ return (-1);
+ }
+
+ size = reply.ActualImageSize;
+ *firmware = calloc(1, sizeof(unsigned char) * size);
+ if (*firmware == NULL) {
+ warn("calloc");
+ return (-1);
+ }
+ if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
+ *firmware, size, 0)) {
+ free(*firmware);
+ return (-1);
+ }
+
+ return (size);
+}
+
+#else
+
+int
+mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
+ MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
+{
+ struct mps_cfg_page_req req;
+
+ if (IOCStatus != NULL)
+ *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
+ if (header == NULL)
+ return (EINVAL);
+ bzero(&req, sizeof(req));
+ req.header.PageType = PageType;
+ req.header.PageNumber = PageNumber;
+ req.page_address = PageAddress;
+ if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0)
+ return (errno);
+ if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
+ if (IOCStatus != NULL)
+ *IOCStatus = req.ioc_status;
+ return (EIO);
+ }
+ bcopy(&req.header, header, sizeof(*header));
+ return (0);
+}
+
+void *
+mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
+ U16 *IOCStatus)
+{
+ struct mps_cfg_page_req req;
+ void *buf;
+ int error;
+
+ error = mps_read_config_page_header(fd, PageType, PageNumber,
+ PageAddress, &req.header, IOCStatus);
+ if (error) {
+ errno = error;
+ return (NULL);
+ }
+
+ if (req.header.PageLength == 0)
+ req.header.PageLength = 4;
+ req.len = req.header.PageLength * 4;
+ buf = malloc(req.len);
+ req.buf = buf;
+ bcopy(&req.header, buf, sizeof(req.header));
+ if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) {
+ error = errno;
+ free(buf);
+ errno = error;
+ return (NULL);
+ }
+ if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
+ if (IOCStatus != NULL)
+ *IOCStatus = req.ioc_status;
+ else
+ warnx("Reading config page failed: 0x%x %s",
+ req.ioc_status, mps_ioc_status(req.ioc_status));
+ free(buf);
+ errno = EIO;
+ return (NULL);
+ }
+ return (buf);
+}
+
+void *
+mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
+ U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
+{
+ struct mps_ext_cfg_page_req req;
+ void *buf;
+ int error;
+
+ if (IOCStatus != NULL)
+ *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
+ bzero(&req, sizeof(req));
+ req.header.PageVersion = PageVersion;
+ req.header.PageNumber = PageNumber;
+ req.header.ExtPageType = ExtPageType;
+ req.page_address = PageAddress;
+ if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0)
+ return (NULL);
+ if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
+ if (IOCStatus != NULL)
+ *IOCStatus = req.ioc_status;
+ else
+ warnx("Reading extended config page header failed: %s",
+ mps_ioc_status(req.ioc_status));
+ errno = EIO;
+ return (NULL);
+ }
+ req.len = req.header.ExtPageLength * 4;
+ buf = malloc(req.len);
+ req.buf = buf;
+ bcopy(&req.header, buf, sizeof(req.header));
+ if (ioctl(fd, MPSIO_READ_EXT_CFG_PAGE, &req) < 0) {
+ error = errno;
+ free(buf);
+ errno = error;
+ return (NULL);
+ }
+ if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
+ if (IOCStatus != NULL)
+ *IOCStatus = req.ioc_status;
+ else
+ warnx("Reading extended config page failed: %s",
+ mps_ioc_status(req.ioc_status));
+ free(buf);
+ errno = EIO;
+ return (NULL);
+ }
+ return (buf);
+}
+#endif
+
+int
+mps_open(int unit)
+{
+ char path[MAXPATHLEN];
+
+ snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit);
+ return (open(path, O_RDWR));
+}
+
+int
+mps_user_command(int fd, void *req, uint32_t req_len, void *reply,
+ uint32_t reply_len, void *buffer, int len, uint32_t flags)
+{
+ struct mps_usr_command cmd;
+
+ bzero(&cmd, sizeof(struct mps_usr_command));
+ cmd.req = req;
+ cmd.req_len = req_len;
+ cmd.rpl = reply;
+ cmd.rpl_len = reply_len;
+ cmd.buf = buffer;
+ cmd.len = len;
+ cmd.flags = flags;
+
+ if (ioctl(fd, is_mps ? MPSIO_MPS_COMMAND : MPRIO_MPR_COMMAND, &cmd) < 0)
+ return (errno);
+ return (0);
+}
+
+int
+mps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
+ uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
+ uint32_t dataout_len, uint32_t timeout)
+{
+ struct mprs_pass_thru pass;
+
+ pass.PtrRequest = (uint64_t)(uintptr_t)req;
+ pass.PtrReply = (uint64_t)(uintptr_t)reply;
+ pass.PtrData = (uint64_t)(uintptr_t)data_in;
+ pass.PtrDataOut = (uint64_t)(uintptr_t)data_out;
+ pass.RequestSize = req_len;
+ pass.ReplySize = reply_len;
+ pass.DataSize = datain_len;
+ pass.DataOutSize = dataout_len;
+ if (datain_len && dataout_len) {
+ if (is_mps) {
+ pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH;
+ } else {
+ pass.DataDirection = MPR_PASS_THRU_DIRECTION_BOTH;
+ }
+ } else if (datain_len) {
+ if (is_mps) {
+ pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ;
+ } else {
+ pass.DataDirection = MPR_PASS_THRU_DIRECTION_READ;
+ }
+ } else if (dataout_len) {
+ if (is_mps) {
+ pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE;
+ } else {
+ pass.DataDirection = MPR_PASS_THRU_DIRECTION_WRITE;
+ }
+ } else {
+ if (is_mps) {
+ pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE;
+ } else {
+ pass.DataDirection = MPR_PASS_THRU_DIRECTION_NONE;
+ }
+ }
+ pass.Timeout = timeout;
+
+ if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0)
+ return (errno);
+ return (0);
+}
+
+MPI2_IOC_FACTS_REPLY *
+mps_get_iocfacts(int fd)
+{
+ MPI2_IOC_FACTS_REPLY *facts;
+ MPI2_IOC_FACTS_REQUEST req;
+ int error;
+
+ facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY));
+ if (facts == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+
+ bzero(&req, sizeof(MPI2_IOC_FACTS_REQUEST));
+ req.Function = MPI2_FUNCTION_IOC_FACTS;
+
+#if 1
+ error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
+ facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, NULL, 0, 10);
+#else
+ error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
+ facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, 0);
+#endif
+ if (error) {
+ free(facts);
+ return (NULL);
+ }
+
+ if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) {
+ free(facts);
+ errno = EINVAL;
+ return (NULL);
+ }
+ return (facts);
+}
+
diff --git a/usr.sbin/mpsutil/mps_flash.c b/usr.sbin/mpsutil/mps_flash.c
new file mode 100644
index 0000000..e22f29c
--- /dev/null
+++ b/usr.sbin/mpsutil/mps_flash.c
@@ -0,0 +1,237 @@
+/*-
+ * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+
+#include <errno.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mpsutil.h"
+
+MPS_TABLE(top, flash);
+
+static int
+flash_save(int argc, char **argv)
+{
+ const char *firmware_file;
+ unsigned char *firmware_buffer = NULL;
+ int error, fd, size;
+ bool bios = false;
+ ssize_t written = 0, ret = 0;
+
+ if (argc < 2) {
+ warnx("missing argument: expecting 'firmware' or bios'");
+ return (EINVAL);
+ }
+
+ if (strcmp(argv[1], "bios") == 0) {
+ bios = true;
+ } else if (strcmp(argv[1], "firmware") != 0) {
+ warnx("Invalid argument '%s', expecting 'firmware' or 'bios'",
+ argv[1]);
+ }
+
+ if (argc > 4) {
+ warnx("save %s: extra arguments", argv[1]);
+ return (EINVAL);
+ }
+
+ firmware_file = argv[1];
+ if (argc == 3) {
+ firmware_file = argv[2];
+ }
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ return (error);
+ }
+
+ if ((size = mps_firmware_get(fd, &firmware_buffer, bios)) < 0) {
+ warnx("Fail to save %s", argv[1]);
+ return (1);
+ }
+
+ close(fd);
+ if (size > 0) {
+ fd = open(firmware_file, O_CREAT | O_TRUNC | O_RDWR, 0644);
+ if (fd <0) {
+ error = errno;
+ warn("open");
+ free(firmware_buffer);
+ return (error);
+ }
+ while (written != size) {
+ if ((ret = write(fd, firmware_buffer + written, size - written)) <0) {
+ error = errno;
+ warn("write");
+ free(firmware_buffer);
+ return (error);
+ }
+ written += ret;
+ }
+ close(fd);
+ }
+ free(firmware_buffer);
+ printf("%s successfully saved as %s\n", argv[1], firmware_file);
+ return (0);
+}
+
+MPS_COMMAND(flash, save, flash_save, "[firmware|bios] [file]",
+ "Save firmware/bios into a file");
+
+static int
+flash_update(int argc, char **argv)
+{
+ int error, fd;
+ unsigned char *mem = NULL;
+ struct stat st;
+ bool bios = false;
+ MPI2_FW_IMAGE_HEADER *fwheader;
+ MPI2_IOC_FACTS_REPLY *facts;
+
+ if (argc < 2) {
+ warnx("missing argument: expecting 'firmware' or bios'");
+ return (EINVAL);
+ }
+
+ if (strcmp(argv[1], "bios") == 0) {
+ bios = true;
+ } else if (strcmp(argv[1], "firmware") != 0) {
+ warnx("Invalid argument '%s', expecting 'firmware' or 'bios'",
+ argv[1]);
+ }
+
+ if (argc > 4) {
+ warnx("update firmware: extra arguments");
+ return (EINVAL);
+ }
+
+ if (argc != 3) {
+ warnx("no firmware specified");
+ return (EINVAL);
+ }
+
+ if (stat(argv[2], &st) == -1) {
+ error = errno;
+ warn("stat");
+ return (error);
+ }
+
+ fd = open(argv[2], O_RDONLY);
+ if (fd < 0) {
+ error = errno;
+ warn("open");
+ return (error);
+ }
+
+ mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (mem == MAP_FAILED) {
+ error = errno;
+ warn("mmap");
+ close(fd);
+ return (error);
+ }
+ close(fd);
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ munmap(mem, st.st_size);
+ return (error);
+ }
+
+ if ((facts = mps_get_iocfacts(fd)) == NULL) {
+ warnx("could not get controller IOCFacts\n");
+ munmap(mem, st.st_size);
+ close(fd);
+ return (EINVAL);
+ }
+
+ if (bios) {
+ /* Check boot record magic number */
+ if (((mem[0x01]<<8) + mem[0x00]) != 0xaa55) {
+ warnx("Invalid bios: no boot record magic number");
+ munmap(mem, st.st_size);
+ close(fd);
+ return (1);
+ }
+ if ((st.st_size % 512) != 0) {
+ warnx("Invalid bios: size not a multiple of 512");
+ munmap(mem, st.st_size);
+ close(fd);
+ return (1);
+ }
+ } else {
+ fwheader = (MPI2_FW_IMAGE_HEADER *)mem;
+ if (fwheader->VendorID != MPI2_MFGPAGE_VENDORID_LSI) {
+ warnx("Invalid firmware:");
+ warnx(" Expected Vendor ID: %04x",
+ MPI2_MFGPAGE_VENDORID_LSI);
+ warnx(" Image Vendor ID: %04x", fwheader->VendorID);
+ munmap(mem, st.st_size);
+ close(fd);
+ return (1);
+ }
+
+ if (fwheader->ProductID != facts->ProductID) {
+ warnx("Invalid image:");
+ warnx(" Expected Product ID: %04x", facts->ProductID);
+ warnx(" Image Product ID: %04x", fwheader->ProductID);
+ munmap(mem, st.st_size);
+ close(fd);
+ return (1);
+ }
+ }
+
+ printf("Updating %s...\n", argv[1]);
+ if (mps_firmware_send(fd, mem, st.st_size, bios) < 0) {
+ warnx("Fail to update %s", argv[1]);
+ munmap(mem, st.st_size);
+ close(fd);
+ return (1);
+ }
+
+ munmap(mem, st.st_size);
+ close(fd);
+ printf("%s successfully updated\n", argv[1]);
+ return (0);
+}
+
+MPS_COMMAND(flash, update, flash_update, "[firmware|bios] file",
+ "Update firmware/bios");
diff --git a/usr.sbin/mpsutil/mps_ioctl.h b/usr.sbin/mpsutil/mps_ioctl.h
new file mode 100644
index 0000000..a52f80e
--- /dev/null
+++ b/usr.sbin/mpsutil/mps_ioctl.h
@@ -0,0 +1,387 @@
+/*-
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * 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.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD userland interface
+ *
+ * $FreeBSD$
+ */
+/*-
+ * Copyright (c) 2011, 2012 LSI Corp.
+ * 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.
+ *
+ * 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.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MPS_IOCTL_H_
+#define _MPS_IOCTL_H_
+
+#include <dev/mps/mpi/mpi2_type.h>
+#include <dev/mps/mpi/mpi2.h>
+#include <dev/mps/mpi/mpi2_cnfg.h>
+#include <dev/mps/mpi/mpi2_sas.h>
+
+/*
+ * For the read header requests, the header should include the page
+ * type or extended page type, page number, and page version. The
+ * buffer and length are unused. The completed header is returned in
+ * the 'header' member.
+ *
+ * For the read page and write page requests, 'buf' should point to a
+ * buffer of 'len' bytes which holds the entire page (including the
+ * header).
+ *
+ * All requests specify the page address in 'page_address'.
+ */
+struct mps_cfg_page_req {
+ MPI2_CONFIG_PAGE_HEADER header;
+ uint32_t page_address;
+ void *buf;
+ int len;
+ uint16_t ioc_status;
+};
+
+struct mps_ext_cfg_page_req {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER header;
+ uint32_t page_address;
+ void *buf;
+ int len;
+ uint16_t ioc_status;
+};
+
+struct mps_raid_action {
+ uint8_t action;
+ uint8_t volume_bus;
+ uint8_t volume_id;
+ uint8_t phys_disk_num;
+ uint32_t action_data_word;
+ void *buf;
+ int len;
+ uint32_t volume_status;
+ uint32_t action_data[4];
+ uint16_t action_status;
+ uint16_t ioc_status;
+ uint8_t write;
+};
+
+struct mps_usr_command {
+ void *req;
+ uint32_t req_len;
+ void *rpl;
+ uint32_t rpl_len;
+ void *buf;
+ int len;
+ uint32_t flags;
+};
+
+typedef struct mps_pci_bits
+{
+ union {
+ struct {
+ uint32_t DeviceNumber :5;
+ uint32_t FunctionNumber :3;
+ uint32_t BusNumber :24;
+ } bits;
+ uint32_t AsDWORD;
+ } u;
+ uint32_t PciSegmentId;
+} mps_pci_bits_t;
+
+/*
+ * The following is the MPSIOCTL_GET_ADAPTER_DATA data structure. This data
+ * structure is setup so that we hopefully are properly aligned for both
+ * 32-bit and 64-bit mode applications.
+ *
+ * Adapter Type - Value = 4 = SCSI Protocol through SAS-2 adapter
+ *
+ * MPI Port Number - The PCI Function number for this device
+ *
+ * PCI Device HW Id - The PCI device number for this device
+ *
+ */
+#define MPSIOCTL_ADAPTER_TYPE_SAS2 4
+#define MPSIOCTL_ADAPTER_TYPE_SAS2_SSS6200 5
+typedef struct mps_adapter_data
+{
+ uint32_t StructureLength;
+ uint32_t AdapterType;
+ uint32_t MpiPortNumber;
+ uint32_t PCIDeviceHwId;
+ uint32_t PCIDeviceHwRev;
+ uint32_t SubSystemId;
+ uint32_t SubsystemVendorId;
+ uint32_t Reserved1;
+ uint32_t MpiFirmwareVersion;
+ uint32_t BiosVersion;
+ uint8_t DriverVersion[32];
+ uint8_t Reserved2;
+ uint8_t ScsiId;
+ uint16_t Reserved3;
+ mps_pci_bits_t PciInformation;
+} mps_adapter_data_t;
+
+
+typedef struct mps_update_flash
+{
+ uint64_t PtrBuffer;
+ uint32_t ImageChecksum;
+ uint32_t ImageOffset;
+ uint32_t ImageSize;
+ uint32_t ImageType;
+} mps_update_flash_t;
+
+
+#define MPS_PASS_THRU_DIRECTION_NONE 0
+#define MPS_PASS_THRU_DIRECTION_READ 1
+#define MPS_PASS_THRU_DIRECTION_WRITE 2
+#define MPS_PASS_THRU_DIRECTION_BOTH 3
+
+typedef struct mps_pass_thru
+{
+ uint64_t PtrRequest;
+ uint64_t PtrReply;
+ uint64_t PtrData;
+ uint32_t RequestSize;
+ uint32_t ReplySize;
+ uint32_t DataSize;
+ uint32_t DataDirection;
+ uint64_t PtrDataOut;
+ uint32_t DataOutSize;
+ uint32_t Timeout;
+} mps_pass_thru_t;
+
+
+/*
+ * Event queue defines
+ */
+#define MPS_EVENT_QUEUE_SIZE (50) /* Max Events stored in driver */
+#define MPS_MAX_EVENT_DATA_LENGTH (48) /* Size of each event in Dwords */
+
+typedef struct mps_event_query
+{
+ uint16_t Entries;
+ uint16_t Reserved;
+ uint32_t Types[4];
+} mps_event_query_t;
+
+typedef struct mps_event_enable
+{
+ uint32_t Types[4];
+} mps_event_enable_t;
+
+/*
+ * Event record entry for ioctl.
+ */
+typedef struct mps_event_entry
+{
+ uint32_t Type;
+ uint32_t Number;
+ uint32_t Data[MPS_MAX_EVENT_DATA_LENGTH];
+} mps_event_entry_t;
+
+typedef struct mps_event_report
+{
+ uint32_t Size;
+ uint64_t PtrEvents;
+} mps_event_report_t;
+
+
+typedef struct mps_pci_info
+{
+ uint32_t BusNumber;
+ uint8_t DeviceNumber;
+ uint8_t FunctionNumber;
+ uint16_t InterruptVector;
+ uint8_t PciHeader[256];
+} mps_pci_info_t;
+
+
+typedef struct mps_diag_action
+{
+ uint32_t Action;
+ uint32_t Length;
+ uint64_t PtrDiagAction;
+ uint32_t ReturnCode;
+} mps_diag_action_t;
+
+#define MPS_FW_DIAGNOSTIC_UID_NOT_FOUND (0xFF)
+
+#define MPS_FW_DIAG_NEW (0x806E6577)
+
+#define MPS_FW_DIAG_TYPE_REGISTER (0x00000001)
+#define MPS_FW_DIAG_TYPE_UNREGISTER (0x00000002)
+#define MPS_FW_DIAG_TYPE_QUERY (0x00000003)
+#define MPS_FW_DIAG_TYPE_READ_BUFFER (0x00000004)
+#define MPS_FW_DIAG_TYPE_RELEASE (0x00000005)
+
+#define MPS_FW_DIAG_INVALID_UID (0x00000000)
+
+#define MPS_DIAG_SUCCESS 0
+#define MPS_DIAG_FAILURE 1
+
+#define MPS_FW_DIAG_ERROR_SUCCESS (0x00000000)
+#define MPS_FW_DIAG_ERROR_FAILURE (0x00000001)
+#define MPS_FW_DIAG_ERROR_INVALID_PARAMETER (0x00000002)
+#define MPS_FW_DIAG_ERROR_POST_FAILED (0x00000010)
+#define MPS_FW_DIAG_ERROR_INVALID_UID (0x00000011)
+#define MPS_FW_DIAG_ERROR_RELEASE_FAILED (0x00000012)
+#define MPS_FW_DIAG_ERROR_NO_BUFFER (0x00000013)
+#define MPS_FW_DIAG_ERROR_ALREADY_RELEASED (0x00000014)
+
+
+typedef struct mps_fw_diag_register
+{
+ uint8_t ExtendedType;
+ uint8_t BufferType;
+ uint16_t ApplicationFlags;
+ uint32_t DiagnosticFlags;
+ uint32_t ProductSpecific[23];
+ uint32_t RequestedBufferSize;
+ uint32_t UniqueId;
+} mps_fw_diag_register_t;
+
+typedef struct mps_fw_diag_unregister
+{
+ uint32_t UniqueId;
+} mps_fw_diag_unregister_t;
+
+#define MPS_FW_DIAG_FLAG_APP_OWNED (0x0001)
+#define MPS_FW_DIAG_FLAG_BUFFER_VALID (0x0002)
+#define MPS_FW_DIAG_FLAG_FW_BUFFER_ACCESS (0x0004)
+
+typedef struct mps_fw_diag_query
+{
+ uint8_t ExtendedType;
+ uint8_t BufferType;
+ uint16_t ApplicationFlags;
+ uint32_t DiagnosticFlags;
+ uint32_t ProductSpecific[23];
+ uint32_t TotalBufferSize;
+ uint32_t DriverAddedBufferSize;
+ uint32_t UniqueId;
+} mps_fw_diag_query_t;
+
+typedef struct mps_fw_diag_release
+{
+ uint32_t UniqueId;
+} mps_fw_diag_release_t;
+
+#define MPS_FW_DIAG_FLAG_REREGISTER (0x0001)
+#define MPS_FW_DIAG_FLAG_FORCE_RELEASE (0x0002)
+
+typedef struct mps_diag_read_buffer
+{
+ uint8_t Status;
+ uint8_t Reserved;
+ uint16_t Flags;
+ uint32_t StartingOffset;
+ uint32_t BytesToRead;
+ uint32_t UniqueId;
+ uint64_t PtrDataBuffer;
+} mps_diag_read_buffer_t;
+
+/*
+ * Register Access
+ */
+#define REG_IO_READ 1
+#define REG_IO_WRITE 2
+#define REG_MEM_READ 3
+#define REG_MEM_WRITE 4
+
+typedef struct mps_reg_access
+{
+ uint32_t Command;
+ uint32_t RegOffset;
+ uint32_t RegData;
+} mps_reg_access_t;
+
+typedef struct mps_btdh_mapping
+{
+ uint16_t TargetID;
+ uint16_t Bus;
+ uint16_t DevHandle;
+ uint16_t Reserved;
+} mps_btdh_mapping_t;
+
+#define MPSIO_MPS_COMMAND_FLAG_VERBOSE 0x01
+#define MPSIO_MPS_COMMAND_FLAG_DEBUG 0x02
+#define MPSIO_READ_CFG_HEADER _IOWR('M', 200, struct mps_cfg_page_req)
+#define MPSIO_READ_CFG_PAGE _IOWR('M', 201, struct mps_cfg_page_req)
+#define MPSIO_READ_EXT_CFG_HEADER _IOWR('M', 202, struct mps_ext_cfg_page_req)
+#define MPSIO_READ_EXT_CFG_PAGE _IOWR('M', 203, struct mps_ext_cfg_page_req)
+#define MPSIO_WRITE_CFG_PAGE _IOWR('M', 204, struct mps_cfg_page_req)
+#define MPSIO_RAID_ACTION _IOWR('M', 205, struct mps_raid_action)
+#define MPSIO_MPS_COMMAND _IOWR('M', 210, struct mps_usr_command)
+
+#define MPTIOCTL ('I')
+#define MPTIOCTL_GET_ADAPTER_DATA _IOWR(MPTIOCTL, 1,\
+ struct mps_adapter_data)
+#define MPTIOCTL_UPDATE_FLASH _IOWR(MPTIOCTL, 2,\
+ struct mps_update_flash)
+#define MPTIOCTL_RESET_ADAPTER _IO(MPTIOCTL, 3)
+#define MPTIOCTL_PASS_THRU _IOWR(MPTIOCTL, 4,\
+ struct mps_pass_thru)
+#define MPTIOCTL_EVENT_QUERY _IOWR(MPTIOCTL, 5,\
+ struct mps_event_query)
+#define MPTIOCTL_EVENT_ENABLE _IOWR(MPTIOCTL, 6,\
+ struct mps_event_enable)
+#define MPTIOCTL_EVENT_REPORT _IOWR(MPTIOCTL, 7,\
+ struct mps_event_report)
+#define MPTIOCTL_GET_PCI_INFO _IOWR(MPTIOCTL, 8,\
+ struct mps_pci_info)
+#define MPTIOCTL_DIAG_ACTION _IOWR(MPTIOCTL, 9,\
+ struct mps_diag_action)
+#define MPTIOCTL_REG_ACCESS _IOWR(MPTIOCTL, 10,\
+ struct mps_reg_access)
+#define MPTIOCTL_BTDH_MAPPING _IOWR(MPTIOCTL, 11,\
+ struct mps_btdh_mapping)
+
+#endif /* !_MPS_IOCTL_H_ */
diff --git a/usr.sbin/mpsutil/mps_show.c b/usr.sbin/mpsutil/mps_show.c
new file mode 100644
index 0000000..d6a7840
--- /dev/null
+++ b/usr.sbin/mpsutil/mps_show.c
@@ -0,0 +1,772 @@
+/*-
+ * Copyright (c) 2015 Netflix, Inc.
+ * All rights reserved.
+ * Written by: Scott Long <scottl@freebsd.org>
+ *
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <err.h>
+#include <libutil.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "mpsutil.h"
+
+static char * get_device_speed(uint8_t rate);
+static char * get_device_type(uint32_t di);
+static int show_all(int ac, char **av);
+static int show_devices(int ac, char **av);
+static int show_enclosures(int ac, char **av);
+static int show_expanders(int ac, char **av);
+
+MPS_TABLE(top, show);
+
+#define STANDALONE_STATE "ONLINE"
+
+static int
+show_adapter(int ac, char **av)
+{
+ MPI2_CONFIG_PAGE_SASIOUNIT_0 *sas0;
+ MPI2_CONFIG_PAGE_SASIOUNIT_1 *sas1;
+ MPI2_SAS_IO_UNIT0_PHY_DATA *phy0;
+ MPI2_SAS_IO_UNIT1_PHY_DATA *phy1;
+ MPI2_CONFIG_PAGE_MAN_0 *man0;
+ MPI2_CONFIG_PAGE_BIOS_3 *bios3;
+ MPI2_IOC_FACTS_REPLY *facts;
+ U16 IOCStatus;
+ char *speed, *minspeed, *maxspeed, *isdisabled, *type;
+ char devhandle[5], ctrlhandle[5];
+ int error, fd, v, i;
+
+ if (ac != 1) {
+ warnx("show adapter: extra arguments");
+ return (EINVAL);
+ }
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ return (error);
+ }
+
+ man0 = mps_read_man_page(fd, 0, NULL);
+ if (man0 == NULL) {
+ error = errno;
+ warn("Failed to get controller info");
+ return (error);
+ }
+ if (man0->Header.PageLength < sizeof(*man0) / 4) {
+ warnx("Invalid controller info");
+ return (EINVAL);
+ }
+ printf("mp%s%d Adapter:\n", is_mps ? "s": "r", mps_unit);
+ printf(" Board Name: %.16s\n", man0->BoardName);
+ printf(" Board Assembly: %.16s\n", man0->BoardAssembly);
+ printf(" Chip Name: %.16s\n", man0->ChipName);
+ printf(" Chip Revision: %.16s\n", man0->ChipRevision);
+ free(man0);
+
+ bios3 = mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_BIOS, 3, 0, NULL);
+ if (bios3 == NULL) {
+ error = errno;
+ warn("Failed to get BIOS page 3 info");
+ return (error);
+ }
+ v = bios3->BiosVersion;
+ printf(" BIOS Revision: %d.%02d.%02d.%02d\n",
+ ((v & 0xff000000) >> 24), ((v &0xff0000) >> 16),
+ ((v & 0xff00) >> 8), (v & 0xff));
+ free(bios3);
+
+ if ((facts = mps_get_iocfacts(fd)) == NULL) {
+ printf("could not get controller IOCFacts\n");
+ close(fd);
+ return (errno);
+ }
+ v = facts->FWVersion.Word;
+ printf("Firmware Revision: %d.%02d.%02d.%02d\n",
+ ((v & 0xff000000) >> 24), ((v &0xff0000) >> 16),
+ ((v & 0xff00) >> 8), (v & 0xff));
+ printf(" Integrated RAID: %s\n",
+ (facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)
+ ? "yes" : "no");
+ free(facts);
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ return (error);
+ }
+
+ sas0 = mps_read_extended_config_page(fd,
+ MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
+ MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus);
+ if (sas0 == NULL) {
+ error = errno;
+ warn("Error retrieving SAS IO Unit page %d", IOCStatus);
+ return (error);
+ }
+
+ sas1 = mps_read_extended_config_page(fd,
+ MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
+ MPI2_SASIOUNITPAGE1_PAGEVERSION, 1, 0, &IOCStatus);
+ if (sas0 == NULL) {
+ error = errno;
+ warn("Error retrieving SAS IO Unit page %d", IOCStatus);
+ return (error);
+ }
+ printf("\n");
+
+ printf("%-8s%-12s%-11s%-10s%-8s%-7s%-7s%s\n", "PhyNum", "CtlrHandle",
+ "DevHandle", "Disabled", "Speed", "Min", "Max", "Device");
+ for (i = 0; i < sas0->NumPhys; i++) {
+ phy0 = &sas0->PhyData[i];
+ phy1 = &sas1->PhyData[i];
+ if (phy0->PortFlags &
+ MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) {
+ printf("Discovery still in progress\n");
+ continue;
+ }
+ if (phy0->PhyFlags & MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED)
+ isdisabled = "Y";
+ else
+ isdisabled = "N";
+
+ minspeed = get_device_speed(phy1->MaxMinLinkRate);
+ maxspeed = get_device_speed(phy1->MaxMinLinkRate >> 4);
+ type = get_device_type(phy0->ControllerPhyDeviceInfo);
+
+ if (phy0->AttachedDevHandle != 0) {
+ snprintf(devhandle, 5, "%04x", phy0->AttachedDevHandle);
+ snprintf(ctrlhandle, 5, "%04x",
+ phy0->ControllerDevHandle);
+ speed = get_device_speed(phy0->NegotiatedLinkRate);
+ } else {
+ snprintf(devhandle, 5, " ");
+ snprintf(ctrlhandle, 5, " ");
+ speed = " ";
+ }
+ printf("%-8d%-12s%-11s%-10s%-8s%-7s%-7s%s\n",
+ i, ctrlhandle, devhandle, isdisabled, speed, minspeed,
+ maxspeed, type);
+ }
+ free(sas0);
+ free(sas1);
+ printf("\n");
+ close(fd);
+ return (0);
+}
+
+MPS_COMMAND(show, adapter, show_adapter, "", "display controller information")
+
+static int
+show_iocfacts(int ac, char **av)
+{
+ MPI2_IOC_FACTS_REPLY *facts;
+ int error, fd;
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ return (error);
+ }
+
+ if ((facts = mps_get_iocfacts(fd)) == NULL) {
+ printf("could not get controller IOCFacts\n");
+ close(fd);
+ return (errno);
+ }
+
+ printf(" MaxChainDepth: %d\n", facts->MaxChainDepth);
+ printf(" WhoInit: 0x%x\n", facts->WhoInit);
+ printf(" NumberOfPorts: %d\n", facts->NumberOfPorts);
+ printf(" MaxMSIxVectors: %d\n", facts->MaxMSIxVectors);
+ printf(" RequestCredit: %d\n", facts->RequestCredit);
+ printf(" ProductID: 0x%x\n", facts->ProductID);
+ printf(" IOCCapabilities: 0x%x\n", facts->IOCCapabilities);
+ printf(" FWVersion: 0x%08x\n", facts->FWVersion.Word);
+ printf(" IOCRequestFrameSize: %d\n", facts->IOCRequestFrameSize);
+ printf(" MaxInitiators: %d\n", facts->MaxInitiators);
+ printf(" MaxTargets: %d\n", facts->MaxTargets);
+ printf(" MaxSasExpanders: %d\n", facts->MaxSasExpanders);
+ printf(" MaxEnclosures: %d\n", facts->MaxEnclosures);
+ printf(" ProtocolFlags: 0x%x\n", facts->ProtocolFlags);
+ printf(" HighPriorityCredit: %d\n", facts->HighPriorityCredit);
+ printf("MaxRepDescPostQDepth: %d\n",
+ facts->MaxReplyDescriptorPostQueueDepth);
+ printf(" ReplyFrameSize: %d\n", facts->ReplyFrameSize);
+ printf(" MaxVolumes: %d\n", facts->MaxVolumes);
+ printf(" MaxDevHandle: %d\n", facts->MaxDevHandle);
+ printf("MaxPersistentEntries: %d\n", facts->MaxPersistentEntries);
+ printf(" MinDevHandle: %d\n", facts->MinDevHandle);
+
+ free(facts);
+ return (0);
+}
+
+MPS_COMMAND(show, iocfacts, show_iocfacts, "", "Show IOC Facts Message");
+
+static int
+show_adapters(int ac, char **av)
+{
+ MPI2_CONFIG_PAGE_MAN_0 *man0;
+ MPI2_IOC_FACTS_REPLY *facts;
+ int unit, fd, error;
+
+ printf("Device Name\t Chip Name Board Name Firmware\n");
+ for (unit = 0; unit < MPS_MAX_UNIT; unit++) {
+ fd = mps_open(unit);
+ if (fd < 0)
+ continue;
+ facts = mps_get_iocfacts(fd);
+ if (facts == NULL) {
+ error = errno;
+ warn("Faled to get controller iocfacts");
+ close(fd);
+ return (error);
+ }
+ man0 = mps_read_man_page(fd, 0, NULL);
+ if (man0 == NULL) {
+ error = errno;
+ warn("Failed to get controller info");
+ close(fd);
+ return (error);
+ }
+ if (man0->Header.PageLength < sizeof(*man0) / 4) {
+ warnx("Invalid controller info");
+ close(fd);
+ free(man0);
+ return (EINVAL);
+ }
+ printf("/dev/mp%s%d\t%16s %16s %08x\n",
+ is_mps ? "s": "r", unit,
+ man0->ChipName, man0->BoardName, facts->FWVersion.Word);
+ free(man0);
+ free(facts);
+ close(fd);
+ }
+ return (0);
+}
+MPS_COMMAND(show, adapters, show_adapters, "", "Show a summary of all adapters");
+
+static char *
+get_device_type(uint32_t di)
+{
+
+ if (di & 0x4000)
+ return ("SEP Target ");
+ if (di & 0x2000)
+ return ("ATAPI Target ");
+ if (di & 0x400)
+ return ("SAS Target ");
+ if (di & 0x200)
+ return ("STP Target ");
+ if (di & 0x100)
+ return ("SMP Target ");
+ if (di & 0x80)
+ return ("SATA Target ");
+ if (di & 0x70)
+ return ("SAS Initiator ");
+ if (di & 0x8)
+ return ("SATA Initiator");
+ if ((di & 0x7) == 0)
+ return ("No Device ");
+ return ("Unknown Device");
+}
+
+static char *
+get_enc_type(uint32_t flags, int *issep)
+{
+ char *type;
+
+ *issep = 0;
+ switch (flags & 0xf) {
+ case 0x01:
+ type = "Direct Attached SES-2";
+ *issep = 1;
+ break;
+ case 0x02:
+ type = "Direct Attached SGPIO";
+ break;
+ case 0x03:
+ type = "Expander SGPIO";
+ break;
+ case 0x04:
+ type = "External SES-2";
+ *issep = 1;
+ break;
+ case 0x05:
+ type = "Direct Attached GPIO";
+ break;
+ case 0x0:
+ default:
+ return ("Unknown");
+ }
+
+ return (type);
+}
+
+static char *
+mps_device_speed[] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "1.5",
+ "3.0",
+ "6.0",
+ "12 "
+};
+
+static char *
+get_device_speed(uint8_t rate)
+{
+ char *speed;
+
+ rate &= 0xf;
+ if (rate >= sizeof(mps_device_speed))
+ return ("Unk");
+
+ if ((speed = mps_device_speed[rate]) == NULL)
+ return ("???");
+ return (speed);
+}
+
+static char *
+mps_page_name[] = {
+ "IO Unit",
+ "IOC",
+ "BIOS",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "RAID Volume",
+ "Manufacturing",
+ "RAID Physical Disk",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "SAS IO Unit",
+ "SAS Expander",
+ "SAS Device",
+ "SAS PHY",
+ "Log",
+ "Enclosure",
+ "RAID Configuration",
+ "Driver Persistent Mapping",
+ "SAS Port",
+ "Ethernet Port",
+ "Extended Manufacturing"
+};
+
+static char *
+get_page_name(u_int page)
+{
+ char *name;
+
+ if (page >= sizeof(mps_page_name))
+ return ("Unknown");
+ if ((name = mps_page_name[page]) == NULL)
+ return ("Unknown");
+ return (name);
+}
+
+static int
+show_all(int ac, char **av)
+{
+ int error;
+
+ printf("Adapter:\n");
+ error = show_adapter(ac, av);
+ printf("Devices:\n");
+ error = show_devices(ac, av);
+ printf("Enclosures:\n");
+ error = show_enclosures(ac, av);
+ printf("Expanders:\n");
+ error = show_expanders(ac, av);
+ return (error);
+}
+MPS_COMMAND(show, all, show_all, "", "Show all devices");
+
+static int
+show_devices(int ac, char **av)
+{
+ MPI2_CONFIG_PAGE_SASIOUNIT_0 *sas0;
+ MPI2_SAS_IO_UNIT0_PHY_DATA *phydata;
+ MPI2_CONFIG_PAGE_SAS_DEV_0 *device;
+ MPI2_CONFIG_PAGE_EXPANDER_1 *exp1;
+ uint16_t IOCStatus, handle, bus, target;
+ char *type, *speed, enchandle[5], slot[3], bt[8];
+ char buf[256];
+ int fd, error, nphys;
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ return (error);
+ }
+
+ sas0 = mps_read_extended_config_page(fd,
+ MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
+ MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus);
+ if (sas0 == NULL) {
+ error = errno;
+ warn("Error retrieving SAS IO Unit page %d", IOCStatus);
+ return (error);
+ }
+ nphys = sas0->NumPhys;
+
+ printf("B____%-5s%-17s%-8s%-10s%-14s%-6s%-5s%-6s%s\n",
+ "T", "SAS Address", "Handle", "Parent", "Device", "Speed",
+ "Enc", "Slot", "Wdt");
+ handle = 0xffff;
+ while (1) {
+ device = mps_read_extended_config_page(fd,
+ MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE,
+ MPI2_SASDEVICE0_PAGEVERSION, 0,
+ MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE | handle,
+ &IOCStatus);
+ if (device == NULL) {
+ if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ break;
+ error = errno;
+ warn("Error retrieving device page");
+ return (error);
+ }
+ handle = device->DevHandle;
+
+ if (device->ParentDevHandle == 0x0) {
+ free(device);
+ continue;
+ }
+
+ bus = 0xffff;
+ target = 0xffff;
+ error = mps_map_btdh(fd, &handle, &bus, &target);
+ if (error) {
+ free(device);
+ continue;
+ }
+ if ((bus == 0xffff) || (target == 0xffff))
+ snprintf(bt, sizeof(bt), " ");
+ else
+ snprintf(bt, sizeof(bt), "%02d %02d", bus, target);
+
+ type = get_device_type(device->DeviceInfo);
+
+ if (device->PhyNum < nphys) {
+ phydata = &sas0->PhyData[device->PhyNum];
+ speed = get_device_speed(phydata->NegotiatedLinkRate);
+ } else if (device->ParentDevHandle > 0) {
+ exp1 = mps_read_extended_config_page(fd,
+ MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
+ MPI2_SASEXPANDER1_PAGEVERSION, 1,
+ MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
+ (device->PhyNum <<
+ MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
+ device->ParentDevHandle, &IOCStatus);
+ if (exp1 == NULL) {
+ if (IOCStatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
+ error = errno;
+ warn("Error retrieving expander page 1: 0x%x",
+ IOCStatus);
+ return (error);
+ }
+ speed = " ";
+ } else {
+ speed = get_device_speed(exp1->NegotiatedLinkRate);
+ free(exp1);
+ }
+ } else
+ speed = " ";
+
+ if (device->EnclosureHandle != 0) {
+ snprintf(enchandle, 5, "%04x", device->EnclosureHandle);
+ snprintf(slot, 3, "%02d", device->Slot);
+ } else {
+ snprintf(enchandle, 5, " ");
+ snprintf(slot, 3, " ");
+ }
+ printf("%-10s", bt);
+ snprintf(buf, sizeof(buf), "%08x%08x", device->SASAddress.High,
+ device->SASAddress.Low);
+ printf("%-17s", buf);
+ snprintf(buf, sizeof(buf), "%04x", device->DevHandle);
+ printf("%-8s", buf);
+ snprintf(buf, sizeof(buf), "%04x", device->ParentDevHandle);
+ printf("%-10s", buf);
+ printf("%-14s%-6s%-5s%-6s%d\n", type, speed,
+ enchandle, slot, device->MaxPortConnections);
+ free(device);
+ }
+ printf("\n");
+ free(sas0);
+ close(fd);
+ return (0);
+}
+MPS_COMMAND(show, devices, show_devices, "", "Show attached devices");
+
+static int
+show_enclosures(int ac, char **av)
+{
+ MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 *enc;
+ char *type, sepstr[5];
+ uint16_t IOCStatus, handle;
+ int fd, error, issep;
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ return (error);
+ }
+
+ printf("Slots Logical ID SEPHandle EncHandle Type\n");
+ handle = 0xffff;
+ while (1) {
+ enc = mps_read_extended_config_page(fd,
+ MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE,
+ MPI2_SASENCLOSURE0_PAGEVERSION, 0,
+ MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE | handle,
+ &IOCStatus);
+ if (enc == NULL) {
+ if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ break;
+ error = errno;
+ warn("Error retrieving enclosure page");
+ return (error);
+ }
+ type = get_enc_type(enc->Flags, &issep);
+ if (issep == 0)
+ snprintf(sepstr, 5, " ");
+ else
+ snprintf(sepstr, 5, "%04x", enc->SEPDevHandle);
+ printf(" %.2d %08x%08x %s %04x %s\n",
+ enc->NumSlots, enc->EnclosureLogicalID.High,
+ enc->EnclosureLogicalID.Low, sepstr, enc->EnclosureHandle,
+ type);
+ handle = enc->EnclosureHandle;
+ free(enc);
+ }
+ printf("\n");
+ close(fd);
+ return (0);
+}
+MPS_COMMAND(show, enclosures, show_enclosures, "", "Show attached enclosures");
+
+static int
+show_expanders(int ac, char **av)
+{
+ MPI2_CONFIG_PAGE_EXPANDER_0 *exp0;
+ MPI2_CONFIG_PAGE_EXPANDER_1 *exp1;
+ uint16_t IOCStatus, handle;
+ char enchandle[5], parent[5], rphy[3], rhandle[5];
+ char *speed, *min, *max, *type;
+ int fd, error, nphys, i;
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ return (error);
+ }
+
+ printf("NumPhys SAS Address DevHandle Parent EncHandle SAS Level\n");
+ handle = 0xffff;
+ while (1) {
+ exp0 = mps_read_extended_config_page(fd,
+ MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
+ MPI2_SASEXPANDER0_PAGEVERSION, 0,
+ MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL | handle,
+ &IOCStatus);
+ if (exp0 == NULL) {
+ if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ break;
+ error = errno;
+ warn("Error retrieving expander page 0");
+ return (error);
+ }
+
+ nphys = exp0->NumPhys;
+ handle = exp0->DevHandle;
+
+ if (exp0->EnclosureHandle == 0x00)
+ snprintf(enchandle, 5, " ");
+ else
+ snprintf(enchandle, 5, "%04d", exp0->EnclosureHandle);
+ if (exp0->ParentDevHandle == 0x0)
+ snprintf(parent, 5, " ");
+ else
+ snprintf(parent, 5, "%04x", exp0->ParentDevHandle);
+ printf(" %02d %08x%08x %04x %s %s %d\n",
+ exp0->NumPhys, exp0->SASAddress.High, exp0->SASAddress.Low,
+ exp0->DevHandle, parent, enchandle, exp0->SASLevel);
+
+ printf("\n");
+ printf(" Phy RemotePhy DevHandle Speed Min Max Device\n");
+ for (i = 0; i < nphys; i++) {
+ exp1 = mps_read_extended_config_page(fd,
+ MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
+ MPI2_SASEXPANDER1_PAGEVERSION, 1,
+ MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
+ (i << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
+ exp0->DevHandle, &IOCStatus);
+ if (exp1 == NULL) {
+ if (IOCStatus !=
+ MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ warn("Error retrieving expander pg 1");
+ continue;
+ }
+ type = get_device_type(exp1->AttachedDeviceInfo);
+ if ((exp1->AttachedDeviceInfo &0x7) == 0) {
+ speed = " ";
+ snprintf(rphy, 3, " ");
+ snprintf(rhandle, 5, " ");
+ } else {
+ speed = get_device_speed(
+ exp1->NegotiatedLinkRate);
+ snprintf(rphy, 3, "%02d",
+ exp1->AttachedPhyIdentifier);
+ snprintf(rhandle, 5, "%04x",
+ exp1->AttachedDevHandle);
+ }
+ min = get_device_speed(exp1->HwLinkRate);
+ max = get_device_speed(exp1->HwLinkRate >> 4);
+ printf(" %02d %s %s %s %s %s %s\n", exp1->Phy, rphy, rhandle, speed, min, max, type);
+
+ free(exp1);
+ }
+ free(exp0);
+ }
+
+ printf("\n");
+ close(fd);
+ return (0);
+}
+
+MPS_COMMAND(show, expanders, show_expanders, "", "Show attached expanders");
+
+static int
+show_cfgpage(int ac, char **av)
+{
+ MPI2_CONFIG_PAGE_HEADER *hdr;
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER *ehdr;
+ void *data;
+ uint32_t addr;
+ uint16_t IOCStatus;
+ uint8_t page, num;
+ int fd, error, len, attrs;
+ char *pgname, *pgattr;
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ return (error);
+ }
+
+ addr = 0;
+ num = 0;
+ page = 0;
+
+ switch (ac) {
+ case 4:
+ addr = (uint32_t)strtoul(av[3], NULL, 0);
+ case 3:
+ num = (uint8_t)strtoul(av[2], NULL, 0);
+ case 2:
+ page = (uint8_t)strtoul(av[1], NULL, 0);
+ break;
+ default:
+ errno = EINVAL;
+ warn("cfgpage: not enough arguments");
+ return (EINVAL);
+ }
+
+ if (page >= 0x10)
+ data = mps_read_extended_config_page(fd, page, 0, num, addr,
+ &IOCStatus);
+ else
+ data = mps_read_config_page(fd, page, num, addr, &IOCStatus);
+
+ if (data == NULL) {
+ error = errno;
+ warn("Error retrieving cfg page: %s\n",
+ mps_ioc_status(IOCStatus));
+ return (error);
+ }
+
+ if (page >= 0x10) {
+ ehdr = data;
+ len = ehdr->ExtPageLength * 4;
+ page = ehdr->ExtPageType;
+ attrs = ehdr->PageType >> 4;
+ } else {
+ hdr = data;
+ len = hdr->PageLength * 4;
+ page = hdr->PageType & 0xf;
+ attrs = hdr->PageType >> 4;
+ }
+
+ pgname = get_page_name(page);
+ if (attrs == 0)
+ pgattr = "Read-only";
+ else if (attrs == 1)
+ pgattr = "Read-Write";
+ else if (attrs == 2)
+ pgattr = "Read-Write Persistent";
+ else
+ pgattr = "Unknown Page Attribute";
+
+ printf("Page 0x%x: %s %d, %s\n", page, pgname, num, pgattr);
+ hexdump(data, len, NULL, HD_REVERSED | 4);
+ free(data);
+ return (0);
+}
+
+MPS_COMMAND(show, cfgpage, show_cfgpage, "page [num] [addr]", "Display config page");
diff --git a/usr.sbin/mpsutil/mpsutil.8 b/usr.sbin/mpsutil/mpsutil.8
new file mode 100644
index 0000000..6634b37
--- /dev/null
+++ b/usr.sbin/mpsutil/mpsutil.8
@@ -0,0 +1,165 @@
+.\"
+.\" Copyright (c) Baptiste Daroussin <bapt@FreeBSD.org>
+.\"
+.\" 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.
+.\"
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 17, 2015
+.Dt MPSUTIL 8
+.Os
+.Sh NAME
+.Nm mpsutil ,
+.Nm mprutil
+.Nd Utility for managing LSI Fusion-MPT 2/3 controllers
+.Sh SYNOPSIS
+.Nm
+.Cm version
+.Nm
+.Op Fl u Ar unit
+.Cm show adapter
+.Nm
+.Op Fl u Ar unit
+.Cm show adapters
+.Nm
+.Op Fl u Ar unit
+.Cm show all
+.Nm
+.Op Fl u Ar unit
+.Cm show cfgpages page
+.Op Ar num
+.Op Ar addr
+.Nm
+.Op Fl u Ar unit
+.Cm show devices
+.Nm
+.Op Fl u Ar unit
+.Cm show enclosures
+.Nm
+.Op Fl u Ar unit
+.Cm show expanders
+.Nm
+.Op Fl u Ar unit
+.Cm show iocfacts
+.Nm
+.Op Fl u Ar unit
+.Cm flash save
+.Op Ar firmware Ns | Ns Ar bios
+.Op Ar file
+.Nm
+.Op Fl u Ar unit
+.Cm flash update
+.Op Ar firmware Ns | Ns Ar bios
+.Ar file
+.Sh DESCRIPTION
+The
+.Nm
+utility can be used to display or modify various parameters on LSI
+Fusion-MPS 2 controllers.
+.Pp
+The
+.Nm mprutil
+utility can be used to display or modify various parameters on LSI
+Fusion-MPS 3 controllers.
+.Pp
+The
+.Nm mprutil
+utility behave identically to
+.Nm .
+(same program)
+.Pp
+Each invocation of
+.Nm
+consists of zero or more global options followed by a command.
+Commands may support additional optional or required arguments after the
+command.
+.Pp
+Currently one global option is supported:
+.Bl -tag -width indent
+.It Fl u Ar unit
+.Ar unit
+specifies the unit of the controller to work with.
+If no unit is specified,
+then unit 0 is used.
+.El
+.Pp
+The
+.Nm
+utility supports several different groups of commands.
+The first group of commands provide information about the controller.
+The second group of commands are used to manager controller-wide operations.
+.Pp
+The informational commands include:
+.Bl -tag -width indent
+.It Cm version
+Displays the version of
+.Nm .
+.It Cm show adapter
+Displays information about the controller such as the model number or firmware
+version.
+.It Cm show adapters
+Displays a summary of all adapters.
+.It Cm show all
+Displays all devices, expanders and enclosures.
+.It Cm show devices
+Displays all devices.
+.It Cm show expanders
+Displays all expanders.
+.It Cm show enclosures
+Displays all enclosures.
+.It Cm show iocfacts
+Displays IOC Facts messages.
+.It Cm show cfgpage page Oo Ar num Oc Op Ar addr
+Show IOC Facts Message
+.El
+.Pp
+Controller management commands include:
+.Bl -tag -width indent
+.It Cm flash save Oo Ar firmware Ns | Ns Ar bios Oc Op Ar file
+Save the
+.Ar firmware
+or
+.Ar bios
+from the controller into a local
+.Ar file .
+If no
+.Ar file
+is specified then the file will be named
+.Pa firmware
+or
+.Pa bios .
+.It Cm flash update Oo Ar firmware Ns | Ns Ar bios Oc Ar file
+Replace the
+.Ar firmware
+or
+.Ar bios
+from the controller with the one specified via
+.Ar file .
+.El
+.Sh SEE ALSO
+.Xr mpr 4 ,
+.Xr mps 4
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 11.0 .
diff --git a/usr.sbin/mpsutil/mpsutil.c b/usr.sbin/mpsutil/mpsutil.c
new file mode 100644
index 0000000..666a46e
--- /dev/null
+++ b/usr.sbin/mpsutil/mpsutil.c
@@ -0,0 +1,207 @@
+/*-
+ * Copyright (c) 2015 Netflix, Inc.
+ * All rights reserved.
+ * Written by: Scott Long <scottl@freebsd.org>
+ *
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "mpsutil.h"
+
+SET_DECLARE(MPS_DATASET(top), struct mpsutil_command);
+SET_DECLARE(MPS_DATASET(usage), struct mpsutil_usage);
+
+int mps_unit;
+int is_mps;
+
+static void
+usage(void)
+{
+ struct mpsutil_usage **cmd;
+ const char *args, *desc;
+
+ fprintf(stderr, "usage: %s [-u unit] <command> ...\n\n", getprogname());
+ fprintf(stderr, "Commands include:\n");
+ SET_FOREACH(cmd, MPS_DATASET(usage)) {
+ if (*cmd == NULL)
+ fprintf(stderr, "\n");
+ else
+ (*cmd)->handler(&args, &desc);
+ if (strncmp((*cmd)->set, "top", 3) == 0)
+ fprintf(stderr, "%s %-30s\t%s\n",
+ (*cmd)->name, args, desc);
+ else
+ fprintf(stderr, "%s %s %-30s\t%s\n",
+ (*cmd)->set, (*cmd)->name, args, desc);
+ }
+ exit(1);
+}
+
+static int
+version(int ac, char **av)
+{
+
+ printf("%s: version %s", MPSUTIL_VERSION, getprogname());
+#ifdef DEBUG
+ printf(" (DEBUG)");
+#endif
+ printf("\n");
+ return (0);
+}
+
+MPS_COMMAND(top, version, version, "", "version")
+
+int
+main(int ac, char **av)
+{
+ struct mpsutil_command **cmd;
+ int ch;
+
+ is_mps = !strcmp(getprogname(), "mpsutil");
+
+ while ((ch = getopt(ac, av, "u:h?")) != -1) {
+ switch (ch) {
+ case 'u':
+ mps_unit = atoi(optarg);
+ break;
+ case 'h':
+ case '?':
+ usage();
+ return (1);
+ }
+ }
+
+ av += optind;
+ ac -= optind;
+
+ /* getopt() eats av[0], so we can't use mpt_table_handler() directly. */
+ if (ac == 0) {
+ usage();
+ return (1);
+ }
+
+ SET_FOREACH(cmd, MPS_DATASET(top)) {
+ if (strcmp((*cmd)->name, av[0]) == 0) {
+ if ((*cmd)->handler(ac, av))
+ return (1);
+ else
+ return (0);
+ }
+ }
+ warnx("Unknown command %s.", av[0]);
+ return (1);
+}
+
+int
+mps_table_handler(struct mpsutil_command **start, struct mpsutil_command **end,
+ int ac, char **av)
+{
+ struct mpsutil_command **cmd;
+
+ if (ac < 2) {
+ warnx("The %s command requires a sub-command.", av[0]);
+ return (EINVAL);
+ }
+ for (cmd = start; cmd < end; cmd++) {
+ if (strcmp((*cmd)->name, av[1]) == 0)
+ return ((*cmd)->handler(ac - 1, av + 1));
+ }
+
+ warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
+ return (ENOENT);
+}
+
+void
+hexdump(const void *ptr, int length, const char *hdr, int flags)
+{
+ int i, j, k;
+ int cols;
+ const unsigned char *cp;
+ char delim;
+
+ if ((flags & HD_DELIM_MASK) != 0)
+ delim = (flags & HD_DELIM_MASK) >> 8;
+ else
+ delim = ' ';
+
+ if ((flags & HD_COLUMN_MASK) != 0)
+ cols = flags & HD_COLUMN_MASK;
+ else
+ cols = 16;
+
+ cp = ptr;
+ for (i = 0; i < length; i+= cols) {
+ if (hdr != NULL)
+ printf("%s", hdr);
+
+ if ((flags & HD_OMIT_COUNT) == 0)
+ printf("%04x ", i);
+
+ if ((flags & HD_OMIT_HEX) == 0) {
+ for (j = 0; j < cols; j++) {
+ if (flags & HD_REVERSED)
+ k = i + (cols - 1 - j);
+ else
+ k = i + j;
+ if (k < length)
+ printf("%c%02x", delim, cp[k]);
+ else
+ printf(" ");
+ }
+ }
+
+ if ((flags & HD_OMIT_CHARS) == 0) {
+ printf(" |");
+ for (j = 0; j < cols; j++) {
+ if (flags & HD_REVERSED)
+ k = i + (cols - 1 - j);
+ else
+ k = i + j;
+ if (k >= length)
+ printf(" ");
+ else if (cp[k] >= ' ' && cp[k] <= '~')
+ printf("%c", cp[k]);
+ else
+ printf(".");
+ }
+ printf("|");
+ }
+ printf("\n");
+ }
+}
diff --git a/usr.sbin/mpsutil/mpsutil.h b/usr.sbin/mpsutil/mpsutil.h
new file mode 100644
index 0000000..46c7d44
--- /dev/null
+++ b/usr.sbin/mpsutil/mpsutil.h
@@ -0,0 +1,147 @@
+/*-
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __MPSUTIL_H__
+#define __MPSUTIL_H__
+
+#include <sys/cdefs.h>
+#include <sys/linker_set.h>
+#include <stdbool.h>
+
+#include <dev/mps/mpi/mpi2_type.h>
+#include <dev/mps/mpi/mpi2.h>
+#include <dev/mps/mpi/mpi2_cnfg.h>
+#include <dev/mps/mpi/mpi2_raid.h>
+#include <dev/mps/mpi/mpi2_ioc.h>
+
+#define MPSUTIL_VERSION "1.0.0"
+
+#define IOC_STATUS_SUCCESS(status) \
+ (((status) & MPI2_IOCSTATUS_MASK) == MPI2_IOCSTATUS_SUCCESS)
+
+struct mpsutil_command {
+ const char *name;
+ int (*handler)(int ac, char **av);
+};
+struct mpsutil_usage {
+ const char *set;
+ const char *name;
+ void (*handler)(const char **, const char**);
+};
+
+#define MPS_DATASET(name) mpsutil_ ## name ## _table
+
+#define MPS_COMMAND(set, name, function, args, desc) \
+ static struct mpsutil_command function ## _mpsutil_command = \
+ { #name, function }; \
+ DATA_SET(MPS_DATASET(set), function ## _mpsutil_command); \
+ static void \
+ function ## _usage(const char **a3, const char **a4) \
+ { \
+ *a3 = args; \
+ *a4 = desc; \
+ return; \
+ }; \
+ static struct mpsutil_usage function ## _mpsutil_usage = \
+ { #set, #name, function ## _usage }; \
+ DATA_SET(MPS_DATASET(usage), function ## _mpsutil_usage);
+
+#define _MPS_COMMAND(set, name, function) \
+ static struct mpsutil_command function ## _mpsutil_command = \
+ { #name, function }; \
+ DATA_SET(MPS_DATASET(set), function ## _mpsutil_command);
+
+#define MPS_TABLE(set, name) \
+ SET_DECLARE(MPS_DATASET(name), struct mpsutil_command); \
+ \
+ static int \
+ mpsutil_ ## name ## _table_handler(int ac, char **av) \
+ { \
+ return (mps_table_handler(SET_BEGIN(MPS_DATASET(name)), \
+ SET_LIMIT(MPS_DATASET(name)), ac, av)); \
+ } \
+ _MPS_COMMAND(set, name, mpsutil_ ## name ## _table_handler)
+
+extern int mps_unit;
+extern int is_mps;
+#define MPS_MAX_UNIT 10
+
+void hexdump(const void *ptr, int length, const char *hdr, int flags);
+#define HD_COLUMN_MASK 0xff
+#define HD_DELIM_MASK 0xff00
+#define HD_OMIT_COUNT (1 << 16)
+#define HD_OMIT_HEX (1 << 17)
+#define HD_OMIT_CHARS (1 << 18)
+#define HD_REVERSED (1 << 19)
+
+int mps_open(int unit);
+int mps_table_handler(struct mpsutil_command **start,
+ struct mpsutil_command **end, int ac, char **av);
+int mps_user_command(int fd, void *req, uint32_t req_len, void *reply,
+ uint32_t reply_len, void *buffer, int len, uint32_t flags);
+int mps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
+ uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
+ uint32_t dataout_len, uint32_t timeout);
+int mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber,
+ U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus);
+int mps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber,
+ U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header,
+ U16 *ExtPageLen, U16 *IOCStatus);
+void *mps_read_config_page(int fd, U8 PageType, U8 PageNumber,
+ U32 PageAddress, U16 *IOCStatus);
+void *mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
+ U8 PageNumber, U32 PageAddress, U16 *IOCStatus);
+int mps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus,
+ uint16_t *target);
+const char *mps_ioc_status(U16 IOCStatus);
+int mps_firmware_send(int fd, unsigned char *buf, uint32_t len, bool bios);
+int mps_firmware_get(int fd, unsigned char **buf, bool bios);
+
+static __inline void *
+mps_read_man_page(int fd, U8 PageNumber, U16 *IOCStatus)
+{
+
+ return (mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_MANUFACTURING,
+ PageNumber, 0, IOCStatus));
+}
+
+static __inline void *
+mps_read_ioc_page(int fd, U8 PageNumber, U16 *IOCStatus)
+{
+
+ return (mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_IOC, PageNumber,
+ 0, IOCStatus));
+}
+
+MPI2_IOC_FACTS_REPLY * mps_get_iocfacts(int fd);
+
+#endif /* !__MPSUTIL_H__ */
OpenPOWER on IntegriCloud