Iniital hack of mpsutil

This commit is contained in:
Scott Long 2015-08-02 03:52:51 +00:00
parent 90c11a7328
commit 29b76e539f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/mpsutil/; revision=286180
10 changed files with 4302 additions and 0 deletions

20
usr.sbin/mpsutil/Makefile Normal file
View file

@ -0,0 +1,20 @@
# $FreeBSD$
PROG= mpsutil
SRCS= mpsutil.c mps_cmd.c mps_show.c
# mpt_flash.c
MAN= mpsutil.8
WARNS?= 3
LIBADD= cam util
CFLAGS+= -I../../sys -I. -DUSE_MPT_IOCTLS -g
# Here be dragons
.ifdef DEBUG
CFLAGS+= -DDEBUG
.endif
.include <bsd.prog.mk>

View file

@ -0,0 +1,386 @@
/*-
* 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)
#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 /* !_MPR_IOCTL_H_ */

713
usr.sbin/mpsutil/mps_cmd.c Normal file
View file

@ -0,0 +1,713 @@
/*-
* 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"
#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 */
};
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 mps_btdh_mapping map;
bzero(&map, sizeof(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);
}
#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
#if 0
int
mpt_write_config_page(int fd, void *buf, U16 *IOCStatus)
{
CONFIG_PAGE_HEADER *hdr;
struct mpt_cfg_page_req req;
if (IOCStatus != NULL)
*IOCStatus = MPI_IOCSTATUS_SUCCESS;
bzero(&req, sizeof(req));
req.buf = buf;
hdr = buf;
req.len = hdr->PageLength * 4;
if (ioctl(fd, MPTIO_WRITE_CFG_PAGE, &req) < 0)
return (errno);
if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
if (IOCStatus != NULL) {
*IOCStatus = req.ioc_status;
return (0);
}
warnx("Writing config page failed: %s",
mpt_ioc_status(req.ioc_status));
return (EIO);
}
return (0);
}
int
mpt_raid_action(int fd, U8 Action, U8 VolumeBus, U8 VolumeID, U8 PhysDiskNum,
U32 ActionDataWord, void *buf, int len, RAID_VOL0_STATUS *VolumeStatus,
U32 *ActionData, int datalen, U16 *IOCStatus, U16 *ActionStatus, int write)
{
struct mpt_raid_action raid_act;
if (IOCStatus != NULL)
*IOCStatus = MPI_IOCSTATUS_SUCCESS;
if (datalen < 0 || (unsigned)datalen > sizeof(raid_act.action_data))
return (EINVAL);
bzero(&raid_act, sizeof(raid_act));
raid_act.action = Action;
raid_act.volume_bus = VolumeBus;
raid_act.volume_id = VolumeID;
raid_act.phys_disk_num = PhysDiskNum;
raid_act.action_data_word = ActionDataWord;
if (buf != NULL && len != 0) {
raid_act.buf = buf;
raid_act.len = len;
raid_act.write = write;
}
if (ioctl(fd, MPTIO_RAID_ACTION, &raid_act) < 0)
return (errno);
if (!IOC_STATUS_SUCCESS(raid_act.ioc_status)) {
if (IOCStatus != NULL) {
*IOCStatus = raid_act.ioc_status;
return (0);
}
warnx("RAID action failed: %s",
mpt_ioc_status(raid_act.ioc_status));
return (EIO);
}
if (ActionStatus != NULL)
*ActionStatus = raid_act.action_status;
if (raid_act.action_status != MPI_RAID_ACTION_ASTATUS_SUCCESS) {
if (ActionStatus != NULL)
return (0);
warnx("RAID action failed: %s",
mpt_raid_status(raid_act.action_status));
return (EIO);
}
if (VolumeStatus != NULL)
*((U32 *)VolumeStatus) = raid_act.volume_status;
if (ActionData != NULL)
bcopy(raid_act.action_data, ActionData, datalen);
return (0);
}
#endif
int
mps_open(int unit)
{
char path[MAXPATHLEN];
snprintf(path, sizeof(path), "/dev/mps%d", 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, MPSIO_MPS_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 mps_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)
pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH;
else if (datain_len)
pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ;
else if (dataout_len)
pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE;
else
pass.DataDirection = MPS_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);
}

