mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-14 10:09:48 +00:00
Iniital hack of mpsutil
This commit is contained in:
parent
90c11a7328
commit
29b76e539f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/mpsutil/; revision=286180
20
usr.sbin/mpsutil/Makefile
Normal file
20
usr.sbin/mpsutil/Makefile
Normal 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>
|
386
usr.sbin/mpsutil/mpr_ioctl.h
Normal file
386
usr.sbin/mpsutil/mpr_ioctl.h
Normal 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
713
usr.sbin/mpsutil/mps_cmd.c
Normal 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);
|
||||
}
|
||||
|
1173
usr.sbin/mpsutil/mps_config.c
Normal file
1173
usr.sbin/mpsutil/mps_config.c
Normal file
File diff suppressed because it is too large
Load Diff
387
usr.sbin/mpsutil/mps_ioctl.h
Normal file
387
usr.sbin/mpsutil/mps_ioctl.h
Normal 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_ */
|
68
usr.sbin/mpsutil/mps_mpr.diff
Normal file
68
usr.sbin/mpsutil/mps_mpr.diff
Normal 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
758
usr.sbin/mpsutil/mps_show.c
Normal 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
397
usr.sbin/mpsutil/mpsutil.8
Normal 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
200
usr.sbin/mpsutil/mpsutil.c
Normal 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
200
usr.sbin/mpsutil/mpsutil.h
Normal 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__ */
|
Loading…
Reference in New Issue
Block a user