File diff suppressed because it is too large Load diff

View file

@ -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_ */

View file

@ -0,0 +1,68 @@
--- //depot/projects/lsimultiq/head/usr.sbin/mpsutil/mps_cmd.c 2015-02-16 06:22:37.000000000 -0700
+++ /home/scottl/p4/projects/lsimultiq/head/usr.sbin/mpsutil/mps_cmd.c 2015-02-16 06:22:37.000000000 -0700
@@ -37,7 +37,7 @@
#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>
@@ -237,7 +237,7 @@
mps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus, uint16_t *target)
{
int error;
- struct mps_btdh_mapping map;
+ struct mpr_btdh_mapping map;
bzero(&map, sizeof(map));
map.Bus = *bus;
@@ -629,9 +629,9 @@
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;
+ struct mpr_usr_command cmd;
- bzero(&cmd, sizeof(struct mps_usr_command));
+ bzero(&cmd, sizeof(struct mpr_usr_command));
cmd.req = req;
cmd.req_len = req_len;
cmd.rpl = reply;
@@ -640,7 +640,7 @@
cmd.len = len;
cmd.flags = flags;
- if (ioctl(fd, MPSIO_MPS_COMMAND, &cmd) < 0)
+ if (ioctl(fd, MPRIO_MPR_COMMAND, &cmd) < 0)
return (errno);
return (0);
}
@@ -650,7 +650,7 @@
uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
uint32_t dataout_len, uint32_t timeout)
{
- struct mps_pass_thru pass;
+ struct mpr_pass_thru pass;
pass.PtrRequest = (uint64_t)(uintptr_t)req;
pass.PtrReply = (uint64_t)(uintptr_t)reply;
@@ -661,13 +661,13 @@
pass.DataSize = datain_len;
pass.DataOutSize = dataout_len;
if (datain_len && dataout_len)
- pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH;
+ pass.DataDirection = MPR_PASS_THRU_DIRECTION_BOTH;
else if (datain_len)
- pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ;
+ pass.DataDirection = MPR_PASS_THRU_DIRECTION_READ;
else if (dataout_len)
- pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE;
+ pass.DataDirection = MPR_PASS_THRU_DIRECTION_WRITE;
else
- pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE;
+ pass.DataDirection = MPR_PASS_THRU_DIRECTION_NONE;
pass.Timeout = timeout;
if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0)

758
usr.sbin/mpsutil/mps_show.c Normal file
View file

@ -0,0 +1,758 @@
/*-
* 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("mps%d Adapter:\n", 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("PhyNum CtlrHandle DevHandle Disabled Speed Min Max Device\n");
for (i = 0; i < sas0->NumPhys; i++) {
phy0 = &sas0->PhyData[i];
phy1 = &sas1->PhyData[i];
printf(" %d ", 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(" %s %s %s %s %s %s %s\n",
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/mps%d\t%16s %16s %08x\n", 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[7];
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____T SAS Address Handle Parent Device Speed Enc Slot Wdt\n");
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, 7, " ");
else
snprintf(bt, 7, "%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("%s %08x%08x %04x %04x %s %s %s %s %d\n",
bt, device->SASAddress.High, device->SASAddress.Low,
device->DevHandle, device->ParentDevHandle, 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");

397
usr.sbin/mpsutil/mpsutil.8 Normal file
View file

@ -0,0 +1,397 @@
.\"
.\" 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$
.\"
.Dd August 16, 2009
.Dt MPTUTIL 8
.Os
.Sh NAME
.Nm mptutil
.Nd Utility for managing LSI Fusion-MPT controllers
.Sh SYNOPSIS
.Nm
.Cm version
.Nm
.Op Fl u Ar unit
.Cm show adapter
.Nm
.Op Fl u Ar unit
.Cm show config
.Nm
.Op Fl u Ar unit
.Cm show drives
.Nm
.Op Fl u Ar unit
.Cm show events
.Nm
.Op Fl u Ar unit
.Cm show volumes
.Nm
.Op Fl u Ar unit
.Cm fail Ar drive
.Nm
.Op Fl u Ar unit
.Cm online Ar drive
.Nm
.Op Fl u Ar unit
.Cm offline Ar drive
.Nm
.Op Fl u Ar unit
.Cm name Ar volume Ar name
.Nm
.Op Fl u Ar unit
.Cm volume status Ar volume
.Nm
.Op Fl u Ar unit
.Cm volume cache Ar volume
.Ar enable|disable
.Nm
.Op Fl u Ar unit
.Cm clear
.Nm
.Op Fl u Ar unit
.Cm create Ar type
.Op Fl q
.Op Fl v
.Op Fl s Ar stripe_size
.Ar drive Ns Op \&, Ns Ar drive Ns Op ",..."
.Nm
.Op Fl u Ar unit
.Cm delete Ar volume
.Nm
.Op Fl u Ar unit
.Cm add Ar drive Op Ar volume
.Nm
.Op Fl u Ar unit
.Cm remove Ar drive
.Sh DESCRIPTION
The
.Nm
utility can be used to display or modify various parameters on LSI
Fusion-MPT controllers.
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
Volumes may be specified in two forms.
First,
a volume may be identified by its location as
.Sm off
.Op Ar xx Ns \&:
.Ar yy
.Sm on
where
.Ar xx
is the bus ID and
.Ar yy
is the target ID.
If the bus ID is omitted,
the volume is assumed to be on bus 0.
Second,
on the volume may be specified by the corresponding
.Em daX
device,
such as
.Em da0 .
.Pp
The
.Xr mpt 4
controller divides drives up into two categories.
Configured drives belong to a RAID volume either as a member drive or as a hot
spare.
Each configured drive is assigned a unique device ID such as 0 or 1 that is
show in
.Cm show config ,
and in the first column of
.Cm show drives .
Any drive not associated with a RAID volume as either a member or a hot spare
is a standalone drive.
Standalone drives are visible to the operating system as SCSI disk devices.
As a result, drives may be specified in three forms.
First,
a configured drive may be identified by its device ID.
Second,
any drive may be identified by its location as
.Sm off
.Ar xx Ns \&:
.Ar yy
.Sm on
where
.Ar xx
is the bus ID and
.Ar yy
is the target ID for each drive as displayed in
.Cm show drives .
Note that unlike volumes,
a drive location always requires the bus ID to avoid confusion with device IDs.
Third,
a standalone drive that is not part of a volume may be identified by its
corresponding
.Em daX
device as displayed in
.Cm show drives .
.Pp
The
.Nm
utility supports several different groups of commands.
The first group of commands provide information about the controller,
the volumes it manages, and the drives it controls.
The second group of commands are used to manage the physical drives
attached to the controller.
The third group of commands are used to manage the logical volumes
managed by the controller.
The fourth group of commands are used to manage the drive configuration for
the controller.
.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 RAID controller such as the model number.
.It Cm show config
Displays the volume and drive configuration for the controller.
Each volume is listed along with the physical drives that the volume spans.
If any hot spare drives are configured, then they are listed as well.
.It Cm show drives
Lists all of the physical drives attached to the controller.
.It Cm show events
Display all the entries from the controller's event log.
Due to lack of documentation this command is not very useful currently and
just dumps each log entry in hex.
.It Cm show volumes
Lists all of the logical volumes managed by the controller.
.El
.Pp
The physical drive management commands include:
.Bl -tag -width indent
.It Cm fail Ar drive
Mark
.Ar drive
as
.Dq failed requested .
Note that this state is different from the
.Dq failed
state that is used when the firmware fails a drive.
.Ar Drive
must be a configured drive.
.It Cm online Ar drive
Mark
.Ar drive
as an online drive.
.Ar Drive
must be part a configured drive in either the
.Dq offline
or
.Dq failed requested
states.
.It Cm offline Ar drive
Mark
.Ar drive
as offline.
.Ar Drive
must be a configured, online drive.
.El
.Pp
The logical volume management commands include:
.Bl -tag -width indent
.It Cm name Ar volume Ar name
Sets the name of
.Ar volume
to
.Ar name .
.It Cm volume cache Ar volume Ar enable|disable
Enables or disables the drive write cache for the member drives of
.Ar volume .
.It Cm volume status Ar volume
Display more detailed status about a single volume including the current
progress of a rebuild operation if one is being performed.
.El
.Pp
The configuration commands include:
.Bl -tag -width indent
.It Cm clear
Delete the entire configuration including all volumes and spares.
All drives will become standalone drives.
.It Xo Cm create Ar type
.Op Fl q
.Op Fl v
.Op Fl s Ar stripe_size
.Ar drive Ns Op \&, Ns Ar drive Ns Op ",..."
.Xc
Create a new volume.
The
.Ar type
specifies the type of volume to create.
Currently supported types include:
.Bl -tag -width indent
.It Cm raid0
Creates one RAID0 volume spanning the drives listed in the single drive list.
.It Cm raid1
Creates one RAID1 volume spanning the drives listed in the single drive list.
.It Cm raid1e
Creates one RAID1E volume spanning the drives listed in the single drive list.
.El
.Pp
.Sy Note:
Not all volume types are supported by all controllers.
.Pp
If the
.Fl q
flag is specified after
.Ar type ,
then a
.Dq quick
initialization of the volume will be done.
This is useful when the drives do not contain any existing data that need
to be preserved.
.Pp
If the
.Fl v
flag is specified after
.Ar type ,
then more verbose output will be enabled.
Currently this just provides notification as drives are added to volumes
when building the configuration.
.Pp
The
.Fl s
.Ar stripe_size
parameter allows the stripe size of the array to be set.
By default a stripe size of 64K is used.
The list of valid values for a given
.Ar type
are listed in the output of
.Cm show adapter .
.It Cm delete Ar volume
Delete the volume
.Ar volume .
Member drives will become standalone drives.
.It Cm add Ar drive Op Ar volume
Mark
.Ar drive
as a hot spare.
.Ar Drive
must not be a member of a volume.
If
.Ar volume
is specified,
then the hot spare will be dedicated to that volume.
Otherwise,
.Ar drive
will be used as a global hot spare backing all volumes for this controller.
Note that
.Ar drive
must be as large as the smallest drive in all of the volumes it is going to
back.
.It Cm remove Ar drive
Remove the hot spare
.Ar drive
from service.
It will become a standalone drive.
.El
.Sh EXAMPLES
Mark the drive at bus 0 target 4 as offline:
.Pp
.Dl Nm Cm offline 0:4
.Pp
Create a RAID1 array from the two standalone drives
.Va da1
and
.Va da2 :
.Pp
.Dl Nm Cm create raid1 da1,da2
.Pp
Mark standalone drive
.Va da3
as a global hot spare:
.Pp
.Dl Nm Cm add da3
.Sh SEE ALSO
.Xr mpt 4
.Sh HISTORY
The
.Nm
utility first appeared in
.Fx 8.0 .
.Sh BUGS
The handling of spare drives appears to be unreliable.
The
.Xr mpt 4
firmware manages spares via spare drive
.Dq pools .
There are eight pools numbered 0 through 7.
Each spare drive can only be assigned to a single pool.
Each volume can be backed by any combination of zero or more spare pools.
The
.Nm
utility attempts to use the following algorithm for managing spares.
Global spares are always assigned to pool 0,
and all volumes are always backed by pool 0.
For dedicated spares,
.Nm
assigns one of the remaining 7 pools to each volume and
assigns dedicated drives to that pool.
In practice however, it seems that assigning a drive as a spare does not
take effect until the box has been rebooted.
Also, the firmware renumbers the spare pool assignments after a reboot
which undoes the effects of the algorithm above.
Simple cases such as assigning global spares seem to work ok
.Pq albeit requiring a reboot to take effect
but more
.Dq exotic
configurations may not work reliably.
.Pp
Drive configuration commands result in an excessive flood of messages on the
console.
.Pp
The mpt version 1 API that is used by
.Nm
and
.Xr mpt 4
does not support volumes above two terabytes.
This is a limitation of the API.
If you are using this adapter with volumes larger than two terabytes, use the adapter in JBOD mode.
Utilize
.Xr geom 8 ,
.Xr zfs 8 ,
or another software volume manager to work around this limitation.

200
usr.sbin/mpsutil/mpsutil.c Normal file
View file

@ -0,0 +1,200 @@
/*-
* 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;
static void
usage(void)
{
struct mpsutil_usage **cmd;
const char *args, *desc;
fprintf(stderr, "usage: mpsutil [-u unit] <command> ...\n\n");
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("mpsutil: version %s", MPSUTIL_VERSION);
#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;
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");
}
}

200
usr.sbin/mpsutil/mpsutil.h Normal file
View file

@ -0,0 +1,200 @@
/*-
* 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 <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;
#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);
#if 0
int mpt_write_config_page(int fd, void *buf, U16 *IOCStatus);
int mpt_raid_action(int fd, U8 Action, U8 VolumeBus, U8 VolumeID,
U8 PhysDiskNum, U32 ActionDataWord, void *buf, int len,
RAID_VOL0_STATUS *VolumeStatus, U32 *ActionData, int datalen,
U16 *IOCStatus, U16 *ActionStatus, int write);
const char *mpt_raid_status(U16 ActionStatus);
const char *mpt_raid_level(U8 VolumeType);
const char *mpt_volstate(U8 State);
const char *mpt_pdstate(CONFIG_PAGE_RAID_PHYS_DISK_0 *info);
const char *mpt_pd_inq_string(CONFIG_PAGE_RAID_PHYS_DISK_0 *pd_info);
struct mpt_drive_list *mpt_pd_list(int fd);
void mpt_free_pd_list(struct mpt_drive_list *list);
int mpt_query_disk(U8 VolumeBus, U8 VolumeID, struct mpt_query_disk *qd);
const char *mpt_volume_name(U8 VolumeBus, U8 VolumeID);
int mpt_fetch_disks(int fd, int *ndisks,
struct mpt_standalone_disk **disksp);
int mpt_lock_volume(U8 VolumeBus, U8 VolumeID);
int mpt_lookup_drive(struct mpt_drive_list *list, const char *drive,
U8 *PhysDiskNum);
int mpt_lookup_volume(int fd, const char *name, U8 *VolumeBus,
U8 *VolumeID);
int mpt_rescan_bus(int bus, int id);
#endif
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);
#if 0
static __inline U32
mpt_vol_pageaddr(U8 VolumeBus, U8 VolumeID)
{
return (VolumeBus << 8 | VolumeID);
}
static __inline CONFIG_PAGE_RAID_VOL_0 *
mpt_vol_info(int fd, U8 VolumeBus, U8 VolumeID, U16 *IOCStatus)
{
return (mpt_read_config_page(fd, MPI_CONFIG_PAGETYPE_RAID_VOLUME, 0,
mpt_vol_pageaddr(VolumeBus, VolumeID), IOCStatus));
}
static __inline CONFIG_PAGE_RAID_VOL_1 *
mpt_vol_names(int fd, U8 VolumeBus, U8 VolumeID, U16 *IOCStatus)
{
return (mpt_read_config_page(fd, MPI_CONFIG_PAGETYPE_RAID_VOLUME, 1,
mpt_vol_pageaddr(VolumeBus, VolumeID), IOCStatus));
}
static __inline CONFIG_PAGE_RAID_PHYS_DISK_0 *
mpt_pd_info(int fd, U8 PhysDiskNum, U16 *IOCStatus)
{
return (mpt_read_config_page(fd, MPI_CONFIG_PAGETYPE_RAID_PHYSDISK, 0,
PhysDiskNum, IOCStatus));
}
#endif
#endif /* !__MPTUTIL_H__ */