lsiutil/source/lsiutil.c

43218 lines
1.4 MiB
Executable File

/***************************************************************************
* *
* Copyright (c) 2002-2013 LSI Corporation. All rights reserved. *
* *
* This file is confidential and a trade secret of LSI Corporation. The *
* receipt of or possession of this file does not convey any rights to *
* reproduce or disclose its contents or to manufacture, use, or sell *
* anything it may describe, in whole, or in part, without the specific *
* written consent of LSI Corporation. *
* *
***************************************************************************
* LSIUtil -- configuration utility for MPT adapters (FC, SCSI, and SAS/SATA)
*
* Written by Stephen F. Shirron, October 11, 2002
*/
#define LSIUTIL_VERSION "Version 1.72, Sep 09, 2014"
char what[] = "@(#)LSI Logic MPT Configuration Utility, " LSIUTIL_VERSION;
/* SAS3108 FPGA-specific defines*/
#define SAS3108_FPGA_WORKAROUND (1)
#define SAS3108_FPGA_VENDORID (0x702)
#ifndef MAX_DEVICES
#define MAX_DEVICES 99
#endif
#ifndef REGISTER_ACCESS
#define REGISTER_ACCESS 1
#endif
#ifndef VERIFY_ENDIANNESS
#define VERIFY_ENDIANNESS 0
#endif
#if !EFI
#include <fcntl.h>
#if WIN32
#include <io.h>
#else
#define _cdecl
#endif
#include <sys/stat.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if WIN32
#include <windows.h>
#include "inc/devioctl.h"
#include <basetsd.h>
#include <errno.h>
#ifdef _CONSOLE
#pragma warning(disable:4242)
#include "inc/getopt.h"
#define sleep(x) _sleep(x*1000)
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#if !_WIN64
typedef unsigned long ULONG_PTR;
#endif
#define stricmp _stricmp
#define strnicmp _strnicmp
#define open _open
#define close _close
#define read _read
#define write _write
#define stat _stat
#define fstat _fstat
#define INT64_FMT "I64"
#else
#define INT64_FMT "ll"
#include <unistd.h>
#include <getopt.h>
int optopt;
int optind;
#endif
#define strcasecmp stricmp
#define strncasecmp strnicmp
#include "inc/ntddscsi.h"
/* MINGW is a little different from the DDK */
#if __MINGW32__
#define offsetof(type,member) ((size_t)&((type *)0)->member)
#define sleep(x) Sleep(x*1000)
#endif
#endif
#if __linux__ || __sparc__ || __irix__ || __alpha__
#include <stdarg.h>
#include <unistd.h>
#include <strings.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <limits.h>
#include <dirent.h>
#define FALSE 0
#define TRUE 1
typedef int HANDLE;
#define O_BINARY 0
#define min(x,y) ((int)(x) < (int)(y) ? (x) : (y))
#define max(x,y) ((int)(x) > (int)(y) ? (x) : (y))
#define INT64_FMT "ll"
#endif
#if __linux__
#include <linux/stddef.h>
#ifndef offsetof
#define offsetof(type,member) ((size_t)&((type *)0)->member)
#endif
#define TotalBufferSize DataSize
#define DataBuffer DiagnosticData
#include <scsi/scsi.h>
#if i386
#include <sys/io.h>
#endif
#define LINUX_MOD_DEVICETABLE_H
#include <linux/pci.h>
#include <sys/mman.h>
#define REG_IO_READ 1
#define REG_IO_WRITE 2
#define REG_MEM_READ 3
#define REG_MEM_WRITE 4
#define REG_DIAG_READ 5
#define REG_DIAG_WRITE 6
#define REG_DIAG_WRITE_BYTE 7
#endif
#if __sparc__
#include <libdevinfo.h>
#include <stddef.h>
#include <sys/param.h>
#include <sys/mkdev.h>
typedef struct
{
caddr_t client;
caddr_t phci;
caddr_t addr;
uint_t buf_elem;
void *ret_buf;
uint_t *ret_elem;
} sv_iocdata_t;
#define SCSI_VHCI_GET_CLIENT_NAME (('x' << 8) + 0x03)
#define NAME_MAX MAXNAMLEN
#define getmajor(x) (((x)>>NBITSMINOR)&MAXMAJ)
#define getminor(x) ((x)&MAXMIN)
#define MINOR2INST(x) ((x)>>6)
#endif
#if DOS
#include <unistd.h>
#include <conio.h>
#include <dos.h>
#include <time.h>
#include <errno.h>
#include <stddef.h>
#include <stdarg.h>
#include "inc/getopt.h"
#define FALSE 0
#define TRUE 1
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
typedef unsigned int PHYSICAL_ADDRESS;
typedef unsigned int mpt_bus_addr_t;
typedef struct mpt_adap *HANDLE;
#define strcasecmp stricmp
#define strncasecmp strnicmp
#define DELAY(n) mpt_delay(adap, n)
#define REG_IO_READ 1
#define REG_IO_WRITE 2
#define REG_MEM_READ 3
#define REG_MEM_WRITE 4
#define REG_DIAG_READ 5
#define REG_DIAG_WRITE 6
#define REG_DIAG_WRITE_BYTE 7
#define INT64_FMT "I64"
#endif
#endif
#if EFI
#if EFIEBC
#pragma warning(disable:175)
#endif
#define _cdecl
#include "helper.h"
#include "getopt.h"
#define O_BINARY 0
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
typedef EFI_PHYSICAL_ADDRESS mpt_bus_addr_t;
typedef struct mpt_adap *HANDLE;
#define min(x,y) ((int)(x) < (int)(y) ? (x) : (y))
#define max(x,y) ((int)(x) > (int)(y) ? (x) : (y))
#define DELAY(n) mpt_delay(adap, n)
#define REG_IO_READ 1
#define REG_IO_WRITE 2
#define REG_MEM_READ 3
#define REG_MEM_WRITE 4
#define REG_DIAG_READ 5
#define REG_DIAG_WRITE 6
#define REG_DIAG_WRITE_BYTE 7
#define INT64_FMT "ll"
extern EFI_HANDLE gImageHandle;
extern EFI_LOADED_IMAGE *gLoadedImage;
#endif
#if DOS || EFI
#define CHUNK_SIZE 0x10000
#else
#define CHUNK_SIZE 0x4000
#endif
typedef unsigned char U8;
typedef unsigned short U16;
typedef unsigned int U32;
typedef struct { U32 Low; U32 High; } U64;
#define MPI_POINTER *
#define MPI2_POINTER *
#if VERIFY_ENDIANNESS
typedef U16 * _U16;
typedef U32 * _U32;
typedef struct { _U32 Low; _U32 High; } _U64;
#else
typedef U16 _U16;
typedef U32 _U32;
typedef U64 _U64;
#endif
#if VERIFY_ENDIANNESS
#define U16 _U16
#define U32 _U32
#define U64 _U64
#endif
#if WIN32 || __linux__ || __sparc__ || DOS || EFI
#pragma pack(1)
#include "lsi/mpi.h"
#include "lsi/mpi_ioc.h"
#include "lsi/mpi_cnfg.h"
#include "lsi/mpi_init.h"
#include "lsi/mpi_fc.h"
#include "lsi/mpi_sas.h"
#include "lsi/mpi_raid.h"
#include "lsi/mpi_tool.h"
#include "lsi/mpi2.h"
#include "lsi/mpi2_ioc.h"
#include "lsi/mpi2_cnfg.h"
#include "lsi/mpi2_init.h"
#include "lsi/mpi2_sas.h"
#include "lsi/mpi2_raid.h"
#include "lsi/mpi2_tool.h"
#pragma pack()
#endif
#if VERIFY_ENDIANNESS
#undef U16
#undef U32
#undef U64
#endif
#if WIN32
#include "inc/sym_dmi.h"
#define ISSUE_BUS_RESET 0x800000FF
typedef struct
{
SRB_IO_CONTROL Sic;
UCHAR Buf[8+128+1024];
} SRB_BUFFER;
typedef struct
{
SRB_IO_CONTROL Sic;
ULONG DiagType;
UCHAR PageVersion[4];
UCHAR Buf[64+32768];
} SRB_DIAG_BUFFER;
#endif
#if __linux__
#ifndef __user
#define __user
#endif
typedef unsigned long long uint64_t;
typedef U8 u8;
typedef U16 u16;
typedef U32 u32;
#include "inc/mptctl.h"
typedef U8 uint8_t;
typedef U16 uint16_t;
typedef U32 uint32_t;
#include "inc/mpt2sas_ctl.h"
#define IOCTL_NAME "/dev/" MPT_MISCDEV_BASENAME
#define IOCTL_NAME2 "/dev/" MPT2SAS_DEV_NAME
#define IOCTL_NAME3 "/dev/mpt3ctl"
#ifdef MPI_FW_DIAG_IOCTL
#define LINUX_DIAG 1
typedef struct
{
struct mpt2_ioctl_header hdr;
unsigned char buf[64+32768];
} IOCTL_DIAG_BUFFER;
#endif
#endif
#if __sparc__
#define TARGET_MPTx
typedef uint8_t UINT8;
typedef uint16_t UINT16;
typedef uint32_t UINT32;
typedef uint64_t UINT64;
#include "inc/dmi_ioctl.h"
#include "inc/mptsas_ioctl.h"
#endif
#if __irix__
#define MPI_POINTER *
typedef uint8_t U8;
typedef uint16_t U16;
typedef uint32_t U32;
typedef struct
{
U32 Low;
U32 High;
} mpiU64;
#pragma pack(1)
#define U64 mpiU64
#include "mpi.h"
#include "mpi_ioc.h"
#include "mpi_cnfg.h"
#include "mpi_init.h"
#include "mpi_fc.h"
#include "mpi_sas.h"
#include "mpi_raid.h"
#include "mpi_tool.h"
#pragma pack(0)
#undef U64
#define TARGET_MPT
typedef uint8_t UINT8;
typedef uint16_t UINT16;
typedef uint32_t UINT32;
typedef uint64_t UINT64;
#include "dmi_ioctl.h"
#include <sys/scsi.h>
#endif
#if __alpha__
typedef unsigned __int64 uint64_t;
#define MPI_POINTER *
typedef unsigned char U8;
typedef unsigned short U16;
typedef unsigned int U32;
typedef unsigned long U64;
typedef struct
{
U32 Low;
U32 High;
} mpiU64;
#pragma pack(1)
#define U64 mpiU64
#include "mpi.h"
#include "mpi_ioc.h"
#include "mpi_cnfg.h"
#include "mpi_init.h"
#include "mpi_fc.h"
#include "mpi_sas.h"
#include "mpi_raid.h"
#include "mpi_tool.h"
#pragma pack(0)
#undef U64
typedef U8 u8;
typedef U16 u16;
typedef U32 u32;
typedef U64 u64;
#include "mptctl.h"
#endif
#if DOS
#include "pcidefs.h"
#include "pcilib.h"
#include "dpmilib.h"
#endif
#if !VERIFY_ENDIANNESS
#define printf printfPaged
#define fprintf fprintfPaged
#endif
#undef __LSIUTIL_BIG_ENDIAN__
#define swap16(x) \
((((U16)(x)>>8)&0xff) | \
(((U16)(x)&0xff)<<8))
#define swap32(x) \
((((U32)(x)>>24)&0xff) | \
((((U32)(x)>>16)&0xff)<<8) | \
((((U32)(x)>>8)&0xff)<<16) | \
(((U32)(x)&0xff)<<24))
#if WIN32 || __alpha__ || DOS || EFI
#define get16(x) (x)
#define get32(x) (x)
#define set16(x) (x)
#define set32(x) (x)
#define get16x(x) (x)
#define get32x(x) (x)
#define set16x(x) (x)
#define set32x(x) (x)
#define get16x_be(x) swap16(x)
#define get32x_be(x) swap32(x)
#define set16x_be(x) swap16(x)
#define set32x_be(x) swap32(x)
#endif
#if __linux__
#include <endian.h>
#include <linux/types.h>
#if __BYTE_ORDER == __BIG_ENDIAN
#include <linux/byteorder/big_endian.h>
#define __LSIUTIL_BIG_ENDIAN__ 1
#endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
#include <linux/byteorder/little_endian.h>
#endif
#define get16(x) __le16_to_cpu(x)
#define get32(x) __le32_to_cpu(x)
#define set16(x) __cpu_to_le16(x)
#define set32(x) __cpu_to_le32(x)
#define get16x(x) __le16_to_cpu(x)
#define get32x(x) __le32_to_cpu(x)
#define set16x(x) __cpu_to_le16(x)
#define set32x(x) __cpu_to_le32(x)
#define get16x_be(x) __be16_to_cpu(x)
#define get32x_be(x) __be32_to_cpu(x)
#define set16x_be(x) __cpu_to_be16(x)
#define set32x_be(x) __cpu_to_be32(x)
#endif
#if __sparc__ || __irix__
#if i386
#define get16(x) (x)
#define get32(x) (x)
#define set16(x) (x)
#define set32(x) (x)
#define get16x(x) (x)
#define get32x(x) (x)
#define set16x(x) (x)
#define set32x(x) (x)
#define get16x_be(x) swap16(x)
#define get32x_be(x) swap32(x)
#define set16x_be(x) swap16(x)
#define set32x_be(x) swap32(x)
#else
#define get16(x) swap16(x)
#define get32(x) swap32(x)
#define set16(x) swap16(x)
#define set32(x) swap32(x)
#define get16x(x) swap16(x)
#define get32x(x) swap32(x)
#define set16x(x) swap16(x)
#define set32x(x) swap32(x)
#define get16x_be(x) (x)
#define get32x_be(x) (x)
#define set16x_be(x) (x)
#define set32x_be(x) (x)
#define __LSIUTIL_BIG_ENDIAN__ 1
#endif
#endif
#define get64(x) (((uint64_t)get32x(((U32 *)&(x))[1])<<32) | get32x(((U32 *)&(x))[0]))
#define get64x(x) (((uint64_t)get32x(((U32 *)&(x))[1])<<32) | get32x(((U32 *)&(x))[0]))
/* These need to be included after the __LSIUTIL_BIG_ENDIAN__ define as they rely on it */
#include "inc/ata.h"
#include "inc/sas.h"
#if VERIFY_ENDIANNESS
#undef get16
#undef get32
#undef set16
#undef set32
U16 get16(U16 *x) { return 0; }
U32 get32(U32 *x) { return 0; }
U16 *set16(int x) { return NULL; }
U32 *set32(int x) { return NULL; }
#endif
#define get2bytes(x, y) (((x[y] << 8) + x[y+1]) & 0xffff)
#define get3bytes(x, y) (((x[y] << 16) + (x[y+1] << 8) + x[y+2]) & 0xffffff)
#define get4bytes(x, y) (((x[y] << 24) + (x[y+1] << 16) + (x[y+2] << 8) + x[y+3]) & 0xffffffff)
#define get8bytes(x, y) (((uint64_t)get4bytes(x, y) << 32) + get4bytes(x, y+4))
#define put2bytes(x, y, z) \
x[y] = (U8)((z) >> 8); \
x[y+1] = (U8)(z)
#define put3bytes(x, y, z) \
x[y] = (U8)((z) >> 16); \
x[y+1] = (U8)((z) >> 8); \
x[y+2] = (U8)(z)
#define put4bytes(x, y, z) \
x[y] = (U8)((z) >> 24); \
x[y+1] = (U8)((z) >> 16); \
x[y+2] = (U8)((z) >> 8); \
x[y+3] = (U8)(z)
#if REGISTER_ACCESS
#define readl(addr, data) \
{ \
U32 temp; \
if (doReadRegister(port, MPI_##addr##_OFFSET, &temp) != 1) \
{ \
printf("Failed to read register!\n"); \
return 0; \
} \
data = temp; \
}
#define writel(addr, data) \
{ \
U32 temp = data; \
if (doWriteRegister(port, MPI_##addr##_OFFSET, &temp) != 1) \
{ \
printf("Failed to write register!\n"); \
return 0; \
} \
}
#endif
#define IO_TIME 20
#define RESET_TIME 60
#define SHORT_TIME 10
#define LONG_TIME 120
#define BOBCAT_FW_HEADER_SIGNATURE_0 ( 0xB0EABCA7 )
#define BOBCAT_FW_HEADER_SIGNATURE_1 ( 0xB0BCEAA7 )
#define BOBCAT_FW_HEADER_SIGNATURE_2 ( 0xB0BCA7EA )
#define COBRA_FW_HEADER_SIGNATURE_0 ( 0xC0EABAA0 )
#define COBRA_FW_HEADER_SIGNATURE_1 ( 0xC0BAEAA0 )
#define COBRA_FW_HEADER_SIGNATURE_2 ( 0xC0BAA0EA )
#define ALLOCATED_RESP_LEN 0xff
#if DEBUG_MALLOC_FREE
int my_mallocs;
int my_frees;
int _cdecl main(int argc, char *argv[])
{
int t;
int _cdecl my_main(int argc, char *argv[]);
my_mallocs = 0;
my_frees = 0;
t = my_main(argc, argv);
if (my_mallocs != my_frees)
printf("mallocs = %d, frees = %d\n", my_mallocs, my_frees);
return t;
}
void *my_malloc(size_t x)
{
my_mallocs++;
return malloc(x);
}
void my_free(void *x)
{
my_frees++;
free(x);
}
#define main my_main
#define malloc my_malloc
#define free my_free
#endif
#define NUM_PORTS 64
typedef struct
{
U8 signature[4];
_U16 vendorId;
_U16 deviceId;
U8 reserved1[2];
_U16 pcirLength;
U8 pcirRevision;
U8 classCode[3];
_U16 imageLength;
_U16 imageRevision;
U8 type;
U8 indicator;
U8 reserved2[2];
} PCIR;
typedef struct
{
int portNumber;
char portName[16];
#if WIN32
char driverName[32];
#endif
#if __sparc__
char pathName[PATH_MAX];
U32 portPhyMap[32];
#endif
HANDLE fileHandle;
int ioctlValue;
int iocNumber;
int hostNumber;
int mptVersion;
int fwVersion;
int whoInit;
U16 deviceIdRaw;
U16 deviceId;
U8 revisionId;
U16 productId;
int pidType;
U32 capabilities;
U8 flags;
U32 fwImageSize;
char *chipName;
char *chipNameRev;
char *pciType;
U32 seqCodeVersion;
int payOff;
int portType;
int maxPersistentIds;
int maxBuses;
int minTargets;
int maxTargets;
int maxLuns;
int maxDevHandle;
int numPhys;
int hostScsiId;
int protocolFlags;
int lastEvent;
#if LINUX_DIAG
int diagBufferSizes[MPI_DIAG_BUF_TYPE_COUNT];
#endif
#if __linux__
off_t ioPhys;
off_t memPhys;
U32 *memVirt;
off_t diagPhys;
U32 *diagVirt;
#endif
int notOperational;
int pciSegment;
int pciBus;
int pciDevice;
int pciFunction;
int raidPassthru;
int raidBus;
int raidTarget;
int raidPhysdisk;
int fastpathCapable;
U16 ioc_status; // Currently only updated during (get|set)ConfigPage()
} MPT_PORT;
typedef struct
{
SCSIIOReply_t reply;
U8 sense[32];
} SCSI_REPLY;
typedef struct
{
Mpi2SCSIIOReply_t reply;
U8 sense[32];
} SCSI_REPLY2;
typedef struct
{
int slot;
int encl_id_l;
int encl_id_h;
} PATH;
typedef struct
{
int bus;
int target;
int lun;
PATH path;
int mode;
unsigned int size;
uint64_t size64;
int eedp;
} DIAG_TARGET;
#define EXPANDER_TYPE_LSI_GEN1_YETI 1
#define EXPANDER_TYPE_LSI_GEN1_X12 2
#define EXPANDER_TYPE_LSI_GEN2_BOBCAT 3
#define EXPANDER_TYPE_LSI_GEN3_COBRA 4
#define EXPANDER_TYPE_3RD_PARTY 8
#define EXPANDER_TYPE_UNKNOWN 9
typedef struct
{
int bus;
int target;
int handle;
_U64 sas_address;
U8 physical_port;
int expanderType;
} EXP_TARGET;
typedef struct
{
int type;
int number;
int data[2];
} EVENT;
typedef struct
{
int type;
int number;
int data[48];
} EVENT2;
typedef struct
{
_U32 Size;
_U32 DiagVersion;
U8 BufferType;
U8 Reserved[3];
_U32 Reserved1;
_U32 Reserved2;
_U32 Reserved3;
} DIAG_BUFFER_START;
typedef struct
{
_U32 Size;
_U16 Type;
U8 Version;
U8 Reserved;
_U32 CapabilitiesFlags;
_U32 FWVersion;
_U16 ProductId;
_U16 Reserved1;
} DIAG_HEADER_FIRM_IDENTIFICATION;
typedef struct
{
_U32 Size;
_U16 Type;
U8 Version;
U8 Reserved;
U8 HostInfo[256];
} DIAG_HEADER_HOST_IDENTIFICATION;
/* diag register for gen 2 */
typedef struct _MPI2_FW_DIAG_REGISTER
{
U8 Reserved;
U8 BufferType;
U16 AppFlags;
U32 DiagFlags;
U32 ProductSpecific[23];
U32 RequestedBufferSize;
U32 UniqueId;
} MPI2_FW_DIAG_REGISTER, *PTR_MPI2_FW_DIAG_REGISTER;
/* diag query for gen 2 */
typedef struct _MPI2_FW_DIAG_QUERY
{
U8 Reserved;
U8 BufferType;
U16 AppFlags;
U32 DiagFlags;
U32 ProductSpecific[23];
U32 TotalBufferSize;
U32 DriverAddedBufferSize;
U32 UniqueId;
} MPI2_FW_DIAG_QUERY, *PTR_MPI2_FW_DIAG_QUERY;
#if WIN32
#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE
#define IOCTL_STORAGE_QUERY_PROPERTY CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
typedef struct _STORAGE_ADAPTER_DESCRIPTOR {
ULONG Version;
ULONG Size;
ULONG MaximumTransferLength;
ULONG MaximumPhysicalPages;
ULONG AlignmentMask;
BOOLEAN AdapterUsesPio;
BOOLEAN AdapterScansDown;
BOOLEAN CommandQueueing;
BOOLEAN AcceleratedTransfer;
UCHAR BusType;
USHORT BusMajorVersion;
USHORT BusMinorVersion;
} STORAGE_ADAPTER_DESCRIPTOR, *PSTORAGE_ADAPTER_DESCRIPTOR;
typedef enum _STORAGE_PROPERTY_ID {
StorageDeviceProperty = 0,
StorageAdapterProperty,
StorageDeviceIdProperty,
StorageDeviceUniqueIdProperty,
StorageDeviceWriteCacheProperty,
StorageMiniportProperty,
StorageAccessAlignmentProperty,
StorageDeviceSeekPenaltyProperty,
StorageDeviceTrimProperty,
StorageDeviceWriteAggregationProperty
} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;
typedef enum _STORAGE_QUERY_TYPE {
PropertyStandardQuery = 0,
PropertyExistsQuery,
PropertyMaskQuery,
PropertyQueryMaxDefined
} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;
typedef struct _STORAGE_PROPERTY_QUERY {
STORAGE_PROPERTY_ID PropertyId;
STORAGE_QUERY_TYPE QueryType;
UCHAR AdditionalParameters[1];
} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;
#endif //WIN32
MPT_PORT *mptPorts[NUM_PORTS];
DIAG_TARGET diag_targets[MAX_DEVICES];
EXP_TARGET exp_targets[MAX_DEVICES];
MPT_PORT *mappedPort;
int mappedBus;
int mappedTarget;
int mappedDevHandle;
int mappedValue;
#if __sparc__
int scsi_vhci_fd;
typedef struct
{
char name[NAME_MAX];
char link[PATH_MAX];
} NAME_LINK;
NAME_LINK *dev_rdsk_cache;
int dev_rdsk_count = 0;
NAME_LINK *dev_rmt_cache;
int dev_rmt_count = 0;
NAME_LINK *dev_es_cache;
int dev_es_count = 0;
int device_caches_initialized = 0;
#endif
char *args;
char *argsCurr;
char *fileNames[3];
int numFileNames;
int yesFlag;
int noFlag;
int xFlag;
int gFlag;
int qFlag;
int kFlag;
int wFlag;
FILE *logFile;
int tagType;
int expert;
int paged;
int lines;
void *osDeviceState = NULL;
int iocMask = 0;
int maxLuns = 256;
#if __linux__
int workaroundsTried = FALSE;
int oldMptBaseDetected = 0;
int newMptBaseDetected = 0;
#endif
int diagReturnCode = 0;
#if __linux__ || __alpha__
HANDLE globalFileHandle;
HANDLE globalFileHandle2;
HANDLE globalFileHandle3;
#endif
#define JUST_FC 1
#define JUST_SCSI 2
#define JUST_SAS 4
#define JUST_ALL (JUST_FC | JUST_SCSI | JUST_SAS)
int just = 0;
int virtInit = 0;
char logPrefixBuffer[64];
char pagedBuffer[1024];
#if WIN32
U32 gRetDataLen = 0;
#endif
#define MPI1 if (mpi1)
#define MPI2 if (mpi2)
#define MPI20 if (mpi20)
#define MPI25 if (mpi25)
#define EXP if (expert)
#define FLASH_RESET_INTEL 0xff
#define FLASH_RESET_AMD 0xf0
#define FLASH_IDENTIFY 0x90
#define FLASH_CFI_QUERY 0x98
// MPI2 2.0.10 header file retired CurReplyFrameSize field
// in IOC Facts reply. Define OldReplyFrameSize to use as
// backward compatible reference
#define OldReplyFrameSize IOCMaxChainSegmentSize
/* user command line arguments */
typedef struct
{
int portNums[NUM_PORTS]; /* port numbers specified */
int numPortNums; /* number of port numbers specified */
int boardInfo; /* board info wanted */
int scan; /* boolean */
int info; /* boolean */
int dump; /* boolean */
char linkspeed; /* desired link speed ('a', '1', '2', or '4') */
char topology; /* desired topology ('a', '1', or '2') */
int reset; /* boolean for chip reset */
int linkReset; /* boolean for link reset */
int linkResetFlag; /* boolean for link reset type */
int coalescing; /* boolean */
int ic_depth; /* desired interrupt coalescing depth */
int ic_timeout; /* desired interrupt coalescing timeout */
int monitorInterval; /* desired monitoring interval */
int monitorDuration; /* desired monitoring duration */
} CMNDLINE_ARGS;
unsigned char LoopIdToAlpa[126] =
{
0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6, /* 0 to 9 */
0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, 0xcd, 0xcc, 0xcb, 0xca, /* 10 to 19 */
0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5, /* 20 to 29 */
0xb4, 0xb3, 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, /* 30 to 39 */
0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, 0x98, 0x97, /* 40 to 49 */
0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79, /* 50 to 59 */
0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b, /* 60 to 69 */
0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56, /* 70 to 79 */
0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, /* 80 to 89 */
0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, 0x3a, 0x39, 0x36, 0x35, /* 90 to 99 */
0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, /* 100 to 109 */
0x27, 0x26, 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17, /* 110 to 119 */
0x10, 0x0f, 0x08, 0x04, 0x02, 0x01 /* 120 to 125 */
};
unsigned char AlpaToLoopId[256] =
{
0x7e, 0x7d, 0x7c, 0xff, 0x7b, 0xff, 0xff, 0xff, /* 0x00 to 0x07 */
0x7a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, /* 0x08 to 0x0f */
0x78, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, /* 0x10 to 0x17 */
0x76, 0xff, 0xff, 0x75, 0xff, 0x74, 0x73, 0x72, /* 0x18 to 0x1f */
0xff, 0xff, 0xff, 0x71, 0xff, 0x70, 0x6f, 0x6e, /* 0x20 to 0x27 */
0xff, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0xff, /* 0x28 to 0x2f */
0xff, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0xff, /* 0x30 to 0x37 */
0xff, 0x61, 0x60, 0xff, 0x5f, 0xff, 0xff, 0xff, /* 0x38 to 0x3f */
0xff, 0xff, 0xff, 0x5e, 0xff, 0x5d, 0x5c, 0x5b, /* 0x40 to 0x47 */
0xff, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0xff, /* 0x48 to 0x4f */
0xff, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0xff, /* 0x50 to 0x57 */
0xff, 0x4e, 0x4d, 0xff, 0x4c, 0xff, 0xff, 0xff, /* 0x58 to 0x5f */
0xff, 0xff, 0xff, 0x4b, 0xff, 0x4a, 0x49, 0x48, /* 0x60 to 0x67 */
0xff, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0xff, /* 0x68 to 0x6f */
0xff, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0xff, /* 0x70 to 0x77 */
0xff, 0x3b, 0x3a, 0xff, 0x39, 0xff, 0xff, 0xff, /* 0x78 to 0x7f */
0x38, 0x37, 0x36, 0xff, 0x35, 0xff, 0xff, 0xff, /* 0x80 to 0x87 */
0x34, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x33, /* 0x88 to 0x8f */
0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, /* 0x90 to 0x97 */
0x30, 0xff, 0xff, 0x2f, 0xff, 0x2e, 0x2d, 0x2c, /* 0x98 to 0x9f */
0xff, 0xff, 0xff, 0x2b, 0xff, 0x2a, 0x29, 0x28, /* 0xa0 to 0xa7 */
0xff, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0xff, /* 0xa8 to 0xaf */
0xff, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0xff, /* 0xb0 to 0xb7 */
0xff, 0x1b, 0x1a, 0xff, 0x19, 0xff, 0xff, 0xff, /* 0xb8 to 0xbf */
0xff, 0xff, 0xff, 0x18, 0xff, 0x17, 0x16, 0x15, /* 0xc0 to 0xc7 */
0xff, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0xff, /* 0xc8 to 0xcf */
0xff, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0xff, /* 0xd0 to 0xd7 */
0xff, 0x08, 0x07, 0xff, 0x06, 0xff, 0xff, 0xff, /* 0xd8 to 0xdf */
0x05, 0x04, 0x03, 0xff, 0x02, 0xff, 0xff, 0xff, /* 0xe0 to 0xe7 */
0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, /* 0xe8 to 0xef */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0 to 0xf7 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff /* 0xf8 to 0xff */
};
void outputPaged(FILE *fp, char *buffer);
int printfPaged(const char *format, ...);
int fprintfPaged(FILE *fp, const char *format, ...);
char *logPrefix(MPT_PORT *port);
#if __sparc__
int getNodeInfo(di_node_t node, void *arg);
#endif
int checkReady(MPT_PORT *port);
int checkOperational(MPT_PORT *port, int flag);
int bringOnline(MPT_PORT *port);
int findPorts(void);
int closePorts(int numPorts);
int closePort(MPT_PORT *port);
int getFileName(char *buf, int len, FILE *file, char *fileString, int fileType);
int getString(char *buf, int len, FILE *file);
int getStringFromArgs(char *buf, int len, FILE *file);
int getYesNoAnswer(int defvalue);
int getNumberAnswer(int low, int high, int defvalue);
int getNumberAnswerHex(int low, int high, int defvalue);
int getHexNumberAnswer(U32 *value);
int getHexDoubleNumberAnswer(U32 *value1, U32 *value2);
int parseHexNumberChange(U32 *value);
int readFile(char *name, unsigned char **outBuf, int *outLen);
int queryFile(char *name);
int printWhatString(char *type, unsigned char *buf, int len);
int getCompatible(int deviceId, int type);
int checkCompatible(int deviceId1, int deviceId2, int type);
int doPort(MPT_PORT *port);
int doPortOption(MPT_PORT *port, int option);
int doIdentify(MPT_PORT *port);
int doFirmwareDownload(MPT_PORT *port);
int doFirmwareUpload(MPT_PORT *port);
int doBiosFcodeDownload(MPT_PORT *port);
int doBiosFcodeUpload(MPT_PORT *port, unsigned char **outBuf, int *outLen, int type);
int verifyBiosFcodeImage(MPT_PORT *port, unsigned char *buf, int len, int type);
int splitBiosImage(MPT_PORT *port, unsigned char **buf1, int *len1, unsigned char **buf2, int *len2);
int fixupBiosFcodeImage(MPT_PORT *port, unsigned char *buf, int len, int last);
int doSeepromDownload(MPT_PORT *port);
int doSeepromUpload(MPT_PORT *port);
int doScanForDevices(MPT_PORT *port, int flag);
int doScanForLuns(MPT_PORT *port, int flag , int option);
int doConfigPage(MPT_PORT *port);
int doInterruptCoalescingValues(MPT_PORT *port, int timeout, int depth);
int doIocSettings(MPT_PORT *port);
int doScsiInitiatorSettings(MPT_PORT *port);
char *syncToMt(int sync);
char *syncToMb(int sync, int wide);
int doScsiTargetSettings(MPT_PORT *port);
int doFcLinkSpeedValue(MPT_PORT *port, int t);
int doFcTopologyValue(MPT_PORT *port, int t);
int doFcPortOffline(MPT_PORT *port);
int doFcPortOnline(MPT_PORT *port);
int doFcTopologyNLPort(MPT_PORT *port);
int doFcTopologyNPort(MPT_PORT *port);
int doFcSpecialMode(MPT_PORT *port, int enable, int permanent);
int doFcPortSettings(MPT_PORT *port);
int doFcChangeWwn(MPT_PORT *port);
int doSasPhyOnOffline(MPT_PORT *port, int onoff);
int doSasIoUnitSettings(MPT_PORT *port);
int doSasChangeWwid(MPT_PORT *port, int checkZero);
int doIoUnitSettings(MPT_PORT *port);
int doFcPersistentMappings(MPT_PORT *port, int command);
int doSasPersistentMappings(MPT_PORT *port, int command);
int doDisplayLoggedInDevices(MPT_PORT *port);
int doDisplayAttachedDevices(MPT_PORT *port);
int showSasDiscoveryErrors(MPT_PORT *port);
int doShowPortAliases(MPT_PORT *port);
int doShowExpanderRoutingTables(MPT_PORT *port);
int doTestConfigPageActions(MPT_PORT *port);
int selectDevice(MPT_PORT *port, int *dev_bus, int *dev_target);
int selectDeviceRWMedia(MPT_PORT *port);
int selectDeviceRWBuffer(MPT_PORT *port);
int getExpanderType(int componentId, U8 *componentVendorId, U8 *vendorId);
char *printExpanderType(int expanderType);
int selectExpander(MPT_PORT *port, int *ses_bus, int *ses_target, U8 *phys_port, _U64 *sas_addr, int *expanderType);
int doDiagnostics(MPT_PORT *port, int command);
void generatePattern(int pattern, void *buf, int len);
void format64bitDecimal(uint64_t number, char *buf, int len);
int doInquiryTest(MPT_PORT *port);
int doWriteBufferReadBufferCompareTest(MPT_PORT *port);
int getEedpMode(MPT_PORT *port, int eedp);
int doReadTest(MPT_PORT *port);
int doWriteReadCompareTest(MPT_PORT *port);
int doWriteTest(MPT_PORT *port);
int doReadCompareTest(MPT_PORT *port);
int doTestUnitReadyTest(MPT_PORT *port);
int doLogSenseTest(MPT_PORT *port);
int doReadCapacityTest(MPT_PORT *port);
int doModePageTest(MPT_PORT *port);
int doEchoTest(MPT_PORT *port);
int doReadLinkErrorStatusTest(MPT_PORT *port);
int doDisplayPortCounters(MPT_PORT *port);
int doClearPortCounters(MPT_PORT *port);
int doTriggerAnalyzerWithEcho(MPT_PORT *port);
int isSata(MPT_PORT *port, int bus, int target);
int isSsd(MPT_PORT *port, int bus, int target);
int getPath(MPT_PORT *port, int bus, int target, PATH *path);
int getParent(MPT_PORT *port, int bus, int target, int *parent);
int isRaidPhysDisk(MPT_PORT *port, int bus, int target, int *physdisk);
int isRaidPhysDisk2(MPT_PORT *port, int bus, int target, int *physdisk);
int doReadLogicalBlocks(MPT_PORT *port);
int doWriteLogicalBlocks(MPT_PORT *port);
int doVerifyLogicalBlocks(MPT_PORT *port);
int doDiagnosticPageTest(MPT_PORT *port);
int doInjectRepairMediaError(MPT_PORT *port, int inject);
int doSoftwareWriteProtect(MPT_PORT *port, int flag);
int doReadWriteCache(MPT_PORT *port, int flag);
int doDisplayPhyCounters(MPT_PORT *port);
int doClearPhyCounters(MPT_PORT *port);
int doSataIdentifyDeviceTest(MPT_PORT *port);
int doSataClearAffiliationTest(MPT_PORT *port);
int doSataSmartReadTest(MPT_PORT *port);
int doSepTest(MPT_PORT *port);
int doProdSpecSasIoUnitControl(MPT_PORT *port);
int doProdSpecSasIoUnitControl2(MPT_PORT *port);
int doDiagDataUpload(MPT_PORT *port);
int doReportLunsTest(MPT_PORT *port);
int doDriveFirmwareDownload(MPT_PORT *port);
int doSesDownloadMicrocode(MPT_PORT *port, int bus, int target, int lun,
int mode, int id, int offset, int size, unsigned char *buf, int len);
int doExpanderChangeMfgDataFields(MPT_PORT *port);
int doExpanderGetSetMfgDataFields(MPT_PORT *port, int bus, int target, U64 *sasAddr, U64 *enclLogId, U8 *macAddr);
int doExpanderFirmwareDownload(MPT_PORT *port);
int doReadBufferFirmwareUpload(MPT_PORT *port);
int doRaidActions(MPT_PORT *port, int command);
int selectVolume(MPT_PORT *port, IOCPage2_t *IOCPage2, int *volumeOut);
int doShowVolumes(MPT_PORT *port, IOCPage2_t *IOCPage2, IOCPage3_t *IOCPage3);
int doShowPhysDisks(MPT_PORT *port, IOCPage2_t *IOCPage2, IOCPage3_t *IOCPage3);
int doGetVolumeState(MPT_PORT *port, IOCPage2_t *IOCPage2);
int doWaitForResync(MPT_PORT *port, IOCPage2_t *IOCPage2);
int doModifyVolume(MPT_PORT *port, IOCPage2_t *IOCPage2, int action, char *string);
int doCreateVolume(MPT_PORT *port, IOCPage2_t *IOCPage2, IOCPage3_t *IOCPage3);
int doDeleteVolume(MPT_PORT *port, IOCPage2_t *IOCPage2);
int doVolumeSettings(MPT_PORT *port, IOCPage2_t *IOCPage2);
int doVolumeName(MPT_PORT *port, IOCPage2_t *IOCPage2);
int doDriveFirmwareUpdateMode(MPT_PORT *port, IOCPage2_t *IOCPage2, IOCPage3_t *IOCPage3, int flag);
int doModifyPhysDisk(MPT_PORT *port, IOCPage2_t *IOCPage2, IOCPage3_t *IOCPage3, int action, char *string);
int doCreatePhysDisk(MPT_PORT *port, IOCPage2_t *IOCPage2);
int doPhysDiskSettings(MPT_PORT *port, IOCPage2_t *IOCPage2, IOCPage3_t *IOCPage3);
int doCreateHotSpare(MPT_PORT *port, IOCPage2_t *IOCPage2, IOCPage3_t *IOCPage3);
int doDeleteHotSpare(MPT_PORT *port, IOCPage2_t *IOCPage2, IOCPage3_t *IOCPage3);
int showHiddenDevices(MPT_PORT *port);
int doRaidActions2(MPT_PORT *port, int command);
int selectVolume2(MPT_PORT *port, int *volumeOut, int *handleOut);
void doShowVolumeState2(int volume, int volState, int volFlag, int useVolume);
int doShowVolumes2(MPT_PORT *port, Mpi2IOCPage6_t *IOCPage6);
int doShowPhysDisks2(MPT_PORT *port, Mpi2IOCPage6_t *IOCPage6);
int doGetVolumeState2(MPT_PORT *port);
int doWaitForResync2(MPT_PORT *port);
int doModifyVolume2(MPT_PORT *port, int action, char *string);
int doCreateVolume2(MPT_PORT *port, Mpi2IOCPage6_t *IOCPage6);
int doDeleteVolume2(MPT_PORT *port, Mpi2IOCPage6_t *IOCPage6);
int doVolumeSettings2(MPT_PORT *port);
int doVolumeName2(MPT_PORT *port);
int doVolumeIRCC2(MPT_PORT *port);
int doVolumeStopIRCC2(MPT_PORT *port);
int doVolumeOCE(MPT_PORT *port);
int doDriveFirmwareUpdateMode2(MPT_PORT *port, Mpi2IOCPage6_t *IOCPage6, int flag);
int doModifyPhysDisk2(MPT_PORT *port, Mpi2IOCPage6_t *IOCPage6, int action, char *string);
int doCreateHotSpare2(MPT_PORT *port, Mpi2IOCPage6_t *IOCPage6);
int doDeleteHotSpare2(MPT_PORT *port, Mpi2IOCPage6_t *IOCPage6);
int showHiddenDevices2(MPT_PORT *port);
int getRaidCounts(MPT_PORT *port, int activeOnly, int *numVolumes, int *numPhysDisks, int *numHotSpares);
int getRaidConfig(MPT_PORT *port, int elementType, int devHandle, int physDiskNum, Mpi2RaidConfigurationPage0_t **RaidConfigPage0);
int doResetBus(MPT_PORT *port);
int doResetTarget(MPT_PORT *port);
int doClearAca(MPT_PORT *port);
int doBeacon(MPT_PORT *port, int on_off);
int doDisplaySfpPages(MPT_PORT *port);
int doClean(MPT_PORT *port);
int doFcManagementTools(MPT_PORT *port);
int doRemoveSasDevice(MPT_PORT *port);
int doDisplayLogEntries(MPT_PORT *port);
int doClearLogEntries(MPT_PORT *port);
int doSasForceFullDiscovery(MPT_PORT *port);
int doFirmwareDownloadBoot(MPT_PORT *port);
int eventQuery(MPT_PORT *port, int *entries, int *types);
int eventEnable(MPT_PORT *port, int *types);
int eventReport(MPT_PORT *port, int entries, EVENT2 *events);
int doDisplayCurrentEvents(MPT_PORT *port);
int doDisplayTransferStatistics(MPT_PORT *port);
int doDisplayTransferStatisticsAll(int numPorts, MPT_PORT *ports[], int interval, int duration);
int isRaidVolume(MPT_PORT *port, int bus, int target);
int isRaidVolume2(MPT_PORT *port, int bus, int target);
void convertBusTarget(MPT_PORT *port, int *bus, int *target, int lun);
#if __sparc__
void cachePathLinks(char *prefix, char *suffix, NAME_LINK **cacheOut, int *countOut);
int findPathLink(MPT_PORT *port, char *prefix, NAME_LINK *cache, int count, char *path, char *buf);
int getPortPhyMap(MPT_PORT *port);
#endif
int getOsDeviceName(MPT_PORT *port, int bus, int target, int lun, char *buf, int len, int type);
int doDisplayOsDeviceNames(MPT_PORT *port);
int diagBufferAction(MPT_PORT *port, int action, void *buf, int size);
int diagBufferAction2(MPT_PORT *port, int action, void *buf, int size);
int diagBufferRegister(MPT_PORT *port, int type, int id, int size);
int diagBufferRegister2(MPT_PORT *port, int type, int id, int size);
int diagBufferUnregister(MPT_PORT *port, int id);
int diagBufferQuery(MPT_PORT *port, int type, int id, int *flags, int *size);
int diagBufferQuery2(MPT_PORT *port, int type, int id, int *flags, int *size);
int diagBufferReadBuffer(MPT_PORT *port, int id, char *name, int file, int *sizeIn, int header);
int diagBufferRelease(MPT_PORT *port, int type, int id);
int doDiagBuffer(MPT_PORT *port);
int doFlashUpload(MPT_PORT *port);
int doDisplayVersionInfo(MPT_PORT *port);
void showVpdData(MPT_PORT *port, ManufacturingPage1_t *ManufacturingPage1);
int doDisplayVpdInfo(MPT_PORT *port);
int doProgramVpdInfo(MPT_PORT *port);
int doReadChipMemoryRegions(MPT_PORT *port, U32 addr, U32 *buf, int num);
int doWriteChipMemoryRegions(MPT_PORT *port, U32 addr, U32 *buf, int num);
int doDumpRegisters(MPT_PORT *port);
int doEnableDiagAccess(MPT_PORT *port, U32 *diagOrig);
int readLocalMemory(MPT_PORT *port, U32 addr, U32 *data, U32 temp);
int doDumpChipMemoryRegions(MPT_PORT *port);
int doReadModifyChipMemoryLocations(MPT_PORT *port);
int doDumpFcTraceBuffer(MPT_PORT *port);
int doForceFirmwareFault(MPT_PORT *port);
int doReadWriteExpanderMemory(MPT_PORT *port);
int doReadWriteExpanderIstwiDevice(MPT_PORT *port);
int doResetExpander(MPT_PORT *port);
int sendResetExpander(MPT_PORT *port, U8 physical_port, _U64 sas_address, U32 addr, U32 data);
int setFlashWrite(MPT_PORT *port, U32 flash_csr, U32 flash_csr_wr_en, int on);
U32 readFlash(MPT_PORT *port, U32 flash_add, int offset);
int writeFlash(MPT_PORT *port, U32 flash_add, int offset, U32 data);
void resetFlash(MPT_PORT *port, U32 flash_csr, U32 flash_csr_wr_en, U32 flash_add, int intel);
int doFlashInfo(MPT_PORT *port);
int doReadRegister(MPT_PORT *port, U32 offset, U32 *data);
int doWriteRegister(MPT_PORT *port, U32 offset, U32 *data);
int doReadWriteRegister(MPT_PORT *port, U32 offset, U32 *data, int command);
int doDumpPciConfigSpace(MPT_PORT *port);
int doShowNonDefaultSettings(MPT_PORT *port);
int doRestoreDefaultSettings(MPT_PORT *port);
int doDefaultPhyRegsSettings(MPT_PORT *port);
int doFcChangePersonalWwn(MPT_PORT *port);
int doGIEL(MPT_PORT *port);
int doGID_FT(MPT_PORT *port);
int doGA_NXT(MPT_PORT *port);
int doExLinkServiceSend(MPT_PORT *port);
int doResetFcLink(MPT_PORT *port, int flag);
int doScsiCdb(MPT_PORT *port);
int doSataPassthroughSend(MPT_PORT *port);
int doSmpPassthroughSend(MPT_PORT *port);
int doResetSasLink(MPT_PORT *port, int flag);
int doDumpPortState(MPT_PORT *port, int flag);
int doPortStateSummary(MPT_PORT *port);
int getChipName(MPT_PORT *port);
int getPortInfo(MPT_PORT *port);
int getPortInfo2(MPT_PORT *port);
int updatePortInfo(MPT_PORT *port);
int updatePortInfo2(MPT_PORT *port);
int getBoardInfo(MPT_PORT *port);
int showBoardInfo(MPT_PORT *port, int flag);
int dumpFcDevicePages(MPT_PORT *port);
int dumpSasDevicePages(MPT_PORT *port);
int showPortInfo(MPT_PORT *port);
int showPortInfoHeader(MPT_PORT *port);
int getDeviceInfo(MPT_PORT *port, int bus, int target, char *buf, int len);
int getDeviceInfoHeader(MPT_PORT *port, char *buf, int len);
int getIocFacts(MPT_PORT *port, IOCFactsReply_t *rep);
int getIocFacts2(MPT_PORT *port, Mpi2IOCFactsReply_t *rep);
int getPortFacts(MPT_PORT *port, PortFactsReply_t *rep);
int getPortFacts2(MPT_PORT *port, Mpi2PortFactsReply_t *rep);
int doConfigPageRequest(MPT_PORT *port, void *req, int reqSize, void *rep, int repSize,
void *payIn, int payInSize, void *payOut, int payOutSize, int timeOut);
int getConfigPageHeader(MPT_PORT *port, int type, int number, int address, ConfigReply_t *repOut);
int getConfigPageLength(MPT_PORT *port, int type, int number, int address, int *length);
int getConfigPageAction(MPT_PORT *port, int action, int type, int number, int address, void *page, int pageSize);
int getConfigPage(MPT_PORT *port, int type, int number, int address, void *page, int pageSize);
void *getConfigPageActionAlloc(MPT_PORT *port, int action, int type, int number, int address, int *length);
void *getConfigPageAlloc(MPT_PORT *port, int type, int number, int address, int *length);
int setConfigPageAction(MPT_PORT *port, int action, int type, int number, int address, void *page, int pageSize);
int setConfigPage(MPT_PORT *port, int type, int number, int address, void *page, int pageSize);
int showConfigPage(MPT_PORT *port, char *string, void *page, int length);
int getProperty(MPT_PORT *port, char *name, char *buf, int bufLen);
void setName(MPT_PORT *port, int bus, int target, void *req);
int setMaxBusTarget(MPT_PORT *port);
int mapDevHandleToBusTarget(MPT_PORT *port, int dev_handle, int *bus, int *target);
int mapBusTargetToDevHandle(MPT_PORT *port, int bus, int target, int *dev_handle);
int mapBTDH(MPT_PORT *port, int *bus, int *target, int *dev_handle);
int mapOsToHwTarget(MPT_PORT *port, int target);
int doTestUnitReady(MPT_PORT *port, int bus, int target, int lun);
int doInquiry(MPT_PORT *port, int bus, int target, int lun, unsigned char *buf, int len);
int doInquiryVpdPage(MPT_PORT *port, int bus, int target, int lun, int page, unsigned char *buf, int len);
int doLogSense(MPT_PORT *port, int bus, int target, int lun, int page, int pc, unsigned char *buf, int len);
int doLogSelect(MPT_PORT *port, int bus, int target, int lun, int pc, int save, unsigned char *buf, int len);
int doReadBlockLimits(MPT_PORT *port, int bus, int target, int lun, unsigned char *buf, int len);
int doReadCapacity(MPT_PORT *port, int bus, int target, int lun, unsigned char *buf, int len);
int doReadCapacity16(MPT_PORT *port, int bus, int target, int lun, unsigned char *buf, int len);
int doModeSense(MPT_PORT *port, int bus, int target, int lun, int page, int control, int dbd, unsigned char *buf, int len);
int doModeSelect(MPT_PORT *port, int bus, int target, int lun, int save, unsigned char *buf, int len);
int doReadBuffer(MPT_PORT *port, int bus, int target, int lun, int mode, unsigned char *buf, int len);
int doWriteBuffer(MPT_PORT *port, int bus, int target, int lun, int mode, unsigned char *buf, int len);
int doReadBufferFull(MPT_PORT *port, int bus, int target, int lun, int mode, int id, int offset, unsigned char *buf, int len);
int doWriteBufferFull(MPT_PORT *port, int bus, int target, int lun, int mode, int id, int offset, unsigned char *buf, int len);
int doRead(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int lbns, int mode, unsigned char *buf, int len);
int doWrite(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int lbns, int mode, unsigned char *buf, int len);
int doVerify(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int lbns, int mode, unsigned char *buf, int len);
int doRead32(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int lbns, int mode, unsigned char *buf, int len);
int doWrite32(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int lbns, int mode, unsigned char *buf, int len);
int doReadLong(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int mode, unsigned char *buf, int len, int *resid);
int doWriteLong(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int mode, unsigned char *buf, int len, int *resid);
int doReportLuns(MPT_PORT *port, int bus, int target, unsigned char *buf, int len);
int doReceiveDiagnosticResults(MPT_PORT *port, int bus, int target, int lun, int page, unsigned char *buf, int len);
int doSendDiagnostic(MPT_PORT *port, int bus, int target, int lun, unsigned char *buf, int len);
int doScsiIo(MPT_PORT *port, int bus, int target, int raid, void *req, int reqSize, SCSI_REPLY *rep, int repSize,
void *payIn, int payInSize, void *payOut, int payOutSize, int timeOut);
int doReadLongSata(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int mode, unsigned char *buf, int len);
int doWriteLongSata(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int mode, unsigned char *buf, int len);
int doFwDownload(MPT_PORT *port, int type, unsigned char *buf, int len, int offset);
int doFwUpload(MPT_PORT *port, int type, unsigned char *buf, int len, int offset, int *outLen);
int doIocInit(MPT_PORT *port, int WhoInit);
char *translateSmpFunctionResult(int functionResult);
int doSmpReportMfg(MPT_PORT *port, _U64 SASAddress, U8 physicalPort, PTR_SMP_REPORT_MANUFACTURER_INFO_RESPONSE smpResp, int *respDataLenth);
int doSmpPassthrough(MPT_PORT *port, U8 smpPort, _U64 smpAddr, void *smpReq, int smpReqSize, void *smpRsp, int smpRspSize, int *respDataLength);
int doResetPort(MPT_PORT *port);
void doLogMptCommandReq(MPT_PORT *port, void *req, int reqSize);
void doLogMptCommandRep(MPT_PORT *port, void *rep, int repSize, int status);
void logMptCommandReq(MPT_PORT *port, void *req, int reqSize);
void logMptCommandRep(MPT_PORT *port, void *req, int reqSize, void *rep, int repSize, int status);
int doMptCommand(MPT_PORT *port, void *req, int reqSize, void *rep, int repSize,
void *payIn, int payInSize, void *payOut, int payOutSize, int timeOut);
int doMptCommandCheck(MPT_PORT *port, void *req, int reqSize, void *rep, int repSize,
void *payIn, int payInSize, void *payOut, int payOutSize, int timeOut);
char *translateIocStatus(int ioc_status);
void displayByteData(unsigned char *buf, int len);
void dumpMemory(void *buf, int len, char *string);
void dumpMemoryWide(void *buf, int len, char *string);
void initT10Crc(void);
unsigned int genT10Crc(unsigned char *buf);
unsigned int genLbCrc(unsigned char *buf, int len);
int checkRemoveT10(MPT_PORT *port, unsigned int lbn, int lbns, unsigned char *buf_in, unsigned char *buf_out, int len);
int checkRemoveLb(MPT_PORT *port, unsigned int lbn, int lbns, unsigned char *buf_in, unsigned char *buf_out, int len, int do_crc);
int insertT10(MPT_PORT *port, unsigned int lbn, int lbns, unsigned char *buf_in, unsigned char *buf_out, int len);
int insertLb(MPT_PORT *port, unsigned int lbn, int lbns, unsigned char *buf_in, unsigned char *buf_out, int len, int do_crc);
void waitForFile(char *name);
char *skipLine(char *buf);
void removeLine(char *buf);
int getNamedItem(MPT_PORT *port, char *name, char *buf, int type, void *address);
int updateConfigPage(MPT_PORT *port, char *string, void *page);
int doWriteFcManufacturingInfo(MPT_PORT *port);
int doWriteSasManufacturingInfo(MPT_PORT *port);
int concatenateSasFirmwareNvdata(void);
char *getSasProductId(char *nvdata);
int selectAltaDevice(MPT_PORT *port, int *dev_bus, int *dev_target);
int doAltaDiagnostics(MPT_PORT *port, int command);
int doAltaProgramManufacturingInfo(MPT_PORT *port);
int doAltaDisplayManufacturingInfo(MPT_PORT *port);
int doResetAlta(MPT_PORT *port);
char *translateExpanderEventCode(int code);
int decodeExpanderLogEntries(FILE *file, unsigned char *buf, int length);
int doDisplayExpanderLogEntries(MPT_PORT *port);
int doClearExpanderLogEntries(MPT_PORT *port);
int doUartDebugConsole(MPT_PORT *port);
int getAdapterPropertiesMaxPages(MPT_PORT *port, int *maxPages);
int doSendPowerManagementControlMPI(MPT_PORT *port);
int doIoUnit7Settings(MPT_PORT *port);
int doSasIoUnit8Settings(MPT_PORT *port);
int dumpSasDevicePage0sLong(MPT_PORT *port);
int doExpanderUart(MPT_PORT *port);
#if LSIINTERNAL
#include "internal/sc.c"
#endif
#if DOS || EFI
#include "mpt.c"
#undef mpi1
#undef mpi2
#undef mpi20
#undef mpi25
#endif
#define mpi1 (port->mptVersion < MPI2_VERSION_02_00)
#define mpi2 (port->mptVersion >= MPI2_VERSION_02_00)
#define mpi20 ((port->mptVersion >= MPI2_VERSION_02_00) && (port->mptVersion < MPI2_VERSION_02_05))
#define mpi25 (port->mptVersion >= MPI2_VERSION_02_05)
void
outputPaged(FILE *fp, char *buffer)
{
char buf[16];
char c;
fputs(buffer, fp);
if (paged && fp == stdout)
{
while ((c = *buffer++) != '\0')
{
if (c == '\n')
lines++;
}
if (lines >= paged)
{
fputs("--more, hit RETURN--", stdout);
if (fgets(buf, sizeof buf, stdin));
lines = 0;
}
}
}
int
printfPaged(const char *format, ...)
{
va_list args;
int n;
va_start(args, format);
n = vsprintf(pagedBuffer, format, args);
va_end(args);
outputPaged(stdout, pagedBuffer);
return n;
}
int
fprintfPaged(FILE *fp, const char *format, ...)
{
va_list args;
int n;
va_start(args, format);
n = vsprintf(pagedBuffer, format, args);
va_end(args);
outputPaged(fp, pagedBuffer);
return n;
}
char *
logPrefix(MPT_PORT *port)
{
time_t now;
time(&now);
if (port)
sprintf(logPrefixBuffer, "%s %s", ctime(&now), port->portName);
else
sprintf(logPrefixBuffer, "%s", ctime(&now));
if (logPrefixBuffer[8] == ' ')
logPrefixBuffer[8] = '0';
if (port)
logPrefixBuffer[24]= ':';
else
logPrefixBuffer[24]= '\0';
return logPrefixBuffer;
}
int _cdecl
main(int argc, char *argv[])
{
int portNumber;
MPT_PORT *port;
int numPorts;
int i;
int arg;
CMNDLINE_ARGS cargs;
char *pArg;
char *type;
int n;
int t;
extern int optind;
extern int optopt;
#if DOS
setvbuf(stdout, NULL, _IONBF, 0);
#endif
memset(mptPorts, 0, sizeof mptPorts);
initT10Crc();
args = NULL;
argsCurr = NULL;
pArg = NULL;
numFileNames = 0;
yesFlag = FALSE;
noFlag = FALSE;
xFlag = FALSE;
gFlag = FALSE;
qFlag = FALSE;
kFlag = FALSE;
wFlag = 0;
logFile = NULL;
tagType = MPI_SCSIIO_CONTROL_SIMPLEQ;
expert = FALSE;
paged = 0;
memset(&cargs, 0, sizeof(CMNDLINE_ARGS));
printf("\nLSI Logic MPT Configuration Utility, %s\n", LSIUTIL_VERSION);
if (argc > 1)
{
while ((arg = getopt(argc, argv, "?a:bc:def:ghij:kl:m:np:qrst:uv:wxyz018")) != EOF)
{
switch (arg)
{
case '?':
if (optopt)
{
optopt = 0;
break;
}
case 'h':
printf(
"\nHelp Usage\n"
"Invoking lsiutil with no arguments will start an interactive session.\n\n"
" -e Turn on Expert Mode (more menu options).\n"
" -w, -ww, -www Log internal operations to lsiutil.log, for debug.\n"
" -y Answer yes to yes/no questions whose default is yes.\n"
" -n Answer no to yes/no questions whose default is no.\n"
" -j type[,type] Include just ports of type 'type' (FC, SCSI, SAS).\n"
" -x Concatenate SAS firmware and NVDATA files.\n\n");
printf(
"Display Options\n"
"usage: lsiutil [ -p portNumber ] [ -u ][ -s ] [ -d ] [ -i ] [ -b ]\n"
" -p portNumber Specify the port number to operate on.\n"
" If not specified, all ports are used.\n"
" -u Use untagged, rather than tagged, SCSI commands.\n"
" -s Scan for and display all targets.\n"
" -d Dump all config pages.\n"
" -i Display port settings.\n"
" -b Show board manufacturing information.\n"
" -m freq[,time] Monitor port performance, updating the display\n"
" every 'freq' seconds, for 'time' seconds.\n\n");
printf(
"Examples:\n"
"1. to display the port settings and targets for port 1:\n"
" lsiutil -p 1 -i -s\n"
"2. to display the targets found on all known ports:\n"
" lsiutil -s\n\n");
printf(
"Operational Options\n"
"usage: lsiutil -p portNumber [ -l linkSpeed ] [ -t topology ]\n"
" [ -c timeout,depth ] [ -r ]\n"
" -p portNumber Specify the port number to operate on.\n"
" Required parameter for operational options.\n"
" -l linkSpeed Set link speed. Valid options for linkSpeed are:\n"
" 'a' Auto link speed negotiation\n"
" '1' Force 1Gb link speed\n"
" '2' Force 2Gb link speed\n"
" '4' Force 4Gb link speed\n");
printf(
" -t topology Set topology. Valid options for topology are:\n"
" 'a' Auto topology negotiation\n"
" '1' Force NL_Port topology\n"
" '2' Force N_Port topology\n"
" -c timeout,depth Set interrupt coalescing values.\n"
" Timeout is a value in microseconds between\n"
" 1 and 1000. Depth is a value between 1 and 128.\n"
" Setting either or both values to zero will\n"
" disable interrupt coalescing for that port.\n"
" -r Perform a chip reset on the given port.\n"
" -z Perform an FC link reset on the given port.\n");
printf(
"NOTE: In order for linkSpeed, topology, or interrupt coalescing\n"
" settings to take effect, a chip reset is necessary.\n\n"
"Examples:\n"
"1. to force linkspeed to 1Gb on port 2:\n"
" lsiutil -p 2 -l 1\n"
"2. to set interrupt coalescing to a timeout of 200ms with\n"
" a depth of 9 and to force N_Port topology on port 1:\n"
" lsiutil -p 1 -c 200,9 -t 2\n\n"
);
return 0;
case 'a':
args = optarg;
break;
case 'b':
cargs.boardInfo = TRUE;
break;
case 'c':
if (sscanf(optarg, "%d,%d", &cargs.ic_timeout, &cargs.ic_depth) != 2)
{
printf("ERROR: Invalid argument %s for interrupt coalescing.\n", optarg);
printf("Must specify two decimal numbers -- timeout,depth\n");
return EINVAL;
}
else
{
if (cargs.ic_timeout < 0)
cargs.ic_timeout = 0;
if (cargs.ic_timeout > 1000)
cargs.ic_timeout = 1000;
if (cargs.ic_depth < 0)
cargs.ic_depth = 0;
if (cargs.ic_depth > 128)
cargs.ic_depth = 128;
cargs.coalescing = TRUE;
}
break;
case 'd':
cargs.dump = TRUE;
break;
case 'e':
expert = TRUE;
break;
case 'f':
while (TRUE)
{
if (numFileNames < 3)
{
fileNames[numFileNames++] = optarg;
}
else
{
printf("ERROR: At most, three filenames may be supplied\n");
return EINVAL;
}
optarg = strchr(optarg, ',');
if (optarg)
*optarg++ = '\0';
else
break;
}
break;
case 'g':
gFlag = TRUE;
break;
case 'i':
cargs.info = TRUE;
break;
case 'j':
while (TRUE)
{
type = optarg;
if (type == NULL)
break;
optarg = strchr(optarg, ',');
if (optarg)
*optarg++ = '\0';
if (strcasecmp(type, "good") == 0)
just |= JUST_ALL;
else if (strcasecmp(type, "fc") == 0)
just |= JUST_FC;
else if (strcasecmp(type, "scsi") == 0)
just |= JUST_SCSI;
else if (strcasecmp(type, "sas") == 0)
just |= JUST_SAS;
else
{
printf("ERROR: Invalid type %s.\n", type);
printf("Valid types are FC, SCSI, and SAS\n");
return EINVAL;
}
}
break;
case 'k':
kFlag = TRUE;
break;
case 'l':
if (*optarg == 'a' || *optarg == '1' || *optarg == '2' || *optarg == '4')
cargs.linkspeed = *optarg;
else
{
printf("ERROR: Invalid link speed %s.\n", optarg);
printf("Valid link speeds are: 'a' for Auto, '1', '2', or '4' for 1Gb, 2Gb, or 4Gb\n");
return EINVAL;
}
break;
case 'm':
cargs.monitorDuration = 0;
if (sscanf(optarg, "%d,%d", &cargs.monitorInterval, &cargs.monitorDuration) != 2 &&
sscanf(optarg, "%d", &cargs.monitorInterval) != 1)
{
printf("ERROR: Invalid argument %s for monitoring interval (and duration).\n", optarg);
printf("Must specify a decimal number and optionally a second decimal number\n");
return EINVAL;
}
else
{
if (cargs.monitorInterval < 0)
cargs.monitorInterval = 0;
if (cargs.monitorDuration < 0)
cargs.monitorDuration = 0;
}
break;
case 'n':
noFlag = TRUE;
break;
case 'p':
pArg = optarg;
break;
case 'q':
qFlag = TRUE;
break;
case 'r':
cargs.reset = TRUE;
break;
case 's':
cargs.scan = TRUE;
break;
case 't':
if (*optarg == 'a' || *optarg == '1' || *optarg == '2')
cargs.topology = *optarg;
else
{
printf("ERROR: Invalid topology %s.\n", optarg);
printf("Valid topologys are: 'a' for Auto, '1' for NL_Port, or '2' for N_Port\n");
return EINVAL;
}
break;
case 'u':
tagType = MPI_SCSIIO_CONTROL_UNTAGGED;
break;
case 'v':
if (sscanf(optarg, "%d", &virtInit) != 1)
{
printf("ERROR: Invalid argument %s for virtual initiator.\n", optarg);
printf("Must specify a decimal number\n");
return EINVAL;
}
break;
case 'w':
wFlag++;
break;
case 'x':
xFlag = TRUE;
break;
case 'y':
yesFlag = TRUE;
break;
case 'z':
cargs.linkReset = TRUE;
cargs.linkResetFlag = FALSE;
break;
case '0':
iocMask |= (1<<0);
break;
case '1':
iocMask |= (1<<1);
break;
case '8':
maxLuns = 8;
break;
default:
return EINVAL;
}
}
if (wFlag)
{
logFile = fopen("lsiutil.log", "a");
if (logFile)
{
fprintf(logFile, "%s: Logging started at level %d\n", logPrefix(NULL), wFlag);
}
else
{
printf("Open failure for file lsiutil.log!\n");
perror("Error is");
logFile = stderr;
}
}
if (xFlag)
{
if (pArg || args || cargs.info || cargs.scan || cargs.dump || cargs.boardInfo ||
cargs.linkspeed || cargs.topology || cargs.coalescing || cargs.reset || cargs.linkReset ||
cargs.monitorInterval || iocMask)
{
printf("-x can be mixed with -f, -n, and -y, only\n");
return EINVAL;
}
if (numFileNames == 0)
{
if (optind == argc - 3)
{
while (optind < argc)
fileNames[numFileNames++] = argv[optind++];
}
else if (optind < argc)
{
optarg = argv[optind++];
while (TRUE)
{
if (numFileNames < 3)
{
fileNames[numFileNames++] = optarg;
}
else
{
printf("ERROR: At most, three filenames may be supplied\n");
return EINVAL;
}
optarg = strchr(optarg, ',');
if (optarg)
*optarg++ = '\0';
else
break;
}
}
}
while (optind < argc)
printf("%s: invalid argument -- %s\n", argv[0], argv[optind++]);
printf("\n");
concatenateSasFirmwareNvdata();
return 0;
}
if (qFlag)
{
char *name;
if (pArg || args || cargs.info || cargs.scan || cargs.dump || cargs.boardInfo ||
cargs.linkspeed || cargs.topology || cargs.coalescing || cargs.reset || cargs.linkReset ||
cargs.monitorInterval || iocMask)
{
printf("-q can be mixed with -f only\n");
return EINVAL;
}
if (numFileNames == 0)
{
while (optind < argc)
{
optarg = argv[optind++];
while (TRUE)
{
name = optarg;
optarg = strchr(optarg, ',');
if (optarg)
*optarg++ = '\0';
queryFile(name);
if (!optarg)
break;
}
}
}
else
{
while (optind < argc)
printf("%s: invalid argument -- %s\n", argv[0], argv[optind++]);
for (i = 0; i < numFileNames; i++)
{
queryFile(fileNames[i]);
}
}
return 0;
}
numPorts = findPorts();
printf("\n%d MPT Port%s found\n", numPorts, numPorts == 1 ? "" : "s");
if (pArg)
{
optarg = pArg;
if (numPorts)
{
t = 0;
while (sscanf(optarg, "%d%n", &i, &n) >= 1)
{
if (i <= 0)
{
cargs.numPortNums = 0;
break;
}
if (t == 1)
{
if (i < cargs.portNums[cargs.numPortNums - 1])
{
cargs.numPortNums = 0;
break;
}
while (i > cargs.portNums[cargs.numPortNums - 1])
{
t = cargs.portNums[cargs.numPortNums - 1] + 1;
if (t <= numPorts && cargs.numPortNums < NUM_PORTS)
{
cargs.portNums[cargs.numPortNums] = t;
cargs.numPortNums++;
}
else
break;
}
t = 0;
}
else
{
if (i <= numPorts && cargs.numPortNums < NUM_PORTS)
{
cargs.portNums[cargs.numPortNums] = i;
cargs.numPortNums++;
}
}
if (optarg[n] == '\0')
{
optarg += n;
break;
}
else if (optarg[n] == ',')
{
optarg += n + 1;
}
else if (optarg[n] == '-' && t == 0)
{
optarg += n + 1;
t = 1;
}
else
{
cargs.numPortNums = 0;
break;
}
}
if (optarg[0] != '\0')
cargs.numPortNums = 0;
if (cargs.numPortNums == 0)
{
printf("ERROR: No such port. Valid ports are:\n");
printf("\n Port Name Chip Vendor/Type/Rev MPT Rev Firmware Rev IOC\n");
for (i = 0; i < numPorts; i++)
{
port = mptPorts[i];
if (port->notOperational)
printf("%2d. %-16s\n", i+1, port->portName);
else
printf("%2d. %-16s LSI Logic %-12s %03x %08x %x\n",
i+1, port->portName, port->chipNameRev,
port->mptVersion, port->fwVersion, port->iocNumber);
}
closePorts(numPorts);
return ENODEV;
}
}
}
if (cargs.monitorInterval)
{
if (args || cargs.info || cargs.scan || cargs.dump || cargs.boardInfo ||
cargs.linkspeed || cargs.topology || cargs.coalescing || cargs.reset || cargs.linkReset ||
optind < argc)
{
printf("WARNING: -m being ignored (other options given)\n");
}
else
{
if (numPorts)
{
MPT_PORT *ports[NUM_PORTS];
memset(ports, 0, sizeof ports);
if (cargs.numPortNums)
{
for (i = 0; i < cargs.numPortNums; i++)
{
ports[cargs.portNums[i]] = mptPorts[cargs.portNums[i] - 1];
}
}
else
{
for (i = 0; i < numPorts; i++)
{
ports[i] = mptPorts[i];
}
}
doDisplayTransferStatisticsAll(NUM_PORTS, ports, cargs.monitorInterval, cargs.monitorDuration);
closePorts(numPorts);
return 0;
}
}
}
if ((cargs.info || cargs.scan || cargs.dump || cargs.boardInfo) &&
(cargs.linkspeed || cargs.topology || cargs.coalescing || cargs.reset || cargs.linkReset))
{
printf("ERROR: -s -i -d and -b (display options) can't be mixed\n");
printf("with -l -t and -c (set options) or -r and -z (reset options)\n");
closePorts(numPorts);
return EINVAL;
}
if (cargs.info || cargs.scan || cargs.dump)
{
if (cargs.numPortNums)
{
for (i = 0; i < cargs.numPortNums; i++)
{
port = mptPorts[cargs.portNums[i] - 1];
printf("\n==============================================================================\n");
if (port->notOperational)
{
printf("\n%-16s\n", port->portName);
continue;
}
printf("\n%-16s LSI Logic %-12s MPT %03x Firmware %08x IOC %x\n",
port->portName, port->chipNameRev, port->mptVersion, port->fwVersion, port->iocNumber);
if (cargs.info || cargs.dump)
{
printf("\n");
showBoardInfo(port, 1);
}
t = !cargs.info;
if (cargs.info)
{
printf("\n");
doPortStateSummary(port);
}
if (cargs.scan)
{
printf("\n");
doScanForDevices(port, t);
}
if (cargs.dump)
{
if (t)
printf("\n");
doDumpPortState(port, t);
}
}
}
else if (numPorts)
{
for (i = 0; i < numPorts; i++)
{
port = mptPorts[i];
printf("\n==============================================================================\n");
if (port->notOperational)
{
printf("\n%-16s\n", port->portName);
continue;
}
printf("\n%-16s LSI Logic %-12s MPT %03x Firmware %08x IOC %x\n",
port->portName, port->chipNameRev, port->mptVersion, port->fwVersion, port->iocNumber);
if (cargs.info || cargs.dump)
{
printf("\n");
showBoardInfo(port, 1);
}
t = !cargs.info;
if (cargs.info)
{
printf("\n");
doPortStateSummary(port);
}
if (cargs.scan)
{
printf("\n");
doScanForDevices(port, t);
}
if (cargs.dump)
{
if (t)
printf("\n");
doDumpPortState(port, t);
}
}
}
}
else if (cargs.boardInfo)
{
if (numPorts)
{
printf("\nPort Name Seg/Bus/Dev Board Name Board Assembly Board Tracer\n");
if (cargs.numPortNums)
{
for (i = 0; i < cargs.numPortNums; i++)
{
port = mptPorts[cargs.portNums[i] - 1];
if (port->notOperational)
continue;
if (iocMask & (1 << port->iocNumber))
continue;
showBoardInfo(port, 0);
}
}
else
{
for (i = 0; i < numPorts; i++)
{
port = mptPorts[i];
if (port->notOperational)
continue;
if (port->iocNumber)
continue;
showBoardInfo(port, 0);
}
}
}
}
if (cargs.linkspeed)
{
if (cargs.numPortNums)
{
for (i = 0; i < cargs.numPortNums; i++)
{
port = mptPorts[cargs.portNums[i] - 1];
if (port->notOperational)
continue;
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
switch (cargs.linkspeed)
{
default:
case 'a': t = MPI_FCPORTPAGE1_LCONFIG_SPEED_AUTO; type = "Auto"; break;
case '1': t = MPI_FCPORTPAGE1_LCONFIG_SPEED_1GIG; type = "1 Gb"; break;
case '2': t = MPI_FCPORTPAGE1_LCONFIG_SPEED_2GIG; type = "2 Gb"; break;
case '4': t = MPI_FCPORTPAGE1_LCONFIG_SPEED_4GIG; type = "4 Gb"; break;
}
printf("Setting link speed to %s on port %d\n", type, cargs.portNums[i]);
doFcLinkSpeedValue(port, t);
}
else
{
printf("ERROR: Link speed supported only on FC ports.\n");
}
}
}
else if (numPorts)
{
printf("ERROR: Must specify a port to set link speed. Valid ports are:\n");
printf("\n Port Name Chip Vendor/Type/Rev MPT Rev Firmware Rev IOC\n");
for (i = 0; i < numPorts; i++)
{
port = mptPorts[i];
if (port->notOperational)
printf("%2d. %-16s\n", i+1, port->portName);
else
printf("%2d. %-16s LSI Logic %-12s %03x %08x %x\n",
i+1, port->portName, port->chipNameRev,
port->mptVersion, port->fwVersion, port->iocNumber);
}
closePorts(numPorts);
return ENODEV;
}
}
if (cargs.topology)
{
if (cargs.numPortNums)
{
for (i = 0; i < cargs.numPortNums; i++)
{
port = mptPorts[cargs.portNums[i] - 1];
if (port->notOperational)
continue;
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
switch (cargs.topology)
{
default:
case 'a': t = MPI_FCPORTPAGE1_TOPOLOGY_AUTO; type = "Auto"; break;
case '1': t = MPI_FCPORTPAGE1_TOPOLOGY_NLPORT; type = "NL_Port"; break;
case '2': t = MPI_FCPORTPAGE1_TOPOLOGY_NPORT; type = "N_Port"; break;
}
printf("Setting topology to %s on port %d\n", type, cargs.portNums[i]);
doFcTopologyValue(port, t);
}
else
{
printf("ERROR: Topology change supported only on FC ports.\n");
}
}
}
else if (numPorts)
{
printf("ERROR: Must specify a port to set topology. Valid ports are:\n");
printf("\n Port Name Chip Vendor/Type/Rev MPT Rev Firmware Rev IOC\n");
for (i = 0; i < numPorts; i++)
{
port = mptPorts[i];
if (port->notOperational)
printf("%2d. %-16s\n", i+1, port->portName);
else
printf("%2d. %-16s LSI Logic %-12s %03x %08x %x\n",
i+1, port->portName, port->chipNameRev,
port->mptVersion, port->fwVersion, port->iocNumber);
}
closePorts(numPorts);
return ENODEV;
}
}
if (cargs.coalescing)
{
if (cargs.numPortNums)
{
for (i = 0; i < cargs.numPortNums; i++)
{
port = mptPorts[cargs.portNums[i] - 1];
if (port->notOperational)
continue;
if (cargs.ic_timeout != 0 && cargs.ic_depth != 0)
{
printf("Setting interrupt coalescing to timeout of %d microseconds\n",
cargs.ic_timeout);
printf("with depth of %d on port %d\n", cargs.ic_depth, cargs.portNums[i]);
}
else
printf("Disabling interrupt coalescing on port %d\n", cargs.portNums[i]);
doInterruptCoalescingValues(port, cargs.ic_timeout, cargs.ic_depth);
}
}
else if (numPorts)
{
printf("ERROR: Must specify a port to set interrupt coalescing. Valid ports are:\n");
printf("\n Port Name Chip Vendor/Type/Rev MPT Rev Firmware Rev IOC\n");
for (i = 0; i < numPorts; i++)
{
port = mptPorts[i];
if (port->notOperational)
printf("%2d. %-16s\n", i+1, port->portName);
else
printf("%2d. %-16s LSI Logic %-12s %03x %08x %x\n",
i+1, port->portName, port->chipNameRev,
port->mptVersion, port->fwVersion, port->iocNumber);
}
closePorts(numPorts);
return ENODEV;
}
}
if (cargs.reset)
{
if (cargs.numPortNums)
{
for (i = 0; i < cargs.numPortNums; i++)
{
port = mptPorts[cargs.portNums[i] - 1];
if (iocMask & (1 << port->iocNumber))
continue;
doResetPort(port);
}
}
else if (numPorts)
{
printf("ERROR: Must specify a port to reset. Valid ports are:\n");
printf("\n Port Name Chip Vendor/Type/Rev MPT Rev Firmware Rev IOC\n");
for (i = 0; i < numPorts; i++)
{
port = mptPorts[i];
if (port->notOperational)
printf("%2d. %-16s\n", i+1, port->portName);
else
printf("%2d. %-16s LSI Logic %-12s %03x %08x %x\n",
i+1, port->portName, port->chipNameRev,
port->mptVersion, port->fwVersion, port->iocNumber);
}
closePorts(numPorts);
return ENODEV;
}
}
if (cargs.linkReset)
{
if (cargs.numPortNums)
{
for (i = 0; i < cargs.numPortNums; i++)
{
port = mptPorts[cargs.portNums[i] - 1];
if (port->notOperational)
continue;
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doResetFcLink(port, cargs.linkResetFlag);
}
else
{
printf("ERROR: Link reset supported only on FC ports.\n");
}
}
}
else if (numPorts)
{
printf("ERROR: Must specify a port to reset. Valid ports are:\n");
printf("\n Port Name Chip Vendor/Type/Rev MPT Rev Firmware Rev IOC\n");
for (i = 0; i < numPorts; i++)
{
port = mptPorts[i];
if (port->notOperational)
printf("%2d. %-16s\n", i+1, port->portName);
else
printf("%2d. %-16s LSI Logic %-12s %03x %08x %x\n",
i+1, port->portName, port->chipNameRev,
port->mptVersion, port->fwVersion, port->iocNumber);
}
closePorts(numPorts);
return ENODEV;
}
}
if (cargs.info || cargs.scan || cargs.dump || cargs.boardInfo ||
cargs.linkspeed || cargs.topology || cargs.coalescing || cargs.reset || cargs.linkReset)
{
closePorts(numPorts);
return 0;
}
if (cargs.numPortNums)
{
if (optind < argc)
{
while (optind < argc)
{
if (sscanf(argv[optind], "%d", &t) == 1)
{
for (i = 0; i < cargs.numPortNums; i++)
{
printf("\n Port Name Chip Vendor/Type/Rev MPT Rev Firmware Rev IOC\n");
port = mptPorts[cargs.portNums[i] - 1];
updatePortInfo(port);
if (port->notOperational)
printf("%2d. %-16s\n", cargs.portNums[i], port->portName);
else
printf("%2d. %-16s LSI Logic %-12s %03x %08x %x\n",
cargs.portNums[i], port->portName, port->chipNameRev,
port->mptVersion, port->fwVersion, port->iocNumber);
argsCurr = args;
doPortOption(port, t);
}
}
else
printf("\n%s: invalid argument -- %s\n", argv[0], argv[optind]);
optind++;
}
}
else
{
iocMask = 0;
for (i = 0; i < cargs.numPortNums; i++)
{
printf("\n Port Name Chip Vendor/Type/Rev MPT Rev Firmware Rev IOC\n");
port = mptPorts[cargs.portNums[i] - 1];
updatePortInfo(port);
if (port->notOperational)
printf("%2d. %-16s\n", cargs.portNums[i], port->portName);
else
printf("%2d. %-16s LSI Logic %-12s %03x %08x %x\n",
cargs.portNums[i], port->portName, port->chipNameRev,
port->mptVersion, port->fwVersion, port->iocNumber);
argsCurr = args;
doPort(port);
}
}
closePorts(numPorts);
return 0;
}
else if (numPorts)
{
if (optind < argc)
{
while (optind < argc)
{
if (sscanf(argv[optind], "%d", &t) == 1)
{
for (i = 0; i < numPorts; i++)
{
printf("\n Port Name Chip Vendor/Type/Rev MPT Rev Firmware Rev IOC\n");
port = mptPorts[i];
updatePortInfo(port);
if (port->notOperational)
printf("%2d. %-16s\n", i+1, port->portName);
else
printf("%2d. %-16s LSI Logic %-12s %03x %08x %x\n",
i+1, port->portName, port->chipNameRev,
port->mptVersion, port->fwVersion, port->iocNumber);
argsCurr = args;
doPortOption(port, t);
}
}
else
printf("\n%s: invalid argument -- %s\n", argv[0], argv[optind]);
optind++;
}
closePorts(numPorts);
return 0;
}
}
}
else
{
if (wFlag)
{
logFile = fopen("lsiutil.log", "a");
if (logFile)
{
fprintf(logFile, "%s: Logging started at level %d\n", logPrefix(NULL), wFlag);
}
else
{
printf("Open failure for file lsiutil.log!\n");
perror("Error is");
logFile = stderr;
}
}
numPorts = findPorts();
printf("\n%d MPT Port%s found\n", numPorts, numPorts == 1 ? "" : "s");
}
if (numPorts)
{
iocMask = 0;
while (TRUE)
{
printf("\n Port Name Chip Vendor/Type/Rev MPT Rev Firmware Rev IOC\n");
for (i = 0; i < numPorts; i++)
{
port = mptPorts[i];
updatePortInfo(port);
if (port->notOperational)
printf("%2d. %-16s\n", i+1, port->portName);
else
printf("%2d. %-16s LSI Logic %-12s %03x %08x %x\n",
i+1, port->portName, port->chipNameRev,
port->mptVersion, port->fwVersion, port->iocNumber);
}
printf("\nSelect a device: [1-%d or 0 to quit] ", numPorts);
portNumber = getNumberAnswer(0, numPorts, -1);
if (portNumber < 0)
continue;
if (portNumber == 0)
break;
doPort(mptPorts[portNumber-1]);
}
}
closePorts(numPorts);
return 0;
}
#if __sparc__
int
getNodeInfo(di_node_t node, void *arg)
{
int *numPorts = (int *)arg;
char *driverName;
char *pathName;
int portNumber;
char path[PATH_MAX];
HANDLE fileHandle;
MPT_PORT *port;
driverName = di_driver_name(node);
pathName = di_devfs_path(node);
portNumber = di_instance(node);
if (driverName != NULL && pathName != NULL && portNumber >= 0)
{
if (strcasecmp("itmpt", driverName) == 0 ||
strcasecmp("itmptfc", driverName) == 0 ||
strcasecmp("lsimpt", driverName) == 0 ||
strcasecmp("mpt", driverName) == 0 ||
strcasecmp("mpt_sas", driverName) == 0 ||
strcasecmp("lsc", driverName) == 0)
{
sprintf(path, "/devices%s:devctl", pathName);
if ((fileHandle = open(path, O_RDWR)) >= 0)
{
port = (MPT_PORT *)malloc(sizeof *port);
memset(port, 0, sizeof *port);
port->portNumber = portNumber;
port->hostNumber = -1;
port->fileHandle = fileHandle;
if (strcasecmp("mpt_sas", driverName) == 0 || strcasecmp("lsc", driverName) == 0 )
{
/* since the global 'mpi2' is based on mptVersion, seed it with an MPI2 base value
* so it can be used until we get the real value from IOCFacts
*/
port->mptVersion = MPI2_VERSION_02_00;
port->ioctlValue = MPTIOCTL_PASS_THRU;
}
else
port->ioctlValue = SYMIOCTL_PASS_THRU_TIMEOUT;
sprintf(port->portName, "%s%d", driverName, portNumber);
if (strstr(driverName, "fc"))
sprintf(port->pathName, "%s/fp@0,0", pathName);
else
sprintf(port->pathName, "%s", pathName);
if (getPortInfo(port) == 1)
{
mptPorts[(*numPorts)++] = port;
}
else
{
close(fileHandle);
free(port);
}
}
}
}
return DI_WALK_CONTINUE;
}
#endif
int
checkReady(MPT_PORT *port)
{
#if DOS || EFI
HANDLE adap = port->fileHandle;
int t;
if (mpt_verify_ready(adap) || mpt_verify_operational(adap))
{
return 1;
}
mpt_stop(adap, TRUE);
if (adap->ioc_online == TRUE)
{
adap->ioc_online = mpt_verify_operational(adap);
if (adap->ioc_online == TRUE)
{
return 1;
}
t = mpt_get_doorbell(adap);
printf("\n%s is not in Operational state! Doorbell is %08x\n",
port->portName, t);
if (wFlag)
fprintf(logFile, "%s: Firmware State is not Operational! Doorbell is %08x\n",
logPrefix(port), t);
return 0;
}
if (mpt_verify_ready(adap) || mpt_verify_operational(adap))
{
return 1;
}
t = mpt_get_state(adap);
printf("\n%s (%s) is in %s state, Doorbell is %08x\n",
port->portName, port->chipNameRev,
t == MPI_IOC_STATE_RESET ? "RESET" :
t == MPI_IOC_STATE_FAULT ? "FAULT" :
"UNKNOWN", mpt_get_doorbell(adap));
return 0;
#else
return 1;
#endif
}
int
checkOperational(MPT_PORT *port, int flag)
{
#if REGISTER_ACCESS
#if WIN32 || __linux__ || __sparc__
U32 data;
if (doReadRegister(port, MPI_DOORBELL_OFFSET, &data) == 1)
{
if ((data & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL)
{
if (!port->notOperational)
{
port->notOperational = 1;
printf("\n%s is not in Operational state! Doorbell is %08x\n",
port->portName, data);
if (wFlag)
fprintf(logFile, "%s: Firmware State is not Operational! Doorbell is %08x\n",
logPrefix(port), data);
}
return 0;
}
port->notOperational = 0;
}
return 1;
#endif
#if DOS || EFI
HANDLE adap = port->fileHandle;
if (flag)
return mpt_verify_operational(adap);
return 1;
#endif
#else
return 1;
#endif
}
int
bringOnline(MPT_PORT *port)
{
#if DOS || EFI
if (port->fileHandle->bootloader == TRUE)
{
return 0;
}
if (port->fileHandle->ioc_online != TRUE)
{
port->fileHandle->port_enable_needed = TRUE;
port->fileHandle->ioc_online = mpt_restart(port->fileHandle);
}
else if (port->fileHandle->port_online == FALSE)
{
port->fileHandle->port_online = mpt_port_online(port->fileHandle);
}
#endif
return 1;
}
int
findPorts(void)
{
#if WIN32
int status;
HKEY hKeyScsi;
HKEY hKeyPort;
const LPSTR NamesKey = TEXT("HARDWARE\\DEVICEMAP\\Scsi");
DWORD portIndex;
DWORD portNameSize;
DWORD valueType;
DWORD driverNameSize;
char portName[16];
char driverName[16];
char fileName[16];
FILETIME lastWriteTime;
int portNumber;
HANDLE fileHandle;
MPT_PORT *port;
int numPorts;
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NamesKey, 0L, KEY_READ, &hKeyScsi);
// if can't open this registry key, there are no scsi drivers installed
if (status != ERROR_SUCCESS)
{
printf("Couldn't get Scsi key from registry\n");
return 0;
}
// enumerate all SCSI ports under the Scsi key
portIndex = 0;
numPorts = 0;
while (TRUE)
{
portNameSize = sizeof portName;
status = RegEnumKeyEx(hKeyScsi, portIndex++, portName,
&portNameSize, NULL, NULL, NULL, &lastWriteTime);
if (status != ERROR_SUCCESS)
break;
// open this port key to check the driver name
status = RegOpenKeyEx(hKeyScsi, portName, 0L, KEY_READ, &hKeyPort);
if (status == ERROR_SUCCESS)
{
driverNameSize = sizeof driverName;
status = RegQueryValueEx(hKeyPort, "Driver", NULL, &valueType,
driverName, &driverNameSize);
if (status == ERROR_SUCCESS)
{
if (strcasecmp("symmpi", driverName) == 0 ||
strcasecmp("lsimpt", driverName) == 0 ||
strcasecmp("lsi_fc", driverName) == 0 ||
strcasecmp("lsi_scsi", driverName) == 0 ||
strcasecmp("lsi_sas", driverName) == 0 ||
strcasecmp("lsi_sas2", driverName) == 0 ||
strcasecmp("lsi_sas3", driverName) == 0 ||
strcasecmp("lsi_gen2", driverName) == 0 ||
strcasecmp("sas2xp86", driverName) == 0 || // new name for lsi_gen2
strcasecmp("lsi_sss", driverName) == 0 ||
strcasecmp("dcssp", driverName) == 0)
{
portNumber = atoi(&portName[10]);
sprintf(fileName, "\\\\.\\Scsi%d:", portNumber);
fileHandle = CreateFile(fileName, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (fileHandle != INVALID_HANDLE_VALUE)
{
port = malloc(sizeof *port);
memset(port, 0, sizeof *port);
port->portNumber = portNumber;
port->fileHandle = fileHandle;
port->ioctlValue = IOCTL_SCSI_MINIPORT;
sprintf(port->portName, "Scsi Port %d", portNumber);
sprintf(fileName, "Scsi%d:", portNumber);
QueryDosDevice(fileName, port->driverName, sizeof port->driverName);
if (getPortInfo(port) == 1)
{
mptPorts[numPorts++] = port;
}
else
{
port->ioctlValue |= 0x2000;
if (getPortInfo(port) == 1)
{
mptPorts[numPorts++] = port;
}
else
{
CloseHandle(fileHandle);
free(port);
}
}
}
}
}
// close SCSI port key
RegCloseKey(hKeyPort);
}
}
// close Scsi key
RegCloseKey(hKeyScsi);
for (portNumber = 0; portNumber < 32; portNumber++)
{
sprintf(fileName, "\\\\.\\DcsMPT%d", portNumber);
fileHandle = CreateFile(fileName, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (fileHandle != INVALID_HANDLE_VALUE)
{
port = malloc(sizeof *port);
memset(port, 0, sizeof *port);
port->portNumber = portNumber;
port->fileHandle = fileHandle;
port->ioctlValue = IOCTL_SCSI_MINIPORT;
sprintf(port->portName, "DcsMPT%d", portNumber);
if (getPortInfo(port) == 1)
{
mptPorts[numPorts++] = port;
}
else
{
CloseHandle(fileHandle);
free(port);
}
}
}
for (portNumber = 0; portNumber < 32; portNumber++)
{
sprintf(fileName, "\\\\.\\MPTstm%d", portNumber);
fileHandle = CreateFile(fileName, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (fileHandle != INVALID_HANDLE_VALUE)
{
port = malloc(sizeof *port);
memset(port, 0, sizeof *port);
port->portNumber = portNumber;
port->fileHandle = fileHandle;
port->ioctlValue = IOCTL_SCSI_MINIPORT;
sprintf(port->portName, "MPTstm%d", portNumber);
if (getPortInfo(port) == 1)
{
mptPorts[numPorts++] = port;
}
else
{
CloseHandle(fileHandle);
free(port);
}
}
}
for (portNumber = 0; portNumber < 32; portNumber++)
{
sprintf(fileName, "\\\\.\\MPTstm%02x", portNumber);
fileHandle = CreateFile(fileName, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (fileHandle != INVALID_HANDLE_VALUE)
{
port = malloc(sizeof *port);
memset(port, 0, sizeof *port);
port->portNumber = portNumber;
port->fileHandle = fileHandle;
port->ioctlValue = IOCTL_SCSI_MINIPORT;
sprintf(port->portName, "MPTstm%02x", portNumber);
if (getPortInfo(port) == 1)
{
mptPorts[numPorts++] = port;
}
else
{
CloseHandle(fileHandle);
free(port);
}
}
}
#endif
#if __linux__
int numPorts;
int status;
HANDLE fileHandle;
HANDLE fileHandle2;
HANDLE fileHandle3;
FILE *portFile;
char portName[64];
int portNumber;
char pathName[PATH_MAX];
MPT_PORT *port;
struct mpt_ioctl_eventquery eventquery;
struct mpt2_ioctl_eventquery eventquery2;
struct mpt_ioctl_iocinfo *iocinfo;
struct mpt_ioctl_iocinfo_rev1 *iocinfo2;
int domain = 0;
int bus = 0;
int device = 0;
int function = 0;
HANDLE pciHandle;
unsigned char config[64];
char *p;
char *q;
char iocEntry[64];
FILE *iocFile;
int i;
U16 deviceIdRaw;
U16 deviceId;
#if REGISTER_ACCESS
char resource[64];
uint64_t t, ts;
off_t bar0;
off_t bar1;
off_t bar2;
size_t bar0size;
size_t bar1size;
size_t bar2size;
char portName1[64];
char portName2[64];
HANDLE pciHandle1;
HANDLE pciHandle2;
#endif
if ((fileHandle = open(IOCTL_NAME, O_RDWR)) < 0)
{
if (system("/sbin/modprobe mptctl"));
if ((fileHandle = open(IOCTL_NAME, O_RDWR)) < 0)
{
if (system("/bin/mknod /dev/mptctl c 10 220"));
fileHandle = open(IOCTL_NAME, O_RDWR);
}
}
fileHandle2 = open(IOCTL_NAME2, O_RDWR);
fileHandle3 = open(IOCTL_NAME3, O_RDWR);
if (fileHandle < 0 && fileHandle2 < 0 && fileHandle3 < 0)
{
printf("Couldn't open " IOCTL_NAME " or " IOCTL_NAME2 " or " IOCTL_NAME3 "!\n");
return 0;
}
globalFileHandle = fileHandle;
globalFileHandle2 = fileHandle2;
globalFileHandle3 = fileHandle3;
memset(&eventquery, 0, sizeof eventquery);
eventquery.hdr.maxDataSize = sizeof eventquery;
memset(&eventquery2, 0, sizeof eventquery2);
eventquery2.hdr.max_data_size = sizeof eventquery2;
iocinfo = (struct mpt_ioctl_iocinfo *)malloc(sizeof *iocinfo);
memset(iocinfo, 0, sizeof *iocinfo);
iocinfo->hdr.maxDataSize = sizeof *iocinfo;
iocinfo2 = (struct mpt_ioctl_iocinfo_rev1 *)malloc(sizeof *iocinfo2);
memset(iocinfo2, 0, sizeof *iocinfo2);
iocinfo2->hdr.maxDataSize = sizeof *iocinfo2;
numPorts = 0;
fileHandle = globalFileHandle;
if (fileHandle < 0)
fileHandle = globalFileHandle2;
if (fileHandle < 0)
fileHandle = globalFileHandle3;
probe_again:
for (portNumber = 0; portNumber < NUM_PORTS; portNumber++)
{
sprintf(portName, "/proc/mpt/ioc%d", portNumber);
portFile = fopen(portName, "r");
if (portFile == NULL)
sprintf(portName, "ioc%d", portNumber);
else
fclose(portFile);
eventquery.hdr.iocnum = portNumber;
eventquery2.hdr.ioc_number = portNumber;
if ( (fileHandle == globalFileHandle2) || (fileHandle == globalFileHandle3) )
status = ioctl(fileHandle, MPT2EVENTQUERY, &eventquery2);
else
status = ioctl(fileHandle, MPTEVENTQUERY, &eventquery);
if (status == 0)
{
port = (MPT_PORT *)malloc(sizeof *port);
memset(port, 0, sizeof *port);
/* since the global 'mpi2' is based on mptVersion, seed it with an MPI2 base value
* so it can be used until we get the real value from IOCFacts
*/
if ( (fileHandle == globalFileHandle2) || (fileHandle == globalFileHandle3) )
port->mptVersion = MPI2_VERSION_02_00;
port->portNumber = portNumber;
port->hostNumber = -1;
port->fileHandle = fileHandle;
strcpy(port->portName, portName);
for (i = 0; i < 32; i++)
{
if (mpi2)
{
sprintf(pathName, "/sys/class/scsi_host/host%d/proc_name", i);
iocFile = fopen(pathName, "r");
if (!iocFile)
continue;
p = fgets(iocEntry, sizeof iocEntry, iocFile);
fclose(iocFile);
if (!p)
continue;
if (strncmp(p, "mpt2sas", 7))
continue;
sprintf(pathName, "/sys/class/scsi_host/host%d/unique_id", i);
iocFile = fopen(pathName, "r");
if (!iocFile)
continue;
p = fgets(iocEntry, sizeof iocEntry, iocFile);
fclose(iocFile);
if (!p)
continue;
}
else
{
sprintf(pathName, "/proc/scsi/mptscsih/%d", i);
iocFile = fopen(pathName, "r");
if (!iocFile)
{
sprintf(pathName, "/proc/scsi/mptfc/%d", i);
iocFile = fopen(pathName, "r");
}
if (!iocFile)
{
sprintf(pathName, "/proc/scsi/mptsas/%d", i);
iocFile = fopen(pathName, "r");
}
if (!iocFile)
{
sprintf(pathName, "/proc/scsi/mptspi/%d", i);
iocFile = fopen(pathName, "r");
}
if (!iocFile)
continue;
p = fgets(iocEntry, sizeof iocEntry, iocFile);
fclose(iocFile);
if (!p)
continue;
p = strstr(iocEntry, "ioc");
if (!p)
continue;
p += 3;
q = strstr(p, ":");
if (!q)
continue;
q[0] = '\0';
}
if (portNumber == atoi(p))
{
port->hostNumber = i;
break;
}
}
iocinfo->hdr.iocnum = portNumber;
if (mpi2)
status = ioctl(fileHandle, MPT2IOCINFO, iocinfo);
else
status = ioctl(fileHandle, MPTIOCINFO, iocinfo);
if (status == 0)
{
domain = iocinfo->pciInfo.segmentID;
bus = iocinfo->pciInfo.u.bits.busNumber;
device = iocinfo->pciInfo.u.bits.deviceNumber;
function = iocinfo->pciInfo.u.bits.functionNumber;
}
else
{
iocinfo2->hdr.iocnum = portNumber;
status = ioctl(fileHandle, MPTIOCINFO2, iocinfo2);
if (status == 0)
{
domain = 0;
bus = iocinfo->pciInfo.u.bits.busNumber;
device = iocinfo->pciInfo.u.bits.deviceNumber;
function = iocinfo->pciInfo.u.bits.functionNumber;
}
}
if (status == 0)
{
sprintf(portName, "/proc/bus/pci/%04x:%02x/%02x.%d",
domain, bus, device, function);
pciHandle = open(portName, O_RDWR);
if (pciHandle < 0)
{
sprintf(portName, "/proc/bus/pci/%02x/%02x.%d",
bus, device, function);
pciHandle = open(portName, O_RDWR);
}
if (pciHandle >= 0)
{
if (read(pciHandle, config, sizeof config) == sizeof config)
{
deviceIdRaw = get16x(*(U16 *)&config[2]);
/* the following three want to be set to the device ID that doesnt include ZC*/
if ( (deviceIdRaw == MPI_MANUFACTPAGE_DEVID_53C1030ZC) ||
(deviceIdRaw == MPI_MANUFACTPAGE_DEVID_1030ZC_53C1035) ||
(deviceIdRaw == MPI_MANUFACTPAGE_DEVID_53C1035ZC))
{
deviceId = deviceIdRaw & ~1;
}
else
{
deviceId = deviceIdRaw;
}
port->deviceId = deviceId;
port->deviceIdRaw = deviceIdRaw;
#if REGISTER_ACCESS
sprintf(portName, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/resource",
domain, bus, device, function);
portFile = fopen(portName, "r");
if (portFile == NULL)
{
sprintf(portName, "/sys/bus/pci/devices/%02x:%02x.%d/resource",
bus, device, function);
portFile = fopen(portName, "r");
}
if (portFile)
{
bar0 = 0;
bar1 = 0;
bar2 = 0;
bar0size = 0;
bar1size = 0;
bar2size = 0;
if (fgets(resource, sizeof resource, portFile))
{
if (sscanf(resource, "%llx %llx", &t, &ts) == 2)
{
if (deviceId == MPI_MANUFACTPAGE_DEVID_SAS1078)
{
bar1 = t;
bar1size = ts - t + 1;
}
else
{
bar0 = t;
bar0size = ts - t + 1;
}
}
if (fgets(resource, sizeof resource, portFile))
{
if (sscanf(resource, "%llx %llx", &t, &ts) == 2)
{
if (deviceId == MPI_MANUFACTPAGE_DEVID_SAS1078)
{
bar0 = t;
bar0size = ts - t + 1;
}
else
{
bar1 = t;
bar1size = ts - t + 1;
}
}
if (fgets(resource, sizeof resource, portFile))
{
if (fgets(resource, sizeof resource, portFile))
{
if (sscanf(resource, "%llx %llx", &t, &ts) == 2)
{
bar2 = t;
bar2size = ts - t + 1;
}
}
}
}
}
fclose(portFile);
}
else
{
if (deviceId == MPI_MANUFACTPAGE_DEVID_SAS1078)
{
bar1 = get64x( config[0x10]) & ~0xF;
bar0 = get32x(*(U32 *)&config[0x18]) & ~0xF;
}
else
{
bar0 = get32x(*(U32 *)&config[0x10]) & ~0xF;
bar1 = get64x( config[0x14]) & ~0xF;
}
bar2 = get64x( config[0x1c]) & ~0xF;
bar0size = 256;
bar1size = 256;
bar2size = 65536;
}
port->ioPhys = bar0;
port->memPhys = bar1;
port->diagPhys = bar2;
ioctl(pciHandle, PCIIOC_MMAP_IS_MEM);
if (deviceId == MPI_MANUFACTPAGE_DEVID_SAS1078)
sprintf(portName1, "%s0", portName);
else
sprintf(portName1, "%s1", portName);
sprintf(portName2, "%s3", portName);
pciHandle1 = open(portName1, O_RDWR);
if (pciHandle1)
{
errno = 0;
port->memVirt = mmap(NULL, bar1size, PROT_READ | PROT_WRITE,
MAP_SHARED, pciHandle1, 0);
if (errno)
port->memVirt = NULL;
}
if (!port->memVirt && bar1 && bar1size)
{
errno = 0;
port->memVirt = mmap(NULL, bar1size, PROT_READ | PROT_WRITE,
MAP_SHARED, pciHandle, bar1);
if (errno)
port->memVirt = NULL;
}
if (!port->memVirt)
port->memPhys = 0;
pciHandle2 = open(portName2, O_RDWR);
if (pciHandle2)
{
errno = 0;
port->diagVirt = mmap(NULL, bar2size, PROT_READ | PROT_WRITE,
MAP_SHARED, pciHandle2, 0);
if (errno)
port->diagVirt = NULL;
}
if (!port->diagVirt && bar2 && bar2size)
{
errno = 0;
port->diagVirt = mmap(NULL, bar2size, PROT_READ | PROT_WRITE,
MAP_SHARED, pciHandle, bar2);
if (errno)
port->diagVirt = NULL;
}
if (!port->diagVirt)
port->diagPhys = 0;
#if i386
if (deviceId == MPI_MANUFACTPAGE_DEVID_53C1030)
{
iopl(3);
if (!(config[0x04] & 1))
{
config[0x04] |= 1;
lseek(pciHandle, 0x04, SEEK_SET);
write(pciHandle, config + 0x04, 1);
}
}
#endif
#endif
}
}
}
if (getPortInfo(port) == 1)
{
mptPorts[numPorts++] = port;
}
else
{
free(port);
}
}
}
if (fileHandle == globalFileHandle)
{
fileHandle = globalFileHandle2;
if (fileHandle >= 0)
goto probe_again;
}
if (fileHandle == globalFileHandle2)
{
fileHandle = globalFileHandle3;
if (fileHandle >= 0)
goto probe_again;
}
free(iocinfo);
free(iocinfo2);
if (numPorts == 0)
{
if (globalFileHandle >= 0)
close(globalFileHandle);
if (globalFileHandle2 >= 0)
close(globalFileHandle2);
if (globalFileHandle3 >= 0)
close(globalFileHandle3);
}
#endif
#if __sparc__
int numPorts;
FILE *pathFile;
char pathEntry[PATH_MAX];
char *o;
char *p;
char *q;
char path[PATH_MAX];
HANDLE fileHandle;
int portNumber;
MPT_PORT *port;
int i;
int j;
int n;
DIR *dirp;
struct dirent *direntp;
char pathName[PATH_MAX];
char linkName[PATH_MAX];
struct stat stat;
di_node_t root_node;
numPorts = 0;
root_node = di_init("/", DINFOSUBTREE);
if (root_node != DI_NODE_NIL)
{
di_walk_node(root_node, DI_WALK_CLDFIRST, &numPorts, getNodeInfo);
di_fini(root_node);
}
if (numPorts == 0)
{
pathFile = fopen("/etc/path_to_inst", "r");
if (pathFile == NULL)
{
printf("Couldn't open /etc/path_to_inst!\n");
perror("Error is");
return 0;
}
while (fgets(pathEntry, sizeof pathEntry, pathFile) != NULL)
{
if ((o = strstr(pathEntry, "\"itmpt\"")) == NULL &&
(o = strstr(pathEntry, "\"itmptfc\"")) == NULL &&
(o = strstr(pathEntry, "\"mpt\"")) == NULL)
continue;
p = strchr(pathEntry, (int)'"');
if (p == NULL)
continue;
p += 1;
if (strncmp(p, "/node@", 6) == 0)
{
p += 6;
p = strchr(p, '/');
if (p == NULL)
continue;
}
q = strchr(p, '"');
if (q == NULL)
continue;
*q = '\0';
q += 1;
portNumber = atoi(q);
o += 1;
q = strchr(o, '"');
*q = '\0';
sprintf(path, "/devices%s:devctl", p);
if ((fileHandle = open(path, O_RDWR)) < 0)
continue;
if (fstat(fileHandle, &stat) < 0)
continue;
if (portNumber != MINOR2INST(getminor(stat.st_rdev)))
continue;
port = (MPT_PORT *)malloc(sizeof *port);
memset(port, 0, sizeof *port);
port->portNumber = portNumber;
port->hostNumber = -1;
port->fileHandle = fileHandle;
port->ioctlValue = SYMIOCTL_PASS_THRU_TIMEOUT;
sprintf(port->portName, "%s%d", o, portNumber);
if (strstr(o, "fc"))
sprintf(port->pathName, "%s/fp@0,0", p);
else
sprintf(port->pathName, "%s", p);
if (getPortInfo(port) == 1)
{
mptPorts[numPorts++] = port;
}
else
{
close(fileHandle);
free(port);
}
}
fclose(pathFile);
}
for (i = 0; i < numPorts; i++)
{
port = mptPorts[i];
dirp = opendir("/dev/cfg/");
while (dirp)
{
direntp = readdir(dirp);
if (!direntp)
break;
strcpy(pathName, "/dev/cfg/");
strcat(pathName, direntp->d_name);
n = readlink(pathName, linkName, sizeof linkName);
if (n <= 0)
continue;
linkName[n] = '\0';
p = strstr(linkName, "/devices");
if (!p)
continue;
p += 8;
q = strrchr(p, ':');
if (q)
*q = '\0';
if (strcmp(port->pathName, p) == 0)
{
port->hostNumber = atoi(direntp->d_name + 1);
break;
}
}
if (dirp)
closedir(dirp);
}
for (i = 0; i < numPorts - 1; i++)
{
for (j = i + 1; j < numPorts; j++)
{
if (strcmp(mptPorts[i]->portName, mptPorts[j]->portName) > 0)
{
port = mptPorts[i];
mptPorts[i] = mptPorts[j];
mptPorts[j] = port;
}
}
}
#endif
#if __irix__
int numPorts;
HANDLE fileHandle;
char portName[24];
int portNumber;
MPT_PORT *port;
numPorts = 0;
for (portNumber = 0; portNumber < NUM_PORTS; portNumber++)
{
sprintf(portName, "/hw/scsi_ctlr/%d/bus", portNumber);
if ((fileHandle = open(portName, O_RDWR)) < 0)
continue;
port = (MPT_PORT *)malloc(sizeof *port);
memset(port, 0, sizeof *port);
port->portNumber = portNumber;
port->fileHandle = fileHandle;
sprintf(port->portName, "scsi_ctlr%d", portNumber);
if (getPortInfo(port) == 1)
{
mptPorts[numPorts++] = port;
}
else
{
free(port);
}
}
#endif
#if __alpha__
int numPorts;
HANDLE fileHandle;
int portNumber;
MPT_PORT *port;
if ((fileHandle = open("/dev/itmpt", O_RDWR)) < 0)
{
printf("Couldn't open /dev/itmpt!\n");
perror("Error is");
return 0;
}
globalFileHandle = fileHandle;
numPorts = 0;
for (portNumber = 0; portNumber < 8; portNumber++)
{
port = (MPT_PORT *)malloc(sizeof *port);
memset(port, 0, sizeof *port);
port->portNumber = portNumber;
port->fileHandle = fileHandle;
sprintf(port->portName, "itmpt%d", portNumber);
if (getPortInfo(port) == 1)
{
mptPorts[numPorts++] = port;
}
else
{
free(port);
}
}
if (numPorts == 0)
close(fileHandle);
#endif
#if DOS
int numPorts;
HANDLE adap;
MPT_PORT *port;
U8 pciMajorRevision;
U8 pciMinorRevision;
U8 maxPciBusNumber;
U8 busNumber;
U8 deviceNumber;
U8 functionNumber;
U8 deviceFunction;
U16 vendorId;
U16 deviceIdRaw;
U16 deviceId;
U8 command;
int io;
int mem;
int diagmem;
int t;
if (PciIsBiosPresent(&pciMajorRevision, &pciMinorRevision, &maxPciBusNumber) != 1)
{
printf("\nThe PCI System BIOS is not present!\n");
return 0;
}
numPorts = 0;
for (busNumber = 0; busNumber <= maxPciBusNumber; busNumber++)
{
for (deviceNumber = 0; deviceNumber < 32; deviceNumber++)
{
for (functionNumber = 0; functionNumber < 8; functionNumber++)
{
deviceFunction = (deviceNumber << 3) | functionNumber;
// have to do this twice for some PCI BIOS implementations!
vendorId = PciReadConfigWord(busNumber, deviceFunction, PCI_CONFIG_VENDOR_ID);
deviceIdRaw = PciReadConfigWord(busNumber, deviceFunction, PCI_CONFIG_DEVICE_ID);
vendorId = PciReadConfigWord(busNumber, deviceFunction, PCI_CONFIG_VENDOR_ID);
deviceIdRaw = PciReadConfigWord(busNumber, deviceFunction, PCI_CONFIG_DEVICE_ID);
if (vendorId != MPI_MANUFACTPAGE_VENDORID_LSILOGIC)
break;
/* the following three want to be set to the device ID that doesnt include ZC*/
if ( (deviceIdRaw == MPI_MANUFACTPAGE_DEVID_53C1030ZC) ||
(deviceIdRaw == MPI_MANUFACTPAGE_DEVID_1030ZC_53C1035) ||
(deviceIdRaw == MPI_MANUFACTPAGE_DEVID_53C1035ZC))
{
deviceId = deviceIdRaw & ~1;
}
else
{
deviceId = deviceIdRaw;
}
if (deviceId == MPI_MANUFACTPAGE_DEVICEID_FC909 ||
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC919 ||
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC929 ||
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC919X ||
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC929X ||
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC939X ||
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC949X ||
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC949E ||
deviceId == MPI_MANUFACTPAGE_DEVID_53C1030 ||
deviceId == MPI_MANUFACTPAGE_DEVID_1030_53C1035 ||
deviceId == MPI_MANUFACTPAGE_DEVID_SAS1064 ||
deviceId == MPI_MANUFACTPAGE_DEVID_SAS1064E ||
deviceId == MPI_MANUFACTPAGE_DEVID_SAS1066 ||
deviceId == MPI_MANUFACTPAGE_DEVID_SAS1066E ||
deviceId == MPI_MANUFACTPAGE_DEVID_SAS1068 ||
deviceId == MPI_MANUFACTPAGE_DEVID_SAS1068E ||
deviceId == MPI_MANUFACTPAGE_DEVID_SAS1078 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2004 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2008 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2108_1 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2108_2 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2108_3 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2116_1 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2116_2 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2208_1 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2208_2 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2208_3 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2208_4 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2208_5 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2208_6 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2308_1 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2308_2 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2308_3 ||
deviceId == MPI25_MFGPAGE_DEVID_SAS3004 ||
deviceId == MPI25_MFGPAGE_DEVID_SAS3008 ||
deviceId == MPI25_MFGPAGE_DEVID_SAS3108_1 ||
deviceId == MPI25_MFGPAGE_DEVID_SAS3108_2 ||
deviceId == MPI25_MFGPAGE_DEVID_SAS3108_5 ||
deviceId == MPI25_MFGPAGE_DEVID_SAS3108_6 ||
deviceId == MPI2_MFGPAGE_DEVID_SSS6200 )
{
adap = malloc(sizeof *adap);
memset(adap, 0, sizeof *adap);
if (deviceId == MPI_MANUFACTPAGE_DEVID_SAS1078)
{
io = PCI_CONFIG0_BASE_ADDRESS2;
mem = PCI_CONFIG0_BASE_ADDRESS0;
diagmem = PCI_CONFIG0_BASE_ADDRESS3;
}
else
{
io = PCI_CONFIG0_BASE_ADDRESS0;
mem = PCI_CONFIG0_BASE_ADDRESS1;
diagmem = PCI_CONFIG0_BASE_ADDRESS3;
}
if (deviceId != MPI_MANUFACTPAGE_DEVID_53C1030)
{
io = mem; // no need to use I/O space, so don't (it's safer not to)
}
adap->bus_number = busNumber;
adap->device_function = deviceFunction;
adap->revision_id = PciReadConfigByte(busNumber, deviceFunction,
PCI_CONFIG_REVISION_ID);
adap->io = io;
adap->mem = mem;
adap->diagmem = diagmem;
adap->io_addr = PciReadConfigDword(busNumber, deviceFunction, io) & ~0xF;
adap->mem_addr = PciReadConfigDword(busNumber, deviceFunction, mem) & ~0xF;
PciWriteConfigDword(busNumber, deviceFunction, mem, 0xFFFFFFFF);
adap->mem_size = ~(PciReadConfigDword(busNumber, deviceFunction, mem) & ~0xF) + 1;
PciWriteConfigDword(busNumber, deviceFunction, mem, adap->mem_addr);
adap->mem_virt = MapPhysicalToLinear(adap->mem_addr, adap->mem_size);
adap->diagmem_addr = PciReadConfigDword(busNumber, deviceFunction, diagmem) & ~0xF;
PciWriteConfigDword(busNumber, deviceFunction, diagmem, 0xFFFFFFFF);
adap->diagmem_size = ~(PciReadConfigDword(busNumber, deviceFunction, diagmem) & ~0xF) + 1;
PciWriteConfigDword(busNumber, deviceFunction, diagmem, adap->diagmem_addr);
adap->diagmem_virt = MapPhysicalToLinear(adap->diagmem_addr, adap->diagmem_size);
PtrAllocateContiguousMemory(sizeof(mpt_shared_t), &adap->shared_contig_mem);
command = PciReadConfigByte(busNumber, deviceFunction, PCI_CONFIG_COMMAND);
command |= PCI_COMMAND_IO;
command |= PCI_COMMAND_MEMORY;
command |= PCI_COMMAND_BUS_MASTER;
PciWriteConfigByte(busNumber, deviceFunction, PCI_CONFIG_COMMAND, command);
port = (MPT_PORT *)malloc(sizeof *port);
memset(port, 0, sizeof *port);
port->portNumber = (busNumber << 8) | deviceFunction;
port->fileHandle = adap;
sprintf(port->portName, "%02x/%02x/%d", busNumber, deviceNumber, functionNumber);
adap->port = port;
adap->name = port->portName;
adap->vendor_id = vendorId;
adap->device_id = deviceId;
adap->shared = adap->shared_contig_mem.PtrContiguous;
adap->shared_ba = adap->shared_contig_mem.PhyPtrContiguous;
adap->max_targets = 256;
adap->restart_needed = FALSE;
adap->bus_reset_needed = FALSE;
memset(adap->shared, 0, sizeof(mpt_shared_t));
port->deviceIdRaw = deviceIdRaw;
port->deviceId = deviceId;
port->revisionId = adap->revision_id;
port->iocNumber = functionNumber;
getChipName(port);
if (functionNumber == 1)
{
MPT_PORT *partner_port = mptPorts[numPorts - 1];
HANDLE partner_adap = partner_port->fileHandle;
adap->partner_adap = partner_adap;
partner_adap->partner_adap = adap;
adap->fw_image = partner_adap->fw_image;
}
if (mpt_verify_enabled(adap) &&
(mpt_verify_ready(adap) || mpt_verify_operational(adap)))
{
getPortInfo(port);
}
else
{
t = mpt_get_state(adap);
printf("\n%s (%s) is in %s state, Doorbell is %08x\n",
port->portName, port->chipNameRev,
t == MPI_IOC_STATE_RESET ? "RESET" :
t == MPI_IOC_STATE_FAULT ? "FAULT" :
"UNKNOWN", mpt_get_doorbell(adap));
}
mptPorts[numPorts++] = port;
}
else
break;
}
}
}
#endif
#if EFI
EFI_DEVICE_PATH_PROTOCOL *ourDevicePath;
EFI_DEVICE_PATH_PROTOCOL *pciDevicePath;
EFI_STATUS status;
EFI_HANDLE handle;
EFI_HANDLE *handles;
UINTN numHandles;
EFI_PCI_IO_PROTOCOL *pciIo;
PCI_TYPE00 pci;
int i;
int numPorts;
HANDLE adap;
MPT_PORT *port;
UINTN segmentNumber;
UINTN busNumber;
UINTN deviceNumber;
UINTN functionNumber;
U8 deviceFunction;
U16 vendorId;
U16 deviceIdRaw;
U16 deviceId;
int io;
int mem;
int diagmem;
U32 bar;
U32 data;
UINTN buffer_size;
void *buffer;
mpt_bus_addr_t buffer_dma;
void *buffer_mapping;
U32 actualImageLen;
int t;
status = BS->HandleProtocol(gLoadedImage->DeviceHandle,
&gEfiDevicePathProtocolGuid, &ourDevicePath);
if (EFI_ERROR(status))
return 0;
status = BS->LocateHandleBuffer(ByProtocol, &gEfiPciIoProtocolGuid,
NULL, &numHandles, &handles);
if (EFI_ERROR(status))
return 0;
numPorts = 0;
for (i = 0; i < (int)numHandles; i++)
{
handle = handles[i];
status = BS->OpenProtocol(handle, &gEfiPciIoProtocolGuid,
&pciIo, gImageHandle, handle,
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL);
if (EFI_ERROR(status))
continue;
status = pciIo->Pci.Read(pciIo, EfiPciIoWidthUint8, 0,
sizeof pci, &pci);
if (EFI_ERROR(status))
{
BS->CloseProtocol(handle, &gEfiPciIoProtocolGuid, gImageHandle, handle);
continue;
}
vendorId = pci.Hdr.VendorId;
deviceIdRaw = pci.Hdr.DeviceId;
/* the following three want to be set to the device ID that doesnt include ZC*/
if ( (deviceIdRaw == MPI_MANUFACTPAGE_DEVID_53C1030ZC) ||
(deviceIdRaw == MPI_MANUFACTPAGE_DEVID_1030ZC_53C1035) ||
(deviceIdRaw == MPI_MANUFACTPAGE_DEVID_53C1035ZC))
{
deviceId = deviceIdRaw & ~1;
}
else
{
deviceId = deviceIdRaw;
}
status = BS->HandleProtocol(handle, &gEfiDevicePathProtocolGuid, &pciDevicePath);
if (EFI_ERROR(status))
{
BS->CloseProtocol(handle, &gEfiPciIoProtocolGuid, gImageHandle, handle);
continue;
}
if (vendorId != MPI_MANUFACTPAGE_VENDORID_LSILOGIC)
{
BS->CloseProtocol(handle, &gEfiPciIoProtocolGuid, gImageHandle, handle);
continue;
}
if (deviceId == MPI_MANUFACTPAGE_DEVICEID_FC909 ||
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC919 ||
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC929 ||
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC919X ||
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC929X ||
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC939X ||
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC949X ||
deviceId == MPI_MANUFACTPAGE_DEVICEID_FC949E ||
deviceId == MPI_MANUFACTPAGE_DEVID_53C1030 ||
deviceId == MPI_MANUFACTPAGE_DEVID_1030_53C1035 ||
deviceId == MPI_MANUFACTPAGE_DEVID_SAS1064 ||
deviceId == MPI_MANUFACTPAGE_DEVID_SAS1064E ||
deviceId == MPI_MANUFACTPAGE_DEVID_SAS1066 ||
deviceId == MPI_MANUFACTPAGE_DEVID_SAS1066E ||
deviceId == MPI_MANUFACTPAGE_DEVID_SAS1068 ||
deviceId == MPI_MANUFACTPAGE_DEVID_SAS1068E ||
deviceId == MPI_MANUFACTPAGE_DEVID_SAS1078 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2004 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2008 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2108_1 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2108_2 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2108_3 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2116_1 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2116_2 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2208_1 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2208_2 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2208_3 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2208_4 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2208_5 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2208_6 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2308_1 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2308_2 ||
deviceId == MPI2_MFGPAGE_DEVID_SAS2308_3 ||
deviceId == MPI25_MFGPAGE_DEVID_SAS3004 ||
deviceId == MPI25_MFGPAGE_DEVID_SAS3008 ||
deviceId == MPI25_MFGPAGE_DEVID_SAS3108_1 ||
deviceId == MPI25_MFGPAGE_DEVID_SAS3108_2 ||
deviceId == MPI25_MFGPAGE_DEVID_SAS3108_5 ||
deviceId == MPI25_MFGPAGE_DEVID_SAS3108_6 ||
deviceId == MPI2_MFGPAGE_DEVID_SSS6200 )
{
adap = malloc(sizeof *adap);
memset(adap, 0, sizeof *adap);
if (deviceId == MPI_MANUFACTPAGE_DEVID_SAS1078)
{
io = 2;
mem = 0;
diagmem = 3;
}
else
{
io = 0;
mem = 1;
diagmem = 3;
}
if (deviceId != MPI_MANUFACTPAGE_DEVID_53C1030)
{
io = mem; // no need to use I/O space, so don't (it's safer not to)
}
pciIo->GetLocation(pciIo, &segmentNumber, &busNumber, &deviceNumber, &functionNumber);
deviceFunction = ((U8)deviceNumber << 3) | (U8)functionNumber;
adap->handle = handle;
adap->pci_io = pciIo;
adap->segment_number = (U8)segmentNumber;
adap->bus_number = (U8)busNumber;
adap->device_function = deviceFunction;
adap->revision_id = pci.Hdr.RevisionID;
adap->io = io;
adap->mem = mem;
adap->diagmem = diagmem;
data = 0xFFFFFFFF;
pciIo->Pci.Read(pciIo, EfiPciIoWidthUint32, 0x10 + diagmem * 4, 1, &bar);
pciIo->Pci.Write(pciIo, EfiPciIoWidthUint32, 0x10 + diagmem * 4, 1, &data);
pciIo->Pci.Read(pciIo, EfiPciIoWidthUint32, 0x10 + diagmem * 4, 1, &data);
pciIo->Pci.Write(pciIo, EfiPciIoWidthUint32, 0x10 + diagmem * 4, 1, &bar);
adap->diagmem_size = ~(data & ~0xF) + 1;
status = pciIo->Attributes(pciIo, EfiPciIoAttributeOperationEnable,
EFI_PCI_IO_ATTRIBUTE_IO |
EFI_PCI_IO_ATTRIBUTE_MEMORY |
EFI_PCI_IO_ATTRIBUTE_BUS_MASTER |
EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE, NULL);
if (status == EFI_UNSUPPORTED)
{
status = pciIo->Attributes(pciIo, EfiPciIoAttributeOperationEnable,
EFI_PCI_IO_ATTRIBUTE_IO |
EFI_PCI_IO_ATTRIBUTE_MEMORY |
EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, NULL);
}
if (EFI_ERROR(status))
{
BS->CloseProtocol(handle, &gEfiPciIoProtocolGuid, gImageHandle, handle);
continue;
}
status = pciIo->AllocateBuffer(pciIo, 0, EfiBootServicesData,
EFI_SIZE_TO_PAGES(sizeof(mpt_shared_t)), &buffer, 0);
if (EFI_ERROR(status))
{
BS->CloseProtocol(handle, &gEfiPciIoProtocolGuid, gImageHandle, handle);
continue;
}
buffer_size = sizeof(mpt_shared_t);
if (pciIo->Map)
{
status = pciIo->Map(pciIo, EfiPciIoOperationBusMasterCommonBuffer,
buffer, &buffer_size, &buffer_dma, &buffer_mapping);
}
else
{
buffer_dma = (mpt_bus_addr_t)buffer;
buffer_mapping = NULL;
}
adap->buffer_mapping = buffer_mapping;
port = (MPT_PORT *)malloc(sizeof *port);
memset(port, 0, sizeof *port);
port->portNumber = ((U8)segmentNumber << 16) | ((U8)busNumber << 8) | deviceFunction;
port->fileHandle = adap;
sprintf(port->portName, "%02x/%02x/%02x/%d", segmentNumber, busNumber, deviceNumber, functionNumber);
adap->port = port;
adap->name = port->portName;
adap->vendor_id = vendorId;
adap->device_id = deviceId;
adap->shared = buffer;
adap->shared_ba = buffer_dma;
adap->max_targets = 256;
adap->restart_needed = FALSE;
adap->bus_reset_needed = FALSE;
memset(adap->shared, 0, sizeof(mpt_shared_t));
port->deviceIdRaw = deviceIdRaw;
port->deviceId = deviceId;
port->revisionId = adap->revision_id;
port->iocNumber = (U8)functionNumber;
getChipName(port);
if (functionNumber == 1)
{
MPT_PORT *partner_port = mptPorts[numPorts - 1];
HANDLE partner_adap = partner_port->fileHandle;
adap->partner_adap = partner_adap;
partner_adap->partner_adap = adap;
adap->fw_image = partner_adap->fw_image;
adap->loaddevice = partner_adap->loaddevice;
}
if (memcmp(pciDevicePath, ourDevicePath, 12+6) == 0)
{
adap->loaddevice = TRUE;
if (adap->partner_adap)
adap->partner_adap->loaddevice = TRUE;
}
if (mpt_verify_enabled(adap) &&
(mpt_verify_ready(adap) || mpt_verify_operational(adap)))
{
getPortInfo(port);
if (port->flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
{
if (adap->fw_image == NULL && port->fwImageSize != 0)
{
buffer = malloc(port->fwImageSize);
if (doFwUpload(port, MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM,
buffer, port->fwImageSize, 0, &actualImageLen) == 1)
{
adap->fw_image = buffer;
adap->fw_image_size = actualImageLen;
if (actualImageLen != port->fwImageSize)
printf("\nFW_UPLOAD of IOC_MEM returned %d bytes (expected %d bytes)\n",
actualImageLen, port->fwImageSize);
}
else
{
printf("\nFW_UPLOAD of IOC_MEM failed!\n");
free(buffer);
}
}
}
}
else
{
t = mpt_get_state(adap);
printf("\n%s (%s) is in %s state, Doorbell is %08x\n",
port->portName, port->chipNameRev,
t == MPI_IOC_STATE_RESET ? "RESET" :
t == MPI_IOC_STATE_FAULT ? "FAULT" :
"UNKNOWN", mpt_get_doorbell(adap));
}
mptPorts[numPorts++] = port;
}
}
if (numHandles)
FreePool(handles);
#endif
if (just)
{
int i;
int j;
for (i = 0, j = 0; i < numPorts; i++)
{
port = mptPorts[i];
mptPorts[j] = port;
if (port->mptVersion == 0)
continue;
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
if (just & JUST_FC)
{
j++;
continue;
}
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SCSI)
{
if (just & JUST_SCSI)
{
j++;
continue;
}
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
if (just & JUST_SAS)
{
j++;
continue;
}
}
closePort(port);
}
numPorts = j;
}
return numPorts;
}
int
closePorts(int numPorts)
{
MPT_PORT *port;
int i;
for (i = 0; i < numPorts; i++)
{
port = mptPorts[i];
if (port)
closePort(port);
}
#if __linux__ || __alpha__
if (globalFileHandle >= 0)
close(globalFileHandle);
if (globalFileHandle2 >= 0)
close(globalFileHandle2);
#endif
if (osDeviceState)
free(osDeviceState);
#if __sparc__
if (scsi_vhci_fd >= 0)
close(scsi_vhci_fd);
if (dev_rdsk_count)
free(dev_rdsk_cache);
if (dev_rmt_count)
free(dev_rmt_cache);
if (dev_es_count)
free(dev_es_cache);
#endif
if (logFile)
{
fprintf(logFile, "%s: Logging ended\n", logPrefix(NULL));
fclose(logFile);
}
return 1;
}
int
closePort(MPT_PORT *port)
{
#if DOS || EFI
HANDLE adap;
#endif
#if WIN32
CloseHandle(port->fileHandle);
#endif
#if __sparc__ || __irix__
close(port->fileHandle);
#endif
#if DOS
adap = port->fileHandle;
mpt_stop(adap, FALSE);
if (adap->fw_image != NULL && adap->fw_image_size != 0)
free(adap->fw_image);
UnmapPhysicalToLinear(adap->mem_addr);
UnmapPhysicalToLinear(adap->diagmem_addr);
FreeContiguousMemory(adap->shared_contig_mem.PtrFree);
free(adap);
#endif
#if EFI
adap = port->fileHandle;
if (adap->disconnected == TRUE || adap->loaddevice == FALSE ||
((port->flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) && adap->fw_image != NULL))
{
adap->loaddevice = FALSE;
mpt_stop(adap, FALSE);
}
if (adap->fw_image != NULL && adap->fw_image_size != 0)
free(adap->fw_image);
if (adap->pci_io->Unmap && adap->buffer_mapping)
adap->pci_io->Unmap(adap->pci_io, adap->buffer_mapping);
adap->pci_io->FreeBuffer(adap->pci_io, EFI_SIZE_TO_PAGES(sizeof(mpt_shared_t)), adap->shared);
BS->CloseProtocol(adap->handle, &gEfiPciIoProtocolGuid, gImageHandle, adap->handle);
if (adap->disconnected == TRUE)
BS->ConnectController(adap->handle, NULL, NULL, TRUE);
free(adap);
#endif
free(port->chipName);
free(port->chipNameRev);
free(port);
return 1;
}
int
getFileName(char *buf, int len, FILE *file, char *fileString, int fileType)
{
int n;
if (numFileNames > fileType && strcmp(fileNames[fileType], "?") != 0)
{
strncpy(buf, fileNames[fileType], len);
}
else
{
printf("Enter %s filename: ", fileString);
if (fgets(buf, len, file) == NULL)
exit(0);
}
if (file == stdin)
lines = 0;
buf[len - 1] = '\0';
n = (int)strlen(buf);
while (n != 0 && (buf[n-1] == ' ' || buf[n-1] == '\n'))
buf[--n] = '\0';
return n;
}
int
getString(char *buf, int len, FILE *file)
{
int n;
if (fgets(buf, len, file) == NULL)
exit(0);
if (file == stdin)
lines = 0;
buf[len - 1] = '\0';
n = (int)strlen(buf);
while (n != 0 && (buf[n-1] == ' ' || buf[n-1] == '\n'))
buf[--n] = '\0';
return n;
}
int
getStringFromArgs(char *buf, int len, FILE *file)
{
int n;
char c;
if (argsCurr == NULL)
return getString(buf, len, file);
n = 0;
while (TRUE)
{
c = argsCurr[n];
if (c == '\0' || c == ',')
break;
if (n < len - 1)
buf[n++] = c;
}
buf[n] = '\0';
if (c == '\0')
argsCurr = NULL;
else
argsCurr += n + 1;
printf("%s\n", buf);
return n;
}
int
getYesNoAnswer(int defvalue)
{
char buf[64];
int n;
n = getStringFromArgs(buf, sizeof buf, stdin);
if (n == 0)
return defvalue;
if (strncasecmp(buf, "no", n) == 0)
return 0;
if (strncasecmp(buf, "yes", n) == 0)
return 1;
return defvalue;
}
int
getNumberAnswer(int low, int high, int defvalue)
{
char buf[64];
int i;
int n;
int answer;
while (TRUE)
{
n = getStringFromArgs(buf, sizeof buf, stdin);
if (n == 0)
return defvalue;
if (defvalue == -999)
{
if (strncasecmp(buf, "expert", n) == 0)
{
if (expert)
printf("\nDisabled expert mode in menus\n");
else
printf("\nEnabled expert mode in menus\n");
expert = !expert;
return defvalue;
}
if (strncasecmp(buf, "paged", n) == 0)
{
if (paged)
{
printf("\nDisabled paged mode\n");
paged = 0;
}
else
{
printf("\nEnabled paged mode, 24 lines\n");
paged = 22;
}
return 999;
}
if (sscanf(buf, "p%d", &i) == 1)
{
if (i >= 4)
{
printf("\nEnabled paged mode, %d lines\n", i);
paged = i - 2;
}
else
{
printf("\nDisabled paged mode\n");
paged = 0;
}
return 999;
}
if (strncasecmp(buf, "wwwwwwww", n) == 0)
{
if (wFlag)
{
wFlag = 0;
printf("\nDisabled logging\n");
fprintf(logFile, "%s: Logging ended\n", logPrefix(NULL));
fclose(logFile);
logFile = NULL;
}
else
{
wFlag = n;
printf("\nEnabled logging (level %d)\n", wFlag);
logFile = fopen("lsiutil.log", "a");
if (logFile)
{
fprintf(logFile, "%s: Logging started at level %d\n", logPrefix(NULL), wFlag);
}
else
{
printf("Open failure for file lsiutil.log!\n");
perror("Error is");
logFile = stderr;
}
}
return 999;
}
if (strncasecmp(buf, "g", n) == 0)
{
gFlag = !gFlag;
return 999;
}
if (strncasecmp(buf, "k", n) == 0)
{
kFlag = !kFlag;
return 999;
}
}
else if (defvalue == -888)
{
if (strncasecmp(buf, "all", n) == 0)
{
return 888;
}
}
for (i = 0; i < n; i++)
if (!isdigit((int)buf[i]))
break;
if (i == n)
{
if (sscanf(buf, "%d", &answer) == 1)
if (answer >= low && answer <= high)
return answer;
}
printf("Invalid answer, try again: ");
}
}
int
getNumberAnswerHex(int low, int high, int defvalue)
{
char buf[64];
int i;
int n;
int answer;
while (TRUE)
{
n = getStringFromArgs(buf, sizeof buf, stdin);
if (n == 0)
return defvalue;
for (i = 0; i < n; i++)
if (!isxdigit((int)buf[i]))
break;
if (i == n)
{
if (sscanf(buf, "%x", &answer) == 1)
if (answer >= low && answer <= high)
return answer;
}
printf("Invalid answer, try again: ");
}
}
int
getHexNumberAnswer(U32 *value)
{
char buf[64];
int i;
int n;
U32 answer;
while (TRUE)
{
n = getStringFromArgs(buf, sizeof buf, stdin);
if (n == 0)
return 0;
for (i = 0; i < n; i++)
if (!isxdigit((int)buf[i]))
break;
if (i == n)
{
if (sscanf(buf, "%x", &answer) == 1)
{
*value = answer;
return 1;
}
}
printf("Invalid answer, try again: ");
}
}
int
getHexDoubleNumberAnswer(U32 *value1, U32 *value2)
{
char buf[64];
int i;
int n;
U32 answer1;
U32 answer2;
while (TRUE)
{
n = getStringFromArgs(buf, sizeof buf, stdin);
if (n == 0)
return 0;
if (n == 16)
{
for (i = 0; i < n; i++)
if (!isxdigit((int)buf[i]))
break;
if (i == n)
{
if (sscanf(buf, "%8x%8x", &answer1, &answer2) == 2)
{
*value1 = answer1;
*value2 = answer2;
return 1;
}
}
}
printf("Invalid answer, try again: ");
}
}
int
parseHexNumberChange(U32 *value)
{
char buf[64];
int i;
int j;
int k;
int n;
U32 answer;
int skip;
U32 shift = 0;
U32 mask = 0xffffffff;
U32 oldvalue;
U32 newvalue;
while (TRUE)
{
skip = 0;
shift = 0;
mask = 0xffffffff;
n = getStringFromArgs(buf, sizeof buf, stdin);
if (n == 0)
return 0;
if (sscanf(buf, "word%d=%n", &i, &k) == 1)
{
if (i <= 1)
{
skip = k;
shift = i * 16;
mask = 0xffff;
}
}
else if (sscanf(buf, "byte%d=%n", &i, &k) == 1)
{
if (i <= 3)
{
skip = k;
shift = i * 8;
mask = 0xff;
}
}
else if (sscanf(buf, "bit%d=%n", &i, &k) == 1)
{
if (i <= 31)
{
skip = k;
shift = i;
mask = 0x1;
}
}
else if (sscanf(buf, "bits%d:%d=%n", &i, &j, &k) == 2)
{
if (i <= 31 && i >= j)
{
skip = k;
shift = j;
mask = 0xffffffff >> (31 - i + j);
}
}
for (i = skip; i < n; i++)
if (!isxdigit((int)buf[i]))
break;
if (i == n)
{
if (sscanf(buf + skip, "%x", &answer) == 1)
{
if ((answer & mask) == answer)
{
oldvalue = *value;
newvalue = (oldvalue & ~(mask << shift)) | (answer << shift);
if (skip)
printf("Old value was %08x, new value is %08x\n", oldvalue, newvalue);
*value = newvalue;
return 1;
}
}
}
printf("Invalid answer, try again: ");
}
}
int
readFile(char *name, unsigned char **outBuf, int *outLen)
{
int file;
struct stat stat;
unsigned char *buf = NULL;
int len;
int t;
file = open(name, O_RDONLY | O_BINARY);
if (file < 0)
{
printf("Open failure for file %s\n", name);
perror("Error is");
return 0;
}
t = fstat(file, &stat);
if (t < 0)
{
printf("Couldn't get size of file %s\n", name);
perror("Error is");
close(file);
return 0;
}
len = (int)stat.st_size;
buf = (unsigned char *)malloc(len + 1);
t = read(file, buf, len);
if (t != len)
{
printf("Read failed for file %s\n", name);
perror("Error is");
free(buf);
close(file);
return 0;
}
close(file);
*outBuf = buf;
*outLen = len;
buf[len] = 0;
return 1;
}
int
queryFile(char *name)
{
unsigned char *imageBuf = NULL;
int imageLen;
MpiFwHeader_t *fwHeader;
U32 checksum;
int i;
if (readFile(name, &imageBuf, &imageLen) == 1)
{
printf("\nQuerying file %s...\n", name);
printWhatString("This", imageBuf, imageLen);
fwHeader = (pMpiFwHeader_t)imageBuf;
if ((get32(fwHeader->Signature0) == MPI_FW_HEADER_SIGNATURE_0 &&
get32(fwHeader->Signature1) == MPI_FW_HEADER_SIGNATURE_1 &&
get32(fwHeader->Signature2) == MPI_FW_HEADER_SIGNATURE_2) ||
(get32(fwHeader->Signature0) == MPI2_FW_HEADER_SIGNATURE0 &&
get32(fwHeader->Signature1) == MPI2_FW_HEADER_SIGNATURE1 &&
get32(fwHeader->Signature2) == MPI2_FW_HEADER_SIGNATURE2))
{
checksum = 0;
for (i = 0; i < imageLen / 4; i++)
checksum += get32x(((U32 *)imageBuf)[i]);
if (checksum != 0)
printf("\nThis image's checksum (%08x) is invalid!\n", checksum);
}
free(imageBuf);
}
return 1;
}
int
printWhatString(char *type, unsigned char *buf, int len)
{
int i;
int j;
char c = 0;
for (i = 0; i < len - 3; i++)
if (buf[i] == '@' && buf[i+1] == '(' && buf[i+2] == '#' && buf[i+3] == ')')
break;
if (i >= len - 3)
{
if (buf[1] == 0xaa && buf[0] == 0x55)
{
PCIR *pcir;
int n;
unsigned short rev, rev1;
n = (buf[0x19]<<8) + buf[0x18];
if (n + (int)sizeof *pcir < len)
{
pcir = (PCIR *)(buf + n);
if (pcir->signature[0] == 'P' &&
pcir->signature[1] == 'C' &&
pcir->signature[2] == 'I' &&
pcir->signature[3] == 'R')
{
if (pcir->type == 1) /* maybe Sun FCode? */
{
for (i = 0; i < len; i++)
if (buf[i] == 0x12 && buf[i+2] == 'L' && buf[i+3] == 'S' && buf[i+4] == 'I')
break;
if (i < len)
{
j = i + buf[i+1] + 2;
c = buf[j];
buf[j] = '\0';
printf("%s image's version is %s\n", type, buf + i + 2);
buf[j] = c;
return len;
}
}
if (pcir->type == 3 &&
buf[5] == 0x0e && buf[4] == 0xf1) /* "efi", how cute */
{
/* SAS2 stored EFI version in 16 bits of imageRevision */
/* SAS3 stored EFI version in imageRevision and reserved field, similar to Legacy BIOS */
/* this is to allow a 32-bit version string */
if ((pcir->deviceId == MPI25_MFGPAGE_DEVID_SAS3004) || /* SAS3 Controllers */
(pcir->deviceId == MPI25_MFGPAGE_DEVID_SAS3008) ||
(pcir->deviceId == MPI25_MFGPAGE_DEVID_SAS3108_1) ||
(pcir->deviceId == MPI25_MFGPAGE_DEVID_SAS3108_2) ||
(pcir->deviceId == MPI25_MFGPAGE_DEVID_SAS3108_5) ||
(pcir->deviceId == MPI25_MFGPAGE_DEVID_SAS3108_6))
{
rev = get16(pcir->imageRevision);
rev1 = get16(get2bytes(pcir->reserved2, 0));
printf("%s image's version is %d.%02d.%02d.%02d\n", type,
(rev >> 8) & 0xff , rev & 0xff, (rev1 >> 8) & 0xff, rev1 & 0xff);
}
else /* everything else */
{
rev = get16(pcir->imageRevision);
printf("%s image's version is %d.%02d.%02d.%02d\n", type,
(rev >> 13) & 0x7, (rev >> 8) & 0x1f, (rev >> 4) & 0xf, (rev >> 0) & 0xf);
}
}
}
}
}
return 0;
}
for (j = i + 4; j < len; j++)
{
if ((c = buf[j]) == '\0' || c == '"' || c == '>' || c == '\n')
break;
}
buf[j] = '\0';
printf("%s image's version is %s\n", type, buf + i + 4);
buf[j] = c;
for (i = j; i < len - 3; i++)
if (buf[i] == '@' && buf[i+1] == '(' && buf[i+2] == '#' && buf[i+3] == ')')
{
for (j = i + 4; j < len; j++)
{
if ((c = buf[j]) == '\0' || c == '"' || c == '>' || c == '\n')
break;
if (j < i + 8)
{
if (!isprint((int)c))
{
i = j;
break;
}
}
else if (c == ' ')
{
if (buf[j-3] == ' ' && buf[j-2] == ' ' && buf[j-1] == ' ')
{
j -= 3;
break;
}
}
}
if (i == j)
continue;
buf[j] = '\0';
if (strcmp((char *)buf + i + 4, "QRY") != 0)
printf(" %s\n", buf + i + 4);
buf[j] = c;
i = j;
}
return len;
}
int
getCompatible(int deviceId, int type)
{
switch (deviceId & ~1)
{
case MPI_MANUFACTPAGE_DEVICEID_FC909: return 1; break;
case MPI_MANUFACTPAGE_DEVICEID_FC919: return 2; break;
case MPI_MANUFACTPAGE_DEVICEID_FC929: return 2; break;
case MPI_MANUFACTPAGE_DEVICEID_FC919X: return 2; break;
case MPI_MANUFACTPAGE_DEVICEID_FC929X: return 2; break;
case MPI_MANUFACTPAGE_DEVICEID_FC939X: return 2; break;
case MPI_MANUFACTPAGE_DEVICEID_FC949X: return 2; break;
case MPI_MANUFACTPAGE_DEVICEID_FC949E: return 2; break;
case MPI_MANUFACTPAGE_DEVID_53C1030: return 3; break;
case MPI_MANUFACTPAGE_DEVID_1030_53C1035: return 3; break;
case MPI_MANUFACTPAGE_DEVID_SAS1064: return 4; break;
case MPI_MANUFACTPAGE_DEVID_SAS1064E: return 4; break;
case MPI_MANUFACTPAGE_DEVID_SAS1066: return 4; break;
case MPI_MANUFACTPAGE_DEVID_SAS1066E: return 4; break;
case MPI_MANUFACTPAGE_DEVID_SAS1068: return 4; break;
case MPI_MANUFACTPAGE_DEVID_SAS1068E: return 4; break;
case MPI_MANUFACTPAGE_DEVID_SAS1078: return 4; break;
case MPI2_MFGPAGE_DEVID_SAS2004: return 5; break;
case MPI2_MFGPAGE_DEVID_SAS2008: return 5; break;
case MPI2_MFGPAGE_DEVID_SAS2108_1: return 5; break;
case MPI2_MFGPAGE_DEVID_SAS2108_2: return 5; break;
case MPI2_MFGPAGE_DEVID_SAS2108_3: return 5; break;
case MPI2_MFGPAGE_DEVID_SAS2116_1: return 5; break;
case MPI2_MFGPAGE_DEVID_SAS2116_2: return 5; break;
case MPI2_MFGPAGE_DEVID_SAS2208_1: return 5; break;
case MPI2_MFGPAGE_DEVID_SAS2208_2: return 5; break;
case MPI2_MFGPAGE_DEVID_SAS2208_3: return 5; break;
case MPI2_MFGPAGE_DEVID_SAS2208_4: return 5; break;
case MPI2_MFGPAGE_DEVID_SAS2208_5: return 5; break;
case MPI2_MFGPAGE_DEVID_SAS2208_6: return 5; break;
case MPI2_MFGPAGE_DEVID_SAS2308_1: return 5; break;
case MPI2_MFGPAGE_DEVID_SAS2308_2: return 5; break;
case MPI2_MFGPAGE_DEVID_SAS2308_3: return 5; break;
case MPI2_MFGPAGE_DEVID_SSS6200: return 5; break;
case MPI25_MFGPAGE_DEVID_SAS3004: return 6; break;
case MPI25_MFGPAGE_DEVID_SAS3008: return 6; break;
case MPI25_MFGPAGE_DEVID_SAS3108_1: return 6; break;
case MPI25_MFGPAGE_DEVID_SAS3108_2: return 6; break;
case MPI25_MFGPAGE_DEVID_SAS3108_5: return 6; break;
case MPI25_MFGPAGE_DEVID_SAS3108_6: return 6; break;
}
return deviceId + 100;
}
int
checkCompatible(int deviceId1, int deviceId2, int type)
{
int id1;
int id2;
id1 = getCompatible(deviceId1, type);
id2 = getCompatible(deviceId2, type);
if (type == 3)
{
/* everything is compatible (one image serves all) */
return 1;
}
return id1 == id2;
}
int
doPort(MPT_PORT *port)
{
int ready;
int option;
ready = checkReady(port);
printf("\n");
option = argsCurr == NULL ? -1 : 0;
while (TRUE)
{
if (!ready || port->notOperational)
{
#if (WIN32 || __linux__ || __sparc__ || DOS || EFI) && REGISTER_ACCESS
printf("50. Dump MPT registers\n");
printf("51. Dump chip memory regions\n");
printf("52. Read/modify chip memory locations\n");
printf("54. Identify FLASH device\n");
#endif
printf("99. Reset port\n");
printf("\n");
option = 0;
}
if (option < 0)
{
printf(" 1. Identify firmware, BIOS, and/or FCode\n");
printf(" 2. Download firmware (update the FLASH)\n");
EXP printf(" 3. Upload firmware\n");
printf(" 4. Download/erase BIOS and/or FCode (update the FLASH)\n");
EXP printf(" 5. Upload BIOS and/or FCode\n");
if (port->pidType != MPI_FW_HEADER_PID_TYPE_SAS)
{
EXP printf(" 6. Download SEEPROM\n");
EXP printf(" 7. Upload SEEPROM\n");
}
printf(" 8. Scan for devices\n");
printf(" 801. Scan for 1 LUN\n");
EXP printf(" 802. Scan for 2 LUN's\n");
EXP printf(" 803. Scan for 3 LUN's\n");
EXP printf(" 804. Scan for 4 LUN's\n");
EXP printf(" 805. Scan for 5 LUN's\n");
EXP printf(" 806. Scan for 6 LUN's\n");
EXP printf(" 807. Scan for 7 LUN's\n");
EXP printf(" 808. Scan for 8 LUN's\n");
EXP printf(" 809. Scan for 9 LUN's\n");
printf(" 810. Scan for 10 LUN's\n");
EXP printf(" 9. Read/change configuration pages\n");
switch (port->deviceId)
{
case MPI_MANUFACTPAGE_DEVICEID_FC939X:
case MPI_MANUFACTPAGE_DEVICEID_FC949X:
case MPI_MANUFACTPAGE_DEVICEID_FC949E:
printf("10. Change IOC settings (interrupt coalescing, EEDP)\n");
break;
default:
printf("10. Change IOC settings (interrupt coalescing)\n");
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SCSI)
{
printf("11. Change SCSI Initiator settings\n");
printf("12. Change SCSI Target settings\n");
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
printf("13. Change FC Port settings\n");
EXP printf("14. Change IO Unit settings (multi-pathing)\n");
EXP printf("15. Change persistent mappings\n");
printf("16. Display logged-in devices\n");
EXP printf("17. Show port aliases\n");
#if DOS || EFI
printf("18. Change FC WWNN/WWPN\n");
#else
EXP printf("18. Change FC WWNN/WWPN\n");
#endif
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
printf("13. Change SAS IO Unit settings\n");
EXP printf("14. Change IO Unit settings (multi-pathing, queuing, caching)\n");
EXP MPI1 printf("15. Change persistent mappings\n");
printf("16. Display attached devices\n");
EXP printf("17. Show expander routing tables\n");
#if DOS || EFI
printf("18. Change SAS WWID\n");
#else
EXP printf("18. Change SAS WWID\n");
#endif
}
EXP printf("19. Test configuration page actions\n");
printf("20. Diagnostics\n");
printf("21. RAID actions\n");
MPI1 printf("22. Reset bus\n");
printf("23. Reset target\n");
EXP printf("24. Clear ACA\n");
EXP MPI2 printf("25. Power Management Control\n");
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
printf("30. Beacon on\n");
printf("31. Beacon off\n");
EXP printf("32. Display SFP pages\n");
}
EXP printf("33. Erase non-volatile adapter storage\n");
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
EXP printf("34. FC management tools\n");
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
EXP printf("34. Remove device from initiator table\n");
EXP printf("35. Display HBA firmware Log entries\n");
EXP printf("36. Clear (erase) HBA firmware Log entries\n");
EXP printf("37. Force full discovery\n");
}
#if DOS || EFI
printf("39. Force firmware download boot\n");
#endif
#if WIN32 || __linux__ || __sparc__
EXP printf("40. Display current events\n");
#endif
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
EXP printf("41. Display transfer statistics\n");
}
#if WIN32 || __linux__ || __sparc__
printf("42. Display operating system names for devices\n");
#endif
#if WIN32 || LINUX_DIAG || __sparc__
if (port->capabilities & (MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER |
MPI_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER))
{
printf("43. Diagnostic Buffer actions\n");
}
#endif
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
EXP printf("44. Program manufacturing information\n");
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
EXP printf("44. Program manufacturing information\n");
printf("45. Concatenate SAS firmware and NVDATA files\n");
}
EXP printf("46. Upload FLASH section\n");
EXP printf("47. Display version information\n");
EXP printf("48. Display chip VPD information\n");
EXP printf("49. Program chip VPD information\n");
#if (WIN32 || __linux__ || __sparc__ || DOS || EFI) && REGISTER_ACCESS
EXP printf("50. Dump MPT registers\n");
EXP printf("51. Dump chip memory regions\n");
EXP printf("52. Read/modify chip memory locations\n");
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
EXP printf("53. Dump FC trace buffer\n");
}
EXP printf("54. Identify FLASH device\n");
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
EXP printf("55. Force firmware to fault (with C0FFEE)\n");
EXP printf("56. Read/write expander memory\n");
EXP printf("57. Read/write expander ISTWI device\n");
}
#endif
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
EXP printf("58. Alta diagnostics\n");
}
printf("59. Dump PCI config space\n");
printf("60. Show non-default settings\n");
printf("61. Restore default settings\n");
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
EXP printf("62. Update default PhyRegs settings\n");
EXP printf("63. Set personal WWNN/WWPN\n");
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
EXP printf("64. SAS Expander UART Console\n");
EXP MPI2 printf("65. SAS UART Debug Console\n");
printf("66. Show SAS discovery errors\n");
}
EXP printf("67. Dump all port state\n");
EXP printf("68. Show port state summary\n");
printf("69. Show board manufacturing information\n");
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC ||
port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
EXP printf("70. Dump all device pages\n");
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
EXP MPI2 printf("71. Dump all SAS device page 0's\n");
#if LSIINTERNAL
EXP MPI20 printf("72. Store SC Information\n");
#endif
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
EXP printf("80. Set port offline\n");
EXP printf("81. Set port online\n");
EXP printf("82. Set port to NL_Port\n");
EXP printf("83. Set port to N_Port\n");
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
EXP printf("80. Set SAS phy offline\n");
EXP printf("81. Set SAS phy online\n");
}
EXP printf("90. Send SCSI CDB\n");
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
EXP printf("93. Send GIEL\n");
EXP printf("94. Send GID_FT\n");
EXP printf("95. Send GA_NXT\n");
EXP printf("96. Send ELS request\n");
EXP printf("97. Reset FC link, Maintain Logins\n");
printf("98. Reset FC link\n");
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
EXP printf("95. Send SATA request\n");
EXP printf("96. Send SMP request\n");
printf("97. Reset SAS link, HARD RESET\n");
printf("98. Reset SAS link\n");
}
printf("99. Reset port\n");
if (expert)
printf(" e Disable expert mode in menus\n");
else
printf(" e Enable expert mode in menus\n");
if (paged)
printf(" p Disable paged mode\n");
else
printf(" p Enable paged mode\n");
if (wFlag)
printf(" w Disable logging\n");
else
printf(" w Enable logging\n");
printf("\n");
}
printf("Main menu, select an option: [1-99 or e/p/w or 0 to quit] ");
option = getNumberAnswer(0, 999, -999);
if (option < 0 || option == 999)
{
printf("\n");
continue;
}
if (option == 0)
break;
doPortOption(port, option);
printf("\n");
}
return 1;
}
int
doPortOption(MPT_PORT *port, int option)
{
int ready;
int t;
ready = checkReady(port);
if (option == 0 || option == 111)
return 1;
printf("\n");
if (iocMask & (1 << port->iocNumber))
{
switch (option)
{
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 14:
case 33:
case 39:
case 44:
case 48:
case 49:
case 51:
case 52:
case 54:
case 53:
case 55:
case 62:
case 99:
printf("Option %d skipped for %s\n", option, port->portName);
return 1;
}
}
if (!ready || port->notOperational)
{
switch (option)
{
#if (WIN32 || __linux__ || __sparc__ || DOS || EFI) && REGISTER_ACCESS
case 50:
doDumpRegisters(port);
break;
case 51:
doDumpChipMemoryRegions(port);
break;
case 52:
doReadModifyChipMemoryLocations(port);
break;
case 54:
doFlashInfo(port);
break;
#endif
case 99:
doResetPort(port);
break;
default:
printf("Invalid selection!\n");
break;
}
return 1;
}
updatePortInfo(port);
switch (option)
{
case 1:
doIdentify(port);
break;
case 2:
doFirmwareDownload(port);
break;
case 3:
doFirmwareUpload(port);
break;
case 4:
doBiosFcodeDownload(port);
break;
case 5:
doBiosFcodeUpload(port, NULL, NULL, 0);
break;
case 6:
if (port->pidType != MPI_FW_HEADER_PID_TYPE_SAS)
{
doSeepromDownload(port);
break;
}
printf("Invalid selection!\n");
break;
case 7:
if (port->pidType != MPI_FW_HEADER_PID_TYPE_SAS)
{
doSeepromUpload(port);
break;
}
printf("Invalid selection!\n");
break;
case 8:
doScanForDevices(port, 1);
break;
case 801:
doScanForLuns(port, 1 , option);
break;
case 802:
doScanForLuns(port, 1 , option);
break;
case 803:
doScanForLuns(port, 1 , option);
break;
case 804:
doScanForLuns(port, 1 , option);
break;
case 805:
doScanForLuns(port, 1 , option);
break;
case 806:
doScanForLuns(port, 1 , option);
break;
case 807:
doScanForLuns(port, 1 , option);
break;
case 808:
doScanForLuns(port, 1 , option);
break;
case 809:
doScanForLuns(port, 1 , option);
break;
case 810:
doScanForLuns(port, 1 , option);
break;
case 9:
doConfigPage(port);
break;
case 10:
doIocSettings(port);
break;
case 11:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SCSI)
{
doScsiInitiatorSettings(port);
break;
}
printf("Invalid selection!\n");
break;
case 12:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SCSI)
{
doScsiTargetSettings(port);
break;
}
printf("Invalid selection!\n");
break;
case 13:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doFcPortSettings(port);
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doSasIoUnitSettings(port);
break;
}
printf("Invalid selection!\n");
break;
case 14:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC ||
port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doIoUnitSettings(port);
break;
}
printf("Invalid selection!\n");
break;
case 15:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC ||
port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
option = argsCurr == NULL ? -1 : 0;
while (TRUE)
{
if (option < 0)
{
printf(" 1. Show persistent mappings\n");
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
printf(" 2. Automatically add persistent mappings for ALL targets\n");
EXP printf(" 3. Automatically add persistent mappings for SOME targets\n");
printf(" 4. Delete persistent mappings for ALL targets\n");
EXP printf(" 5. Delete persistent mappings for SOME targets\n");
EXP printf(" 6. Manually add persistent mappings for targets\n");
EXP printf(" 7. Automatically add persistent mappings for ALL LoopIDs\n");
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
EXP printf(" 4. Delete persistent mappings for ALL targets\n");
EXP printf(" 5. Delete persistent mappings for SOME targets\n");
printf(" 6. Change Bus/Target or EnclosureId of an existing mapping\n");
printf(" 7. Save persistent mappings to a file\n");
printf(" 8. Load persistent mappings from a file\n");
printf("10. Clear all persistent mappings\n");
printf("11. Clear all non-present persistent mappings\n");
printf("12. Change (enable/disable) persistence\n");
}
printf("99. Reset port\n");
if (expert)
printf(" e Disable expert mode in menus\n");
else
printf(" e Enable expert mode in menus\n");
if (paged)
printf(" p Disable paged mode\n");
else
printf(" p Enable paged mode\n");
if (wFlag)
printf(" w Disable logging\n");
else
printf(" w Enable logging\n");
printf("\n");
}
printf("Persistence menu, select an option: [1-99 or e/p/w or 0 to quit] ");
option = getNumberAnswer(0, 99, -999);
if (option < 0 || option == 999)
{
printf("\n");
continue;
}
if (option == 0)
break;
printf("\n");
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
if (option <= 7)
{
doFcPersistentMappings(port, option);
}
else if (option == 99)
{
doResetPort(port);
}
else
{
printf("Invalid selection!\n");
}
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS && mpi1)
{
if (option == 1 || (option >= 4 && option <= 8) || (option >= 10 && option <= 12))
{
doSasPersistentMappings(port, option);
}
else if (option == 99)
{
doResetPort(port);
}
else
{
printf("Invalid selection!\n");
}
}
printf("\n");
}
option = -1;
break;
}
printf("Invalid selection!\n");
break;
case 16:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doDisplayLoggedInDevices(port);
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doDisplayAttachedDevices(port);
break;
}
printf("Invalid selection!\n");
break;
case 17:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doShowPortAliases(port);
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doShowExpanderRoutingTables(port);
break;
}
printf("Invalid selection!\n");
break;
case 18:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doFcChangeWwn(port);
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doSasChangeWwid(port, 0);
break;
}
printf("Invalid selection!\n");
break;
case 19:
doTestConfigPageActions(port);
break;
case 20:
option = argsCurr == NULL ? -1 : 0;
while (TRUE)
{
if (option < 0)
{
printf(" 1. Inquiry Test\n");
printf(" 2. WriteBuffer/ReadBuffer/Compare Test\n");
printf(" 3. Read Test\n");
printf(" 4. Write/Read/Compare Test\n");
EXP printf(" 5. Write Test\n");
EXP printf(" 6. Read/Compare Test\n");
#if 0
EXP printf(" 7. Test Unit Ready Test\n");
#else
EXP printf(" 7. Log Sense Test\n");
#endif
printf(" 8. Read Capacity / Read Block Limits Test\n");
EXP printf(" 9. Mode Page Test\n");
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
printf("10. Echo ELS Test\n");
EXP printf("11. Read Link Error Status ELS Test\n");
printf("12. Display port counters\n");
printf("13. Clear port counters\n");
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
EXP printf("10. SATA Identify Device Test\n");
EXP printf("11. SATA Clear Affiliation Test\n");
printf("12. Display phy counters\n");
printf("13. Clear phy counters\n");
printf("14. SATA SMART Read Test\n");
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SCSI ||
port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
printf("15. SEP (SCSI Enclosure Processor) Test\n");
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
EXP printf("16. Issue product-specific SAS IO Unit Control\n");
}
EXP printf("17. Diag data upload\n");
printf("18. Report LUNs Test\n");
printf("19. Drive firmware download\n");
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
EXP printf("20. Trigger FC Analyzer With Echo ELS\n");
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
printf("20. Expander firmware download\n");
}
printf("21. Read Logical Blocks\n");
EXP printf("22. Write Logical Blocks\n");
EXP printf("23. Verify Logical Blocks\n");
EXP printf("24. Read Buffer (for firmware upload)\n");
EXP printf("25. Display Expander Log entries\n");
EXP printf("26. Clear (erase) Expander Log entries\n");
EXP printf("27. Change SAS2/SAS3 Expander Manufacturing Data Fields\n");
EXP printf("29. Diagnostic Page Test\n");
EXP printf("30. Inject media error\n");
EXP printf("31. Repair media error\n");
EXP printf("32. Set software write protect\n");
EXP printf("33. Clear software write protect\n");
EXP printf("34. Enable read cache\n");
EXP printf("35. Disable read cache\n");
EXP printf("36. Enable write cache\n");
EXP printf("37. Disable write cache\n");
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
EXP printf("98. Reset expander\n");
}
printf("99. Reset port\n");
if (expert)
printf(" e Disable expert mode in menus\n");
else
printf(" e Enable expert mode in menus\n");
if (paged)
printf(" p Disable paged mode\n");
else
printf(" p Enable paged mode\n");
if (wFlag)
printf(" w Disable logging\n");
else
printf(" w Enable logging\n");
printf("\n");
}
printf("Diagnostics menu, select an option: [1-99 or e/p/w or 0 to quit] ");
option = getNumberAnswer(0, 99, -999);
if (option < 0 || option == 999)
{
printf("\n");
continue;
}
if (option == 0)
break;
printf("\n");
if (option == 99)
doResetPort(port);
else
doDiagnostics(port, option);
printf("\n");
}
option = -1;
break;
case 21:
option = argsCurr == NULL ? -1 : 0;
while (TRUE)
{
if (option < 0)
{
printf(" 1. Show volumes\n");
printf(" 2. Show physical disks\n");
printf(" 3. Get volume state\n");
printf(" 4. Wait for volume resync to complete\n");
EXP printf("10. Disable all volumes\n");
EXP printf("11. Enable all volumes\n");
EXP MPI1 printf("12. Inactivate volume\n");
EXP printf("13. Activate volume\n");
EXP printf("20. Offline physical disk\n");
EXP printf("21. Online physical disk\n");
EXP printf("22. Fail physical disk\n");
MPI1 printf("23. Replace physical disk\n");
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
EXP MPI1 printf("24. Quiesce physical disk I/Os\n");
EXP MPI1 printf("25. Unquiesce physical disk I/Os\n");
}
printf("26. Disable drive firmware update mode\n");
printf("27. Enable drive firmware update mode\n");
printf("30. Create volume\n");
printf("31. Delete volume\n");
printf("32. Change volume settings\n");
printf("33. Change volume name\n");
MPI2 printf("34. Volume consistency check\n");
MPI2 printf("35. Stop volume consistency check\n");
MPI2 printf("36. Online Capacity Expansion\n");
// MPI1 printf("40. Create physical disk\n");
EXP MPI1 printf("41. Delete physical disk\n");
EXP MPI1 printf("42. Change physical disk settings\n");
printf("50. Create hot spare\n");
printf("51. Delete hot spare\n");
EXP MPI2 printf("60. Change RAID rate\n");
printf("99. Reset port\n");
if (expert)
printf(" e Disable expert mode in menus\n");
else
printf(" e Enable expert mode in menus\n");
if (paged)
printf(" p Disable paged mode\n");
else
printf(" p Enable paged mode\n");
if (wFlag)
printf(" w Disable logging\n");
else
printf(" w Enable logging\n");
printf("\n");
}
printf("RAID actions menu, select an option: [1-99 or e/p/w or 0 to quit] ");
option = getNumberAnswer(0, 99, -999);
if (option < 0 || option == 999)
{
printf("\n");
continue;
}
if (option == 0)
break;
printf("\n");
if (option == 99)
doResetPort(port);
else
doRaidActions(port, option);
printf("\n");
}
option = -1;
break;
case 22:
if (mpi1)
{
doResetBus(port);
break;
}
printf("Invalid selection!\n");
break;
case 23:
doResetTarget(port);
break;
case 24:
doClearAca(port);
break;
case 25:
// Power Management Control
option = argsCurr == NULL ? -1 : 0;
while (TRUE)
{
if (option < 0)
{
printf(" 1. Send Power Management Control MPI message\n");
printf(" 2. Display IOUnit7 Config Page\n");
printf(" 3. Get/Set SASIoUnit8 Config Page\n");
printf("\n");
}
printf("Power Management actions menu, select an option: [1-99 or e/p/w or 0 to quit] ");
option = getNumberAnswer(0, 99, -999);
if (option < 0 || option == 999)
{
printf("\n");
continue;
}
if (option == 0)
break;
printf("\n");
switch (option)
{
case 1:
doSendPowerManagementControlMPI(port);
break;
case 2:
doIoUnit7Settings(port);
break;
case 3:
doSasIoUnit8Settings(port);
break;
}
printf("\n");
}
option = -1;
break;
case 30:
doBeacon(port, 1);
break;
case 31:
doBeacon(port, 0);
break;
case 32:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doDisplaySfpPages(port);
break;
}
printf("Invalid selection!\n");
break;
case 33:
doClean(port);
break;
case 34:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doFcManagementTools(port);
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doRemoveSasDevice(port);
break;
}
printf("Invalid selection!\n");
break;
case 35:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doDisplayLogEntries(port);
break;
}
printf("Invalid selection!\n");
break;
case 36:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doClearLogEntries(port);
break;
}
printf("Invalid selection!\n");
break;
case 37:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doSasForceFullDiscovery(port);
break;
}
printf("Invalid selection!\n");
break;
#if DOS || EFI
case 39:
doFirmwareDownloadBoot(port);
break;
#endif
#if WIN32 || __linux__ || __sparc__
case 40:
doDisplayCurrentEvents(port);
break;
#endif
case 41:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doDisplayTransferStatistics(port);
break;
}
printf("Invalid selection!\n");
break;
#if WIN32 || __linux__ || __sparc__
case 42:
doDisplayOsDeviceNames(port);
break;
#endif
#if WIN32 || LINUX_DIAG || __sparc__
case 43:
if (port->capabilities & (MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER |
MPI_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER))
{
doDiagBuffer(port);
break;
}
printf("Invalid selection!\n");
break;
#endif
case 44:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
t = doWriteFcManufacturingInfo(port);
if (wFlag)
fprintf(logFile, "%s: Program Manufacturing Information: %s\n",
logPrefix(port), t ? "PASS" : "FAIL");
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
t = doWriteSasManufacturingInfo(port);
if (wFlag)
fprintf(logFile, "%s: Program Manufacturing Information: %s\n",
logPrefix(port), t ? "PASS" : "FAIL");
break;
}
printf("Invalid selection!\n");
break;
case 45:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
concatenateSasFirmwareNvdata();
break;
}
printf("Invalid selection!\n");
break;
case 46:
doFlashUpload(port);
break;
case 47:
doDisplayVersionInfo(port);
break;
case 48:
doDisplayVpdInfo(port);
break;
case 49:
t = doProgramVpdInfo(port);
if (wFlag)
fprintf(logFile, "%s: Program VPD Information: %s\n",
logPrefix(port), t ? "PASS" : "FAIL");
break;
#if (WIN32 || __linux__ || __sparc__ || DOS || EFI) && REGISTER_ACCESS
case 50:
doDumpRegisters(port);
break;
case 51:
doDumpChipMemoryRegions(port);
break;
case 52:
doReadModifyChipMemoryLocations(port);
break;
case 53:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doDumpFcTraceBuffer(port);
break;
}
printf("Invalid selection!\n");
break;
case 54:
doFlashInfo(port);
break;
case 55:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doForceFirmwareFault(port);
break;
}
printf("Invalid selection!\n");
break;
#endif
case 56:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doReadWriteExpanderMemory(port);
break;
}
printf("Invalid selection!\n");
break;
case 57:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doReadWriteExpanderIstwiDevice(port);
break;
}
printf("Invalid selection!\n");
break;
case 58:
option = argsCurr == NULL ? -1 : 0;
while (TRUE)
{
if (option < 0)
{
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
printf(" 1. Program manufacturing information\n");
printf(" 2. Display manufacturing information\n");
printf(" 3. Reset Alta\n");
}
if (expert)
printf(" e Disable expert mode in menus\n");
else
printf(" e Enable expert mode in menus\n");
if (paged)
printf(" p Disable paged mode\n");
else
printf(" p Enable paged mode\n");
if (wFlag)
printf(" w Disable logging\n");
else
printf(" w Enable logging\n");
printf("\n");
}
printf("Alta diagnostics menu, select an option: [1-99 or e/p/w or 0 to quit] ");
option = getNumberAnswer(0, 99, -999);
if (option < 0 || option == 999)
{
printf("\n");
continue;
}
if (option == 0)
break;
printf("\n");
doAltaDiagnostics(port, option);
printf("\n");
}
option = -1;
break;
case 59:
doDumpPciConfigSpace(port);
break;
case 60:
doShowNonDefaultSettings(port);
break;
case 61:
doRestoreDefaultSettings(port);
break;
case 62:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doDefaultPhyRegsSettings(port);
break;
}
printf("Invalid selection!\n");
break;
case 63:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doFcChangePersonalWwn(port);
break;
}
printf("Invalid selection!\n");
break;
case 64:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doExpanderUart(port);
break;
}
printf("Invalid selection!\n");
break;
case 65:
if (mpi2 && port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doUartDebugConsole(port);
break;
}
printf("Invalid selection!\n");
break;
case 66:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
showSasDiscoveryErrors(port);
break;
}
printf("Invalid selection!\n");
break;
case 67:
doDumpPortState(port, 1);
break;
case 68:
doPortStateSummary(port);
break;
case 69:
showBoardInfo(port, 1);
break;
case 70:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
dumpFcDevicePages(port);
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
dumpSasDevicePages(port);
break;
}
printf("Invalid selection!\n");
break;
case 71:
if (mpi2 && port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
dumpSasDevicePage0sLong(port);
break;
}
printf("Invalid selection!\n");
break;
case 72:
#if LSIINTERNAL
if (mpi2 && port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doSCProgram(port);
break;
}
#endif
printf("Invalid selection!\n");
break;
case 80:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doFcPortOffline(port);
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doSasPhyOnOffline(port, 0);
break;
}
printf("Invalid selection!\n");
break;
case 81:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doFcPortOnline(port);
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doSasPhyOnOffline(port, 1);
break;
}
printf("Invalid selection!\n");
break;
case 82:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doFcTopologyNLPort(port);
break;
}
printf("Invalid selection!\n");
break;
case 83:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doFcTopologyNPort(port);
break;
}
printf("Invalid selection!\n");
break;
case 86:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doFcSpecialMode(port, 1, 0);
break;
}
printf("Invalid selection!\n");
break;
case 87:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doFcSpecialMode(port, 0, 0);
break;
}
printf("Invalid selection!\n");
break;
case 88:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doFcSpecialMode(port, 1, 1);
break;
}
printf("Invalid selection!\n");
break;
case 89:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doFcSpecialMode(port, 0, 1);
break;
}
printf("Invalid selection!\n");
break;
case 90:
doScsiCdb(port);
break;
case 93:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doGIEL(port);
break;
}
printf("Invalid selection!\n");
break;
case 94:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doGID_FT(port);
break;
}
printf("Invalid selection!\n");
break;
case 95:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doGA_NXT(port);
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doSataPassthroughSend(port);
break;
}
printf("Invalid selection!\n");
break;
case 96:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doExLinkServiceSend(port);
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doSmpPassthroughSend(port);
break;
}
printf("Invalid selection!\n");
break;
case 97:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doResetFcLink(port, 1);
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doResetSasLink(port, 1);
break;
}
printf("Invalid selection!\n");
break;
case 98:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doResetFcLink(port, 0);
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doResetSasLink(port, 0);
break;
}
printf("Invalid selection!\n");
break;
case 99:
doResetPort(port);
break;
case 100:
doDumpPortState(port, 1);
break;
case 101:
doPortStateSummary(port);
break;
case 102:
showBoardInfo(port, 1);
break;
default:
printf("Invalid selection!\n");
break;
}
return 1;
}
int
doIdentify(MPT_PORT *port)
{
unsigned char *imageBuf;
int imageLen;
int actualImageLen;
int offset;
unsigned char *buf;
int len;
int i;
int n;
PCIR *pcir;
char *type;
i = port->fwVersion;
if (port->mptVersion < MPI_VERSION_01_02)
{
printf("Current active firmware version is %08x (%d.%02d.%02d)\n",
i, (i >> 12) & 0xf, (i >> 8) & 0xf, i & 0xff);
}
else
{
if (i & 0xff)
{
printf("Current active firmware version is %08x (%d.%02d.%02d.%02d)\n",
i, (i >> 24) & 0xff, (i >> 16) & 0xff, (i >> 8) & 0xff, i & 0xff);
}
else
{
printf("Current active firmware version is %08x (%d.%02d.%02d)\n",
i, (i >> 24) & 0xff, (i >> 16) & 0xff, (i >> 8) & 0xff);
}
}
imageLen = 0x10000;
imageBuf = (unsigned char *)malloc(imageLen);
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
i = MPI_FW_UPLOAD_ITYPE_FW_BACKUP;
else
i = MPI_FW_UPLOAD_ITYPE_FW_FLASH;
if (doFwUpload(port, i, imageBuf, imageLen, 0, &actualImageLen) == 1)
{
printWhatString("Firmware", imageBuf, imageLen);
}
offset = 0;
while (offset < 0x80000)
{
if (doFwUpload(port, MPI_FW_UPLOAD_ITYPE_BIOS_FLASH, imageBuf, imageLen, offset, &actualImageLen) != 1)
break;
if (port->pidType != MPI_FW_HEADER_PID_TYPE_SCSI)
{
if (offset >= actualImageLen)
break;
}
for (i = 0; i < imageLen; i += 512)
{
buf = imageBuf + i;
n = (buf[0x01]<<8) + buf[0x00];
if (n != 0xaa55)
continue;
n = (buf[0x19]<<8) + buf[0x18];
if (i + n + (int)sizeof *pcir > imageLen)
{
// not all of the image is in the buffer, so quit now and read more of the image
break;
}
pcir = (PCIR *)(buf + n);
if (pcir->signature[0] != 'P' ||
pcir->signature[1] != 'C' ||
pcir->signature[2] != 'I' ||
pcir->signature[3] != 'R')
{
printf("Image's PCIR signature is invalid!\n");
type = "Unknown";
len = 512;
}
else
{
len = get16(pcir->imageLength) * 512;
if (i + len > imageLen)
{
// not all of the image is in the buffer, so quit now and read more of the image
if (len > imageLen)
{
free(imageBuf);
imageLen = len;
imageBuf = (unsigned char *)malloc(len);
}
break;
}
switch (pcir->type)
{
case 0: type = "x86 BIOS"; break;
case 1: type = "FCode"; break;
case 3: type = "EFI BIOS"; break;
default: type = "Unknown"; break;
}
if (pcir->type == 255)
{
if (buf[4] == 'L' && buf[5] == 'S' && buf[6] == 'I' && buf[7] == 'L' && buf[0x34] == 0x02)
type = NULL;
}
if (pcir->indicator & 0x80)
{
// last image, so make sure we quit after this
i += 0x80000;
}
}
if (type)
printWhatString(type, buf, len);
i += len - 512;
}
offset += i;
}
free(imageBuf);
return 1;
}
int
doFirmwareDownload(MPT_PORT *port)
{
ManufacturingPage0_t ManufacturingPage0;
char name[256];
unsigned char *imageBuf = NULL;
int imageLen;
int len;
int n;
int warn = 0;
MpiFwHeader_t *fwHeader;
MpiExtImageHeader_t *fwExtImageHeader;
Mpi2ExtImageHeader_t *fwExtImageHeader2;
Mpi2SupportedDevicesData_t *fwSupportedDevices;
U32 fwNextImage;
int i;
U32 t;
U32 checksum;
char *productId;
int cur2MB;
int new2MB;
U32 buf0[16];
#if REGISTER_ACCESS
U32 buf1[16];
U32 buf2[16];
U32 buf4[16];
U32 zeros[16];
int romSize;
#endif
#if DOS || EFI
HANDLE adap = port->fileHandle;
int mustExit = 0;
#endif
unsigned char *imageBufUpload;
int imageLenUpload;
int actualImageLenUpload;
int offset;
int type;
int skip_verify = 0;
n = getFileName(name, sizeof name, stdin, "firmware", 0);
if (n > 0)
{
if (readFile(name, &imageBuf, &imageLen) != 1)
return 0;
}
else
{
printf("Image won't be downloaded\n");
return 1;
}
printWhatString("Firmware", imageBuf, imageLen);
checksum = 0;
for (i = 0; i < imageLen / 4; i++)
checksum += get32x(((U32 *)imageBuf)[i]);
if (checksum != 0)
{
if (!warn)
printf("\n");
printf("Image's checksum is invalid!\n");
printf(" The image appears to be corrupted, proceed with caution\n");
warn = 1;
}
if (port->mptVersion > MPI_VERSION_01_00)
{
fwHeader = (pMpiFwHeader_t)imageBuf;
if (get16(fwHeader->VendorId) != MPI_MANUFACTPAGE_VENDORID_LSILOGIC)
{
if (!warn)
printf("\n");
printf("Image's Vendor ID appears to be wrong!\n");
printf(" Current hardware Vendor ID is %04x\n", MPI_MANUFACTPAGE_VENDORID_LSILOGIC);
printf(" Image's hardware Vendor ID is %04x\n", get16(fwHeader->VendorId));
warn = 1;
}
if (get16(fwHeader->ProductId) != port->productId)
{
if (!warn)
printf("\n");
printf("Image's Product ID appears to be wrong!\n");
printf(" Current firmware Product ID is %04x\n", port->productId);
printf(" Image's firmware Product ID is %04x\n", get16(fwHeader->ProductId));
warn = 1;
}
len = get32(fwHeader->ImageSize);
fwNextImage = get32(fwHeader->NextImageHeaderOffset);
while (fwNextImage != 0)
{
if (fwNextImage > imageLen - sizeof *fwExtImageHeader)
{
if (!warn)
printf("\n");
printf("Image's NextImageHeaderOffset field is invalid!\n");
printf(" The image appears to be corrupted, proceed with caution\n");
warn = 1;
break;
}
fwExtImageHeader = (pMpiExtImageHeader_t)(imageBuf + fwNextImage);
fwExtImageHeader2 = (pMpi2ExtImageHeader_t)fwExtImageHeader;
if (fwExtImageHeader->ImageType == MPI_EXT_IMAGE_TYPE_NVDATA)
{
if (get32(fwExtImageHeader->ImageSize) <= sizeof *fwExtImageHeader)
{
if (!warn)
printf("\n");
printf("Image's attached NVDATA is invalid!\n");
printf(" Using this image is likely to cause pain and suffering\n");
warn = 1;
}
else if (mpi1)
{
productId = getSasProductId(mpi2 ? (char *)(fwExtImageHeader2 + 1)
: (char *)(fwExtImageHeader + 1));
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
&ManufacturingPage0, sizeof ManufacturingPage0) == 1)
{
if (strcmp(productId, (char *)ManufacturingPage0.BoardName) != 0)
{
if (!warn)
printf("\n");
printf("Image's attached NVDATA appears to be for the wrong board!\n");
printf(" Current Board Name is %-16s\n", ManufacturingPage0.BoardName);
printf(" Image's Board Name is %-16s\n", productId);
warn = 1;
}
}
}
}
if (fwExtImageHeader->ImageType == MPI2_EXT_IMAGE_TYPE_SUPPORTED_DEVICES)
{
fwSupportedDevices = (pMpi2SupportedDevicesData_t)(fwExtImageHeader2 + 1);
for (i = 0; i < fwSupportedDevices->NumberOfDevices; i++)
{
t = port->deviceIdRaw & ~get16(fwSupportedDevices->SupportedDevice[i].DeviceIDMask);
if (t == get16(fwSupportedDevices->SupportedDevice[i].DeviceID) &&
port->revisionId >= fwSupportedDevices->SupportedDevice[i].LowPCIRev &&
port->revisionId <= fwSupportedDevices->SupportedDevice[i].HighPCIRev)
{
break;
}
}
if (i == fwSupportedDevices->NumberOfDevices)
{
if (!warn)
printf("\n");
printf("Image's Supported Device List appears to be wrong!\n");
printf(" Current hardware Device ID is %04x, Revision ID is %02x\n",
port->deviceIdRaw, port->revisionId);
for (i = 0; i < fwSupportedDevices->NumberOfDevices; i++)
{
if (fwSupportedDevices->SupportedDevice[i].LowPCIRev ==
fwSupportedDevices->SupportedDevice[i].HighPCIRev)
{
printf(" Image's hardware Device ID is %04x, Revision ID is %02x\n",
get16(fwSupportedDevices->SupportedDevice[i].DeviceID),
fwSupportedDevices->SupportedDevice[i].LowPCIRev);
}
else
{
printf(" Image's hardware Device ID is %04x, Revision ID is %02x to %02x\n",
get16(fwSupportedDevices->SupportedDevice[i].DeviceID),
fwSupportedDevices->SupportedDevice[i].LowPCIRev,
fwSupportedDevices->SupportedDevice[i].HighPCIRev);
}
}
warn = 1;
}
}
len += get32(fwExtImageHeader->ImageSize);
fwNextImage = get32(fwExtImageHeader->NextImageHeaderOffset);
}
if (len != imageLen)
{
if (!warn)
printf("\n");
printf("Image's length is invalid!\n");
printf(" The image appears to be corrupted, proceed with caution\n");
warn = 1;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
t = get16(fwHeader->ProductId);
if ((port->deviceId == MPI_MANUFACTPAGE_DEVICEID_FC919X ||
port->deviceId == MPI_MANUFACTPAGE_DEVICEID_FC929X) &&
port->revisionId >= 0x80 &&
t == (MPI_FW_HEADER_PID_TYPE_FC|MPI_FW_HEADER_PID_FAMILY_919X_FC))
{
t = get32(fwHeader->FWVersion.Word);
if (t < 0x0102090d)
{
if (!warn)
printf("\n");
printf("Image is for FC929X, port is FC929XL, image is not compatible!\n");
warn = 1;
}
}
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS && mpi1)
{
t = get32(fwHeader->SeqCodeVersion);
if (t != port->seqCodeVersion)
{
if (!warn)
printf("\n");
printf("Image is for %X, port is %X, image is not compatible!\n", t, port->seqCodeVersion);
warn = 1;
}
#if DOS || EFI
if (adap->bootloader)
cur2MB = get32x(((U32 *)adap->fw_image)[5]) & 1;
else
#endif
if (doFwUpload(port, MPI_FW_UPLOAD_ITYPE_FW_FLASH, (unsigned char *)buf0, sizeof buf0, 0, &i) == 1)
cur2MB = get32x(buf0[5]) & 1;
else
cur2MB = 0;
new2MB = get32x(((U32 *)imageBuf)[5]) & 1;
if (cur2MB != new2MB)
{
if (new2MB)
{
#if REGISTER_ACCESS
doReadChipMemoryRegions(port, 0x3e000000, buf0, sizeof buf0 / 4);
doReadChipMemoryRegions(port, 0x3e100000, buf1, sizeof buf1 / 4);
doReadChipMemoryRegions(port, 0x3e200000, buf2, sizeof buf2 / 4);
doReadChipMemoryRegions(port, 0x3e400000, buf4, sizeof buf4 / 4);
memset(zeros, 0, sizeof zeros);
if (memcmp(buf0, zeros, sizeof buf0) == 0)
romSize = 0;
else if (memcmp(buf0, buf1, sizeof buf0) == 0)
romSize = 1;
else if (memcmp(buf0, buf2, sizeof buf0) == 0)
romSize = 2;
else if (memcmp(buf0, buf4, sizeof buf0) == 0)
romSize = 4;
else
romSize = 0;
if (romSize == 1)
{
printf("\nImage requires 2 MB FLASH ROM, current FLASH ROM is 1 MB\n");
printf("\nFirmware download cannot be performed!\n");
free(imageBuf);
return 0;
}
#endif
}
}
t = port->fwVersion;
if (t == 0x01126300) // 1.18.99, "bridge" from phase 8 to phase 9
{
if (new2MB)
{
printf("\nVersion 1.18.99 is being used to upgrade to Phase 9 firmware\n");
cur2MB = 1;
skip_verify = 1;
}
else
{
printf("\nVersion 1.18.99 can only be used to upgrade to Phase 9 firmware\n");
printf("\nFirmware download cannot be performed!\n");
free(imageBuf);
return 0;
}
}
t = get32(fwHeader->FWVersion.Word);
if (t == 0x01126300) // 1.18.99, "bridge" from phase 8 to phase 9
{
if (cur2MB)
{
printf("\nVersion 1.18.99 cannot be used to downgrade to Phase 8 firmware\n");
printf("\nFirmware download cannot be performed!\n");
free(imageBuf);
return 0;
}
else
{
printf("\nVersion 1.18.99 can only be used to upgrade to Phase 9 firmware\n");
printf("\nMake sure to do the second firmware download as soon as possible\n");
skip_verify = 1;
}
}
if (cur2MB != new2MB)
{
#if DOS || EFI
if (adap->fw_image != NULL)
free(adap->fw_image);
adap->fw_image = malloc(imageLen);
adap->fw_image_size = imageLen;
memcpy(adap->fw_image, imageBuf, imageLen);
adap->ioc_online = FALSE;
if (adap->partner_adap != NULL)
{
adap->partner_adap->ioc_online = FALSE;
adap->partner_adap->fw_image = adap->fw_image;
adap->partner_adap->fw_image_size = 0;
}
if (mpt_fwdownloadboot(adap) != 1)
{
printf("\nThe chip was not made operational with this firmware!\n");
printf("\nFirmware download cannot be performed!\n");
mpt_stop(adap, TRUE);
return 0;
}
mustExit = 1;
#else
if (new2MB)
{
printf("\nSwitching from a 1 MB to a 2 MB FLASH ROM image requires special actions\n");
printf("\nIt can either be done using the 1.18.99 bridge firmware image, or...\n");
printf("\nUse the DOS or EFI version of lsiutil to perform the firmware download\n");
free(imageBuf);
return 0;
}
else
{
printf("\nSwitching from a 2 MB to a 1 MB FLASH ROM image cannot be done online!\n");
printf("\nUse the DOS or EFI version of lsiutil to perform the firmware download\n");
free(imageBuf);
return 0;
}
#endif
}
}
}
if (warn && noFlag == TRUE)
{
free(imageBuf);
return 0;
}
if (warn || yesFlag == FALSE)
{
if (warn)
printf("\nAre you sure you want to continue? [Yes or No, default is No] ");
else
printf("\nDo you want to continue? [Yes or No, default is No] ");
if (getYesNoAnswer(0) != 1)
{
free(imageBuf);
return 0;
}
}
retry:
t = doFwDownload(port, MPI_FW_DOWNLOAD_ITYPE_FW, imageBuf, imageLen, 0);
if (t != 1)
goto no_verify;
#if DOS || EFI
if (adap->bootloader)
goto no_verify;
#endif
if (skip_verify)
goto no_verify;
printf("\nVerifying download...\n");
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
type = MPI_FW_UPLOAD_ITYPE_FW_BACKUP;
else
type = MPI_FW_UPLOAD_ITYPE_FW_FLASH;
imageLenUpload = 0x10000;
imageBufUpload = (unsigned char *)malloc(imageLenUpload);
offset = 0;
while (TRUE)
{
if (doFwUpload(port, type, imageBufUpload, imageLenUpload, offset, &actualImageLenUpload) != 1)
break;
if (offset + imageLenUpload > actualImageLenUpload)
imageLenUpload = actualImageLenUpload - offset;
if (memcmp(imageBuf + offset, imageBufUpload, imageLenUpload) != 0)
{
t = 0;
break;
}
offset += imageLenUpload;
if (offset >= actualImageLenUpload)
break;
}
if (t && imageLen == actualImageLenUpload)
printf("Verification succeeded\n");
else
{
printf("Verification failed!\n");
if (noFlag != TRUE)
{
printf("\nAt a minimum, to recover, the download operation should be retried\n");
printf("\nWould you like to retry the download now? [Yes or No, default is No] ");
if (getYesNoAnswer(0) == 1)
goto retry;
}
}
free(imageBufUpload);
no_verify:
free(imageBuf);
#if DOS || EFI
if (mustExit)
{
if (adap->fw_image != NULL)
free(adap->fw_image);
adap->fw_image = NULL;
doResetPort(port);
closePorts(NUM_PORTS);
exit(0);
}
#endif
return t;
}
int
doFirmwareUpload(MPT_PORT *port)
{
char name[256];
int file;
unsigned char *imageBuf = NULL;
int imageLen;
int actualImageLen;
int offset;
int n;
int t;
n = getFileName(name, sizeof name, stdin, "firmware", 0);
if (n > 0)
{
file = open(name, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, 0644);
if (file < 0)
{
printf("Open failure for file %s\n", name);
perror("Error is");
return 0;
}
}
else
{
printf("Image won't be uploaded\n");
return 1;
}
imageLen = 0x10000;
imageBuf = (unsigned char *)malloc(imageLen);
offset = 0;
while (TRUE)
{
if (doFwUpload(port, MPI_FW_UPLOAD_ITYPE_FW_FLASH, imageBuf, imageLen, offset, &actualImageLen) != 1)
break;
if (offset + imageLen > actualImageLen)
imageLen = actualImageLen - offset;
t = write(file, imageBuf, imageLen);
if (t != imageLen)
{
printf("Write failed for file %s, t = %x\n", name, t);
perror("Error is");
break;
}
offset += imageLen;
if (offset >= actualImageLen)
break;
}
printf("\nWrote %d bytes to file %s\n", offset, name);
close(file);
free(imageBuf);
return 1;
}
int
doBiosFcodeDownload(MPT_PORT *port)
{
char name[256];
unsigned char *imageBuf = NULL;
unsigned char *image1Buf = NULL;
unsigned char *image2Buf = NULL;
unsigned char *image3Buf = NULL;
unsigned char *image4Buf = NULL;
unsigned char *image5Buf = NULL;
int imageLen;
int image1Len;
int image2Len;
int image3Len;
int image4Len = 0;
int image5Len = 0;
int imageOff;
int n;
int warn = 0;
int last;
int valid = 0;
printf("To erase an image:\n");
printf(" 1. hit RETURN when asked for a image file name\n");
printf(" 2. answer No if asked to preserve an existing image\n\n");
n = getFileName(name, sizeof name, stdin, "x86 BIOS", 0);
if (n > 0)
{
if (readFile(name, &image1Buf, &image1Len) != 1)
return 0;
printWhatString("x86 BIOS", image1Buf, image1Len);
warn |= verifyBiosFcodeImage(port, image1Buf, image1Len, 0);
}
else
{
if (doBiosFcodeUpload(port, &image1Buf, &image1Len, 0) == 1 && image1Buf != NULL)
{
valid = 1;
printWhatString("Current x86 BIOS", image1Buf, image1Len);
if (yesFlag == FALSE)
{
printf("\nDo you want to preserve the current x86 BIOS? [Yes or No, default is Yes] ");
if (getYesNoAnswer(1) != 1)
{
free(image1Buf);
image1Buf = NULL;
}
}
}
else
{
printf("No x86 BIOS image exists in FLASH, and image won't be downloaded\n");
if (gFlag == TRUE && yesFlag == FALSE)
{
printf("\nYou realize there is nothing to preserve, right? [Yes or No] ");
getYesNoAnswer(1);
}
}
}
printf("\n");
n = getFileName(name, sizeof name, stdin, "FCode", 1);
if (n > 0)
{
if (readFile(name, &image2Buf, &image2Len) != 1)
return 0;
printWhatString("FCode", image2Buf, image2Len);
warn |= verifyBiosFcodeImage(port, image2Buf, image2Len, 1);
}
else
{
if (doBiosFcodeUpload(port, &image2Buf, &image2Len, 1) == 1 && image2Buf != NULL)
{
valid = 1;
printWhatString("Current FCode", image2Buf, image2Len);
if (yesFlag == FALSE)
{
printf("\nDo you want to preserve the current FCode? [Yes or No, default is Yes] ");
if (getYesNoAnswer(1) != 1)
{
free(image2Buf);
image2Buf = NULL;
}
}
}
else
{
printf("No FCode image exists in FLASH, and image won't be downloaded\n");
if (gFlag == TRUE && yesFlag == FALSE)
{
printf("\nYou realize there is nothing to preserve, right? [Yes or No] ");
getYesNoAnswer(1);
}
}
}
printf("\n");
n = getFileName(name, sizeof name, stdin, "EFI BIOS", 2);
if (n > 0)
{
if (readFile(name, &image3Buf, &image3Len) != 1)
return 0;
printWhatString("EFI BIOS", image3Buf, image3Len);
warn |= verifyBiosFcodeImage(port, image3Buf, image3Len, 3);
}
else
{
if (doBiosFcodeUpload(port, &image3Buf, &image3Len, 3) == 1 && image3Buf != NULL)
{
valid = 1;
printWhatString("Current EFI BIOS", image3Buf, image3Len);
if (yesFlag == FALSE)
{
printf("\nDo you want to preserve the current EFI BIOS? [Yes or No, default is Yes] ");
if (getYesNoAnswer(1) != 1)
{
free(image3Buf);
image3Buf = NULL;
}
}
}
else
{
printf("No EFI BIOS image exists in FLASH, and image won't be downloaded\n");
if (gFlag == TRUE && yesFlag == FALSE)
{
printf("\nYou realize there is nothing to preserve, right? [Yes or No] ");
getYesNoAnswer(1);
}
}
}
if (image1Buf != NULL)
{
last = image2Buf == NULL && image3Buf == NULL;
splitBiosImage(port, &image1Buf, &image1Len, &image4Buf, &image4Len);
fixupBiosFcodeImage(port, image1Buf, image1Len, last);
}
else
image1Len = 0;
if (image2Buf != NULL)
{
last = image3Buf == NULL;
fixupBiosFcodeImage(port, image2Buf, image2Len, last);
}
else
image2Len = 0;
if (image3Buf != NULL)
{
last = 1;
splitBiosImage(port, &image3Buf, &image3Len, &image5Buf, &image5Len);
fixupBiosFcodeImage(port, image3Buf, image3Len, last);
}
else
image3Len = 0;
imageLen = image1Len + image2Len + image3Len + image4Len + image5Len;
if (imageLen == 0)
{
if (valid)
{
image1Len = 512;
image1Buf = malloc(image1Len);
memset(image1Buf, 0xff, image1Len);
imageLen = image1Len;
}
else
return 1;
}
imageBuf = (unsigned char *)malloc(imageLen);
imageOff = 0;
if (image1Buf != NULL)
{
memcpy(imageBuf + imageOff, image1Buf, image1Len);
imageOff += image1Len;
free(image1Buf);
}
if (image2Buf != NULL)
{
memcpy(imageBuf + imageOff, image2Buf, image2Len);
imageOff += image2Len;
free(image2Buf);
}
if (image3Buf != NULL)
{
memcpy(imageBuf + imageOff, image3Buf, image3Len);
imageOff += image3Len;
free(image3Buf);
}
if (image4Buf != NULL)
{
memcpy(imageBuf + imageOff, image4Buf, image4Len);
imageOff += image4Len;
free(image4Buf);
}
if (image5Buf != NULL)
{
memcpy(imageBuf + imageOff, image5Buf, image5Len);
imageOff += image5Len;
free(image5Buf);
}
if (warn && noFlag == TRUE)
{
free(imageBuf);
return 0;
}
if (warn || yesFlag == FALSE)
{
if (warn)
printf("\nAre you sure you want to continue? [Yes or No, default is No] ");
else
printf("\nDo you want to continue? [Yes or No, default is No] ");
if (getYesNoAnswer(0) != 1)
{
free(imageBuf);
return 0;
}
}
doFwDownload(port, MPI_FW_DOWNLOAD_ITYPE_BIOS, imageBuf, imageLen, 0);
free(imageBuf);
return 1;
}
int
doBiosFcodeUpload(MPT_PORT *port, unsigned char **outBuf, int *outLen, int type)
{
char name[4][256];
int file[4];
int who;
unsigned char *imageBuf = NULL;
int imageLen;
int actualImageLen;
int offset;
unsigned char *buf;
int len;
int i;
int n;
PCIR *pcir;
int t;
int last;
if (outBuf == NULL || outLen == NULL)
printf("Searching for BIOS and/or FCode images\n");
for (i = 0; i < 4; i++)
file[i] = -1;
imageLen = 0x10000;
imageBuf = (unsigned char *)malloc(imageLen);
offset = 0;
while (offset < 0x80000)
{
if (doFwUpload(port, MPI_FW_UPLOAD_ITYPE_BIOS_FLASH, imageBuf, imageLen, offset, &actualImageLen) != 1)
break;
buf = imageBuf;
n = (buf[0x01]<<8) + buf[0x00];
if (n != 0xaa55 && n != 0xbb55)
{
break;
}
n = (buf[0x19]<<8) + buf[0x18];
if (n + (int)sizeof *pcir >= imageLen)
{
// not all of the image is in the buffer, so quit now and read more of the image
free(imageBuf);
imageLen = n + (int)sizeof *pcir;
imageBuf = (unsigned char *)malloc(imageLen);
continue;
}
pcir = (PCIR *)(buf + n);
if (pcir->signature[0] != 'P' ||
pcir->signature[1] != 'C' ||
pcir->signature[2] != 'I' ||
pcir->signature[3] != 'R')
{
break;
}
len = get16(pcir->imageLength) * 512;
if (len > imageLen)
{
// not all of the image is in the buffer, so quit now and read more of the image
free(imageBuf);
imageLen = len;
imageBuf = (unsigned char *)malloc(imageLen);
continue;
}
last = pcir->indicator & 0x80;
if (outBuf == NULL || outLen == NULL)
{
printf("\n");
switch (pcir->type)
{
case 0:
n = getFileName(name[0], sizeof name[0], stdin, "x86 BIOS", 0);
who = 0;
break;
case 1:
n = getFileName(name[1], sizeof name[1], stdin, "FCode", 1);
who = 1;
break;
case 3:
n = getFileName(name[2], sizeof name[2], stdin, "EFI BIOS", 2);
who = 2;
break;
case 255:
if (buf[4] == 'L' && buf[5] == 'S' && buf[6] == 'I' && buf[7] == 'L' && buf[0x34] == 0x02)
{
if ((buf[0x3b] & 0xf0) == 0x10)
{
printf("Found x86 BIOS extended image\n");
n = -1;
who = 0;
break;
}
if ((buf[0x3b] & 0xf0) == 0x30)
{
printf("Found EFI BIOS extended image\n");
n = -1;
who = 2;
break;
}
}
default:
printf("Image type is unknown, enter filename: ");
n = getString(name[3], sizeof name[3], stdin);
who = 3;
break;
}
if (n > 0)
{
fixupBiosFcodeImage(port, buf, len, 1);
file[who] = open(name[who], O_CREAT | O_TRUNC | O_RDWR | O_BINARY, 0644);
if (file[who] < 0)
{
printf("Open failure for file %s\n", name[who]);
perror("Error is");
}
t = write(file[who], buf, len);
if (t != len)
{
printf("Write failed for file %s, t = %x\n", name[who], t);
perror("Error is");
}
else
printf("\nWrote %d bytes to file %s\n", len, name[who]);
}
else if (n < 0)
{
if (file[who] >= 0)
{
fixupBiosFcodeImage(port, buf, len, 0);
t = write(file[who], buf, len);
if (t != len)
{
printf("Write failed for file %s, t = %x\n", name[who], t);
perror("Error is");
}
else
printf("\nWrote %d bytes to file %s\n", len, name[who]);
}
}
else
{
printf("Image won't be uploaded\n");
}
}
else
{
if (pcir->type == type)
{
*outBuf = (unsigned char *)malloc(len);
*outLen = len;
memcpy(*outBuf, buf, len);
}
else if (pcir->type == 255)
{
if (buf[4] == 'L' && buf[5] == 'S' && buf[6] == 'I' && buf[7] == 'L' && buf[0x34] == 0x02)
{
if (type == 0 && (buf[0x3b] & 0xf0) == 0x10)
{
*outBuf = (unsigned char *)realloc(*outBuf, *outLen + len);
memcpy(*outBuf + *outLen, buf, len);
*outLen = *outLen + len;
}
if (type == 3 && (buf[0x3b] & 0xf0) == 0x30)
{
*outBuf = (unsigned char *)realloc(*outBuf, *outLen + len);
memcpy(*outBuf + *outLen, buf, len);
*outLen = *outLen + len;
}
}
}
}
offset += len;
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SCSI)
{
if (last)
{
// last image, so make sure we quit after this
break;
}
}
else
{
if (offset >= actualImageLen)
{
// last image, so make sure we quit after this
break;
}
}
}
for (i = 0; i < 4; i++)
if (file[i] >= 0)
close(file[i]);
free(imageBuf);
return 1;
}
int
verifyBiosFcodeImage(MPT_PORT *port, unsigned char *buf, int len, int type)
{
int n;
int n1;
int warn = 0;
PCIR *pcir;
int i;
U8 checksum;
n = (buf[0x01]<<8) + buf[0x00];
if (n != 0xaa55)
{
if (n == 0xbb55)
{
printf("\nThis appears to be the special non-functional (blank) image!\n");
return 0;
}
if (!warn)
printf("\n");
printf("Image's ROM signature %04x is invalid!\n", n);
warn = 1;
}
if ((len % 512) != 0)
{
if (!warn)
printf("\n");
printf("Image's length is not a multiple of 512 bytes!\n");
printf(" The image appears to be corrupted, proceed with caution\n");
warn = 1;
}
/* if there's a what string, we will check the checksum even if it's not BIOS */
for (i = 0; i < len; i++)
if (buf[i] == '@' && buf[i+1] == '(' && buf[i+2] == '#' && buf[i+3] == ')')
break;
if (type == 0 || i < len)
{
checksum = 0;
for (i = 0; i < len; i++)
checksum += buf[i];
if (checksum != 0)
{
if (!warn)
printf("\n");
printf("Image's checksum is invalid!\n");
printf(" The image appears to be corrupted, proceed with caution\n");
warn = 1;
}
}
if (type == 1)
{
int len;
U32 checksum;
len = get4bytes(buf, 0x38);
checksum = 0;
for (i = 0x3c; i < len + 0x34; i++)
checksum += buf[i];
while (checksum > 0xffff)
checksum -= 0xffff;
checksum -= get2bytes(buf, 0x36);
if (checksum != 0)
{
if (!warn)
printf("\n");
printf("Image's FCode checksum is invalid!\n");
printf(" The image appears to be corrupted, proceed with caution\n");
warn = 1;
}
}
n = (buf[0x19]<<8) + buf[0x18];
if (n + (int)sizeof *pcir < len)
{
pcir = (PCIR *)(buf + n);
if (pcir->signature[0] != 'P' ||
pcir->signature[1] != 'C' ||
pcir->signature[2] != 'I' ||
pcir->signature[3] != 'R')
{
if (!warn)
printf("\n");
printf("Image's PCIR signature is invalid!\n");
warn = 1;
}
if (get16(pcir->vendorId) != MPI_MANUFACTPAGE_VENDORID_LSILOGIC)
{
if (!warn)
printf("\n");
printf("Image's PCI Vendor ID %04x is not correct!\n", get16(pcir->vendorId));
warn = 1;
}
if (checkCompatible(get16(pcir->deviceId), port->deviceId, type) != 1)
{
if (!warn)
printf("\n");
printf("Image's PCI Device ID %04x is not compatible!\n", get16(pcir->deviceId));
warn = 1;
}
if (pcir->type != type)
{
if (!warn)
printf("\n");
printf("Image's PCI Type %d is not correct!\n", pcir->type);
warn = 1;
}
n = get16(pcir->imageLength) * 512;
if (n < len)
{
n1 = (buf[0x01]<<8) + buf[0x00];
if (n1 == 0xaa55)
{
n1 = (buf[n+0x19]<<8) + buf[n+0x18];
if (n + n1 + (int)sizeof *pcir < len)
{
pcir = (PCIR *)(buf + n + n1);
if (pcir->signature[0] == 'P' ||
pcir->signature[1] == 'C' ||
pcir->signature[2] == 'I' ||
pcir->signature[3] == 'R')
{
// printf("Image is in multiple parts, length check circumvented\n");
n = len;
}
}
}
}
if (n != len)
{
if (!warn)
printf("\n");
printf("Image's PCI Image Length %04x is not correct!\n", get16(pcir->imageLength));
warn = 1;
}
}
else
{
if (!warn)
printf("\n");
printf("Image's PCIR offset %04x is invalid!\n", n);
warn = 1;
}
return warn;
}
int
splitBiosImage(MPT_PORT *port, unsigned char **buf1, int *len1, unsigned char **buf2, int *len2)
{
int n;
PCIR *pcir;
n = ((*buf1)[0x19]<<8) + (*buf1)[0x18];
if (n + (int)sizeof *pcir < *len1)
{
pcir = (PCIR *)(*buf1 + n);
if (pcir->signature[0] == 'P' &&
pcir->signature[1] == 'C' &&
pcir->signature[2] == 'I' &&
pcir->signature[3] == 'R')
{
n = get16(pcir->imageLength) * 512;
if (n < *len1)
{
*buf2 = (unsigned char *)malloc(*len1 - n);
*len2 = *len1 - n;
memcpy(*buf2, *buf1 + n, *len1 - n);
*buf1 = (unsigned char *)realloc(*buf1, n);
*len1 = n;
}
}
}
return 1;
}
int
fixupBiosFcodeImage(MPT_PORT *port, unsigned char *buf, int len, int last)
{
int n;
PCIR *pcir;
int type = 0;
int i;
U8 checksum;
n = (buf[0x19]<<8) + buf[0x18];
if (n + (int)sizeof *pcir < len)
{
pcir = (PCIR *)(buf + n);
if (pcir->signature[0] == 'P' &&
pcir->signature[1] == 'C' &&
pcir->signature[2] == 'I' &&
pcir->signature[3] == 'R')
{
type = pcir->type;
if (type != 255)
pcir->deviceId = set16(port->deviceIdRaw);
if (last)
pcir->indicator |= 0x80;
else
pcir->indicator &= ~0x80;
}
n = get16(pcir->imageLength) * 512;
}
else
{
n = len;
}
/* if there's a what string, we will fix up the checksum as long as it's not FCode */
for (i = 0; i < len; i++)
if (buf[i] == '@' && buf[i+1] == '(' && buf[i+2] == '#' && buf[i+3] == ')')
break;
if (type != 1 || i < len)
{
checksum = 0;
for (i = 0; i < n - 1; i++)
checksum += buf[i];
buf[i] = -checksum;
}
return 1;
}
int
doSeepromDownload(MPT_PORT *port)
{
char name[256];
unsigned char *imageBuf = NULL;
int imageLen;
int n;
n = getFileName(name, sizeof name, stdin, "SEEPROM", 0);
if (n > 0)
{
if (readFile(name, &imageBuf, &imageLen) != 1)
return 0;
}
else
{
printf("Image won't be downloaded\n");
return 1;
}
if (doFwDownload(port, MPI_FW_DOWNLOAD_ITYPE_NVDATA, imageBuf, imageLen, 0) == 1)
{
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
printf("\n");
printf("WARNING! The SEEPROM contains information (World Wide Names) that must\n");
printf(" be unique for each port. Each port on a host adapter must have\n");
printf(" its own WWNs, not copied from another host adapter. Please use\n");
printf(" Manufacturing Page 3 to verify that the WWNs assigned to this\n");
printf(" port are unique, and modify them if necessary.\n");
}
}
free(imageBuf);
return 1;
}
int
doSeepromUpload(MPT_PORT *port)
{
char name[256];
int file;
unsigned char *imageBuf = NULL;
int imageLen;
int actualImageLen;
int offset;
int n;
int t;
n = getFileName(name, sizeof name, stdin, "SEEPROM", 0);
if (n > 0)
{
file = open(name, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, 0644);
if (file < 0)
{
printf("Open failure for file %s\n", name);
perror("Error is");
return 0;
}
}
else
{
printf("Image won't be uploaded\n");
return 1;
}
imageLen = CHUNK_SIZE;
imageBuf = (unsigned char *)malloc(imageLen);
offset = 0;
while (TRUE)
{
if (doFwUpload(port, MPI_FW_UPLOAD_ITYPE_NVDATA, imageBuf, imageLen, offset, &actualImageLen) != 1)
break;
if (offset + imageLen > actualImageLen)
imageLen = actualImageLen - offset;
t = write(file, imageBuf, imageLen);
if (t != imageLen)
{
printf("Write failed for file %s, t = %x\n", name, t);
perror("Error is");
break;
}
offset += imageLen;
if (offset >= actualImageLen)
break;
}
printf("\nWrote %d bytes to file %s\n", offset, name);
close(file);
free(imageBuf);
return 1;
}
char *deviceType[32] =
{
"Disk",
"Tape",
"Printer",
"Processor",
"WriteOnce",
"CDROM",
"Scanner",
"Optical",
"Jukebox",
"Comm",
"0Ah",
"0Bh",
"RAIDArray",
"EnclServ",
"0Eh",
"0Fh",
"10h",
"11h",
"12h",
"13h",
"14h",
"15h",
"16h",
"17h",
"18h",
"19h",
"1Ah",
"1Bh",
"1Ch",
"1Dh",
"1Eh",
""
};
int
doScanForLuns(MPT_PORT *port, int flag , int option)
{
int bus;
int target;
int lun;
unsigned char inq[36];
char buf[32];
int i;
int version;
int max_lun;
//int option;
//printf("Number of LUN's to scan for, select an option: [1-10] ");
printf("Number of LUN's to scan for is %d \n", option- 800);
//option = getNumberAnswer(0, 10, 10);
//printf("option value %d \n", option);
if (flag)
showPortInfoHeader(port);
getDeviceInfoHeader(port, buf, sizeof buf);
printf(" B___T___L Type Vendor Product Rev %s\n", buf);
for (bus = 0; bus < port->maxBuses; bus++)
{
for (target = port->minTargets; target < port->maxTargets; target++)
{
max_lun = 1;
for (lun = 0; lun < max_lun; lun++)
{
if (doInquiry(port, bus, target, lun, inq, sizeof inq) != 1)
{
#if __linux__ || DOS || EFI
if (errno == EFAULT)
return 0;
#endif
if (lun == 0)
break;
else
continue;
}
if (lun == 0)
{
getDeviceInfo(port, bus, target, buf, sizeof buf);
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SCSI)
{
version = inq[2] & 0x07;
if (version > 1)
max_lun = option - 800;
//printf("option1 value %d \n", option);
if (version > 3)
max_lun = option - 800;
//printf("option2 value %d \n", option);
}
else
{
max_lun = option - 800;
//printf("option3 value %d \n", option);
}
//printf("max_lun value %d \n", max_lun);
}
else
{
if ((inq[0] & 0x1f) == 0x1f)
continue;
if ((inq[0] & 0xe0) == 0x20)
continue;
if ((inq[0] & 0xe0) == 0x60)
continue;
if ((inq[0] & 0x1f) == 0x0d)
continue;
}
for (i = 8; i < 36; i++)
if (!isprint(inq[i]))
inq[i] = ' ';
//printf("debug the max lun number \n");
printf("%2d %3d %3d %-9s %-8.8s %-16.16s %-4.4s %s\n",
bus, target, lun, deviceType[inq[0] & 0x1f],
inq+8, inq+16, inq+32, lun == 0 ? buf : "");
} /* next lun */
} /* next target */
} /* next bus */
showPortInfo(port);
showHiddenDevices(port);
return 1;
}
int
doScanForDevices(MPT_PORT *port, int flag)
{
int bus;
int target;
int lun;
unsigned char inq[36];
char buf[32];
int i;
int version;
int max_lun;
if (flag)
showPortInfoHeader(port);
getDeviceInfoHeader(port, buf, sizeof buf);
printf(" B___T___L Type Vendor Product Rev %s\n", buf);
for (bus = 0; bus < port->maxBuses; bus++)
{
for (target = port->minTargets; target < port->maxTargets; target++)
{
max_lun = 1;
for (lun = 0; lun < max_lun; lun++)
{
if (doInquiry(port, bus, target, lun, inq, sizeof inq) != 1)
{
#if __linux__ || DOS || EFI
if (errno == EFAULT)
return 0;
#endif
if (lun == 0)
break;
else
continue;
}
if (lun == 0)
{
getDeviceInfo(port, bus, target, buf, sizeof buf);
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SCSI)
{
version = inq[2] & 0x07;
if (version > 1)
max_lun = 8;
if (version > 3)
max_lun = 64;
}
else
{
max_lun = port->maxLuns;
}
}
else
{
if ((inq[0] & 0x1f) == 0x1f)
continue;
if ((inq[0] & 0xe0) == 0x20)
continue;
if ((inq[0] & 0xe0) == 0x60)
continue;
if ((inq[0] & 0x1f) == 0x0d)
continue;
}
for (i = 8; i < 36; i++)
if (!isprint(inq[i]))
inq[i] = ' ';
printf("%2d %3d %3d %-9s %-8.8s %-16.16s %-4.4s %s\n",
bus, target, lun, deviceType[inq[0] & 0x1f],
inq+8, inq+16, inq+32, lun == 0 ? buf : "");
} /* next lun */
} /* next target */
} /* next bus */
showPortInfo(port);
showHiddenDevices(port);
return 1;
}
int
doConfigPage(MPT_PORT *port)
{
ConfigReply_t rep;
U32 buf[256];
int type;
int number;
U32 address;
U32 offset;
U32 value;
int i;
int n;
int t;
int attributes;
int action;
int changed;
while (TRUE)
{
printf("Enter page type: [0-255 or RETURN to quit] ");
type = getNumberAnswer(0, 255, -1);
if (type < 0)
break;
if (type == 15)
{
printf("\nPage type 15 is reserved!\n\n");
continue;
}
printf("Enter page number: [0-255 or RETURN to quit] ");
number = getNumberAnswer(0, 255, -1);
if (number < 0)
break;
if ((type == MPI_CONFIG_PAGETYPE_SCSI_DEVICE && (number == 0 || number == 1)) ||
(type == MPI_CONFIG_PAGETYPE_FC_PORT && (number == 3 || number == 5)) ||
(type == MPI_CONFIG_PAGETYPE_FC_DEVICE && number == 0) ||
(type == MPI_CONFIG_PAGETYPE_RAID_VOLUME && (number == 0 || number == 1)) ||
(type == MPI_CONFIG_PAGETYPE_RAID_PHYSDISK && (number == 0 || number == 1)) ||
(type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER && (number == 0 || number == 1)) ||
(type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE && (number == 0 || number == 1 || number == 2)) ||
(type == MPI_CONFIG_EXTPAGETYPE_SAS_PHY && (number == 0 || number == 1 || number == 2 || number == 3 || number == 4)) ||
(type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE && number == 0) ||
(type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG && number == 0) ||
(type == MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING && number == 0) ||
(type == MPI2_CONFIG_EXTPAGETYPE_SAS_PORT && number == 0))
{
printf("Enter page address: [00000000-FFFFFFFF or RETURN to quit] ");
if (getHexNumberAnswer(&address) == 0)
break;
}
else
address = 0;
if (getConfigPageHeader(port, type, number, address, &rep) != 1)
{
printf("\nFailed to read page header -- that page might not exist\n\n");
continue;
}
attributes = rep.Header.PageType & MPI_CONFIG_PAGEATTR_MASK;
if (attributes == MPI_CONFIG_PAGEATTR_PERSISTENT ||
attributes == MPI_CONFIG_PAGEATTR_RO_PERSISTENT)
{
printf("Read NVRAM or current values? [0=NVRAM, 1=Current, default is 0] ");
t = getNumberAnswer(0, 1, 0);
if (t == 0)
action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
else
action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
}
else
action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
t = getConfigPageAction(port, action, type, number, address, buf, sizeof buf);
if (t != 1 && action == MPI_CONFIG_ACTION_PAGE_READ_NVRAM)
{
printf("The current values for this page will be used instead\n");
t = getConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, type, number, address, buf, sizeof buf);
}
if (t == 1)
{
if (type > MPI_CONFIG_PAGETYPE_EXTENDED)
n = get16(((pConfigExtendedPageHeader_t)buf)->ExtPageLength);
else
n = ((pConfigPageHeader_t)buf)->PageLength;
if (n == 0)
{
if (type > MPI_CONFIG_PAGETYPE_EXTENDED)
n = get16(rep.ExtPageLength);
else
n = rep.Header.PageLength;
}
printf("\n");
for (i = 0; i < n; i++)
printf("%04x : %08x\n", i*4, get32x(buf[i]));
if (attributes == MPI_CONFIG_PAGEATTR_CHANGEABLE ||
attributes == MPI_CONFIG_PAGEATTR_PERSISTENT ||
attributes == MPI_CONFIG_PAGEATTR_RO_PERSISTENT)
{
printf("\nDo you want to make changes? [Yes or No, default is No] ");
if (getYesNoAnswer(0) == 1)
{
if (type > MPI_CONFIG_PAGETYPE_EXTENDED)
i = sizeof(ConfigExtendedPageHeader_t);
else
i = sizeof(ConfigPageHeader_t);
changed = FALSE;
while (TRUE)
{
printf("Enter offset of value to change: [%04x-%04x or RETURN to quit] ", i, (n - 1) * 4);
while (TRUE)
{
t = getHexNumberAnswer(&offset);
if (t == 0)
break;
if ((offset % 4) == 0)
{
offset /= 4;
if (offset >= (U32)(i / 4) && offset < (U32)n)
break;
}
printf("Invalid answer, try again: ");
}
if (t == 0)
break;
printf("Enter value: [00000000-FFFFFFFF or RETURN to not change] ");
value = get32x(buf[offset]);
if (parseHexNumberChange(&value) == 0)
continue;
buf[offset] = set32x(value);
changed = TRUE;
}
if (changed == TRUE)
{
printf("\nDo you want to write your changes? [Yes or No, default is No] ");
if (getYesNoAnswer(0) == 1)
{
if (action == MPI_CONFIG_ACTION_PAGE_READ_NVRAM)
action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
else
action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
if (type == MPI_CONFIG_PAGETYPE_MANUFACTURING && number == 2)
{
U8 checksum = 0xa5;
U8 *p = (U8 *)buf;
p += 8;
t = n * 4 - 8;
switch (port->deviceId)
{
case MPI_MANUFACTPAGE_DEVICEID_FC919: t -= 4; break;
case MPI_MANUFACTPAGE_DEVICEID_FC929: t -= 4; break;
case MPI_MANUFACTPAGE_DEVICEID_FC919X: t -= 3; break;
case MPI_MANUFACTPAGE_DEVICEID_FC929X: t -= 3; break;
case MPI_MANUFACTPAGE_DEVICEID_FC939X: t -= 3; break;
case MPI_MANUFACTPAGE_DEVICEID_FC949X: t -= 3; break;
case MPI_MANUFACTPAGE_DEVICEID_FC949E: t -= 4; break;
default: t = 0; break;
}
if (t != 0)
{
for (i = 0; i < t; i++)
{
checksum += *p++;
}
*p = -checksum;
}
}
if (type == MPI_CONFIG_PAGETYPE_MANUFACTURING)
doIocInit(port, MPI_WHOINIT_MANUFACTURER);
if (setConfigPageAction(port, action, type, number, address, buf, sizeof buf) != 1)
printf("Failed to write changes!\n");
else
printf("Changes have been written\n");
if (type == MPI_CONFIG_PAGETYPE_MANUFACTURING)
doIocInit(port, port->whoInit);
}
}
}
}
}
printf("\n");
}
return 1;
}
int
doInterruptCoalescingValues(MPT_PORT *port, int timeout, int depth)
{
IOCPage1_t *IOCPage1;
int length;
int flags;
IOCPage1 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_IOC, 1, 0, &length);
if (IOCPage1 == NULL)
return 0;
flags = get32(IOCPage1->Flags);
if (timeout != 0 && depth != 0)
{
flags |= MPI_IOCPAGE1_REPLY_COALESCING;
IOCPage1->Flags = set32(flags);
IOCPage1->CoalescingTimeout = set32(timeout);
IOCPage1->CoalescingDepth = depth;
}
else
{
flags &= ~MPI_IOCPAGE1_REPLY_COALESCING;
IOCPage1->Flags = set32(flags);
IOCPage1->CoalescingTimeout = 0;
IOCPage1->CoalescingDepth = 0;
}
if (setConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 1, 0, IOCPage1, length) != 1)
{
printf("Failed to save changes to NVRAM!\n");
free(IOCPage1);
return 0;
}
free(IOCPage1);
return 1;
}
int
doIocSettings(MPT_PORT *port)
{
IOCPage1_t *IOCPage1;
int length;
int flags;
int timeout;
int depth;
int on;
int mode;
IOCPage1 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_IOC, 1, 0, &length);
if (IOCPage1 == NULL)
return 0;
flags = get32(IOCPage1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
timeout = get32(IOCPage1->CoalescingTimeout);
depth = IOCPage1->CoalescingDepth;
if (timeout < 0)
timeout = 0;
if (timeout > 1000)
timeout = 1000;
if (depth < 0)
depth = 0;
if (depth > 128)
depth = 128;
on = flags != 0 && timeout != 0 && depth != 0;
if (on)
printf("Interrupt Coalescing is enabled, timeout is %d microseconds, depth is %d\n",
timeout, depth);
else
printf("Interrupt Coalescing is disabled\n");
printf("Enable interrupt coalescing: [0=No, 1=Yes, default is %d] ", on);
on = getNumberAnswer(0, 1, on);
if (on)
{
printf("Enter timeout: [1-1000, 0=disable, default is %d] ", timeout);
timeout = getNumberAnswer(0, 1000, timeout);
printf("Enter depth: [1-128, 0=disable, default is %d] ", depth);
depth = getNumberAnswer(0, 128, depth);
}
else
{
timeout = 0;
depth = 0;
}
flags = get32(IOCPage1->Flags);
if (on && timeout != 0 && depth != 0)
{
flags |= MPI_IOCPAGE1_REPLY_COALESCING;
IOCPage1->Flags = set32(flags);
IOCPage1->CoalescingTimeout = set32(timeout);
IOCPage1->CoalescingDepth = depth;
}
else
{
flags &= ~MPI_IOCPAGE1_REPLY_COALESCING;
IOCPage1->Flags = set32(flags);
IOCPage1->CoalescingTimeout = 0;
IOCPage1->CoalescingDepth = 0;
}
switch (port->deviceId)
{
case MPI_MANUFACTPAGE_DEVICEID_FC939X:
case MPI_MANUFACTPAGE_DEVICEID_FC949X:
case MPI_MANUFACTPAGE_DEVICEID_FC949E:
flags = get32(IOCPage1->Flags);
mode = (flags & MPI_IOCPAGE1_EEDP_MODE_MASK) >> 24;
printf("\nEnd-to-End Data Protection Mode: [0=Disabled, 1=T10, 2=LB, default is %d] ", mode);
mode = getNumberAnswer(0, 2, mode);
flags &= ~MPI_IOCPAGE1_EEDP_MODE_MASK;
flags |= mode << 24;
IOCPage1->Flags = set32(flags);
break;
}
if (setConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 1, 0, IOCPage1, length) != 1)
{
printf("Failed to save changes to NVRAM!\n");
free(IOCPage1);
return 0;
}
free(IOCPage1);
return 1;
}
int
doScsiInitiatorSettings(MPT_PORT *port)
{
SCSIPortPage1_t SCSIPortPage1;
SCSIPortPage2_t SCSIPortPage2;
int flags;
int settings;
int id;
int t;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, 0, &SCSIPortPage2, sizeof SCSIPortPage2) != 1)
return 0;
flags = get32(SCSIPortPage2.PortFlags);
settings = get32(SCSIPortPage2.PortSettings);
id = settings & MPI_SCSIPORTPAGE2_PORT_HOST_ID_MASK;
printf("Host SCSI ID: [0-15, default is %d] ", id);
id = getNumberAnswer(0, 15, id);
settings &= ~MPI_SCSIPORTPAGE2_PORT_HOST_ID_MASK;
settings |= id;
t = (flags & MPI_SCSIPORTPAGE2_PORT_FLAGS_SCAN_HIGH_TO_LOW) != 0;
printf("Bus scan order: [0=LowToHigh, 1=HighToLow, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 0)
flags &= ~MPI_SCSIPORTPAGE2_PORT_FLAGS_SCAN_HIGH_TO_LOW;
else
flags |= MPI_SCSIPORTPAGE2_PORT_FLAGS_SCAN_HIGH_TO_LOW;
t = (flags & MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) != 0;
printf("Avoid SCSI bus reset: [0=No, 1=Yes, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 0)
flags &= ~MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET;
else
flags |= MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET;
t = (flags & MPI_SCSIPORTPAGE2_PORT_FLAGS_ALTERNATE_CHS) != 0;
printf("CHS mapping: [0=PlugAndPlay, 1=AlternateCHS, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 0)
flags &= ~MPI_SCSIPORTPAGE2_PORT_FLAGS_ALTERNATE_CHS;
else
flags |= MPI_SCSIPORTPAGE2_PORT_FLAGS_ALTERNATE_CHS;
t = (settings & MPI_SCSIPORTPAGE2_PORT_REMOVABLE_MEDIA) >> 6;
printf("Removable media support: [0=None, 1=BootDrive, 2=AnyWithMedia, default is %d] ", t);
t = getNumberAnswer(0, 2, t);
settings &= ~MPI_SCSIPORTPAGE2_PORT_REMOVABLE_MEDIA;
settings |= t << 6; // what, no nice symbolic name I can use here?
t = (settings & MPI_SCSIPORTPAGE2_PORT_SPINUP_DELAY_MASK) >> 8;
printf("Spinup delay (in seconds): [0-15, default is %d] ", t);
t = getNumberAnswer(0, 15, t);
settings &= ~MPI_SCSIPORTPAGE2_PORT_SPINUP_DELAY_MASK;
settings |= t << 8; // what, no nice symbolic name I can use here?
SCSIPortPage2.PortFlags = set32(flags);
SCSIPortPage2.PortSettings = set32(settings);
if (setConfigPage(port, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, 0, &SCSIPortPage2, sizeof SCSIPortPage2) != 1)
{
printf("Failed to save changes to NVRAM!\n");
return 0;
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1, 0, &SCSIPortPage1, sizeof SCSIPortPage1) != 1)
return 0;
SCSIPortPage1.Configuration = set32((1 << (id + 16)) | id);
if (setConfigPage(port, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1, 0, &SCSIPortPage1, sizeof SCSIPortPage1) != 1)
{
printf("Failed to save changes to NVRAM!\n");
return 0;
}
return 1;
}
char *
syncToMt(int sync)
{
if (sync == 0)
return "Async";
if (sync == 8)
return "160";
if (sync == 9)
return "80";
if (sync == 10)
return "40";
if (sync == 12)
return "20";
if (sync == 25)
return "10";
if (sync == 50)
return "5";
return "";
}
char *
syncToMb(int sync, int wide)
{
if (wide == 0)
return syncToMt(sync);
if (sync == 0)
return "Async";
if (sync == 8)
return "320";
if (sync == 9)
return "160";
if (sync == 10)
return "80";
if (sync == 12)
return "40";
if (sync == 25)
return "20";
if (sync == 50)
return "10";
return "";
}
int
doScsiTargetSettings(MPT_PORT *port)
{
SCSIPortPage2_t SCSIPortPage2;
U8 timeout[16];
U8 sync_factor[16];
U16 device_flags[16];
int id;
int sync;
int i;
int t;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, 0, &SCSIPortPage2, sizeof SCSIPortPage2) != 1)
return 0;
id = get32(SCSIPortPage2.PortSettings) & MPI_SCSIPORTPAGE2_PORT_HOST_ID_MASK;
for (i = 0; i < 16; i++)
{
timeout[i] = SCSIPortPage2.DeviceSettings[i].Timeout;
sync_factor[i] = SCSIPortPage2.DeviceSettings[i].SyncFactor;
device_flags[i] = get16(SCSIPortPage2.DeviceSettings[i].DeviceFlags);
}
while (TRUE)
{
printf("Target MB/sec | MT/sec Wide ScanID ScanLUNs Disconnect Timeout QueueTag Boot\n");
for (i = 0; i < 16; i++)
printf(" %2d %5s | %5s %3s %3s %3s %3s %3d %3s %3s\n",
i,
syncToMb(sync_factor[i],
device_flags[i] & MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE ? 0 : 1),
syncToMt(sync_factor[i]),
device_flags[i] & MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE ? "No" : "Yes",
device_flags[i] & MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE ? "Yes" : "No",
device_flags[i] & MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE ? "Yes" : "No",
device_flags[i] & MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE ? "Yes" : "No",
timeout[i],
device_flags[i] & MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE ? "Yes" : "No",
device_flags[i] & MPI_SCSIPORTPAGE2_DEVICE_BOOT_CHOICE ? "Yes" : "No");
printf("\nSelect a Target: [0-15, %d=AllTargets, RETURN to quit] ", id);
i = getNumberAnswer(0, 15, -1);
if (i < 0)
break;
switch (sync_factor[i])
{
case 8: sync = 160; break;
case 9: sync = 80; break;
case 10: sync = 40; break;
case 12: sync = 20; break;
case 25: sync = 10; break;
case 50: sync = 5; break;
default:
case 0: sync = 0; break;
}
printf("\nMT/sec: [160, 80, 40, 20, 10, 5, 0=Async, default is %d] ", sync);
while (TRUE)
{
t = getNumberAnswer(0, 160, sync);
switch (t)
{
case 160: t = 8; break;
case 80: t = 9; break;
case 40: t = 10; break;
case 20: t = 12; break;
case 10: t = 25; break;
case 5: t = 50; break;
case 0: t = 0; break;
default:
printf("Invalid response, try again: ");
t = -1;
break;
}
if (t >= 0)
break;
}
sync_factor[i] = t;
if (sync_factor[i] > 9 || sync_factor[i] == 0)
{
t = (device_flags[i] & MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE) == 0;
printf("Enable Wide: [0=No, 1=Yes, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 1)
device_flags[i] &= ~MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE;
else
device_flags[i] |= MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE;
}
else
device_flags[i] &= ~MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE;
t = (device_flags[i] & MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE) != 0;
printf("Enable ScanID: [0=No, 1=Yes, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 0)
device_flags[i] &= ~MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE;
else
device_flags[i] |= MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE;
t = (device_flags[i] & MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE) != 0;
printf("Enable ScanLUNs: [0=No, 1=Yes, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 0)
device_flags[i] &= ~MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE;
else
device_flags[i] |= MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE;
t = (device_flags[i] & MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE) != 0;
printf("Enable Disconnect: [0=No, 1=Yes, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 0)
device_flags[i] &= ~MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE;
else
device_flags[i] |= MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE;
t = timeout[i];
printf("Timeout: [0-255, default is %d] ", t);
t = getNumberAnswer(0, 255, t);
timeout[i] = t;
t = (device_flags[i] & MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE) != 0;
printf("Enable QueueTag: [0=No, 1=Yes, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 0)
device_flags[i] &= ~MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE;
else
device_flags[i] |= MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE;
t = (device_flags[i] & MPI_SCSIPORTPAGE2_DEVICE_BOOT_CHOICE) != 0;
printf("Enable Boot: [0=No, 1=Yes, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 0)
device_flags[i] &= ~MPI_SCSIPORTPAGE2_DEVICE_BOOT_CHOICE;
else
device_flags[i] |= MPI_SCSIPORTPAGE2_DEVICE_BOOT_CHOICE;
if (i == id)
{
for (i = 0; i < 16; i++)
{
if (i != id)
{
timeout[i] = timeout[id];
sync_factor[i] = sync_factor[id];
device_flags[i] = device_flags[id];
}
}
}
printf("\n");
}
for (i = 0; i < 16; i++)
{
SCSIPortPage2.DeviceSettings[i].Timeout = timeout[i];
SCSIPortPage2.DeviceSettings[i].SyncFactor = sync_factor[i];
SCSIPortPage2.DeviceSettings[i].DeviceFlags = set16(device_flags[i]);
}
if (setConfigPage(port, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, 0, &SCSIPortPage2, sizeof SCSIPortPage2) != 1)
{
printf("Failed to save changes to NVRAM!\n");
return 0;
}
return 1;
}
int
doFcLinkSpeedValue(MPT_PORT *port, int t)
{
FCPortPage0_t FCPortPage0;
FCPortPage1_t FCPortPage1;
int speeds;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 0, 0, &FCPortPage0, sizeof FCPortPage0) != 1)
return 0;
speeds = get32(FCPortPage0.SupportedSpeeds);
switch (t)
{
case MPI_FCPORTPAGE1_LCONFIG_SPEED_1GIG:
speeds &= MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED;
break;
case MPI_FCPORTPAGE1_LCONFIG_SPEED_2GIG:
speeds &= MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED;
break;
case MPI_FCPORTPAGE1_LCONFIG_SPEED_4GIG:
speeds &= MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED;
break;
}
if (speeds == 0)
{
printf("That link speed is not supported on this port!\n");
return 0;
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
return 0;
FCPortPage1.LinkConfig &= ~MPI_FCPORTPAGE1_LCONFIG_SPEED_MASK;
FCPortPage1.LinkConfig |= t;
if (setConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
{
printf("Failed to save changes to NVRAM!\n");
return 0;
}
return 1;
}
int
doFcTopologyValue(MPT_PORT *port, int t)
{
FCPortPage1_t FCPortPage1;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
return 0;
FCPortPage1.TopologyConfig &= ~MPI_FCPORTPAGE1_TOPOLOGY_MASK;
FCPortPage1.TopologyConfig |= t;
if (setConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
{
printf("Failed to save changes to NVRAM!\n");
return 0;
}
return 1;
}
int
doFcPortOffline(MPT_PORT *port)
{
FCPortPage1_t FCPortPage1;
int flags;
printf("Setting port offline\n");
if (getConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
return 0;
flags = get32(FCPortPage1.Flags);
flags |= MPI_FCPORTPAGE1_FLAGS_PORT_OFFLINE;
FCPortPage1.Flags = set32(flags);
if (setConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
{
printf("Failed to write changes!\n");
return 0;
}
return 1;
}
int
doFcPortOnline(MPT_PORT *port)
{
FCPortPage1_t FCPortPage1;
int flags;
printf("Setting port online\n");
if (getConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
return 0;
flags = get32(FCPortPage1.Flags);
flags &= ~MPI_FCPORTPAGE1_FLAGS_PORT_OFFLINE;
FCPortPage1.Flags = set32(flags);
if (setConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
{
printf("Failed to write changes!\n");
return 0;
}
return 1;
}
int
doFcTopologyNLPort(MPT_PORT *port)
{
FCPortPage1_t FCPortPage1;
printf("Setting port to NL_Port\n");
if (getConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
return 0;
FCPortPage1.TopologyConfig &= ~MPI_FCPORTPAGE1_TOPOLOGY_MASK;
FCPortPage1.TopologyConfig |= MPI_FCPORTPAGE1_TOPOLOGY_NLPORT;
if (setConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
{
printf("Failed to write changes!\n");
return 0;
}
return 1;
}
int
doFcTopologyNPort(MPT_PORT *port)
{
FCPortPage1_t FCPortPage1;
printf("Setting port to N_Port\n");
if (getConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
return 0;
FCPortPage1.TopologyConfig &= ~MPI_FCPORTPAGE1_TOPOLOGY_MASK;
FCPortPage1.TopologyConfig |= MPI_FCPORTPAGE1_TOPOLOGY_NPORT;
if (setConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
{
printf("Failed to write changes!\n");
return 0;
}
return 1;
}
int
doFcSpecialMode(MPT_PORT *port, int enable, int permanent)
{
FCPortPage1_t FCPortPage1;
int flags;
printf("%s special mode on port\n", enable ? "Enabling" : "Disabling");
if (getConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
return 0;
flags = get32(FCPortPage1.Flags);
if (enable)
flags |= 0x1000;
else
flags &= ~0x1000;
FCPortPage1.Flags = set32(flags);
if (setConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
{
printf("Failed to write changes!\n");
return 0;
}
if (permanent)
{
if (getConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_READ_NVRAM, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
return 0;
flags = get32(FCPortPage1.Flags);
if (enable)
flags |= 0x1000;
else
flags &= ~0x1000;
FCPortPage1.Flags = set32(flags);
if (setConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
{
printf("Failed to write changes!\n");
return 0;
}
}
return 1;
}
int
doFcPortSettings(MPT_PORT *port)
{
FCPortPage0_t FCPortPage0;
FCPortPage1_t FCPortPage1;
FCPortPage4_t FCPortPage4;
int flags;
int speed;
int speeds;
int t;
U32 alpa;
int settings;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 0, 0, &FCPortPage0, sizeof FCPortPage0) != 1)
return 0;
speeds = get32(FCPortPage0.SupportedSpeeds);
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
return 0;
t = FCPortPage1.TopologyConfig & MPI_FCPORTPAGE1_TOPOLOGY_MASK;
if (t == MPI_FCPORTPAGE1_TOPOLOGY_AUTO)
t = 0;
printf("Link topology: [0=Auto, 1=NL_Port, 2=N_Port, default is %d] ", t);
t = getNumberAnswer(0, 2, t);
if (t == 0)
t = MPI_FCPORTPAGE1_TOPOLOGY_AUTO;
FCPortPage1.TopologyConfig &= ~MPI_FCPORTPAGE1_TOPOLOGY_MASK;
FCPortPage1.TopologyConfig |= t;
t = FCPortPage1.LinkConfig & MPI_FCPORTPAGE1_LCONFIG_SPEED_MASK;
if (t == MPI_FCPORTPAGE1_LCONFIG_SPEED_AUTO)
speed = 0;
else
speed = t + 1;
if (speeds & MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED)
{
if (speed == 4)
speed = 10;
else if (speed == 3)
speed = 4;
else if (speed > 3)
speed = 0;
printf("Link speed: [0=Auto, 1=1Gb, 2=2Gb, 4=4Gb, 10=10Gb, default is %d] ", speed);
while (TRUE)
{
t = getNumberAnswer(0, 10, speed);
if (t < 3 || t == 4 || t == 10)
break;
printf("Invalid response, try again: ");
}
if (t == 10)
t = 4;
else if (t == 4)
t = 3;
}
else if (speeds & MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED)
{
if (speed == 3)
speed = 4;
else if (speed > 3)
speed = 0;
printf("Link speed: [0=Auto, 1=1Gb, 2=2Gb, 4=4Gb, default is %d] ", speed);
while (TRUE)
{
t = getNumberAnswer(0, 4, speed);
if (t < 3 || t == 4)
break;
printf("Invalid response, try again: ");
}
if (t == 4)
t = 3;
}
else if (speeds & MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED)
{
if (speed > 2)
speed = 0;
printf("Link speed: [0=Auto, 1=1Gb, 2=2Gb, default is %d] ", speed);
t = getNumberAnswer(0, 2, speed);
}
else if (speeds & MPI_FCPORTPAGE1_LCONFIG_SPEED_1GIG)
{
t = 1;
}
else
{
t = 0;
}
if (t == 0)
t = MPI_FCPORTPAGE1_LCONFIG_SPEED_AUTO;
else
t--;
FCPortPage1.LinkConfig &= ~MPI_FCPORTPAGE1_LCONFIG_SPEED_MASK;
FCPortPage1.LinkConfig |= t;
flags = get32(FCPortPage1.Flags);
t = (flags & MPI_FCPORTPAGE1_FLAGS_PROT_FCP_INIT) != 0;
printf("FCP Initiator protocol: [0=Disabled, 1=Enabled, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 0)
flags &= ~MPI_FCPORTPAGE1_FLAGS_PROT_FCP_INIT;
else
flags |= MPI_FCPORTPAGE1_FLAGS_PROT_FCP_INIT;
t = (flags & MPI_FCPORTPAGE1_FLAGS_PROT_FCP_TARG) != 0;
printf("FCP Target protocol: [0=Disabled, 1=Enabled, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 0)
flags &= ~MPI_FCPORTPAGE1_FLAGS_PROT_FCP_TARG;
else
flags |= MPI_FCPORTPAGE1_FLAGS_PROT_FCP_TARG;
t = (flags & MPI_FCPORTPAGE1_FLAGS_PROT_LAN) != 0;
printf("LAN protocol: [0=Disabled, 1=Enabled, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 0)
flags &= ~MPI_FCPORTPAGE1_FLAGS_PROT_LAN;
else
flags |= MPI_FCPORTPAGE1_FLAGS_PROT_LAN;
t = (flags & MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID) != 0;
printf("Assignment of Bus/Target IDs: [0=SortByWWN, 1=SortByDID, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 0)
flags &= ~MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID;
else
flags |= MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID;
t = (flags & MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY) != 0;
printf("Immediate Error Reply: [0=Disabled, 1=Enabled, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 0)
flags &= ~MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY;
else
flags |= MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY;
t = (flags & MPI_FCPORTPAGE1_FLAGS_MAINTAIN_LOGINS) != 0;
printf("Maintain Logins: [0=Disabled, 1=Enabled, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 0)
flags &= ~MPI_FCPORTPAGE1_FLAGS_MAINTAIN_LOGINS;
else
flags |= MPI_FCPORTPAGE1_FLAGS_MAINTAIN_LOGINS;
FCPortPage1.Flags = set32(flags);
t = FCPortPage1.HardALPA;
printf("Hard AL_PA: [01 to EF, or FF for Soft AL_PA, default is %02x] ", t);
alpa = t;
while (TRUE)
{
t = getHexNumberAnswer(&alpa);
if (t == 0)
{
alpa = FCPortPage1.HardALPA;
break;
}
if (alpa == 0xff)
break;
if (alpa > 0x00 && alpa < 0xff && AlpaToLoopId[alpa] != 0xff)
break;
printf("Invalid answer, try again: ");
}
FCPortPage1.HardALPA = (U8)alpa;
t = FCPortPage1.InitiatorDeviceTimeout;
if (t == 0)
t = 60;
if (t & MPI_FCPORTPAGE1_INITIATOR_DEV_UNIT_16)
t = (t & ~MPI_FCPORTPAGE1_INITIATOR_DEV_UNIT_16) * 16;
printf("Initiator Device Timeout: [0 to 2047, default is %d] ", t);
t = getNumberAnswer(0, 2047, t);
if (t >= MPI_FCPORTPAGE1_INITIATOR_DEV_UNIT_16)
t = (t / 16) | MPI_FCPORTPAGE1_INITIATOR_DEV_UNIT_16;
if (t == 60)
t = 0;
FCPortPage1.InitiatorDeviceTimeout = t;
t = FCPortPage1.InitiatorIoPendTimeout;
if (t == 0)
t = 8;
printf("Initiator I/O Pending Timeout: [0 to 127, default is %d] ", t);
t = getNumberAnswer(0, 127, t);
if (t == 8)
t = 0;
FCPortPage1.InitiatorIoPendTimeout = t;
if (setConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
{
printf("Failed to save changes to NVRAM!\n");
return 0;
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 4, 0, &FCPortPage4, sizeof FCPortPage4) != 1)
return 0;
settings = get32(FCPortPage4.PortSettings);
t = settings & MPI_FCPORTPAGE4_PORT_MASK_INIT_HBA;
printf("Enable booting under EFI BIOS: [Yes or No, default is %s] ",
t != MPI_FCPORTPAGE4_PORT_DISABLE_INIT_HBA ? "Yes" : "No");
if (getYesNoAnswer(t != MPI_FCPORTPAGE4_PORT_DISABLE_INIT_HBA) == 0)
t = MPI_FCPORTPAGE4_PORT_DISABLE_INIT_HBA;
else if (t == MPI_FCPORTPAGE4_PORT_DISABLE_INIT_HBA)
t = MPI_FCPORTPAGE4_PORT_BIOS_OS_INIT_HBA;
FCPortPage4.PortSettings = set32((settings & ~MPI_FCPORTPAGE4_PORT_MASK_INIT_HBA) | t);
if (setConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 4, 0, &FCPortPage4, sizeof FCPortPage4) != 1)
{
printf("Failed to save changes to NVRAM!\n");
return 0;
}
return 1;
}
int
doFcChangeWwn(MPT_PORT *port)
{
ManufacturingPage3_t *ManufacturingPage3;
int length;
int t;
U32 *p;
U32 wwnn_l;
U32 wwnn_h;
U32 wwpn_l;
U32 wwpn_h;
ManufacturingPage3 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 3, 0, &length);
if (ManufacturingPage3 == NULL)
return 0;
p = (U32 *)ManufacturingPage3 + 2 + port->iocNumber * 8;
wwnn_l = get32x(p[2]);
wwnn_h = get32x(p[3]);
wwpn_l = get32x(p[0]);
wwpn_h = get32x(p[1]);
printf("Current FC WWNN = %08x%08x, WWPN = %08x%08x\n\n", wwnn_h, wwnn_l, wwpn_h, wwpn_l);
printf("Enter new WWNN: [16 hex digits or RETURN to quit] ");
t = getHexDoubleNumberAnswer(&wwnn_h, &wwnn_l);
if (t == 0)
{
free(ManufacturingPage3);
return 1;
}
printf("Enter new WWPN: [16 hex digits or RETURN to quit] ");
t = getHexDoubleNumberAnswer(&wwpn_h, &wwpn_l);
if (t == 0)
{
free(ManufacturingPage3);
return 1;
}
p[2] = set32x(wwnn_l);
p[3] = set32x(wwnn_h);
p[0] = set32x(wwpn_l);
p[1] = set32x(wwpn_h);
doIocInit(port, MPI_WHOINIT_MANUFACTURER);
t = setConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 3, 0, ManufacturingPage3, length);
doIocInit(port, port->whoInit);
free(ManufacturingPage3);
if (t != 1)
{
printf("Failed to save changes to NVRAM!\n");
return 0;
}
return 1;
}
int
doSasPhyOnOffline(MPT_PORT *port, int onoff)
{
SasDevicePage0_t SASDevicePage0;
SasExpanderPage0_t SASExpanderPage0;
SasExpanderPage1_t SASExpanderPage1;
SasIOUnitPage1_t *SASIOUnitPage1;
SasIoUnitControlRequest_t req;
SasIoUnitControlReply_t rep;
int length;
int handle;
int phy;
int min_phy;
int max_phy;
int dev_info;
int dev_type;
unsigned char phy_control_req[40];
unsigned char phy_control_rsp[4];
int parent;
int attached;
int t;
printf("Enter handle: [0000-FFFF or RETURN to quit] ");
handle = getNumberAnswerHex(0x0000, 0xffff, -1);
if (handle < 0)
return 0;
if (handle == 0)
{
min_phy = 0;
max_phy = port->numPhys - 1;
parent = 0;
}
else
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0,
(MPI_SAS_DEVICE_PGAD_FORM_HANDLE
<<MPI_SAS_DEVICE_PGAD_FORM_SHIFT) + handle,
&SASDevicePage0, sizeof SASDevicePage0) != 1)
{
printf("\nInvalid handle!\n");
return 0;
}
parent = get16(SASDevicePage0.ParentDevHandle);
dev_info = get32(SASDevicePage0.DeviceInfo);
dev_type = dev_info & MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE;
if (SASDevicePage0.ParentDevHandle == 0)
{
min_phy = handle - 1;
max_phy = handle - 1;
}
else if (dev_type == MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
dev_type == MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0,
(MPI_SAS_EXPAND_PGAD_FORM_HANDLE
<<MPI_SAS_EXPAND_PGAD_FORM_SHIFT) + handle,
&SASExpanderPage0, sizeof SASExpanderPage0) != 1)
{
return 0;
}
min_phy = 0;
max_phy = SASExpanderPage0.NumPhys - 1;
}
else if (dev_type == MPI_SAS_DEVICE_INFO_END_DEVICE)
{
min_phy = SASDevicePage0.PhyNum;
max_phy = SASDevicePage0.PhyNum;
handle = parent;
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0,
(MPI_SAS_DEVICE_PGAD_FORM_HANDLE
<<MPI_SAS_DEVICE_PGAD_FORM_SHIFT) + handle,
&SASDevicePage0, sizeof SASDevicePage0) != 1)
{
return 0;
}
parent = get16(SASDevicePage0.ParentDevHandle);
if (parent != 0)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0,
(MPI_SAS_EXPAND_PGAD_FORM_HANDLE
<<MPI_SAS_EXPAND_PGAD_FORM_SHIFT) + handle,
&SASExpanderPage0, sizeof SASExpanderPage0) != 1)
{
return 0;
}
}
if (!onoff)
printf("To set this phy online, specify handle %x, phy %d\n", handle, min_phy);
}
else
{
return 0;
}
}
if (min_phy != max_phy || gFlag == TRUE)
{
printf("Enter phy: [%d-%d or RETURN to quit] ", min_phy, max_phy);
phy = getNumberAnswer(min_phy, max_phy, -1);
if (phy < 0)
return 0;
}
else
{
phy = min_phy;
}
if (parent == 0)
{
SASIOUnitPage1 = getConfigPageActionAlloc(port, MPI_CONFIG_ACTION_PAGE_READ_CURRENT,
MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0,
&length);
if (SASIOUnitPage1 == NULL)
return 0;
printf("\nSetting SAS phy %sline\n", onoff ? "on" : "off");
if (mpi2)
{
if (onoff)
SASIOUnitPage1->PhyData[phy].PhyFlags &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
else
SASIOUnitPage1->PhyData[phy].PhyFlags |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
}
else
{
if (onoff)
SASIOUnitPage1->PhyData[phy].PhyFlags &= ~MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE;
else
SASIOUnitPage1->PhyData[phy].PhyFlags |= MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE;
}
t = setConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT,
MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0, SASIOUnitPage1, length);
free(SASIOUnitPage1);
if (t != 1)
{
printf("Failed to write changes!\n");
return 0;
}
if (!onoff)
{
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
req.Operation = MPI_SAS_OP_PHY_LINK_RESET;
req.PhyNum = phy;
doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
}
else
{
if (!onoff && yesFlag == FALSE)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 1,
(MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM
<<MPI_SAS_EXPAND_PGAD_FORM_SHIFT) +
(phy << MPI_SAS_EXPAND_PGAD_HPN_SHIFT_PHY) + handle,
&SASExpanderPage1, sizeof SASExpanderPage1) == 1)
{
attached = get16(SASExpanderPage1.AttachedDevHandle);
if (parent == attached)
{
printf("\nExpander handle %x, phy %d is attached to parent handle %x, phy %d\n",
handle, phy, attached, SASExpanderPage1.AttachedPhyIdentifier);
printf("If the selected phy is offlined, it cannot later be onlined\n");
printf("If the parent's phy is offlined instead, it can later be onlined\n");
printf("\nAre you sure you want to continue? [Yes or No, default is No] ");
if (getYesNoAnswer(0) != 1)
{
return 0;
}
}
}
}
memset(phy_control_req, 0, sizeof phy_control_req);
phy_control_req[0] = 0x40;
phy_control_req[1] = 0x91;
phy_control_req[2] = 0xff;
phy_control_req[9] = phy;
phy_control_req[10] = onoff ? 0x01 : 0x03;
printf("\nSetting SAS phy %sline\n", onoff ? "on" : "off");
if (doSmpPassthrough(port, SASExpanderPage0.PhysicalPort, SASExpanderPage0.SASAddress,
phy_control_req, sizeof phy_control_req,
phy_control_rsp, sizeof phy_control_rsp, NULL) == 1)
{
if (phy_control_rsp[2] != 0)
{
printf("%sable Phy failed with result %02x\n",
onoff ? "En" : "Dis", phy_control_rsp[2]);
}
}
else
{
printf("%sable Phy failed\n", onoff ? "En" : "Dis");
}
}
return 1;
}
int
doSasIoUnitSettings(MPT_PORT *port)
{
SasIOUnitPage0_t SASIOUnitPage0;
SasIOUnitPage1_t *SASIOUnitPage1;
Mpi2SasIOUnitPage1_t *SASIOUnitPage1_2;
SasIOUnitPage2_t SASIOUnitPage2;
int length;
int flags;
int min;
int max;
int dev_info;
int port_config;
int init;
int targ;
char sas_port[8];
int i;
int t;
int num_phys;
SASIOUnitPage1 = getConfigPageAlloc(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0, &length);
if (SASIOUnitPage1 == NULL)
return 0;
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0,
&SASIOUnitPage0, sizeof SASIOUnitPage0) == 1)
num_phys = SASIOUnitPage0.NumPhys;
else
num_phys = SASIOUnitPage1->NumPhys;
t = SASIOUnitPage1->SATAMaxQDepth;
printf("SATA Maximum Queue Depth: [0 to 255, default is %d] ", t);
t = getNumberAnswer(0, 255, t);
SASIOUnitPage1->SATAMaxQDepth = t;
if (mpi2)
{
SASIOUnitPage1_2 = (pMpi2SasIOUnitPage1_t)SASIOUnitPage1;
t = get16(SASIOUnitPage1_2->SASNarrowMaxQueueDepth);
printf("SAS Max Queue Depth, Narrow: [0 to 65535, default is %d] ", t);
t = getNumberAnswer(0, 65535, t);
SASIOUnitPage1_2->SASNarrowMaxQueueDepth = set16(t);
t = get16(SASIOUnitPage1_2->SASWideMaxQueueDepth);
printf("SAS Max Queue Depth, Wide: [0 to 65535, default is %d] ", t);
t = getNumberAnswer(0, 65535, t);
SASIOUnitPage1_2->SASWideMaxQueueDepth = set16(t);
}
t = SASIOUnitPage1->ReportDeviceMissingDelay;
if (t & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16)
t = (t & ~MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) * 16;
printf("Device Missing Report Delay: [0 to 2047, default is %d] ", t);
t = getNumberAnswer(0, 2047, t);
if (t >= MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16)
t = (t / 16) | MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16;
SASIOUnitPage1->ReportDeviceMissingDelay = t;
t = SASIOUnitPage1->IODeviceMissingDelay;
printf("Device Missing I/O Delay: [0 to 255, default is %d] ", t);
t = getNumberAnswer(0, 127, t);
SASIOUnitPage1->IODeviceMissingDelay = t;
while (TRUE)
{
printf("\nPhyNum Link MinRate MaxRate Initiator Target Port\n");
for (i = 0; i < num_phys; i++)
{
if (mpi2)
flags = SASIOUnitPage1->PhyData[i].PhyFlags & MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
else
flags = SASIOUnitPage1->PhyData[i].PhyFlags & MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE;
min = SASIOUnitPage1->PhyData[i].MaxMinLinkRate & MPI_SAS_IOUNIT1_MIN_RATE_MASK;
max = SASIOUnitPage1->PhyData[i].MaxMinLinkRate & MPI_SAS_IOUNIT1_MAX_RATE_MASK;
dev_info = get32(SASIOUnitPage1->PhyData[i].ControllerPhyDeviceInfo);
if (SASIOUnitPage1->PhyData[i].PortFlags & MPI_SAS_IOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG)
sprintf(sas_port, "Auto");
else
sprintf(sas_port, " %d ", SASIOUnitPage1->PhyData[i].Port);
printf(" %2d %s %s %s %s %s %s\n", i,
flags ? "Disabled" : "Enabled ",
min == MPI25_SASIOUNIT1_MIN_RATE_12_0 ? "12.0" :
min == MPI2_SASIOUNIT1_MIN_RATE_6_0 ? "6.0" :
min == MPI_SAS_IOUNIT1_MIN_RATE_3_0 ? "3.0" : "1.5",
max == MPI25_SASIOUNIT1_MAX_RATE_12_0 ? "12.0" :
max == MPI2_SASIOUNIT1_MAX_RATE_6_0 ? "6.0" :
max == MPI_SAS_IOUNIT1_MAX_RATE_3_0 ? "3.0" : "1.5",
dev_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR ? "Enabled " : "Disabled",
dev_info & MPI_SAS_DEVICE_INFO_SSP_TARGET ? "Enabled " : "Disabled",
sas_port);
}
printf("\nSelect a Phy: [0-%d, %d=AllPhys, RETURN to quit] ", num_phys - 1, num_phys);
i = getNumberAnswer(0, num_phys, -1);
if (i < 0)
break;
if (i < num_phys)
{
if (mpi2)
flags = SASIOUnitPage1->PhyData[i].PhyFlags & MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
else
flags = SASIOUnitPage1->PhyData[i].PhyFlags & MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE;
min = SASIOUnitPage1->PhyData[i].MaxMinLinkRate & MPI_SAS_IOUNIT1_MIN_RATE_MASK;
max = SASIOUnitPage1->PhyData[i].MaxMinLinkRate & MPI_SAS_IOUNIT1_MAX_RATE_MASK;
dev_info = get32(SASIOUnitPage1->PhyData[i].ControllerPhyDeviceInfo);
t = flags == 0;
printf("Link: [0=Disabled, 1=Enabled, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (mpi2)
{
if (t == 1)
SASIOUnitPage1->PhyData[i].PhyFlags &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
else
SASIOUnitPage1->PhyData[i].PhyFlags |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
}
else
{
if (t == 1)
SASIOUnitPage1->PhyData[i].PhyFlags &= ~MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE;
else
SASIOUnitPage1->PhyData[i].PhyFlags |= MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE;
}
switch (min)
{
default:
case MPI_SAS_IOUNIT1_MIN_RATE_1_5: t = 0; break;
case MPI_SAS_IOUNIT1_MIN_RATE_3_0: t = 1; break;
case MPI2_SASIOUNIT1_MIN_RATE_6_0: t = 2; break;
case MPI25_SASIOUNIT1_MIN_RATE_12_0: t = 3; break;
}
if (mpi20)
{
printf("MinRate: [0=1.5 Gbps, 1=3.0 Gbps, 2=6.0 Gbps, default is %d] ", t);
t = getNumberAnswer(0, 2, t);
}
else if (mpi25)
{
printf("MinRate: [0=1.5 Gbps, 1=3.0 Gbps, 2=6.0 Gbps, 3=12.0 Gbps, default is %d] ", t);
t = getNumberAnswer(0, 3, t);
}
else
{
printf("MinRate: [0=1.5 Gbps, 1=3.0 Gbps, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
}
switch (t)
{
case 0: min = MPI_SAS_IOUNIT1_MIN_RATE_1_5; break;
case 1: min = MPI_SAS_IOUNIT1_MIN_RATE_3_0; break;
case 2: min = MPI2_SASIOUNIT1_MIN_RATE_6_0; break;
case 3: min = MPI25_SASIOUNIT1_MIN_RATE_12_0; break;
}
SASIOUnitPage1->PhyData[i].MaxMinLinkRate &= ~MPI_SAS_IOUNIT1_MIN_RATE_MASK;
SASIOUnitPage1->PhyData[i].MaxMinLinkRate |= min;
switch (max)
{
default:
case MPI_SAS_IOUNIT1_MAX_RATE_1_5: t = 0; break;
case MPI_SAS_IOUNIT1_MAX_RATE_3_0: t = 1; break;
case MPI2_SASIOUNIT1_MAX_RATE_6_0: t = 2; break;
case MPI25_SASIOUNIT1_MAX_RATE_12_0: t = 3; break;
}
if (mpi20)
{
printf("MaxRate: [0=1.5 Gbps, 1=3.0 Gbps, 2=6.0 Gbps, default is %d] ", t);
t = getNumberAnswer(0, 2, t);
}
else if (mpi25)
{
printf("MaxRate: [0=1.5 Gbps, 1=3.0 Gbps, 2=6.0 Gbps, 3=12.0 Gbps, default is %d] ", t);
t = getNumberAnswer(0, 3, t);
}
else
{
printf("MaxRate: [0=1.5 Gbps, 1=3.0 Gbps, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
}
switch (t)
{
case 0: max = MPI_SAS_IOUNIT1_MAX_RATE_1_5; break;
case 1: max = MPI_SAS_IOUNIT1_MAX_RATE_3_0; break;
case 2: max = MPI2_SASIOUNIT1_MAX_RATE_6_0; break;
case 3: max = MPI25_SASIOUNIT1_MAX_RATE_12_0; break;
}
SASIOUnitPage1->PhyData[i].MaxMinLinkRate &= ~MPI_SAS_IOUNIT1_MAX_RATE_MASK;
SASIOUnitPage1->PhyData[i].MaxMinLinkRate |= max;
t = (dev_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR) != 0;
printf("Initiator: [0=Disabled, 1=Enabled, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 1)
dev_info |= (MPI_SAS_DEVICE_INFO_SSP_INITIATOR |
MPI_SAS_DEVICE_INFO_STP_INITIATOR |
MPI_SAS_DEVICE_INFO_SMP_INITIATOR);
else
dev_info &= ~(MPI_SAS_DEVICE_INFO_SSP_INITIATOR |
MPI_SAS_DEVICE_INFO_STP_INITIATOR |
MPI_SAS_DEVICE_INFO_SMP_INITIATOR);
t = (dev_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) != 0;
printf("Target: [0=Disabled, 1=Enabled, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 1)
dev_info |= MPI_SAS_DEVICE_INFO_SSP_TARGET;
else
dev_info &= ~MPI_SAS_DEVICE_INFO_SSP_TARGET;
SASIOUnitPage1->PhyData[i].ControllerPhyDeviceInfo = set32(dev_info);
if (SASIOUnitPage1->PhyData[i].PortFlags & MPI_SAS_IOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG)
t = num_phys;
else
t = SASIOUnitPage1->PhyData[i].Port;
printf("Port: [0 to %d for manual config, %d for auto config, default is %d] ",
num_phys - 1, num_phys, t);
t = getNumberAnswer(0, num_phys, t);
if (t == num_phys)
{
SASIOUnitPage1->PhyData[i].PortFlags |= MPI_SAS_IOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG;
SASIOUnitPage1->PhyData[i].Port = 0;
}
else
{
SASIOUnitPage1->PhyData[i].PortFlags &= ~MPI_SAS_IOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG;
SASIOUnitPage1->PhyData[i].Port = t;
}
}
else
{
printf("Link: [0=Disabled, 1=Enabled, or RETURN to not change] ");
flags = getNumberAnswer(0, 1, -1);
if (mpi20)
{
printf("MinRate: [0=1.5 Gbps, 1=3.0 Gbps, 2=6.0 Gbps, or RETURN to not change] ");
min = getNumberAnswer(0, 2, -1);
printf("MaxRate: [0=1.5 Gbps, 1=3.0 Gbps, 2=6.0 Gbps, or RETURN to not change] ");
max = getNumberAnswer(0, 2, -1);
}
if (mpi25)
{
printf("MinRate: [0=1.5 Gbps, 1=3.0 Gbps, 2=6.0 Gbps, 3=12.0 Gbps, or RETURN to not change] ");
min = getNumberAnswer(0, 3, -1);
printf("MaxRate: [0=1.5 Gbps, 1=3.0 Gbps, 2=6.0 Gbps, 3=12.0 Gpbs, or RETURN to not change] ");
max = getNumberAnswer(0, 3, -1);
}
else
{
printf("MinRate: [0=1.5 Gbps, 1=3.0 Gbps, or RETURN to not change] ");
min = getNumberAnswer(0, 1, -1);
printf("MaxRate: [0=1.5 Gbps, 1=3.0 Gbps, or RETURN to not change] ");
max = getNumberAnswer(0, 1, -1);
}
switch (min)
{
case 0: min = MPI_SAS_IOUNIT1_MIN_RATE_1_5; break;
case 1: min = MPI_SAS_IOUNIT1_MIN_RATE_3_0; break;
case 2: min = MPI2_SASIOUNIT1_MIN_RATE_6_0; break;
case 3: min = MPI25_SASIOUNIT1_MIN_RATE_12_0; break;
}
switch (max)
{
case 0: max = MPI_SAS_IOUNIT1_MAX_RATE_1_5; break;
case 1: max = MPI_SAS_IOUNIT1_MAX_RATE_3_0; break;
case 2: max = MPI2_SASIOUNIT1_MAX_RATE_6_0; break;
case 3: max = MPI25_SASIOUNIT1_MAX_RATE_12_0; break;
}
printf("Initiator: [0=Disabled, 1=Enabled, or RETURN to not change] ");
init = getNumberAnswer(0, 1, -1);
printf("Target: [0=Disabled, 1=Enabled, or RETURN to not change] ");
targ = getNumberAnswer(0, 1, -1);
if (t == 1)
dev_info |= MPI_SAS_DEVICE_INFO_SSP_TARGET;
printf("Port configuration: [1=Auto, 2=Narrow, 3=Wide, or RETURN to not change] ");
port_config = getNumberAnswer(0, 3, -1);
for (i = 0; i < num_phys; i++)
{
if (mpi2)
{
if (flags == 0)
SASIOUnitPage1->PhyData[i].PhyFlags |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
if (flags == 1)
SASIOUnitPage1->PhyData[i].PhyFlags &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
}
else
{
if (flags == 0)
SASIOUnitPage1->PhyData[i].PhyFlags |= MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE;
if (flags == 1)
SASIOUnitPage1->PhyData[i].PhyFlags &= ~MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE;
}
if (min != -1)
{
SASIOUnitPage1->PhyData[i].MaxMinLinkRate &= ~MPI_SAS_IOUNIT1_MIN_RATE_MASK;
SASIOUnitPage1->PhyData[i].MaxMinLinkRate |= min;
}
if (max != -1)
{
SASIOUnitPage1->PhyData[i].MaxMinLinkRate &= ~MPI_SAS_IOUNIT1_MAX_RATE_MASK;
SASIOUnitPage1->PhyData[i].MaxMinLinkRate |= max;
}
t = get32(SASIOUnitPage1->PhyData[i].ControllerPhyDeviceInfo);
if (init == 0)
t &= ~(MPI_SAS_DEVICE_INFO_SSP_INITIATOR |
MPI_SAS_DEVICE_INFO_STP_INITIATOR |
MPI_SAS_DEVICE_INFO_SMP_INITIATOR);
if (init == 1)
t |= (MPI_SAS_DEVICE_INFO_SSP_INITIATOR |
MPI_SAS_DEVICE_INFO_STP_INITIATOR |
MPI_SAS_DEVICE_INFO_SMP_INITIATOR);
if (targ == 0)
t &= ~MPI_SAS_DEVICE_INFO_SSP_TARGET;
if (targ == 1)
t |= MPI_SAS_DEVICE_INFO_SSP_TARGET;
SASIOUnitPage1->PhyData[i].ControllerPhyDeviceInfo = set32(t);
if (port_config == 1)
{
SASIOUnitPage1->PhyData[i].PortFlags |= MPI_SAS_IOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG;
SASIOUnitPage1->PhyData[i].Port = 0;
}
if (port_config == 2)
{
SASIOUnitPage1->PhyData[i].PortFlags &= ~MPI_SAS_IOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG;
SASIOUnitPage1->PhyData[i].Port = i;
}
if (port_config == 3)
{
SASIOUnitPage1->PhyData[i].PortFlags &= ~MPI_SAS_IOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG;
SASIOUnitPage1->PhyData[i].Port = i / 4;
}
}
}
}
if (setConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0, SASIOUnitPage1, length) != 1)
{
printf("Failed to save changes to NVRAM!\n");
free(SASIOUnitPage1);
return 0;
}
if (mpi1)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 2, 0,
&SASIOUnitPage2, sizeof SASIOUnitPage2) != 1)
{
free(SASIOUnitPage1);
return 0;
}
flags = SASIOUnitPage2.Flags;
t = (flags & MPI_SAS_IOUNIT2_FLAGS_DISABLE_PERSISTENT_MAPPINGS) == 0;
printf("\nPersistence: [0=Disabled, 1=Enabled, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 1)
flags &= ~MPI_SAS_IOUNIT2_FLAGS_DISABLE_PERSISTENT_MAPPINGS;
else
flags |= MPI_SAS_IOUNIT2_FLAGS_DISABLE_PERSISTENT_MAPPINGS;
t = (flags & MPI_SAS_IOUNIT2_FLAGS_MASK_PHYS_MAP_MODE) >> MPI_SAS_IOUNIT2_FLAGS_SHIFT_PHYS_MAP_MODE;
printf("Physical mapping: [0=None, 1=DirectAttach, 2=EnclosureSlot, default is %d] ", t);
t = getNumberAnswer(0, 2, t);
flags &= ~MPI_SAS_IOUNIT2_FLAGS_MASK_PHYS_MAP_MODE;
flags |= t << MPI_SAS_IOUNIT2_FLAGS_SHIFT_PHYS_MAP_MODE;
SASIOUnitPage2.Flags = flags;
if (t != MPI_SAS_IOUNIT2_FLAGS_NO_PHYS_MAP)
{
t = get16(SASIOUnitPage2.MaxNumPhysicalMappedIDs);
if (t == 0)
t = num_phys;
if (t > 32)
t = 32;
printf("Number of Target IDs to reserve: [0 to 32, default is %d] ", t);
t = getNumberAnswer(0, 32, t);
SASIOUnitPage2.MaxNumPhysicalMappedIDs = set16(t);
}
if (setConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 2, 0,
&SASIOUnitPage2, sizeof SASIOUnitPage2) != 1)
{
printf("Failed to save changes to NVRAM!\n");
free(SASIOUnitPage1);
return 0;
}
}
free(SASIOUnitPage1);
return 1;
}
int
doSasChangeWwid(MPT_PORT *port, int checkZero)
{
ManufacturingPage5_t *ManufacturingPage5;
Mpi2ManufacturingPage5_t *ManufacturingPage5_2;
int length;
int t;
int i;
U32 wwid_l;
U32 wwid_h;
ManufacturingPage5 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 5, 0, &length);
if (ManufacturingPage5 == NULL)
return 0;
ManufacturingPage5_2 = (pMpi2ManufacturingPage5_t)ManufacturingPage5;
if (mpi2)
{
wwid_l = get32(ManufacturingPage5_2->Phy[0].WWID.Low);
wwid_h = get32(ManufacturingPage5_2->Phy[0].WWID.High);
}
else
{
wwid_l = get32(ManufacturingPage5->BaseWWID.Low);
wwid_h = get32(ManufacturingPage5->BaseWWID.High);
}
if (checkZero)
{
free(ManufacturingPage5);
return wwid_l == 0 && wwid_h == 0;
}
printf("Current SAS WWID = %08x%08x\n\n", wwid_h, wwid_l);
printf("Enter new WWID: [16 hex digits or RETURN to quit] ");
t = getHexDoubleNumberAnswer(&wwid_h, &wwid_l);
if (t == 0)
{
free(ManufacturingPage5);
return 0;
}
if (mpi2)
{
for(i = 0; i < port->numPhys; i++)
{
ManufacturingPage5_2->Phy[i].WWID.Low = set32(wwid_l + i);
ManufacturingPage5_2->Phy[i].WWID.High = set32(wwid_h);
}
}
else
{
ManufacturingPage5->BaseWWID.Low = set32(wwid_l);
ManufacturingPage5->BaseWWID.High = set32(wwid_h);
}
doIocInit(port, MPI_WHOINIT_MANUFACTURER);
t = setConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 5, 0, ManufacturingPage5, length);
doIocInit(port, port->whoInit);
free(ManufacturingPage5);
if (t != 1)
{
printf("Failed to save changes to NVRAM!\n");
return 0;
}
return 1;
}
int
doIoUnitSettings(MPT_PORT *port)
{
IOUnitPage1_t IOUnitPage1;
int flags;
int t;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IO_UNIT, 1, 0, &IOUnitPage1, sizeof IOUnitPage1) != 1)
return 0;
flags = get32(IOUnitPage1.Flags);
t = (flags & MPI_IOUNITPAGE1_MULTI_PATHING) != 0;
printf("Multi-pathing: [0=Disabled, 1=Enabled, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 0)
flags &= ~MPI_IOUNITPAGE1_MULTI_PATHING;
else
flags |= MPI_IOUNITPAGE1_MULTI_PATHING;
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
t = (flags & MPI_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE) == 0;
printf("SATA Native Command Queuing: [0=Disabled, 1=Enabled, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 1)
flags &= ~MPI_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE;
else
flags |= MPI_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE;
t = (flags & MPI_IOUNITPAGE1_SATA_WRITE_CACHE_DISABLE) == 0;
printf("SATA Write Caching: [0=Disabled, 1=Enabled, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 1)
flags &= ~MPI_IOUNITPAGE1_SATA_WRITE_CACHE_DISABLE;
else
flags |= MPI_IOUNITPAGE1_SATA_WRITE_CACHE_DISABLE;
}
IOUnitPage1.Flags = set32(flags);
if (setConfigPage(port, MPI_CONFIG_PAGETYPE_IO_UNIT, 1, 0, &IOUnitPage1, sizeof IOUnitPage1) != 1)
{
printf("Failed to save changes to NVRAM!\n");
return 0;
}
return 1;
}
int
doFcPersistentMappings(MPT_PORT *port, int command)
{
FCPortPage1_t FCPortPage1;
FCPortPage3_t *FCPortPage3;
FCDevicePage0_t FCDevicePage0;
int sort_by_did;
int do_by_entry;
int i;
int j;
int loop_id;
int t;
int flags;
int bus;
int target;
int b_t;
int n;
int *changed;
int n_changed;
char *type;
int d_id = 0;
U32 wwnn_l;
U32 wwnn_h;
U32 wwpn_l;
U32 wwpn_h;
if (bringOnline(port) != 1)
return 0;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
return 0;
sort_by_did = get32(FCPortPage1.Flags) & MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID;
n = port->maxPersistentIds * sizeof(PersistentData_t) + sizeof(ConfigPageHeader_t);
FCPortPage3 = (pFCPortPage3_t)malloc(n);
changed = (int *)malloc(port->maxPersistentIds * sizeof *changed);
if (n > 255 * 4)
{
FCPortPage3_t tempFCPortPage3;
do_by_entry = 1;
for (i = 0; i < port->maxPersistentIds; i++)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 3,
MPI_FC_PORT_PGAD_FORM_INDEX + i,
&tempFCPortPage3, sizeof tempFCPortPage3) != 1)
{
free(FCPortPage3);
free(changed);
return 0;
}
FCPortPage3->Entry[i] = tempFCPortPage3.Entry[0];
}
FCPortPage3->Header = tempFCPortPage3.Header;
n = port->maxPersistentIds;
}
else
{
do_by_entry = 0;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 3, 0, FCPortPage3, n) != 1)
{
free(FCPortPage3);
free(changed);
return 0;
}
n = (FCPortPage3->Header.PageLength * 4 - sizeof(ConfigPageHeader_t)) / sizeof(PersistentData_t);
}
memset(changed, 0, port->maxPersistentIds * sizeof *changed);
n_changed = 0;
if (command == 1 || command == 4 || command == 5)
{
j = 0;
for (i = 0; i < n; i++)
{
flags = get16(FCPortPage3->Entry[i].Flags);
if (flags & MPI_PERSISTENT_FLAGS_ENTRY_VALID)
{
j++;
if (flags & MPI_PERSISTENT_FLAGS_BY_DID)
{
printf("Persistent entry %d is valid, Bus %d Target %d is DID %06x\n", i,
FCPortPage3->Entry[i].Bus,
FCPortPage3->Entry[i].TargetID,
get32(FCPortPage3->Entry[i].PhysicalIdentifier.Did));
if (!sort_by_did)
printf(" Since the port is in SortByWWN mode, this entry is being ignored\n");
}
else
{
printf("Persistent entry %d is valid, Bus %d Target %d is WWN %08x%08x\n", i,
FCPortPage3->Entry[i].Bus,
FCPortPage3->Entry[i].TargetID,
get32(FCPortPage3->Entry[i].PhysicalIdentifier.WWN.WWPN.High),
get32(FCPortPage3->Entry[i].PhysicalIdentifier.WWN.WWPN.Low));
if (sort_by_did)
printf(" Since the port is in SortByDID mode, this entry is being ignored\n");
}
if (command == 5)
{
printf(" Delete the entry for this target? [Yes or No, default is No] ");
if (getYesNoAnswer(0) != 1)
continue;
}
if (command == 4 || command == 5)
{
printf(" Deleting persistent entry %d\n", i);
flags &= ~MPI_PERSISTENT_FLAGS_ENTRY_VALID;
FCPortPage3->Entry[i].Flags = set16(flags);
changed[i] = 1;
n_changed++;
}
}
}
if (j == 0)
printf("No persistent entries found\n");
}
if (command == 2 || command == 3)
{
for (bus = 0; bus < port->maxBuses; bus++)
{
for (target = port->minTargets; target < port->maxTargets; target++)
{
b_t = (bus << 8) + target;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_DEVICE, 0,
MPI_FC_DEVICE_PGAD_FORM_BUS_TID + b_t,
&FCDevicePage0, sizeof FCDevicePage0) != 1)
continue;
if (sort_by_did)
printf("Bus %d Target %d is DID %06x\n", bus, target,
get32(FCDevicePage0.PortIdentifier));
else
printf("Bus %d Target %d is WWN %08x%08x\n", bus, target,
get32(FCDevicePage0.WWPN.High), get32(FCDevicePage0.WWPN.Low));
for (i = 0; i < n; i++)
{
if (get16(FCPortPage3->Entry[i].Flags) & MPI_PERSISTENT_FLAGS_ENTRY_VALID)
{
if (FCPortPage3->Entry[i].Bus != bus ||
FCPortPage3->Entry[i].TargetID != target)
{
continue;
}
if (sort_by_did)
{
if (FCPortPage3->Entry[i].PhysicalIdentifier.Did == FCDevicePage0.PortIdentifier)
{
break;
}
}
else
{
if (FCPortPage3->Entry[i].PhysicalIdentifier.WWN.WWPN.High == FCDevicePage0.WWPN.High &&
FCPortPage3->Entry[i].PhysicalIdentifier.WWN.WWPN.Low == FCDevicePage0.WWPN.Low &&
FCPortPage3->Entry[i].PhysicalIdentifier.WWN.WWNN.High == FCDevicePage0.WWNN.High &&
FCPortPage3->Entry[i].PhysicalIdentifier.WWN.WWNN.Low == FCDevicePage0.WWNN.Low)
{
break;
}
}
}
}
if (i < n)
{
printf(" Persistent entry %d is already valid for this target!\n", i);
continue;
}
for (i = 0; i < n; i++)
{
if (!(get16(FCPortPage3->Entry[i].Flags) & MPI_PERSISTENT_FLAGS_ENTRY_VALID))
{
break;
}
}
if (i < n)
{
if (command == 3)
{
printf(" Add an entry for this target? [Yes or No, default is No] ");
if (getYesNoAnswer(0) != 1)
continue;
}
printf(" Adding persistent entry %d\n", i);
flags = MPI_PERSISTENT_FLAGS_ENTRY_VALID |
MPI_PERSISTENT_FLAGS_SCAN_ID |
MPI_PERSISTENT_FLAGS_SCAN_LUNS;
FCPortPage3->Entry[i].Flags = set16(flags);
FCPortPage3->Entry[i].Bus = bus;
FCPortPage3->Entry[i].TargetID = target;
if (sort_by_did)
{
flags |= MPI_PERSISTENT_FLAGS_BY_DID;
FCPortPage3->Entry[i].Flags = set16(flags);
FCPortPage3->Entry[i].PhysicalIdentifier.Did = FCDevicePage0.PortIdentifier;
}
else
{
FCPortPage3->Entry[i].PhysicalIdentifier.WWN.WWPN.High = FCDevicePage0.WWPN.High;
FCPortPage3->Entry[i].PhysicalIdentifier.WWN.WWPN.Low = FCDevicePage0.WWPN.Low;
FCPortPage3->Entry[i].PhysicalIdentifier.WWN.WWNN.High = FCDevicePage0.WWNN.High;
FCPortPage3->Entry[i].PhysicalIdentifier.WWN.WWNN.Low = FCDevicePage0.WWNN.Low;
}
changed[i] = 1;
n_changed++;
}
else
{
printf(" No persistent entry available for this target!\n");
}
}
}
}
if (command == 6)
{
if (sort_by_did)
{
printf("The port is in SortByDID mode, enter Port IDs\n");
type = "DID";
}
else
{
printf("The port is in SortByWWN mode, enter World Wide Node and Port Names\n");
type = "WWN";
}
for (i = 0; i < n; i++)
{
if (get16(FCPortPage3->Entry[i].Flags) & MPI_PERSISTENT_FLAGS_ENTRY_VALID)
continue;
printf("\n");
if (sort_by_did)
{
printf("Enter DID: [000000-FFFFFF or RETURN to quit] ");
d_id = getNumberAnswerHex(0x000000, 0xFFFFFF, -1);
if (d_id < 0)
break;
}
else
{
printf("Enter WWNN: [16 hex digits or RETURN to quit] ");
t = getHexDoubleNumberAnswer(&wwnn_h, &wwnn_l);
if (t == 0)
break;
printf("Enter WWPN: [16 hex digits or RETURN to quit] ");
t = getHexDoubleNumberAnswer(&wwpn_h, &wwpn_l);
if (t == 0)
break;
}
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Enter desired Bus for this %s: [0-%d or RETURN to quit] ", type, port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
break;
}
else
{
bus = 0;
}
printf("Enter desired Target for this %s: [0-%d or RETURN to quit] ", type, port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
break;
for (j = 0; j < n; j++)
{
if (i == j)
continue;
if (get16(FCPortPage3->Entry[j].Flags) & MPI_PERSISTENT_FLAGS_ENTRY_VALID)
{
if (sort_by_did)
{
if (get32(FCPortPage3->Entry[j].PhysicalIdentifier.Did) == (U32)d_id)
{
printf("\nPersistent entry %d is already valid for this DID!\n", j);
break;
}
}
else
{
if (get32(FCPortPage3->Entry[j].PhysicalIdentifier.WWN.WWPN.High) == wwpn_h &&
get32(FCPortPage3->Entry[j].PhysicalIdentifier.WWN.WWPN.Low) == wwpn_l &&
get32(FCPortPage3->Entry[j].PhysicalIdentifier.WWN.WWNN.High) == wwnn_h &&
get32(FCPortPage3->Entry[j].PhysicalIdentifier.WWN.WWNN.Low) == wwnn_l)
{
printf("\nPersistent entry %d is already valid for this WWN!\n", j);
break;
}
}
if (FCPortPage3->Entry[j].Bus == bus &&
FCPortPage3->Entry[j].TargetID == target)
{
printf("\nPersistent entry %d is already valid for this Bus & Target!\n", j);
break;
}
}
}
if (j < n)
{
i--;
continue;
}
printf("\nAdding persistent entry %d\n", i);
flags = MPI_PERSISTENT_FLAGS_ENTRY_VALID |
MPI_PERSISTENT_FLAGS_SCAN_ID |
MPI_PERSISTENT_FLAGS_SCAN_LUNS;
FCPortPage3->Entry[i].Flags = set16(flags);
FCPortPage3->Entry[i].Bus = bus;
FCPortPage3->Entry[i].TargetID = target;
if (sort_by_did)
{
flags |= MPI_PERSISTENT_FLAGS_BY_DID;
FCPortPage3->Entry[i].Flags = set16(flags);
FCPortPage3->Entry[i].PhysicalIdentifier.Did = set32(d_id);
}
else
{
FCPortPage3->Entry[i].PhysicalIdentifier.WWN.WWPN.High = set32(wwpn_h);
FCPortPage3->Entry[i].PhysicalIdentifier.WWN.WWPN.Low = set32(wwpn_l);
FCPortPage3->Entry[i].PhysicalIdentifier.WWN.WWNN.High = set32(wwnn_h);
FCPortPage3->Entry[i].PhysicalIdentifier.WWN.WWNN.Low = set32(wwnn_l);
}
changed[i] = 1;
n_changed++;
}
}
if (command == 7)
{
if (!sort_by_did)
{
printf("The port is not in SortByDID mode!\n");
printf("\nDo you want to switch to SortByDID mode? [Yes or No, default is No] ");
if (getYesNoAnswer(0) == 1)
{
flags = get32(FCPortPage1.Flags);
flags |= MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID;
FCPortPage1.Flags = set32(flags);
if (setConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
{
printf("Failed to save changes to NVRAM!\n");
free(FCPortPage3);
free(changed);
return 0;
}
else
{
sort_by_did = 1;
printf("\n");
}
}
}
loop_id = 0;
for (i = 0; i < n; i++)
{
if (get16(FCPortPage3->Entry[i].Flags) & MPI_PERSISTENT_FLAGS_ENTRY_VALID)
continue;
d_id = LoopIdToAlpa[loop_id];
bus = 0;
target = loop_id;
t = n;
for (j = 0; j < n; j++)
{
if (i == j)
continue;
if (get16(FCPortPage3->Entry[j].Flags) & MPI_PERSISTENT_FLAGS_ENTRY_VALID)
{
if (get32(FCPortPage3->Entry[j].PhysicalIdentifier.Did) == (U32)d_id &&
FCPortPage3->Entry[j].Bus == bus &&
FCPortPage3->Entry[j].TargetID == target)
{
printf("Persistent entry %d exists for LoopID %d: Bus %d Target %d is DID %02x\n",
j, loop_id, bus, target, d_id);
t = j;
break;
}
else
{
if (get32(FCPortPage3->Entry[j].PhysicalIdentifier.Did) == (U32)d_id)
{
printf("\nPersistent entry %d is already valid for DID %02x!\n", j, d_id);
break;
}
if (FCPortPage3->Entry[j].Bus == bus &&
FCPortPage3->Entry[j].TargetID == target)
{
printf("\nPersistent entry %d is already valid for Bus %d Target %d!\n", j, bus, target);
break;
}
}
}
}
if (j < n)
{
if (t == n)
{
printf("\nDo you want to continue? [Yes or No, default is No] ");
if (getYesNoAnswer(0) != 1)
break;
printf("\n");
}
i--;
}
else
{
printf("Adding persistent entry %d for LoopID %d: Bus %d Target %d is DID %02x\n",
i, loop_id, bus, target, d_id);
flags = MPI_PERSISTENT_FLAGS_ENTRY_VALID |
MPI_PERSISTENT_FLAGS_SCAN_ID |
MPI_PERSISTENT_FLAGS_SCAN_LUNS |
MPI_PERSISTENT_FLAGS_BY_DID;
FCPortPage3->Entry[i].Flags = set16(flags);
FCPortPage3->Entry[i].Bus = bus;
FCPortPage3->Entry[i].TargetID = target;
FCPortPage3->Entry[i].PhysicalIdentifier.Did = set32(d_id);
changed[i] = 1;
n_changed++;
}
loop_id++;
if (loop_id == 126)
break;
}
}
if (n_changed != 0)
{
if (do_by_entry)
{
FCPortPage3_t tempFCPortPage3;
tempFCPortPage3.Header = FCPortPage3->Header;
for (i = 0; i < port->maxPersistentIds; i++)
{
if (changed[i])
{
tempFCPortPage3.Entry[0] = FCPortPage3->Entry[i];
if (setConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 3,
MPI_FC_PORT_PGAD_FORM_INDEX + i,
&tempFCPortPage3, sizeof tempFCPortPage3) != 1)
{
printf("Failed to save changes to NVRAM!\n");
free(FCPortPage3);
free(changed);
return 0;
}
}
}
}
else
{
n = FCPortPage3->Header.PageLength * 4;
if (setConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 3, 0, FCPortPage3, n) != 1)
{
printf("Failed to save changes to NVRAM!\n");
free(FCPortPage3);
free(changed);
return 0;
}
}
}
free(FCPortPage3);
free(changed);
return 1;
}
int
doSasPersistentMappings(MPT_PORT *port, int command)
{
ConfigReply_t configRep;
SasDevicePage2_t *SASDevicePage2;
SasDevicePage2_t tempSASDevicePage2;
SasIOUnitPage2_t SASIOUnitPage2;
SasIoUnitControlRequest_t req;
SasIoUnitControlReply_t rep;
int flags;
int encl_slot;
int start_slot;
int num_slots;
U32 encl_id_l;
U32 encl_id_h;
int i;
int j;
int k;
int t;
int bus;
int target;
int b_t;
int max_b_t;
int n;
int *changed;
int n_changed;
int *i_to_b_t;
int old_i;
char name[256];
FILE *file;
unsigned char *mappingBuf = NULL;
int mappingLen;
char *c;
U32 phys_id_l;
U32 phys_id_h;
U32 encl_map;
int warn = 0;
if (bringOnline(port) != 1)
return 0;
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 2, 0,
&SASIOUnitPage2, sizeof SASIOUnitPage2) != 1)
return 0;
flags = SASIOUnitPage2.Flags;
encl_slot = (flags & MPI_SAS_IOUNIT2_FLAGS_MASK_PHYS_MAP_MODE) ==
(MPI_SAS_IOUNIT2_FLAGS_ENCLOSURE_SLOT_PHYS_MAP << MPI_SAS_IOUNIT2_FLAGS_SHIFT_PHYS_MAP_MODE);
if (command == 10 || command == 11)
{
if (flags & MPI_SAS_IOUNIT2_FLAGS_DISABLE_PERSISTENT_MAPPINGS)
{
printf("Persistent mapping is disabled, no entries will be cleared\n");
return 1;
}
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
if (command == 10)
{
req.Operation = MPI_SAS_OP_CLEAR_ALL_PERSISTENT;
printf("Clearing all persistent entries...\n");
}
if (command == 11)
{
req.Operation = MPI_SAS_OP_CLEAR_NOT_PRESENT;
printf("Clearing all non-present persistent entries...\n");
}
t = doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
if (t != 1)
printf("Clear failed!\n");
if (wFlag)
fprintf(logFile, "%s: Clear (SAS_IO_UNIT_CONTROL) of type %d: %s\n",
logPrefix(port), command, t ? "PASS" : "FAIL");
return t;
}
if (command == 12)
{
t = (flags & MPI_SAS_IOUNIT2_FLAGS_DISABLE_PERSISTENT_MAPPINGS) == 0;
printf("Persistence: [0=Disabled, 1=Enabled, default is %d] ", t);
t = getNumberAnswer(0, 1, t);
if (t == 1)
flags &= ~MPI_SAS_IOUNIT2_FLAGS_DISABLE_PERSISTENT_MAPPINGS;
else
flags |= MPI_SAS_IOUNIT2_FLAGS_DISABLE_PERSISTENT_MAPPINGS;
SASIOUnitPage2.Flags = flags;
if (setConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 2, 0,
&SASIOUnitPage2, sizeof SASIOUnitPage2) != 1)
{
printf("Failed to save changes to NVRAM!\n");
return 0;
}
return 1;
}
max_b_t = (port->maxBuses << 8) + port->maxTargets;
n = port->maxPersistentIds;
SASDevicePage2 = (pSasDevicePage2_t)malloc(n * sizeof *SASDevicePage2);
changed = (int *)malloc(n * sizeof *changed);
i_to_b_t = (int *)malloc(n * sizeof *i_to_b_t);
if (getConfigPageHeader(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 2, 0, &configRep) != 1)
{
free(SASDevicePage2);
free(changed);
free(i_to_b_t);
return 0;
}
memset(&tempSASDevicePage2, 0, sizeof tempSASDevicePage2);
tempSASDevicePage2.Header.ExtPageType = configRep.ExtPageType;
tempSASDevicePage2.Header.ExtPageLength = configRep.ExtPageLength;
tempSASDevicePage2.Header.PageType = configRep.Header.PageType;
tempSASDevicePage2.Header.PageNumber = configRep.Header.PageNumber;
tempSASDevicePage2.Header.PageVersion = configRep.Header.PageVersion;
for (i = 0, j = 0; i < max_b_t && j < n; i++)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 2,
(MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
<<MPI_SAS_DEVICE_PGAD_FORM_SHIFT) + i,
&SASDevicePage2[j], sizeof *SASDevicePage2) == 1)
{
if (SASDevicePage2[j].PhysicalIdentifier.High != 0 ||
SASDevicePage2[j].PhysicalIdentifier.Low != 0)
{
i_to_b_t[j] = i;
j++;
}
}
}
memset(changed, 0, n * sizeof *changed);
n_changed = 0;
if (command == 1 || command == 4 || command == 5)
{
for (i = 0; i < j; i++)
{
if (encl_slot)
{
encl_map = get32(SASDevicePage2[i].EnclosureMapping);
start_slot = (encl_map & MPI_SASDEVICE2_ENC_MAP_MASK_START_INDEX) >>
MPI_SASDEVICE2_ENC_MAP_SHIFT_START_INDEX;
num_slots = (encl_map & MPI_SASDEVICE2_ENC_MAP_MASK_NUM_SLOTS) >>
MPI_SASDEVICE2_ENC_MAP_SHIFT_NUM_SLOTS;
if (num_slots == 1)
printf("Persistent entry %d is valid, EnclosureId %08x%08x, Slot %d\n",
i,
get32(SASDevicePage2[i].PhysicalIdentifier.High),
get32(SASDevicePage2[i].PhysicalIdentifier.Low),
start_slot);
else
printf("Persistent entry %d is valid, EnclosureId %08x%08x, Slots %d to %d\n",
i,
get32(SASDevicePage2[i].PhysicalIdentifier.High),
get32(SASDevicePage2[i].PhysicalIdentifier.Low),
start_slot, start_slot + num_slots - 1);
}
else
{
b_t = i_to_b_t[i];
printf("Persistent entry %d is valid, Bus %d Target %d is PhysId %08x%08x\n",
i, b_t >> 8, b_t & 255,
get32(SASDevicePage2[i].PhysicalIdentifier.High),
get32(SASDevicePage2[i].PhysicalIdentifier.Low));
}
if (command == 5)
{
printf(" Delete the entry for this %s? [Yes or No, default is No] ",
encl_slot ? "enclosure" : "target");
if (getYesNoAnswer(0) != 1)
continue;
}
if (command == 4 || command == 5)
{
printf(" Deleting persistent entry\n");
SASDevicePage2[i].PhysicalIdentifier.High = 0;
SASDevicePage2[i].PhysicalIdentifier.Low = 0;
SASDevicePage2[i].EnclosureMapping = 0;
changed[i] = 1;
n_changed++;
}
}
if (j == 0)
printf("No persistent entries found\n");
}
if (command == 6)
{
while (j < n)
{
if (encl_slot)
{
printf("Enter current EnclosureId: [16 hex digits or RETURN to quit] ");
t = getHexDoubleNumberAnswer(&encl_id_h, &encl_id_l);
if (t == 0)
break;
k = 0;
for (i = 0; i < j; i++)
{
if (get32(SASDevicePage2[i].PhysicalIdentifier.High) == encl_id_h &&
get32(SASDevicePage2[i].PhysicalIdentifier.Low) == encl_id_l)
{
printf("\nPersistent entry %d is valid for the current EnclosureId\n\n", i);
k++;
}
}
if (k == 0)
{
printf("\nNo persistent entries are valid for the current EnclosureId!\n\n");
continue;
}
old_i = i;
printf("Enter desired EnclosureId: [16 hex digits or RETURN to quit] ");
t = getHexDoubleNumberAnswer(&phys_id_h, &phys_id_l);
if (t == 0)
break;
if (phys_id_h == encl_id_h && phys_id_l == encl_id_l)
{
printf("\nDesired EnclosureId is equal to Current EnclosureId!\n\n");
continue;
}
for (i = 0; i < j; i++)
{
if (get32(SASDevicePage2[i].PhysicalIdentifier.High) == phys_id_h &&
get32(SASDevicePage2[i].PhysicalIdentifier.Low) == phys_id_l)
{
printf("\nPersistent entry %d is valid for the desired EnclosureId\n\n", i);
}
}
for (i = 0; i < j; i++)
{
if (get32(SASDevicePage2[i].PhysicalIdentifier.High) == encl_id_h &&
get32(SASDevicePage2[i].PhysicalIdentifier.Low) == encl_id_l)
{
printf("Modifying persistent entry %d!\n", i);
SASDevicePage2[i].PhysicalIdentifier.High = set32(phys_id_h);
SASDevicePage2[i].PhysicalIdentifier.Low = set32(phys_id_l);
changed[i] = 1;
n_changed++;
continue;
}
if (get32(SASDevicePage2[i].PhysicalIdentifier.High) == phys_id_h &&
get32(SASDevicePage2[i].PhysicalIdentifier.Low) == phys_id_l)
{
printf("Deleting persistent entry %d!\n", i);
SASDevicePage2[i].PhysicalIdentifier.High = 0;
SASDevicePage2[i].PhysicalIdentifier.Low = 0;
SASDevicePage2[i].EnclosureMapping = 0;
changed[i] = 1;
n_changed++;
continue;
}
}
printf("\n");
}
else
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Enter current Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
break;
}
else
{
bus = 0;
}
printf("Enter current Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
break;
b_t = (bus << 8) + target;
for (i = 0; i < j; i++)
{
if (i_to_b_t[i] == b_t &&
(SASDevicePage2[i].PhysicalIdentifier.High != 0 ||
SASDevicePage2[i].PhysicalIdentifier.Low != 0))
{
// printf("\nPersistent entry %d is valid for this Bus/Target\n\n", i);
break;
}
}
if (i == j)
{
printf("\nNo persistent entry is valid for this Bus/Target!\n\n");
continue;
}
old_i = i;
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Enter desired Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
break;
}
else
{
bus = 0;
}
printf("Enter desired Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
break;
b_t = (bus << 8) + target;
for (i = 0; i < j; i++)
{
if (i_to_b_t[i] == b_t &&
(SASDevicePage2[i].PhysicalIdentifier.High != 0 ||
SASDevicePage2[i].PhysicalIdentifier.Low != 0))
{
if (i == old_i)
printf("\nDesired Bus/Target is equal to Current Bus/Target!\n\n");
else
printf("\nPersistent entry %d is already valid for this Bus/Target!\n\n", i);
break;
}
}
if (i < j)
continue;
printf("\nDeleting persistent entry %d!\n", old_i);
printf("Creating persistent entry %d!\n\n", j);
printf("Persistent entry %d is valid, Bus %d Target %d is PhysId %08x%08x\n\n",
j, bus, target,
get32(SASDevicePage2[old_i].PhysicalIdentifier.High),
get32(SASDevicePage2[old_i].PhysicalIdentifier.Low));
SASDevicePage2[j] = SASDevicePage2[old_i];
changed[j] = 1;
n_changed++;
i_to_b_t[j] = b_t;
j++;
SASDevicePage2[old_i].PhysicalIdentifier.High = 0;
SASDevicePage2[old_i].PhysicalIdentifier.Low = 0;
SASDevicePage2[old_i].EnclosureMapping = 0;
changed[old_i] = 1;
n_changed++;
}
}
}
if (command == 7)
{
n = getFileName(name, sizeof name, stdin, "persistent mapping", 0);
if (n > 0)
{
file = fopen(name, "w");
if (file == NULL)
{
printf("Open failure for file %s\n", name);
perror("Error is");
}
else
{
for (i = 0; i < j; i++)
{
b_t = i_to_b_t[i];
fprintf(file, "Bus %d Target %d is PhysId %08x%08x EnclMap %08x\n",
b_t >> 8, b_t & 255,
get32(SASDevicePage2[i].PhysicalIdentifier.High),
get32(SASDevicePage2[i].PhysicalIdentifier.Low),
get32(SASDevicePage2[i].EnclosureMapping));
}
fclose(file);
if (j)
printf("%d persistent entries saved\n", j);
else
printf("No persistent entries found\n");
}
}
else
{
printf("Persistent mappings won't be saved\n");
}
}
if (command == 8)
{
n = getFileName(name, sizeof name, stdin, "persistent mapping", 0);
if (n > 0)
{
if (readFile(name, &mappingBuf, &mappingLen) != 1)
return 0;
t = 0;
c = (char *)mappingBuf;
while (*c != '\0')
{
if (sscanf(c, "Bus %d Target %d is PhysId %8x%8x EnclMap %8x%n",
&bus, &target, &phys_id_h, &phys_id_l, &encl_map, &n) != 5)
{
printf("Incorrectly formatted file!\n");
break;
}
c += n;
while (*c == '\r' || *c == '\n')
c++;
b_t = (bus << 8) + target;
k = ~MPI_SASDEVICE2_ENC_MAP_MASK_MISSING_COUNT;
for (i = 0; i < j; i++)
{
if (i_to_b_t[i] == b_t &&
get32(SASDevicePage2[i].PhysicalIdentifier.High) == phys_id_h &&
get32(SASDevicePage2[i].PhysicalIdentifier.Low) == phys_id_l &&
(get32(SASDevicePage2[i].EnclosureMapping) & k) == (encl_map & k))
{
break;
}
if (i_to_b_t[i] == b_t)
{
printf("Bus %d Target %d is already valid with PhysId %08x%08x EnclMap %08x\n",
bus, target,
get32(SASDevicePage2[i].PhysicalIdentifier.High),
get32(SASDevicePage2[i].PhysicalIdentifier.Low),
get32(SASDevicePage2[i].EnclosureMapping));
warn = 1;
break;
}
if (get32(SASDevicePage2[i].PhysicalIdentifier.High) == phys_id_h &&
get32(SASDevicePage2[i].PhysicalIdentifier.Low) == phys_id_l &&
(get32(SASDevicePage2[i].EnclosureMapping) & k) == (encl_map & k))
{
printf("PhysId %08x%08x EnclMap %08x is already valid with Bus %d Target %d\n",
get32(SASDevicePage2[i].PhysicalIdentifier.High),
get32(SASDevicePage2[i].PhysicalIdentifier.Low),
get32(SASDevicePage2[i].EnclosureMapping),
i_to_b_t[i] >> 8, i_to_b_t[i] & 255);
warn = 1;
break;
}
}
if (i == j)
{
t++;
SASDevicePage2[j] = tempSASDevicePage2;
SASDevicePage2[j].PhysicalIdentifier.High = set32(phys_id_h);
SASDevicePage2[j].PhysicalIdentifier.Low = set32(phys_id_l);
SASDevicePage2[j].EnclosureMapping = set32(encl_map);
changed[j] = 1;
n_changed++;
i_to_b_t[j] = b_t;
j++;
}
}
if (t)
printf("%d persistent entries loaded\n", t);
else
printf("No persistent entries loaded\n");
if (warn)
printf("\nSome persistent mappings were not loaded; clear persistent entries first!\n");
free(mappingBuf);
}
else
{
printf("Persistent mappings won't be loaded\n");
}
}
if (n_changed != 0)
{
for (i = 0; i < j; i++)
{
if (changed[i])
{
if (setConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 2,
(MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
<<MPI_SAS_DEVICE_PGAD_FORM_SHIFT) + i_to_b_t[i],
&SASDevicePage2[i], sizeof *SASDevicePage2) != 1)
{
printf("Failed to save changes for persistent entry %d to NVRAM!\n", i);
// free(SASDevicePage2);
// free(changed);
// free(i_to_b_t);
// return 0;
}
}
}
}
free(SASDevicePage2);
free(changed);
free(i_to_b_t);
return 1;
}
int
doDisplayLoggedInDevices(MPT_PORT *port)
{
FCPortPage0_t FCPortPage0;
FCDevicePage0_t FCDevicePage0;
U32 s_id;
U32 d_id;
showPortInfoHeader(port);
printf(" B___T WWNN WWPN PortId\n");
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 0, 0,
&FCPortPage0, sizeof FCPortPage0) == 1)
s_id = get32(FCPortPage0.PortIdentifier);
else
s_id = 0xffffff;
d_id = 0xffffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_DEVICE, 0, d_id,
&FCDevicePage0, sizeof FCDevicePage0) != 1)
break;
d_id = get32(FCDevicePage0.PortIdentifier);
if (s_id == d_id)
{
s_id = 0xffffff;
}
else if (s_id < d_id)
{
printf(" %08x%08x %08x%08x %06x\n",
get32(FCPortPage0.WWNN.High), get32(FCPortPage0.WWNN.Low),
get32(FCPortPage0.WWPN.High), get32(FCPortPage0.WWPN.Low),
s_id);
s_id = 0xffffff;
}
if (FCDevicePage0.Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID)
{
printf("%2d %3d %08x%08x %08x%08x %06x\n",
FCDevicePage0.CurrentBus, FCDevicePage0.CurrentTargetID,
get32(FCDevicePage0.WWNN.High), get32(FCDevicePage0.WWNN.Low),
get32(FCDevicePage0.WWPN.High), get32(FCDevicePage0.WWPN.Low),
d_id);
}
else
{
printf(" %08x%08x %08x%08x %06x\n",
get32(FCDevicePage0.WWNN.High), get32(FCDevicePage0.WWNN.Low),
get32(FCDevicePage0.WWPN.High), get32(FCDevicePage0.WWPN.Low),
d_id);
}
}
if (s_id != 0xffffff)
printf(" %08x%08x %08x%08x %06x\n",
get32(FCPortPage0.WWNN.High), get32(FCPortPage0.WWNN.Low),
get32(FCPortPage0.WWPN.High), get32(FCPortPage0.WWPN.Low),
s_id);
return 1;
}
int
doDisplayAttachedDevices(MPT_PORT *port)
{
SasDevicePage0_t SASDevicePage0;
SasIOUnitPage0_t *SASIOUnitPage0;
Mpi2SasIOUnitPage0_t *SASIOUnitPage0_2;
SasIOUnit0PhyData *SASIOUnit0PhyData;
SasPhyPage0_t SASPhyPage0;
Mpi2SasPhyPage0_t SASPhyPage0_2;
SasExpanderPage0_t SASExpanderPage0;
SasExpanderPage1_t SASExpanderPage1;
SasEnclosurePage0_t SASEnclosurePage0;
int handle;
int bus;
int target;
int dev_info;
int flags;
int mapped;
int type;
int rate;
char info[80];
int length;
int i;
int n;
char *speed;
showPortInfoHeader(port);
printf(" B___T SASAddress PhyNum Handle Parent Type\n");
handle = 0xffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, handle,
&SASDevicePage0, sizeof SASDevicePage0) != 1)
break;
handle = get16(SASDevicePage0.DevHandle);
dev_info = get32(SASDevicePage0.DeviceInfo);
flags = get16(SASDevicePage0.Flags);
if (mpi1)
{
mapped = flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED;
bus = SASDevicePage0.Bus;
target = SASDevicePage0.TargetID;
}
else
{
mapped = mapDevHandleToBusTarget(port, handle, &bus, &target);
}
memset(info, 0, sizeof info);
type = dev_info & MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE;
if (type == MPI_SAS_DEVICE_INFO_EDGE_EXPANDER)
strcat(info, ", Edge Expander");
if (type == MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER)
strcat(info, ", FanOut Expander");
if (dev_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
if (dev_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
strcat(info, ", SAS Initiator and Target");
else
strcat(info, ", SAS Initiator");
else if (dev_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
strcat(info, ", SAS Target");
if (dev_info & MPI_SAS_DEVICE_INFO_SATA_HOST)
if (dev_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
strcat(info, ", SATA Initiator and Target");
else
strcat(info, ", SATA Initiator");
else if (dev_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
strcat(info, ", SATA Target");
if (dev_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
strcat(info, ", STP Target");
if (dev_info & MPI_SAS_DEVICE_INFO_ATAPI_DEVICE)
strcat(info, ", ATAPI");
if (!(flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT))
strcat(info, ", not present");
if (SASDevicePage0.ParentDevHandle == 0)
{
printf(" %08x%08x %04x %s\n",
get32(SASDevicePage0.SASAddress.High), get32(SASDevicePage0.SASAddress.Low),
handle,
info + 2);
}
else if (mapped)
{
printf("%2d %3d %08x%08x %2d %04x %04x %s\n",
bus, target,
get32(SASDevicePage0.SASAddress.High), get32(SASDevicePage0.SASAddress.Low),
SASDevicePage0.PhyNum, handle, get16(SASDevicePage0.ParentDevHandle),
info + 2);
}
else
{
printf(" %08x%08x %2d %04x %04x %s\n",
get32(SASDevicePage0.SASAddress.High), get32(SASDevicePage0.SASAddress.Low),
SASDevicePage0.PhyNum, handle, get16(SASDevicePage0.ParentDevHandle),
info + 2);
}
}
printf("\nType NumPhys PhyNum Handle PhyNum Handle Port Speed\n");
SASIOUnitPage0 = getConfigPageAlloc(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0, &length);
if (SASIOUnitPage0 == NULL)
return 0;
SASIOUnitPage0_2 = (pMpi2SasIOUnitPage0_t)SASIOUnitPage0;
printf("Adapter %2d", SASIOUnitPage0->NumPhys);
n = 0;
for (i = 0; i < SASIOUnitPage0->NumPhys; i++)
{
if (mpi2)
{
SASIOUnit0PhyData = (pSasIOUnit0PhyData)&SASIOUnitPage0_2->PhyData[i];
rate = (SASIOUnit0PhyData->NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_LOGICAL) >>
MPI2_SAS_NEG_LINK_RATE_SHIFT_LOGICAL;
}
else
{
SASIOUnit0PhyData = (pSasIOUnit0PhyData)&SASIOUnitPage0->PhyData[i];
rate = SASIOUnit0PhyData->NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL;
}
if (rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
rate == MPI_SAS_IOUNIT0_RATE_3_0 ||
rate == MPI2_SAS_NEG_LINK_RATE_6_0 ||
rate == MPI25_SAS_NEG_LINK_RATE_12_0)
{
if (mpi2)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, 0, i,
&SASPhyPage0_2, sizeof SASPhyPage0_2) != 1)
continue;
// convert from MPI 2.x format to MPI 1.x format (only a couple fields are needed)
SASPhyPage0.AttachedPhyIdentifier = SASPhyPage0_2.AttachedPhyIdentifier;
SASPhyPage0.AttachedDevHandle = SASPhyPage0_2.AttachedDevHandle;
}
else
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, 0, i,
&SASPhyPage0, sizeof SASPhyPage0) != 1)
continue;
}
if (rate == MPI_SAS_IOUNIT0_RATE_1_5)
speed = "1.5";
else if (rate == MPI_SAS_IOUNIT0_RATE_3_0)
speed = "3.0";
else if (rate == MPI2_SAS_NEG_LINK_RATE_6_0)
speed = "6.0";
else if (rate == MPI25_SAS_NEG_LINK_RATE_12_0)
speed = "12.0";
else
speed = "???";
if (n++)
printf(" ");
printf(" %2d %04x --> %2d %04x %2d %s\n",
i, get16(SASIOUnit0PhyData->ControllerDevHandle),
SASPhyPage0.AttachedPhyIdentifier,
get16(SASPhyPage0.AttachedDevHandle),
SASIOUnit0PhyData->Port, speed);
}
} //next phy
if (n == 0)
printf("\n");
free(SASIOUnitPage0);
handle = 0xffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, handle,
&SASExpanderPage0, sizeof SASExpanderPage0) != 1)
break;
handle = get16(SASExpanderPage0.DevHandle);
printf("\nExpander %2d", SASExpanderPage0.NumPhys);
n = 0;
for (i = 0; i < SASExpanderPage0.NumPhys; i++)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 1,
(MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM
<<MPI_SAS_EXPAND_PGAD_FORM_SHIFT) +
(i << MPI_SAS_EXPAND_PGAD_HPN_SHIFT_PHY) + handle,
&SASExpanderPage1, sizeof SASExpanderPage1) != 1)
continue;
// Don't report the expander's PHY if DeviceType == No Device (bits 2:0)
if((SASExpanderPage1.AttachedDeviceInfo & 0x07) == 0)
continue;
if (mpi2)
rate = (SASExpanderPage1.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_LOGICAL) >>
MPI2_SAS_NEG_LINK_RATE_SHIFT_LOGICAL;
else
rate = SASExpanderPage1.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL;
if (rate == MPI_SAS_EXPANDER1_NEG_RATE_1_5 ||
rate == MPI_SAS_EXPANDER1_NEG_RATE_3_0 ||
rate == MPI2_SAS_NEG_LINK_RATE_6_0 ||
rate == MPI25_SAS_NEG_LINK_RATE_12_0)
{
if (rate == MPI_SAS_IOUNIT0_RATE_1_5)
speed = "1.5";
else if (rate == MPI_SAS_EXPANDER1_NEG_RATE_3_0)
speed = "3.0";
else if (rate == MPI25_SAS_NEG_LINK_RATE_12_0)
speed = "12.0";
else
speed = "6.0";
if (n++)
printf(" ");
printf(" %2d %04x --> %2d %04x %2d %s\n",
i, handle,
SASExpanderPage1.AttachedPhyIdentifier,
get16(SASExpanderPage1.AttachedDevHandle),
SASExpanderPage1.PhysicalPort, speed);
}
}
if (n == 0)
printf("\n");
}
printf("\nEnclosure Handle Slots SASAddress B___T (SEP)\n");
handle = 0xffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_ENCLOSURE, 0, handle,
&SASEnclosurePage0, sizeof SASEnclosurePage0) != 1)
break;
handle = get16(SASEnclosurePage0.EnclosureHandle);
flags = get16(SASEnclosurePage0.Flags);
if (handle == 1)
{
mapped = 0;
}
else if (mpi1)
{
mapped = flags & MPI_SAS_ENCLS0_FLAGS_SEP_BUS_ID_VALID;
bus = SASEnclosurePage0.SEPBus;
target = SASEnclosurePage0.SEPTargetID;
}
else
{
Mpi2SasEnclosurePage0_t *SASEnclosurePage0_2;
int handle;
SASEnclosurePage0_2 = (pMpi2SasEnclosurePage0_t)&SASEnclosurePage0;
handle = get16(SASEnclosurePage0_2->SEPDevHandle);
mapped = mapDevHandleToBusTarget(port, handle, &bus, &target);
}
if (mapped)
{
printf(" %04x %5d %08x%08x %2d %3d\n",
handle, get16(SASEnclosurePage0.NumSlots),
get32(SASEnclosurePage0.EnclosureLogicalID.High),
get32(SASEnclosurePage0.EnclosureLogicalID.Low),
bus, target);
}
else
{
printf(" %04x %5d %08x%08x\n",
handle, get16(SASEnclosurePage0.NumSlots),
get32(SASEnclosurePage0.EnclosureLogicalID.High),
get32(SASEnclosurePage0.EnclosureLogicalID.Low));
}
}
return 1;
}
int
showSasDiscoveryErrors(MPT_PORT *port)
{
SasIOUnitPage0_t *SASIOUnitPage0;
Mpi2SasIOUnitPage0_t *SASIOUnitPage0_2;
SasIOUnit0PhyData *SASIOUnit0PhyData;
SasExpanderPage0_t SASExpanderPage0;
Mpi2ExpanderPage0_t *SASExpanderPage0_2;
int handle;
int length;
int i;
int n;
int t;
int disc_stat;
n = 0;
SASIOUnitPage0 = getConfigPageAlloc(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0, &length);
if (SASIOUnitPage0 == NULL)
return 0;
SASIOUnitPage0_2 = (pMpi2SasIOUnitPage0_t)SASIOUnitPage0;
for (i = 0; i < SASIOUnitPage0->NumPhys; i++)
{
if (mpi2)
SASIOUnit0PhyData = (pSasIOUnit0PhyData)&SASIOUnitPage0_2->PhyData[i];
else
SASIOUnit0PhyData = (pSasIOUnit0PhyData)&SASIOUnitPage0->PhyData[i];
if (SASIOUnit0PhyData->PortFlags & MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS)
{
if (n++)
printf("\n");
printf("Discovery is in progress for adapter phy %d!\n", i);
}
disc_stat = get32(SASIOUnit0PhyData->DiscoveryStatus);
if (disc_stat)
{
if (n++)
printf("\n");
printf("Discovery errors for adapter phy %d:\n", i);
if (mpi1)
{
if (disc_stat & MPI_SAS_IOUNIT0_DS_LOOP_DETECTED)
printf(" Loop detected\n");
if (disc_stat & MPI_SAS_IOUNIT0_DS_UNADDRESSABLE_DEVICE)
printf(" Unaddressable device detected\n");
if (disc_stat & MPI_SAS_IOUNIT0_DS_MULTIPLE_PORTS)
printf(" Multiple ports with same SAS address detected\n");
if (disc_stat & MPI_SAS_IOUNIT0_DS_EXPANDER_ERR)
printf(" Expander error\n");
if (disc_stat & MPI_SAS_IOUNIT0_DS_SMP_TIMEOUT)
printf(" SMP timeout\n");
if (disc_stat & MPI_SAS_IOUNIT0_DS_OUT_ROUTE_ENTRIES)
printf(" Expander route table out of entries\n");
if (disc_stat & MPI_SAS_IOUNIT0_DS_INDEX_NOT_EXIST)
printf(" Route table index does not exist\n");
if (disc_stat & MPI_SAS_IOUNIT0_DS_SMP_FUNCTION_FAILED)
printf(" SMP function failed\n");
if (disc_stat & MPI_SAS_IOUNIT0_DS_SMP_CRC_ERROR)
printf(" SMP CRC error\n");
if (disc_stat & MPI_SAS_IOUNIT0_DS_SUBTRACTIVE_LINK)
printf(" Subtractive-to-subtractive link detected\n");
if (disc_stat & MPI_SAS_IOUNIT0_DS_TABLE_LINK)
printf(" Table-to-table link detected\n");
if (disc_stat & MPI_SAS_IOUNIT0_DS_UNSUPPORTED_DEVICE)
printf(" Unsupported device detected\n");
if (disc_stat & MPI_SAS_IOUNIT0_DS_MAX_SATA_TARGETS)
printf(" Maximum number of supported SATA targets reached\n");
if (disc_stat & MPI_SAS_IOUNIT0_DS_MULTI_PORT_DOMAIN)
printf(" Multiple ports attached to the same domain\n");
}
else
{
if (disc_stat & MPI2_SASIOUNIT0_DS_MAX_ENCLOSURES_EXCEED)
printf(" Maximum number of enclosures exceeded\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_MAX_EXPANDERS_EXCEED)
printf(" Maximum number of expanders exceeded\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_MAX_DEVICES_EXCEED)
printf(" Maximum number of devices exceeded\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_MAX_TOPO_PHYS_EXCEED)
printf(" Maximum number of phys exceeded\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_DOWNSTREAM_INITIATOR )
printf(" Downstream initiator detected in simplified routing mode\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE )
printf(" Multiple subtractive-to-subtractive ports detected\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_EXP_MULTI_SUBTRACTIVE )
printf(" Multiple subtractive ports within an expander detected\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_MULTI_PORT_DOMAIN)
printf(" Multiple ports attached to the same domain\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_TABLE_TO_SUBTRACTIVE_LINK)
printf(" Table-to-subtractive link detected\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_UNSUPPORTED_DEVICE)
printf(" Unsupported device detected\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_TABLE_LINK)
printf(" Table-to-table link detected\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_SUBTRACTIVE_LINK)
printf(" Subtractive-to-subtractive link detected\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_SMP_CRC_ERROR)
printf(" SMP CRC error\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_SMP_FUNCTION_FAILED)
printf(" SMP function failed\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_INDEX_NOT_EXIST)
printf(" Route table index does not exist\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_OUT_ROUTE_ENTRIES)
printf(" Expander route table out of entries\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_SMP_TIMEOUT)
printf(" SMP timeout\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_MULTIPLE_PORTS)
printf(" Multiple ports with same SAS address detected\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_UNADDRESSABLE_DEVICE)
printf(" Unaddressable device detected\n");
if (disc_stat & MPI2_SASIOUNIT0_DS_LOOP_DETECTED)
printf(" Loop detected\n");
}
}
}
free(SASIOUnitPage0);
handle = 0xffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, handle,
&SASExpanderPage0, sizeof SASExpanderPage0) != 1)
break;
handle = get16(SASExpanderPage0.DevHandle);
if (mpi2)
{
SASExpanderPage0_2 = (pMpi2ExpanderPage0_t)&SASExpanderPage0;
t = get16(SASExpanderPage0_2->Flags) & MPI2_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS;
}
else
{
t = SASExpanderPage0.Flags & MPI2_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS;
}
if (t)
{
if (n++)
printf("\n");
printf("Configuration is in progress for expander %04x!\n", handle);
}
disc_stat = get32(SASExpanderPage0.DiscoveryStatus);
if (disc_stat)
{
if (n++)
printf("\n");
printf("Discovery errors for expander %04x:\n", handle);
if (mpi1)
{
if (disc_stat & MPI_SAS_EXPANDER0_DS_LOOP_DETECTED)
printf(" Loop detected\n");
if (disc_stat & MPI_SAS_EXPANDER0_DS_UNADDRESSABLE_DEVICE)
printf(" Unaddressable device detected\n");
if (disc_stat & MPI_SAS_EXPANDER0_DS_MULTIPLE_PORTS)
printf(" Multiple ports with same SAS address detected\n");
if (disc_stat & MPI_SAS_EXPANDER0_DS_EXPANDER_ERR)
printf(" Expander error\n");
if (disc_stat & MPI_SAS_EXPANDER0_DS_SMP_TIMEOUT)
printf(" SMP timeout\n");
if (disc_stat & MPI_SAS_EXPANDER0_DS_OUT_ROUTE_ENTRIES)
printf(" Expander route table out of entries\n");
if (disc_stat & MPI_SAS_EXPANDER0_DS_INDEX_NOT_EXIST)
printf(" Route table index does not exist\n");
if (disc_stat & MPI_SAS_EXPANDER0_DS_SMP_FUNCTION_FAILED)
printf(" SMP function failed\n");
if (disc_stat & MPI_SAS_EXPANDER0_DS_SMP_CRC_ERROR)
printf(" SMP CRC error\n");
if (disc_stat & MPI_SAS_EXPANDER0_DS_SUBTRACTIVE_LINK)
printf(" Subtractive-to-subtractive link detected\n");
if (disc_stat & MPI_SAS_EXPANDER0_DS_TABLE_LINK)
printf(" Table-to-table link detected\n");
if (disc_stat & MPI_SAS_EXPANDER0_DS_UNSUPPORTED_DEVICE)
printf(" Unsupported device detected\n");
}
else
{
if (disc_stat & MPI2_SAS_EXPANDER0_DS_MAX_ENCLOSURES_EXCEED)
printf(" Maximum number of enclosures exceeded\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_MAX_EXPANDERS_EXCEED)
printf(" Maximum number of expanders exceeded\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_MAX_DEVICES_EXCEED)
printf(" Maximum number of devices exceeded\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_MAX_TOPO_PHYS_EXCEED)
printf(" Maximum number of phys exceeded\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_DOWNSTREAM_INITIATOR)
printf(" Downstream initiator detected in simplified routing mode\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE )
printf(" Multiple subtractive-to-subtractive ports detected\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_EXP_MULTI_SUBTRACTIVE )
printf(" Multiple subtractive ports within an expander detected\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_MULTI_PORT_DOMAIN)
printf(" Multiple ports attached to the same domain\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_TABLE_TO_SUBTRACTIVE_LINK)
printf(" Table-to-subtractive link detected\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_UNSUPPORTED_DEVICE)
printf(" Unsupported device detected\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_TABLE_LINK)
printf(" Table-to-table link detected\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_SUBTRACTIVE_LINK)
printf(" Subtractive-to-subtractive link detected\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_SMP_CRC_ERROR)
printf(" SMP CRC error\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_SMP_FUNCTION_FAILED)
printf(" SMP function failed\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_INDEX_NOT_EXIST)
printf(" Route table index does not exist\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_OUT_ROUTE_ENTRIES)
printf(" Expander route table out of entries\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_SMP_TIMEOUT)
printf(" SMP timeout\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_MULTIPLE_PORTS)
printf(" Multiple ports with same SAS address detected\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_UNADDRESSABLE_DEVICE)
printf(" Unaddressable device detected\n");
if (disc_stat & MPI2_SAS_EXPANDER0_DS_LOOP_DETECTED)
printf(" Loop detected\n");
}
}
}
if (n == 0)
printf("No discovery errors found\n");
return 1;
}
int
doShowPortAliases(MPT_PORT *port)
{
FCPortPage0_t FCPortPage0;
FCPortPage1_t FCPortPage1;
FCPortPage5_t FCPortPage5;
int i;
if (bringOnline(port) != 1)
return 0;
if (getConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, MPI_CONFIG_PAGETYPE_FC_PORT, 0, 0, &FCPortPage0, sizeof FCPortPage0) != 1)
return 0;
if (getConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
return 0;
if (FCPortPage0.MaxAliasesSupported == 0)
{
printf("Aliases are not supported on this port\n");
return 1;
}
printf("%d aliases requested, %d aliases active\n", FCPortPage1.NumRequestedAliases, FCPortPage0.NumCurrentAliases);
if (FCPortPage1.NumRequestedAliases == 0)
return 1;
printf("\n WWNN WWPN PortId Flags\n");
for (i = 1; i <= FCPortPage1.NumRequestedAliases; i++)
{
if (getConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, MPI_CONFIG_PAGETYPE_FC_PORT, 5,
MPI_FC_PORT_PGAD_FORM_INDEX + i, &FCPortPage5, sizeof FCPortPage5) != 1)
continue;
printf("%3d %08x%08x %08x%08x %04x%02x %02x (%s%s)\n", i,
get32(FCPortPage5.AliasInfo.AliasWWNN.High), get32(FCPortPage5.AliasInfo.AliasWWNN.Low),
get32(FCPortPage5.AliasInfo.AliasWWPN.High), get32(FCPortPage5.AliasInfo.AliasWWPN.Low),
get16(FCPortPage5.AliasInfo.DomainArea),
FCPortPage5.AliasInfo.AliasAlpa,
FCPortPage5.AliasInfo.Flags,
(FCPortPage5.AliasInfo.Flags & MPI_FCPORTPAGE5_FLAGS_DISABLE) ? "Disabled, " : "",
(FCPortPage5.AliasInfo.Flags & MPI_FCPORTPAGE5_FLAGS_ALPA_ACQUIRED) ? "Active" : "Inactive");
}
return 1;
}
int
doShowExpanderRoutingTables(MPT_PORT *port)
{
SasExpanderPage0_t SASExpanderPage0;
SasExpanderPage1_t SASExpanderPage1;
Mpi2ExpanderPage0_t *SASExpanderPage0_2;
int exp_handle;
int handle;
int phy_info;
int i;
int j;
int t;
int flags;
int route_table_config;
int n1;
int n2;
unsigned char report_route_information_req[12];
unsigned char report_route_information_rsp[40];
unsigned char report_expander_route_table_req[28];
unsigned char report_expander_route_table_rsp[48];
U32 wwid_l = 0;
U32 wwid_h = 0;
char types[49];
if (bringOnline(port) != 1)
return 0;
if (gFlag == TRUE)
{
printf("Enter expander handle: [0000-FFFF or RETURN for all expanders] ");
exp_handle = getNumberAnswerHex(0x0000, 0xffff, -1);
printf("\n");
}
else
exp_handle = -1;
memset(report_route_information_req, 0, sizeof report_route_information_req);
report_route_information_req[0] = 0x40;
report_route_information_req[1] = 0x13;
report_route_information_req[2] = 0xff;
memset(report_expander_route_table_req, 0, sizeof report_expander_route_table_req);
report_expander_route_table_req[0] = 0x40;
// report_expander_route_table_req[1] =
report_expander_route_table_req[2] = 0xff;
report_expander_route_table_req[3] = 6;
report_expander_route_table_req[9] = 1;
n1 = 0;
handle = 0xffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, handle,
&SASExpanderPage0, sizeof SASExpanderPage0) != 1)
break;
handle = get16(SASExpanderPage0.DevHandle);
if (exp_handle >= 0 && exp_handle != handle)
continue;
if (n1++)
printf("\n");
for (i = 0; i < SASExpanderPage0.NumPhys; i++)
{
if (i >= sizeof types - 1)
break;
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 1,
(MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM
<<MPI_SAS_EXPAND_PGAD_FORM_SHIFT) +
(i << MPI_SAS_EXPAND_PGAD_HPN_SHIFT_PHY) + handle,
&SASExpanderPage1, sizeof SASExpanderPage1) != 1)
{
types[i] = '?';
continue;
}
phy_info = get32(SASExpanderPage1.PhyInfo);
/* if the discovery returned PHY_VACANT, the phy_info is invalid.
* some versions of fw do not set the PHYINFO_PHY_VACANT bit in this
* case, so look for the entire rest of the field being 0 as a
* workaround.
*/
if (((phy_info & ~MPI2_SAS_PHYINFO_PHY_VACANT) == 0) || (phy_info & MPI2_SAS_PHYINFO_PHY_VACANT))
types[i] = 'V';
else
{
switch (phy_info & MPI_SAS_PHY0_PHYINFO_MASK_ROUTING_ATTRIBUTE)
{
case MPI_SAS_PHY0_PHYINFO_DIRECT_ROUTING:
types[i] = 'D';
break;
case MPI_SAS_PHY0_PHYINFO_SUBTRACTIVE_ROUTING:
types[i] = 'S';
break;
case MPI_SAS_PHY0_PHYINFO_TABLE_ROUTING:
types[i] = 'T';
break;
default:
types[i] = 'U';
break;
}
}
}
types[i] = '\0';
printf("Handle %04x, %d Phys, Types %s\n", handle, i, types);
if (mpi2)
{
SASExpanderPage0_2 = (pMpi2ExpanderPage0_t)&SASExpanderPage0;
flags = get16(SASExpanderPage0_2->Flags);
route_table_config = flags & MPI2_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG;
}
else
{
flags = SASExpanderPage0.Flags;
route_table_config = flags & MPI_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG;
}
if (route_table_config)
{
printf("Sending Report Route Information\n");
n2 = 0;
for (i = 0; i < SASExpanderPage0.NumPhys; i++)
{
if (types[i] == 'T')
{
report_route_information_req[9] = i;
for (j = 0; j < get16(SASExpanderPage0.ExpanderRouteIndexes); j++)
{
report_route_information_req[6] = j >> 8;
report_route_information_req[7] = j;
if (doSmpPassthrough(port, SASExpanderPage0.PhysicalPort, SASExpanderPage0.SASAddress,
report_route_information_req, sizeof report_route_information_req,
report_route_information_rsp, sizeof report_route_information_rsp, NULL) == 1)
{
if (report_route_information_rsp[2] == 0x01)
break;
if (report_route_information_rsp[2] == 0x11)
break;
if (report_route_information_rsp[2] != 0)
{
printf("Report Route Information failed with result %02x\n",
report_route_information_rsp[2]);
continue;
}
if (report_route_information_rsp[12] & 0x80)
continue;
wwid_h = get4bytes(report_route_information_rsp, 16);
wwid_l = get4bytes(report_route_information_rsp, 20);
if (n2++ == 0)
printf("Phy Index SASAddress\n");
printf("%3d %5d %08x%08x\n", i, j, wwid_h, wwid_l);
}
else
{
printf("Report Route Information failed!\n");
break;
}
}
}
}
}
else
{
n2 = 0;
printf("Sending Report Expander Route Table\n");
report_expander_route_table_req[1] = 0x22;
for (j = 0; j < 65536; j++)
{
report_expander_route_table_req[10] = j >> 8;
report_expander_route_table_req[11] = j;
t = doSmpPassthrough(port, SASExpanderPage0.PhysicalPort, SASExpanderPage0.SASAddress,
report_expander_route_table_req, sizeof report_expander_route_table_req,
report_expander_route_table_rsp, sizeof report_expander_route_table_rsp, NULL);
if (t == 1)
{
if (report_expander_route_table_rsp[2] == 0x01 && j == 0)
{
report_expander_route_table_req[1] = 0x17;
t = doSmpPassthrough(port, SASExpanderPage0.PhysicalPort, SASExpanderPage0.SASAddress,
report_expander_route_table_req, sizeof report_expander_route_table_req,
report_expander_route_table_rsp, sizeof report_expander_route_table_rsp, NULL);
}
}
if (t == 1)
{
if (report_expander_route_table_rsp[2] == 0x01)
break;
if (report_expander_route_table_rsp[2] == 0x11)
break;
if (report_expander_route_table_rsp[2] != 0)
{
printf("Report Expander Route Table failed with result %02x\n",
report_expander_route_table_rsp[2]);
continue;
}
if (report_expander_route_table_rsp[11] == 0)
break;
j = get2bytes(report_expander_route_table_rsp, 12);
wwid_h = get4bytes(report_expander_route_table_rsp, 32);
wwid_l = get4bytes(report_expander_route_table_rsp, 36);
if (n2++ == 0)
printf("Index SASAddress Zone Phy Bitmask\n");
printf("%5d %08x%08x ", j, wwid_h, wwid_l);
if (report_expander_route_table_rsp[46] & 0x80)
printf(" %3d ", report_expander_route_table_rsp[47]);
else
printf(" ");
for (i = 40; i < 46; i++)
printf("%02x", report_expander_route_table_rsp[i]);
printf("\n");
}
else
{
printf("Report Expander Route Table failed!\n");
break;
}
}
}
}
if (n1 == 0)
{
if (exp_handle < 0)
printf("No expanders found\n");
else
printf("Expander %04x not found\n", exp_handle);
}
return 1;
}
int
doTestConfigPageActions(MPT_PORT *port)
{
Config_t req;
ConfigReply_t rep;
char name[256];
FILE *in_file;
FILE *out_file;
char str[80];
char act[80];
U32 buf[256];
int action;
int type;
int number;
int length;
int ioc_status;
U32 address;
U32 offset;
U32 value;
int i;
int j;
int n;
int t;
char *action_string[7] = {"H", "RC", "WC", "D", "WN", "RD", "RN"};
printf("Enter input file, or RETURN to enter commands interactively: ");
n = getString(name, sizeof name, stdin);
if (n > 0)
{
in_file = fopen(name, "r");
if (in_file == NULL)
{
printf("Open failure for file %s\n", name);
perror("Error is");
return 0;
}
}
else
{
in_file = stdin;
}
printf("Enter output file, or RETURN to send output to the screen: ");
n = getString(name, sizeof name, stdin);
if (n > 0)
{
out_file = fopen(name, "w");
if (out_file == NULL)
{
printf("Open failure for file %s\n", name);
perror("Error is");
if (in_file != stdin)
fclose(in_file);
return 0;
}
}
else
{
out_file = stdout;
}
while (TRUE)
{
while (TRUE)
{
if (in_file == stdin)
{
printf("\nEnter command, or ? for help, or RETURN to quit: ");
n = getString(str, sizeof str, stdin);
lines = 0;
}
else
{
if (fgets(str, sizeof str, in_file) == NULL)
{
n = 0;
}
else
{
str[sizeof str - 1] = '\0';
n = (int)strlen(str);
if (n >= 1 && str[n-1] == '\n')
{
str[n-1] = '\0';
n -= 1;
}
if (n == 0)
continue;
printf("Executing \"%s\"...\n", str);
}
}
if (n == 0)
{
if (in_file != stdin)
fclose(in_file);
if (out_file != stdout)
fclose(out_file);
return 1;
}
act[0] = '\0';
type = 0;
number = 0;
address = 0;
i = sscanf(str, "%s %d %d %x%n\n", act, &type, &number, &address, &j);
if (i >= 4 && j < n && str[j] != ' ')
i = 0;
if (i >= 3)
{
if (sscanf(act, "%d", &action) == 1)
;
else if (strcasecmp(act, "h") == 0)
action = 0;
else if (strcasecmp(act, "rc") == 0)
action = 1;
else if (strcasecmp(act, "wc") == 0)
action = 2;
else if (strcasecmp(act, "d") == 0)
action = 3;
else if (strcasecmp(act, "wn") == 0)
action = 4;
else if (strcasecmp(act, "rd") == 0)
action = 5;
else if (strcasecmp(act, "rn") == 0)
action = 6;
else if (strcasecmp(act, "rdwn") == 0)
action = 5;
else
action = -1;
if (action >= 0 && action <= 6 &&
type >= 0 && type <= 255 && type != 15 &&
number >= 0 && number <= 255)
{
break;
}
}
if (in_file == stdin)
{
if (n != 1 || str[0] != '?')
printf("\nInvalid response!\n");
printf("\nValid input is: <Action> <PageType> <PageNumber> [<PageAddress>]\n");
printf(" Action is:\n");
printf(" 0 or H display page Header only\n");
printf(" 1 or RC display page after Read Current\n");
printf(" 2 or WC enter page and do Write Current\n");
printf(" 3 or D set current page to Default values\n");
printf(" 4 or WN enter page and do Write NVRAM\n");
printf(" 5 or RD display page after Read Default\n");
printf(" 6 or RN display page after Read NVRAM\n");
printf(" RDWN do Read Default then Write NVRAM\n");
printf(" PageType is a decimal number beteen 0 and 255, but not 15\n");
printf(" PageNumber is a decimal number between 0 and 255\n");
printf(" PageAddress is an optional hex number\n");
}
}
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_CONFIG;
req.AliasIndex = virtInit;
req.Action = MPI_CONFIG_ACTION_PAGE_HEADER;
if (type > MPI_CONFIG_PAGETYPE_EXTENDED)
{
req.Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
req.ExtPageType = type;
}
else
{
req.Header.PageType = type;
}
req.Header.PageNumber = number;
req.PageAddress = set32(address);
if (doMptCommand(port, &req, sizeof req - sizeof req.PageBufferSGE, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
{
printf("\nFailed to get Header for page %d/%d/%x\n", type, number, address);
continue;
}
if (action == 0)
{
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
fprintf(out_file, "\n%s %d %d %x -- IOCStatus = %04x (%s)\n",
action_string[action], type, number, address,
ioc_status, translateIocStatus(ioc_status));
if (ioc_status == MPI_IOCSTATUS_SUCCESS)
{
fprintf(out_file, "0000 : %08x\n", get32x(*(U32 *)&rep.Header));
if (type > MPI_CONFIG_PAGETYPE_EXTENDED)
fprintf(out_file, "0004 : 00%02x%04x\n", rep.ExtPageType, get16(rep.ExtPageLength));
}
}
if (action == 1 || action == 5 || action == 6)
{
req.Action = action;
req.ExtPageType = rep.ExtPageType;
req.ExtPageLength = rep.ExtPageLength;
req.Header = rep.Header;
if (doMptCommand(port, &req, sizeof req - sizeof req.PageBufferSGE, &rep, sizeof rep,
buf, sizeof buf, NULL, 0, SHORT_TIME) != 1)
{
printf("\nFailed to read page %d/%d/%x\n", type, number, address);
continue;
}
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
fprintf(out_file, "\n%s %d %d %x -- IOCStatus = %04x (%s)\n",
action_string[action], type, number, address,
ioc_status, translateIocStatus(ioc_status));
if (ioc_status == MPI_IOCSTATUS_SUCCESS)
{
if (type > MPI_CONFIG_PAGETYPE_EXTENDED)
n = get16(rep.ExtPageLength);
else
n = rep.Header.PageLength;
for (i = 0; i < n; i++)
fprintf(out_file, "%04x : %08x\n", i*4, get32x(buf[i]));
}
}
if (action == 2 || action == 4)
{
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status == MPI_IOCSTATUS_SUCCESS)
{
if (type > MPI_CONFIG_PAGETYPE_EXTENDED)
length = get16(rep.ExtPageLength) * 4;
else
length = rep.Header.PageLength * 4;
}
else
length = sizeof buf;
memset (buf, 0, sizeof buf);
((pConfigPageHeader_t)buf)->PageVersion = rep.Header.PageVersion;
((pConfigPageHeader_t)buf)->PageLength = rep.Header.PageLength;
((pConfigPageHeader_t)buf)->PageNumber = rep.Header.PageNumber;
((pConfigPageHeader_t)buf)->PageType = rep.Header.PageType;
if (type > MPI_CONFIG_PAGETYPE_EXTENDED)
{
((pConfigExtendedPageHeader_t)buf)->ExtPageLength = rep.ExtPageLength;
((pConfigExtendedPageHeader_t)buf)->ExtPageType = rep.ExtPageType;
t = 8;
}
else
t = 4;
while (TRUE)
{
if (in_file == stdin)
{
printf("Enter offset (%04x) and value, or ? for help, or RETURN to quit: ", t);
n = getString(str, sizeof str, stdin);
lines = 0;
}
else
{
if (fgets(str, sizeof str, in_file) == NULL)
{
n = 0;
}
else
{
str[sizeof str - 1] = '\0';
n = (int)strlen(str);
if (n >= 1 && str[n-1] == '\n')
{
str[n-1] = '\0';
n -= 1;
}
}
}
if (n == 0)
break;
offset = 0;
value = 0;
i = sscanf(str, "%x : %x%n\n", &offset, &value, &j);
if (i == 1 && strchr(str, ':') == NULL)
{
i = sscanf(str, "%x %x%n\n", &offset, &value, &j);
if (i == 1 && strchr(str, ' ') == NULL)
{
offset = t;
sscanf(str, "%x%n", &value, &j);
i = 2;
}
}
if (i == 2 && j == n)
{
if (offset < (U32)length && (offset % 4) == 0)
{
buf[offset / 4] = value;
t = offset + 4;
if (t == length)
break;
continue;
}
}
if (in_file == stdin)
{
if (n != 1 || str[0] != '?')
printf("\nInvalid response!\n");
printf("\nValid input is: [<Offset> [:]] <Value>\n");
printf(" Offset is an optional hex number between 0000 and %04x (multiple of 4 only)\n", length - 4);
printf(" Value is a hex number\n\n");
}
}
}
if (strcasecmp(act, "rdwn") == 0)
action = 4;
if (action == 2 || action == 3 || action == 4)
{
req.Action = action;
req.ExtPageType = rep.ExtPageType;
req.ExtPageLength = rep.ExtPageLength;
req.Header = rep.Header;
if (action != 3 && type == MPI_CONFIG_PAGETYPE_MANUFACTURING && number == 2)
{
U8 checksum = 0xa5;
U8 *p = (U8 *)buf;
p += 8;
t = n * 4 - 8;
switch (port->deviceId)
{
case MPI_MANUFACTPAGE_DEVICEID_FC919: t -= 4; break;
case MPI_MANUFACTPAGE_DEVICEID_FC929: t -= 4; break;
case MPI_MANUFACTPAGE_DEVICEID_FC919X: t -= 3; break;
case MPI_MANUFACTPAGE_DEVICEID_FC929X: t -= 3; break;
case MPI_MANUFACTPAGE_DEVICEID_FC939X: t -= 3; break;
case MPI_MANUFACTPAGE_DEVICEID_FC949X: t -= 3; break;
case MPI_MANUFACTPAGE_DEVICEID_FC949E: t -= 4; break;
default: t = 0; break;
}
if (t != 0)
{
for (i = 0; i < t; i++)
{
checksum += *p++;
}
*p = -checksum;
}
}
if (type == MPI_CONFIG_PAGETYPE_MANUFACTURING)
doIocInit(port, MPI_WHOINIT_MANUFACTURER);
if (doMptCommand(port, &req, sizeof req - sizeof req.PageBufferSGE, &rep, sizeof rep,
NULL, 0, buf, sizeof buf, SHORT_TIME) != 1)
{
if (type == MPI_CONFIG_PAGETYPE_MANUFACTURING)
doIocInit(port, port->whoInit);
printf("\nFailed to write page %d/%d/%x\n", type, number, address);
continue;
}
if (type == MPI_CONFIG_PAGETYPE_MANUFACTURING)
doIocInit(port, port->whoInit);
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
fprintf(out_file, "\n%s %d %d %x -- IOCStatus = %04x (%s)\n",
action_string[action], type, number, address,
ioc_status, translateIocStatus(ioc_status));
}
}
}
int
selectDevice(MPT_PORT *port, int *dev_bus, int *dev_target)
{
int bus;
int target;
unsigned char inq[36];
int i;
int n;
if (kFlag == TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 0;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 0;
*dev_bus = bus;
*dev_target = target;
return 1;
}
showPortInfoHeader(port);
printf(" B___T Type Vendor Product Rev\n");
n = 0;
for (bus = 0; bus < port->maxBuses; bus++)
{
for (target = port->minTargets; target < port->maxTargets; target++)
{
if (doInquiry(port, bus, target, 0, inq, sizeof inq) != 1)
{
#if __linux__ || DOS || EFI
if (errno == EFAULT)
return 0;
#endif
continue;
}
if ((inq[0] & 0x1f) == 0x1f)
continue;
if ((inq[0] & 0xe0) == 0x20)
continue;
if ((inq[0] & 0xe0) == 0x60)
continue;
for (i = 8; i < 36; i++)
if (!isprint(inq[i]))
inq[i] = ' ';
diag_targets[n].bus = bus;
diag_targets[n].target = target;
n++;
printf("%2d. %2d %3d %-9s %-8.8s %-16.16s %-4.4s\n",
n, bus, target, deviceType[inq[0] & 0x1f],
inq+8, inq+16, inq+32);
if (n == MAX_DEVICES)
break;
}
if (n == MAX_DEVICES)
break;
}
if (n == 0)
{
printf("\nNo devices are available for this test\n");
return 0;
}
printf("\nSelect a device: [1-%d or RETURN to quit] ", n);
n = getNumberAnswer(1, n, 0);
if (n == 0)
return 0;
n--;
bus = diag_targets[n].bus;
target = diag_targets[n].target;
*dev_bus = bus;
*dev_target = target;
return 1;
}
int
selectDeviceRWMedia(MPT_PORT *port)
{
int bus;
int target;
int lun;
unsigned char inq[36];
unsigned char cap[8];
unsigned char cap16[32];
int i;
int n;
unsigned int mode;
unsigned int size;
int eedp;
if (kFlag == TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 0;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 0;
printf("LUN: [0-%d or RETURN to quit] ", port->maxLuns - 1);
lun = getNumberAnswer(0, port->maxLuns - 1, -1);
if (lun < 0)
return 0;
if (doInquiry(port, bus, target, lun, inq, sizeof inq) != 1)
return 0;
if (doReadCapacity(port, bus, target, lun, cap, sizeof cap) != 1)
return 0;
mode = get4bytes(cap, 4);
size = get4bytes(cap, 0);
eedp = 0;
if (mode == 512 && (inq[5] & 1))
{
if (doReadCapacity16(port, bus, target, lun, cap16, sizeof cap16) == 1)
{
if (cap16[12] && 1)
{
mode = 520;
eedp = 1;
}
}
}
else if (mode == 520)
{
eedp = 2;
}
diag_targets[0].bus = bus;
diag_targets[0].target = target;
diag_targets[0].lun = lun;
diag_targets[0].mode = mode;
diag_targets[0].size = size;
diag_targets[0].eedp = eedp;
return 1;
}
showPortInfoHeader(port);
printf(" B___T___L Type Vendor Product Rev Mode Disk Blocks\n");
n = 0;
for (bus = 0; bus < port->maxBuses; bus++)
{
for (target = port->minTargets; target < port->maxTargets; target++)
{
for (lun = 0; lun < port->maxLuns; lun++)
{
if (doInquiry(port, bus, target, lun, inq, sizeof inq) != 1)
{
#if __linux__ || DOS || EFI
if (errno == EFAULT)
return 0;
#endif
if (lun == 0)
break;
else
continue;
}
if ((inq[0] & 0x1f) != 0x00)
continue;
if ((inq[0] & 0xe0) == 0x20)
continue;
if ((inq[0] & 0xe0) == 0x60)
continue;
for (i = 8; i < 36; i++)
if (!isprint(inq[i]))
inq[i] = ' ';
if (doReadCapacity(port, bus, target, lun, cap, sizeof cap) != 1)
continue;
mode = get4bytes(cap, 4);
size = get4bytes(cap, 0);
eedp = 0;
if (mode == 512 && (inq[5] & 1))
{
if (doReadCapacity16(port, bus, target, lun, cap16, sizeof cap16) == 1)
{
if (cap16[12] && 1)
{
mode = 520;
eedp = 1;
}
}
}
else if (mode == 520)
{
eedp = 2;
}
diag_targets[n].bus = bus;
diag_targets[n].target = target;
diag_targets[n].lun = lun;
diag_targets[n].mode = mode;
diag_targets[n].size = size;
diag_targets[n].eedp = eedp;
n++;
printf("%2d. %2d %3d %3d %-9s %-8.8s %-16.16s %-4.4s %4d %10d\n",
n, bus, target, lun, deviceType[inq[0] & 0x1f],
inq+8, inq+16, inq+32, mode, size + 1);
if (n == MAX_DEVICES)
break;
}
if (n == MAX_DEVICES)
break;
}
if (n == MAX_DEVICES)
break;
}
if (n == 0)
{
printf("\nNo devices are available for this test\n");
return 0;
}
printf("\nSelect a device: [1-%d or RETURN to quit] ", n);
n = getNumberAnswer(1, n, 0);
return n;
}
int
selectDeviceRWBuffer(MPT_PORT *port)
{
int bus;
int target;
unsigned char inq[36];
unsigned char buf[4];
int i;
int n;
int mode;
unsigned int size;
if (kFlag == TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 0;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 0;
printf("Buffer: [0=Data, 1=Echo, or RETURN to quit] ");
i = getNumberAnswer(0, 1, -1);
if (i < 0)
return 0;
switch (i)
{
case 0: mode = 0x2; break;
case 1: mode = 0xa; break;
default: return 0;
}
if (doReadBuffer(port, bus, target, 0, mode + 1, buf, sizeof buf) != 1)
return 0;
size = min(0x4000, get3bytes(buf, 1));
if (size < 4)
return 0;
diag_targets[0].bus = bus;
diag_targets[0].target = target;
diag_targets[0].mode = mode;
diag_targets[0].size = size;
return 1;
}
showPortInfoHeader(port);
printf(" B___T Type Vendor Product Rev Buffer & Size\n");
n = 0;
for (bus = 0; bus < port->maxBuses; bus++)
{
for (target = port->minTargets; target < port->maxTargets; target++)
{
if (doInquiry(port, bus, target, 0, inq, sizeof inq) != 1)
{
#if __linux__ || DOS || EFI
if (errno == EFAULT)
return 0;
#endif
continue;
}
if ((inq[0] & 0x1f) == 0x1f)
continue;
if ((inq[0] & 0xe0) == 0x20)
continue;
if ((inq[0] & 0xe0) == 0x60)
continue;
for (i = 8; i < 36; i++)
if (!isprint(inq[i]))
inq[i] = ' ';
mode = 0x2;
if (doReadBuffer(port, bus, target, 0, mode + 1, buf, sizeof buf) == 1)
{
size = min(0x4000, get3bytes(buf, 1));
if (size < 4)
continue;
diag_targets[n].bus = bus;
diag_targets[n].target = target;
diag_targets[n].mode = mode;
diag_targets[n].size = size;
n++;
printf("%2d. %2d %3d %-9s %-8.8s %-16.16s %-4.4s Data %5d\n",
n, bus, target, deviceType[inq[0] & 0x1f],
inq+8, inq+16, inq+32, size);
if (n == MAX_DEVICES)
break;
}
mode = 0xa;
if (doReadBuffer(port, bus, target, 0, mode + 1, buf, sizeof buf) == 1)
{
size = min(0x4000, get3bytes(buf, 1));
if (size < 4)
continue;
diag_targets[n].bus = bus;
diag_targets[n].target = target;
diag_targets[n].mode = mode;
diag_targets[n].size = size;
n++;
printf("%2d. %2d %3d %-9s %-8.8s %-16.16s %-4.4s Echo %5d\n",
n, bus, target, deviceType[inq[0] & 0x1f],
inq+8, inq+16, inq+32, size);
if (n == MAX_DEVICES)
break;
}
}
if (n == MAX_DEVICES)
break;
}
if (n == 0)
{
printf("\nNo devices are available for this test\n");
return 0;
}
printf("\nSelect a device: [1-%d or RETURN to quit] ", n);
n = getNumberAnswer(1, n, 0);
return n;
}
int
getExpanderType(int componentId, U8 *componentVendorId, U8 *vendorId)
{
if ( (strncmp((char *)componentVendorId, "LSI", 3) != 0) &&
(strncmp((char *)vendorId, "LSI", 3) != 0) )
return EXPANDER_TYPE_3RD_PARTY;
else
{
switch(componentId)
{
case 0x0211:
case 0x0213:
return EXPANDER_TYPE_LSI_GEN1_YETI;
case 0x0220:
case 0x0221:
case 0x0223:
case 0x0224:
case 0x0225:
case 0x0226:
case 0x0227:
return EXPANDER_TYPE_LSI_GEN2_BOBCAT;
case 0x0230:
case 0x0231:
case 0x0232:
case 0x0233:
case 0x0235:
case 0x0236:
return EXPANDER_TYPE_LSI_GEN3_COBRA;
default:
return EXPANDER_TYPE_3RD_PARTY;
}
}
}
char *
printExpanderType(int expanderType)
{
switch(expanderType)
{
case EXPANDER_TYPE_LSI_GEN1_YETI: return "LSI SAS1 (Yeti)";
case EXPANDER_TYPE_LSI_GEN2_BOBCAT: return "LSI SAS2 (Bobcat)";
case EXPANDER_TYPE_LSI_GEN3_COBRA: return "LSI SAS3 (Cobra)";
case EXPANDER_TYPE_LSI_GEN1_X12: return "LSI SAS1 (X12)";
case EXPANDER_TYPE_3RD_PARTY: return "non LSI expander";
case EXPANDER_TYPE_UNKNOWN:
default: return "unknown expander";
}
}
int
selectExpander(MPT_PORT *port, int *ses_bus, int *ses_target, U8 *phys_port, _U64 *sas_addr, int *expanderType)
{
SasExpanderPage0_t SASExpanderPage0;
int handle = -1;
U32 wwid_l;
U32 wwid_h;
_U64 sas_address;
U8 physical_port;
int bus;
int target = 0;
unsigned char inq[36];
char buf[32];
int i;
int n;
int t;
int numDev;
int multipleSelect = FALSE;
int curr;
SMP_REPORT_MANUFACTURER_INFO_RESPONSE smpResp;
int respDataLength;
t = ses_bus && ses_target;
if (kFlag == TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
{
if (t)
return 0;
goto getHandle;
}
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
{
if (t)
return 0;
goto getHandle;
}
if (t)
{
*ses_bus = bus;
*ses_target = target;
}
getParent(port, bus, target, &handle);
goto getHandle;
}
showPortInfoHeader(port);
getDeviceInfoHeader(port, buf, sizeof buf);
printf(" B___T Type Vendor Product Rev %s\n", buf);
n = 0;
for (bus = 0; bus < port->maxBuses; bus++)
{
for (target = port->minTargets; target < port->maxTargets; target++)
{
if (doInquiry(port, bus, target, 0, inq, sizeof inq) != 1)
{
#if __linux__ || DOS || EFI
if (errno == EFAULT)
return 0;
#endif
continue;
}
if ((inq[0] & 0x1f) != 0x0d)
continue;
for (i = 8; i < 36; i++)
if (!isprint(inq[i]))
inq[i] = ' ';
diag_targets[n].bus = bus;
diag_targets[n].target = target;
n++;
getDeviceInfo(port, bus, target, buf, sizeof buf);
printf("%2d. %2d %3d %-9s %-8.8s %-16.16s %-4.4s %s\n",
n, bus, target, deviceType[inq[0] & 0x1f],
inq+8, inq+16, inq+32, buf);
if (n == MAX_DEVICES)
break;
}
if (n == MAX_DEVICES)
break;
}
if (n == 0)
{
if (t)
{
printf("\nNo expanders are available for this test\n");
return 0;
}
goto getHandle;
}
numDev = n;
printf("\nSelect an expander: [1-%d or RETURN to quit] ", numDev);
n = getNumberAnswer(1, numDev, -888);
if (n > 0)
{
if (n == 888)
{
for (i = 0; i < numDev; i++)
{
bus = exp_targets[i].bus = diag_targets[i].bus;
target = exp_targets[i].target = diag_targets[i].target;
getParent(port, bus, target, &exp_targets[i].handle);
}
exp_targets[i].bus = -1;
exp_targets[i].target = -1;
exp_targets[i].handle = -1;
if (t)
{
*ses_bus = -1;
*ses_target = -1;
}
handle = 0xffff; // dummy value to indicate we need a list of handles
multipleSelect = TRUE;
}
else
{
n--;
bus = diag_targets[n].bus;
target = diag_targets[n].target;
if (t)
{
*ses_bus = bus;
*ses_target = target;
}
getParent(port, bus, target, &handle);
}
}
getHandle:
if (handle < 0)
{
printf("\nExpander Handle SASAddress Port Phys\n");
handle = 0xffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, handle,
&SASExpanderPage0, sizeof SASExpanderPage0) != 1)
break;
handle = get16(SASExpanderPage0.DevHandle);
printf(" %04x %08x%08x %2d %2d\n", handle,
get32(SASExpanderPage0.SASAddress.High),
get32(SASExpanderPage0.SASAddress.Low),
SASExpanderPage0.PhysicalPort,
SASExpanderPage0.NumPhys);
}
printf("\nEnter handle: [0000-FFFF or RETURN to quit] ");
handle = getNumberAnswerHex(0x0000, 0xffff, -1);
if (handle < 0)
return 0;
}
if (handle == 0)
{
printf("Enter SASAddress: [16 hex digits or RETURN to quit] ");
t = getHexDoubleNumberAnswer(&wwid_h, &wwid_l);
if (t == 0)
return 0;
printf("Enter port: [0 to %d or RETURN to leave unspecified] ", port->numPhys - 1);
physical_port = (U8)getNumberAnswer(0, port->numPhys - 1, 255);
sas_address.Low = set32(wwid_l);
sas_address.High = set32(wwid_h);
}
else
{
curr = -1;
while (TRUE)
{
if (multipleSelect)
{
curr++;
handle = exp_targets[curr].handle;
if (handle == -1)
{
physical_port = -1;
sas_address.Low = 0;
sas_address.High = 0;
break;
}
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0,
(MPI_SAS_EXPAND_PGAD_FORM_HANDLE
<<MPI_SAS_EXPAND_PGAD_FORM_SHIFT) + handle,
&SASExpanderPage0, sizeof SASExpanderPage0) != 1)
{
printf("\nInvalid handle, not an expander!\n");
return 0;
}
if (multipleSelect)
{
exp_targets[curr].sas_address = SASExpanderPage0.SASAddress;
exp_targets[curr].physical_port = SASExpanderPage0.PhysicalPort;
}
else
{
physical_port = SASExpanderPage0.PhysicalPort;
sas_address = SASExpanderPage0.SASAddress;
break;
}
}
}
if (phys_port)
*phys_port = physical_port;
if (sas_addr)
*sas_addr = sas_address;
curr = -1;
while (TRUE)
{
if (multipleSelect)
{
curr++;
sas_address = exp_targets[curr].sas_address;
physical_port = exp_targets[curr].physical_port;
bus = exp_targets[curr].bus;
target = exp_targets[curr].target;
if (exp_targets[curr].handle == -1)
{
if (expanderType)
*expanderType = -1;
break;
}
}
if (doSmpReportMfg(port, sas_address, physical_port, &smpResp, &respDataLength) != 1)
{
printf("Unable to communicate with the expander\n (WWN: %08x%08x, Bus: %d, Target: %d) to determine it's type!\n",
get32(sas_address.High), get32(sas_address.Low), bus, target);
if (multipleSelect)
exp_targets[curr].expanderType = EXPANDER_TYPE_UNKNOWN;
else
return 0;
}
else
{
if (multipleSelect)
exp_targets[curr].expanderType = getExpanderType(get16x_be(smpResp.ComponentId), smpResp.ComponentVendorId,
smpResp.VendorIdentification);
else
if (expanderType)
*expanderType = getExpanderType(get16x_be(smpResp.ComponentId), smpResp.ComponentVendorId,
smpResp.VendorIdentification);
}
if (!multipleSelect)
break;
}
return 1;
}
int
doDiagnostics(MPT_PORT *port, int command)
{
if (bringOnline(port) != 1)
return 0;
switch (command)
{
case 1:
doInquiryTest(port);
break;
case 2:
doWriteBufferReadBufferCompareTest(port);
break;
case 3:
doReadTest(port);
break;
case 4:
doWriteReadCompareTest(port);
break;
case 5:
doWriteTest(port);
break;
case 6:
doReadCompareTest(port);
break;
case 7:
#if 0
doTestUnitReadyTest(port);
#else
doLogSenseTest(port);
#endif
break;
case 8:
doReadCapacityTest(port);
break;
case 9:
doModePageTest(port);
break;
case 10:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doEchoTest(port);
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doSataIdentifyDeviceTest(port);
break;
}
printf("Invalid selection!\n");
break;
case 11:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doReadLinkErrorStatusTest(port);
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doSataClearAffiliationTest(port);
break;
}
printf("Invalid selection!\n");
break;
case 12:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doDisplayPortCounters(port);
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doDisplayPhyCounters(port);
break;
}
printf("Invalid selection!\n");
break;
case 13:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doClearPortCounters(port);
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doClearPhyCounters(port);
break;
}
printf("Invalid selection!\n");
break;
case 14:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doSataSmartReadTest(port);
break;
}
printf("Invalid selection!\n");
break;
case 15:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SCSI ||
port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doSepTest(port);
break;
}
printf("Invalid selection!\n");
break;
case 16:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doProdSpecSasIoUnitControl(port);
break;
}
printf("Invalid selection!\n");
break;
case 17:
doDiagDataUpload(port);
break;
case 18:
doReportLunsTest(port);
break;
case 19:
doDriveFirmwareDownload(port);
break;
case 20:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
doTriggerAnalyzerWithEcho(port);
break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doExpanderFirmwareDownload(port);
break;
}
printf("Invalid selection!\n");
break;
case 21:
doReadLogicalBlocks(port);
break;
case 22:
doWriteLogicalBlocks(port);
break;
case 23:
doVerifyLogicalBlocks(port);
break;
case 24:
doReadBufferFirmwareUpload(port);
break;
case 25:
doDisplayExpanderLogEntries(port);
break;
case 26:
doClearExpanderLogEntries(port);
break;
case 27:
doExpanderChangeMfgDataFields(port);
break;
case 29:
doDiagnosticPageTest(port);
break;
case 30:
doInjectRepairMediaError(port, 1);
break;
case 31:
doInjectRepairMediaError(port, 0);
break;
case 32:
doSoftwareWriteProtect(port, 1);
break;
case 33:
doSoftwareWriteProtect(port, 0);
break;
case 34:
doReadWriteCache(port, 1);
break;
case 35:
doReadWriteCache(port, 0);
break;
case 36:
doReadWriteCache(port, 3);
break;
case 37:
doReadWriteCache(port, 2);
break;
case 98:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doResetExpander(port);
break;
}
printf("Invalid selection!\n");
break;
default:
printf("Invalid selection!\n");
break;
}
return 1;
}
void
generatePattern(int pattern, void *buf, int len)
{
int i;
int j;
unsigned char *buf1 = (unsigned char *)buf;
unsigned short *buf2 = (unsigned short *)buf;
switch (pattern)
{
case 1:
for (i = 0; i < len / 2; i++)
{
*buf1++ = 0x00;
*buf1++ = 0xff;
}
break;
case 2:
for (i = 0; i < len / 2; i++)
{
*buf1++ = 0x55;
*buf1++ = 0xaa;
}
break;
case 3:
for (i = 0; i < len; i++)
{
*buf1++ = i;
}
break;
case 4:
for (i = 0; i < len / 2; i++)
{
*buf1++ = 1 << (i & 7);
*buf1++ = ~(1 << (i & 7));
}
break;
case 5:
for (i = 0; i < len / 4; i++)
{
*buf2++ = 0x0000;
*buf2++ = 0xffff;
}
break;
case 6:
for (i = 0; i < len / 4; i++)
{
*buf2++ = 0x5555;
*buf2++ = 0xaaaa;
}
break;
case 7:
for (i = 0; i < len / 2; i++)
{
*buf2++ = i;
}
break;
case 8:
for (i = 0; i < len / 4; i++)
{
*buf2++ = 1 << (i & 15);
*buf2++ = ~(1 << (i & 15));
}
break;
case 9:
for (i = 0; i < len; i++)
{
*buf1++ = rand();
}
break;
case 10:
for (j = 0; j < len / 0x200; j++)
{
for (i = 0x0; i < 0x200; i++)
*buf1++ = 0xb5;
}
break;
case 11:
for (j = 0; j < len / 0x200; j++)
{
for (i = 0x0; i < 0x200; i++)
*buf1++ = 0x4a;
}
break;
}
}
void
format64bitDecimal(uint64_t number, char *buf, int len)
{
int i;
int part;
char temp[4];
memset(buf, ' ', len);
i = len - 1;
while (TRUE)
{
part = (int)(number % 1000);
number /= 1000;
if (number == 0)
{
sprintf(temp, "%3d", part);
buf[--i] = temp[2];
buf[--i] = temp[1];
buf[--i] = temp[0];
break;
}
sprintf(temp, "%03d", part);
buf[--i] = temp[2];
buf[--i] = temp[1];
buf[--i] = temp[0];
buf[--i] = ',';
}
buf[len - 1] = '\0';
}
int
doInquiryTest(MPT_PORT *port)
{
int bus;
int target;
int lun;
int vpd;
int page;
unsigned char inq[255];
int i;
int n;
int t;
while (TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
printf("LUN: [0-%d or RETURN to quit] ", port->maxLuns - 1);
lun = getNumberAnswer(0, port->maxLuns - 1, -1);
if (lun < 0)
return 1;
printf("VPD Page: [00-FF or RETURN for normal Inquiry] ");
page = getNumberAnswerHex(0x00, 0xff, -1);
vpd = page != -1;
printf("\n");
if (vpd)
{
t = doInquiryVpdPage(port, bus, target, lun, page, inq, sizeof inq);
n = inq[3] + 4;
}
else
{
t = doInquiry(port, bus, target, lun, inq, sizeof inq);
n = inq[4] + 5;
}
if (t == 1)
{
if (vpd)
{
printf(" B___T___L Page\n");
printf("%2d %3d %3d %02x\n\n",
bus, target, lun, page);
}
else
{
for (i = 8; i < 36; i++)
if (!isprint(inq[i]))
inq[i] = ' ';
printf(" B___T___L Type Vendor Product Rev\n");
printf("%2d %3d %3d %-9s %-8.8s %-16.16s %-4.4s\n\n",
bus, target, lun, deviceType[inq[0] & 0x1f],
inq+8, inq+16, inq+32);
}
printf("%d bytes of Inquiry Data returned\n\n", n);
displayByteData(inq, n);
}
else
{
printf("Inquiry failed\n");
}
printf("\n");
}
}
int
doWriteBufferReadBufferCompareTest(MPT_PORT *port)
{
int bus;
int target;
unsigned char *data_in;
unsigned char *data_out;
unsigned char *p;
unsigned char *q;
int i;
unsigned int j;
int n;
int mode;
unsigned int size;
int pattern;
int passes;
int progress;
n = selectDeviceRWBuffer(port);
if (n == 0)
return 0;
n--;
bus = diag_targets[n].bus;
target = diag_targets[n].target;
mode = diag_targets[n].mode;
while (TRUE)
{
size = diag_targets[n].size;
printf("\n");
printf(" 1. Alternating, 8-Bit, 00 and FF\n");
printf(" 2. Alternating, 8-Bit, 55 and AA\n");
printf(" 3. Incrementing, 8-Bit\n");
printf(" 4. Walking 1s and 0s, 8-Bit\n");
printf(" 5. Alternating, 16-Bit, 0000 and FFFF\n");
printf(" 6. Alternating, 16-Bit, 5555 and AAAA\n");
printf(" 7. Incrementing, 16-Bit\n");
printf(" 8. Walking 1s and 0s, 16-Bit\n");
printf(" 9: Random\n");
printf("10: All B5\n");
printf("11: All 4A\n");
printf("\nSelect a data pattern: [1-11 or RETURN to quit] ");
pattern = getNumberAnswer(1, 11, 0);
if (pattern == 0)
return 1;
printf("Pattern length: [1-%d or RETURN to quit] ", size);
size = getNumberAnswer(1, size, 0);
if (size == 0)
return 1;
printf("Number of iterations: [1-1000000 or 0 for infinite or RETURN to quit] ");
passes = getNumberAnswer(0, 1000000, -1);
if (passes < 0)
return 1;
data_in = malloc(size);
data_out = malloc(size);
generatePattern(pattern, data_out, size);
progress = max(10, passes / 10);
printf("Testing started...\n");
for (i = 1; i <= passes || passes == 0; i++)
{
if (doWriteBuffer(port, bus, target, 0, mode, data_out, size) != 1)
{
printf("W ");
continue;
}
if (doReadBuffer(port, bus, target, 0, mode, data_in, size) != 1)
{
printf("R ");
continue;
}
if (memcmp(data_in, data_out, size) != 0)
{
p = data_out;
q = data_in;
for (j = 0; j < size; j++)
{
if (*p != *q)
printf("\nMiscompare at buffer offset %02x expected %02x actual %02x\n", j, *p, *q);
p++; q++;
}
break;
}
// printf(".");
if (passes == 0)
{
if (i % 100000 == 0)
{
printf(" %d", i);
if (i == 1000000)
{
i = 0;
printf("\n");
}
fflush(stdout);
}
}
else if (i % progress == 0)
{
printf(" %d%% ", i * 100 / passes);
fflush(stdout);
}
}
printf("\nTesting ended...\n");
free(data_in);
free(data_out);
}
}
int
getEedpMode(MPT_PORT *port, int eedp)
{
IOCPage1_t IOCPage1;
int flags = 0;
int eedp_mode = -1;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 1, 0, &IOCPage1, sizeof IOCPage1) == 1)
{
flags = get32(IOCPage1.Flags);
switch (flags & MPI_IOCPAGE1_EEDP_MODE_MASK)
{
case MPI_IOCPAGE1_EEDP_MODE_OFF:
printf("\nEnd-to-End Data Protection Mode is disabled\n");
break;
case MPI_IOCPAGE1_EEDP_MODE_T10:
printf("\nEnd-to-End Data Protection Mode is set to T10\n");
eedp_mode = 0x1;
break;
case MPI_IOCPAGE1_EEDP_MODE_LSI_1:
printf("\nEnd-to-End Data Protection Mode is set to LB\n");
eedp_mode = 0x2;
break;
default:
printf("\nEnd-to-End Data Protection Mode is unknown, ignoring\n");
break;
}
}
if (eedp_mode > 0)
{
printf("\nIs firmware/hardware going to handle EEDP? [Yes or No, default is Yes] ");
if (getYesNoAnswer(1) != 1)
{
printf("This utility will manage the Data Integrity Fields\n");
eedp_mode += 0x100;
}
else
{
printf("Firmware/Hardware will manage the Data Integrity Fields\n");
}
}
else
{
printf("\nShould software T10 EEDP be implemented? [Yes or No, default is Yes] ");
if (getYesNoAnswer(1) == 1)
{
printf("This utility will manage the Data Integrity Fields\n");
eedp_mode = 0x201;
}
else if (eedp == 2)
{
printf("No EEDP will be provided\n");
eedp_mode = 0;
}
else
{
printf("Disk cannot be used in this test\n");
}
}
return eedp_mode;
}
int
doReadTest(MPT_PORT *port)
{
int bus;
int target;
int lun;
unsigned char *data_in;
int i;
int n;
unsigned int mode;
unsigned int size;
int eedp;
unsigned int lbn;
int lbns;
int len;
int passes;
int random;
int progress;
int eedp_mode = 0;
n = selectDeviceRWMedia(port);
if (n == 0)
return 0;
n--;
bus = diag_targets[n].bus;
target = diag_targets[n].target;
lun = diag_targets[n].lun;
mode = diag_targets[n].mode;
size = diag_targets[n].size;
eedp = diag_targets[n].eedp;
if (eedp)
{
eedp_mode = getEedpMode(port, eedp);
if (eedp_mode < 0)
return 0;
}
while (TRUE)
{
printf("\n");
printf("Number of blocks per I/O: [1-64 or RETURN to quit] ");
lbns = getNumberAnswer(1, 64, 0);
if (lbns == 0)
return 1;
printf("Number of iterations: [1-1000000 or 0 for infinite or RETURN to quit] ");
passes = getNumberAnswer(0, 1000000, -1);
if (passes < 0)
return 1;
printf("Type of I/O: [0=Sequential, 1=Random, default is 0] ");
random = getNumberAnswer(0, 1, 0);
len = lbns * ((eedp_mode == 0) ? mode : 512);
data_in = malloc(lbns * mode);
progress = max(10, passes / 10);
lbn = 128;
printf("Testing started...\n");
for (i = 1; i <= passes || passes == 0; i++, lbn += lbns)
{
if (random)
{
lbn = rand();
while (lbn + lbns >= size)
{
lbn /= 2;
}
}
else
{
if (lbn + lbns >= size)
{
lbn = 128;
}
}
if (doRead(port, bus, target, lun, lbn, lbns, eedp_mode, data_in, len) != 1)
{
printf("R ");
continue;
}
// printf(".");
if (passes == 0)
{
if (i % 100000 == 0)
{
printf(" %d", i);
if (i == 1000000)
{
i = 0;
printf("\n");
}
fflush(stdout);
}
}
else if (i % progress == 0)
{
printf(" %d%% ", i * 100 / passes);
fflush(stdout);
}
}
printf("\nTesting ended...\n");
free(data_in);
}
}
int
doWriteReadCompareTest(MPT_PORT *port)
{
int bus;
int target;
int lun;
unsigned char *data_in;
unsigned char *data_out;
int i;
int n;
unsigned int mode;
unsigned int size;
int eedp;
int pattern;
unsigned int lbn;
int lbns;
int len;
int passes;
int random;
int progress;
int eedp_mode = 0;
int quit;
n = selectDeviceRWMedia(port);
if (n == 0)
return 0;
n--;
bus = diag_targets[n].bus;
target = diag_targets[n].target;
lun = diag_targets[n].lun;
mode = diag_targets[n].mode;
size = diag_targets[n].size;
eedp = diag_targets[n].eedp;
if (eedp)
{
eedp_mode = getEedpMode(port, eedp);
if (eedp_mode < 0)
return 0;
}
while (TRUE)
{
printf("\n");
printf(" 1. Alternating, 8-Bit, 00 and FF\n");
printf(" 2. Alternating, 8-Bit, 55 and AA\n");
printf(" 3. Incrementing, 8-Bit\n");
printf(" 4. Walking 1s and 0s, 8-Bit\n");
printf(" 5. Alternating, 16-Bit, 0000 and FFFF\n");
printf(" 6. Alternating, 16-Bit, 5555 and AAAA\n");
printf(" 7. Incrementing, 16-Bit\n");
printf(" 8. Walking 1s and 0s, 16-Bit\n");
printf(" 9: Random\n");
printf("10: All B5\n");
printf("11: All 4A\n");
printf("12: Incrementing across iterations (00 through FF)\n");
printf("\nSelect a data pattern: [1-12 or RETURN to quit] ");
pattern = getNumberAnswer(1, 12, 0);
if (pattern == 0)
return 1;
printf("Number of blocks per I/O: [1-64 or RETURN to quit] ");
lbns = getNumberAnswer(1, 64, 0);
if (lbns == 0)
return 1;
if (pattern == 12)
printf("Number of iterations per pattern: [1-1000000 or RETURN to quit] ");
else
printf("Number of iterations: [1-1000000 or 0 for infinite or RETURN to quit] ");
passes = getNumberAnswer(0, 1000000, -1);
if (passes < 0)
return 1;
if (passes == 0 && pattern == 12)
return 1;
printf("Type of I/O: [0=Sequential, 1=Random, default is 0] ");
random = getNumberAnswer(0, 1, 0);
len = lbns * ((eedp_mode == 0) ? mode : 512);
data_in = malloc(lbns * mode);
data_out = malloc(lbns * mode);
if (pattern == 12)
{
int j;
int quit_test = 0;
printf("Stop pattern on Write, Read, or Compare error? [Yes or No, default is Yes] ");
quit = getYesNoAnswer(1);
if (quit)
{
printf("Stop test on Write, Read, or Compare error? [Yes or No, default is Yes] ");
quit_test = getYesNoAnswer(1);
}
lbn = 128;
printf("Testing started...\n");
for (j = 0x00; j <= 0xff; j++)
{
FCPortPage6_t FCPortPage6;
uint64_t LipCount = 0;
uint64_t LossOfSyncCount = 0;
uint64_t LipCountDiff;
uint64_t LossOfSyncCountDiff;
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 6, 0, &FCPortPage6, sizeof FCPortPage6) == 1)
{
LipCount = get64(FCPortPage6.LipCount);
LossOfSyncCount = get64(FCPortPage6.LossOfSyncCount);
}
}
printf(" %02X ", j);
fflush(stdout);
memset(data_out, j, len);
for (i = 1; i <= passes; i++, lbn += lbns)
{
if (random)
{
lbn = rand();
while (lbn + lbns >= size)
{
lbn /= 2;
}
}
else
{
if (lbn + lbns >= size)
{
lbn = 128;
}
}
if (doWrite(port, bus, target, lun, lbn, lbns, eedp_mode, data_out, len) != 1)
{
if (quit)
{
printf("W at pass %d", i);
if (quit_test)
j = 256;
break;
}
else
{
printf("W ");
continue;
}
}
if (doRead(port, bus, target, lun, lbn, lbns, eedp_mode, data_in, len) != 1)
{
if (quit)
{
printf("R at pass %d", i);
if (quit_test)
j = 256;
break;
}
else
{
printf("R ");
continue;
}
}
if (memcmp(data_in, data_out, len) != 0)
{
if (quit)
{
printf("C at pass %d", i);
if (quit_test)
j = 256;
break;
}
else
{
printf("C ");
continue;
}
}
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 6, 0, &FCPortPage6, sizeof FCPortPage6) == 1)
{
LipCountDiff = get64(FCPortPage6.LipCount) - LipCount;
LossOfSyncCountDiff = get64(FCPortPage6.LossOfSyncCount) - LossOfSyncCount;
if (LipCountDiff != 0 || LossOfSyncCountDiff != 0)
{
printf("\nPattern %02X caused %s%d LIP%s and %s%d Loss%sOfSync\n", data_out[0],
LipCountDiff > 1000 ? ">" : "",
LipCountDiff > 1000 ? 1000 : (int)LipCountDiff,
LipCountDiff != 1 ? "s" : "",
LossOfSyncCountDiff > 1000 ? ">" : "",
LossOfSyncCountDiff > 1000 ? 1000 : (int)LossOfSyncCountDiff,
LossOfSyncCountDiff != 1 ? "es" : "");
}
}
}
}
printf("\nTesting ended...\n");
}
else
{
generatePattern(pattern, data_out, len);
printf("Stop test on Write, Read, or Compare error? [Yes or No, default is Yes] ");
quit = getYesNoAnswer(1);
progress = max(10, passes / 10);
lbn = 128;
printf("Testing started...\n");
for (i = 1; i <= passes || passes == 0; i++, lbn += lbns)
{
if (random)
{
lbn = rand();
while (lbn + lbns >= size)
{
lbn /= 2;
}
}
else
{
if (lbn + lbns >= size)
{
lbn = 128;
}
}
if (doWrite(port, bus, target, lun, lbn, lbns, eedp_mode, data_out, len) != 1)
{
if (quit)
{
printf("W at pass %d", i);
break;
}
else
{
printf("W ");
continue;
}
}
if (doRead(port, bus, target, lun, lbn, lbns, eedp_mode, data_in, len) != 1)
{
if (quit)
{
printf("R at pass %d", i);
break;
}
else
{
printf("R ");
continue;
}
}
if (memcmp(data_in, data_out, len) != 0)
{
if (quit)
{
printf("C at pass %d", i);
break;
}
else
{
printf("C ");
continue;
}
}
// printf(".");
if (passes == 0)
{
if (i % 100000 == 0)
{
printf(" %d", i);
if (i == 1000000)
{
i = 0;
printf("\n");
}
fflush(stdout);
}
}
else if (i % progress == 0)
{
printf(" %d%% ", i * 100 / passes);
fflush(stdout);
}
}
printf("\nTesting ended...\n");
}
free(data_in);
free(data_out);
}
}
int
doWriteTest(MPT_PORT *port)
{
int bus;
int target;
int lun;
unsigned char *data_in;
unsigned char *data_out;
int i;
int j;
int n;
unsigned int mode;
unsigned int size;
int eedp;
U32 tag;
unsigned int lbn;
int lbns;
int len;
int progress;
int eedp_mode = 0;
int quit;
U32 *p;
n = selectDeviceRWMedia(port);
if (n == 0)
return 0;
n--;
bus = diag_targets[n].bus;
target = diag_targets[n].target;
lun = diag_targets[n].lun;
mode = diag_targets[n].mode;
size = diag_targets[n].size;
eedp = diag_targets[n].eedp;
if (eedp)
{
eedp_mode = getEedpMode(port, eedp);
if (eedp_mode < 0)
return 0;
}
printf("\nTagging data value: [00000000-FFFFFFFF or RETURN to quit] ");
if (getHexNumberAnswer(&tag) == 0)
return 1;
printf("Number of blocks per I/O: [1-64 or RETURN to quit] ");
lbns = getNumberAnswer(1, 64, 0);
if (lbns == 0)
return 1;
len = lbns * ((eedp_mode == 0) ? mode : 512);
data_in = malloc(lbns * mode);
data_out = malloc(lbns * mode);
printf("Stop pattern on Write error? [Yes or No, default is Yes] ");
quit = getYesNoAnswer(1);
progress = ((size - 128) / 10) / lbns * lbns;
printf("Testing started...\n");
for (lbn = 128; lbn < size; i++, lbn += lbns)
{
p = (U32 *)data_out;
for (i = 0; i < lbns; i++)
{
*p++ = set32x(tag);
for (j = 4; j < (int)((eedp_mode == 0) ? mode : 512); j += 4)
{
*p++ = set32x(lbn + i);
}
}
if (doWrite(port, bus, target, lun, lbn, lbns, eedp_mode, data_out, len) != 1)
{
if (quit)
{
printf("W at lbn %d", lbn);
break;
}
else
{
printf("W ");
continue;
}
}
// printf(".");
if (lbn > 128 && (lbn - 128) % progress == 0)
{
printf(" %d%% ", (lbn - 128) * 10 / progress);
fflush(stdout);
}
}
printf("\nTesting ended...\n");
free(data_in);
free(data_out);
return 1;
}
int
doReadCompareTest(MPT_PORT *port)
{
int bus;
int target;
int lun;
unsigned char *data_in;
unsigned char *data_out;
int i;
int j;
int n;
unsigned int mode;
unsigned int size;
int eedp;
U32 tag;
unsigned int lbn;
int lbns;
int len;
int progress;
int eedp_mode = 0;
int quit;
U32 *p;
U32 *q;
n = selectDeviceRWMedia(port);
if (n == 0)
return 0;
n--;
bus = diag_targets[n].bus;
target = diag_targets[n].target;
lun = diag_targets[n].lun;
mode = diag_targets[n].mode;
size = diag_targets[n].size;
eedp = diag_targets[n].eedp;
if (eedp)
{
eedp_mode = getEedpMode(port, eedp);
if (eedp_mode < 0)
return 0;
}
printf("\nTagging data value: [00000000-FFFFFFFF or RETURN to quit] ");
if (getHexNumberAnswer(&tag) == 0)
return 1;
printf("Number of blocks per I/O: [1-64 or RETURN to quit] ");
lbns = getNumberAnswer(1, 64, 0);
if (lbns == 0)
return 1;
len = lbns * ((eedp_mode == 0) ? mode : 512);
data_in = malloc(lbns * mode);
data_out = malloc(lbns * mode);
printf("Stop pattern on Read or Compare error? [Yes or No, default is Yes] ");
quit = getYesNoAnswer(1);
progress = ((size - 128) / 10) / lbns * lbns;
printf("Testing started...\n");
for (lbn = 128; lbn < size; i++, lbn += lbns)
{
p = (U32 *)data_out;
for (i = 0; i < lbns; i++)
{
*p++ = set32x(tag);
for (j = 4; j < (int)((eedp_mode == 0) ? mode : 512); j += 4)
{
*p++ = set32x(lbn + i);
}
}
if (doRead(port, bus, target, lun, lbn, lbns, eedp_mode, data_in, len) != 1)
{
if (quit)
{
printf("R at lbn %d", lbn);
break;
}
else
{
printf("R ");
continue;
}
}
if (memcmp(data_in, data_out, len) != 0)
{
if (quit)
{
p = (U32 *)data_out;
q = (U32 *)data_in;
for (i = 0; i < lbns; i++)
{
for (j = 0; j < (int)((eedp_mode == 0) ? mode : 512); j += 4)
{
if (*p++ != *q++)
{
printf("C at lbn %d offset %x", lbn + i, j);
i = lbns - 1;
break;
}
}
}
break;
}
else
{
printf("C ");
continue;
}
}
// printf(".");
if (lbn > 128 && (lbn - 128) % progress == 0)
{
printf(" %d%% ", (lbn - 128) * 10 / progress);
fflush(stdout);
}
}
printf("\nTesting ended...\n");
free(data_in);
free(data_out);
return 1;
}
int
doTestUnitReadyTest(MPT_PORT *port)
{
int bus;
int target;
int lun;
unsigned char data[512];
while (TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
printf("LUN: [0-%d or RETURN to quit] ", port->maxLuns - 1);
lun = getNumberAnswer(0, port->maxLuns - 1, -1);
if (lun < 0)
return 1;
if (doTestUnitReady(port, bus, target, lun) == 1)
{
printf("\nTest Unit Ready successful\n");
}
else
{
printf("\nTest Unit Ready failed\n");
}
if (doRead(port, bus, target, lun, 0, 1, 0, data, sizeof data) == 1)
{
printf("\nRead successful\n");
}
else
{
printf("\nRead failed\n");
}
if (doTestUnitReady(port, bus, target, lun) == 1)
{
printf("\nTest Unit Ready successful\n");
}
else
{
printf("\nTest Unit Ready failed\n");
}
printf("\n");
}
}
int
doLogSenseTest(MPT_PORT *port)
{
int bus;
int target;
int lun;
int page;
unsigned char log[1024];
int n;
int t;
while (TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
printf("LUN: [0-%d or RETURN to quit] ", port->maxLuns - 1);
lun = getNumberAnswer(0, port->maxLuns - 1, -1);
if (lun < 0)
return 1;
printf("Page: [00-3F or RETURN to quit] ");
page = getNumberAnswerHex(0x00, 0x3f, -1);
if (page < 0)
return 1;
printf("\n");
t = doLogSense(port, bus, target, lun, page, 1, log, sizeof log);
n = get2bytes(log, 2) + 4;
if (t == 1)
{
printf(" B___T___L Page\n");
printf("%2d %3d %3d %02x\n\n",
bus, target, lun, page);
printf("%d bytes of Log Sense Data returned\n\n", n);
if (n > sizeof log)
{
printf("Too much data received, only %d bytes will be displayed\n\n", (int)sizeof log);
n = sizeof log;
}
displayByteData(log, n);
}
else
{
printf("Log Sense failed\n");
}
printf("\n");
}
}
int
doReadCapacityTest(MPT_PORT *port)
{
int bus;
int target;
int lun;
unsigned char inq[36];
unsigned char cap[8];
unsigned char bl[6];
unsigned int min_size;
unsigned int max_size;
unsigned int gran;
unsigned int mode;
unsigned int size;
unsigned char cap16[32];
uint64_t size16;
uint64_t capacity;
int t;
while (TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
printf("LUN: [0-%d or RETURN to quit] ", port->maxLuns - 1);
lun = getNumberAnswer(0, port->maxLuns - 1, -1);
if (lun < 0)
return 1;
printf("\n");
if (doInquiry(port, bus, target, lun, inq, sizeof inq) == 1)
{
if ((inq[0] & 0x1f) == 0x01)
{
if (doReadBlockLimits(port, bus, target, lun, bl, sizeof bl) == 1)
{
min_size = get2bytes(bl, 4);
max_size = get3bytes(bl, 1);
gran = 1 << (bl[0] & 0x1f);
printf("Min Block Size = %d, Max Block Size = %d, Granularity = %d\n",
min_size, max_size, gran);
}
else
{
printf("Read Block Limits failed\n");
}
printf("\n");
continue;
}
}
if (doReadCapacity16(port, bus, target, lun, cap16, sizeof cap16) == 1)
{
mode = get4bytes(cap16, 8);
size16 = get8bytes(cap16, 0);
capacity = (uint64_t)mode * (size16 + 1);
printf("Block Size = %08x, Last Block = %016" INT64_FMT "x", mode, size16);
}
else if (doReadCapacity(port, bus, target, lun, cap, sizeof cap) == 1)
{
mode = get4bytes(cap, 4);
size = get4bytes(cap, 0);
capacity = (uint64_t)mode * (size + 1);
printf("Block Size = %08x, Last Block = %08x", mode, size);
}
else
{
capacity = 0;
printf("Read Capacity failed\n");
}
if (capacity == 0)
{
}
else if (capacity > (uint64_t)1000*1000*1000*1000)
{
t = (int)(capacity / ((uint64_t)100*1000*1000*1000));
printf(" -- Capacity is %d.%d TB\n", t / 10, t % 10);
}
else if (capacity > (uint64_t)1000*1000*1000)
{
t = (int)(capacity / ((uint64_t)100*1000*1000));
printf(" -- Capacity is %d.%d GB\n", t / 10, t % 10);
}
else if (capacity > (uint64_t)1000*1000)
{
t = (int)(capacity / ((uint64_t)100*1000));
printf(" -- Capacity is %d.%d MB\n", t / 10, t % 10);
}
else
{
t = (int)(capacity / ((uint64_t)100));
printf(" -- Capacity is %d.%d KB\n", t / 10, t % 10);
}
printf("\n");
}
}
int
doModePageTest(MPT_PORT *port)
{
int bus;
int target;
int lun;
int control;
int page;
unsigned char data[255];
int n;
int t;
char *control_strings[4] = {"Current", "Changeable", "Default", "Saved"};
while (TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
printf("LUN: [0-%d or RETURN to quit] ", port->maxLuns - 1);
lun = getNumberAnswer(0, port->maxLuns - 1, -1);
if (lun < 0)
return 1;
printf("Mode Page: [00-3F or RETURN to quit] ");
page = getNumberAnswerHex(0x00, 0x3f, -1);
if (page < 0)
return 1;
printf("\n");
for (control = 0; control < 4; control++)
{
t = doModeSense(port, bus, target, lun, page, control, 0, data, sizeof data);
n = data[0] + 1;
if (t == 1)
{
printf("%d bytes of Page %x %s Data returned\n\n",
n, page, control_strings[control]);
displayByteData(data, n);
}
else
{
printf("Mode Sense (Page %x %s) failed\n", page, control_strings[control]);
}
printf("\n");
}
}
}
int
doEchoTest(MPT_PORT *port)
{
FCPortPage0_t FCPortPage0;
FCDevicePage0_t FCDevicePage0;
ExLinkServiceSendRequest_t req;
ExLinkServiceSendReply_t rep;
U32 buf_in[32];
U32 buf_out[32];
U32 els;
U32 d_id;
U32 port_id;
int len;
int n;
int i;
char *type;
U32 port_ids[MAX_DEVICES];
int pattern;
int passes;
int progress;
int ioc_status;
U32 code;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 0, 0, &FCPortPage0, sizeof FCPortPage0) != 1)
return 0;
port_id = get32(FCPortPage0.PortIdentifier);
printf(" Type WWNN WWPN PortId\n");
n = 0;
d_id = 0xffffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_DEVICE, 0, d_id,
&FCDevicePage0, sizeof FCDevicePage0) != 1)
break;
d_id = get32(FCDevicePage0.PortIdentifier);
if (d_id == port_id)
{
type = port->chipName;
}
else if (FCDevicePage0.Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
{
if (FCDevicePage0.Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET)
type = "FCP Initiator & Target";
else
type = "FCP Initiator";
}
else
{
if (FCDevicePage0.Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET)
type = "FCP Target";
else
type = "Non-FCP";
}
port_ids[n] = d_id;
n++;
printf("%2d. %-24s %08x%08x %08x%08x %06x\n", n, type,
get32(FCDevicePage0.WWNN.High), get32(FCDevicePage0.WWNN.Low),
get32(FCDevicePage0.WWPN.High), get32(FCDevicePage0.WWPN.Low),
d_id);
if (n == MAX_DEVICES)
break;
}
if (n == 0)
{
printf("\nNo devices are available for this test\n");
return 1;
}
printf("\nSelect a device: [1-%d or RETURN to quit] ", n);
n = getNumberAnswer(1, n, 0);
if (n == 0)
return 1;
n--;
d_id = port_ids[n];
els = 0x10;
while (TRUE)
{
printf("\n");
printf(" 1. Alternating, 8-Bit, 00 and FF\n");
printf(" 2. Alternating, 8-Bit, 55 and AA\n");
printf(" 3. Incrementing, 8-Bit\n");
printf(" 4. Walking 1s and 0s, 8-Bit\n");
printf(" 5. Alternating, 16-Bit, 0000 and FFFF\n");
printf(" 6. Alternating, 16-Bit, 5555 and AAAA\n");
printf(" 7. Incrementing, 16-Bit\n");
printf(" 8. Walking 1s and 0s, 16-Bit\n");
printf("\nSelect a data pattern: [1-8 or RETURN to quit] ");
pattern = getNumberAnswer(1, 8, 0);
if (pattern == 0)
return 1;
printf("Pattern length in words: [2-32 or RETURN to quit] ");
len = getNumberAnswer(2, 32, 0);
if (len == 0)
return 1;
len *= 4;
printf("Number of iterations: [1-1000000 or 0 for infinite or RETURN to quit] ");
passes = getNumberAnswer(0, 1000000, -1);
if (passes < 0)
return 1;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_FC_EX_LINK_SRVC_SEND;
req.AliasIndex = virtInit;
req.MsgFlags_Did = set32(d_id);
req.ElsCommandCode = set32(els);
generatePattern(pattern, buf_out, len);
buf_out[0] = set32x(els);
progress = max(10, passes / 10);
printf("Testing started...\n");
for (i = 1; i <= passes || passes == 0; i++)
{
buf_in[0] = 0;
if (doMptCommand(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
buf_in, sizeof buf_in, buf_out, len, SHORT_TIME) != 1)
{
printf("E");
continue;
}
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status != MPI_IOCSTATUS_SUCCESS)
{
printf("\nSendELS failed, IOCStatus = %04x (%s)\n", ioc_status, translateIocStatus(ioc_status));
return 0;
}
code = (get32x_be(buf_in[0]) >> 24) & 0xff;
if (code == 0x01)
{
printf("\nECHO ELS rejected\n");
return 0;
}
if (code != 0x02)
{
printf("\nECHO ELS not accepted, code is %02x\n", code);
return 0;
}
if (memcmp(buf_in + 1, buf_out + 1, len - 4) != 0)
{
printf("C ");
continue;
}
// printf(".");
if (passes == 0)
{
if (i % 100000 == 0)
{
printf(" %d", i);
if (i == 1000000)
{
i = 0;
printf("\n");
}
fflush(stdout);
}
}
else if (i % progress == 0)
{
printf(" %d%% ", i * 100 / passes);
fflush(stdout);
}
}
printf("\nTesting ended...\n");
}
}
int
doReadLinkErrorStatusTest(MPT_PORT *port)
{
FCPortPage0_t FCPortPage0;
FCDevicePage0_t FCDevicePage0;
ExLinkServiceSendRequest_t req;
ExLinkServiceSendReply_t rep;
U32 buf_in[7];
U32 buf_out[2];
U32 els;
U32 d_id;
U32 port_id;
int n;
char *type;
U32 port_ids[MAX_DEVICES];
int ioc_status;
U32 code;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 0, 0, &FCPortPage0, sizeof FCPortPage0) != 1)
return 0;
port_id = get32(FCPortPage0.PortIdentifier);
printf(" Type WWNN WWPN PortId\n");
n = 0;
d_id = 0xffffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_DEVICE, 0, d_id,
&FCDevicePage0, sizeof FCDevicePage0) != 1)
break;
d_id = get32(FCDevicePage0.PortIdentifier);
if (d_id == port_id)
{
type = port->chipName;
}
else if (FCDevicePage0.Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
{
if (FCDevicePage0.Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET)
type = "FCP Initiator & Target";
else
type = "FCP Initiator";
}
else
{
if (FCDevicePage0.Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET)
type = "FCP Target";
else
type = "Non-FCP";
}
port_ids[n] = d_id;
n++;
printf("%2d. %-24s %08x%08x %08x%08x %06x\n", n, type,
get32(FCDevicePage0.WWNN.High), get32(FCDevicePage0.WWNN.Low),
get32(FCDevicePage0.WWPN.High), get32(FCDevicePage0.WWPN.Low),
d_id);
if (n == MAX_DEVICES)
break;
}
if (n == 0)
{
printf("\nNo devices are available for this test\n");
return 1;
}
printf("\nSelect a device: [1-%d or RETURN to quit] ", n);
n = getNumberAnswer(1, n, 0);
if (n == 0)
return 1;
n--;
printf("\n");
d_id = port_ids[n];
els = 0x0f;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_FC_EX_LINK_SRVC_SEND;
req.AliasIndex = virtInit;
req.MsgFlags_Did = set32(d_id);
req.ElsCommandCode = set32(els);
buf_out[0] = set32x(els);
buf_out[1] = set32x_be(d_id);
buf_in[0] = 0;
if (doMptCommand(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
buf_in, sizeof buf_in, buf_out, sizeof buf_out, SHORT_TIME) == 1)
{
char buf[32];
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status != MPI_IOCSTATUS_SUCCESS)
{
printf("SendELS failed, IOCStatus = %04x (%s)\n", ioc_status, translateIocStatus(ioc_status));
return 0;
}
code = (get32x_be(buf_in[0]) >> 24) & 0xff;
if (code == 0x01)
{
printf("RLS ELS rejected\n");
return 0;
}
if (code != 0x02)
{
printf("RLS ELS not accepted, code is %02x\n", code);
return 0;
}
format64bitDecimal(get32x_be(buf_in[1]), buf, sizeof buf);
printf("Link Failure Count %32s\n", buf);
format64bitDecimal(get32x_be(buf_in[2]), buf, sizeof buf);
printf("Loss Of Sync Count %32s\n", buf);
format64bitDecimal(get32x_be(buf_in[3]), buf, sizeof buf);
printf("Loss Of Signal Count %32s\n", buf);
format64bitDecimal(get32x_be(buf_in[4]), buf, sizeof buf);
printf("Primitive Sequence Error Count %32s\n", buf);
format64bitDecimal(get32x_be(buf_in[5]), buf, sizeof buf);
printf("Invalid Tx Word Count %32s\n", buf);
format64bitDecimal(get32x_be(buf_in[6]), buf, sizeof buf);
printf("Invalid CRC Count %32s\n", buf);
}
return 1;
}
int
doDisplayPortCounters(MPT_PORT *port)
{
FCPortPage6_t FCPortPage6;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 6, 0, &FCPortPage6, sizeof FCPortPage6) == 1)
{
char buf[32];
uint64_t time;
int seconds;
int minutes;
int hours;
int days;
time = get64(FCPortPage6.TimeSinceReset);
seconds = (int)(time / 1000000) % 60;
minutes = (int)(time / 1000000 / 60) % 60;
hours = (int)(time / 1000000 / 60 / 60) % 24;
days = (int)(time / 1000000 / 60 / 60 / 24);
sprintf(buf, "%d day%s + %02d:%02d:%02d", days, days == 1 ? "" : "s", hours, minutes, seconds);
printf("Time Since Reset %32s\n\n", buf);
format64bitDecimal(get64(FCPortPage6.TxFrames), buf, sizeof buf);
printf("Tx Frames %32s\n", buf);
format64bitDecimal(get64(FCPortPage6.RxFrames), buf, sizeof buf);
printf("Rx Frames %32s\n\n", buf);
format64bitDecimal(get64(FCPortPage6.TxWords), buf, sizeof buf);
printf("Tx Words %32s\n", buf);
format64bitDecimal(get64(FCPortPage6.RxWords), buf, sizeof buf);
printf("Rx Words %32s\n\n", buf);
format64bitDecimal(get64(FCPortPage6.LipCount), buf, sizeof buf);
printf("LIP Count %32s\n", buf);
format64bitDecimal(get64(FCPortPage6.NosCount), buf, sizeof buf);
printf("NOS Count %32s\n\n", buf);
format64bitDecimal(get64(FCPortPage6.ErrorFrames), buf, sizeof buf);
printf("Error Frames %32s\n", buf);
format64bitDecimal(get64(FCPortPage6.DumpedFrames), buf, sizeof buf);
printf("Dumped Frames %32s\n\n", buf);
format64bitDecimal(get64(FCPortPage6.LinkFailureCount), buf, sizeof buf);
printf("Link Failure Count %32s\n", buf);
format64bitDecimal(get64(FCPortPage6.LossOfSyncCount), buf, sizeof buf);
printf("Loss Of Sync Count %32s\n", buf);
format64bitDecimal(get64(FCPortPage6.LossOfSignalCount), buf, sizeof buf);
printf("Loss Of Signal Count %32s\n", buf);
format64bitDecimal(get64(FCPortPage6.PrimativeSeqErrCount), buf, sizeof buf);
printf("Primitive Sequence Error Count %32s\n", buf);
format64bitDecimal(get64(FCPortPage6.InvalidTxWordCount), buf, sizeof buf);
printf("Invalid Tx Word Count %32s\n", buf);
format64bitDecimal(get64(FCPortPage6.InvalidCrcCount), buf, sizeof buf);
printf("Invalid CRC Count %32s\n\n", buf);
format64bitDecimal(get64(FCPortPage6.FcpInitiatorIoCount), buf, sizeof buf);
printf("FCP Initiator I/O Count %32s\n", buf);
}
return 1;
}
int
doClearPortCounters(MPT_PORT *port)
{
ConfigReply_t rep;
FCPortPage6_t FCPortPage6;
if (getConfigPageHeader(port, MPI_CONFIG_PAGETYPE_FC_PORT, 6, 0, &rep) != 1)
return 0;
memset(&FCPortPage6, 0, sizeof FCPortPage6);
FCPortPage6.Header = rep.Header;
if (setConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 6, 0, &FCPortPage6, sizeof FCPortPage6) != 1)
printf("Failed to clear port counters!\n");
else
printf("Port counters have been cleared\n");
return 1;
}
int
doTriggerAnalyzerWithEcho(MPT_PORT *port)
{
FCPortPage0_t FCPortPage0;
ExLinkServiceSendRequest_t req;
ExLinkServiceSendReply_t rep;
U32 buf_in[32];
U32 buf_out[32];
U32 els;
U32 d_id;
char name[256];
int n;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 0, 0, &FCPortPage0, sizeof FCPortPage0) != 1)
return 0;
d_id = get32(FCPortPage0.PortIdentifier);
els = 0x10;
n = getFileName(name, sizeof name, stdin, "analyzer trigger", 0);
if (n > 0)
{
printf("Waiting for \"%s\" to be created...", name);
waitForFile(name);
printf("\nFile created, sending ECHO ELS\n");
}
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_FC_EX_LINK_SRVC_SEND;
req.AliasIndex = virtInit;
req.MsgFlags_Did = set32(d_id);
req.ElsCommandCode = set32(els);
memset(buf_out, 0, sizeof buf_out);
buf_out[0] = set32x(els);
memset(buf_in, 0, sizeof buf_in);
return doMptCommandCheck(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
buf_in, sizeof buf_in, buf_out, sizeof buf_out, SHORT_TIME);
}
int
isSata(MPT_PORT *port, int bus, int target)
{
int b_t;
int dev_handle;
int address;
SasDevicePage0_t SASDevicePage0;
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
if (mpi2)
{
if (mapBusTargetToDevHandle(port, bus, target, &dev_handle) != 1)
dev_handle = 0;
address = MPI2_SAS_DEVICE_PGAD_FORM_HANDLE + dev_handle;
}
else
{
b_t = (bus << 8) + target;
address = (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
<<MPI_SAS_DEVICE_PGAD_FORM_SHIFT) + b_t;
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, address,
&SASDevicePage0, sizeof SASDevicePage0) == 1)
{
if (get32(SASDevicePage0.DeviceInfo) & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
{
return 1;
}
}
}
return 0;
}
int
isSsd(MPT_PORT *port, int bus, int target)
{
unsigned char vpd[255];
int i;
int n;
int t;
if (doInquiryVpdPage(port, bus, target, 0, 0x00, vpd, sizeof vpd) == 1)
{
if ((vpd[0] & 0x1f) == 0x00)
{
n = vpd[3] + 4;
for (i = 4; i < n; i++)
{
if (vpd[i] == 0xb1)
{
if (doInquiryVpdPage(port, bus, target, 0, 0xb1, vpd, sizeof vpd) == 1)
{
n = vpd[3] + 4;
if (n >= 6)
{
t = get2bytes(vpd, 4);
if (t == 0x0001)
{
return 1;
}
}
}
}
}
}
}
return 0;
}
int
getPath(MPT_PORT *port, int bus, int target, PATH *path)
{
int b_t;
int dev_handle;
int address;
int handle;
SasDevicePage0_t SASDevicePage0;
SasEnclosurePage0_t SASEnclosurePage0;
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
if (mpi2)
{
if (mapBusTargetToDevHandle(port, bus, target, &dev_handle) != 1)
dev_handle = 0;
address = MPI2_SAS_DEVICE_PGAD_FORM_HANDLE + dev_handle;
}
else
{
b_t = (bus << 8) + target;
address = (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
<<MPI_SAS_DEVICE_PGAD_FORM_SHIFT) + b_t;
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, address,
&SASDevicePage0, sizeof SASDevicePage0) == 1)
{
handle = get16(SASDevicePage0.EnclosureHandle);
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_ENCLOSURE, 0,
(MPI_SAS_ENCLOS_PGAD_FORM_HANDLE
<<MPI_SAS_ENCLOS_PGAD_FORM_SHIFT) + handle,
&SASEnclosurePage0, sizeof SASEnclosurePage0) == 1)
{
path->slot = get16(SASDevicePage0.Slot);
path->encl_id_l = get32(SASEnclosurePage0.EnclosureLogicalID.Low);
path->encl_id_h = get32(SASEnclosurePage0.EnclosureLogicalID.High);
return 1;
}
}
}
return 0;
}
int
getParent(MPT_PORT *port, int bus, int target, int *parent)
{
int b_t;
int dev_handle;
int address;
int handle;
SasDevicePage0_t SASDevicePage0;
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
if (mpi2)
{
if (mapBusTargetToDevHandle(port, bus, target, &dev_handle) != 1)
dev_handle = 0;
address = MPI2_SAS_DEVICE_PGAD_FORM_HANDLE + dev_handle;
}
else
{
b_t = (bus << 8) + target;
address = (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
<<MPI_SAS_DEVICE_PGAD_FORM_SHIFT) + b_t;
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, address,
&SASDevicePage0, sizeof SASDevicePage0) == 1)
{
handle = get16(SASDevicePage0.ParentDevHandle);
*parent = handle;
return 1;
}
}
return 0;
}
int
isRaidPhysDisk(MPT_PORT *port, int bus, int target, int *physdisk)
{
IOCPage3_t *IOCPage3;
int length;
int i;
int ioc = port->iocNumber;
if (mpi2)
return isRaidPhysDisk2(port, bus, target, physdisk);
IOCPage3 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_IOC, 3, 0, &length);
if (IOCPage3 == NULL)
return 0;
for (i = 0; i < IOCPage3->NumPhysDisks; i++)
{
if (bus == IOCPage3->PhysDisk[i].PhysDiskBus &&
target == IOCPage3->PhysDisk[i].PhysDiskID &&
ioc == IOCPage3->PhysDisk[i].PhysDiskIOC)
{
*physdisk = IOCPage3->PhysDisk[i].PhysDiskNum;
free(IOCPage3);
return 1;
}
}
free(IOCPage3);
return 0;
}
int
isRaidPhysDisk2(MPT_PORT *port, int bus, int target, int *physdisk)
{
Mpi2RaidConfigurationPage0_t *RaidConfigPage0;
int i;
int handle;
int flags;
int type;
if (!mapBusTargetToDevHandle(port, bus, target, &handle))
return 0;
getRaidConfig(port, MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT, handle, -1, &RaidConfigPage0);
if (RaidConfigPage0 == NULL)
return 0;
for (i = 0; i < RaidConfigPage0->NumElements; i++)
{
flags = get16(RaidConfigPage0->ConfigElement[i].ElementFlags);
type = flags & MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE;
if (type == MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT)
{
if (handle == get16(RaidConfigPage0->ConfigElement[i].PhysDiskDevHandle))
{
if (physdisk)
*physdisk = RaidConfigPage0->ConfigElement[i].PhysDiskNum;
free(RaidConfigPage0);
return 1;
}
}
}
free(RaidConfigPage0);
return 0;
}
int
doReadLogicalBlocks(MPT_PORT *port)
{
int bus;
int target;
int lun;
int physdisk;
U32 lbn;
int lbns;
unsigned char *buf;
int i;
int j;
int n;
while (TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
printf("LUN: [0-%d or RETURN to quit] ", port->maxLuns - 1);
lun = getNumberAnswer(0, port->maxLuns - 1, -1);
if (lun < 0)
return 1;
printf("Logical block: [00000000-FFFFFFFF or RETURN to quit] ");
if (getHexNumberAnswer(&lbn) == 0)
return 1;
printf("Number of logical blocks: [1-64 or RETURN to quit] ");
lbns = getNumberAnswer(1, 64, 0);
if (lbns == 0)
return 1;
n = lbns * 512;
buf = malloc(n);
printf("\n");
if (isRaidPhysDisk(port, bus, target, &physdisk))
{
if (isRaidVolume(port, bus, target))
{
printf("The device selected is part of a RAID Volume (PhysDisk %d)\n\n", physdisk);
printf("Do you want to directly access the PhysDisk? [Yes or No, default is No] ");
port->raidPassthru = getYesNoAnswer(0);
printf("\n");
}
else
{
printf("The device selected is RAID PhysDisk %d\n\n", physdisk);
port->raidPassthru = 1;
}
port->raidBus = bus;
port->raidTarget = target;
port->raidPhysdisk = physdisk;
}
if (doRead(port, bus, target, lun, lbn, lbns, 0, buf, n) == 1)
{
for (i = 0, j = 0; i < n/4; i++, j++)
{
if (j == 0)
printf("%04x : ", i*4);
printf("%08x ", get32x(((unsigned int *)buf)[i]));
if (j == 7)
{
printf("\n");
j = -1;
}
if ((i % 128) == 127)
printf("\n");
}
}
else
{
printf("Read failed\n\n");
}
free(buf);
}
return 1;
}
int
doWriteLogicalBlocks(MPT_PORT *port)
{
int bus;
int target;
int lun;
int physdisk;
U32 lbn;
int lbns;
unsigned char *buf;
int n;
int pattern;
while (TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
printf("LUN: [0-%d or RETURN to quit] ", port->maxLuns - 1);
lun = getNumberAnswer(0, port->maxLuns - 1, -1);
if (lun < 0)
return 1;
printf("Logical block: [00000000-FFFFFFFF or RETURN to quit] ");
if (getHexNumberAnswer(&lbn) == 0)
return 1;
printf("Number of logical blocks: [1-64 or RETURN to quit] ");
lbns = getNumberAnswer(1, 64, 0);
if (lbns == 0)
return 1;
printf("Data to write: [0=Zeros, 1=Ones, 2=Preserve (read first), default is 2] ");
pattern = getNumberAnswer(0, 2, 2);
n = lbns * 512;
buf = malloc(n);
printf("\n");
if (isRaidPhysDisk(port, bus, target, &physdisk))
{
if (isRaidVolume(port, bus, target))
{
printf("The device selected is part of a RAID Volume (PhysDisk %d)\n\n", physdisk);
printf("Do you want to directly access the PhysDisk? [Yes or No, default is No] ");
port->raidPassthru = getYesNoAnswer(0);
printf("\n");
}
else
{
printf("The device selected is RAID PhysDisk %d\n\n", physdisk);
port->raidPassthru = 1;
}
port->raidBus = bus;
port->raidTarget = target;
port->raidPhysdisk = physdisk;
}
if (pattern == 2)
{
if (doRead(port, bus, target, lun, lbn, lbns, 0, buf, n) != 1)
{
printf("Read failed\n\n");
continue;
}
}
else if (pattern == 0)
{
memset(buf, 0x00, n);
}
else if (pattern == 1)
{
memset(buf, 0xff, n);
}
if (doWrite(port, bus, target, lun, lbn, lbns, 0, buf, n) == 1)
{
printf("Write successful\n\n");
}
else
{
printf("Write failed\n\n");
}
free(buf);
}
return 1;
}
int
doVerifyLogicalBlocks(MPT_PORT *port)
{
int bus;
int target;
int lun;
int physdisk;
U32 lbn;
int lbns;
while (TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
printf("LUN: [0-%d or RETURN to quit] ", port->maxLuns - 1);
lun = getNumberAnswer(0, port->maxLuns - 1, -1);
if (lun < 0)
return 1;
printf("Logical block: [00000000-FFFFFFFF or RETURN to quit] ");
if (getHexNumberAnswer(&lbn) == 0)
return 1;
printf("Number of logical blocks: [1-1024 or RETURN to quit] ");
lbns = getNumberAnswer(1, 1024, 0);
if (lbns == 0)
return 1;
printf("\n");
if (isRaidPhysDisk(port, bus, target, &physdisk))
{
if (isRaidVolume(port, bus, target))
{
printf("The device selected is part of a RAID Volume (PhysDisk %d)\n\n", physdisk);
printf("Do you want to directly access the PhysDisk? [Yes or No, default is No] ");
port->raidPassthru = getYesNoAnswer(0);
printf("\n");
}
else
{
printf("The device selected is RAID PhysDisk %d\n\n", physdisk);
port->raidPassthru = 1;
}
port->raidBus = bus;
port->raidTarget = target;
port->raidPhysdisk = physdisk;
}
if (doVerify(port, bus, target, lun, lbn, lbns, 0, NULL, 0) == 1)
{
printf("Verify successful\n\n");
}
else
{
printf("Verify failed\n\n");
}
}
return 1;
}
int
doDiagnosticPageTest(MPT_PORT *port)
{
int bus;
int target;
int lun;
int page;
unsigned char data[1024];
int i;
int n;
int t;
int value;
int changed;
while (TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
printf("LUN: [0-%d or RETURN to quit] ", port->maxLuns - 1);
lun = getNumberAnswer(0, port->maxLuns - 1, -1);
if (lun < 0)
return 1;
printf("Diagnostic Page: [00-FF or RETURN to quit] ");
page = getNumberAnswerHex(0x00, 0xff, -1);
if (page < 0)
return 1;
printf("\n");
t = doReceiveDiagnosticResults(port, bus, target, lun, page, data, sizeof data);
n = get2bytes(data, 2) + 4;
if (t == 1)
{
printf("%d bytes of Page %x Data returned\n\n", n, page);
if (n > sizeof data)
{
printf("Too much data received, only %d bytes will be displayed\n\n", (int)sizeof data);
n = sizeof data;
t = 0;
}
displayByteData(data, n);
if (t && (page == 0x02 ||
page == 0x04 ||
page == 0x0c ||
page == 0x0e ||
page == 0x0f ||
page >= 0x10))
{
printf("\nDo you want to make changes? [Yes or No, default is No] ");
if (getYesNoAnswer(0) == 1)
{
changed = FALSE;
while (TRUE)
{
printf("\nEnter offset of value to change: [00-%02x or RETURN to quit] ", n - 1);
i = getNumberAnswerHex(0, n - 1, -1);
if (i < 0)
break;
printf("Enter value: [00-FF or RETURN to not change] ");
value = getNumberAnswerHex(0x00, 0xff, -1);
if (value < 0)
continue;
data[i] = (unsigned char)value;
changed = TRUE;
printf("\n");
displayByteData(data, n);
}
if (changed == TRUE)
{
printf("\nDo you want to write your changes? [Yes or No, default is No] ");
if (getYesNoAnswer(0) == 1)
{
if (doSendDiagnostic(port, bus, target, lun, data, n) != 1)
{
printf("Send Diagnostic (Page %x) failed\n", page);
}
}
}
}
}
}
else
{
printf("Receive Diagnostic Results (Page %x) failed\n", page);
}
printf("\n");
}
}
int
doInjectRepairMediaError(MPT_PORT *port, int inject)
{
int bus;
int target;
int lun;
int physdisk;
int sata;
U32 lbn;
unsigned char *buf;
int i;
int j;
int n;
int t;
int resid;
buf = malloc(1024);
while (TRUE)
{
port->raidPassthru = 0;
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
break;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
break;
printf("LUN: [0-%d or RETURN to quit] ", port->maxLuns - 1);
lun = getNumberAnswer(0, port->maxLuns - 1, -1);
if (lun < 0)
break;
printf("Logical block: [00000000-FFFFFFFF or RETURN to quit] ");
if (getHexNumberAnswer(&lbn) == 0)
break;
if (isRaidPhysDisk(port, bus, target, &physdisk))
{
printf("\nThe device selected is RAID PhysDisk %d\n", physdisk);
port->raidPassthru = 1;
port->raidBus = bus;
port->raidTarget = target;
port->raidPhysdisk = physdisk;
}
/* first try using WRITE LONG(10) with the WR_UNCOR bit set. For SATA devices
* this should get translated to WRITE UNCORRECTABLE EXT
* If a SATA device supports WRITE UNCORRECTABLE EXT, then word 120, bit 2 of
* the IDENTIFY data should be set
*/
if (inject)
{
printf("Attempting error injection via WRITE LONG(10) / ATA WRITE UNCORRECTABLE EXT\n");
if (doWriteLong(port, bus, target, lun, lbn, 0, NULL, 0, &resid) == 1 && resid == 0)
{
printf("\nWrite (inject) successful\n\n");
continue;
}
}
sata = isSata(port, bus, target);
if (sata)
{
n = 1024;
printf("Attempting error %s via SATA SCT / Long Sector Read/Write\n", inject ? "injection" : "repair");
if (doReadLongSata(port, bus, target, lun, lbn, 0, buf, n) != 1)
{
if (inject)
{
printf("\nRead failed\n\n");
continue;
}
printf("\nRead failed, can't preserve data\n");
n = 0;
}
}
else
{
n = 512;
if (doReadLong(port, bus, target, lun, lbn, 0, buf, n, &resid) != 1)
{
if (inject)
{
printf("\nRead failed\n\n");
continue;
}
printf("\nRead failed, can't preserve data\n");
n = 0;
}
else
{
n -= resid;
printf("\nActual block size is %d bytes\n", n);
if (doReadLong(port, bus, target, lun, lbn, 0, buf, n, &resid) != 1 || resid != 0)
{
if (inject)
{
printf("\nRead failed\n\n");
continue;
}
printf("\nRead failed, can't preserve data\n");
n = 0;
}
}
}
for (i = 0, j = 0; i < n/4; i++, j++)
{
if ((i % 128) == 0)
printf("\n");
if (j == 0)
printf("%04x : ", i*4);
printf("%08x ", get32x(((unsigned int *)buf)[i]));
if (j == 7)
{
printf("\n");
j = -1;
}
}
if (j != 0)
printf("\n");
if (inject)
{
for (i = 512; i < n; i++)
if (buf[i])
buf[i] = 0;
else
buf[i] = 1;
if (sata)
{
t = doWriteLongSata(port, bus, target, lun, lbn, 0, buf, n);
}
else
{
t = doWriteLong(port, bus, target, lun, lbn, 0, buf, n, &resid) == 1 && resid == 0;
}
}
else
{
t = doWrite(port, bus, target, lun, lbn, 1, 0, buf, 512) == 1;
}
if (t)
{
printf("\nWrite (%s) successful\n\n", inject ? "inject" : "repair");
}
else
{
printf("Write (%s) failed\n\n", inject ? "inject" : "repair");
}
}
free(buf);
return 1;
}
int
doSoftwareWriteProtect(MPT_PORT *port, int flag)
{
int bus;
int target;
int lun;
unsigned char data[4+12];
int n;
int t;
int offset = 4 + 4;
int bit = 3;
int mask;
char *mode = flag ? "set" : "clear";
mask = 1 << bit;
flag <<= bit;
while (TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
printf("LUN: [0-%d or RETURN to quit] ", port->maxLuns - 1);
lun = getNumberAnswer(0, port->maxLuns - 1, -1);
if (lun < 0)
return 1;
printf("\n");
t = doModeSense(port, bus, target, lun, 0x0a, 1, 1, data, sizeof data);
n = data[0] + 1;
if (t == 1 && n == sizeof data)
{
if (!(data[offset] & mask))
{
printf("Software Write Protect is not changeable!\n\n");
continue;
}
}
else
{
printf("Mode Sense (Changeable Control Mode Page) failed\n\n");
continue;
}
t = doModeSense(port, bus, target, lun, 0x0a, 0, 1, data, sizeof data);
n = data[0] + 1;
if (t == 1 && n == sizeof data)
{
if ((data[offset] & mask) == flag)
{
printf("Software Write Protect is already %s\n\n", mode);
continue;
}
else
{
data[0] = 0;
data[1] = 0;
data[2] = 0;
data[4] &= 0x3f;
data[offset] &= ~mask;
data[offset] |= flag;
if (doModeSelect(port, bus, target, lun, 0, data, sizeof data) != 1)
{
printf("Mode Select (Current Control Mode Page) failed\n\n");
continue;
}
}
}
else
{
printf("Mode Sense (Current Control Mode Page) failed\n\n");
continue;
}
printf("Software Write Protect is now %s\n\n", mode);
}
}
int
doReadWriteCache(MPT_PORT *port, int flag)
{
int bus;
int target;
int lun;
unsigned char data[4+20];
int n;
int t;
int offset = 4 + 2;
int bit = (flag & 2) ? 2 : 0;
int mask;
char *type = (flag & 2) ? "Write" : "Read";
char *mode = (flag & 1) ? "enabled" : "disabled";
flag &= 1;
mask = 1 << bit;
flag <<= bit;
while (TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
printf("LUN: [0-%d or RETURN to quit] ", port->maxLuns - 1);
lun = getNumberAnswer(0, port->maxLuns - 1, -1);
if (lun < 0)
return 1;
printf("\n");
t = doModeSense(port, bus, target, lun, 0x08, 1, 1, data, sizeof data);
n = data[0] + 1;
if (t == 1 && n == sizeof data)
{
if (!(data[offset] & mask))
{
printf("%s Cache is not changeable!\n\n", type);
continue;
}
}
else
{
printf("Mode Sense (Changeable Caching Mode Page) failed\n\n");
continue;
}
t = doModeSense(port, bus, target, lun, 0x08, 0, 1, data, sizeof data);
n = data[0] + 1;
if (t == 1 && n == sizeof data)
{
if ((data[offset] & mask) == flag)
{
printf("%s Cache is already %s\n\n", type, mode);
continue;
}
else
{
data[0] = 0;
data[1] = 0;
data[2] = 0;
data[4] &= 0x3f;
data[offset] &= ~mask;
data[offset] |= flag;
if (doModeSelect(port, bus, target, lun, 0, data, sizeof data) != 1)
{
printf("Mode Select (Current Caching Mode Page) failed\n\n");
continue;
}
}
}
else
{
printf("Mode Sense (Current Caching Mode Page) failed\n\n");
continue;
}
printf("%s Cache is now %s\n\n", type, mode);
}
}
int
doDisplayPhyCounters(MPT_PORT *port)
{
SasIOUnitPage0_t *SASIOUnitPage0;
Mpi2SasIOUnitPage0_t *SASIOUnitPage0_2;
SasIOUnit0PhyData *SASIOUnit0PhyData;
SasPhyPage1_t SASPhyPage1;
SasExpanderPage0_t SASExpanderPage0;
SasExpanderPage1_t SASExpanderPage1;
U32 handle;
int length;
int phy;
int rate;
int link_up;
uint64_t count1;
uint64_t count2;
uint64_t count3;
uint64_t count4;
char buf[32];
unsigned char report_phy_error_log_req[12];
unsigned char report_phy_error_log_rsp[28];
SASIOUnitPage0 = getConfigPageAlloc(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0, &length);
if (SASIOUnitPage0 == NULL)
return 0;
SASIOUnitPage0_2 = (pMpi2SasIOUnitPage0_t)SASIOUnitPage0;
for (phy = 0; phy < SASIOUnitPage0->NumPhys; phy++)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, 1, phy, &SASPhyPage1, sizeof SASPhyPage1) == 1)
{
if (phy != 0)
printf("\n");
if (mpi2)
{
SASIOUnit0PhyData = (pSasIOUnit0PhyData)&SASIOUnitPage0_2->PhyData[phy];
rate = (SASIOUnit0PhyData->NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_LOGICAL) >>
MPI2_SAS_NEG_LINK_RATE_SHIFT_LOGICAL;
}
else
{
SASIOUnit0PhyData = (pSasIOUnit0PhyData)&SASIOUnitPage0->PhyData[phy];
rate = SASIOUnit0PhyData->NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL;
}
link_up = rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
rate == MPI_SAS_IOUNIT0_RATE_3_0 ||
rate == MPI2_SAS_NEG_LINK_RATE_6_0 ||
rate == MPI25_SAS_NEG_LINK_RATE_12_0;
printf("Adapter Phy %d: Link %s", phy, link_up ? "Up" : "Down");
count1 = get32(SASPhyPage1.InvalidDwordCount);
count2 = get32(SASPhyPage1.RunningDisparityErrorCount);
count3 = get32(SASPhyPage1.LossDwordSynchCount);
count4 = get32(SASPhyPage1.PhyResetProblemCount);
if (count1 || count2 || count3 || (link_up ? count4 : 0))
{
printf("\n");
format64bitDecimal(count1, buf, sizeof buf);
printf(" Invalid DWord Count %32s\n", buf);
format64bitDecimal(count2, buf, sizeof buf);
printf(" Running Disparity Error Count %32s\n", buf);
format64bitDecimal(count3, buf, sizeof buf);
printf(" Loss of DWord Synch Count %32s\n", buf);
format64bitDecimal(count4, buf, sizeof buf);
printf(" Phy Reset Problem Count %32s\n", buf);
}
else
{
printf(", No Errors\n");
}
}
}
handle = 0xffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, handle,
&SASExpanderPage0, sizeof SASExpanderPage0) != 1)
break;
handle = get16(SASExpanderPage0.DevHandle);
for (phy = 0; phy < SASExpanderPage0.NumPhys; phy++)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 1,
(MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM
<<MPI_SAS_EXPAND_PGAD_FORM_SHIFT) +
(phy << MPI_SAS_EXPAND_PGAD_HPN_SHIFT_PHY) + handle,
&SASExpanderPage1, sizeof SASExpanderPage1) != 1)
continue;
memset(report_phy_error_log_req, 0, sizeof report_phy_error_log_req);
report_phy_error_log_req[0] = 0x40;
report_phy_error_log_req[1] = 0x11;
report_phy_error_log_req[2] = 0xff;
report_phy_error_log_req[9] = phy;
if (doSmpPassthrough(port, SASExpanderPage0.PhysicalPort, SASExpanderPage0.SASAddress,
report_phy_error_log_req, sizeof report_phy_error_log_req,
report_phy_error_log_rsp, sizeof report_phy_error_log_rsp, NULL) == 1)
{
if (report_phy_error_log_rsp[2] == 0x01)
break;
if (report_phy_error_log_rsp[2] != 0)
{
printf("Report Phy Error Log failed with result %02x\n", report_phy_error_log_rsp[2]);
continue;
}
printf("\n");
if (mpi2)
rate = (SASExpanderPage1.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_LOGICAL) >>
MPI2_SAS_NEG_LINK_RATE_SHIFT_LOGICAL;
else
rate = SASExpanderPage1.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL;
link_up = rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
rate == MPI_SAS_IOUNIT0_RATE_3_0 ||
rate == MPI2_SAS_NEG_LINK_RATE_6_0 ||
rate == MPI25_SAS_NEG_LINK_RATE_12_0;
printf("Expander (Handle %04x) Phy %d: Link %s", handle, phy, link_up ? "Up" : "Down");
count1 = get4bytes(report_phy_error_log_rsp, 12);
count2 = get4bytes(report_phy_error_log_rsp, 16);
count3 = get4bytes(report_phy_error_log_rsp, 20);
count4 = get4bytes(report_phy_error_log_rsp, 24);
if (count1 || count2 || count3 || (link_up ? count4 : 0))
{
printf("\n");
format64bitDecimal(count1, buf, sizeof buf);
printf(" Invalid DWord Count %32s\n", buf);
format64bitDecimal(count2, buf, sizeof buf);
printf(" Running Disparity Error Count %32s\n", buf);
format64bitDecimal(count3, buf, sizeof buf);
printf(" Loss of DWord Synch Count %32s\n", buf);
format64bitDecimal(count4, buf, sizeof buf);
printf(" Phy Reset Problem Count %32s\n", buf);
}
else
{
printf(", No Errors\n");
}
}
else
{
printf("Report Phy Error Log failed\n");
break;
}
}
}
free(SASIOUnitPage0);
return 1;
}
int
doClearPhyCounters(MPT_PORT *port)
{
SasIoUnitControlRequest_t req;
SasIoUnitControlReply_t rep;
SasIOUnitPage0_t *SASIOUnitPage0;
SasExpanderPage0_t SASExpanderPage0;
SasExpanderPage1_t SASExpanderPage1;
U32 handle;
int length;
int phy;
unsigned char phy_control_req[40];
unsigned char phy_control_rsp[4];
SASIOUnitPage0 = getConfigPageAlloc(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0, &length);
if (SASIOUnitPage0 == NULL)
return 0;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
req.Operation = MPI_SAS_OP_PHY_CLEAR_ERROR_LOG;
for (phy = 0; phy < SASIOUnitPage0->NumPhys; phy++)
{
req.PhyNum = phy;
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME) != 1)
printf("Failed to clear phy %d counters!\n", phy);
else
printf("Adapter Phy %d counters have been cleared\n", phy);
}
handle = 0xffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, handle,
&SASExpanderPage0, sizeof SASExpanderPage0) != 1)
break;
handle = get16(SASExpanderPage0.DevHandle);
for (phy = 0; phy < SASExpanderPage0.NumPhys; phy++)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 1,
(MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM
<<MPI_SAS_EXPAND_PGAD_FORM_SHIFT) +
(phy << MPI_SAS_EXPAND_PGAD_HPN_SHIFT_PHY) + handle,
&SASExpanderPage1, sizeof SASExpanderPage1) != 1)
continue;
memset(phy_control_req, 0, sizeof phy_control_req);
phy_control_req[0] = 0x40;
phy_control_req[1] = 0x91;
phy_control_req[2] = 0xff;
phy_control_req[9] = phy;
phy_control_req[10] = 0x05;
if (doSmpPassthrough(port, SASExpanderPage0.PhysicalPort, SASExpanderPage0.SASAddress,
phy_control_req, sizeof phy_control_req,
phy_control_rsp, sizeof phy_control_rsp, NULL) == 1)
{
if (phy_control_rsp[2] == 0x01)
break;
if (phy_control_rsp[2] != 0)
{
printf("Clear Phy Error Log failed with result %02x\n", phy_control_rsp[2]);
continue;
}
printf("Expander (Handle %04x) Phy %d counters have been cleared\n", handle, phy);
}
else
{
printf("Clear Phy Error Log failed\n");
break;
}
}
}
free(SASIOUnitPage0);
return 1;
}
int
doSataIdentifyDeviceTest(MPT_PORT *port)
{
int bus;
int target;
unsigned char id[512];
int i;
int j;
int t;
char c[21];
while (TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
if (!isSata(port, bus, target))
{
printf("\nCan't do Identify Device, device is not SATA!\n\n");
continue;
}
{
SataPassthroughRequest_t req;
SataPassthroughReply_t rep;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SATA_PASSTHROUGH;
req.PassthroughFlags = set16(MPI_SATA_PT_REQ_PT_FLAGS_PIO | MPI_SATA_PT_REQ_PT_FLAGS_READ);
req.DataLength = set32(sizeof id);
req.CommandFIS[0] = 0x27;
req.CommandFIS[1] = 0x80;
req.CommandFIS[2] = 0xec;
setName(port, bus, target, &req);
if (doMptCommandCheck(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
id, sizeof id, NULL, 0, SHORT_TIME) != 1)
{
printf("SataPassThrough failed!\n");
t = 0;
}
else
t = 1;
}
if (t == 1)
{
printf("\n%d words of Identify Device Data returned\n\n", (int)(sizeof id / 2));
for (i = 0, j = 0; i < sizeof id; i++, j++)
{
if (j == 0)
printf("%3d : ", i / 2);
if (i & 1)
printf("%02x ", id[i^1]);
else
printf("%02x", id[i^1]);
if (!isprint(id[i^1]))
c[j] = ' ';
else
c[j] = id[i^1];
if (j == sizeof c - 2)
{
c[j+1] = 0;
printf(" %s\n", c);
j = -1;
}
}
if (j != 0)
{
c[j] = 0;
for (i = j; i < sizeof c - 1; i++)
if (i & 1)
printf(" ");
else
printf(" ");
printf(" %s\n", c);
}
}
else
{
printf("Identify Device failed\n");
}
printf("\n");
}
}
int
doSataClearAffiliationTest(MPT_PORT *port)
{
SasDevicePage0_t SASDevicePage0;
SasExpanderPage0_t SASExpanderPage0;
int bus;
int target;
int b_t;
int dev_handle;
int address;
int info;
int parent;
unsigned char report_phy_sata_req[12];
unsigned char report_phy_sata_rsp[56];
unsigned char phy_control_req[40];
unsigned char phy_control_rsp[4];
while (TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
printf("\n");
if (mpi2)
{
if (mapBusTargetToDevHandle(port, bus, target, &dev_handle) != 1)
dev_handle = 0;
address = MPI2_SAS_DEVICE_PGAD_FORM_HANDLE + dev_handle;
}
else
{
b_t = (bus << 8) + target;
address = (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
<<MPI_SAS_DEVICE_PGAD_FORM_SHIFT) + b_t;
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, address,
&SASDevicePage0, sizeof SASDevicePage0) != 1)
{
printf("Can't get device data, device might not exist!\n\n");
continue;
}
info = get32(SASDevicePage0.DeviceInfo);
if (!(info & MPI_SAS_DEVICE_INFO_SATA_DEVICE))
{
printf("Can't do Clear Affiliation, device is not SATA!\n\n");
continue;
}
if (info & MPI_SAS_DEVICE_INFO_DIRECT_ATTACH)
{
printf("Can't do Clear Affiliation, device is directly attached!\n\n");
continue;
}
parent = get16(SASDevicePage0.ParentDevHandle);
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0,
(MPI_SAS_EXPAND_PGAD_FORM_HANDLE
<<MPI_SAS_EXPAND_PGAD_FORM_SHIFT) + parent,
&SASExpanderPage0, sizeof SASExpanderPage0) != 1)
{
printf("Can't get expander data, device might not exist!\n\n");
continue;
}
memset(report_phy_sata_req, 0, sizeof report_phy_sata_req);
report_phy_sata_req[0] = 0x40;
report_phy_sata_req[1] = 0x12;
report_phy_sata_req[2] = 0xff;
report_phy_sata_req[9] = SASDevicePage0.PhyNum;
if (doSmpPassthrough(port, SASExpanderPage0.PhysicalPort, SASExpanderPage0.SASAddress,
report_phy_sata_req, sizeof report_phy_sata_req,
report_phy_sata_rsp, sizeof report_phy_sata_rsp, NULL) == 1)
{
if (report_phy_sata_rsp[2] != 0)
{
printf("Report Phy SATA failed with result %02x\n\n", report_phy_sata_rsp[2]);
continue;
}
if (!(report_phy_sata_rsp[11] & 2))
{
printf("Affiliations not supported by this SATA device!\n\n");
continue;
}
if (!(report_phy_sata_rsp[11] & 1))
{
printf("No affiliation active for this SATA device!\n\n");
continue;
}
}
else
{
printf("Report Phy SATA failed\n\n");
continue;
}
memset(phy_control_req, 0, sizeof phy_control_req);
phy_control_req[0] = 0x40;
phy_control_req[1] = 0x91;
phy_control_req[2] = 0xff;
phy_control_req[9] = SASDevicePage0.PhyNum;
phy_control_req[10] = 0x06;
if (doSmpPassthrough(port, SASExpanderPage0.PhysicalPort, SASExpanderPage0.SASAddress,
phy_control_req, sizeof phy_control_req,
phy_control_rsp, sizeof phy_control_rsp, NULL) == 1)
{
if (phy_control_rsp[2] != 0)
{
printf("Clear Affiliation failed with result %02x\n\n", report_phy_sata_rsp[2]);
continue;
}
}
else
{
printf("Clear Affiliation failed\n\n");
continue;
}
}
}
int
doSataSmartReadTest(MPT_PORT *port)
{
int bus;
int target;
unsigned char data[512];
int i;
int j;
int t;
char c[21];
while (TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
if (!isSata(port, bus, target))
{
printf("\nCan't do SMART Read, device is not SATA!\n\n");
continue;
}
{
SataPassthroughRequest_t req;
SataPassthroughReply_t rep;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SATA_PASSTHROUGH;
req.PassthroughFlags = set16(MPI_SATA_PT_REQ_PT_FLAGS_PIO | MPI_SATA_PT_REQ_PT_FLAGS_READ);
req.DataLength = set32(sizeof data);
req.CommandFIS[0] = 0x27;
req.CommandFIS[1] = 0x80;
req.CommandFIS[2] = 0xb0;
req.CommandFIS[3] = 0xd0;
req.CommandFIS[5] = 0x4f;
req.CommandFIS[6] = 0xc2;
setName(port, bus, target, &req);
if (doMptCommandCheck(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
data, sizeof data, NULL, 0, SHORT_TIME) != 1)
{
printf("SataPassThrough failed!\n");
t = 0;
}
else
t = 1;
}
if (t == 1)
{
printf("\n%d words of SMART Read Data returned\n\n", (int)(sizeof data / 2));
for (i = 0, j = 0; i < sizeof data; i++, j++)
{
if (j == 0)
printf("%3d : ", i / 2);
if (i & 1)
printf("%02x ", data[i^1]);
else
printf("%02x", data[i^1]);
if (!isprint(data[i^1]))
c[j] = ' ';
else
c[j] = data[i^1];
if (j == sizeof c - 2)
{
c[j+1] = 0;
printf(" %s\n", c);
j = -1;
}
}
if (j != 0)
{
c[j+1] = 0;
for (i = j; i < sizeof c - 1; i++)
if (i & 1)
printf(" ");
else
printf(" ");
printf(" %s\n", c);
}
}
else
{
printf("SMART Read failed\n");
}
printf("\n");
}
}
int
doSepTest(MPT_PORT *port)
{
SEPRequest_t req;
SEPReply_t rep;
int bus;
int target;
int handle;
int slot;
int flags = MPI_SEP_REQ_FLAGS_BUS_TARGETID_ADDRESS;
U32 status;
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
printf("Use Enclosure/Slot, not Bus/Target, addressing? [Yes or No, default is Yes] ");
if (getYesNoAnswer(1) == 1)
{
flags = MPI_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS;
}
}
while (TRUE)
{
if (flags == MPI_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS)
{
printf("Enclosure handle: [0000-FFFF or RETURN to quit] ");
handle = getNumberAnswerHex(0x0000, 0xffff, -1);
if (handle < 0)
return 1;
printf("Slot: [0-255 or RETURN to quit] ");
slot = getNumberAnswer(0, 255, -1);
if (slot < 0)
return 1;
bus = 0;
target = 0;
}
else
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
handle = 0;
slot = 0;
}
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
req.Flags = flags;
req.EnclosureHandle = set16(handle);
req.Slot = set16(slot);
setName(port, bus, target, &req);
req.Action = MPI_SEP_REQ_ACTION_READ_STATUS;
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
{
printf("SCSI Enclosure Processor Read Status failed!\n");
}
else
{
status = get32(rep.SlotStatus);
printf("\nSlot Status = %08x\n", status);
printf("\nDo you want to change the Slot Status? [Yes or No, default is No] ");
if (getYesNoAnswer(0) == 1)
{
printf("Enter value: [00000000-FFFFFFFF or RETURN to skip] ");
if (parseHexNumberChange(&status) == 1)
{
req.Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
req.SlotStatus = set32(status);
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
{
printf("SCSI Enclosure Processor Write Status failed!\n");
}
}
}
}
printf("\n");
}
}
int
doProdSpecSasIoUnitControl(MPT_PORT *port)
{
SasIoUnitControlRequest_t req;
SasIoUnitControlReply_t rep;
int iocparameter;
U32 iocparametervalue;
int devhandle;
if (mpi2)
{
return doProdSpecSasIoUnitControl2(port);
}
while (TRUE)
{
printf("Enter IOC Parameter: [80-FF or RETURN to quit] ");
iocparameter = getNumberAnswerHex(0x80, 0xff, -1);
if (iocparameter < 0)
return 1;
printf("Enter IOC Parameter: [00000000-FFFFFFFF or RETURN if not needed] ");
if (getHexNumberAnswer(&iocparametervalue) == 0)
iocparametervalue = 0;
printf("Enter DevHandle: [0000-FFFF or RETURN if not needed] ");
devhandle = getNumberAnswerHex(0x0000, 0xffff, 0);
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
req.Operation = MPI_SAS_OP_SET_IOC_PARAMETER;
req.IOCParameter = iocparameter;
req.IOCParameterValue = set32(iocparametervalue);
req.DevHandle = set16(devhandle);
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
printf("Failed to issue product-specific SAS IO Unit Control request!\n");
printf("\n");
}
}
int
doProdSpecSasIoUnitControl2(MPT_PORT *port)
{
Mpi2SasIoUnitControlRequest_t req;
Mpi2SasIoUnitControlReply_t rep;
int iocparameter;
U32 iocparametervalue;
int devhandle;
while (TRUE)
{
printf("Enter IOC Parameter: [80-FF or RETURN to quit] ");
iocparameter = getNumberAnswerHex(0x80, 0xff, -1);
if (iocparameter < 0)
return 1;
printf("Enter IOC Parameter: [00000000-FFFFFFFF or RETURN if not needed] ");
if (getHexNumberAnswer(&iocparametervalue) == 0)
iocparametervalue = 0;
printf("Enter DevHandle: [0000-FFFF or RETURN if not needed] ");
devhandle = getNumberAnswerHex(0x0000, 0xffff, 0);
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
req.Operation = MPI2_SAS_OP_SET_IOC_PARAMETER;
req.IOCParameter = iocparameter;
req.IOCParameterValue = set32(iocparametervalue);
req.DevHandle = set16(devhandle);
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
printf("Failed to issue product-specific SAS IO Unit Control request!\n");
printf("\n");
}
}
int
doDiagDataUpload(MPT_PORT *port)
{
ToolboxDiagDataUploadRequest_t req;
ToolboxReply_t rep;
U32 flags;
DiagDataUploadHeader_t *header;
unsigned char *buf;
int length;
FILE *file;
char name[256];
int n;
int binary = 0;
int binfile;
int i;
int j;
printf("Enter flags: [00000000-FFFFFFFF or RETURN if not needed] ");
if (getHexNumberAnswer(&flags) == 0)
flags = 0;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_TOOLBOX;
req.Tool = MPI_TOOLBOX_DIAG_DATA_UPLOAD_TOOL;
req.Flags = set32(flags);
printf("\nUploading diagnostic data...\n");
length = 16384 + sizeof *header;
buf = malloc(length);
if (doMptCommandCheck(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
buf, length, NULL, 0, SHORT_TIME) != 1)
{
printf("Failed to upload diagnostic data!\n");
return 0;
}
header = (pDiagDataUploadHeader_t)buf;
length = get32(header->DiagDataLength);
printf("%d bytes of data uploaded\n", length);
if (length)
{
if (numFileNames)
{
n = getFileName(name, sizeof name, stdin, "output", 0);
}
else
{
printf("\nEnter output filename, or RETURN to send output to the screen: ");
n = getString(name, sizeof name, stdin);
}
if (n > 0)
{
if (gFlag == TRUE)
{
printf("File type: [0=ASCII, 1=Binary, default is 0] ");
binary = getNumberAnswer(0, 1, 0);
}
if (binary)
{
binfile = open(name, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, 0644);
if (binfile < 0)
{
printf("Open failure for file %s\n", name);
perror("Error is");
return 0;
}
if (write(binfile, buf, length));
close(binfile);
return 1;
}
else
{
file = fopen(name, "w");
if (file == NULL)
{
printf("Open failure for file %s\n", name);
perror("Error is");
return 0;
}
}
}
else
{
file = stdout;
printf("\n");
}
for (i = 0, j = 0; i < length/4; i++, j++)
{
if (j == 0)
fprintf(file, "%04x : ", i*4);
fprintf(file, "%08x ", get32x(((unsigned int *)buf)[i]));
if (j == 7)
{
fprintf(file, "\n");
j = -1;
}
}
if (j != 0)
fprintf(file, "\n");
if (file != stdout)
fclose(file);
}
free(buf);
return 1;
}
int
doReportLunsTest(MPT_PORT *port)
{
int bus;
int target;
int len;
unsigned char *luns;
int i;
int n;
int t;
len = 8 + 256 + 8;
luns = malloc(len);
while (TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
break;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
break;
printf("\n");
t = doReportLuns(port, bus, target, luns, len);
n = get4bytes(luns, 0) / 8;
if (t == 1)
{
if (n > 256)
{
printf("%d LUNs reported for this device, only 256 LUNs will be displayed\n\n", n);
n = 256;
}
printf("LUN List: ");
for (i = 0; i < n; i++)
{
printf(" %d", get2bytes(luns, (i + 1) * 8));
}
printf("\n");
}
else
{
printf("Report LUNs failed\n");
}
printf("\n");
}
free(luns);
return 1;
}
int
doDriveFirmwareDownload(MPT_PORT *port)
{
int bus;
int target;
int n;
char name[256];
unsigned char *imageBuf = NULL;
int imageLen;
int size;
unsigned char *buf;
int len;
int offset;
int mode;
int id;
if (selectDevice(port, &bus, &target) != 1)
return 0;
n = getFileName(name, sizeof name, stdin, "drive firmware", 0);
if (n > 0)
{
if (readFile(name, &imageBuf, &imageLen) != 1)
return 0;
}
else
{
printf("Image won't be downloaded\n");
return 1;
}
mode = isSata(port, bus, target) ? 5 : 7;
printf("Mode: [0-31, default is %d] ", mode);
mode = getNumberAnswer(0, 31, mode);
printf("BufferID: [0-255, default is 0] ");
id = getNumberAnswer(0, 255, 0);
if (yesFlag == FALSE)
{
printf("\nDo you want to continue? [Yes or No, default is No] ");
if (getYesNoAnswer(0) != 1)
{
free(imageBuf);
return 0;
}
}
printf("\nDownloading image...\n");
buf = imageBuf;
len = imageLen;
offset = 0;
while (len > 0)
{
if (mode == 5)
size = len;
else
size = min(len, 0x20000);
if (doWriteBufferFull(port, bus, target, 0, mode, id, offset, buf, size) != 1)
{
printf("Download failed\n");
if (wFlag)
fprintf(logFile, "%s: Drive Firmware Download (DRIVE_FW_DOWNLOAD): FAIL\n",
logPrefix(port));
return 0;
}
buf += size;
len -= size;
offset += size;
}
printf("Download succeeded\n");
if (wFlag)
fprintf(logFile, "%s: Drive Firmware Download (DRIVE_FW_DOWNLOAD) of size %x: PASS\n",
logPrefix(port), imageLen);
free(imageBuf);
return 1;
}
int
doSesDownloadMicrocode(MPT_PORT *port, int bus, int target, int lun,
int mode, int id, int offset, int size, unsigned char *buf, int len)
{
unsigned char *data;
int n;
int t;
n = ((len + 3) & ~3) + 24;
data = malloc(n);
t = n - 4;
memset(data, 0, 24);
data[0] = 0x0e;
data[2] = t >> 8;
data[3] = t;
data[8] = mode;
data[11] = id;
data[12] = offset >> 24;
data[13] = offset >> 16;
data[14] = offset >> 8;
data[15] = offset;
data[16] = size >> 24;
data[17] = size >> 16;
data[18] = size >> 8;
data[19] = size;
data[20] = len >> 24;
data[21] = len >> 16;
data[22] = len >> 8;
data[23] = len;
memcpy(data + 24, buf, len);
t = doSendDiagnostic(port, bus, target, lun, data, n);
free(data);
return t;
}
int
doExpanderChangeMfgDataFields(MPT_PORT *port)
{
int bus;
int target;
int expanderType;
if (selectExpander(port, &bus, &target, NULL, NULL, &expanderType) != 1)
return 0;
if (bus == -1 && target == -1)
{
printf("Sorry, 'all' is not a valid selection for this operation\n");
return 0;
}
if (expanderType != EXPANDER_TYPE_LSI_GEN2_BOBCAT &&
expanderType != EXPANDER_TYPE_LSI_GEN3_COBRA)
{
printf("This option is only supported on LSI SAS2/SAS3 expanders (Bobcat/Cobra).\n");
return 0;
}
return doExpanderGetSetMfgDataFields(port, bus, target, NULL, NULL, NULL);
}
/* fetch the expander SAS address, enclosure logical ID, and ethernet MAC address from
* the bobcat or cobra expander manufacturing data and return in sasAddr, enclLogId, and macAddr.
* If sasAddr, enclLogId, and macAddr are all NULL then interactively prompt for new
* addresses and program them into the expander's manufacturing data
*/
int
doExpanderGetSetMfgDataFields(MPT_PORT *port, int bus, int target, U64 *sasAddr, U64 *enclLogId, U8 *macAddr)
{
unsigned char desc[4];
unsigned char *imageBuf = NULL;
unsigned char *buf;
int imageLen;
int offset;
U16 pageId;
U16 pageLength;
U8 checksum8;
int i, x;
U64 sas_address;
U64 logical_id;
U8 mac_address[6];
int mac_address_int[6];
char mac_address_ascii[32];
int prompt;
int enclIdPageOffset = 0;
int addrPageOffset = 0;
int etherPageOffset = 0;
int haveChange;
if (!sasAddr && !enclLogId && !macAddr)
prompt = TRUE;
else
prompt = FALSE;
haveChange = FALSE;
sas_address.High = 0;
sas_address.Low = 0;
logical_id.High = 0;
logical_id.Low = 0;
memset(mac_address, 0, sizeof mac_address);
if (doReadBufferFull(port, bus, target, 0, 3, 1, 0, desc, sizeof desc) == 1)
{
imageLen = get3bytes(desc, 1);
}
else
{
printf("Can't read current manufacturing data, unknown buffer length.\n");
return 0;
}
imageBuf = (unsigned char *)malloc(imageLen);
if (doReadBufferFull(port, bus, target, 0, 2, 1, 0, imageBuf, imageLen) == 1)
{
buf = imageBuf;
offset = buf[3]; //get the start offset of the first config page from the region header
if ( offset == 0xFF )
{
printf("WARNING: The expander's manufacturing region does not appear to have valid data\n");
free(imageBuf);
return 0;
}
buf += offset;
while ( offset+8 < imageLen )
{
checksum8 = 0;
pageLength = get16x(((U16 *)buf)[2]);
pageId = get16x(((U16 *)buf)[3]);
if (pageLength == 0xFFFF && pageId == 0xFFFF)
break;
for( i=0; i<pageLength; i++ )
{
checksum8 += buf[i+4];
}
//sas address config page
if (pageId == 0xFF00 && pageLength == 0xC)
{
if (checksum8 == buf[1])
{
sas_address.High = get32x(((U32 *)buf)[2]);
sas_address.Low = get32x(((U32 *)buf)[3]);
addrPageOffset = offset;
}
else
{
printf("Found SAS address config page, but checksum is invalid!\n");
}
}
//unit specific sas address page
if (pageId == 0xFE00 && pageLength == 0xC)
{
if (checksum8 == buf[1])
{
sas_address.High = get32x(((U32 *)buf)[2]);
sas_address.Low = get32x(((U32 *)buf)[3]);
addrPageOffset = offset;
}
else
{
printf("Found unit specific SAS address config page, but checksum is invalid!\n");
}
}
// report general config page
if (pageId == 0xFF02 && pageLength == 0xC)
{
if (checksum8 == buf[1])
{
logical_id.High = get32x(((U32 *)buf)[2]);
logical_id.Low = get32x(((U32 *)buf)[3]);
enclIdPageOffset = offset;
}
else
{
printf("Found Report General config page, but checksum is invalid!\n");
}
}
// unit specific report general config page
if (pageId == 0xFE01 && pageLength == 0xC)
{
if (checksum8 == buf[1])
{
logical_id.High = get32x(((U32 *)buf)[2]);
logical_id.Low = get32x(((U32 *)buf)[3]);
enclIdPageOffset = offset;
}
else
{
printf("Found unit specific Report General config page, but checksum is invalid!\n");
}
}
// ethernet config page
if (pageId == 0xFF10 && pageLength >= 0x24)
{
if (checksum8 == buf[1])
{
memcpy(mac_address, &buf[20], sizeof mac_address );
etherPageOffset = offset;
}
else
{
printf("Found Ethernet config page, but checksum is invalid!\n");
}
}
// unit specific ethernet config page
if (pageId == 0xFE05 && pageLength == 0xC)
{
if (checksum8 == buf[1])
{
memcpy(mac_address, &buf[8], sizeof mac_address );
etherPageOffset = offset;
}
else
{
printf("Found unit specific Ethernet config page, but checksum is invalid!\n");
}
}
offset += pageLength + 4;
buf += pageLength + 4;
}
if (prompt)
{
printf("Current SAS Address is %08x%08x\n", sas_address.High, sas_address.Low);
printf("Enter new SAS Address: [16 hex digits or RETURN to skip] ");
i = getHexDoubleNumberAnswer(&(sas_address.High), &(sas_address.Low));
if (i != 0)
{
haveChange = TRUE;
buf = imageBuf + addrPageOffset;
checksum8 = 0;
pageLength = get16x(((U16 *)buf)[2]);
// displayByteData(buf, pageLength+4);
((U32 *)buf)[2] = set32x(sas_address.High);
((U32 *)buf)[3] = set32x(sas_address.Low);
for( i=0; i < pageLength; i++ )
{
checksum8 += buf[i+4];
}
buf[1] = checksum8;
// displayByteData(buf, pageLength+4);
}
printf("Current Enclosure Logical ID is %08x%08x\n", logical_id.High, logical_id.Low);
printf("Enter new Enclosure Logical ID: [16 hex digits or RETURN to skip] ");
i = getHexDoubleNumberAnswer(&(logical_id.High), &(logical_id.Low));
if (i != 0)
{
haveChange = TRUE;
buf = imageBuf + enclIdPageOffset;
checksum8 = 0;
pageLength = get16x(((U16 *)buf)[2]);
// displayByteData(buf, pageLength+4);
((U32 *)buf)[2] = set32x(logical_id.High);
((U32 *)buf)[3] = set32x(logical_id.Low);
for( i=0; i < pageLength; i++ )
{
checksum8 += buf[i+4];
}
buf[1] = checksum8;
// displayByteData(buf, pageLength+4);
}
printf("Current Ethernet MAC Address is %02x-%02x-%02x-%02x-%02x-%02x\n",
mac_address[0],mac_address[1],mac_address[2],
mac_address[3],mac_address[4],mac_address[5]);
i = 0;
while ( TRUE )
{
printf("Enter new MAC Address: [or RETURN to skip] ");
i = getStringFromArgs(mac_address_ascii, sizeof mac_address_ascii, stdin);
if (i == 0)
break;
if ((sscanf(mac_address_ascii, "%x-%x-%x-%x-%x-%x",
&mac_address_int[0],&mac_address_int[1],&mac_address_int[2],
&mac_address_int[3],&mac_address_int[4],&mac_address_int[5]) == 6) &&
mac_address_int[0] <= 0xFF && mac_address_int[1] <= 0xFF &&
mac_address_int[2] <= 0xFF && mac_address_int[3] <= 0xFF &&
mac_address_int[4] <= 0xFF && mac_address_int[5] <= 0xFF &&
i <= 17)
{
for (x = 0; x < 6; x++)
mac_address[x] = mac_address_int[x];
break;
}
else
printf("Invalid MAC Address. Please enter a MAC Address in the form xx-xx-xx-xx-xx-xx\n");
}
if (i != 0)
{
haveChange = TRUE;
buf = imageBuf + etherPageOffset;
checksum8 = 0;
pageLength = get16x(((U16 *)buf)[2]);
pageId = get16x(((U16 *)buf)[3]);
// displayByteData(buf, pageLength+4);
if (pageId == 0xFF10)
memcpy(&buf[20], mac_address, sizeof mac_address);
else // pageId == 0xFE05
memcpy(&buf[8], mac_address, sizeof mac_address);
for( i=0; i < pageLength; i++ )
{
checksum8 += buf[i+4];
}
buf[1] = checksum8;
// displayByteData(buf, pageLength+4);
}
if (haveChange)
{
if (yesFlag == FALSE)
{
printf("\nDo you want to continue? [Yes or No, default is No] ");
if (getYesNoAnswer(0) != 1)
{
free(imageBuf);
return 0;
}
}
i = doWriteBufferFull(port, bus, target, 0, 2, 1, 0, imageBuf, imageLen);
}
else
i = 2;
if (i == 1)
{
printf("\nWriting changes...Success!\n");
}
else if (i == 2)
{
printf("\nNothing to do, no changes made.\n");
}
else
{
printf("Writing changes failed\n");
free(imageBuf);
return 0;
}
}
else
{
if (sasAddr)
*sasAddr = sas_address;
if (enclLogId)
*enclLogId = logical_id;
if (macAddr)
memcpy(macAddr, mac_address, sizeof mac_address);
}
free(imageBuf);
return 1;
}
else
{
printf("Error reading manufacturing data from expander.\n");
free(imageBuf);
return 0;
}
}
int
doExpanderFirmwareDownload(MPT_PORT *port)
{
int bus;
int target;
int n;
int t;
char name[256];
unsigned char *imageBuf = NULL;
int imageLen;
int size;
unsigned char *buf;
int len;
int offset;
int mode;
int id;
unsigned char *imageBufUpload = NULL;
int imageLenUpload;
MpiFwHeader_t *fwHeader;
U32 checksum32;
U8 checksum8;
int i, x;
int warn = 0;
int updateAll = FALSE;
int curr;
int expanderType;
int imageType;
int foundYeti;
int foundBobcat;
int foundCobra;
int foundOther;
int updateChoice;
int skip;
U64 currMfgSasAddr;
U64 currMfgEnclLogId;
U8 currMfgMACAddr[6];
U64 newMfgSasAddr;
U64 newMfgEnclLogId;
U8 newMfgMACAddr[6];
U64 mfgSasAddr;
U64 mfgEnclLogId;
U8 mfgMACAddr[6];
U16 pageLength;
U16 pageId;
int enclIdPageOffset;
int addrPageOffset;
int etherPageOffset;
int choice;
int mac_address_int[6];
char mac_address_ascii[32];
if (selectExpander(port, &bus, &target, NULL, NULL, &expanderType) != 1)
return 0;
if (bus == -1 && target == -1)
updateAll = TRUE;
if (updateAll)
{
curr = -1;
foundYeti = FALSE;
foundBobcat = FALSE;
foundCobra = FALSE;
foundOther = FALSE;
while (TRUE)
{
curr++;
if (exp_targets[curr].bus == -1 && exp_targets[curr].target == -1)
break;
if (exp_targets[curr].expanderType == EXPANDER_TYPE_LSI_GEN1_YETI)
foundYeti = TRUE;
else if (exp_targets[curr].expanderType == EXPANDER_TYPE_LSI_GEN2_BOBCAT)
foundBobcat = TRUE;
else if (exp_targets[curr].expanderType == EXPANDER_TYPE_LSI_GEN3_COBRA)
foundCobra = TRUE;
else
foundOther = TRUE;
}
if (!foundYeti && !foundBobcat && !foundCobra)
{
printf("No supported LSI expanders found to update. The 'all' option to update all\n");
printf("expanders is only supported for LSI SAS1 (Yeti) and SAS2 (Bobcat) expanders.\n");
return 0;
}
if (foundYeti + foundBobcat + foundCobra > 1)
{
printf("More than one type of LSI expander was found. Only one type can be updated.\n");
printf("Which do you want to update? [0=SAS1 (Yeti), 1=SAS2 (Bobcat), 2=SAS3 (Cobra), default is 0] ");
updateChoice = getNumberAnswer(0, 2, 0);
if (updateChoice == 0)
expanderType = EXPANDER_TYPE_LSI_GEN1_YETI;
else if (updateChoice == 1)
expanderType = EXPANDER_TYPE_LSI_GEN2_BOBCAT;
else
expanderType = EXPANDER_TYPE_LSI_GEN3_COBRA;
}
else if (foundYeti)
expanderType = EXPANDER_TYPE_LSI_GEN1_YETI;
else if (foundBobcat)
expanderType = EXPANDER_TYPE_LSI_GEN2_BOBCAT;
else
expanderType = EXPANDER_TYPE_LSI_GEN3_COBRA;
if (foundOther)
{
printf("The 'all' option to update all expanders is only supported for LSI SAS1 (Yeti)\n");
printf("SAS2 (Bobcat), and SAS3 (Cobra) expanders. All other expanders will be ignored.\n");
}
}
n = getFileName(name, sizeof name, stdin, "expander firmware", 0);
if (n > 0)
{
if (readFile(name, &imageBuf, &imageLen) != 1)
return 0;
}
else
{
printf("Image won't be downloaded\n");
return 1;
}
printf("Mode: [0-31, default is 2] ");
mode = getNumberAnswer(0, 31, 2);
printf("BufferID: [0-255, default is 2] ");
id = getNumberAnswer(0, 255, 2);
if (id == 0 || id == 2 ||
(id == 0xe2 && (expanderType == EXPANDER_TYPE_LSI_GEN2_BOBCAT ||
expanderType == EXPANDER_TYPE_LSI_GEN3_COBRA)))
{
printWhatString("\nFirmware", imageBuf, imageLen);
fwHeader = (pMpiFwHeader_t)imageBuf;
if (get32(fwHeader->Signature0) == MPI_FW_HEADER_SIGNATURE_0 &&
get32(fwHeader->Signature1) == MPI_FW_HEADER_SIGNATURE_1 &&
get32(fwHeader->Signature2) == MPI_FW_HEADER_SIGNATURE_2)
{
imageType = EXPANDER_TYPE_LSI_GEN1_YETI;
}
else if (get32(fwHeader->Signature0) == BOBCAT_FW_HEADER_SIGNATURE_0 &&
get32(fwHeader->Signature1) == BOBCAT_FW_HEADER_SIGNATURE_1 &&
get32(fwHeader->Signature2) == BOBCAT_FW_HEADER_SIGNATURE_2)
{
imageType = EXPANDER_TYPE_LSI_GEN2_BOBCAT;
}
else if (get32(fwHeader->Signature0) == COBRA_FW_HEADER_SIGNATURE_0 &&
get32(fwHeader->Signature1) == COBRA_FW_HEADER_SIGNATURE_1 &&
get32(fwHeader->Signature2) == COBRA_FW_HEADER_SIGNATURE_2)
{
imageType = EXPANDER_TYPE_LSI_GEN3_COBRA;
}
else
{
if (!warn)
printf("\n");
printf("Image's signature is not valid!\n");
warn = 1;
imageType = EXPANDER_TYPE_UNKNOWN;
}
checksum32 = 0;
for (i = 0; i < imageLen / 4; i++)
checksum32 += get32x(((U32 *)imageBuf)[i]);
if (checksum32 != 0)
{
if (!warn)
printf("\n");
printf("Image's checksum is invalid!\n");
warn = 1;
}
if (imageType != expanderType)
{
if (!warn)
printf("\n");
printf("Image mismatch detected. The expander selected for updating is <%s>\n", printExpanderType(expanderType));
printf("and the firmware image is for <%s>!\n", printExpanderType(imageType));
warn = 1;
}
}
if (id == 10)
{
int header_okay = 0;
int record_okay = 0;
buf = imageBuf;
if (buf[0] == 0x01 && buf[1] == 0x21 && buf[2] == 0x41 && buf[3] == 0x61)
{
header_okay = 1;
buf += 64;
}
if (buf[0] == 'Y' && buf[1] == 'e' && buf[2] == 't' && buf[3] == 'i')
{
record_okay = 1;
}
if (!record_okay)
{
if (!warn)
printf("\n");
printf("Image's signature is not valid!\n");
warn = 1;
}
else
{
if (mode == 2)
{
if (!header_okay)
{
printf("\nImage header not found, creating it...\n");
buf = malloc(imageLen + 64);
memset(buf, 0, 64);
buf[0] = 0x01;
buf[1] = 0x21;
buf[2] = 0x41;
buf[3] = 0x61;
memcpy(buf + 64, imageBuf, imageLen);
free(imageBuf);
header_okay = 1;
imageBuf = buf;
imageLen += 64;
}
}
if (mode == 6 || mode == 7)
{
if (header_okay)
{
printf("\nImage header found, stripping it...\n");
buf = malloc(imageLen - 64);
memcpy(buf, imageBuf + 64, imageLen - 64);
free(imageBuf);
header_okay = 0;
imageBuf = buf;
imageLen -= 64;
}
}
}
t = header_okay ? 64 : 0;
checksum8 = 0;
for (i = t; i < t + 220; i++)
checksum8 += imageBuf[i];
if (checksum8 != 0)
{
if (!warn)
printf("\n");
printf("Image's checksum is invalid!\n");
checksum8 = imageBuf[i-1] - checksum8;
printf(" At offset %04x, value %02x should be %02x\n", i-1, imageBuf[i-1], checksum8);
warn = 1;
}
}
if ((expanderType == EXPANDER_TYPE_LSI_GEN2_BOBCAT || expanderType == EXPANDER_TYPE_LSI_GEN3_COBRA) &&
(id == 1 || id == 0xE3))
{
if (updateAll)
{
printf("Sorry, 'all' is not currently supported for updating LSI SAS2/SAS3 expander\n");
printf("manufacturing data.\n");
free(imageBuf);
return 0;
}
if (imageBuf[2] != 0x10)
{
printf("This image does not appear to be a valid manufacturing image for an LSI SAS2/SAS3 expander!\n");
warn = 1;
}
else
{
currMfgSasAddr.High = 0;
currMfgSasAddr.Low = 0;
currMfgEnclLogId.High = 0;
currMfgEnclLogId.Low = 0;
memset(currMfgMACAddr, 0, sizeof currMfgMACAddr);
/* get the current SAS address, enclosure logical ID, and ethernet MAC address from the Bobcat or Cobra mfg data */
doExpanderGetSetMfgDataFields(port, bus, target, &currMfgSasAddr, &currMfgEnclLogId, currMfgMACAddr);
newMfgSasAddr.High = 0;
newMfgSasAddr.Low = 0;
newMfgEnclLogId.High = 0;
newMfgEnclLogId.Low = 0;
memset(newMfgMACAddr, 0, sizeof newMfgMACAddr);
buf = imageBuf;
offset = buf[3];
buf += offset;
addrPageOffset = enclIdPageOffset = etherPageOffset = 0;
while ( offset+8 < imageLen )
{
checksum8 = 0;
pageLength = get16x(((U16 *)buf)[2]);
pageId = get16x(((U16 *)buf)[3]);
if (pageLength == 0xFFFF && pageId == 0xFFFF)
break;
if (pageLength == 0)
break;
for( i=0; i < pageLength; i++ )
{
checksum8 += buf[i+4];
}
//sas address config page
if (pageId == 0xFF00 && pageLength == 0xC)
{
if (checksum8 == buf[1])
{
newMfgSasAddr.High = get32x(((U32 *)buf)[2]);
newMfgSasAddr.Low = get32x(((U32 *)buf)[3]);
addrPageOffset = offset;
}
else
{
printf("Found SAS address config page in image, but checksum is invalid!\n");
}
}
//unit specific sas address page
if (pageId == 0xFE00 && pageLength == 0xC)
{
if (checksum8 == buf[1])
{
newMfgSasAddr.High = get32x(((U32 *)buf)[2]);
newMfgSasAddr.Low = get32x(((U32 *)buf)[3]);
addrPageOffset = offset;
}
else
{
printf("Found unit specific SAS address config page, but checksum is invalid!\n");
}
}
// report general config page
if (pageId == 0xFF02 && pageLength == 0xC)
{
if (checksum8 == buf[1])
{
newMfgEnclLogId.High = get32x(((U32 *)buf)[2]);
newMfgEnclLogId.Low = get32x(((U32 *)buf)[3]);
enclIdPageOffset = offset;
}
else
{
printf("Found Report General config page in image, but checksum is invalid!\n");
}
}
// unit specific report general config page
if (pageId == 0xFE01 && pageLength == 0xC)
{
if (checksum8 == buf[1])
{
newMfgEnclLogId.High = get32x(((U32 *)buf)[2]);
newMfgEnclLogId.Low = get32x(((U32 *)buf)[3]);
enclIdPageOffset = offset;
}
else
{
printf("Found unit specific Report General config page, but checksum is invalid!\n");
}
}
// ethernet config page
if (pageId == 0xFF10 && pageLength >= 0x24)
{
if (checksum8 == buf[1])
{
memcpy(newMfgMACAddr, &buf[20], sizeof newMfgMACAddr);
etherPageOffset = offset;
}
else
{
printf("Found Ethernet config page in image, but checksum is invalid!\n");
}
}
// unit specific ethernet config page
if (pageId == 0xFE05 && pageLength == 0xC)
{
if (checksum8 == buf[1])
{
memcpy(newMfgMACAddr, &buf[8], sizeof newMfgMACAddr);
etherPageOffset = offset;
}
else
{
printf("Found unit specific Ethernet config page, but checksum is invalid!\n");
}
}
offset += pageLength + 4;
buf += pageLength + 4;
}
if (addrPageOffset)
{
printf("Current SAS Address programmed in expander mfg data is %08x%08x\n",
currMfgSasAddr.High, currMfgSasAddr.Low);
printf("New SAS Address in supplied mfg image is %08x%08x\n",
newMfgSasAddr.High, newMfgSasAddr.Low);
while (TRUE)
{
printf("Use which SAS Address? [1=from supplied image, 2=preserve existing, 3=override, default is 1] ");
choice = getNumberAnswer(1, 3, 1);
if (choice == 3)
{
printf("Enter SAS Address: [16 hex digits or RETURN to quit] ");
i = getHexDoubleNumberAnswer(&(mfgSasAddr.High), &(mfgSasAddr.Low));
if (i == 0)
continue;
}
break;
}
if (choice == 2)
mfgSasAddr = currMfgSasAddr;
if (choice == 2 || choice == 3)
{
buf = imageBuf + addrPageOffset;
checksum8 = 0;
pageLength = get16x(((U16 *)buf)[2]);
// displayByteData(buf, pageLength+4);
((U32 *)buf)[2] = set32x(mfgSasAddr.High);
((U32 *)buf)[3] = set32x(mfgSasAddr.Low);
for( i=0; i < pageLength; i++ )
{
checksum8 += buf[i+4];
}
buf[1] = checksum8;
// displayByteData(buf, pageLength+4);
}
}
else
{
printf("Unable to locate the SAS address config page in the image!\n");
warn = 1;
}
if (enclIdPageOffset)
{
printf("Current Enclosure Logical ID programmed in expander mfg data is %08x%08x\n",
currMfgEnclLogId.High, currMfgEnclLogId.Low);
printf("New Enclosure Logical ID in supplied mfg image is %08x%08x\n",
newMfgEnclLogId.High, newMfgEnclLogId.Low);
while (TRUE)
{
printf("Use which Enclosure Logical ID? [1=from supplied image, 2=preserve existing, 3=override, default is 1] ");
choice = getNumberAnswer(1, 3, 1);
if (choice == 3)
{
printf("Enter SAS Address: [16 hex digits or RETURN to quit] ");
i = getHexDoubleNumberAnswer(&(mfgEnclLogId.High), &(mfgEnclLogId.Low));
if (i == 0)
continue;
}
break;
}
if (choice == 2)
mfgEnclLogId = currMfgEnclLogId;
if (choice == 2 || choice == 3)
{
buf = imageBuf + enclIdPageOffset;
checksum8 = 0;
pageLength = get16x(((U16 *)buf)[2]);
// displayByteData(buf, pageLength+4);
((U32 *)buf)[2] = set32x(mfgEnclLogId.High);
((U32 *)buf)[3] = set32x(mfgEnclLogId.Low);
for( i=0; i < pageLength; i++ )
{
checksum8 += buf[i+4];
}
buf[1] = checksum8;
// displayByteData(buf, pageLength+4);
}
}
else
{
printf("Unable to locate the Report General config page in the image!\n");
warn = 1;
}
if (etherPageOffset)
{
printf("Current Ethernet MAC Address programmed in expander mfg data is %02x-%02x-%02x-%02x-%02x-%02x\n",
currMfgMACAddr[0], currMfgMACAddr[1], currMfgMACAddr[2],
currMfgMACAddr[3], currMfgMACAddr[4], currMfgMACAddr[5]);
printf("New Ethernet MAC Address in supplied mfg image is %02x-%02x-%02x-%02x-%02x-%02x\n",
newMfgMACAddr[0], newMfgMACAddr[1], newMfgMACAddr[2],
newMfgMACAddr[3], newMfgMACAddr[4], newMfgMACAddr[5]);
while (TRUE)
{
printf("Use which MAC Address? [1=from supplied image, 2=preserve existing, 3=override, default is 1] ");
choice = getNumberAnswer(1, 3, 1);
if (choice == 3)
{
while ( TRUE )
{
printf("Enter new MAC Address: [or RETURN to quit] ");
i = getStringFromArgs(mac_address_ascii, sizeof mac_address_ascii, stdin);
if (i == 0)
break;
if ((sscanf(mac_address_ascii, "%x-%x-%x-%x-%x-%x",
&mac_address_int[0],&mac_address_int[1],&mac_address_int[2],
&mac_address_int[3],&mac_address_int[4],&mac_address_int[5]) == 6) &&
mac_address_int[0] <= 0xFF && mac_address_int[1] <= 0xFF &&
mac_address_int[2] <= 0xFF && mac_address_int[3] <= 0xFF &&
mac_address_int[4] <= 0xFF && mac_address_int[5] <= 0xFF &&
i <= 17)
{
for (x = 0; x < 6; x++)
mfgMACAddr[x] = mac_address_int[x];
break;
}
else
printf("Invalid MAC Address. Please enter a MAC Address in the form xx-xx-xx-xx-xx-xx\n");
}
if (i == 0)
continue;
}
break;
}
if (choice == 2)
memcpy(mfgMACAddr, currMfgMACAddr, sizeof mfgMACAddr);
if (choice == 2 || choice == 3)
{
buf = imageBuf + etherPageOffset;
checksum8 = 0;
pageLength = get16x(((U16 *)buf)[2]);
pageId = get16x(((U16 *)buf)[3]);
// displayByteData(buf, pageLength+4);
if (pageId == 0xFF10)
memcpy(&buf[20], mfgMACAddr, sizeof mfgMACAddr);
else // pageId == 0xFE05
memcpy(&buf[8], mfgMACAddr, sizeof mfgMACAddr);
for( i=0; i < pageLength; i++ )
{
checksum8 += buf[i+4];
}
buf[1] = checksum8;
// displayByteData(buf, pageLength+4);
}
}
else
{
printf("Unable to locate the Ethernet config page in the image!\n");
warn = 1;
}
}
}
if (warn && noFlag == TRUE)
{
free(imageBuf);
return 0;
}
if (warn || yesFlag == FALSE)
{
if (warn)
printf("\nAre you sure you want to continue? [Yes or No, default is No] ");
else
printf("\nDo you want to continue? [Yes or No, default is No] ");
if (getYesNoAnswer(0) != 1)
{
free(imageBuf);
return 0;
}
}
curr = -1;
while (TRUE)
{
skip = FALSE;
if (updateAll)
{
curr++;
bus = exp_targets[curr].bus;
target = exp_targets[curr].target;
if (bus == -1 && target == -1)
break;
if (curr == 0)
printf("\n");
if (expanderType != exp_targets[curr].expanderType)
{
printf("Skipping image download to %d/%d...\n", bus, target);
skip = TRUE;
}
else
printf("Downloading image to %d/%d...\n", bus, target);
}
else
printf("\nDownloading image...\n");
if (skip)
len = 0;
else
len = imageLen;
buf = imageBuf;
offset = 0;
while (len > 0)
{
if (mode == 2 && (id == 0 || id == 2 ||
(id == 0xe2 && (expanderType == EXPANDER_TYPE_LSI_GEN2_BOBCAT ||
expanderType == EXPANDER_TYPE_LSI_GEN3_COBRA))))
size = len;
else
size = min(len, CHUNK_SIZE);
if (mode == 6 || mode == 7)
t = doSesDownloadMicrocode(port, bus, target, 0, mode, id, offset, imageLen, buf, size);
else
t = doWriteBufferFull(port, bus, target, 0, mode, id, offset, buf, size);
if (t != 1)
{
printf("Download failed\n");
return 0;
}
buf += size;
len -= size;
offset += size;
if (len > 0)
{
printf(".");
fflush(stdout);
}
else if (size != imageLen)
{
printf("\n");
}
}
if (!skip)
printf("Download succeeded\n");
if (!updateAll)
break;
}
if (mode == 6 || mode == 7)
{
unsigned char data[24];
int inProg;
curr = -1;
while (TRUE)
{
skip = FALSE;
if (updateAll)
{
curr++;
bus = exp_targets[curr].bus;
target = exp_targets[curr].target;
if (bus == -1 && target == -1)
break;
if (expanderType != exp_targets[curr].expanderType)
skip = TRUE;
}
inProg = FALSE;
while (!skip && TRUE)
{
if (doReceiveDiagnosticResults(port, bus, target, 0, 0x0e, data, sizeof data) == 1)
{
if (data[10] == mode + 10)
{
if (inProg) printf("\n");
if (updateAll)
printf("\nSES Download Microcode to %d/%d succeeded\n", bus, target);
else
printf("\nSES Download Microcode succeeded\n");
if (mode == 6)
printf("\nExpander will automatically reset itself\n");
break;
}
else
{
/* on some expander platforms 0x70 and 0x71 are used as interim statuses */
if (((data[10] > 0) && (data[10] <= 3)) || data[10] == 0x70 || data[10] == 0x71)
{
if (!inProg)
{
if (updateAll)
printf("SES Download Microcode update to %d/%d in progress.", bus, target);
else
printf("SES Download Microcode update in progress.");
inProg = TRUE;
}
else
{
printf(".");
fflush(stdout);
}
sleep(1);
}
else
{
if ( inProg ) printf("\n");
if (updateAll)
printf("\nSES Download Microcode to %d/%d failed, status/additional status is %02x/%02x\n",
bus, target, data[10], data[11]);
else
printf("\nSES Download Microcode failed, status/additional status is %02x/%02x\n",
data[10], data[11]);
break;
}
}
}
}
if (!updateAll)
break;
}
free(imageBuf);
return 1;
}
curr = -1;
while ( TRUE )
{
skip = FALSE;
if (updateAll)
{
curr++;
bus = exp_targets[curr].bus;
target = exp_targets[curr].target;
if (bus == -1 && target == -1)
break;
if (expanderType != exp_targets[curr].expanderType)
skip = TRUE;
else
printf("\nVerifying download for %d/%d...\n", bus, target);
}
else
printf("\nVerifying download...\n");
imageLenUpload = CHUNK_SIZE;
imageBufUpload = (unsigned char *)malloc(imageLenUpload);
if (skip)
len = 0;
else
len = imageLen;
buf = imageBufUpload;
offset = 0;
t = 1;
i = 1;
while (len > 0)
{
size = min(len, CHUNK_SIZE);
if (doReadBufferFull(port, bus, target, 0, mode, id, offset, buf, size) != 1)
{
t = 0;
i = 0;
break;
}
if (memcmp(imageBuf + offset, buf, size) != 0)
{
t = 0;
break;
}
len -= size;
offset += size;
}
if (!skip)
{
if (t == 1)
printf("Verification succeeded\n");
else
{
if (offset == 0 && i == 0)
printf("Verification not supported!\n");
else
printf("Verification failed!\n");
}
}
if (!updateAll)
break;
}
free(imageBuf);
free(imageBufUpload);
return 1;
}
int
doReadBufferFirmwareUpload(MPT_PORT *port)
{
int bus;
int target;
unsigned char desc[4];
int n;
int t;
char name[256];
int file;
unsigned char *imageBuf = NULL;
int imageLen;
int length;
int offset;
int id;
if (selectDevice(port, &bus, &target) != 1)
return 0;
while (TRUE)
{
printf("\nBufferID: [0-255 or RETURN to quit] ");
id = getNumberAnswer(0, 255, -1);
if (id < 0)
return 1;
if (doReadBufferFull(port, bus, target, 0, 3, id, 0, desc, sizeof desc) == 1)
{
length = get3bytes(desc, 1);
printf("Buffer length is %d\n", length);
}
else
{
length = 0;
printf("Buffer length is unknown\n");
}
n = getFileName(name, sizeof name, stdin, "output", 0);
if (n > 0)
{
file = open(name, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, 0644);
if (file < 0)
{
printf("Open failure for file %s\n", name);
perror("Error is");
return 0;
}
}
else
{
printf("Buffer won't be saved\n");
return 1;
}
imageLen = CHUNK_SIZE;
if (length)
if (imageLen > length)
imageLen = length;
imageBuf = (unsigned char *)malloc(imageLen);
offset = 0;
while (TRUE)
{
if (doReadBufferFull(port, bus, target, 0, 2, id, offset, imageBuf, imageLen) != 1)
{
if (length)
break;
if (imageLen == 0x200)
break;
imageLen /= 2;
continue;
}
t = write(file, imageBuf, imageLen);
if (t != imageLen)
{
printf("Write failed for file %s, t = %x\n", name, t);
perror("Error is");
break;
}
offset += imageLen;
if (length)
if (offset >= length)
break;
}
printf("\nWrote %d bytes to file %s\n", offset, name);
close(file);
free(imageBuf);
}
return 1;
}
int
doRaidActions(MPT_PORT *port, int command)
{
IOCPage2_t *IOCPage2;
IOCPage3_t *IOCPage3;
int length;
if (bringOnline(port) != 1)
return 0;
if (mpi2)
return doRaidActions2(port, command);
IOCPage2 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_IOC, 2, 0, &length);
if (IOCPage2 == NULL || IOCPage2->MaxVolumes == 0)
{
printf("RAID is not supported on this port\n");
if (IOCPage2)
free(IOCPage2);
return 0;
}
IOCPage3 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_IOC, 3, 0, &length);
if (IOCPage3 == NULL)
{
printf("RAID is not supported on this port\n");
free(IOCPage2);
return 0;
}
switch (command)
{
case 1:
doShowVolumes(port, IOCPage2, IOCPage3);
break;
case 2:
doShowPhysDisks(port, IOCPage2, IOCPage3);
break;
case 3:
doGetVolumeState(port, IOCPage2);
break;
case 4:
doWaitForResync(port, IOCPage2);
break;
case 10:
doModifyVolume(port, IOCPage2, MPI_RAID_ACTION_DISABLE_VOLUME, "disabled");
break;
case 11:
doModifyVolume(port, IOCPage2, MPI_RAID_ACTION_ENABLE_VOLUME, "enabled");
break;
case 12:
doModifyVolume(port, IOCPage2, MPI_RAID_ACTION_INACTIVATE_VOLUME, "inactivated");
break;
case 13:
doModifyVolume(port, IOCPage2, MPI_RAID_ACTION_ACTIVATE_VOLUME, "activated");
break;
case 20:
doModifyPhysDisk(port, IOCPage2, IOCPage3, MPI_RAID_ACTION_PHYSDISK_OFFLINE, "offlined");
break;
case 21:
doModifyPhysDisk(port, IOCPage2, IOCPage3, MPI_RAID_ACTION_PHYSDISK_ONLINE, "onlined");
break;
case 22:
doModifyPhysDisk(port, IOCPage2, IOCPage3, MPI_RAID_ACTION_FAIL_PHYSDISK, "failed");
break;
case 23:
doModifyPhysDisk(port, IOCPage2, IOCPage3, MPI_RAID_ACTION_REPLACE_PHYSDISK, "replaced");
break;
case 24:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doModifyPhysDisk(port, IOCPage2, IOCPage3, MPI_RAID_ACTION_QUIESCE_PHYS_IO, "quiesced");
}
else
{
printf("Invalid selection!\n");
}
break;
case 25:
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
doModifyPhysDisk(port, IOCPage2, IOCPage3, MPI_RAID_ACTION_ENABLE_PHYS_IO, "unquiesced");
}
else
{
printf("Invalid selection!\n");
}
break;
case 26:
doDriveFirmwareUpdateMode(port, IOCPage2, IOCPage3, 0);
break;
case 27:
doDriveFirmwareUpdateMode(port, IOCPage2, IOCPage3, 1);
break;
case 30:
doCreateVolume(port, IOCPage2, IOCPage3);
break;
case 31:
doDeleteVolume(port, IOCPage2);
break;
case 32:
doVolumeSettings(port, IOCPage2);
break;
case 33:
doVolumeName(port, IOCPage2);
break;
case 40:
doCreatePhysDisk(port, IOCPage2);
break;
case 41:
doModifyPhysDisk(port, IOCPage2, IOCPage3, MPI_RAID_ACTION_DELETE_PHYSDISK, "deleted");
break;
case 42:
doPhysDiskSettings(port, IOCPage2, IOCPage3);
break;
case 50:
doCreateHotSpare(port, IOCPage2, IOCPage3);
break;
case 51:
doDeleteHotSpare(port, IOCPage2, IOCPage3);
break;
default:
printf("Invalid selection!\n");
break;
}
free(IOCPage2);
free(IOCPage3);
#if DOS || EFI
// give the firmware a chance to update the volume metadata
sleep(5);
#endif
return 1;
}
int
selectVolume(MPT_PORT *port, IOCPage2_t *IOCPage2, int *volumeOut)
{
int volume;
int i;
if (IOCPage2->NumActiveVolumes == 0)
{
printf("No active volumes\n");
return 0;
}
for (i = 0; i < IOCPage2->NumActiveVolumes; i++)
{
printf("Volume %d is Bus %d Target %d, Type %s%s\n",
i, IOCPage2->RaidVolume[i].VolumeBus, IOCPage2->RaidVolume[i].VolumeID,
IOCPage2->RaidVolume[i].VolumeType == MPI_RAID_VOL_TYPE_IS ? "IS (Integrated Striping)" :
IOCPage2->RaidVolume[i].VolumeType == MPI_RAID_VOL_TYPE_IME ? "IME (Integrated Mirroring Extended)" :
IOCPage2->RaidVolume[i].VolumeType == MPI_RAID_VOL_TYPE_IM ? "IM (Integrated Mirroring)" : "Unknown",
IOCPage2->RaidVolume[i].Flags & MPI_IOCPAGE2_FLAG_VOLUME_INACTIVE ? ", inactive" : "");
}
printf("\n");
if (IOCPage2->NumActiveVolumes > 1 || gFlag == TRUE)
{
printf("Volume: [0-%d or RETURN to quit] ", IOCPage2->NumActiveVolumes - 1);
volume = getNumberAnswer(0, IOCPage2->NumActiveVolumes - 1, -1);
if (volume < 0)
return 0;
printf("\n");
}
else
{
volume = 0;
}
*volumeOut = volume;
return 1;
}
int
doShowVolumes(MPT_PORT *port, IOCPage2_t *IOCPage2, IOCPage3_t *IOCPage3)
{
RaidVolumePage0_t *RaidVolumePage0;
RaidVolumePage1_t RaidVolumePage1;
int b_t;
int i;
int j;
int k;
int nv;
int nd;
int t1;
int t2;
int length;
nv = IOCPage2->NumActiveVolumes;
nd = IOCPage3->NumPhysDisks;
printf("%d volume%s active, %d physical disk%s active\n",
nv, nv == 1 ? " is" : "s are", nd, nd == 1 ? " is" : "s are");
for (i = 0; i < nv; i++)
{
printf("\nVolume %d is Bus %d Target %d, Type %s%s\n",
i, IOCPage2->RaidVolume[i].VolumeBus, IOCPage2->RaidVolume[i].VolumeID,
IOCPage2->RaidVolume[i].VolumeType == MPI_RAID_VOL_TYPE_IS ? "IS (Integrated Striping)" :
IOCPage2->RaidVolume[i].VolumeType == MPI_RAID_VOL_TYPE_IME ? "IME (Integrated Mirroring Extended)" :
IOCPage2->RaidVolume[i].VolumeType == MPI_RAID_VOL_TYPE_IM ? "IM (Integrated Mirroring)" : "Unknown",
IOCPage2->RaidVolume[i].Flags & MPI_IOCPAGE2_FLAG_VOLUME_INACTIVE ? ", inactive" : "");
if (IOCPage2->RaidVolume[i].VolumePageNumber == 0)
{
b_t = (IOCPage2->RaidVolume[i].VolumeBus << 8) + IOCPage2->RaidVolume[i].VolumeID;
RaidVolumePage0 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_RAID_VOLUME, 0, b_t, &length);
if (RaidVolumePage0 == NULL)
continue;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_RAID_VOLUME, 1, b_t,
&RaidVolumePage1, sizeof RaidVolumePage1) == 1)
{
printf(" Volume Name: %-32s\n",
RaidVolumePage1.Name);
printf(" Volume WWID: %08x%08x\n",
get32(RaidVolumePage1.WWID.High), get32(RaidVolumePage1.WWID.Low));
}
t1 = RaidVolumePage0->VolumeStatus.State;
t2 = RaidVolumePage0->VolumeStatus.Flags;
printf(" Volume State: %s%s%s%s%s\n",
t1 == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL ? "optimal" :
t1 == MPI_RAIDVOL0_STATUS_STATE_DEGRADED ? "degraded" :
t1 == MPI_RAIDVOL0_STATUS_STATE_FAILED ? "failed" :
t1 == MPI_RAIDVOL0_STATUS_STATE_MISSING ? "missing" : "unknown",
t2 & MPI_RAIDVOL0_STATUS_FLAG_ENABLED ? ", enabled" : ", disabled",
t2 & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED ? ", quiesced" : "",
t2 & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS ? ", resync in progress" : "",
t2 & MPI_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL ? ", bad block table full" : "");
t1 = get16(RaidVolumePage0->VolumeSettings.Settings);
t2 = RaidVolumePage0->VolumeSettings.HotSparePool;
printf(" Volume Settings: write caching %s%s%s%s\n",
t1 & MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE ? "enabled" : "disabled",
t1 & MPI_RAIDVOL0_SETTING_OFFLINE_ON_SMART ? ", offline on SMART data" : "",
t1 & MPI_RAIDVOL0_SETTING_AUTO_CONFIGURE ? ", auto configure" : "",
t1 & MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC ? ", priority resync" : "");
if (t2 != 0)
printf(" Volume draws from Hot Spare Pools: %s%s%s%s%s%s%s%s\n",
t2 & MPI_RAID_HOT_SPARE_POOL_0 ? " 0" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_1 ? " 1" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_2 ? " 2" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_3 ? " 3" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_4 ? " 4" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_5 ? " 5" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_6 ? " 6" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_7 ? " 7" : "");
if (IOCPage2->RaidVolume[i].VolumeType == MPI_RAID_VOL_TYPE_IM)
printf(" Volume Size %" INT64_FMT "d MB, %d Members\n",
(get64(RaidVolumePage0->MaxLBA) + 1) / 2048, RaidVolumePage0->NumPhysDisks);
else
printf(" Volume Size %" INT64_FMT "d MB, Stripe Size %d KB, %d Members\n",
(get64(RaidVolumePage0->MaxLBA) + 1) / 2048, get32(RaidVolumePage0->StripeSize) / 2,
RaidVolumePage0->NumPhysDisks);
for (j = 0; j < RaidVolumePage0->NumPhysDisks; j++)
{
for (k = 0; k < nd; k++)
{
if (IOCPage3->PhysDisk[k].PhysDiskNum == RaidVolumePage0->PhysDisk[j].PhysDiskNum)
{
if (IOCPage2->RaidVolume[i].VolumeType == MPI_RAID_VOL_TYPE_IM)
printf(" %s is PhysDisk %d (Bus %d Target %d)\n",
RaidVolumePage0->PhysDisk[j].PhysDiskMap == MPI_RAIDVOL0_PHYSDISK_PRIMARY ? "Primary" :
RaidVolumePage0->PhysDisk[j].PhysDiskMap == MPI_RAIDVOL0_PHYSDISK_SECONDARY ? "Secondary" :
"Member", RaidVolumePage0->PhysDisk[j].PhysDiskNum,
IOCPage3->PhysDisk[k].PhysDiskBus, IOCPage3->PhysDisk[k].PhysDiskID);
else
printf(" Member %d is PhysDisk %d (Bus %d Target %d)\n",
RaidVolumePage0->PhysDisk[j].PhysDiskMap, RaidVolumePage0->PhysDisk[j].PhysDiskNum,
IOCPage3->PhysDisk[k].PhysDiskBus, IOCPage3->PhysDisk[k].PhysDiskID);
break;
}
}
if (k < nd)
continue;
if (IOCPage2->RaidVolume[i].VolumeType == MPI_RAID_VOL_TYPE_IM)
printf(" %s is PhysDisk %d\n",
RaidVolumePage0->PhysDisk[j].PhysDiskMap == MPI_RAIDVOL0_PHYSDISK_PRIMARY ? "Primary" :
RaidVolumePage0->PhysDisk[j].PhysDiskMap == MPI_RAIDVOL0_PHYSDISK_SECONDARY ? "Secondary" :
"Member", RaidVolumePage0->PhysDisk[j].PhysDiskNum);
else
printf(" Member %d is PhysDisk %d\n",
RaidVolumePage0->PhysDisk[j].PhysDiskMap, RaidVolumePage0->PhysDisk[j].PhysDiskNum);
}
free(RaidVolumePage0);
}
}
return 1;
}
int
doShowPhysDisks(MPT_PORT *port, IOCPage2_t *IOCPage2, IOCPage3_t *IOCPage3)
{
RaidPhysDiskPage0_t RaidPhysDiskPage0;
RaidPhysDiskPage1_t *RaidPhysDiskPage1;
int i;
int j;
int physdisk;
int nv;
int nd;
int np;
int t1;
int t2;
int length;
nv = IOCPage2->NumActiveVolumes;
nd = IOCPage3->NumPhysDisks;
if (nd == 0 && nv)
{
nv = IOCPage2->MaxVolumes;
nd = IOCPage2->MaxPhysDisks;
printf("%d volume%s defined, %d physical disk%s possible\n",
nv, nv == 1 ? " is" : "s are", nd, nd == 1 ? " is" : "s are");
}
else
{
printf("%d volume%s active, %d physical disk%s active\n",
nv, nv == 1 ? " is" : "s are", nd, nd == 1 ? " is" : "s are");
}
for (i = 0; i < nd; i++)
{
if (IOCPage3->NumPhysDisks)
physdisk = IOCPage3->PhysDisk[i].PhysDiskNum;
else
physdisk = i;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_RAID_PHYSDISK, 0, physdisk,
&RaidPhysDiskPage0, sizeof RaidPhysDiskPage0) != 1)
continue;
printf("\nPhysDisk %d is Bus %d Target %d\n",
physdisk, RaidPhysDiskPage0.PhysDiskBus, RaidPhysDiskPage0.PhysDiskID);
t1 = RaidPhysDiskPage0.PhysDiskStatus.State;
t2 = RaidPhysDiskPage0.PhysDiskStatus.Flags;
printf(" PhysDisk State: %s%s%s%s\n",
t1 == MPI_PHYSDISK0_STATUS_ONLINE ? "online" :
t1 == MPI_PHYSDISK0_STATUS_MISSING ? "missing" :
t1 == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE ? "not compatible" :
t1 == MPI_PHYSDISK0_STATUS_FAILED ? "failed" :
t1 == MPI_PHYSDISK0_STATUS_INITIALIZING ? "initializing" :
t1 == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED ? "offline requested" :
t1 == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED ? "failed requested" :
t1 == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE ? "offline" : "unknown",
t2 & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC ? ", out of sync" : "",
t2 & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED ? ", quiesced" : "",
t2 & MPI_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME ? ", inactive volume" : "");
t1 = RaidPhysDiskPage0.PhysDiskSettings.PhysDiskSettings;
t2 = RaidPhysDiskPage0.PhysDiskSettings.HotSparePool;
// printf(" PhysDisk Settings: \n");
if (t2 != 0)
printf(" PhysDisk belongs to Hot Spare Pools: %s%s%s%s%s%s%s%s\n",
t2 & MPI_RAID_HOT_SPARE_POOL_0 ? " 0" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_1 ? " 1" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_2 ? " 2" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_3 ? " 3" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_4 ? " 4" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_5 ? " 5" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_6 ? " 6" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_7 ? " 7" : "");
printf(" PhysDisk Size %d MB, Inquiry Data: %-8.8s %-16.16s %-4.4s\n",
(get32(RaidPhysDiskPage0.MaxLBA) + 1) / 2048, RaidPhysDiskPage0.InquiryData.VendorID,
RaidPhysDiskPage0.InquiryData.ProductID, RaidPhysDiskPage0.InquiryData.ProductRevLevel);
t1 = get16(RaidPhysDiskPage0.ErrorData.ErrorCount);
t2 = get16(RaidPhysDiskPage0.ErrorData.SmartCount);
if (t1 != 0)
printf(" Error Count %d, Last Error: Command = %02Xh, Key = %d, ASC/ASCQ = %02Xh/%02Xh\n",
t1, RaidPhysDiskPage0.ErrorData.ErrorCdbByte,
RaidPhysDiskPage0.ErrorData.ErrorSenseKey,
RaidPhysDiskPage0.ErrorData.ErrorASC, RaidPhysDiskPage0.ErrorData.ErrorASCQ);
if (t2 != 0)
printf(" SMART Data Count %d, Last SMART Data: ASC/ASCQ = %02Xh/%02Xh\n",
t2, RaidPhysDiskPage0.ErrorData.SmartASC, RaidPhysDiskPage0.ErrorData.SmartASCQ);
if (RaidPhysDiskPage0.PhysDiskStatus.Flags & MPI_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME)
continue;
RaidPhysDiskPage1 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_RAID_PHYSDISK, 1, physdisk, &length);
if (RaidPhysDiskPage1 == NULL)
continue;
np = RaidPhysDiskPage1->NumPhysDiskPaths;
if (np > 1)
{
for (j = 0; j < np; j++)
{
t1 = get16(RaidPhysDiskPage1->Path[j].Flags);
printf(" Path %d is Bus %d Target %d, %s\n", j,
RaidPhysDiskPage1->Path[j].PhysDiskBus,
RaidPhysDiskPage1->Path[j].PhysDiskID,
t1 & MPI_RAID_PHYSDISK1_FLAG_INVALID ? "invalid" :
t1 & MPI_RAID_PHYSDISK1_FLAG_BROKEN ? "broken" :
"online");
}
}
free(RaidPhysDiskPage1);
}
return 1;
}
int
doGetVolumeState(MPT_PORT *port, IOCPage2_t *IOCPage2)
{
MpiRaidActionRequest_t req;
struct
{
MpiRaidActionReply_t rep;
MpiRaidVolIndicator_t data;
} rep;
MpiRaidVolIndicator_t *data;
RaidVol0Status_t *status;
int volume;
uint64_t size;
uint64_t done;
int t1;
int t2;
if (selectVolume(port, IOCPage2, &volume) != 1)
return 0;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_RAID_ACTION;
req.Action = MPI_RAID_ACTION_INDICATOR_STRUCT;
req.VolumeBus = IOCPage2->RaidVolume[volume].VolumeBus;
req.VolumeID = IOCPage2->RaidVolume[volume].VolumeID;
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME) == 1)
{
data = (pMpiRaidVolIndicator_t)&rep.rep.ActionData;
status = (pRaidVol0Status_t)&rep.rep.VolumeStatus;
t1 = status->State;
t2 = status->Flags;
printf("Volume %d State: %s%s%s%s\n", volume,
t1 == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL ? "optimal" :
t1 == MPI_RAIDVOL0_STATUS_STATE_DEGRADED ? "degraded" :
t1 == MPI_RAIDVOL0_STATUS_STATE_FAILED ? "failed" : "unknown",
t2 & MPI_RAIDVOL0_STATUS_FLAG_ENABLED ? ", enabled" : ", disabled",
t2 & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED ? ", quiesced" : "",
t2 & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS ? ", resync in progress" : "");
if (t2 & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
{
size = get64(data->TotalBlocks);
done = get64(data->BlocksRemaining);
if (size)
{
printf("Resync Progress: total blocks %" INT64_FMT "d, blocks remaining %" INT64_FMT "d, %d%%\n",
size, done, (int)(done / (size / 100)));
}
}
}
return 1;
}
int
doWaitForResync(MPT_PORT *port, IOCPage2_t *IOCPage2)
{
MpiRaidActionRequest_t req;
struct
{
MpiRaidActionReply_t rep;
MpiRaidVolIndicator_t data;
} rep;
MpiRaidVolIndicator_t *data;
RaidVol0Status_t *status;
int volume;
uint64_t size;
uint64_t done;
int t1;
int t2;
int percent;
int last_percent = -1;
int n;
if (selectVolume(port, IOCPage2, &volume) != 1)
return 0;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_RAID_ACTION;
req.Action = MPI_RAID_ACTION_INDICATOR_STRUCT;
req.VolumeBus = IOCPage2->RaidVolume[volume].VolumeBus;
req.VolumeID = IOCPage2->RaidVolume[volume].VolumeID;
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
return 0;
data = (pMpiRaidVolIndicator_t)&rep.rep.ActionData;
status = (pRaidVol0Status_t)&rep.rep.VolumeStatus;
t1 = status->State;
t2 = status->Flags;
printf("Volume %d State: %s%s%s%s\n", volume,
t1 == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL ? "optimal" :
t1 == MPI_RAIDVOL0_STATUS_STATE_DEGRADED ? "degraded" :
t1 == MPI_RAIDVOL0_STATUS_STATE_FAILED ? "failed" : "unknown",
t2 & MPI_RAIDVOL0_STATUS_FLAG_ENABLED ? ", enabled" : ", disabled",
t2 & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED ? ", quiesced" : "",
t2 & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS ? ", resync in progress" : "");
if (t2 & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
{
size = get64(data->TotalBlocks);
done = get64(data->BlocksRemaining);
if (size)
{
last_percent = (int)(done / (size / 100));
printf("Resync Progress: total blocks %" INT64_FMT "d, blocks remaining %" INT64_FMT "d, %d%%\n",
size, done, last_percent);
}
}
else
return 1;
n = 0;
while (TRUE)
{
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
return 0;
data = (pMpiRaidVolIndicator_t)&rep.rep.ActionData;
status = (pRaidVol0Status_t)&rep.rep.VolumeStatus;
t1 = status->State;
t2 = status->Flags;
if (t2 & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
{
size = get64(data->TotalBlocks);
done = get64(data->BlocksRemaining);
if (size)
{
percent = (int)(done / (size / 100));
if (percent != last_percent)
{
last_percent = percent;
n += printf(" %d%%", last_percent);
if (n >= 75)
{
printf("\n");
n = 0;
}
}
}
}
else
break;
sleep(1);
}
if (n)
printf("\n");
printf("Volume %d State: %s%s%s%s\n", volume,
t1 == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL ? "optimal" :
t1 == MPI_RAIDVOL0_STATUS_STATE_DEGRADED ? "degraded" :
t1 == MPI_RAIDVOL0_STATUS_STATE_FAILED ? "failed" : "unknown",
t2 & MPI_RAIDVOL0_STATUS_FLAG_ENABLED ? ", enabled" : ", disabled",
t2 & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED ? ", quiesced" : "",
t2 & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS ? ", resync in progress" : "");
return 1;
}
int
doModifyVolume(MPT_PORT *port, IOCPage2_t *IOCPage2, int action, char *string)
{
MpiRaidActionRequest_t req;
MpiRaidActionReply_t rep;
int volume;
int all;
if (IOCPage2->NumActiveVolumes == 0)
{
printf("No active volumes\n");
return 1;
}
if (action == MPI_RAID_ACTION_DISABLE_VOLUME ||
action == MPI_RAID_ACTION_ENABLE_VOLUME)
{
all = 1;
volume = 0;
}
else
{
all = 0;
if (selectVolume(port, IOCPage2, &volume) != 1)
return 0;
}
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_RAID_ACTION;
req.Action = action;
req.VolumeBus = IOCPage2->RaidVolume[volume].VolumeBus;
req.VolumeID = IOCPage2->RaidVolume[volume].VolumeID;
if (all)
printf("Volumes are being %s\n", string);
else
printf("Volume %d is being %s\n", volume, string);
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doCreateVolume(MPT_PORT *port, IOCPage2_t *IOCPage2, IOCPage3_t *IOCPage3)
{
RaidVolumePage0_t *RaidVolumePage0;
RaidPhysDiskPage0_t RaidPhysDiskPage0;
ManufacturingPage4_t ManufacturingPage4;
IOCPage6_t IOCPage6;
MpiRaidActionRequest_t req;
MpiRaidActionReply_t rep;
ConfigReply_t config_rep;
int bus;
int target;
PATH path;
int no_mix_sas_sata;
int no_mix_ssd_non_ssd;
int sata = 0;
int ssd = 0;
int num_physdisks;
int physdisks[MAX_DEVICES];
int chosen[MAX_DEVICES];
unsigned char inq[36];
unsigned char cap[8];
unsigned int size;
unsigned int metadata_size = 0;
unsigned int coerced_size;
unsigned int min_size = 0;
uint64_t volume_size;
uint64_t max_volume_size;
uint64_t max_lba;
int first_bus = 0;
int first_target = 0;
int length;
int i;
int n;
int t;
int settings = 0;
int flags;
int min_disks;
int stripe_map = 0;
int min_stripe;
int max_stripe;
int def_stripe;
if (IOCPage2->NumActiveVolumes >= IOCPage2->MaxVolumes)
{
printf("Cannot create another active volume\n");
return 0;
}
if (IOCPage3->NumPhysDisks + 2 > IOCPage2->MaxPhysDisks)
{
printf("Cannot create at least 2 physical disks\n");
return 0;
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 6, 0, &IOCPage6, sizeof IOCPage6) != 1)
{
memset(&IOCPage6, 0, sizeof IOCPage6);
IOCPage6.MinDrivesIS = 2;
IOCPage6.MinDrivesIM = 2;
IOCPage6.MinDrivesIME = 3;
IOCPage6.MaxDrivesIS = IOCPage2->MaxPhysDisks;
IOCPage6.MaxDrivesIM = 2;
IOCPage6.MaxDrivesIME = IOCPage2->MaxPhysDisks;
if (IOCPage2->MaxVolumes > 1)
{
IOCPage6.MaxDrivesIS -= 2;
IOCPage6.MaxDrivesIME -= 2;
}
IOCPage6.MaxGlobalHotSpares = 1;
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SCSI)
IOCPage6.SupportedStripeSizeMapIS = set32(0x3f8);
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
IOCPage6.SupportedStripeSizeMapIS = set32(0x80);
}
min_disks = min(2, min(IOCPage6.MinDrivesIS, IOCPage6.MinDrivesIME));
printf(" B___T___L Type Vendor Product Rev Disk Blocks Disk MB\n");
n = 0;
for (bus = 0; bus < port->maxBuses; bus++)
{
for (target = port->minTargets; target < port->maxTargets; target++)
{
if (isRaidVolume(port, bus, target))
continue;
if (doInquiry(port, bus, target, 0, inq, sizeof inq) != 1)
{
#if __linux__ || DOS || EFI
if (errno == EFAULT)
return 0;
#endif
continue;
}
if ((inq[0] & 0x1f) != 0x00)
continue;
if ((inq[0] & 0xe0) == 0x20)
continue;
if ((inq[0] & 0xe0) == 0x60)
continue;
for (i = 8; i < 36; i++)
if (!isprint(inq[i]))
inq[i] = ' ';
if (doReadCapacity(port, bus, target, 0, cap, sizeof cap) != 1)
continue;
size = get4bytes(cap, 0);
if (getPath(port, bus, target, &path) == 1)
{
for (i = 0; i < n; i++)
{
if (diag_targets[i].path.slot == path.slot &&
diag_targets[i].path.encl_id_l == path.encl_id_l &&
diag_targets[i].path.encl_id_h == path.encl_id_h)
{
printf("Bus %d Target %d is another path to Bus %d Target %d, ignoring\n",
bus, target, diag_targets[i].bus, diag_targets[i].target);
break;
}
}
if (i < n)
continue;
}
diag_targets[n].bus = bus;
diag_targets[n].target = target;
diag_targets[n].size = size;
diag_targets[n].path = path;
n++;
printf("%2d. %2d %3d %3d %-9s %-8.8s %-16.16s %-4.4s %10d %7d\n",
n, bus, target, 0, deviceType[inq[0] & 0x1f],
inq+8, inq+16, inq+32, size + 1, (size + 1) / 2048);
if (n == MAX_DEVICES)
break;
}
if (n == MAX_DEVICES)
break;
}
if (n < min_disks)
{
printf("\nNot enough available targets found\n");
return 1;
}
flags = get32(IOCPage2->CapabilitiesFlags);
printf("\nTo create a volume, select %d or more of the available targets\n", min_disks);
if (flags & MPI_IOCPAGE2_CAP_FLAGS_IME_SUPPORT)
printf(" select %d to %d targets for a mirrored volume\n",
IOCPage6.MinDrivesIME, IOCPage6.MaxDrivesIME);
else if (flags & MPI_IOCPAGE2_CAP_FLAGS_IM_SUPPORT)
printf(" select 2 targets for a mirrored volume\n");
if (flags & MPI_IOCPAGE2_CAP_FLAGS_IS_SUPPORT)
printf(" select %d to %d targets for a striped volume\n",
IOCPage6.MinDrivesIS, IOCPage6.MaxDrivesIS);
printf("\n");
num_physdisks = 0;
if (getConfigPageHeader(port, MPI_CONFIG_PAGETYPE_RAID_PHYSDISK, 0, 0, &config_rep) != 1)
return 0;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 4, 0,
&ManufacturingPage4, sizeof ManufacturingPage4) != 1)
return 0;
no_mix_sas_sata = (ManufacturingPage4.Flags & MPI_MANPAGE4_IR_NO_MIX_SAS_SATA) != 0;
no_mix_ssd_non_ssd = (get16(ManufacturingPage4.ExtFlags) & MPI_MANPAGE4_EXTFLAGS_MIX_SSD_AND_NON_SSD) == 0;
while (TRUE)
{
printf("Select a target: [1-%d or RETURN to quit] ", n);
i = getNumberAnswer(1, n, 0);
if (i == 0)
break;
i--;
for (t = 0; t < num_physdisks; t++)
{
if (i == chosen[t])
{
printf("\nThis target has already been chosen!\n\n");
break;
}
}
if (t < num_physdisks)
continue;
chosen[num_physdisks] = i;
bus = diag_targets[i].bus;
target = diag_targets[i].target;
if (no_mix_sas_sata)
{
if (num_physdisks == 0)
{
sata = isSata(port, bus, target);
}
else if (sata != isSata(port, bus, target))
{
printf("\nThis %s target cannot be mixed with the %s target%s already chosen!\n\n",
sata ? "SAS" : "SATA", sata ? "SATA" : "SAS",
num_physdisks == 1 ? "" : "s");
continue;
}
}
if (no_mix_ssd_non_ssd)
{
if (num_physdisks == 0)
{
ssd = isSsd(port, bus, target);
}
else if (ssd != isSsd(port, bus, target))
{
printf("\nThis %s target cannot be mixed with the %s target%s already chosen!\n\n",
ssd ? "non-SSD" : "SSD", ssd ? "SSD" : "non-SSD",
num_physdisks == 1 ? "" : "s");
continue;
}
}
memset(&RaidPhysDiskPage0, 0, sizeof RaidPhysDiskPage0);
RaidPhysDiskPage0.Header.PageType = config_rep.Header.PageType;
RaidPhysDiskPage0.Header.PageNumber = config_rep.Header.PageNumber;
RaidPhysDiskPage0.Header.PageLength = config_rep.Header.PageLength;
RaidPhysDiskPage0.Header.PageVersion = config_rep.Header.PageVersion;
RaidPhysDiskPage0.PhysDiskIOC = port->iocNumber;
RaidPhysDiskPage0.PhysDiskBus = bus;
RaidPhysDiskPage0.PhysDiskID = target;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_RAID_ACTION;
req.Action = MPI_RAID_ACTION_CREATE_PHYSDISK;
if (doMptCommandCheck(port, &req, sizeof req - sizeof req.ActionDataSGE, &rep, sizeof rep,
NULL, 0, &RaidPhysDiskPage0, sizeof RaidPhysDiskPage0, SHORT_TIME) != 1)
return 0;
physdisks[num_physdisks] = get32(rep.ActionData);
// printf("PhysDisk %d was created\n", physdisks[num_physdisks]);
if (num_physdisks == 0)
{
first_bus = bus;
first_target = target;
}
num_physdisks++;
if (num_physdisks >= n && gFlag != TRUE)
break;
if (IOCPage3->NumPhysDisks + num_physdisks >= IOCPage2->MaxPhysDisks)
{
printf(" no more physical disks can be created, exiting loop\n");
break;
}
if (num_physdisks >= max(IOCPage6.MaxDrivesIS, IOCPage6.MaxDrivesIME))
{
printf(" no more physical disks allowed in a volume, exiting loop\n");
break;
}
}
printf("\n%d physical disks were created\n\n", num_physdisks);
if (num_physdisks < min_disks)
{
printf("Volumes must have at least %d physical disks!\n", min_disks);
return 0;
}
if (getConfigPageHeader(port, MPI_CONFIG_PAGETYPE_RAID_VOLUME, 0, 0, &config_rep) != 1)
return 0;
length = sizeof *RaidVolumePage0 + sizeof RaidVolumePage0->PhysDisk * (num_physdisks - 1);
if (length < config_rep.Header.PageLength * 4)
length = config_rep.Header.PageLength * 4;
RaidVolumePage0 = malloc(length);
memset(RaidVolumePage0, 0, length);
RaidVolumePage0->Header.PageType = config_rep.Header.PageType;
RaidVolumePage0->Header.PageNumber = config_rep.Header.PageNumber;
RaidVolumePage0->Header.PageLength = length / 4;
RaidVolumePage0->Header.PageVersion = config_rep.Header.PageVersion;
RaidVolumePage0->VolumeIOC = port->iocNumber;
RaidVolumePage0->VolumeBus = first_bus;
RaidVolumePage0->VolumeID = first_target;
RaidVolumePage0->NumPhysDisks = num_physdisks;
if (flags & (MPI_IOCPAGE2_CAP_FLAGS_IM_SUPPORT | MPI_IOCPAGE2_CAP_FLAGS_IME_SUPPORT) &&
flags & MPI_IOCPAGE2_CAP_FLAGS_IS_SUPPORT)
{
printf("Select volume type: [0=Mirroring, 1=Striping, default is 0] ");
if (getNumberAnswer(0, 1, 0) == 0)
if (num_physdisks == 2 && flags & MPI_IOCPAGE2_CAP_FLAGS_IM_SUPPORT)
RaidVolumePage0->VolumeType = MPI_RAID_VOL_TYPE_IM;
else
RaidVolumePage0->VolumeType = MPI_RAID_VOL_TYPE_IME;
else
RaidVolumePage0->VolumeType = MPI_RAID_VOL_TYPE_IS;
}
else if (flags & (MPI_IOCPAGE2_CAP_FLAGS_IM_SUPPORT | MPI_IOCPAGE2_CAP_FLAGS_IME_SUPPORT))
{
if (num_physdisks == 2 && flags & MPI_IOCPAGE2_CAP_FLAGS_IM_SUPPORT)
RaidVolumePage0->VolumeType = MPI_RAID_VOL_TYPE_IM;
else
RaidVolumePage0->VolumeType = MPI_RAID_VOL_TYPE_IME;
}
else if (flags & MPI_IOCPAGE2_CAP_FLAGS_IS_SUPPORT)
{
RaidVolumePage0->VolumeType = MPI_RAID_VOL_TYPE_IS;
}
if (RaidVolumePage0->VolumeType == MPI_RAID_VOL_TYPE_IM)
{
settings = get32(ManufacturingPage4.IMVolumeSettings);
}
if (RaidVolumePage0->VolumeType == MPI_RAID_VOL_TYPE_IME)
{
settings = get32(ManufacturingPage4.IMEVolumeSettings);
stripe_map = get32(IOCPage6.SupportedStripeSizeMapIME);
}
if (RaidVolumePage0->VolumeType == MPI_RAID_VOL_TYPE_IS)
{
settings = get32(ManufacturingPage4.ISVolumeSettings);
stripe_map = get32(IOCPage6.SupportedStripeSizeMapIS);
}
if (flags & MPI_IOCPAGE2_CAP_FLAGS_RAID_64_BIT_ADDRESSING)
max_volume_size = ((uint64_t)1 << (64 - 11)); // in MB
else
max_volume_size = ((uint64_t)1 << (32 - 11)); // in MB
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SCSI)
metadata_size = 32; // 32 blocks
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
switch (settings & MPI_RAIDVOL0_SETTING_MASK_METADATA_SIZE)
{
default:
case MPI_RAIDVOL0_SETTING_64MB_METADATA_SIZE:
metadata_size = 64 * 2048; // 64 MB
break;
case MPI_RAIDVOL0_SETTING_512MB_METADATA_SIZE:
metadata_size = 512 * 2048; // 512 MB
break;
}
}
if (metadata_size > 2048)
printf("Required metadata size is %d MB, plus 2 MB\n", metadata_size / 2048);
else
printf("Required metadata size is %d blocks, plus 2 MB\n", metadata_size);
max_volume_size -= metadata_size;
t = 0;
for (i = 0; i < num_physdisks; i++)
{
size = diag_targets[chosen[i]].size + 1;
if (size <= metadata_size)
{
printf("Target %d is smaller than the required metadata size!\n", chosen[i]);
free(RaidVolumePage0);
return 0;
}
size = (size - metadata_size) / 2048;
if (size > 1000)
{
coerced_size = ((((size + 127) / 128) * 128) / 10) * 10;
if (coerced_size > size)
{
coerced_size = (((size / 128) * 128) / 10) * 10;
}
size = coerced_size;
}
if (size <= 2)
{
printf("Target %d is smaller than the required metadata size!\n", chosen[i]);
free(RaidVolumePage0);
return 0;
}
size -= 2;
// printf("Usable size of member %d is %d MB\n", i, size);
if (i == 0)
{
min_size = size;
}
else
{
if (size != min_size)
t = 1;
if (size < min_size)
{
// printf(" reducing volume member size from %d MB to %d MB\n", min_size, size);
min_size = size;
}
}
}
if (t)
{
printf("Not all physical disks are the same size!\n");
printf("A common size of %d MB will be used for each physical disk\n", min_size);
}
volume_size = (uint64_t)min_size * num_physdisks;
if (RaidVolumePage0->VolumeType != MPI_RAID_VOL_TYPE_IS)
volume_size /= 2;
if (volume_size > max_volume_size)
{
printf("Maximum volume size exceeded; reducing size from %" INT64_FMT "d MB to %" INT64_FMT "d MB\n",
volume_size, max_volume_size);
volume_size = max_volume_size;
}
printf("Select volume size: [1 to %" INT64_FMT "d MB, default is %" INT64_FMT "d] ",
volume_size, volume_size);
max_lba = (uint64_t)getNumberAnswer(1, (int)volume_size, (int)volume_size) * 2048 - 1;
t = (U32)max_lba;
RaidVolumePage0->MaxLBA = set32(t);
t = (U32)(max_lba >> 32);
RaidVolumePage0->MaxLBAHigh = set32(t);
if (stripe_map)
{
if (stripe_map & (stripe_map - 1))
{
t = stripe_map / 2;
min_stripe = t & (-t);
t = ((t | (min_stripe - 1)) + 1) / 2;
max_stripe = t & (-t);
def_stripe = min(max(64, min_stripe), max_stripe);
printf("Select stripe size: [%d to %d KB, default is %d] ", min_stripe, max_stripe, def_stripe);
size = getNumberAnswer(min_stripe, max_stripe, def_stripe);
}
else
{
size = stripe_map / 2;
printf("A stripe size of %d KB will be used\n", size);
}
RaidVolumePage0->StripeSize = set32(size * 2);
}
for (i = 0; i < num_physdisks; i++)
{
RaidVolumePage0->PhysDisk[i].PhysDiskNum = physdisks[i];
RaidVolumePage0->PhysDisk[i].PhysDiskMap = i;
}
if (RaidVolumePage0->VolumeType == MPI_RAID_VOL_TYPE_IM)
{
RaidVolumePage0->PhysDisk[0].PhysDiskMap = MPI_RAIDVOL0_PHYSDISK_PRIMARY;
RaidVolumePage0->PhysDisk[1].PhysDiskMap = MPI_RAIDVOL0_PHYSDISK_SECONDARY;
}
t = settings & MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE ? 1 : 0;
printf("Enable write caching: [Yes or No, default is %s] ", t == 0 ? "No" : "Yes");
if (getYesNoAnswer(t))
settings |= MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE;
else
settings &= ~MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE;
RaidVolumePage0->VolumeSettings.Settings = set16(settings);
flags = 0;
printf("Zero the first and last blocks of the volume? [Yes or No, default is No] ");
if (getYesNoAnswer(0) == 1)
flags |= MPI_RAID_ACTION_ADATA_LOW_LEVEL_INIT;
printf("Skip initial volume resync? [Yes or No, default is No] ");
if (getYesNoAnswer(0) == 1)
flags |= MPI_RAID_ACTION_ADATA_DO_NOT_SYNC;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_RAID_ACTION;
req.Action = MPI_RAID_ACTION_CREATE_VOLUME;
req.VolumeBus = first_bus;
req.VolumeID = first_target;
req.ActionDataWord = set32(flags);
t = doMptCommandCheck(port, &req, sizeof req - sizeof req.ActionDataSGE, &rep, sizeof rep,
NULL, 0, RaidVolumePage0, length, LONG_TIME);
if (t)
printf("\nVolume was created\n");
free(RaidVolumePage0);
return t;
}
int
doDeleteVolume(MPT_PORT *port, IOCPage2_t *IOCPage2)
{
MpiRaidActionRequest_t req;
MpiRaidActionReply_t rep;
IOCPage5_t IOCPage5;
int volume;
int i;
int flags;
if (selectVolume(port, IOCPage2, &volume) != 1)
return 0;
printf("All data on Volume %d will be lost!\n", volume);
printf("\nAre you sure you want to continue? [Yes or No, default is No] ");
if (getYesNoAnswer(0) != 1)
return 1;
flags = MPI_RAID_ACTION_ADATA_DEL_PHYS_DISKS;
printf("Zero the first block of all volume members? [Yes or No, default is No] ");
if (getYesNoAnswer(0) == 1)
flags |= MPI_RAID_ACTION_ADATA_ZERO_LBA0;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_RAID_ACTION;
req.Action = MPI_RAID_ACTION_DELETE_VOLUME;
req.VolumeBus = IOCPage2->RaidVolume[volume].VolumeBus;
req.VolumeID = IOCPage2->RaidVolume[volume].VolumeID;
req.ActionDataWord = set32(flags);
printf("\nVolume %d is being deleted\n", volume);
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
{
printf("\nVolume delete operation failed!\n");
return 0;
}
if (IOCPage2->NumActiveVolumes > 1)
return 1;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 5, 0, &IOCPage5, sizeof IOCPage5) != 1)
return 1;
for (i = 0; i < IOCPage5.NumHotSpares; i++)
{
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_RAID_ACTION;
req.Action = MPI_RAID_ACTION_DELETE_PHYSDISK;
req.PhysDiskNum = IOCPage5.HotSpare[i].PhysDiskNum;
printf("\nHot Spare %d (PhysDisk %d) is being deleted\n",
i, IOCPage5.HotSpare[i].PhysDiskNum);
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
{
printf("\nHot Spare delete operation failed!\n");
}
}
return 1;
}
int
doVolumeSettings(MPT_PORT *port, IOCPage2_t *IOCPage2)
{
RaidVolumePage0_t *RaidVolumePage0;
MpiRaidActionRequest_t req;
MpiRaidActionReply_t rep;
int length;
int b_t;
int volume;
int t1;
int t2;
int t;
if (selectVolume(port, IOCPage2, &volume) != 1)
return 0;
b_t = (IOCPage2->RaidVolume[volume].VolumeBus << 8) + IOCPage2->RaidVolume[volume].VolumeID;
RaidVolumePage0 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_RAID_VOLUME, 0, b_t, &length);
if (RaidVolumePage0 == NULL)
return 0;
t1 = get16(RaidVolumePage0->VolumeSettings.Settings);
t2 = RaidVolumePage0->VolumeSettings.HotSparePool;
printf("Volume %d Settings: write caching %s%s%s%s\n", volume,
t1 & MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE ? "enabled" : "disabled",
t1 & MPI_RAIDVOL0_SETTING_OFFLINE_ON_SMART ? ", offline on SMART data" : "",
t1 & MPI_RAIDVOL0_SETTING_AUTO_CONFIGURE ? ", auto configure" : "",
t1 & MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC ? ", priority resync" : "");
if (t2 != 0)
printf("Volume %d draws from Hot Spare Pools: %s%s%s%s%s%s%s%s\n", volume,
t2 & MPI_RAID_HOT_SPARE_POOL_0 ? " 0" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_1 ? " 1" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_2 ? " 2" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_3 ? " 3" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_4 ? " 4" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_5 ? " 5" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_6 ? " 6" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_7 ? " 7" : "");
printf("\n");
t = t1 & MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE ? 1 : 0;
printf("Enable write caching: [Yes or No, default is %s] ", t == 0 ? "No" : "Yes");
if (getYesNoAnswer(t))
t1 |= MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE;
else
t1 &= ~MPI_RAIDVOL0_SETTING_WRITE_CACHING_ENABLE;
t = t1 & MPI_RAIDVOL0_SETTING_OFFLINE_ON_SMART ? 1 : 0;
printf("Offline on SMART data: [Yes or No, default is %s] ", t == 0 ? "No" : "Yes");
if (getYesNoAnswer(t))
t1 |= MPI_RAIDVOL0_SETTING_OFFLINE_ON_SMART;
else
t1 &= ~MPI_RAIDVOL0_SETTING_OFFLINE_ON_SMART;
t = t1 & MPI_RAIDVOL0_SETTING_AUTO_CONFIGURE ? 1 : 0;
printf("Auto configuration: [Yes or No, default is %s] ", t == 0 ? "No" : "Yes");
if (getYesNoAnswer(t))
t1 |= MPI_RAIDVOL0_SETTING_AUTO_CONFIGURE;
else
t1 &= ~MPI_RAIDVOL0_SETTING_AUTO_CONFIGURE;
t = t1 & MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC ? 1 : 0;
printf("Priority resync: [Yes or No, default is %s] ", t == 0 ? "No" : "Yes");
if (getYesNoAnswer(t))
t1 |= MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC;
else
t1 &= ~MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC;
printf("Hot Spare Pools (bitmask of pool numbers): [00 to FF, default is %02x] ", t2);
t2 = getNumberAnswerHex(0x00, 0xff, t2);
RaidVolumePage0->VolumeSettings.Settings = set16(t1);
RaidVolumePage0->VolumeSettings.HotSparePool = (U8)t2;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_RAID_ACTION;
req.Action = MPI_RAID_ACTION_CHANGE_VOLUME_SETTINGS;
req.VolumeBus = IOCPage2->RaidVolume[volume].VolumeBus;
req.VolumeID = IOCPage2->RaidVolume[volume].VolumeID;
memcpy(&req.ActionDataWord, &RaidVolumePage0->VolumeSettings, sizeof req.ActionDataWord);
free(RaidVolumePage0);
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doVolumeName(MPT_PORT *port, IOCPage2_t *IOCPage2)
{
MpiRaidActionRequest_t req;
MpiRaidActionReply_t rep;
RaidVolumePage1_t RaidVolumePage1;
int b_t;
int volume;
char name[16];
int n;
if (selectVolume(port, IOCPage2, &volume) != 1)
return 0;
b_t = (IOCPage2->RaidVolume[volume].VolumeBus << 8) + IOCPage2->RaidVolume[volume].VolumeID;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_RAID_VOLUME, 1, b_t,
&RaidVolumePage1, sizeof RaidVolumePage1) != 1)
return 0;
printf("Enter a volume name: [0 to %d characters, current is \"%s\"] ",
(int)sizeof name - 1, RaidVolumePage1.Name);
n = getStringFromArgs(name, sizeof name, stdin);
if (n == 0)
{
return 0;
}
if (n >= sizeof name)
{
printf("\nThe name is too long, current name not changed!\n");
return 0;
}
memset(name + n, '\0', sizeof name - n);
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_RAID_ACTION;
req.Action = MPI_RAID_ACTION_SET_VOLUME_NAME;
req.VolumeBus = IOCPage2->RaidVolume[volume].VolumeBus;
req.VolumeID = IOCPage2->RaidVolume[volume].VolumeID;
printf("\nVolume %d's name is being changed...\n", volume);
return doMptCommandCheck(port, &req, sizeof req - sizeof req.ActionDataSGE, &rep, sizeof rep,
NULL, 0, name, sizeof name, SHORT_TIME);
}
int
doDriveFirmwareUpdateMode(MPT_PORT *port, IOCPage2_t *IOCPage2, IOCPage3_t *IOCPage3, int flag)
{
MpiRaidActionRequest_t req;
MpiRaidActionReply_t rep;
int physdisk;
int timeout;
if (IOCPage3->NumPhysDisks == 0)
{
printf("No active physical disks\n");
return 1;
}
printf("PhysDisk: [0-%d or RETURN to quit] ", IOCPage2->MaxPhysDisks - 1);
physdisk = getNumberAnswer(0, IOCPage2->MaxPhysDisks - 1, -1);
if (physdisk < 0)
return 1;
printf("Timeout in seconds: [0-255 or RETURN to quit] ");
timeout = getNumberAnswer(0, 255, -1);
if (timeout < 0)
return 1;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_RAID_ACTION;
req.Action = MPI_RAID_ACTION_DEVICE_FW_UPDATE_MODE;
req.PhysDiskNum = physdisk;
req.ActionDataWord = set32((timeout << MPI_RAID_ACTION_ADATA_SHIFT_FW_UPDATE_TIMEOUT) | flag);
printf("\nDrive Firmware Update Mode on PhysDisk %d is being %s\n", physdisk, flag ? "enabled" : "disabled");
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doModifyPhysDisk(MPT_PORT *port, IOCPage2_t *IOCPage2, IOCPage3_t *IOCPage3, int action, char *string)
{
MpiRaidActionRequest_t req;
MpiRaidActionReply_t rep;
int physdisk;
int physdisk2;
if (IOCPage3->NumPhysDisks == 0)
{
printf("No active physical disks\n");
return 1;
}
printf("PhysDisk: [0-%d or RETURN to quit] ", IOCPage2->MaxPhysDisks - 1);
physdisk = getNumberAnswer(0, IOCPage2->MaxPhysDisks - 1, -1);
if (physdisk < 0)
return 1;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_RAID_ACTION;
req.Action = action;
req.PhysDiskNum = physdisk;
if (action == MPI_RAID_ACTION_REPLACE_PHYSDISK)
{
printf("Replacement PhysDisk: [0-%d or RETURN to quit] ", IOCPage2->MaxPhysDisks - 1);
physdisk2 = getNumberAnswer(0, IOCPage2->MaxPhysDisks - 1, -1);
if (physdisk2 < 0)
return 1;
req.ActionDataWord = set32(physdisk2);
}
printf("\nPhysDisk %d is being %s\n", physdisk, string);
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doCreatePhysDisk(MPT_PORT *port, IOCPage2_t *IOCPage2)
{
RaidPhysDiskPage0_t RaidPhysDiskPage0;
MpiRaidActionRequest_t req;
MpiRaidActionReply_t rep;
ConfigReply_t config_rep;
int bus;
int target;
int physdisk;
if (getConfigPageHeader(port, MPI_CONFIG_PAGETYPE_RAID_PHYSDISK, 0, 0, &config_rep) != 1)
return 0;
while (TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
break;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
break;
memset(&RaidPhysDiskPage0, 0, sizeof RaidPhysDiskPage0);
RaidPhysDiskPage0.Header.PageType = config_rep.Header.PageType;
RaidPhysDiskPage0.Header.PageNumber = config_rep.Header.PageNumber;
RaidPhysDiskPage0.Header.PageLength = config_rep.Header.PageLength;
RaidPhysDiskPage0.Header.PageVersion = config_rep.Header.PageVersion;
RaidPhysDiskPage0.PhysDiskIOC = port->iocNumber;
RaidPhysDiskPage0.PhysDiskBus = bus;
RaidPhysDiskPage0.PhysDiskID = target;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_RAID_ACTION;
req.Action = MPI_RAID_ACTION_CREATE_PHYSDISK;
if (doMptCommandCheck(port, &req, sizeof req - sizeof req.ActionDataSGE, &rep, sizeof rep,
NULL, 0, &RaidPhysDiskPage0, sizeof RaidPhysDiskPage0, SHORT_TIME) != 1)
return 0;
physdisk = get32(rep.ActionData);
printf("PhysDisk %d was created\n", physdisk);
}
return 1;
}
int
doPhysDiskSettings(MPT_PORT *port, IOCPage2_t *IOCPage2, IOCPage3_t *IOCPage3)
{
RaidPhysDiskPage0_t RaidPhysDiskPage0;
MpiRaidActionRequest_t req;
MpiRaidActionReply_t rep;
int physdisk;
int t2;
if (IOCPage3->NumPhysDisks == 0)
{
printf("No active physical disks\n");
return 1;
}
printf("PhysDisk: [0-%d or RETURN to quit] ", IOCPage2->MaxPhysDisks - 1);
physdisk = getNumberAnswer(0, IOCPage2->MaxPhysDisks - 1, -1);
if (physdisk < 0)
return 1;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_RAID_PHYSDISK, 0, physdisk,
&RaidPhysDiskPage0, sizeof RaidPhysDiskPage0) != 1)
return 0;
t2 = RaidPhysDiskPage0.PhysDiskSettings.HotSparePool;
if (t2 != 0)
printf("PhysDisk %d belongs to Hot Spare Pools: %s%s%s%s%s%s%s%s\n", physdisk,
t2 & MPI_RAID_HOT_SPARE_POOL_0 ? " 0" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_1 ? " 1" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_2 ? " 2" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_3 ? " 3" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_4 ? " 4" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_5 ? " 5" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_6 ? " 6" : "",
t2 & MPI_RAID_HOT_SPARE_POOL_7 ? " 7" : "");
printf("\n");
printf("Hot Spare Pools (bitmask of pool numbers): [00 to FF, default is %02x] ", t2);
t2 = getNumberAnswerHex(0x00, 0xff, t2);
RaidPhysDiskPage0.PhysDiskSettings.HotSparePool = (U8)t2;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_RAID_ACTION;
req.Action = MPI_RAID_ACTION_CHANGE_PHYSDISK_SETTINGS;
req.PhysDiskNum = physdisk;
memcpy(&req.ActionDataWord, &RaidPhysDiskPage0.PhysDiskSettings, sizeof req.ActionDataWord);
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doCreateHotSpare(MPT_PORT *port, IOCPage2_t *IOCPage2, IOCPage3_t *IOCPage3)
{
RaidPhysDiskPage0_t RaidPhysDiskPage0;
IOCPage5_t IOCPage5;
IOCPage6_t IOCPage6;
MpiRaidActionRequest_t req;
MpiRaidActionReply_t rep;
ConfigReply_t config_rep;
int bus;
int target;
unsigned char inq[36];
unsigned char cap[8];
unsigned int size;
int i;
int n;
int t;
if (IOCPage3->NumPhysDisks == IOCPage2->MaxPhysDisks)
{
printf("Cannot create another active physical disk\n");
return 1;
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 6, 0, &IOCPage6, sizeof IOCPage6) != 1)
{
memset(&IOCPage6, 0, sizeof IOCPage6);
IOCPage6.MaxDrivesIS = IOCPage2->MaxPhysDisks;
IOCPage6.MaxDrivesIM = 2;
IOCPage6.MaxDrivesIME = IOCPage2->MaxPhysDisks;
if (IOCPage2->MaxVolumes > 1)
{
IOCPage6.MaxDrivesIS -= 2;
IOCPage6.MaxDrivesIME -= 2;
}
IOCPage6.MaxGlobalHotSpares = 1;
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 5, 0, &IOCPage5, sizeof IOCPage5) == 1)
{
if (IOCPage5.NumHotSpares >= IOCPage6.MaxGlobalHotSpares)
{
printf("Cannot create another hot spare\n");
return 1;
}
}
printf(" B___T___L Type Vendor Product Rev Disk Blocks Disk MB\n");
n = 0;
for (bus = 0; bus < port->maxBuses; bus++)
{
for (target = port->minTargets; target < port->maxTargets; target++)
{
if (isRaidVolume(port, bus, target))
continue;
if (doInquiry(port, bus, target, 0, inq, sizeof inq) != 1)
{
#if __linux__ || DOS || EFI
if (errno == EFAULT)
return 0;
#endif
continue;
}
if ((inq[0] & 0x1f) != 0x00)
continue;
if ((inq[0] & 0xe0) == 0x20)
continue;
if ((inq[0] & 0xe0) == 0x60)
continue;
for (i = 8; i < 36; i++)
if (!isprint(inq[i]))
inq[i] = ' ';
if (doReadCapacity(port, bus, target, 0, cap, sizeof cap) != 1)
continue;
size = get4bytes(cap, 0);
diag_targets[n].bus = bus;
diag_targets[n].target = target;
diag_targets[n].size = size;
n++;
printf("%2d. %2d %3d %3d %-9s %-8.8s %-16.16s %-4.4s %10d %7d\n",
n, bus, target, 0, deviceType[inq[0] & 0x1f],
inq+8, inq+16, inq+32, size + 1, (size + 1) / 2048);
if (n == MAX_DEVICES)
break;
}
if (n == MAX_DEVICES)
break;
}
if (n < 1)
{
printf("\nNo available targets found\n");
return 1;
}
printf("\nTo create a hot spare, select one of the available targets\n\n");
if (getConfigPageHeader(port, MPI_CONFIG_PAGETYPE_RAID_PHYSDISK, 0, 0, &config_rep) != 1)
return 0;
printf("Select a target: [1-%d or RETURN to quit] ", n);
i = getNumberAnswer(1, n, 0);
if (i == 0)
return 1;
i--;
bus = diag_targets[i].bus;
target = diag_targets[i].target;
printf("Hot Spare Pool: [0-7 or RETURN to quit] ");
t = getNumberAnswer(0, 7, -1);
if (t < 0)
return 1;
memset(&RaidPhysDiskPage0, 0, sizeof RaidPhysDiskPage0);
RaidPhysDiskPage0.Header.PageType = config_rep.Header.PageType;
RaidPhysDiskPage0.Header.PageNumber = config_rep.Header.PageNumber;
RaidPhysDiskPage0.Header.PageLength = config_rep.Header.PageLength;
RaidPhysDiskPage0.Header.PageVersion = config_rep.Header.PageVersion;
RaidPhysDiskPage0.PhysDiskIOC = port->iocNumber;
RaidPhysDiskPage0.PhysDiskBus = bus;
RaidPhysDiskPage0.PhysDiskID = target;
RaidPhysDiskPage0.PhysDiskSettings.HotSparePool = (U8)(1 << t);
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_RAID_ACTION;
req.Action = MPI_RAID_ACTION_CREATE_PHYSDISK;
if (doMptCommandCheck(port, &req, sizeof req - sizeof req.ActionDataSGE, &rep, sizeof rep,
NULL, 0, &RaidPhysDiskPage0, sizeof RaidPhysDiskPage0, SHORT_TIME) != 1)
return 0;
printf("\nHot Spare was created\n");
return 1;
}
int
doDeleteHotSpare(MPT_PORT *port, IOCPage2_t *IOCPage2, IOCPage3_t *IOCPage3)
{
MpiRaidActionRequest_t req;
MpiRaidActionReply_t rep;
IOCPage5_t IOCPage5;
int physdisk;
int i;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 5, 0, &IOCPage5, sizeof IOCPage5) != 1)
return 1;
if (IOCPage5.NumHotSpares == 0)
{
printf("No active hot spares\n");
return 1;
}
printf("PhysDisk: [0-%d or RETURN to quit] ", IOCPage2->MaxPhysDisks - 1);
physdisk = getNumberAnswer(0, IOCPage2->MaxPhysDisks - 1, -1);
if (physdisk < 0)
return 1;
for (i = 0; i < IOCPage5.NumHotSpares; i++)
{
if (physdisk == IOCPage5.HotSpare[i].PhysDiskNum)
{
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_RAID_ACTION;
req.Action = MPI_RAID_ACTION_DELETE_PHYSDISK;
req.PhysDiskNum = IOCPage5.HotSpare[i].PhysDiskNum;
printf("\nHot Spare %d (PhysDisk %d) is being deleted\n",
i, IOCPage5.HotSpare[i].PhysDiskNum);
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
{
printf("\nHot Spare delete operation failed!\n");
}
return 1;
}
}
printf("PhysDisk %d is not a valid hot spare!\n", physdisk);
return 0;
}
int
showHiddenDevices(MPT_PORT *port)
{
IOCPage2_t *IOCPage2;
IOCPage3_t *IOCPage3;
RaidPhysDiskPage0_t RaidPhysDiskPage0;
int i;
int physdisk;
int nd;
int length;
int bus;
int target;
char buf[32];
if (mpi2)
return showHiddenDevices2(port);
IOCPage2 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_IOC, 2, 0, &length);
if (IOCPage2 == NULL || IOCPage2->MaxVolumes == 0)
{
if (IOCPage2)
free(IOCPage2);
return 0;
}
IOCPage3 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_IOC, 3, 0, &length);
if (IOCPage3 == NULL)
{
free(IOCPage2);
return 0;
}
nd = IOCPage3->NumPhysDisks;
if (nd == 0 && IOCPage2->NumActiveVolumes)
nd = IOCPage2->MaxPhysDisks;
if (nd)
{
printf("\nHidden RAID Devices:\n\n");
getDeviceInfoHeader(port, buf, sizeof buf);
printf(" B___T Device Vendor Product Rev %s\n", buf);
for (i = 0; i < nd; i++)
{
if (IOCPage3->NumPhysDisks)
physdisk = IOCPage3->PhysDisk[i].PhysDiskNum;
else
physdisk = i;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_RAID_PHYSDISK, 0, physdisk,
&RaidPhysDiskPage0, sizeof RaidPhysDiskPage0) != 1)
continue;
if (!IOCPage3->NumPhysDisks)
if (RaidPhysDiskPage0.PhysDiskStatus.State & MPI_PHYSDISK0_STATUS_MISSING)
continue;
bus = RaidPhysDiskPage0.PhysDiskBus;
target = RaidPhysDiskPage0.PhysDiskID;
getDeviceInfo(port, bus, target, buf, sizeof buf);
printf("%2d %3d PhysDisk %-4d %-8.8s %-16.16s %-4.4s %s\n",
bus, target, physdisk,
RaidPhysDiskPage0.InquiryData.VendorID,
RaidPhysDiskPage0.InquiryData.ProductID,
RaidPhysDiskPage0.InquiryData.ProductRevLevel, buf);
}
}
free(IOCPage2);
free(IOCPage3);
return 1;
}
int
doRaidActions2(MPT_PORT *port, int command)
{
Mpi2IOCPage6_t *IOCPage6;
int length;
if (!(port->capabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
{
printf("INTEGRATED_RAID capability is not set!\n");
printf("RAID is not supported on this port\n");
return 0;
}
IOCPage6 = getConfigPageAlloc(port, MPI2_CONFIG_PAGETYPE_IOC, 6, 0, &length);
if (IOCPage6 == NULL)
{
printf("Failed to read IOCPage6!\n");
printf("RAID is not supported on this port\n");
return 0;
}
if (IOCPage6->MaxVolumes == 0)
{
printf("MaxVolumes is zero!\n");
printf("RAID is not supported on this port\n");
return 0;
}
switch (command)
{
case 1:
doShowVolumes2(port, IOCPage6);
break;
case 2:
doShowPhysDisks2(port, IOCPage6);
break;
case 3:
doGetVolumeState2(port);
break;
case 4:
doWaitForResync2(port);
break;
case 10:
doModifyVolume2(port, MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES, "disabled");
break;
case 11:
doModifyVolume2(port, MPI2_RAID_ACTION_ENABLE_ALL_VOLUMES, "enabled");
break;
case 13:
doModifyVolume2(port, MPI2_RAID_ACTION_ACTIVATE_VOLUME, "activated");
break;
case 20:
doModifyPhysDisk2(port, IOCPage6, MPI2_RAID_ACTION_PHYSDISK_OFFLINE, "offlined");
break;
case 21:
doModifyPhysDisk2(port, IOCPage6, MPI2_RAID_ACTION_PHYSDISK_ONLINE, "onlined");
break;
case 22:
doModifyPhysDisk2(port, IOCPage6, MPI2_RAID_ACTION_FAIL_PHYSDISK, "failed");
break;
case 26:
doDriveFirmwareUpdateMode2(port, IOCPage6, 0);
break;
case 27:
doDriveFirmwareUpdateMode2(port, IOCPage6, 1);
break;
case 30:
doCreateVolume2(port, IOCPage6);
break;
case 31:
doDeleteVolume2(port, IOCPage6);
break;
case 32:
doVolumeSettings2(port);
break;
case 33:
doVolumeName2(port);
break;
case 34:
doVolumeIRCC2(port);
break;
case 35:
doVolumeStopIRCC2(port);
break;
case 36:
doVolumeOCE(port);
break;
case 50:
doCreateHotSpare2(port, IOCPage6);
break;
case 51:
doDeleteHotSpare2(port, IOCPage6);
break;
case 60:
doModifyVolume2(port, MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE, "modified");
break;
default:
printf("Invalid selection!\n");
break;
}
free(IOCPage6);
#if DOS || EFI
// give the firmware a chance to update the volume metadata
sleep(5);
#endif
return 1;
}
int
selectVolume2(MPT_PORT *port, int *volumeOut, int *handleOut)
{
Mpi2RaidVolPage0_t *RaidVolumePage0;
int volume;
int volumes[MAX_DEVICES];
int i;
int length;
int handle;
int type;
int flags;
int bus;
int target;
handle = 0xffff;
for (i = 0; ; i++)
{
RaidVolumePage0 = getConfigPageAlloc(port, MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 0,
MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE + handle,
&length);
if (RaidVolumePage0 == NULL)
break;
handle = get16(RaidVolumePage0->DevHandle);
type = RaidVolumePage0->VolumeType;
flags = get32(RaidVolumePage0->VolumeStatusFlags);
if (mapDevHandleToBusTarget(port, handle, &bus, &target))
{
printf("Volume %d is DevHandle %04x, Bus %d Target %d, Type %s%s\n",
i, handle, bus, target,
type == MPI2_RAID_VOL_TYPE_RAID0 ? "RAID0 (Striping)" :
type == MPI2_RAID_VOL_TYPE_RAID1E ? "RAID1E (Mirroring Extended)" :
type == MPI2_RAID_VOL_TYPE_RAID1 ? "RAID1 (Mirroring)" :
type == MPI2_RAID_VOL_TYPE_RAID10 ? "RAID10 (Striped Mirroring)" : "Unknown",
flags & MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ? ", inactive" : "");
}
else
{
printf("Volume %d is DevHandle %04x, Type %s%s\n",
i, handle,
type == MPI2_RAID_VOL_TYPE_RAID0 ? "RAID0 (Striping)" :
type == MPI2_RAID_VOL_TYPE_RAID1E ? "RAID1E (Mirroring Extended)" :
type == MPI2_RAID_VOL_TYPE_RAID1 ? "RAID1 (Mirroring)" :
type == MPI2_RAID_VOL_TYPE_RAID10 ? "RAID10 (Striped Mirroring)" : "Unknown",
flags & MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ? ", inactive" : "");
}
volumes[i] = handle;
free(RaidVolumePage0);
}
printf("\n");
if (i == 0)
{
printf("No volumes found.\n");
return 0;
}
else
{
if (i > 1 || gFlag == TRUE)
{
printf("Volume: [0-%d or RETURN to quit] ", i - 1);
volume = getNumberAnswer(0, i - 1, -1);
if (volume < 0)
return 0;
printf("\n");
}
else
{
volume = 0;
}
}
*volumeOut = volume;
*handleOut = volumes[volume];
return 1;
}
int
doShowVolumes2(MPT_PORT *port, Mpi2IOCPage6_t *IOCPage6)
{
Mpi2RaidVolPage0_t *RaidVolumePage0;
Mpi2RaidVolPage1_t RaidVolumePage1;
Mpi2RaidPhysDiskPage0_t RaidPhysDiskPage0;
int i;
int j;
int t1;
int t2;
int t3;
int length;
int handle2;
int handle;
int physdisk;
int type;
int flags;
int bus;
int target;
handle = 0xffff;
for (i = 0; ; i++)
{
RaidVolumePage0 = getConfigPageAlloc(port, MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 0,
MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE + handle,
&length);
if (RaidVolumePage0 == NULL)
break;
if (i)
printf("\n");
handle = get16(RaidVolumePage0->DevHandle);
type = RaidVolumePage0->VolumeType;
flags = get32(RaidVolumePage0->VolumeStatusFlags);
if (mapDevHandleToBusTarget(port, handle, &bus, &target))
{
printf("Volume %d is DevHandle %04x, Bus %d Target %d, Type %s%s\n",
i, handle, bus, target,
type == MPI2_RAID_VOL_TYPE_RAID0 ? "RAID0 (Striping)" :
type == MPI2_RAID_VOL_TYPE_RAID1E ? "RAID1E (Mirroring Extended)" :
type == MPI2_RAID_VOL_TYPE_RAID1 ? "RAID1 (Mirroring)" :
type == MPI2_RAID_VOL_TYPE_RAID10 ? "RAID10 (Striped Mirroring)" : "Unknown",
flags & MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ? ", inactive" : "");
}
else
{
printf("Volume %d is DevHandle %04x, Type %s%s\n",
i, handle,
type == MPI2_RAID_VOL_TYPE_RAID0 ? "RAID0 (Striping)" :
type == MPI2_RAID_VOL_TYPE_RAID1E ? "RAID1E (Mirroring Extended)" :
type == MPI2_RAID_VOL_TYPE_RAID1 ? "RAID1 (Mirroring)" :
type == MPI2_RAID_VOL_TYPE_RAID10 ? "RAID10 (Striped Mirroring)" : "Unknown",
flags & MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ? ", inactive" : "");
}
if (getConfigPage(port, MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 1,
MPI2_RAID_VOLUME_PGAD_FORM_HANDLE + handle,
&RaidVolumePage1, sizeof RaidVolumePage1) == 1)
{
printf(" Volume Name: %-32s\n",
RaidVolumePage1.Name);
printf(" Volume WWID: %08x%08x\n",
get32(RaidVolumePage1.WWID.High), get32(RaidVolumePage1.WWID.Low));
}
t1 = RaidVolumePage0->VolumeState;
t2 = flags;
doShowVolumeState2(i, t1, t2, FALSE);
if ( flags & MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE )
{
t3 = RaidVolumePage0->InactiveStatus;
printf(" Volume Inactive Reason: %s\n",
t3 == MPI2_RAIDVOLPAGE0_STALE_METADATA_INACTIVE ? "stale metadata" :
t3 == MPI2_RAIDVOLPAGE0_FOREIGN_VOLUME_INACTIVE ? "foreign volume" :
t3 == MPI2_RAIDVOLPAGE0_INSUFFICIENT_RESOURCE_INACTIVE ? "insufficient resources" :
t3 == MPI2_RAIDVOLPAGE0_CLONE_VOLUME_INACTIVE ? "clone of volume found" :
t3 == MPI2_RAIDVOLPAGE0_INSUFFICIENT_METADATA_INACTIVE ? "insufficent valid metadata" :
t3 == MPI2_RAIDVOLPAGE0_PREVIOUSLY_DELETED ? "volume previously deleted" : "unknown");
}
t1 = get16(RaidVolumePage0->VolumeSettings.Settings);
t2 = RaidVolumePage0->VolumeSettings.HotSparePool;
printf(" Volume Settings: write caching %s, auto configure hot swap %s%s\n",
t1 & MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING ? "enabled" :
t1 & MPI2_RAIDVOL0_SETTING_DISABLE_WRITE_CACHING ? "disabled" : "controlled by members",
t1 & MPI2_RAIDVOL0_SETTING_AUTO_CONFIG_HSWAP_DISABLE ? "disabled" : "enabled",
flags & MPI2_RAIDVOL0_STATUS_FLAG_DATA_SCRUB ? ", data scrub allowed" : "");
if (t2 != 0)
printf(" Volume draws from Hot Spare Pools: %s%s%s%s%s%s%s%s\n",
t2 & MPI2_RAID_HOT_SPARE_POOL_0 ? " 0" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_1 ? " 1" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_2 ? " 2" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_3 ? " 3" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_4 ? " 4" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_5 ? " 5" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_6 ? " 6" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_7 ? " 7" : "");
if (type == MPI2_RAID_VOL_TYPE_RAID1)
printf(" Volume Size %" INT64_FMT "d MB, %d Members\n",
(get64(RaidVolumePage0->MaxLBA) + 1) / 2048, RaidVolumePage0->NumPhysDisks);
else
printf(" Volume Size %" INT64_FMT "d MB, Stripe Size %d KB, %d Members\n",
(get64(RaidVolumePage0->MaxLBA) + 1) / 2048, get32(RaidVolumePage0->StripeSize) / 2,
RaidVolumePage0->NumPhysDisks);
for (j = 0; j < RaidVolumePage0->NumPhysDisks; j++)
{
physdisk = RaidVolumePage0->PhysDisk[j].PhysDiskNum;
if (getConfigPage(port, MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK, 0,
MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM + physdisk,
&RaidPhysDiskPage0, sizeof RaidPhysDiskPage0) == 1)
{
handle2 = get16(RaidPhysDiskPage0.DevHandle);
if (mapDevHandleToBusTarget(port, handle2, &bus, &target))
{
if (type == MPI2_RAID_VOL_TYPE_RAID1)
printf(" %s is PhysDisk %d (DevHandle %04x, Bus %d Target %d)\n",
RaidVolumePage0->PhysDisk[j].PhysDiskMap == MPI2_RAIDVOL0_PHYSDISK_PRIMARY ? "Primary" :
RaidVolumePage0->PhysDisk[j].PhysDiskMap == MPI2_RAIDVOL0_PHYSDISK_SECONDARY ? "Secondary" :
"Member", RaidVolumePage0->PhysDisk[j].PhysDiskNum, handle2, bus, target);
else
printf(" Member %d is PhysDisk %d (DevHandle %04x, Bus %d Target %d)\n",
RaidVolumePage0->PhysDisk[j].PhysDiskMap, RaidVolumePage0->PhysDisk[j].PhysDiskNum,
handle2, bus, target);
}
else
{
if (type == MPI2_RAID_VOL_TYPE_RAID1)
printf(" %s is PhysDisk %d (DevHandle %04x)\n",
RaidVolumePage0->PhysDisk[j].PhysDiskMap == MPI2_RAIDVOL0_PHYSDISK_PRIMARY ? "Primary" :
RaidVolumePage0->PhysDisk[j].PhysDiskMap == MPI2_RAIDVOL0_PHYSDISK_SECONDARY ? "Secondary" :
"Member", RaidVolumePage0->PhysDisk[j].PhysDiskNum, handle2);
else
printf(" Member %d is PhysDisk %d (DevHandle %04x)\n",
RaidVolumePage0->PhysDisk[j].PhysDiskMap, RaidVolumePage0->PhysDisk[j].PhysDiskNum,
handle2);
}
}
}
free(RaidVolumePage0);
}
if (i == 0)
printf("No volumes active\n");
return 1;
}
int
doShowPhysDisks2(MPT_PORT *port, Mpi2IOCPage6_t *IOCPage6)
{
Mpi2RaidPhysDiskPage0_t RaidPhysDiskPage0;
Mpi2RaidPhysDiskPage1_t *RaidPhysDiskPage1;
int i;
int j;
int physdisk;
int np;
int t1;
int t2;
int length;
int handle;
int handle2;
int bus;
int target;
physdisk = 0xff;
for (i = 0; ; i++)
{
if (getConfigPage(port, MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK, 0,
MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM + physdisk,
&RaidPhysDiskPage0, sizeof RaidPhysDiskPage0) != 1)
break;
if (i)
printf("\n");
physdisk = RaidPhysDiskPage0.PhysDiskNum;
handle = get16(RaidPhysDiskPage0.DevHandle);
if (mapDevHandleToBusTarget(port, handle, &bus, &target))
{
printf("PhysDisk %d is DevHandle %04x, Bus %d Target %d\n",
physdisk, handle, bus, target);
}
else
{
printf("PhysDisk %d is DevHandle %04x\n",
physdisk, handle);
}
t1 = RaidPhysDiskPage0.PhysDiskState;
t2 = get32(RaidPhysDiskPage0.PhysDiskStatusFlags);
printf(" PhysDisk State: %s%s%s%s%s%s%s\n",
t1 == MPI2_RAID_PD_STATE_NOT_CONFIGURED ? "not configured" :
t1 == MPI2_RAID_PD_STATE_NOT_COMPATIBLE ? "not compatible" :
t1 == MPI2_RAID_PD_STATE_OFFLINE ? "offline" :
t1 == MPI2_RAID_PD_STATE_ONLINE ? "online" :
t1 == MPI2_RAID_PD_STATE_HOT_SPARE ? "hot spare" :
t1 == MPI2_RAID_PD_STATE_DEGRADED ? "degraded" :
t1 == MPI2_RAID_PD_STATE_REBUILDING ? "rebuilding" :
t1 == MPI2_RAID_PD_STATE_OPTIMAL ? "optimal" : "unknown",
t2 & MPI2_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC ? ", out of sync" : "",
t2 & MPI2_PHYSDISK0_STATUS_FLAG_QUIESCED ? ", quiesced" : "",
t2 & MPI2_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME ? ", member of inactive volume" : "",
t2 & MPI2_PHYSDISK0_STATUS_FLAG_WRITE_CACHE_ENABLED ? ", write cache enabled" : "",
t2 & MPI2_PHYSDISK0_STATUS_FLAG_OCE_TARGET ? ", online capacity expansion target" : "",
t2 & MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED ? ", disk not certified" : "");
if (t1 == MPI2_RAID_PD_STATE_NOT_COMPATIBLE)
{
t2 = RaidPhysDiskPage0.IncompatibleReason;
printf(" PhysDisk Incompatible Reason: %s\n",
t2 == MPI2_PHYSDISK0_INCOMPATIBLE_PROTOCOL ? "incorrect protocol" :
t2 == MPI2_PHYSDISK0_INCOMPATIBLE_BLOCKSIZE ? "block size mismatch" :
t2 == MPI2_PHYSDISK0_INCOMPATIBLE_MAX_LBA ? "disk too small" :
t2 == MPI2_PHYSDISK0_INCOMPATIBLE_SATA_EXTENDED_CMD ? "SATA extended command set not supported" :
t2 == MPI2_PHYSDISK0_INCOMPATIBLE_REMOVEABLE_MEDIA ? "disk media is removable" : "unknown");
}
if (t1 == MPI2_RAID_PD_STATE_OFFLINE)
{
t2 = RaidPhysDiskPage0.OfflineReason;
printf(" PhysDisk Offline Reason: %s\n",
t2 == MPI2_PHYSDISK0_OFFLINE_MISSING ? "missing" :
t2 == MPI2_PHYSDISK0_OFFLINE_FAILED ? "failed" :
t2 == MPI2_PHYSDISK0_OFFLINE_INITIALIZING ? "initializing" :
t2 == MPI2_PHYSDISK0_OFFLINE_REQUESTED ? "offline at host request" :
t2 == MPI2_PHYSDISK0_OFFLINE_FAILED_REQUESTED ? "failed at host request" : "unknown");
}
// t1 = RaidPhysDiskPage0.PhysDiskSettings.PhysDiskSettings;
t2 = RaidPhysDiskPage0.PhysDiskSettings.HotSparePool;
// printf(" PhysDisk Settings: \n");
if (t2 != 0)
printf(" PhysDisk belongs to Hot Spare Pools: %s%s%s%s%s%s%s%s\n",
t2 & MPI2_RAID_HOT_SPARE_POOL_0 ? " 0" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_1 ? " 1" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_2 ? " 2" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_3 ? " 3" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_4 ? " 4" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_5 ? " 5" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_6 ? " 6" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_7 ? " 7" : "");
printf(" PhysDisk Size %" INT64_FMT "d MB, Inquiry Data: %-8.8s %-16.16s %-4.4s\n",
(get64(RaidPhysDiskPage0.CoercedMaxLBA) + 1) / 2048, RaidPhysDiskPage0.InquiryData.VendorID,
RaidPhysDiskPage0.InquiryData.ProductID, RaidPhysDiskPage0.InquiryData.ProductRevLevel);
RaidPhysDiskPage1 = getConfigPageAlloc(port, MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK, 1,
MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM + physdisk,
&length);
if (RaidPhysDiskPage1 == NULL)
continue;
np = RaidPhysDiskPage1->NumPhysDiskPaths;
if (np > 1)
{
for (j = 0; j < np; j++)
{
handle2 = get16(RaidPhysDiskPage1->PhysicalDiskPath[j].DevHandle);
t1 = get16(RaidPhysDiskPage1->PhysicalDiskPath[j].Flags);
if (mapDevHandleToBusTarget(port, handle2, &bus, &target))
{
printf(" Path %d is DevHandle %04x, Bus %d Target %d, %s\n", j,
handle2, bus, target,
t1 & MPI2_RAID_PHYSDISK1_FLAG_INVALID ? "invalid" :
t1 & MPI2_RAID_PHYSDISK1_FLAG_BROKEN ? "broken" :
t1 & MPI2_RAID_PHYSDISK1_FLAG_PRIMARY ? "online, primary" :
"online");
}
else
{
printf(" Path %d is DevHandle %04x, %s\n", j,
handle2,
t1 & MPI2_RAID_PHYSDISK1_FLAG_INVALID ? "invalid" :
t1 & MPI2_RAID_PHYSDISK1_FLAG_BROKEN ? "broken" :
t1 & MPI2_RAID_PHYSDISK1_FLAG_PRIMARY ? "online, primary" :
"online");
}
printf(" WWID %" INT64_FMT "x\tOwner WWID %" INT64_FMT "x\tOwner ID %x\n",
get64(RaidPhysDiskPage1->PhysicalDiskPath[j].WWID),
get64(RaidPhysDiskPage1->PhysicalDiskPath[j].OwnerWWID),
RaidPhysDiskPage1->PhysicalDiskPath[j].OwnerIdentifier);
}
}
free(RaidPhysDiskPage1);
}
if (i == 0)
printf("No physical disks active\n");
return 1;
}
void
doShowVolumeState2(int volume, int volState, int volFlag, int useVolume)
{
char volStr[5];
int gotOne;
memset(volStr, 0, sizeof(volStr));
if (useVolume)
{
sprintf(volStr, "%d ", volume);
}
printf("%sVolume %sState: %s%s%s%s%s%s\n", useVolume ? "" : " ", volStr,
volState == MPI2_RAID_VOL_STATE_OPTIMAL ? "optimal" :
volState == MPI2_RAID_VOL_STATE_DEGRADED ? "degraded" :
volState == MPI2_RAID_VOL_STATE_ONLINE ? "online" :
volState == MPI2_RAID_VOL_STATE_INITIALIZING ? "initializing" :
volState == MPI2_RAID_VOL_STATE_FAILED ? "failed" :
volState == MPI2_RAID_VOL_STATE_MISSING ? "missing" : "unknown",
volFlag & MPI2_RAIDVOL0_STATUS_FLAG_ENABLED ? ", enabled" : ", disabled",
volFlag & MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED ? ", quiesced" : "",
volFlag & MPI2_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL ? ", bad block table full" : "",
volFlag & MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED ? ", online capacity expansion allowed" : "",
volFlag & MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE ? ", background init complete" : "");
if (volFlag & (MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS |
MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT |
MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION |
MPI2_RAIDVOL0_STATUS_FLAG_CONSISTENCY_CHECK |
MPI2_RAIDVOL0_STATUS_FLAG_MAKE_DATA_CONSISTENT))
{
printf("%s [In Progress: ", useVolume ? "" : " ");
gotOne = 0;
if (volFlag & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
{
printf("resync");
gotOne = 1;
}
if (volFlag & MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT)
{
printf("%sbackground init", gotOne ? ", " : "");
gotOne = 1;
}
if (volFlag & MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION)
{
printf("%scapacity expansion", gotOne ? ", " : "");
gotOne = 1;
}
if (volFlag & MPI2_RAIDVOL0_STATUS_FLAG_CONSISTENCY_CHECK)
{
printf("%suser initiated consistency check", gotOne ? ", " : "");
gotOne = 1;
}
if (volFlag & MPI2_RAIDVOL0_STATUS_FLAG_MAKE_DATA_CONSISTENT)
{
printf("%smake data consistent", gotOne ? ", " : "");
gotOne = 1;
}
printf("]\n");
}
if (volFlag & (MPI2_RAIDVOL0_STATUS_FLAG_USER_CONSIST_PENDING |
MPI2_RAIDVOL0_STATUS_FLAG_MDC_PENDING |
MPI2_RAIDVOL0_STATUS_FLAG_BACKG_INIT_PENDING |
MPI2_RAIDVOL0_STATUS_FLAG_PENDING_RESYNC))
{
printf("%s [Pending: ", useVolume ? "" : " ");
gotOne = 0;
if (volFlag & MPI2_RAIDVOL0_STATUS_FLAG_USER_CONSIST_PENDING)
{
printf("user initiated consistency check");
gotOne = 1;
}
if (volFlag & MPI2_RAIDVOL0_STATUS_FLAG_MDC_PENDING)
{
printf("%smake data consistent", gotOne ? ", " : "");
gotOne = 1;
}
if (volFlag & MPI2_RAIDVOL0_STATUS_FLAG_BACKG_INIT_PENDING)
{
printf("%sbackground init", gotOne ? ", " : "");
gotOne = 1;
}
if (volFlag & MPI2_RAIDVOL0_STATUS_FLAG_PENDING_RESYNC)
{
printf("%sresync", gotOne ? ", " : "");
gotOne = 1;
}
printf("]\n");
}
}
int
doGetVolumeState2(MPT_PORT *port)
{
Mpi2RaidVolPage0_t *RaidVolumePage0;
Mpi2RaidActionRequest_t req;
Mpi2RaidActionReply_t rep;
Mpi2RaidVolIndicator_t *data;
int volume;
int handle;
int length;
int t1;
int t2;
int t3;
uint64_t size;
uint64_t done;
if (selectVolume2(port, &volume, &handle) != 1)
return 0;
RaidVolumePage0 = getConfigPageAlloc(port, MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 0,
MPI2_RAID_VOLUME_PGAD_FORM_HANDLE + handle,
&length);
if (RaidVolumePage0 == NULL)
{
printf("Failed to read RaidVolumePage0!\n");
return 0;
}
t1 = RaidVolumePage0->VolumeState;
t2 = get32(RaidVolumePage0->VolumeStatusFlags);
doShowVolumeState2(volume, t1, t2, TRUE);
if (t2 & MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE)
{
t3 = RaidVolumePage0->InactiveStatus;
printf("Volume %d Inactive Reason: %s\n", volume,
t3 == MPI2_RAIDVOLPAGE0_STALE_METADATA_INACTIVE ? "stale metadata" :
t3 == MPI2_RAIDVOLPAGE0_FOREIGN_VOLUME_INACTIVE ? "foreign volume" :
t3 == MPI2_RAIDVOLPAGE0_INSUFFICIENT_RESOURCE_INACTIVE ? "insufficient resources" :
t3 == MPI2_RAIDVOLPAGE0_CLONE_VOLUME_INACTIVE ? "clone of volume found" :
t3 == MPI2_RAIDVOLPAGE0_INSUFFICIENT_METADATA_INACTIVE ? "insufficent valid metadata" :
t3 == MPI2_RAIDVOLPAGE0_PREVIOUSLY_DELETED ? "volume previously deleted" : "unknown");
}
if (t2 & (MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS |
MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT |
MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION |
MPI2_RAIDVOL0_STATUS_FLAG_CONSISTENCY_CHECK |
MPI2_RAIDVOL0_STATUS_FLAG_MAKE_DATA_CONSISTENT))
{
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI2_FUNCTION_RAID_ACTION;
req.Action = MPI2_RAID_ACTION_INDICATOR_STRUCT;
req.VolDevHandle = set16(handle);
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME) != 1)
return 0;
data = (pMpi2RaidVolIndicator_t)&rep.ActionData.RaidVolumeIndicator;
size = get64(data->TotalBlocks);
done = get64(data->BlocksRemaining);
if (size && done)
{
printf("Progress: total blocks %" INT64_FMT "d, blocks remaining %" INT64_FMT "d, %d%%\n",
size, done, (int)(done / (size / 100)));
}
}
free (RaidVolumePage0);
return 1;
}
int
doWaitForResync2(MPT_PORT *port)
{
Mpi2RaidVolPage0_t *RaidVolumePage0;
Mpi2RaidActionRequest_t req;
Mpi2RaidActionReply_t rep;
Mpi2RaidVolIndicator_t *data;
int volume;
int handle;
int length;
uint64_t size;
uint64_t done;
int t1;
int t2;
int percent;
int last_percent = -1;
int n;
if (selectVolume2(port, &volume, &handle) != 1)
return 0;
RaidVolumePage0 = getConfigPageAlloc(port, MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 0,
MPI2_RAID_VOLUME_PGAD_FORM_HANDLE + handle,
&length);
if (RaidVolumePage0 == NULL)
{
printf("Failed to read RaidVolumePage0!\n");
return 0;
}
t1 = RaidVolumePage0->VolumeState;
t2 = get32(RaidVolumePage0->VolumeStatusFlags);
doShowVolumeState2(volume, t1, t2, TRUE);
if (t2 & (MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS |
MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT |
MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION |
MPI2_RAIDVOL0_STATUS_FLAG_CONSISTENCY_CHECK |
MPI2_RAIDVOL0_STATUS_FLAG_MAKE_DATA_CONSISTENT))
{
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI2_FUNCTION_RAID_ACTION;
req.Action = MPI2_RAID_ACTION_INDICATOR_STRUCT;
req.VolDevHandle = set16(handle);
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
return 0;
data = (pMpi2RaidVolIndicator_t)&rep.ActionData.RaidVolumeIndicator;
size = get64(data->TotalBlocks);
done = get64(data->BlocksRemaining);
if (size && done)
{
last_percent = (int)(done / (size / 100));
printf("Progress: total blocks %" INT64_FMT "d, blocks remaining %" INT64_FMT "d, %d%%\n",
size, done, last_percent);
}
}
else
return 1;
n = 0;
while (TRUE)
{
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
return 0;
data = (pMpi2RaidVolIndicator_t)&rep.ActionData.RaidVolumeIndicator;
size = get64(data->TotalBlocks);
done = get64(data->BlocksRemaining);
if (size && done)
{
percent = (int)(done / (size / 100));
if (percent != last_percent)
{
last_percent = percent;
n += printf(" %d%%", last_percent);
fflush(stdout);
if (n >= 75)
{
printf("\n");
n = 0;
}
}
}
else
break;
sleep(1);
}
if (n)
printf("\n");
if (getConfigPage(port, MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 0,
MPI2_RAID_VOLUME_PGAD_FORM_HANDLE + handle,
RaidVolumePage0, length) != 1)
{
free(RaidVolumePage0);
return 0;
}
t1 = RaidVolumePage0->VolumeState;
t2 = get32(RaidVolumePage0->VolumeStatusFlags);
doShowVolumeState2(volume, t1, t2, TRUE);
free(RaidVolumePage0);
return 1;
}
int
doModifyVolume2(MPT_PORT *port, int action, char *string)
{
Mpi2RaidActionRequest_t req;
Mpi2RaidActionReply_t rep;
int volume;
int handle;
int all;
int nv;
int rate;
int interval;
int actionWord;
all = 0;
nv = 0;
handle = 0;
/* get the current number of volumes across all configs */
getRaidCounts(port, FALSE, &nv, NULL, NULL);
if (nv == 0)
{
printf("No volumes available\n");
return 1;
}
if (action == MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES ||
action == MPI2_RAID_ACTION_ENABLE_ALL_VOLUMES)
{
all = 1;
volume = 0;
}
else
{
all = 0;
if (selectVolume2(port, &volume, &handle) != 1)
return 0;
if (action == MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE)
{
printf("Enter rate to modify (0 = Resync, 1 = Data Scrub Duration, 2 = Power Save Mode): ");
rate = getNumberAnswer(0, 2, -1);
printf("Enter new rate: ");
interval = getNumberAnswer(0, 999, -1);
if(rate == 1)
{
actionWord = ((interval << 16) | rate); // For data scrub only
}
else
{
actionWord = ((interval << 8) | rate); // For resync and powersave modes
}
} /* if MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE */
}
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI2_FUNCTION_RAID_ACTION;
req.Action = action;
req.VolDevHandle = set16(handle);
if(action == MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE)
{
req.ActionDataWord.Word = set32(actionWord);
}
if (all)
printf("Volumes are being %s\n", string);
else
printf("Volume %d is being %s\n", volume, string);
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doCreateVolume2(MPT_PORT *port, Mpi2IOCPage6_t *IOCPage6)
{
Mpi2ManufacturingPage4_t ManufacturingPage4;
Mpi2RaidPhysDiskPage0_t RaidPhysDiskPage0;
Mpi2RaidActionRequest_t req;
Mpi2RaidActionReply_t rep;
Mpi2RaidVolumeCreationStruct_t *RaidVolumeCreate;
int bus;
int target;
PATH path;
int no_mix_sas_sata;
int no_mix_ssd_non_ssd;
int no_mix_ssd_sas_sata;
int sata = 0;
int ssd = 0;
int num_physdisks;
int physdisks[MAX_DEVICES];
int chosen[MAX_DEVICES];
unsigned char inq[36];
unsigned char cap[8];
uint64_t size;
uint64_t coerced_size;
uint64_t min_size = 0;
uint64_t volume_size;
uint64_t max_volume_size;
uint64_t max_lba;
int length;
int i;
int n;
int t;
int settings = 0;
int nd;
int nv;
int cap_flags;
int man_flags;
int type;
int handle;
char name[16];
int raid0_okay;
int raid1_okay;
int raid1e_okay;
int raid10_okay;
int flags;
int min_disks;
/* get the current number of volumes and phys disks in the active config */
getRaidCounts(port, TRUE, &nv, &nd, NULL);
if (nv >= IOCPage6->MaxVolumes)
{
printf("Cannot create another active volume\n");
return 0;
}
min_disks = min(2, min(IOCPage6->MinDrivesRAID0, min(IOCPage6->MinDrivesRAID1E, IOCPage6->MinDrivesRAID10)));
if (nd + min_disks > IOCPage6->MaxPhysDisks)
{
printf("Cannot create at least %d physical disk%s\n",
min_disks, min_disks == 1 ? "" : "s");
return 0;
}
if (getConfigPage(port, MPI2_CONFIG_PAGETYPE_MANUFACTURING, 4, 0,
&ManufacturingPage4, sizeof ManufacturingPage4) != 1)
return 0;
if (nv >= ManufacturingPage4.MaxVolumes)
{
printf("Cannot create another active volume\n");
return 0;
}
if (nd + min_disks > ManufacturingPage4.MaxPhysDisks)
{
printf("Cannot create at least %d physical disk%s\n",
min_disks, min_disks == 1 ? "" : "s");
return 0;
}
printf(" B___T___L Type Vendor Product Rev Disk Blocks Disk MB\n");
n = 0;
for (bus = 0; bus < port->maxBuses; bus++)
{
for (target = port->minTargets; target < port->maxTargets; target++)
{
if (isRaidVolume(port, bus, target))
continue;
if (doInquiry(port, bus, target, 0, inq, sizeof inq) != 1)
{
#if __linux__ || DOS || EFI
if (errno == EFAULT)
return 0;
#endif
continue;
}
if ((inq[0] & 0x1f) != 0x00)
continue;
if ((inq[0] & 0xe0) == 0x20)
continue;
if ((inq[0] & 0xe0) == 0x60)
continue;
for (i = 8; i < 36; i++)
if (!isprint(inq[i]))
inq[i] = ' ';
if (doReadCapacity(port, bus, target, 0, cap, sizeof cap) != 1)
continue;
size = get4bytes(cap, 0);
if (size == 0xffffffff)
{
if (doReadCapacity16(port, bus, target, 0, cap, sizeof cap) == 1)
{
size = get8bytes(cap, 0);
}
}
if (getPath(port, bus, target, &path) == 1)
{
for (i = 0; i < n; i++)
{
if (diag_targets[i].path.slot == path.slot &&
diag_targets[i].path.encl_id_l == path.encl_id_l &&
diag_targets[i].path.encl_id_h == path.encl_id_h)
{
printf("Bus %d Target %d is another path to Bus %d Target %d, ignoring\n",
bus, target, diag_targets[i].bus, diag_targets[i].target);
break;
}
}
if (i < n)
continue;
}
if (!mapBusTargetToDevHandle(port, bus, target, &handle))
{
printf("Failed to get DevHandle for Bus %d Target %d\n", bus, target);
continue;
}
if (getConfigPage(port, MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK, 0,
MPI2_PHYSDISK_PGAD_FORM_DEVHANDLE + handle,
&RaidPhysDiskPage0, sizeof RaidPhysDiskPage0) != 1)
{
printf("Failed to get DevHandle for Bus %d Target %d\n", bus, target);
continue;
}
coerced_size = get64(RaidPhysDiskPage0.CoercedMaxLBA);
printf("%2d. %2d %3d %3d %-9s %-8.8s %-16.16s %-4.4s %10"INT64_FMT"d %7"INT64_FMT"d\n",
n+1, bus, target, 0, deviceType[inq[0] & 0x1f],
inq+8, inq+16, inq+32, size + 1, (size + 1) / 2048);
if (coerced_size > size) // unsigned arithmetic, checking for underflow (that is, disk too small)
{
printf("Bus %d Target %d is %d blocks (%d MB), too small to be a volume member\n",
bus, target, size + 1, (size + 1) / 2048);
continue;
}
diag_targets[n].bus = bus;
diag_targets[n].target = target;
diag_targets[n].size64 = coerced_size;
diag_targets[n].path = path;
n++;
if (n == MAX_DEVICES)
break;
}
if (n == MAX_DEVICES)
break;
}
if (n < min_disks)
{
printf("\nNot enough available targets found\n");
return 1;
}
cap_flags = get32(IOCPage6->CapabilitiesFlags);
printf("\nTo create a volume, select %d or more of the available targets\n", min_disks);
if (cap_flags & MPI2_IOCPAGE6_CAP_FLAGS_RAID0_SUPPORT)
printf(" select %d to %d targets for a RAID0 volume\n",
IOCPage6->MinDrivesRAID0, IOCPage6->MaxDrivesRAID0);
if (cap_flags & MPI2_IOCPAGE6_CAP_FLAGS_RAID1_SUPPORT)
printf(" select 2 targets for a RAID1 volume\n");
if (cap_flags & MPI2_IOCPAGE6_CAP_FLAGS_RAID1E_SUPPORT)
printf(" select %d to %d targets for a RAID1E volume\n",
IOCPage6->MinDrivesRAID1E, IOCPage6->MaxDrivesRAID1E);
if (cap_flags & MPI2_IOCPAGE6_CAP_FLAGS_RAID10_SUPPORT)
{
printf(" select %d to %d targets for a RAID10 volume\n",
IOCPage6->MinDrivesRAID10, IOCPage6->MaxDrivesRAID10);
printf("\nNote: for a RAID10, the number of targets must be even\n");
}
printf("\n");
num_physdisks = 0;
man_flags = get32(ManufacturingPage4.Flags);
no_mix_sas_sata = (man_flags & MPI2_MANPAGE4_IR_NO_MIX_SAS_SATA) != 0;
no_mix_ssd_non_ssd = (man_flags & MPI2_MANPAGE4_MIX_SSD_AND_NON_SSD) == 0;
no_mix_ssd_sas_sata = (man_flags & MPI2_MANPAGE4_MIX_SSD_SAS_SATA) == 0;
while (TRUE)
{
printf("Select a target: [1-%d or RETURN to quit] ", n);
i = getNumberAnswer(1, n, 0);
if (i == 0)
break;
i--;
for (t = 0; t < num_physdisks; t++)
{
if (i == chosen[t])
{
printf("\nThis target has already been chosen!\n\n");
break;
}
}
if (t < num_physdisks)
continue;
chosen[num_physdisks] = i;
bus = diag_targets[i].bus;
target = diag_targets[i].target;
if (num_physdisks == 0)
{
sata = isSata(port, bus, target);
ssd = isSsd(port, bus, target);
}
else
{
if (no_mix_sas_sata)
{
if (sata != isSata(port, bus, target))
{
printf("\nThis %s target cannot be mixed with the %s target%s already chosen!\n\n",
sata ? "SAS" : "SATA", sata ? "SATA" : "SAS",
num_physdisks == 1 ? "" : "s");
continue;
}
}
if (no_mix_ssd_non_ssd)
{
if (ssd != isSsd(port, bus, target))
{
printf("\nThis %s target cannot be mixed with the %s target%s already chosen!\n\n",
ssd ? "non-SSD" : "SSD", ssd ? "SSD" : "non-SSD",
num_physdisks == 1 ? "" : "s");
continue;
}
}
if (no_mix_ssd_sas_sata)
{
if (ssd && isSsd(port, bus, target) && sata != isSata(port, bus, target))
{
printf("\nThis %s SSD target cannot be mixed with the %s SSD target%s already chosen!\n\n",
sata ? "SAS" : "SATA", sata ? "SATA" : "SAS",
num_physdisks == 1 ? "" : "s");
continue;
}
}
}
if (!mapBusTargetToDevHandle(port, bus, target, &handle))
{
printf("\nFailed to get DevHandle for Bus %d Target %d\n", bus, target);
continue;
}
physdisks[num_physdisks] = handle;
num_physdisks++;
if (num_physdisks >= n && gFlag != TRUE)
break;
if (nd + num_physdisks >= ManufacturingPage4.MaxPhysDisks)
{
printf(" no more physical disks can be created, exiting loop\n");
break;
}
if (num_physdisks >= ManufacturingPage4.MaxPhysDisksPerVol)
{
printf(" no more physical disks allowed in a volume, exiting loop\n");
break;
}
}
printf("\n%d physical disks were selected\n\n", num_physdisks);
if (num_physdisks < min_disks)
{
printf("Volumes must have at least %d physical disks!\n", min_disks);
return 0;
}
raid0_okay = num_physdisks >= IOCPage6->MinDrivesRAID0 && cap_flags & MPI2_IOCPAGE6_CAP_FLAGS_RAID0_SUPPORT;
raid1_okay = num_physdisks == 2 && cap_flags & MPI2_IOCPAGE6_CAP_FLAGS_RAID1_SUPPORT;
raid1e_okay = num_physdisks >= IOCPage6->MinDrivesRAID1E && cap_flags & MPI2_IOCPAGE6_CAP_FLAGS_RAID1E_SUPPORT;
raid10_okay = num_physdisks >= IOCPage6->MinDrivesRAID10 && num_physdisks % 2 == 0 && cap_flags & MPI2_IOCPAGE6_CAP_FLAGS_RAID10_SUPPORT;
if (!raid0_okay && !raid1_okay && !raid1e_okay && !raid10_okay)
{
printf("No suitable RAID volume type could be found for the targets selected!\n");
return 0;
}
printf("Select volume type: [%s%s%s%sor RETURN to quit] ",
raid0_okay ? "0=RAID0, " : "",
raid1_okay ? "1=RAID1, " : "",
raid1e_okay ? "2=RAID1E, " : "",
raid10_okay ? "3=RAID10, " : "");
while (TRUE)
{
type = getNumberAnswer(0, 3, -1);
if (type < 0)
return 0;
if ((type == 0 && raid0_okay) ||
(type == 1 && raid1_okay) ||
(type == 2 && raid1e_okay) ||
(type == 3 && raid10_okay))
{
break;
}
printf("Invalid answer, try again: ");
}
switch (type)
{
case 0:
type = MPI2_RAID_VOL_TYPE_RAID0;
settings = get32(ManufacturingPage4.RAID0VolumeSettings);
break;
case 1:
type = MPI2_RAID_VOL_TYPE_RAID1;
settings = get32(ManufacturingPage4.RAID1VolumeSettings);
break;
case 2:
type = MPI2_RAID_VOL_TYPE_RAID1E;
settings = get32(ManufacturingPage4.RAID1EVolumeSettings);
break;
case 3:
type = MPI2_RAID_VOL_TYPE_RAID10;
settings = get32(ManufacturingPage4.RAID10VolumeSettings);
break;
}
length = sizeof *RaidVolumeCreate + sizeof RaidVolumeCreate->PhysDisk * (num_physdisks - 1);
RaidVolumeCreate = malloc(length);
memset(RaidVolumeCreate, 0, length);
RaidVolumeCreate->NumPhysDisks = num_physdisks;
RaidVolumeCreate->VolumeType = type;
RaidVolumeCreate->ResyncRate = ManufacturingPage4.ResyncRate;
RaidVolumeCreate->DataScrubDuration = ManufacturingPage4.DataScrubDuration;
max_volume_size = ((uint64_t)1 << (64 - 11)); // in MB
t = 0;
for (i = 0; i < num_physdisks; i++)
{
size = (diag_targets[chosen[i]].size64 + 1) / 2048;
printf("Usable size of member %d is %"INT64_FMT"d MB\n", i, size);
if (i == 0)
{
min_size = size;
}
else
{
if (size != min_size)
t = 1;
if (size < min_size)
{
printf(" reducing volume member size from %d MB to %d MB\n", min_size, size);
min_size = size;
}
}
}
if (t)
{
printf("Not all physical disks are the same size!\n");
printf("A common size of %d MB will be used for each physical disk\n", min_size);
}
volume_size = (uint64_t)min_size * num_physdisks;
if (type != MPI2_RAID_VOL_TYPE_RAID0)
volume_size /= 2;
if (volume_size > max_volume_size)
{
printf("Maximum volume size exceeded; reducing size from %" INT64_FMT "d MB to %" INT64_FMT "d MB\n",
volume_size, max_volume_size);
volume_size = max_volume_size;
}
printf("Select volume size: [1 to %" INT64_FMT "d MB, default is %" INT64_FMT "d] ",
volume_size, volume_size);
max_lba = (uint64_t)getNumberAnswer(1, (int)volume_size, (int)volume_size) * 2048 - 1;
t = (U32)max_lba;
RaidVolumeCreate->VolumeMaxLBA.Low = set32(t);
t = (U32)(max_lba >> 32);
RaidVolumeCreate->VolumeMaxLBA.High = set32(t);
// Volumes can be made up of 512b sector and 4Kb sector drives. As such,
// we can no longer simply use the IOCPage6 map. We really should get
// the drive information and calculate the size based on that. However,
// the firmware only supports one block size. We can tell the FW to use
// its only supported size by setting StripeSize to 0.
RaidVolumeCreate->StripeSize = set32(0);
#if 0
if (stripe_map)
{
if (stripe_map & (stripe_map - 1))
{
t = stripe_map / 2;
min_stripe = t & (-t);
t = ((t | (min_stripe - 1)) + 1) / 2;
max_stripe = t & (-t);
def_stripe = min(max(128, min_stripe), max_stripe);
printf("Select stripe size: [%d to %d KB, default is %d] ", min_stripe, max_stripe, def_stripe);
size = getNumberAnswer(min_stripe, max_stripe, def_stripe);
}
else
{
size = stripe_map / 2;
printf("A stripe size of %d KB will be used\n", size);
}
RaidVolumeCreate->StripeSize = set32((unsigned int)size * 2);
}
#endif
while (TRUE)
{
printf("Enter a volume name: [0 to %d characters] ", (int)sizeof name - 1);
n = getStringFromArgs(name, sizeof name, stdin);
if (n < sizeof name)
break;
printf("Invalid answer, try again: ");
}
memcpy(RaidVolumeCreate->Name, name, n);
for (i = 0; i < num_physdisks; i++)
{
RaidVolumeCreate->PhysDisk[i].PhysDiskDevHandle = set16(physdisks[i]);
RaidVolumeCreate->PhysDisk[i].PhysDiskMap = i;
}
if (type == MPI2_RAID_VOL_TYPE_RAID1)
{
RaidVolumeCreate->PhysDisk[0].PhysDiskMap = MPI2_RAIDVOL0_PHYSDISK_PRIMARY;
RaidVolumeCreate->PhysDisk[1].PhysDiskMap = MPI2_RAIDVOL0_PHYSDISK_SECONDARY;
}
RaidVolumeCreate->VolumeSettings = set32(settings);
flags = 0;
printf("Use default settings? [Yes or No, default is Yes] ");
if (getYesNoAnswer(1) == 1)
flags |= MPI2_RAID_VOL_CREATION_DEFAULT_SETTINGS;
printf("Zero the first and last blocks of the volume? [Yes or No, default is No] ");
if (getYesNoAnswer(0) == 1)
flags |= MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT;
if (type == MPI2_RAID_VOL_TYPE_RAID1)
{
printf("Copy all data from primary to secondary? [Yes or No, default is Yes] ");
if (getYesNoAnswer(1) == 1)
flags |= MPI2_RAID_VOL_CREATION_MIGRATE_DATA;
}
if (type != MPI2_RAID_VOL_TYPE_RAID0)
{
flags |= MPI2_RAID_VOL_CREATION_BACKGROUND_INIT;
}
RaidVolumeCreate->VolumeCreationFlags = set32(flags);
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI2_FUNCTION_RAID_ACTION;
req.Action = MPI2_RAID_ACTION_CREATE_VOLUME;
t = doMptCommandCheck(port, &req, sizeof req - sizeof req.ActionDataSGE, &rep, sizeof rep,
NULL, 0, RaidVolumeCreate, length, LONG_TIME);
if (t == 1)
printf("\nVolume was created\n");
free(RaidVolumeCreate);
return t;
}
int
doDeleteVolume2(MPT_PORT *port, Mpi2IOCPage6_t *IOCPage6)
{
Mpi2RaidActionRequest_t req;
Mpi2RaidActionReply_t rep;
Mpi2RaidConfigurationPage0_t *RaidConfigPage0;
int volume;
int i;
int handle;
int type;
int flags;
int configNum;
int length;
if (selectVolume2(port, &volume, &handle) != 1)
return 0;
if (getRaidConfig(port, MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT, handle, -1, &RaidConfigPage0) == 1)
{
/* save the RAID config this volume resides in so we can check for hot spares after it is deleted */
configNum = RaidConfigPage0->ConfigNum;
free(RaidConfigPage0);
}
else
{
printf("\nUnable to determine raid configuration volume resides in!\n");
return 1;
}
printf("All data on Volume %d will be lost!\n", volume);
printf("\nAre you sure you want to continue? [Yes or No, default is No] ");
if (getYesNoAnswer(0) != 1)
return 1;
flags = 0;
printf("Zero the first block of all volume members? [Yes or No, default is No] ");
if (getYesNoAnswer(0) == 1)
flags |= MPI2_RAID_ACTION_ADATA_ZERO_LBA0;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI2_FUNCTION_RAID_ACTION;
req.Action = MPI2_RAID_ACTION_DELETE_VOLUME;
req.VolDevHandle = set16(handle);
req.ActionDataWord.Word = set32(flags);
printf("\nVolume %d is being deleted\n", volume);
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
{
printf("\nVolume delete operation failed!\n");
return 0;
}
RaidConfigPage0 = getConfigPageAlloc(port, MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG, 0,
MPI2_RAID_PGAD_FORM_CONFIGNUM + configNum, &length);
if (RaidConfigPage0 == NULL)
{
return 1;
}
if (RaidConfigPage0->NumVolumes > 0)
{
free(RaidConfigPage0);
return 1;
}
for (i = 0; i < RaidConfigPage0->NumElements; i++)
{
flags = get16(RaidConfigPage0->ConfigElement[i].ElementFlags);
type = flags & MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE;
if (type == MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT)
{
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI2_FUNCTION_RAID_ACTION;
req.Action = MPI2_RAID_ACTION_DELETE_HOT_SPARE;
req.PhysDiskNum = RaidConfigPage0->ConfigElement[i].PhysDiskNum;
printf("\nHot Spare (PhysDisk %d) is being deleted\n",
RaidConfigPage0->ConfigElement[i].PhysDiskNum);
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
{
printf("\nHot Spare delete operation failed!\n");
}
}
}
free(RaidConfigPage0);
return 1;
}
int
doVolumeSettings2(MPT_PORT *port)
{
Mpi2RaidVolPage0_t *RaidVolumePage0;
Mpi2RaidActionRequest_t req;
Mpi2RaidActionReply_t rep;
int length;
int volume;
int handle;
int t1;
int t2;
int t;
if (selectVolume2(port, &volume, &handle) != 1)
return 0;
RaidVolumePage0 = getConfigPageAlloc(port, MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 0,
MPI2_RAID_VOLUME_PGAD_FORM_HANDLE + handle,
&length);
if (RaidVolumePage0 == NULL)
{
printf("Failed to read RaidVolumePage0!\n");
return 0;
}
t1 = get16(RaidVolumePage0->VolumeSettings.Settings);
t2 = RaidVolumePage0->VolumeSettings.HotSparePool;
printf(" Volume %d Settings: write caching %s, auto configure hot swap %s\n", volume,
t1 & MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING ? "enabled" :
t1 & MPI2_RAIDVOL0_SETTING_DISABLE_WRITE_CACHING ? "disabled" : "controlled by members",
t1 & MPI2_RAIDVOL0_SETTING_AUTO_CONFIG_HSWAP_DISABLE ? "disabled" : "enabled");
if (t2 != 0)
printf("Volume %d draws from Hot Spare Pools: %s%s%s%s%s%s%s%s\n", volume,
t2 & MPI2_RAID_HOT_SPARE_POOL_0 ? " 0" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_1 ? " 1" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_2 ? " 2" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_3 ? " 3" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_4 ? " 4" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_5 ? " 5" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_6 ? " 6" : "",
t2 & MPI2_RAID_HOT_SPARE_POOL_7 ? " 7" : "");
printf("\n");
t = t1 & MPI2_RAIDVOL0_SETTING_MASK_WRITE_CACHING;
switch (t)
{
case MPI2_RAIDVOL0_SETTING_DISABLE_WRITE_CACHING:
t = 0;
break;
case MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING:
t = 1;
break;
default:
case MPI2_RAIDVOL0_SETTING_UNCHANGED:
t = 2;
break;
}
printf("Write caching: [0=Disabled, 1=Enabled, 2=MemberControlled, default is %d] ", t);
t = getNumberAnswer(0, 2, t);
switch (t)
{
case 0:
t = MPI2_RAIDVOL0_SETTING_DISABLE_WRITE_CACHING;
break;
case 1:
t = MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING;
break;
case 2:
t = MPI2_RAIDVOL0_SETTING_UNCHANGED;
break;
}
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI2_FUNCTION_RAID_ACTION;
req.Action = MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE;
req.VolDevHandle = set16(handle);
req.ActionDataWord.Word = set32(t);
free(RaidVolumePage0);
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doVolumeName2(MPT_PORT *port)
{
Mpi2RaidActionRequest_t req;
Mpi2RaidActionReply_t rep;
Mpi2RaidVolPage1_t RaidVolumePage1;
int volume;
int handle;
char name[16];
int n;
if (selectVolume2(port, &volume, &handle) != 1)
return 0;
if (getConfigPage(port, MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 1,
MPI2_RAID_VOLUME_PGAD_FORM_HANDLE + handle,
&RaidVolumePage1, sizeof RaidVolumePage1) != 1)
return 0;
printf("Enter a volume name: [0 to %d characters, current is \"%s\"] ",
(int)sizeof name - 1, RaidVolumePage1.Name);
n = getStringFromArgs(name, sizeof name, stdin);
if (n == 0)
{
return 0;
}
if (n >= sizeof name)
{
printf("\nThe name is too long, current name not changed!\n");
return 0;
}
memset(name + n, '\0', sizeof name - n);
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI2_FUNCTION_RAID_ACTION;
req.Action = MPI2_RAID_ACTION_SET_VOLUME_NAME;
req.VolDevHandle = set16(handle);
printf("\nVolume %d's name is being changed...\n", volume);
return doMptCommandCheck(port, &req, sizeof req - sizeof req.ActionDataSGE, &rep, sizeof rep,
NULL, 0, name, sizeof name, SHORT_TIME);
}
int
doVolumeIRCC2(MPT_PORT *port)
{
Mpi2RaidActionRequest_t req;
Mpi2RaidActionReply_t rep;
int volume;
int handle;
if (selectVolume2(port, &volume, &handle) != 1)
return 0;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI2_FUNCTION_RAID_ACTION;
req.Action = MPI2_RAID_ACTION_START_RAID_FUNCTION;
req.VolDevHandle = set16(handle);
req.ActionDataWord.StartRaidFunction.RAIDFunction = MPI2_RAID_ACTION_START_CONSISTENCY_CHECK;
printf("\nIRCC started on volume %d...\n", volume);
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doVolumeStopIRCC2(MPT_PORT *port)
{
Mpi2RaidActionRequest_t req;
Mpi2RaidActionReply_t rep;
int volume;
int handle;
if (selectVolume2(port, &volume, &handle) != 1)
return 0;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI2_FUNCTION_RAID_ACTION;
req.Action = MPI2_RAID_ACTION_STOP_RAID_FUNCTION;
req.VolDevHandle = set16(handle);
req.ActionDataWord.StopRaidFunction.RAIDFunction = MPI2_RAID_ACTION_STOP_CONSISTENCY_CHECK;
printf("\nStopping IRCC on volume %d...\n", volume);
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doVolumeOCE(MPT_PORT *port)
{
Mpi2RaidActionRequest_t req;
Mpi2RaidActionReply_t rep;
int volume;
int handle;
if (selectVolume2(port, &volume, &handle) != 1)
return 0;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI2_FUNCTION_RAID_ACTION;
req.Action = MPI2_RAID_ACTION_START_RAID_FUNCTION;
req.VolDevHandle = set16(handle);
req.ActionDataWord.StartRaidFunction.RAIDFunction = MPI2_RAID_ACTION_START_ONLINE_CAP_EXPANSION;
printf("\nOCE is being performed on volume %d...\n", volume);
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doDriveFirmwareUpdateMode2(MPT_PORT *port, Mpi2IOCPage6_t *IOCPage6, int flag)
{
Mpi2RaidActionRequest_t req;
Mpi2RaidActionReply_t rep;
int physdisk;
int timeout;
int nd;
/* get the current number of phys disks in the active config */
getRaidCounts(port, TRUE, NULL, &nd, NULL);
if (nd == 0)
{
printf("No active physical disks\n");
return 1;
}
printf("PhysDisk: [0-%d or RETURN to quit] ", IOCPage6->MaxPhysDisks - 1);
physdisk = getNumberAnswer(0, IOCPage6->MaxPhysDisks - 1, -1);
if (physdisk < 0)
return 1;
printf("Timeout in seconds: [0-255 or RETURN to quit] ");
timeout = getNumberAnswer(0, 255, -1);
if (timeout < 0)
return 1;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI2_FUNCTION_RAID_ACTION;
req.Action = MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE;
req.PhysDiskNum = physdisk;
req.ActionDataWord.
FwUpdateMode.Flags = flag;
req.ActionDataWord.FwUpdateMode.
DeviceFirmwareUpdateModeTimeout = timeout;
printf("\nDrive Firmware Update Mode on PhysDisk %d is being %s\n", physdisk, flag ? "enabled" : "disabled");
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doModifyPhysDisk2(MPT_PORT *port, Mpi2IOCPage6_t *IOCPage6, int action, char *string)
{
MpiRaidActionRequest_t req;
MpiRaidActionReply_t rep;
int physdisk;
int nd;
/* get the current number of phys disks across all configs */
getRaidCounts(port, FALSE, NULL, &nd, NULL);
if (nd == 0)
{
printf("No active physical disks\n");
return 1;
}
printf("PhysDisk: [0-%d or RETURN to quit] ", IOCPage6->MaxPhysDisks - 1);
physdisk = getNumberAnswer(0, IOCPage6->MaxPhysDisks - 1, -1);
if (physdisk < 0)
return 1;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI2_FUNCTION_RAID_ACTION;
req.Action = action;
req.PhysDiskNum = physdisk;
printf("\nPhysDisk %d is being %s\n", physdisk, string);
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doCreateHotSpare2(MPT_PORT *port, Mpi2IOCPage6_t *IOCPage6)
{
Mpi2RaidActionRequest_t req;
Mpi2RaidActionReply_t rep;
int bus;
int target;
unsigned char inq[36];
unsigned char cap[8];
unsigned int size;
int i;
int n;
int t;
int handle;
int nd;
int ns;
/* get the current number of phys disks and hot spares in the active config */
getRaidCounts(port, TRUE, NULL, &nd, &ns);
if (nd >= IOCPage6->MaxPhysDisks)
{
printf("Cannot create another active physical disk\n");
return 0;
}
if (ns >= IOCPage6->MaxGlobalHotSpares)
{
printf("Cannot create another hot spare\n");
return 0;
}
printf(" B___T___L Type Vendor Product Rev Disk Blocks Disk MB\n");
n = 0;
for (bus = 0; bus < port->maxBuses; bus++)
{
for (target = port->minTargets; target < port->maxTargets; target++)
{
if (isRaidVolume(port, bus, target))
continue;
if (doInquiry(port, bus, target, 0, inq, sizeof inq) != 1)
{
#if __linux__ || DOS || EFI
if (errno == EFAULT)
return 0;
#endif
continue;
}
if ((inq[0] & 0x1f) != 0x00)
continue;
if ((inq[0] & 0xe0) == 0x20)
continue;
if ((inq[0] & 0xe0) == 0x60)
continue;
for (i = 8; i < 36; i++)
if (!isprint(inq[i]))
inq[i] = ' ';
if (doReadCapacity(port, bus, target, 0, cap, sizeof cap) != 1)
continue;
size = get4bytes(cap, 0);
diag_targets[n].bus = bus;
diag_targets[n].target = target;
diag_targets[n].size = size;
n++;
printf("%2d. %2d %3d %3d %-9s %-8.8s %-16.16s %-4.4s %10d %7d\n",
n, bus, target, 0, deviceType[inq[0] & 0x1f],
inq+8, inq+16, inq+32, size + 1, (size + 1) / 2048);
if (n == MAX_DEVICES)
break;
}
if (n == MAX_DEVICES)
break;
}
if (n < 1)
{
printf("\nNo available targets found\n");
return 1;
}
printf("\nTo create a hot spare, select one of the available targets\n\n");
printf("Select a target: [1-%d or RETURN to quit] ", n);
i = getNumberAnswer(1, n, 0);
if (i == 0)
return 1;
i--;
bus = diag_targets[i].bus;
target = diag_targets[i].target;
if (!mapBusTargetToDevHandle(port, bus, target, &handle))
{
printf("\nFailed to get DevHandle for Bus %d Target %d\n", bus, target);
return 0;
}
printf("Hot Spare Pool: [0-7 or RETURN to quit] ");
t = getNumberAnswer(0, 7, -1);
if (t < 0)
return 1;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI2_FUNCTION_RAID_ACTION;
req.Action = MPI2_RAID_ACTION_CREATE_HOT_SPARE;
req.ActionDataWord.HotSpare.HotSparePool = (U8)(1 << t);
req.ActionDataWord.HotSpare.DevHandle = set16(handle);
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME) != 1)
return 0;
printf("\nHot Spare was created\n");
return 1;
}
int
doDeleteHotSpare2(MPT_PORT *port, Mpi2IOCPage6_t *IOCPage6)
{
Mpi2RaidActionRequest_t req;
Mpi2RaidActionReply_t rep;
int physdisk;
int ns;
/* get the current number of hot spares across all configs */
getRaidCounts(port, FALSE, NULL, NULL, &ns);
if (ns == 0)
{
printf("No hot spares\n");
return 0;
}
printf("PhysDisk: [0-%d or RETURN to quit] ", IOCPage6->MaxPhysDisks - 1);
physdisk = getNumberAnswer(0, IOCPage6->MaxPhysDisks - 1, -1);
if (physdisk < 0)
return 1;
if (getRaidConfig(port, MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT, -1, physdisk, NULL) == 1)
{
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI2_FUNCTION_RAID_ACTION;
req.Action = MPI2_RAID_ACTION_DELETE_HOT_SPARE;
req.PhysDiskNum = physdisk;
printf("\nHot Spare (PhysDisk %d) is being deleted\n", physdisk);
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
{
printf("\nHot Spare delete operation failed!\n");
}
return 1;
}
printf("PhysDisk %d is not a valid hot spare!\n", physdisk);
return 0;
}
int
showHiddenDevices2(MPT_PORT *port)
{
Mpi2RaidPhysDiskPage0_t RaidPhysDiskPage0;
int i;
int physdisk;
int nd;
int handle;
int bus;
int target;
char buf[32];
getRaidCounts(port, FALSE, NULL, &nd, NULL);
if (nd)
{
printf("\nHidden RAID Devices:\n\n");
getDeviceInfoHeader(port, buf, sizeof buf);
printf(" B___T Device Vendor Product Rev %s\n", buf);
physdisk = 0xff;
for (i = 0; ; i++)
{
if (getConfigPage(port, MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK, 0,
MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM + physdisk,
&RaidPhysDiskPage0, sizeof RaidPhysDiskPage0) != 1)
break;
physdisk = RaidPhysDiskPage0.PhysDiskNum;
handle = get16(RaidPhysDiskPage0.DevHandle);
if (mapDevHandleToBusTarget(port, handle, &bus, &target))
{
getDeviceInfo(port, bus, target, buf, sizeof buf);
printf("%2d %3d PhysDisk %-4d %-8.8s %-16.16s %-4.4s %s\n",
bus, target, physdisk,
RaidPhysDiskPage0.InquiryData.VendorID,
RaidPhysDiskPage0.InquiryData.ProductID,
RaidPhysDiskPage0.InquiryData.ProductRevLevel, buf);
}
}
}
return 1;
}
int
getRaidCounts(MPT_PORT *port, int activeOnly, int *numVolumes, int *numPhysDisks, int *numHotSpares)
{
Mpi2RaidConfigurationPage0_t *RaidConfigPage0;
int length;
int i;
int address;
if (numVolumes)
*numVolumes = 0;
if (numPhysDisks)
*numPhysDisks = 0;
if (numHotSpares)
*numHotSpares = 0;
if (mpi2 && port->capabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)
{
i = 0xff;
while (TRUE)
{
if (activeOnly)
address = MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG;
else
address = MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM + i;
RaidConfigPage0 = getConfigPageAlloc(port, MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG, 0,
address, &length);
if (RaidConfigPage0 == NULL)
break;
i = RaidConfigPage0->ConfigNum;
if (numVolumes)
*numVolumes += RaidConfigPage0->NumVolumes;
if (numPhysDisks)
*numPhysDisks += RaidConfigPage0->NumPhysDisks;
if (numHotSpares)
*numHotSpares += RaidConfigPage0->NumHotSpares;
free(RaidConfigPage0);
if (activeOnly)
break;
}
}
return 1;
}
/*
* getRaidConfig - Look for a raid config that contains an element matching the inputs.
*
* Inputs: elementType (required) - A MPI2_RAIDCONFIG0_EFLAGS_* value used to match
* a devHandle or physDiskNum
* devHandle - If elementType is VOLUME_ELEMENT then this is matched
* against VolDevHandle. If elementType is any other value
* then elementType is matched against PhysDiskDevHandle.
* If this field is used then physDiskNum should be -1.
* physDiskNum - Valid for any elementType except VOLUME_ELEMENT, it is
* the value to match against PhysDiskNum in the ConfigElement
* list. If this field is used then devHandle should be -1.
*
* Outputs: RaidConfigPage0 (optional) - If not NULL then an allocated RaidConfigPage0 is returned
* which contains the matched input or NULL if no match found.
*
* Return: 1 if a match is found, 0 otherwise.
*
* Note: If both devHandle and physDiskNum are not -1 then devHandle will be used and physDiskNum ignored.
*/
int
getRaidConfig(MPT_PORT *port, int elementType, int devHandle, int physDiskNum, Mpi2RaidConfigurationPage0_t **RaidConfigPage0)
{
Mpi2RaidConfigurationPage0_t *rcp0;
int i;
int j;
int length;
int flags;
int currType;
int currDevHandle;
if (devHandle == -1 && physDiskNum == -1)
{
if (RaidConfigPage0)
*RaidConfigPage0 = NULL;
return 0;
}
if (mpi2 && port->capabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)
{
i = 0xff;
while (TRUE)
{
rcp0 = getConfigPageAlloc(port, MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG, 0,
MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM + i, &length);
if (rcp0 != NULL)
{
i = rcp0->ConfigNum;
for (j = 0; j < rcp0->NumElements; j++)
{
flags = get16(rcp0->ConfigElement[j].ElementFlags);
currType = flags & MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE;
if (devHandle != -1)
{
if (elementType == MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT)
currDevHandle = get16(rcp0->ConfigElement[j].VolDevHandle);
else
currDevHandle = get16(rcp0->ConfigElement[j].PhysDiskDevHandle);
if (currType == elementType && currDevHandle == devHandle)
{
if (RaidConfigPage0)
*RaidConfigPage0 = rcp0;
return 1;
}
}
else
{
if (currType != MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT &&
currType == elementType &&
physDiskNum == rcp0->ConfigElement[j].PhysDiskNum)
{
if (RaidConfigPage0)
*RaidConfigPage0 = rcp0;
return 1;
}
}
}
}
else
break;
free(rcp0);
}
}
if (RaidConfigPage0)
*RaidConfigPage0 = NULL;
return 0;
}
int
doResetBus(MPT_PORT *port)
{
#if WIN32
int status;
SRB_BUFFER srb;
int inLen;
int outLen;
DWORD retLen;
memset(&srb, 0, sizeof srb);
srb.Sic.Length = sizeof srb - sizeof srb.Sic;
srb.Sic.ControlCode = ISSUE_BUS_RESET;
srb.Sic.HeaderLength = sizeof srb.Sic;
srb.Sic.Timeout = RESET_TIME;
inLen = sizeof srb;
outLen = sizeof srb;
retLen = 0;
printf("Resetting bus...\n");
status = DeviceIoControl(port->fileHandle, port->ioctlValue,
&srb, inLen, &srb, outLen, &retLen, NULL);
return status;
#else
SCSITaskMgmt_t req;
SCSITaskMgmtReply_t rep;
int bus;
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SCSI_TASK_MGMT;
req.TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
printf("Resetting bus...\n");
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, RESET_TIME);
#endif
}
int
doResetTarget(MPT_PORT *port)
{
SCSITaskMgmt_t req;
SCSITaskMgmtReply_t rep;
int bus;
int target;
int lun;
int type;
printf(" 1. Target Reset\n");
printf(" 2. Logical Unit Reset\n");
printf(" 3. Abort Task Set\n");
printf(" 4. Clear Task Set\n");
printf(" 5. Query Task\n");
printf(" 6. Abort Task\n");
printf("\nSelect a reset type: [1-6 or RETURN to quit] ");
type = getNumberAnswer(1, 6, 0);
if (type == 0)
return 1;
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
if (type != 1)
{
printf("LUN: [0-%d or RETURN to quit] ", port->maxLuns - 1);
lun = getNumberAnswer(0, port->maxLuns - 1, -1);
if (lun < 0)
return 1;
}
else
{
lun = 0;
}
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SCSI_TASK_MGMT;
switch(type)
{
case 1: req.TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET; break;
case 2: req.TaskType = MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET; break;
case 3: req.TaskType = MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET; break;
case 4: req.TaskType = MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET; break;
case 5: req.TaskType = MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK; break;
case 6: req.TaskType = MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK; break;
}
req.LUN[1] = lun;
setName(port, bus, target, &req);
if (type == 5)
printf("\nSending Query Task...\n");
else if (type == 6)
printf("\nSending Abort Task...\n");
else
printf("\nResetting target...\n");
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, RESET_TIME);
}
int
doClearAca(MPT_PORT *port)
{
SCSITaskMgmt_t req;
SCSITaskMgmtReply_t rep;
int bus;
int target;
int lun;
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
printf("LUN: [0-%d or RETURN to quit] ", port->maxLuns - 1);
lun = getNumberAnswer(0, port->maxLuns - 1, -1);
if (lun < 0)
return 1;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SCSI_TASK_MGMT;
req.TaskType = MPI_SCSITASKMGMT_TASKTYPE_CLR_ACA;
req.LUN[1] = lun;
setName(port, bus, target, &req);
printf("\nClearing ACA...\n");
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doBeacon(MPT_PORT *port, int on_off)
{
ToolboxBeaconRequest_t req;
ToolboxReply_t rep;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_TOOLBOX;
req.Tool = MPI_TOOLBOX_BEACON_TOOL;
req.ConnectNum = 0;
req.Flags = on_off ? MPI_TOOLBOX_FLAGS_BEACON_MODE_ON : MPI_TOOLBOX_FLAGS_BEACON_MODE_OFF;
printf("Turning beacon %s...\n", on_off ? "on" : "off");
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doDisplaySfpPages(MPT_PORT *port)
{
ToolboxIstwiReadWriteRequest_t req;
ToolboxReply_t rep;
unsigned char buf[256];
int i;
int j;
char c[16];
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_TOOLBOX;
req.Tool = MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL;
req.Flags = MPI_TB_ISTWI_FLAGS_READ;
req.NumAddressBytes = 1;
req.DataLength = set16(sizeof buf);
req.DeviceAddr = 0xa0;
printf("Reading SFP Page 0 (ISTWI address A0)...\n");
if (doMptCommand(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
buf, sizeof buf, NULL, 0, SHORT_TIME) == 1)
{
printf("\n");
for (i = 0, j = 0; i < sizeof buf; i++, j++)
{
if (j == 0)
printf("%04x : ", i);
printf("%02x ", buf[i]);
if (!isprint(buf[i]))
c[j] = ' ';
else
c[j] = buf[i];
if (j == sizeof c - 1)
{
printf(" ");
for (j = 0; j < sizeof c; j++)
{
printf("%c", c[j]);
}
printf("\n");
j = -1;
}
if (i == 127)
break; // last part is unused (reserved)
}
}
printf("\n");
req.DeviceAddr = 0xa2;
printf("Reading SFP Page 1 (ISTWI address A2)...\n");
if (doMptCommand(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
buf, sizeof buf, NULL, 0, SHORT_TIME) == 1)
{
printf("\n");
for (i = 0, j = 0; i < sizeof buf; i++, j++)
{
if (j == 0)
printf("%04x : ", i);
printf("%02x ", buf[i]);
if (!isprint(buf[i]))
c[j] = ' ';
else
c[j] = buf[i];
if (j == sizeof c - 1)
{
printf(" ");
for (j = 0; j < sizeof c; j++)
{
printf("%c", c[j]);
}
printf("\n");
j = -1;
}
}
}
return 1;
}
int
doClean(MPT_PORT *port)
{
ToolboxCleanRequest_t req;
ToolboxReply_t rep;
int type;
int flags;
char name[256];
FILE *file;
int n;
int t;
while (TRUE)
{
printf(" 1. NVSRAM\n");
printf(" 2. SEEPROM\n");
printf(" 3. FLASH\n");
printf(" 4. BootLoader\n");
printf(" 5. Firmware (backup copy)\n");
printf(" 6. Firmware (current copy)\n");
printf(" 7. Persistent non-manufacturing config pages\n");
printf(" 8. Persistent manufacturing config pages\n");
printf(" 9. Boot services (BIOS/FCode)\n");
printf("\nSelect what to erase: [1-9 or RETURN to quit] ");
type = getNumberAnswer(1, 9, 0);
if (type == 0)
return 1;
switch(type)
{
case 1: flags = MPI_TOOLBOX_CLEAN_NVSRAM; break;
case 2: flags = MPI_TOOLBOX_CLEAN_SEEPROM; break;
case 3: flags = MPI_TOOLBOX_CLEAN_FLASH; break;
case 4: flags = MPI_TOOLBOX_CLEAN_BOOTLOADER; break;
case 5: flags = MPI_TOOLBOX_CLEAN_FW_BACKUP; break;
case 6: flags = MPI_TOOLBOX_CLEAN_FW_CURRENT; break;
case 7: flags = MPI_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES; break;
case 8: flags = MPI_TOOLBOX_CLEAN_PERSIST_MANUFACT_PAGES; break;
case 9: flags = MPI_TOOLBOX_CLEAN_BOOT_SERVICES; break;
default: flags = 0; break;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC &&
flags == MPI_TOOLBOX_CLEAN_SEEPROM)
{
ManufacturingPage0_t ManufacturingPage0;
ManufacturingPage3_t *ManufacturingPage3;
int length;
U32 *p;
U32 wwnn_l;
U32 wwnn_h;
U32 wwpn_l;
U32 wwpn_h;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
&ManufacturingPage0, sizeof ManufacturingPage0) == 1)
{
printf("\n");
printf("BoardName = %-16s\n", ManufacturingPage0.BoardName);
printf("BoardAssembly = %-16s\n", ManufacturingPage0.BoardAssembly);
printf("BoardTracerNumber = %-16s\n", ManufacturingPage0.BoardTracerNumber);
ManufacturingPage3 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 3, 0, &length);
if (ManufacturingPage3 != NULL)
{
p = (U32 *)ManufacturingPage3 + 2;
wwnn_l = get32x(p[2]);
wwnn_h = get32x(p[3]);
wwpn_l = get32x(p[0]);
wwpn_h = get32x(p[1]);
printf("FC WWNN = %08x%08x\n", wwnn_h, wwnn_l);
printf("FC WWPN = %08x%08x\n", wwpn_h, wwpn_l);
if (numFileNames)
{
n = getFileName(name, sizeof name, stdin, "board identity", 0);
}
else
{
printf("\nEnter board identity filename, or RETURN for none: ");
n = getString(name, sizeof name, stdin);
}
if (n > 0)
{
file = fopen(name, "w");
if (file == NULL)
{
printf("Open failure for file %s\n", name);
perror("Error is");
}
else
{
fprintf(file, "BoardName = %-16s\n", ManufacturingPage0.BoardName);
fprintf(file, "BoardAssembly = %-16s\n", ManufacturingPage0.BoardAssembly);
fprintf(file, "BoardTracerNumber = %-16s\n", ManufacturingPage0.BoardTracerNumber);
fprintf(file, "FC WWNN = %08x%08x\n", wwnn_h, wwnn_l);
fprintf(file, "FC WWPN = %08x%08x\n", wwpn_h, wwpn_l);
fclose(file);
}
}
free (ManufacturingPage3);
}
}
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS &&
flags == MPI_TOOLBOX_CLEAN_PERSIST_MANUFACT_PAGES)
{
ManufacturingPage0_t ManufacturingPage0;
ManufacturingPage5_t *ManufacturingPage5;
Mpi2ManufacturingPage5_t *ManufacturingPage5_2;
U32 wwid_l;
U32 wwid_h;
int length;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
&ManufacturingPage0, sizeof ManufacturingPage0) == 1)
{
printf("\n");
printf("BoardName = %-16s\n", ManufacturingPage0.BoardName);
printf("BoardAssembly = %-16s\n", ManufacturingPage0.BoardAssembly);
printf("BoardTracerNumber = %-16s\n", ManufacturingPage0.BoardTracerNumber);
ManufacturingPage5 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 5, 0,
&length);
if (ManufacturingPage5)
{
ManufacturingPage5_2 = (pMpi2ManufacturingPage5_t)ManufacturingPage5;
if (mpi2)
{
wwid_l = get32(ManufacturingPage5_2->Phy[0].WWID.Low);
wwid_h = get32(ManufacturingPage5_2->Phy[0].WWID.High);
}
else
{
wwid_l = get32(ManufacturingPage5->BaseWWID.Low);
wwid_h = get32(ManufacturingPage5->BaseWWID.High);
}
free (ManufacturingPage5);
printf("SAS WWID = %08x%08x\n", wwid_h, wwid_l);
if (numFileNames)
{
n = getFileName(name, sizeof name, stdin, "board identity", 0);
}
else
{
printf("\nEnter board identity filename, or RETURN for none: ");
n = getString(name, sizeof name, stdin);
}
if (n > 0)
{
file = fopen(name, "w");
if (file == NULL)
{
printf("Open failure for file %s\n", name);
perror("Error is");
}
else
{
fprintf(file, "BoardName = %-16s\n", ManufacturingPage0.BoardName);
fprintf(file, "BoardAssembly = %-16s\n", ManufacturingPage0.BoardAssembly);
fprintf(file, "BoardTracerNumber = %-16s\n", ManufacturingPage0.BoardTracerNumber);
fprintf(file, "SAS WWID = %08x%08x\n", wwid_h, wwid_l);
fclose(file);
}
}
}
}
}
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_TOOLBOX;
req.Tool = MPI_TOOLBOX_CLEAN_TOOL;
req.Flags = set32(flags);
printf("\nErasing...\n");
t = doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, LONG_TIME);
if (t != 1)
printf("\nErase failed\n");
if (wFlag)
fprintf(logFile, "%s: Erase (TOOLBOX CLEAN_TOOL) of type %d: %s\n",
logPrefix(port), type, t ? "PASS" : "FAIL");
printf("\n");
}
}
int
doFcManagementTools(MPT_PORT *port)
{
ToolboxFcManageRequest_t req;
ToolboxFcManageReply_t rep;
int type;
int bus;
int target;
int portid;
int index;
int flags;
int count;
int period;
int temp[4];
int t;
if (bringOnline(port) != 1)
return 0;
while (TRUE)
{
printf(" 1. Discover all targets\n");
printf(" 2. Discover one target by PortId\n");
printf(" 3. Discover one target by Bus/Target\n");
printf(" 4. Set maximum frame size\n");
printf(" 5. Log out target by PortId\n");
printf(" 6. Log out target by Bus/Target\n");
printf(" 7. Set login parameters\n");
printf(" 8. Get login parameters\n");
t = 8;
if (virtInit == 0)
{
printf(" 9. Create a virtual port\n");
printf("10. Delete a virtual port\n");
t = 10;
}
printf("\nSelect a tool: [1-%d or RETURN to quit] ", t);
type = getNumberAnswer(1, t, 0);
if (type == 0)
return 1;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_TOOLBOX;
req.Tool = MPI_TOOLBOX_FC_MANAGEMENT_TOOL;
req.AliasIndex = virtInit;
switch(type)
{
case 1:
printf("\nDiscovering all targets...\n");
req.Action = MPI_TB_FC_MANAGE_ACTION_DISC_ALL;
break;
case 2:
printf("PortId: [000000-FFFFFF or RETURN to quit] ");
portid = getNumberAnswerHex(0x000000, 0xffffff, -1);
if (portid < 0)
return 1;
printf("\nDiscovering PortId %06x...\n", portid);
req.Action = MPI_TB_FC_MANAGE_ACTION_DISC_PID;
req.ActionInfo.Port.PortIdentifier = set32(portid);
break;
case 3:
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
printf("\nDiscovering Bus %d Target %d...\n", bus, target);
req.Action = MPI_TB_FC_MANAGE_ACTION_DISC_BUS_TID;
req.ActionInfo.BusTid.Bus = bus;
req.ActionInfo.BusTid.TargetId = target;
break;
case 4:
printf("Maximum frame size: [128-2048 or RETURN to quit] ");
t = getNumberAnswer(128, 2048, -1);
if (t < 0)
return 1;
printf("\nSetting maximum frame size to %d...\n", t);
req.Action = MPI_TB_FC_MANAGE_ACTION_SET_MAX_FRAME_SIZE;
req.ActionInfo.FrameSize.FrameSize = set16(t);
break;
case 5:
printf("PortId: [000000-FFFFFF or RETURN to quit] ");
portid = getNumberAnswerHex(0x000000, 0xffffff, -1);
if (portid < 0)
return 1;
printf("Keep this target logged out? [Yes or No, default is No] ");
flags = getYesNoAnswer(0) == 1 ? MPI_TB_FC_MANAGE_FLAGS_KEEP_LOGGED_OUT : 0;
printf("\nLogging out PortId %06x...\n", portid);
req.Action = MPI_TB_FC_MANAGE_ACTION_LOGOUT_PID;
req.ActionInfo.Port.PortIdentifier = set32(portid);
req.Flags = flags;
break;
case 6:
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
printf("Keep this target logged out? [Yes or No, default is No] ");
flags = getYesNoAnswer(0) == 1 ? MPI_TB_FC_MANAGE_FLAGS_KEEP_LOGGED_OUT : 0;
printf("\nLogging out Bus %d Target %d...\n", bus, target);
req.Action = MPI_TB_FC_MANAGE_ACTION_LOGOUT_BUS_TID;
req.ActionInfo.BusTid.Bus = bus;
req.ActionInfo.BusTid.TargetId = target;
req.Flags = flags;
break;
case 7:
printf("Number of PLOGI attempts: [1-255 or 0 for default or RETURN to quit] ");
count = getNumberAnswer(0, 255, -1);
if (count < 0)
return 1;
printf("Seconds between PLOGI attempts: [1-255 or 0 for default or RETURN to quit] ");
period = getNumberAnswer(0, 255, -1);
if (period < 0)
return 1;
printf("Maximum FLOGI burst: [1-255 or 0 for default or RETURN to quit] ");
temp[0] = getNumberAnswer(0, 255, -1);
if (temp[0] < 0)
return 1;
printf("Percent of resources for FLOGI: [1-99 or 0 for default or RETURN to quit] ");
temp[1] = getNumberAnswer(0, 99, -1);
if (temp[1] < 0)
return 1;
printf("Maximum PLOGI burst: [1-255 or 0 for default or RETURN to quit] ");
temp[2] = getNumberAnswer(0, 255, -1);
if (temp[2] < 0)
return 1;
printf("Percent of resources for PLOGI: [1-99 or 0 for default or RETURN to quit] ");
temp[3] = getNumberAnswer(0, 99, -1);
if (temp[3] < 0)
return 1;
printf("\nSetting login parameters...\n");
req.Action = MPI_TB_FC_MANAGE_ACTION_SET_LOGIN_PARAMS;
req.ActionInfo.LoginParams.Count = count;
req.ActionInfo.LoginParams.Period = period;
req.ActionInfo.LoginParams.FlogiBurst = temp[0];
req.ActionInfo.LoginParams.FlogiExchanges = temp[1];
req.ActionInfo.LoginParams.PlogiBurst = temp[2];
req.ActionInfo.LoginParams.PlogiExchanges = temp[3];
break;
case 8:
printf("\nGetting login parameters...\n");
req.Action = MPI_TB_FC_MANAGE_ACTION_GET_LOGIN_PARAMS;
break;
case 9:
printf("\nCreating VP...\n");
req.Action = MPI_TB_FC_MANAGE_ACTION_CREATE_VP;
req.Flags = MPI_TB_FC_MANAGE_FLAGS_AUTO_RETRY;
break;
case 10:
printf("VP to delete: [1-125 or RETURN to quit] ");
index = getNumberAnswer(1, 125, -1);
if (index < 0)
return 1;
printf("\nDeleting VP %d...\n", index);
req.Action = MPI_TB_FC_MANAGE_ACTION_DELETE_VP;
req.AliasIndex = index;
break;
}
if (doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep,
NULL, 0, NULL, 0, LONG_TIME) != 1)
{
printf("FcManagment tool failed\n");
}
else if (type == 8)
{
printf("\nNumber of PLOGI attempts: %d\n",
rep.ActionInfo.LoginParams.Count);
printf("Seconds between PLOGI attempts: %d\n",
rep.ActionInfo.LoginParams.Period);
printf("Maximum FLOGI burst: %d\n",
rep.ActionInfo.LoginParams.FlogiBurst);
printf("Percent of resources for FLOGI: %d\n",
rep.ActionInfo.LoginParams.FlogiExchanges);
printf("Maximum PLOGI burst: %d\n",
rep.ActionInfo.LoginParams.PlogiBurst);
printf("Percent of resources for PLOGI: %d\n",
rep.ActionInfo.LoginParams.PlogiExchanges);
}
else if (type == 9)
{
printf("\nVP %d created, PortId = %06x, WWNN = %08x%08x, WWPN = %08x%08x\n",
rep.AliasIndex, get32(rep.ActionInfo.CreateVp.PortIdentifier),
get32(rep.ActionInfo.CreateVp.WWNN.High), get32(rep.ActionInfo.CreateVp.WWNN.Low),
get32(rep.ActionInfo.CreateVp.WWPN.High), get32(rep.ActionInfo.CreateVp.WWPN.Low));
}
printf("\n");
}
}
int
doRemoveSasDevice(MPT_PORT *port)
{
SasIoUnitControlRequest_t req;
SasIoUnitControlReply_t rep;
int handle;
printf("Enter the DevHandle to remove: [0000-FFFF or RETURN to quit] ");
handle = getNumberAnswerHex(0x0000, 0xffff, -1);
if (handle < 0)
return 0;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
req.Operation = MPI_SAS_OP_REMOVE_DEVICE;
req.DevHandle = set16(handle);
printf("\nRemoving SAS DevHandle %04x...\n", handle);
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doDisplayLogEntries(MPT_PORT *port)
{
LogPage0_t *LogPage0;
Mpi2LogPage0_t *LogPage0_2;
int length;
int i;
int j;
int k;
int n;
U32 *p;
int dataLen;
int decodeTime;
char timeString[64];
time_t timestamp;
decodeTime = FALSE;
if (mpi2 && gFlag == TRUE)
{
printf("\nDo you want to decode timestamps? [Yes or No, default is Yes] ");
if (getYesNoAnswer(1) == 1)
decodeTime = TRUE;
}
LogPage0 = getConfigPageAlloc(port, MPI_CONFIG_EXTPAGETYPE_LOG, 0, 0, &length);
if (LogPage0 == NULL)
return 0;
LogPage0_2 = (pMpi2LogPage0_t)LogPage0;
n = get16(LogPage0->NumLogEntries);
printf("%d Log entr%s found\n", n, n == 1 ? "y" : "ies");
if (n)
{
printf("\n");
if (mpi2)
{
dataLen = MPI2_LOG_0_LOG_DATA_LENGTH;
if (decodeTime)
printf("SeqN Type Time Data\n");
else
printf("SeqN Type Time Data\n");
}
else
{
dataLen = MPI_LOG_0_LOG_DATA_LENGTH;
printf("SeqN Type Time Data\n");
}
for (i = 0; i < n; i++)
{
if (mpi2)
{
p = (U32 *)LogPage0_2->LogEntry[i].LogData;
if (decodeTime)
{
timestamp = (time_t)(((uint64_t)get64(LogPage0_2->LogEntry[i].TimeStamp)) / 1000);
strcpy(timeString, ctime(&timestamp));
timeString[strlen(timeString) - 1] = '\0';
printf("%04x %04x [%s]",
get16(LogPage0_2->LogEntry[i].LogSequence),
get16(LogPage0_2->LogEntry[i].LogEntryQualifier),
timeString);
}
else
{
printf("%04x %04x %08x%08x",
get16(LogPage0_2->LogEntry[i].LogSequence),
get16(LogPage0_2->LogEntry[i].LogEntryQualifier),
get32(LogPage0_2->LogEntry[i].TimeStamp.High),
get32(LogPage0_2->LogEntry[i].TimeStamp.Low));
}
}
else
{
p = (U32 *)LogPage0->LogEntry[i].LogData;
printf("%04x %04x %08x",
get16(LogPage0->LogEntry[i].LogSequence),
get16(LogPage0->LogEntry[i].LogEntryQualifier),
get32(LogPage0->LogEntry[i].TimeStamp));
}
for (k = dataLen / 4 - 1; k > 0; k--)
if (p[k] != 0)
break;
for (j = 0; j <= k; j++)
printf(" %08x", get32x(p[j]));
printf("\n");
}
}
free(LogPage0);
return 0;
}
int
doClearLogEntries(MPT_PORT *port)
{
LogPage0_t *LogPage0;
int length;
int n;
LogPage0 = getConfigPageAlloc(port, MPI_CONFIG_EXTPAGETYPE_LOG, 0, 0, &length);
if (LogPage0 == NULL)
return 0;
n = get16(LogPage0->NumLogEntries);
printf("%d Log entr%s found, will be cleared\n", n, n == 1 ? "y" : "ies");
if (yesFlag == FALSE)
{
printf("\nAre you sure you want to continue? [Yes or No, default is Yes] ");
}
if (yesFlag == TRUE || getYesNoAnswer(1) == 1)
{
LogPage0->NumLogEntries = 0;
if (setConfigPage(port, MPI_CONFIG_EXTPAGETYPE_LOG, 0, 0, LogPage0, length) != 1)
{
printf("Failed to save changes to NVRAM!\n");
return 0;
}
}
free(LogPage0);
return 0;
}
int
doSasForceFullDiscovery(MPT_PORT *port)
{
SasIoUnitControlRequest_t req;
SasIoUnitControlReply_t rep;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
req.Operation = MPI_SAS_OP_FORCE_FULL_DISCOVERY;
printf("Forcing full discovery...\n");
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doFirmwareDownloadBoot(MPT_PORT *port)
{
#if DOS || EFI
HANDLE adap = port->fileHandle;
HANDLE partner_adap = adap->partner_adap;
char name[256];
int n;
printf("A valid firmware image can be temporarily loaded into this chip...\n\n");
n = getFileName(name, sizeof name, stdin, "firmware", 99);
if (n > 0)
{
if (adap->fw_image != NULL)
{
free(adap->fw_image);
adap->fw_image = NULL;
adap->fw_image_size = 0;
if (partner_adap != NULL)
{
partner_adap->fw_image = NULL;
partner_adap->fw_image_size = 0;
}
}
if (readFile(name, &adap->fw_image, &adap->fw_image_size) == 1)
{
adap->ioc_online = FALSE;
if (partner_adap != NULL)
{
partner_adap->ioc_online = FALSE;
partner_adap->fw_image = adap->fw_image;
}
if (mpt_fwdownloadboot(adap) == 1)
{
printf("\nThe chip was made operational, remember that this is temporary!\n");
}
else
{
printf("\nThe chip was not made operational with this firmware!\n");
mpt_stop(adap, TRUE);
return 0;
}
}
}
else
{
printf("Image won't be download booted\n");
return 1;
}
#endif
return 1;
}
int
eventQuery(MPT_PORT *port, int *entries, int *types)
{
#if WIN32
int len;
int status;
MPI_EVENTS_SRB *srb;
int inLen;
int outLen;
DWORD retLen;
if (mpi2)
len = sizeof *srb + (sizeof(U32) * 4);
else
len = sizeof *srb + sizeof(U32);
srb = malloc(len);
memset(srb, 0, len);
srb->Sic.Length = len - sizeof srb->Sic;
srb->Sic.ControlCode = DRVR_INFO_IOCTL;
srb->Sic.HeaderLength = sizeof srb->Sic;
srb->Sic.Timeout = SHORT_TIME;
memcpy((char *)&srb->Sic.Signature, "4.00 ", 8);
srb->PageCode = EVENT_QUERY;
inLen = len;
outLen = len;
retLen = 0;
status = DeviceIoControl(port->fileHandle, port->ioctlValue,
srb, inLen, srb, outLen, &retLen, NULL);
if (status != 1)
{
free(srb);
return 0;
}
*entries = srb->EventData[0];
types[0] = srb->EventData[1];
if (mpi2)
{
types[1] = srb->EventData[2];
types[2] = srb->EventData[3];
types[3] = srb->EventData[4];
}
free(srb);
#endif
#if __linux__
struct mpt2_ioctl_eventquery eventquery;
int status;
memset(&eventquery, 0, sizeof eventquery);
if (mpi2)
eventquery.hdr.max_data_size = sizeof (struct mpt2_ioctl_eventquery);
else
eventquery.hdr.max_data_size = sizeof (struct mpt_ioctl_eventquery);
eventquery.hdr.ioc_number = port->portNumber;
if (mpi2)
status = ioctl(port->fileHandle, MPT2EVENTQUERY, &eventquery);
else
status = ioctl(port->fileHandle, MPTEVENTQUERY, &eventquery);
if (status != 0)
return 0;
*entries = eventquery.event_entries;
types[0] = eventquery.event_types[0];
if (mpi2)
{
types[1] = eventquery.event_types[1];
types[2] = eventquery.event_types[2];
types[3] = eventquery.event_types[3];
}
#endif
#if __sparc__
int status;
mptsas_event_query_t eventquery;
if (mpi2)
status = ioctl(port->fileHandle, MPTIOCTL_EVENT_QUERY, &eventquery);
else
status = ioctl(port->fileHandle, SYMIOCTL_EVENT_QUERY, &eventquery);
if (status != 0)
return 0;
if (mpi2)
{
*entries = eventquery.Entries;
types[0] = eventquery.Types[0];
types[1] = eventquery.Types[1];
types[2] = eventquery.Types[2];
types[3] = eventquery.Types[3];
}
else
{
/* Entries was a U32 (now a U16) in the gen1 data structure, so cast it here to
* avoid any endian problems
*/
*entries = *(U32 *)&(eventquery.Entries);
types[0] = eventquery.Types[0];
}
#endif
return 1;
}
int
eventEnable(MPT_PORT *port, int *types)
{
#if WIN32
int len;
int status;
MPI_EVENTS_SRB *srb;
int inLen;
int outLen;
DWORD retLen;
if (mpi2)
len = sizeof *srb + (sizeof(U32) * 3);
else
len = sizeof *srb;
srb = malloc(len);
memset(srb, 0, len);
srb->Sic.Length = len - sizeof srb->Sic;
srb->Sic.ControlCode = DRVR_INFO_IOCTL;
srb->Sic.HeaderLength = sizeof srb->Sic;
srb->Sic.Timeout = SHORT_TIME;
memcpy((char *)&srb->Sic.Signature, "4.00 ", 8);
srb->PageCode = EVENT_ENABLE;
srb->EventData[0] = types[0];
if (mpi2)
{
srb->EventData[1] = types[1];
srb->EventData[2] = types[2];
srb->EventData[3] = types[3];
}
inLen = len;
outLen = len;
retLen = 0;
status = DeviceIoControl(port->fileHandle, port->ioctlValue,
srb, inLen, srb, outLen, &retLen, NULL);
free(srb);
if (status != 1)
return 0;
#endif
#if __linux__
struct mpt2_ioctl_eventenable eventenable;
int status;
memset(&eventenable, 0, sizeof eventenable);
eventenable.event_types[0] = types[0];
eventenable.hdr.ioc_number = port->portNumber;
if (mpi2)
{
eventenable.event_types[1] = types[1];
eventenable.event_types[2] = types[2];
eventenable.event_types[3] = types[3];
eventenable.hdr.max_data_size = sizeof (struct mpt2_ioctl_eventenable);
}
else
eventenable.hdr.max_data_size = sizeof (struct mpt_ioctl_eventenable);
if (mpi2)
status = ioctl(port->fileHandle, MPT2EVENTENABLE, &eventenable);
else
status = ioctl(port->fileHandle, MPTEVENTENABLE, &eventenable);
if (status != 0)
return 0;
#endif
#if __sparc__
int status;
mptsas_event_enable_t eventenable;
eventenable.Types[0] = types[0];
if (mpi2)
{
eventenable.Types[1] = types[1];
eventenable.Types[2] = types[2];
eventenable.Types[3] = types[3];
status = ioctl(port->fileHandle, MPTIOCTL_EVENT_ENABLE, &eventenable);
}
else
status = ioctl(port->fileHandle, SYMIOCTL_EVENT_ENABLE, &eventenable);
if (status != 0)
return 0;
#endif
return 1;
}
int
eventReport(MPT_PORT *port, int entries, EVENT2 *events)
{
#if WIN32
int len;
int status;
MPI_EVENTS_SRB *srb;
int inLen;
int outLen;
DWORD retLen;
len = sizeof *srb - sizeof srb->EventData + (mpi2 ? sizeof(EVENT2) : sizeof(EVENT)) * entries;
srb = malloc(len);
memset(srb, 0, len);
srb->Sic.Length = len - sizeof srb->Sic;
srb->Sic.ControlCode = DRVR_INFO_IOCTL;
srb->Sic.HeaderLength = sizeof srb->Sic;
srb->Sic.Timeout = SHORT_TIME;
memcpy((char *)&srb->Sic.Signature, "4.00 ", 8);
srb->PageCode = GET_EVENTS;
inLen = len;
outLen = len;
retLen = 0;
status = DeviceIoControl(port->fileHandle, port->ioctlValue,
srb, inLen, srb, outLen, &retLen, NULL);
if (status != 1)
{
free(srb);
return 0;
}
if (mpi2)
{
memcpy(events, srb->EventData, entries * sizeof *events);
}
else
{
EVENT *events1 = (EVENT *)srb->EventData;
int i;
memset(events, 0, entries * sizeof *events);
for (i = 0; i < entries; i++)
{
memcpy(events + i, events1 + i, sizeof(EVENT));
}
}
free(srb);
#endif
#if __linux__
struct mpt_ioctl_eventreport *eventreport;
int len;
int status;
len = sizeof *eventreport - sizeof eventreport->eventData + (mpi2 ? sizeof(EVENT2) : sizeof(EVENT)) * entries;
eventreport = (struct mpt_ioctl_eventreport *)malloc(len);
memset(eventreport, 0, len);
eventreport->hdr.maxDataSize = len;
eventreport->hdr.iocnum = port->portNumber;
if (mpi2)
status = ioctl(port->fileHandle, MPT2EVENTREPORT, eventreport);
else
status = ioctl(port->fileHandle, MPTEVENTREPORT, eventreport);
if (status != 0)
{
free(eventreport);
return 0;
}
if (mpi2)
{
memcpy(events, eventreport->eventData, entries * sizeof *events);
}
else
{
EVENT *events1 = (EVENT *)eventreport->eventData;
int i;
memset(events, 0, entries * sizeof *events);
for (i = 0; i < entries; i++)
{
memcpy(events + i, events1 + i, sizeof(EVENT));
}
}
free(eventreport);
#endif
#if __sparc__
int len;
int status;
SYM_EVENT_REPORT *eventreport;
len = sizeof *eventreport - sizeof eventreport->Events + (mpi2 ? sizeof(EVENT2) : sizeof(EVENT)) * entries;
eventreport = malloc(len);
memset(eventreport, 0, len);
eventreport->Size = len;
if (mpi2)
status = ioctl(port->fileHandle, MPTIOCTL_EVENT_REPORT, eventreport);
else
status = ioctl(port->fileHandle, SYMIOCTL_EVENT_REPORT, eventreport);
if (status != 0)
return 0;
if (mpi2)
{
memcpy(events, eventreport->Events, entries * sizeof *events);
}
else
{
EVENT *events1 = (EVENT *)eventreport->Events;
int i;
memset(events, 0, entries * sizeof *events);
for (i = 0; i < entries; i++)
{
memcpy(events + i, events1 + i, sizeof(EVENT));
}
}
free(eventreport);
#endif
return 1;
}
int
doDisplayCurrentEvents(MPT_PORT *port)
{
int entries;
int types[4] = { 0, 0, 0, 0 };
EVENT2 *events;
int i;
int j;
int k;
int l;
int n;
int t;
if (eventQuery(port, &entries, types) != 1)
{
printf("Failed to query events!\n");
return 0;
}
if ( (types[0] != 0xffffffff) ||
(mpi2 && ((types[1] != 0xffffffff) ||
(types[2] != 0xffffffff) ||
(types[3] != 0xffffffff))) )
{
memset(types, 0xffffffff, sizeof(types));
if (eventEnable(port, types) != 1)
{
printf("Failed to enable events!\n");
return 0;
}
if (eventQuery(port, &entries, types) != 1)
{
printf("Failed to query events!\n");
return 0;
}
if (entries < 1)
return 0;
port->lastEvent = -1;
}
events = malloc(entries * sizeof *events);
memset(events, 0, sizeof *events);
if (eventReport(port, entries, events) != 1)
return 0;
for (j = 0; j < entries - 1; j++)
{
if (events[j].number > events[j+1].number)
{
j++;
break;
}
}
printf("Sequence Event Event Data\n");
for (i = 0; i < entries; i++)
{
k = (i + j) % entries;
if (events[k].type)
{
t = events[k].number;
if (port->lastEvent < t)
{
for (n = 47; n >= 2; n--)
if (events[k].data[n] != 0)
break;
printf("%08x %2x ", events[k].number, events[k].type);
for (l = 0; l <= n; l++)
printf(" %08x", events[k].data[l]);
printf("\n");
port->lastEvent = t;
}
}
}
return 1;
}
int
doDisplayTransferStatistics(MPT_PORT *port)
{
ConfigReply_t rep;
FCPortPage6_t FCPortPage6;
int i;
if (getConfigPageHeader(port, MPI_CONFIG_PAGETYPE_FC_PORT, 6, 0, &rep) != 1)
return 0;
FCPortPage6.Header = rep.Header;
printf("Port Name Tx Frames Rx Frames Tx MB Rx MB Total MB\n\n");
for (i = 0; i < 10; i++)
{
setConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 6, 0, &FCPortPage6, sizeof FCPortPage6);
sleep(1);
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 6, 0, &FCPortPage6, sizeof FCPortPage6) == 1)
{
#if !EFIEBC
double time;
double tx_frames;
double rx_frames;
double tx_words;
double rx_words;
time = (int64_t)get64(FCPortPage6.TimeSinceReset) / 1000000.;
tx_frames = (int64_t)get64(FCPortPage6.TxFrames) / time;
rx_frames = (int64_t)get64(FCPortPage6.RxFrames) / time;
tx_words = (int64_t)get64(FCPortPage6.TxWords) * 4. / time / 1000000.;
rx_words = (int64_t)get64(FCPortPage6.RxWords) * 4. / time / 1000000.;
printf("%-16s %8.0f %8.0f %8.2f %8.2f %8.2f\n",
port->portName, tx_frames, rx_frames, tx_words, rx_words, tx_words + rx_words);
#endif
}
}
return 1;
}
int
doDisplayTransferStatisticsAll(int numPorts, MPT_PORT *ports[], int interval, int duration)
{
MPT_PORT *port;
ConfigReply_t rep;
FCPortPage6_t FCPortPage6;
int i;
int n;
int p;
n = 0;
for (i = 0; i < numPorts; i++)
{
port = ports[i];
if (port)
{
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
if (getConfigPageHeader(port, MPI_CONFIG_PAGETYPE_FC_PORT, 6, 0, &rep) == 1)
n++;
else
{
printf("%s can't be monitored, failed to read FCPortPage6\n", port->portName);
ports[i] = NULL;
}
}
else
{
printf("%s can't be monitored, only FC ports implement performance counters\n", port->portName);
ports[i] = NULL;
}
}
}
if (n == 0)
{
printf("There are no eligible ports to monitor!\n");
return 0;
}
FCPortPage6.Header = rep.Header;
p = 0;
while (TRUE)
{
for (i = 0; i < numPorts; i++)
{
port = ports[i];
if (port)
{
setConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 6, 0, &FCPortPage6, sizeof FCPortPage6);
}
}
sleep(interval);
if (p == 0)
printf("\nPort Name Tx Frames Rx Frames Tx MB Rx MB Total MB\n\n");
if (n == 1)
{
p++;
if (p >= 10)
p = 0;
}
for (i = 0; i < numPorts; i++)
{
port = ports[i];
if (port)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 6, 0, &FCPortPage6, sizeof FCPortPage6) == 1)
{
#if !EFIEBC
double time;
double tx_frames;
double rx_frames;
double tx_words;
double rx_words;
time = (int64_t)get64(FCPortPage6.TimeSinceReset) / 1000000.;
tx_frames = (int64_t)get64(FCPortPage6.TxFrames) / time;
rx_frames = (int64_t)get64(FCPortPage6.RxFrames) / time;
tx_words = (int64_t)get64(FCPortPage6.TxWords) * 4. / time / 1000000.;
rx_words = (int64_t)get64(FCPortPage6.RxWords) * 4. / time / 1000000.;
printf("%-16s %8.0f %8.0f %8.2f %8.2f %8.2f\n",
port->portName, tx_frames, rx_frames, tx_words, rx_words, tx_words + rx_words);
#endif
}
}
}
if (duration)
{
duration -= interval;
if (duration <= 0)
break;
}
}
return 1;
}
int
isRaidVolume(MPT_PORT *port, int bus, int target)
{
IOCPage2_t *IOCPage2;
int length;
int i;
int ioc = port->iocNumber;
if (mpi2)
return isRaidVolume2(port, bus, target);
IOCPage2 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_IOC, 2, 0, &length);
if (IOCPage2 == NULL || IOCPage2->MaxVolumes == 0 || IOCPage2->NumActiveVolumes == 0)
{
if (IOCPage2)
free(IOCPage2);
return 0;
}
for (i = 0; i < IOCPage2->NumActiveVolumes; i++)
{
if (bus == IOCPage2->RaidVolume[i].VolumeBus &&
target == IOCPage2->RaidVolume[i].VolumeID &&
ioc == IOCPage2->RaidVolume[i].VolumeIOC)
{
free(IOCPage2);
return 1;
}
}
free(IOCPage2);
return 0;
}
int
isRaidVolume2(MPT_PORT *port, int bus, int target)
{
int handle;
if (!mapBusTargetToDevHandle(port, bus, target, &handle))
return 0;
return getRaidConfig(port, MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT, handle, -1, NULL);
}
#if WIN32 || __linux__ || __sparc__
#if __linux__
void
convertBusTarget(MPT_PORT *port, int *bus, int *target, int lun)
{
char pathName[PATH_MAX];
char linkName[PATH_MAX];
char pathName2[PATH_MAX];
char linkName2[PATH_MAX];
int n;
int n2;
int i;
int j;
DIR *dirp;
struct dirent *direntp = NULL;
FCDevicePage0_t FCDevicePage0;
SasDevicePage0_t SASDevicePage0;
FILE *filep;
char deviceName[64];
char deviceName2[64];
char *p;
int t1;
int t2;
int t3;
int t4;
char matchName[64];
char *typeString;
char *nameString;
int b_t;
int dev_handle;
int address;
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_DEVICE, 0,
MPI_FC_DEVICE_PGAD_FORM_BUS_TID + (*bus << 8) + *target,
&FCDevicePage0, sizeof FCDevicePage0) != 1)
return;
i = sprintf(deviceName, "0x%08x%08x\n",
get32(FCDevicePage0.WWPN.High), get32(FCDevicePage0.WWPN.Low));
j = sprintf(matchName, "target%d:", port->hostNumber);
typeString = "fc_transport";
nameString = "port_name";
}
else if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
if (mpi1 && *bus == 0 && lun == 0 && isRaidVolume(port, *bus, *target))
{
*bus = 1;
return;
}
if (mpi2)
{
if (mapBusTargetToDevHandle(port, *bus, *target, &dev_handle) != 1)
dev_handle = 0;
address = MPI2_SAS_DEVICE_PGAD_FORM_HANDLE + dev_handle;
}
else
{
b_t = (*bus << 8) + *target;
address = (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
<<MPI_SAS_DEVICE_PGAD_FORM_SHIFT) + b_t;
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, address,
&SASDevicePage0, sizeof SASDevicePage0) != 1)
return;
i = sprintf(deviceName, "0x%08x%08x\n",
get32(SASDevicePage0.SASAddress.High),
get32(SASDevicePage0.SASAddress.Low));
j = sprintf(matchName, "end_device-%d:", port->hostNumber);
typeString = "sas_device";
nameString = "sas_address";
}
else
return;
sprintf(pathName, "/sys/class/%s/", typeString);
dirp = opendir(pathName);
while (dirp)
{
direntp = readdir(dirp);
if (!direntp)
break;
if (strncmp(direntp->d_name, matchName, j) == 0)
{
sprintf(pathName,
"/sys/class/%s/%s/%s",
typeString, direntp->d_name, nameString);
filep = fopen(pathName, "r");
if (filep)
{
p = fgets(deviceName2, sizeof deviceName2, filep);
fclose(filep);
if (p)
{
if (memcmp(deviceName, deviceName2, i) == 0)
{
closedir(dirp);
sprintf(pathName,
"/sys/class/%s/%s/device",
typeString, direntp->d_name);
n = readlink(pathName, linkName, sizeof linkName);
if (n > 0)
{
dirp = opendir("/sys/class/scsi_device/");
while (dirp)
{
direntp = readdir(dirp);
if (!direntp)
break;
sprintf(pathName2,
"/sys/class/scsi_device/%s/device",
direntp->d_name);
memset(linkName2, 0, sizeof linkName2);
n2 = readlink(pathName2, linkName2, sizeof linkName2);
if (n2 > 0)
{
if (memcmp(linkName, linkName2, n) == 0)
{
// printf("matched SCSI %s with MPT %d/%d/%d/%d\n",
// direntp->d_name, port->hostNumber, *bus, *target, lun);
sscanf(direntp->d_name, "%d:%d:%d:%d", &t1, bus, target, &t2);
closedir(dirp);
return;
}
}
}
if (dirp)
closedir(dirp);
}
dirp = opendir(pathName);
while (dirp)
{
direntp = readdir(dirp);
if (!direntp)
break;
n = sscanf(direntp->d_name, "%d:%d:%d:%d", &t1, &t2, &t3, &t4);
if (n == 4 && t1 == port->hostNumber)
{
*bus = t2;
*target = t3;
closedir(dirp);
return;
}
n = sscanf(direntp->d_name, "target%d:%d:%d", &t1, &t2, &t3);
if (n == 3 && t1 == port->hostNumber)
{
*bus = t2;
*target = t3;
closedir(dirp);
return;
}
}
if (dirp)
closedir(dirp);
return;
}
}
}
}
}
if (dirp)
closedir(dirp);
}
#endif
#if __sparc__
void
cachePathLinks(char *prefix, char *suffix, NAME_LINK **cacheOut, int *countOut)
{
char *p;
char *q;
int n;
int count;
int limit;
DIR *dirp;
struct dirent *direntp;
char pathName[PATH_MAX];
char linkName[PATH_MAX];
NAME_LINK *cache;
limit = 0;
count = 0;
cache = NULL;
dirp = opendir(prefix);
while (dirp)
{
direntp = readdir(dirp);
if (!direntp)
break;
strcpy(pathName, prefix);
strcat(pathName, direntp->d_name);
n = readlink(pathName, linkName, sizeof linkName);
if (n <= 0)
continue;
linkName[n] = '\0';
p = strstr(linkName, "/devices");
if (p)
{
p += 8;
q = strchr(p, ':');
if (q)
{
if (strcmp(q, suffix) != 0)
continue;
*q = '\0';
}
if (count == limit)
{
limit += 100;
cache = realloc(cache, limit * sizeof *cache);
}
strcpy(cache[count].name, direntp->d_name);
strcpy(cache[count].link, p);
count++;
}
}
if (dirp)
closedir(dirp);
*cacheOut = cache;
*countOut = count;
}
int
findPathLink(MPT_PORT *port, char *prefix, NAME_LINK *cache, int count, char *path, char *buf)
{
int i;
int n;
n = 0;
buf[0] = '\0';
for (i = 0; i < count; i++)
{
if (strcmp(path, cache[i].link) == 0)
{
sprintf(buf, "%s%s", prefix, cache[i].name);
n++;
}
}
return n;
}
int
getVhciName(char *phci_buf, char *addr_buf, char *vhci_buf)
{
sv_iocdata_t ioc;
bzero(&ioc, sizeof(sv_iocdata_t));
ioc.phci = phci_buf;
ioc.addr = addr_buf;
ioc.client = vhci_buf;
vhci_buf[0] = '\0';
return scsi_vhci_fd >= 0 && ioctl(scsi_vhci_fd, SCSI_VHCI_GET_CLIENT_NAME, &ioc) == 0;
}
int
getPortPhyMap(MPT_PORT *port)
{
Mpi2SasIOUnitPage0_t *SASIOUnitPage0;
int length;
int i;
int j;
SASIOUnitPage0 = getConfigPageAlloc(port, MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0, &length);
if (SASIOUnitPage0 == NULL)
return 0;
memset(port->portPhyMap, 0, sizeof port->portPhyMap);
for (i = 0; i < SASIOUnitPage0->NumPhys; i++)
{
if (SASIOUnitPage0->PhyData[i].AttachedDevHandle)
{
j = SASIOUnitPage0->PhyData[i].Port;
port->portPhyMap[j] |= (1 << i);
}
}
return 0;
}
#endif
int
getOsDeviceName(MPT_PORT *port, int bus, int target, int lun, char *buf, int len, int type)
{
#if WIN32
char name[512];
char *p;
int t;
char device[32];
HANDLE handle;
DWORD retLen;
SCSI_ADDRESS scsiAddress;
if (osDeviceState == NULL)
{
t = 4096;
do
{
t *= 2;
if (osDeviceState)
osDeviceState = realloc(osDeviceState, t);
else
osDeviceState = malloc(t);
QueryDosDevice(NULL, osDeviceState, t);
} while (GetLastError() == ERROR_INSUFFICIENT_BUFFER);
}
for (p = osDeviceState; *p; p += (int)strlen(p) + 1)
{
if (strlen(p) == 2 && p[1] == ':' && p[0] >= 'C' && p[0] <= 'Z')
{
QueryDosDevice (p, name, sizeof name);
if (strncmp(name,"\\Device\\CdRom",13))
{
continue;
}
}
if (strncmp(p, "PhysicalDrive", 13) && strncmp(p, "TAPE", 4) &&
strncmp(p, "Scanner", 7) && strncmp(p, "Changer", 7) )
{
continue;
}
sprintf(device, "\\\\.\\%s", p);
handle = CreateFile(device, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (handle == INVALID_HANDLE_VALUE && GetLastError() == ERROR_SHARING_VIOLATION)
{
handle = CreateFile(device, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
}
if (handle == INVALID_HANDLE_VALUE)
{
continue;
}
t = DeviceIoControl(handle, IOCTL_SCSI_GET_ADDRESS, NULL, 0,
&scsiAddress, sizeof scsiAddress, &retLen, NULL);
CloseHandle(handle);
if (t)
{
if (port->portNumber == scsiAddress.PortNumber &&
bus == scsiAddress.PathId &&
target == scsiAddress.TargetId &&
lun == scsiAddress.Lun)
{
QueryDosDevice (p, name, sizeof name);
name[len - 21] = '\0';
sprintf(buf, "%-18s %s", p, name);
return 1;
}
}
}
#endif
#if __linux__
char pathName[PATH_MAX];
char linkName[PATH_MAX];
int n;
char *c = NULL;
int i;
int fd;
int id[2];
int match;
int fail;
DIR *dirp;
struct dirent *direntp = NULL;
convertBusTarget(port, &bus, &target, lun);
sprintf(pathName,
"/sys/class/scsi_device/%d:%d:%d:%d/device/",
port->hostNumber, bus, target, lun);
dirp = opendir(pathName);
while (dirp)
{
direntp = readdir(dirp);
if (!direntp)
break;
if (strncmp(direntp->d_name, "block", 5) == 0)
break;
if (strncmp(direntp->d_name, "tape", 4) == 0)
break;
}
if (direntp)
{
strcat(pathName, direntp->d_name);
n = readlink(pathName, linkName, sizeof linkName);
if (n > 0)
{
linkName[n] = '\0';
c = strrchr(linkName, '/');
}
if (c)
{
sprintf(buf, "/dev%-8s[%d:%d:%d:%d]",
c, port->hostNumber, bus, target, lun);
return 1;
}
}
if (dirp)
closedir(dirp);
match = (port->hostNumber << 24) | (bus << 16) | (lun << 8) | target;
fail = 0;
for (i = 0; i < 256; i++)
{
if (i < 26)
{
sprintf(pathName, "/dev/sd%c", 'a' + i);
}
else
{
sprintf(pathName, "/dev/sd%c%c", 'a' + ((i-26) / 26), 'a' + (i % 26));
}
fd = open(pathName, O_RDONLY | O_NONBLOCK);
if (fd < 0)
{
if (fail++ > 32)
break;
else
continue;
}
fail = 0;
n = ioctl(fd, SCSI_IOCTL_GET_IDLUN, id);
close(fd);
if (n == 0)
{
if (match == id[0])
{
sprintf(buf, "%-12s[%d:%d:%d:%d]",
pathName, port->hostNumber, bus, target, lun);
return 1;
}
}
}
fail = 0;
for (i = 0; i < 32; i++)
{
sprintf(pathName, "/dev/sr%d", i);
fd = open(pathName, O_RDONLY | O_NONBLOCK);
if (fd < 0)
{
if (fail++ > 4)
break;
else
continue;
}
fail = 0;
n = ioctl(fd, SCSI_IOCTL_GET_IDLUN, id);
close(fd);
if (n == 0)
{
if (match == id[0])
{
sprintf(buf, "%-12s[%d:%d:%d:%d]",
pathName, port->hostNumber, bus, target, lun);
return 1;
}
}
}
fail = 0;
for (i = 0; i < 32; i++)
{
sprintf(pathName, "/dev/st%d", i);
fd = open(pathName, O_RDONLY | O_NONBLOCK);
if (fd < 0)
{
if (fail++ > 4)
break;
else
continue;
}
fail = 0;
n = ioctl(fd, SCSI_IOCTL_GET_IDLUN, id);
close(fd);
if (n == 0)
{
if (match == id[0])
{
sprintf(buf, "%-12s[%d:%d:%d:%d]",
pathName, port->hostNumber, bus, target, lun);
return 1;
}
}
}
#endif
#if __sparc__
FCDevicePage0_t FCDevicePage0;
int fd;
int n;
char path[PATH_MAX];
char phci_buf[MAXNAMELEN];
char addr_buf[MAXNAMELEN];
char vhci_buf[MAXNAMELEN];
U32 wwpn_l;
U32 wwpn_h;
char *name;
int b_t;
int dev_handle;
Mpi2RaidVolPage1_t RaidVolumePage1;
Mpi2SasDevicePage0_t SASDevicePage0;
unsigned char vpd[255];
U32 wwid_l;
U32 wwid_h;
U32 map;
if (device_caches_initialized == 0)
{
device_caches_initialized = 1;
scsi_vhci_fd = open("/devices/scsi_vhci:devctl", O_RDWR);
cachePathLinks("/dev/rdsk/", ":c,raw", &dev_rdsk_cache, &dev_rdsk_count);
cachePathLinks("/dev/rmt/", ":", &dev_rmt_cache, &dev_rmt_count);
cachePathLinks("/dev/es/", ":0", &dev_es_cache, &dev_es_count);
}
if (strstr(port->portName, "fc") &&
getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_DEVICE, 0,
MPI_FC_DEVICE_PGAD_FORM_BUS_TID + mapOsToHwTarget(port, target),
&FCDevicePage0, sizeof FCDevicePage0) == 1)
{
wwpn_l = get32(FCDevicePage0.WWPN.Low);
wwpn_h = get32(FCDevicePage0.WWPN.High);
sprintf(addr_buf, "w%08x%08x,%x", wwpn_h, wwpn_l, lun);
if (type == 0 || type == 5 || type == 7 || type == 13)
{
if (getVhciName(port->pathName, addr_buf, vhci_buf) == 1)
{
sprintf(path, "%s", vhci_buf);
}
else
{
if (type == 13)
{
name = "ses";
}
else
{
#if i386
name = "disk";
#else
name = "ssd";
#endif
}
sprintf(path, "%s/%s@%s", port->pathName, name, addr_buf);
}
if (type == 13)
n = findPathLink(port, "/dev/es/", dev_es_cache, dev_es_count, path, buf);
else
n = findPathLink(port, "/dev/rdsk/", dev_rdsk_cache, dev_rdsk_count, path, buf);
if (n == 0)
{
if (strlen(vhci_buf))
sprintf(buf, "/devices%s", vhci_buf);
return 0;
}
}
else if (type == 1)
{
sprintf(path, "%s/st@%s", port->pathName, addr_buf);
n = findPathLink(port, "/dev/rmt/", dev_rmt_cache, dev_rmt_count, path, buf);
return n > 0;
}
else
{
buf[0] = '\0';
return 0;
}
}
else if (mpi2 && port->ioctlValue == MPTIOCTL_PASS_THRU)
{
if (mapBusTargetToDevHandle(port, bus, target, &dev_handle) != 1)
{
buf[0] = '\0';
return 0;
}
if (getConfigPage(port, MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 1,
MPI2_RAID_VOLUME_PGAD_FORM_HANDLE + dev_handle,
&RaidVolumePage1, sizeof RaidVolumePage1) == 1)
{
wwid_l = get32(RaidVolumePage1.WWID.Low);
wwid_h = get32(RaidVolumePage1.WWID.High);
wwid_h &= 0x0fffffff;
wwid_h |= 0x30000000;
sprintf(phci_buf, "%s/iport@v0", port->pathName);
sprintf(addr_buf, "w%08x%08x,%x", wwid_h, wwid_l, lun);
}
else if (getConfigPage(port, MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0,
MPI2_SAS_DEVICE_PGAD_FORM_HANDLE + dev_handle,
&SASDevicePage0, sizeof SASDevicePage0) == 1)
{
if (get32(SASDevicePage0.DeviceInfo) & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
{
if (doInquiryVpdPage(port, bus, target, 0, 0x83, vpd, sizeof vpd) == 1 &&
vpd[3] >= 12 && vpd[4] == 1 && vpd[5] == 3 && vpd[7] == 8)
{
wwid_h = get4bytes(vpd, 8);
wwid_l = get4bytes(vpd, 12);
}
else if (get16(SASDevicePage0.ParentDevHandle) >= port->numPhys)
{
wwid_l = get32(SASDevicePage0.SASAddress.Low);
wwid_h = get32(SASDevicePage0.SASAddress.High);
}
else
{
wwid_l = 0;
wwid_h = 0;
}
}
else
{
wwid_l = get32(SASDevicePage0.SASAddress.Low);
wwid_h = get32(SASDevicePage0.SASAddress.High);
}
map = port->portPhyMap[SASDevicePage0.PhysicalPort];
sprintf(phci_buf, "%s/iport@%x", port->pathName, map);
if (wwid_l || wwid_h)
sprintf(addr_buf, "w%08x%08x,%x", wwid_h, wwid_l, lun);
else
sprintf(addr_buf, "p%x,%x", SASDevicePage0.PhyNum, lun);
}
else
{
buf[0] = '\0';
return 0;
}
if (getVhciName(phci_buf, addr_buf, vhci_buf) == 1)
{
sprintf(path, "%s", vhci_buf);
}
else
{
if (type == 13)
name = "enclosure";
else
name = "disk";
sprintf(path, "%s/%s@%s", phci_buf, name, addr_buf);
}
if (type == 13)
n = findPathLink(port, "/dev/es/", dev_es_cache, dev_es_count, path, buf);
else
n = findPathLink(port, "/dev/rdsk/", dev_rdsk_cache, dev_rdsk_count, path, buf);
if (n == 0)
{
if (strlen(vhci_buf))
sprintf(buf, "/devices%s", vhci_buf);
return 0;
}
}
else
{
b_t = (bus << 8) + target;
if (type == 0 || type == 5 || type == 7 || type == 13)
{
sprintf(addr_buf, "%x,%x", b_t, lun);
if (getVhciName(port->pathName, addr_buf, vhci_buf) == 1)
{
sprintf(path, "%s", vhci_buf);
}
else
{
if (type == 13)
{
name = "ses";
}
else
{
#if i386
name = "sd";
#else
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
name = "ssd";
else
name = "sd";
#endif
}
sprintf(path, "%s/%s@%s", port->pathName, name, addr_buf);
}
if (type == 13)
n = findPathLink(port, "/dev/es/", dev_es_cache, dev_es_count, path, buf);
else
n = findPathLink(port, "/dev/rdsk/", dev_rdsk_cache, dev_rdsk_count, path, buf);
if (n == 0)
return 0;
}
else if (type == 1)
{
sprintf(path, "%s/st@%x,%x", port->pathName, b_t, lun);
n = findPathLink(port, "/dev/rmt/", dev_rmt_cache, dev_rmt_count, path, buf);
return n > 0;
}
else
{
buf[0] = '\0';
return 0;
}
}
fd = open(buf, O_RDONLY | O_NDELAY);
if (fd >= 0)
{
close(fd);
return 1;
}
else
{
strcat(buf, " (?)");
return 1;
}
#endif
buf[0] = '\0';
return 0;
}
int
doDisplayOsDeviceNames(MPT_PORT *port)
{
int bus;
int target;
int lun;
int type;
unsigned char inq[36];
char buf[80];
int version;
int max_lun;
#if WIN32
if (strlen(port->driverName))
printf("%s is %s\n\n", port->portName, port->driverName);
#endif
#if __linux__
if (port->hostNumber >= 0)
printf("%s is SCSI host %d\n\n", port->portName, port->hostNumber);
#endif
#if __sparc__
if (mpi2)
getPortPhyMap(port);
if (port->hostNumber >= 0)
printf("%s is /dev/cfg/c%d\n\n", port->portName, port->hostNumber);
#endif
printf(" B___T___L Type Operating System Device Name\n");
for (bus = 0; bus < port->maxBuses; bus++)
{
for (target = port->minTargets; target < port->maxTargets; target++)
{
max_lun = 1;
for (lun = 0; lun < max_lun; lun++)
{
if (doInquiry(port, bus, target, lun, inq, sizeof inq) != 1)
{
#if __linux__ || DOS || EFI
if (errno == EFAULT)
return 0;
#endif
if (lun == 0)
break;
else
continue;
}
if (lun == 0)
{
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SCSI)
{
version = inq[2] & 0x07;
if (version > 1)
max_lun = 8;
if (version > 3)
max_lun = 64;
}
else
{
max_lun = port->maxLuns;
}
}
else
{
if ((inq[0] & 0x1f) == 0x1f)
continue;
if ((inq[0] & 0xe0) == 0x20)
continue;
if ((inq[0] & 0xe0) == 0x60)
continue;
if ((inq[0] & 0x1f) == 0x0d)
continue;
}
type = inq[0] & 0x1f;
getOsDeviceName(port, bus, target, lun, buf, sizeof buf, type);
printf("%2d %3d %3d %-9s %s\n",
bus, target, lun, deviceType[type], buf);
}
}
}
return 1;
}
#endif
#if WIN32 || LINUX_DIAG || __sparc__
int
diagBufferAction(MPT_PORT *port, int action, void *buf, int size)
{
#if WIN32
int status;
SRB_DIAG_BUFFER srb;
int inLen;
int outLen;
DWORD retLen;
memset(&srb, 0, sizeof srb);
srb.Sic.Length = sizeof srb - sizeof srb.Buf + size - sizeof srb.Sic;
srb.Sic.ControlCode = MPI_FW_DIAG_IOCTL;
srb.Sic.HeaderLength = sizeof srb.Sic;
srb.Sic.Timeout = LONG_TIME;
srb.Sic.ReturnCode = MPI_FW_DIAG_NEW;
memcpy((char *)&srb.Sic.Signature, "FwDiag ", 8);
srb.DiagType = action;
memcpy(srb.Buf, buf, size);
inLen = sizeof srb - sizeof srb.Buf + size;
outLen = sizeof srb - sizeof srb.Buf + size;
retLen = 0;
status = DeviceIoControl(port->fileHandle, port->ioctlValue,
&srb, inLen, &srb, outLen, &retLen, NULL);
if (mpi1 && srb.Sic.ReturnCode == 2) // old drivers can return this bogus value
diagReturnCode = 0;
else
diagReturnCode = srb.Sic.ReturnCode;
if (status != 1 || diagReturnCode != 0)
return 0;
memcpy(buf, srb.Buf, size);
return 1;
#endif
#if __linux__
IOCTL_DIAG_BUFFER diagbuffer;
int status;
int ioctl_code;
if (mpi2)
return diagBufferAction2(port, action, buf, size);
switch (action)
{
case MPI_FW_DIAG_TYPE_REGISTER: ioctl_code = MPTDIAGREGISTER; break;
case MPI_FW_DIAG_TYPE_UNREGISTER: ioctl_code = MPTDIAGUNREGISTER; break;
case MPI_FW_DIAG_TYPE_QUERY: ioctl_code = MPTDIAGQUERY; break;
case MPI_FW_DIAG_TYPE_READ_BUFFER: ioctl_code = MPTDIAGREADBUFFER; break;
case MPI_FW_DIAG_TYPE_RELEASE: ioctl_code = MPTDIAGRELEASE; break;
default: return 0;
}
memset(&diagbuffer, 0, sizeof diagbuffer);
diagbuffer.hdr.max_data_size = sizeof diagbuffer - sizeof diagbuffer.buf + size;
diagbuffer.hdr.ioc_number = port->portNumber;
memcpy(diagbuffer.buf, buf, size);
// mptctl bug, remember size for later workaround
if (action == MPI_FW_DIAG_TYPE_REGISTER)
{
MPI_FW_DIAG_REGISTER *diagRegister = (MPI_FW_DIAG_REGISTER *)diagbuffer.buf;
port->diagBufferSizes[diagRegister->BufferType] = diagRegister->RequestedBufferSize;
}
if (action == MPI_FW_DIAG_TYPE_UNREGISTER)
{
MPI_FW_DIAG_UNREGISTER *diagUnregister = (MPI_FW_DIAG_UNREGISTER *)diagbuffer.buf;
port->diagBufferSizes[diagUnregister->UniqueId & 0xff] = 0;
}
// mptctl bug, poison field for later workaround
if (action == MPI_FW_DIAG_TYPE_QUERY)
{
MPI_FW_DIAG_QUERY *diagQuery = (MPI_FW_DIAG_QUERY *)diagbuffer.buf;
diagQuery->DriverAddedBufferSize = 0x07071959;
errno = 0;
}
status = ioctl(port->fileHandle, ioctl_code, &diagbuffer);
// mptctl bug, MPTDIAGQUERY returns EFAULT even in success!
if (status != 0 && errno == EFAULT && action == MPI_FW_DIAG_TYPE_QUERY)
{
MPI_FW_DIAG_QUERY *diagQuery = (MPI_FW_DIAG_QUERY *)diagbuffer.buf;
if (diagQuery->DriverAddedBufferSize != 0x07071959)
{
status = 0;
errno = 0;
}
}
if (status != 0)
{
return 0;
}
// mptctl bug, MPTDIAGQUERY returns 0 for TotalBufferSize!
if (action == MPI_FW_DIAG_TYPE_QUERY)
{
MPI_FW_DIAG_QUERY *diagQuery = (MPI_FW_DIAG_QUERY *)diagbuffer.buf;
if (diagQuery->TotalBufferSize == 0)
{
diagQuery->TotalBufferSize = port->diagBufferSizes[diagQuery->BufferType];
}
}
memcpy(buf, diagbuffer.buf, size);
return 1;
#endif
#if __sparc__
SYM_DIAG_ACTION diagAction;
int status;
diagAction.Action = action;
diagAction.Length = size;
diagAction.PtrDiagAction = (UINT64)(UINT32)buf;
diagAction.ReturnCode = MPI_FW_DIAG_NEW;
if (mpi2)
status = ioctl(port->fileHandle, MPTIOCTL_DIAG_ACTION, &diagAction);
else
status = ioctl(port->fileHandle, SYMIOCTL_DIAG_ACTION, &diagAction);
diagReturnCode = diagAction.ReturnCode;
return status == 0 && diagReturnCode == 0;
#endif
}
int
diagBufferAction2(MPT_PORT *port, int action, void *buf, int size)
{
#if __linux__
IOCTL_DIAG_BUFFER diagbuffer;
int status;
int ioctl_code;
switch (action)
{
case MPI_FW_DIAG_TYPE_REGISTER: ioctl_code = MPT2DIAGREGISTER; break;
case MPI_FW_DIAG_TYPE_UNREGISTER: ioctl_code = MPT2DIAGUNREGISTER; break;
case MPI_FW_DIAG_TYPE_QUERY: ioctl_code = MPT2DIAGQUERY; break;
case MPI_FW_DIAG_TYPE_READ_BUFFER: ioctl_code = MPT2DIAGREADBUFFER; break;
case MPI_FW_DIAG_TYPE_RELEASE: ioctl_code = MPT2DIAGRELEASE; break;
default: return 0;
}
memset(&diagbuffer, 0, sizeof diagbuffer);
diagbuffer.hdr.max_data_size = sizeof diagbuffer - sizeof diagbuffer.buf + size;
diagbuffer.hdr.ioc_number = port->portNumber;
memcpy(diagbuffer.buf, buf, size);
status = ioctl(port->fileHandle, ioctl_code, &diagbuffer);
if (status != 0)
{
return 0;
}
memcpy(buf, diagbuffer.buf, size);
#endif
return 1;
}
int
diagBufferRegister(MPT_PORT *port, int type, int id, int size)
{
MPI_FW_DIAG_REGISTER diagRegister;
if (mpi2)
return diagBufferRegister2(port, type, id, size);
memset(&diagRegister, 0, sizeof diagRegister);
diagRegister.BufferType = type;
diagRegister.UniqueId = id;
diagRegister.RequestedBufferSize = size;
printf("\nUse default settings? [Yes or No, default is Yes] ");
if (getYesNoAnswer(1) != 1)
{
printf("Buffer posting options (ProductSpecific[0]): [00000000-FFFFFFFF, default is 00000000] ");
if (getHexNumberAnswer(&diagRegister.ProductSpecific[0]) == 0)
diagRegister.ProductSpecific[0] = 0x00000000;
printf("IOP Debug Mask (ProductSpecific[1]): [00000000-FFFFFFFF, default is FFFFEFFF] ");
if (getHexNumberAnswer(&diagRegister.ProductSpecific[1]) == 0)
diagRegister.ProductSpecific[1] = 0xFFFFEFFF;
printf("PL debug mask (ProductSpecific[2]): [00000000-FFFFFFFF, default is FFF3FFFF] ");
if (getHexNumberAnswer(&diagRegister.ProductSpecific[2]) == 0)
diagRegister.ProductSpecific[2] = 0xFFF3FFFF;
printf("IR debug mask (ProductSpecific[3]): [00000000-FFFFFFFF, default is FFFFFFFF] ");
if (getHexNumberAnswer(&diagRegister.ProductSpecific[3]) == 0)
diagRegister.ProductSpecific[3] = 0xFFFFFFFF;
}
return diagBufferAction(port, MPI_FW_DIAG_TYPE_REGISTER, &diagRegister, sizeof diagRegister);
}
/* diag buffer register routine for gen2 */
int
diagBufferRegister2(MPT_PORT *port, int type, int id, int size)
{
MPI2_FW_DIAG_REGISTER diagRegister;
memset(&diagRegister, 0, sizeof diagRegister);
diagRegister.BufferType = type;
diagRegister.UniqueId = id;
diagRegister.RequestedBufferSize = size;
printf("\nUse default settings? [Yes or No, default is Yes] ");
if (getYesNoAnswer(1) != 1)
{
printf("Buffer Posting Options (ProductSpecific[0]): [00000000-FFFFFFFF, default is 00000000] ");
if (getHexNumberAnswer(&diagRegister.ProductSpecific[0]) == 0)
diagRegister.ProductSpecific[0] = 0x00000000;
printf("IOP Debug Mask (ProductSpecific[2:1]): [16 hex digits (no dashes), default is FFFFCFFF-FFFFFFFF] ");
if (getHexDoubleNumberAnswer(&diagRegister.ProductSpecific[2], &diagRegister.ProductSpecific[1]) == 0)
{
diagRegister.ProductSpecific[1] = 0xFFFFFFFF;
diagRegister.ProductSpecific[2] = 0xFFFFCFFF;
}
printf("PL Debug Mask (ProductSpecific[4:3]): [16 hex digits (no dashes), default is FFFFEFFF-EFFFFFFF] ");
if (getHexDoubleNumberAnswer(&diagRegister.ProductSpecific[4], &diagRegister.ProductSpecific[3]) == 0)
{
diagRegister.ProductSpecific[3] = 0xEFFFFFFF;
diagRegister.ProductSpecific[4] = 0xFFFFEFFF;
}
printf("IR Debug Mask (ProductSpecific[6:5]): [16 hex digits (no dashes), default is FFFFEFFF-FFFFFFFF] ");
if (getHexDoubleNumberAnswer(&diagRegister.ProductSpecific[6], &diagRegister.ProductSpecific[5]) == 0)
{
diagRegister.ProductSpecific[5] = 0xFFFFFFFF;
diagRegister.ProductSpecific[6] = 0xFFFFEFFF;
}
}
return diagBufferAction(port, MPI_FW_DIAG_TYPE_REGISTER, &diagRegister, sizeof diagRegister);
}
int
diagBufferUnregister(MPT_PORT *port, int id)
{
MPI_FW_DIAG_UNREGISTER diagUnregister;
memset(&diagUnregister, 0, sizeof diagUnregister);
diagUnregister.UniqueId = id;
return diagBufferAction(port, MPI_FW_DIAG_TYPE_UNREGISTER, &diagUnregister, sizeof diagUnregister);
}
/* diag buffer query routine for gen1 */
int
diagBufferQuery(MPT_PORT *port, int type, int id, int *flags, int *size)
{
MPI_FW_DIAG_QUERY diagQuery;
if (mpi2)
return diagBufferQuery2(port, type, id, flags, size);
memset(&diagQuery, 0, sizeof diagQuery);
diagQuery.BufferType = type;
diagQuery.UniqueId = id;
if (diagBufferAction(port, MPI_FW_DIAG_TYPE_QUERY, &diagQuery, sizeof diagQuery) != 1)
return 0;
*flags = diagQuery.Flags;
*size = diagQuery.TotalBufferSize;
return 1;
}
/* diag buffer query routine for gen2 */
int
diagBufferQuery2(MPT_PORT *port, int type, int id, int *flags, int *size)
{
MPI2_FW_DIAG_QUERY diagQuery;
memset(&diagQuery, 0, sizeof diagQuery);
diagQuery.BufferType = type;
diagQuery.UniqueId = id;
if (diagBufferAction(port, MPI_FW_DIAG_TYPE_QUERY, &diagQuery, sizeof diagQuery) != 1)
return 0;
*flags = diagQuery.AppFlags;
*size = diagQuery.TotalBufferSize;
return 1;
}
int
diagBufferReadBuffer(MPT_PORT *port, int id, char *name, int file, int *sizeIn, int header)
{
MPI_FW_DIAG_READ_BUFFER *diagReadBuffer;
DIAG_BUFFER_START *diagBufferStart;
DIAG_HEADER_FIRM_IDENTIFICATION diagHeaderFirm;
DIAG_HEADER_HOST_IDENTIFICATION diagHeaderHost;
int size = *sizeIn;
int offset = 0;
int length;
int t;
int actual;
t = sizeof *diagReadBuffer - sizeof diagReadBuffer->DataBuffer + 32768;
diagReadBuffer = malloc(t);
memset(diagReadBuffer, 0, t);
diagReadBuffer->UniqueId = id;
while (size)
{
length = min(size, 32768);
diagReadBuffer->StartingOffset = offset;
diagReadBuffer->BytesToRead = length;
t = sizeof *diagReadBuffer - sizeof diagReadBuffer->DataBuffer + length;
if (diagBufferAction(port, MPI_FW_DIAG_TYPE_READ_BUFFER, diagReadBuffer, t) != 1)
{
free(diagReadBuffer);
return 0;
}
if (offset == 0)
{
diagBufferStart = (DIAG_BUFFER_START *)diagReadBuffer->DataBuffer;
if ((get32(diagBufferStart->DiagVersion) == 0x00000000 ||
get32(diagBufferStart->DiagVersion) == 0x01000000) &&
get32(diagBufferStart->Reserved3) == 0x4742444c)
{
if (diagBufferStart->BufferType == 0)
printf("Current trace pointer = %x\n", get32x(((U32 *)(diagBufferStart + 1))[3]));
actual = get32(diagBufferStart->Size);
if (size > actual)
{
size = actual;
*sizeIn = actual;
}
if (length > actual)
length = actual;
if (header)
{
memset(&diagHeaderFirm, 0, sizeof diagHeaderFirm);
diagHeaderFirm.Size = set32(sizeof diagHeaderFirm);
diagHeaderFirm.Type = set16(1);
diagHeaderFirm.Version = 1;
// diagHeaderFirm.CapabilitiesFlags = set32(port->capabilities);
diagHeaderFirm.FWVersion = set32(port->fwVersion);
diagHeaderFirm.ProductId = set16(port->productId);
memset(&diagHeaderHost, 0, sizeof diagHeaderHost);
diagHeaderHost.Size = set32(sizeof diagHeaderHost);
diagHeaderHost.Type = set16(2);
diagHeaderHost.Version = 1;
t = write(file, diagBufferStart, sizeof *diagBufferStart);
t += write(file, &diagHeaderFirm, sizeof diagHeaderFirm);
t += write(file, &diagHeaderHost, sizeof diagHeaderHost);
t += write(file, diagBufferStart + 1, length - sizeof *diagBufferStart);
if (t != length + (int)sizeof diagHeaderFirm + (int)sizeof diagHeaderHost)
{
printf("Write failed for file %s, t = %x\n", name, t);
perror("Error is");
free(diagReadBuffer);
return 0;
}
*sizeIn += sizeof diagHeaderFirm + sizeof diagHeaderHost;
size -= length;
offset += length;
continue;
}
}
}
t = write(file, diagReadBuffer->DataBuffer, length);
if (t != length)
{
printf("Write failed for file %s, t = %x\n", name, t);
perror("Error is");
free(diagReadBuffer);
return 0;
}
size -= length;
offset += length;
}
free(diagReadBuffer);
return 1;
}
int
diagBufferRelease(MPT_PORT *port, int type, int id)
{
MPI_FW_DIAG_RELEASE diagRelease;
memset(&diagRelease, 0, sizeof diagRelease);
diagRelease.UniqueId = id;
return diagBufferAction(port, MPI_FW_DIAG_TYPE_RELEASE, &diagRelease, sizeof diagRelease);
}
int
doDiagBuffer(MPT_PORT *port)
{
int type;
int id;
int action;
int flags;
int size;
char name[256];
int file;
int n;
int header = 0;
char *string;
printf("Buffer type: [0=Trace, 1=Snapshot, or RETURN to quit] ");
type = getNumberAnswer(0, 1, -1);
if (type < 0)
return 1;
switch (type)
{
case 0: type = MPI_DIAG_BUF_TYPE_TRACE; string = "trace"; break;
case 1: type = MPI_DIAG_BUF_TYPE_SNAPSHOT; string = "snapsot"; break;
default: return 0;
}
id = 0x07075900 + type;
printf("\nNOTE: the expected sequence is Register, Release, Read Buffer, Unregister\n");
while (TRUE)
{
printf("\n");
printf(" 1. Register\n");
printf(" 2. Query\n");
printf(" 3. Read Buffer\n");
printf(" 4. Release\n");
printf(" 5. Unregister\n");
printf("\nSelect an action: [1-5 or RETURN to quit] ");
action = getNumberAnswer(1, 5, 0);
if (action == 0)
return 1;
switch (action)
{
case 1:
if (type == MPI_DIAG_BUF_TYPE_TRACE)
size = 128;
else
size = 5*1024;
printf("\nRequested size in KB: [8 to 8192, default is %d] ", size);
size = getNumberAnswer(8, 8192, size) * 1024;
if (type == MPI_DIAG_BUF_TYPE_TRACE)
size += 64;
printf("\nRegistering...\n");
if (diagBufferRegister(port, type, id, size) != 1)
{
printf("Register failed!\n");
switch (diagReturnCode)
{
case MPI_FW_DIAG_ERROR_INVALID_UID:
printf("\nA %s buffer is already registered\n", string);
break;
case MPI_FW_DIAG_ERROR_NO_BUFFER:
#if WIN32
printf("\nDriver support for a %s buffer is not enabled\n", string);
#else
printf("\nA %s buffer could not be allocated due to insufficient memory\n", string);
#endif
break;
case MPI_FW_DIAG_ERROR_POST_FAILED:
printf("\nThe %s buffer could not be posted\n", string);
break;
}
break;
}
if (diagBufferQuery(port, type, id, &flags, &size) != 1)
{
printf("Query failed\n");
break;
}
printf("\nActual size is %d KB (0x%x bytes)\n", size / 1024, size);
break;
case 2:
printf("\nQuerying...\n");
if (diagBufferQuery(port, type, id, &flags, &size) != 1)
{
if (diagReturnCode == MPI_FW_DIAG_ERROR_INVALID_UID)
printf("\nNo %s buffer is currently registered\n", string);
else
printf("Query failed\n");
break;
}
printf("\nA %d KB %s buffer is currently registered\n", size / 1024, string);
if (flags & MPI_FW_DIAG_FLAG_APP_OWNED)
printf(" buffer was registered by an application\n");
if (flags & MPI_FW_DIAG_FLAG_BUFFER_VALID)
printf(" buffer contains valid data\n");
if (flags & MPI_FW_DIAG_FLAG_FW_BUFFER_ACCESS)
printf(" buffer is being accessed by firmware\n");
break;
case 3:
if (diagBufferQuery(port, type, id, &flags, &size) != 1)
{
if (diagReturnCode == MPI_FW_DIAG_ERROR_INVALID_UID)
printf("\nNo %s buffer is currently registered\n", string);
else
printf("Query failed\n");
break;
}
if (!(flags & MPI_FW_DIAG_FLAG_BUFFER_VALID))
{
printf("The %s buffer does not contain valid data\n", string);
break;
}
n = getFileName(name, sizeof name, stdin, "trace", 0);
if (n > 0)
{
file = open(name, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, 0644);
if (file < 0)
{
printf("Open failure for file %s\n", name);
perror("Error is");
break;
}
}
else
{
printf("Read Buffer will not be done\n");
break;
}
if (gFlag == TRUE)
{
printf("Add tool header? [Yes or No, default is No] ");
header = getYesNoAnswer(0);
}
printf("\nReading Buffer...\n");
if (diagBufferReadBuffer(port, id, name, file, &size, header) != 1)
printf("Read Buffer failed\n");
else
printf("\nWrote %d bytes to file %s\n", size, name);
close(file);
break;
case 4:
printf("\nReleasing...\n");
if (diagBufferRelease(port, type, id) != 1)
{
printf("Release failed!\n");
switch (diagReturnCode)
{
case MPI_FW_DIAG_ERROR_INVALID_UID:
printf("\nNo %s buffer is currently registered\n", string);
break;
case MPI_FW_DIAG_ERROR_ALREADY_RELEASED:
printf("\nThe %s buffer is already released\n", string);
break;
case MPI_FW_DIAG_ERROR_RELEASE_FAILED:
printf("\nThe %s buffer could not be released\n", string);
break;
}
}
break;
case 5:
printf("\nUnregistering...\n");
if (diagBufferUnregister(port, id) != 1)
{
printf("Unregister failed\n");
switch (diagReturnCode)
{
case MPI_FW_DIAG_ERROR_INVALID_UID:
printf("\nNo %s buffer is currently registered\n", string);
break;
case MPI_FW_DIAG_ERROR_RELEASE_FAILED:
printf("\nThe %s buffer could not be released\n", string);
break;
}
}
break;
}
}
return 1;
}
#endif
int
doFlashUpload(MPT_PORT *port)
{
char name[256];
int file;
unsigned char *imageBuf = NULL;
int imageLen;
int actualImageLen;
int offset;
int type;
int n;
int t;
printf(" 1. Firmware\n");
printf(" 2. BIOS/FCode\n");
printf(" 3. BootLoader\n");
printf(" 4. Firmware (backup copy)\n");
printf(" 5. Complete (all sections)\n");
t = 5;
if (port->deviceId == MPI_MANUFACTPAGE_DEVID_SAS1078)
{
printf(" 6. MegaRAID\n");
t = 6;
}
printf("\nSelect what to upload: [1-%d or RETURN to quit] ", t);
type = getNumberAnswer(1, t, 0);
if (type == 0)
return 1;
switch(type)
{
case 1: type = MPI_FW_UPLOAD_ITYPE_FW_FLASH; break;
case 2: type = MPI_FW_UPLOAD_ITYPE_BIOS_FLASH; break;
case 3: type = MPI_FW_UPLOAD_ITYPE_BOOTLOADER; break;
case 4: type = MPI_FW_UPLOAD_ITYPE_FW_BACKUP; break;
case 5: type = MPI_FW_UPLOAD_ITYPE_COMPLETE; break;
case 6: type = MPI_FW_UPLOAD_ITYPE_MEGARAID; break;
default: type = 0; break;
}
printf("\n");
n = getFileName(name, sizeof name, stdin, "FLASH section", 0);
if (n > 0)
{
file = open(name, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, 0644);
if (file < 0)
{
printf("Open failure for file %s\n", name);
perror("Error is");
return 0;
}
}
else
{
printf("Image won't be uploaded\n");
return 1;
}
imageLen = 0x10000;
imageBuf = (unsigned char *)malloc(imageLen);
printf("\nUploading image...\n");
offset = 0;
while (TRUE)
{
if (doFwUpload(port, type, imageBuf, imageLen, offset, &actualImageLen) != 1)
break;
if (offset + imageLen > actualImageLen)
imageLen = actualImageLen - offset;
t = write(file, imageBuf, imageLen);
if (t != imageLen)
{
printf("Write failed for file %s, t = %x\n", name, t);
perror("Error is");
break;
}
offset += imageLen;
if (offset >= actualImageLen)
break;
}
printf("\nWrote %d bytes to file %s\n", offset, name);
close(file);
free(imageBuf);
return 1;
}
int
doDisplayVersionInfo(MPT_PORT *port)
{
Mpi2IOUnitPage0_t IOUnitPage0;
SasIOUnitPage0_t SASIOUnitPage0;
ManufacturingPage0_t ManufacturingPage0;
#if WIN32
int status;
DRVR_INFO_SRB srb;
int inLen;
int outLen;
DWORD retLen;
#endif
#if __linux__
int status;
struct mpt_ioctl_iocinfo iocinfo;
char *c;
#endif
#if __sparc__
SYMHI_DMI_DATA dmiData;
mptsas_adapter_data_t adapterData;
#endif
int i;
#if WIN32
memset(&srb, 0, sizeof srb);
srb.Sic.Length = sizeof srb - sizeof srb.Sic;
srb.Sic.ControlCode = DRVR_INFO_IOCTL;
srb.Sic.HeaderLength = sizeof srb.Sic;
srb.Sic.Timeout = SHORT_TIME;
memcpy((char *)&srb.Sic.Signature, "4.00 ", 8);
srb.PageCode = ADAPTER_INFO_PAGE;
inLen = sizeof srb;
outLen = sizeof srb;
retLen = 0;
status = DeviceIoControl(port->fileHandle, port->ioctlValue,
&srb, inLen, &srb, outLen, &retLen, NULL);
if (status == 1)
{
if (strlen(port->driverName))
printf("%s is %s, Version %s\n\n", port->portName,
port->driverName, srb.AdapterPageOut.DriverVersion);
}
#endif
#if __linux__
memset(&iocinfo, 0, sizeof iocinfo);
iocinfo.hdr.maxDataSize = sizeof iocinfo;
iocinfo.hdr.iocnum = port->portNumber;
if (mpi2)
status = ioctl(port->fileHandle, MPT2IOCINFO, &iocinfo);
else
status = ioctl(port->fileHandle, MPTIOCINFO, &iocinfo);
if (status == 0)
{
c = iocinfo.driverVersion;
if (c[0] == '@' && c[1] == '(' && c[2] == '#' && c[3] == ')')
c += 4;
if (port->hostNumber >= 0)
printf("%s is SCSI host %d, Driver is %s\n\n",
port->portName, port->hostNumber, c);
else
printf("%s, Driver is %s\n\n",
port->portName, c);
}
#endif
#if __sparc__
if (mpi2)
{
memset(&adapterData, 0, sizeof adapterData);
adapterData.StructureLength = sizeof adapterData;
if (ioctl(port->fileHandle, MPTIOCTL_GET_ADAPTER_DATA, &adapterData) == 0 &&
strlen(adapterData.DriverVersion) != 0)
{
if (port->hostNumber >= 0)
printf("%s is /dev/cfg/c%d, Driver is %s\n\n",
port->portName, port->hostNumber, adapterData.DriverVersion);
else
printf("%s, Driver is %s\n\n",
port->portName, adapterData.DriverVersion);
}
else
{
if (port->hostNumber >= 0)
printf("%s is /dev/cfg/c%d\n\n",
port->portName, port->hostNumber);
}
}
else
{
memset(&dmiData, 0, sizeof dmiData);
dmiData.StructureLength = sizeof dmiData;
if (ioctl(port->fileHandle, SYMIOCTL_GET_DMI_DATA, &dmiData) == 0 &&
strlen(dmiData.DriverVersion) != 0)
{
if (port->hostNumber >= 0)
printf("%s is /dev/cfg/c%d, Driver is %s\n\n",
port->portName, port->hostNumber, dmiData.DriverVersion);
else
printf("%s, Driver is %s\n\n",
port->portName, dmiData.DriverVersion);
}
else
{
if (port->hostNumber >= 0)
printf("%s is /dev/cfg/c%d\n\n",
port->portName, port->hostNumber);
}
}
#endif
i = port->fwVersion;
if (port->mptVersion < MPI_VERSION_01_02)
{
printf("Firmware version is %08x (%d.%02d.%02d)\n",
i, (i >> 12) & 0xf, (i >> 8) & 0xf, i & 0xff);
}
else
{
if (i & 0xff)
{
printf("Firmware version is %08x (%d.%02d.%02d.%02d)\n",
i, (i >> 24) & 0xff, (i >> 16) & 0xff, (i >> 8) & 0xff, i & 0xff);
}
else
{
printf("Firmware version is %08x (%d.%02d.%02d)\n",
i, (i >> 24) & 0xff, (i >> 16) & 0xff, (i >> 8) & 0xff);
}
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
if (mpi2)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IO_UNIT, 0, 0,
&IOUnitPage0, sizeof IOUnitPage0) == 1)
{
if (IOUnitPage0.NvdataVersionDefault.Word == IOUnitPage0.NvdataVersionPersistent.Word)
printf("NVDATA version is %08x\n",
get32(IOUnitPage0.NvdataVersionDefault.Word));
else
printf("NVDATA version is %08x (default), %08x (persistent)\n",
get32(IOUnitPage0.NvdataVersionDefault.Word),
get32(IOUnitPage0.NvdataVersionPersistent.Word));
}
}
else
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0,
&SASIOUnitPage0, sizeof SASIOUnitPage0) == 1)
{
if (SASIOUnitPage0.NvdataVersionDefault == SASIOUnitPage0.NvdataVersionPersistent)
printf("NVDATA version is %04x\n",
get16(SASIOUnitPage0.NvdataVersionDefault));
else
printf("NVDATA version is %04x (default), %04x (persistent)\n",
get16(SASIOUnitPage0.NvdataVersionDefault),
get16(SASIOUnitPage0.NvdataVersionPersistent));
}
}
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
&ManufacturingPage0, sizeof ManufacturingPage0) == 1)
{
for (i = 0; i < sizeof ManufacturingPage0.BoardName; i++)
if (!isprint(ManufacturingPage0.BoardName[i]))
break;
if (i >= 4)
printf("Board name is %-16s\n", ManufacturingPage0.BoardName);
}
if (port->pciType)
printf("Chip is %s, %s\n", port->chipNameRev, port->pciType);
else
printf("Chip is %s\n", port->chipNameRev);
if (getBoardInfo(port) == 1)
{
printf("PCI location is Segment %d, Bus %d, Device %d, Function %d (combined: %02x%02x%02x)\n",
port->pciSegment, port->pciBus, port->pciDevice, port->pciFunction,
port->pciSegment, port->pciBus, (port->pciDevice << 3) | port->pciFunction);
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
printf("Initiator Mode is %s, Target Mode is %s\n",
port->protocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR ? "enabled" : "disabled",
port->protocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET ? "enabled" : "disabled");
}
return 1;
}
void
showVpdData(MPT_PORT *port, ManufacturingPage1_t *ManufacturingPage1)
{
int i;
int j;
char c[16];
printf("\nRaw VPD Data:\n");
for (i = 0, j = 0; i < sizeof ManufacturingPage1->VPD; i++, j++)
{
if (j == 0)
printf("%04x : ", i);
printf("%02x ", ManufacturingPage1->VPD[i]);
if (!isprint(ManufacturingPage1->VPD[i]))
c[j] = ' ';
else
c[j] = ManufacturingPage1->VPD[i];
if (j == sizeof c - 1)
{
printf(" ");
for (j = 0; j < sizeof c; j++)
{
printf("%c", c[j]);
}
printf("\n");
j = -1;
}
}
}
int
doDisplayVpdInfo(MPT_PORT *port)
{
ManufacturingPage1_t ManufacturingPage1;
U8 *p;
U8 *q;
U8 tag;
int item;
int length;
int i;
int j;
int l;
int n;
char c;
int error;
int got_end;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 1, 0,
&ManufacturingPage1, sizeof ManufacturingPage1) == 1)
{
if (ManufacturingPage1.VPD[0] == 0x82)
{
printf("VPD Data is valid\n\n");
error = 0;
got_end = 0;
p = ManufacturingPage1.VPD;
for (i = 0; i < sizeof ManufacturingPage1.VPD; i += length, p += length)
{
tag = p[0];
if (tag == 0)
break;
if (tag & 0x80)
{
item = tag & 0x7f;
length = (p[2] << 8) + p[1];
switch (item)
{
case 2:
l = 3 + length;
c = p[l];
p[l] = '\0';
printf("%02x %02x %s\n", tag, length, p + 3);
p[l] = c;
break;
case 16:
case 17:
printf("%02x %02x\n", tag, length);
q = p + 3;
for (j = 0; j < length; j += n + 3, q += n + 3)
{
n = q[2];
if (q[0] == 'R' && q[1] == 'W')
{
printf(" %02x RW\n", n);
continue;
}
if (q[0] == 'R' && q[1] == 'V')
{
printf(" %02x RV %02x\n", n, q[3]);
continue;
}
l = 3 + n;
c = q[l];
q[l] = '\0';
printf(" %02x %c%c %s\n", n, q[0], q[1], q + 3);
q[l] = c;
}
if (j != length)
{
printf(" Incorrect large resource length, should be %02x!\n", j);
error = 1;
}
break;
default:
printf("%02x %02x Unknown large resource type!\n", tag, length);
error = 1;
break;
}
length += 3;
}
else
{
item = (tag & 0x78) >> 3;
length = tag & 0x07;
switch (item)
{
case 15:
printf("%02x %02x\n", tag, length);
if (i + 1 != sizeof ManufacturingPage1.VPD)
{
printf(" Incorrect end tag placement, is at offset %02x, should be at offset %02x\n",
i, (int)sizeof ManufacturingPage1.VPD - 1);
error = 1;
}
if (length != 0)
{
printf(" Incorrect end tag length, should be 00\n");
error = 1;
}
got_end = 1;
break;
default:
printf("%02x %02x Unknown small resource type!\n", tag, length);
error = 1;
break;
}
length += 1;
}
}
if (!got_end)
{
printf("Missing end tag, expected at offset %02x!\n", i);
error = 1;
}
if (error)
{
showVpdData(port, &ManufacturingPage1);
}
}
else
{
printf("VPD Data is not valid\n");
}
}
return 1;
}
int
doProgramVpdInfo(MPT_PORT *port)
{
ManufacturingPage1_t ManufacturingPage1;
char name[256];
unsigned char *vpdinfoBuf = NULL;
int vpdinfoLen;
int n;
int i;
int t;
char *buf;
int after_equals;
int in_quotes;
char serial[64];
char *c;
int tag;
int length;
char key1;
char key2;
int lr_n;
int lr_length;
n = getFileName(name, sizeof name, stdin, "VPD information", 0);
if (n > 0)
{
if (readFile(name, &vpdinfoBuf, &vpdinfoLen) != 1)
return 0;
}
else
{
printf("VPD information won't be programmed\n");
return 0;
}
printf("%d bytes read from %s\n\n", vpdinfoLen, name);
n = vpdinfoLen;
buf = realloc(vpdinfoBuf, n + 2);
if (n && buf[n-1] != '\n')
{
vpdinfoLen++;
buf[n++] = '\n';
}
buf[n] = '\0';
n = 0;
after_equals = 0;
in_quotes = 0;
for (i = 0; i < vpdinfoLen; i++)
{
if (buf[i] == '\0' || buf[i] == '\r') // NUL and CR are ignored
continue;
if (buf[i] == ';') // lines starting with ; are ignored
{
while (buf[i] != '\n' && i < vpdinfoLen)
i++;
}
if (n)
{
if (buf[i] == '\n' && buf[n-1] == '\n') // blank lines are ignored
continue;
}
else
{
if (buf[i] == '\n') // blank lines are ignored
continue;
}
if (buf[i] == '=')
after_equals = 1;
if (buf[i] == '\n')
after_equals = 0;
if (buf[i] == '"')
in_quotes ^= 1;
if (!in_quotes && buf[i] == ' ')
continue;
buf[n++] = after_equals ? buf[i] : toupper(buf[i]);
}
buf[n] = '\0';
memset(&ManufacturingPage1, 0, sizeof ManufacturingPage1);
ManufacturingPage1.Header.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING |
MPI_CONFIG_PAGEATTR_PERSISTENT;
ManufacturingPage1.Header.PageNumber = 1;
ManufacturingPage1.Header.PageLength = sizeof(ManufacturingPage1_t) / 4;
ManufacturingPage1.Header.PageVersion = MPI_MANUFACTURING1_PAGEVERSION;
c = buf;
n = 0;
lr_n = 0;
lr_length = 0;
if (sscanf(c, "LR_ID_STRING_TAG=0x%x\n%n", &tag, &t) != 1)
{
printf("LR_ID_STRING_TAG not found or invalid!\n");
goto error;
}
ManufacturingPage1.VPD[n++] = tag;
c += t;
if (sscanf(c, "LR_ID_STRING_LENGTH=0x%x\n%n", &length, &t) != 1)
{
printf("LR_ID_STRING_LENGTH not found or invalid!\n");
goto error;
}
ManufacturingPage1.VPD[n++] = length;
ManufacturingPage1.VPD[n++] = length >> 8;
c += t;
if (strncmp(c, "LR_ID_STRING=", 13) != 0 || c[13] != '"' || c[14+length] != '"' || c[15+length] != '\n')
{
printf("LR_ID_STRING not found or invalid!\n");
goto error;
}
memcpy(ManufacturingPage1.VPD + n, c + 14, length);
n += length;
c += 16 + length;
while (c[0] != '\0')
{
if (c[0] == 'S')
break;
else if (c[0] == 'L')
{
if (lr_n && lr_n + lr_length != n)
{
printf("VPD large resource tag %02x length is incorrect, is %02x, should be %02x\n",
ManufacturingPage1.VPD[lr_n-3], lr_length, n - lr_n);
}
if (sscanf(c, "LR_VPD_TAG=0x%x\n%n", &tag, &t) != 1)
{
printf("LR_VPD_TAG not found or invalid!\n");
goto error;
}
ManufacturingPage1.VPD[n++] = tag;
c += t;
if (sscanf(c, "LR_VPD_LENGTH=0x%x\n%n", &length, &t) != 1)
{
printf("LR_VPD_LENGTH not found or invalid!\n");
goto error;
}
ManufacturingPage1.VPD[n++] = length;
ManufacturingPage1.VPD[n++] = length >> 8;
c += t;
lr_n = n;
lr_length = length;
}
else if (c[0] == 'V')
{
if (sscanf(c, "VPD_KEYWORD=\"%c%c\"\n%n", &key1, &key2, &t) != 2)
{
printf("VPD_KEYWORD not found or invalid!\n");
goto error;
}
key1 = toupper(key1);
key2 = toupper(key2);
ManufacturingPage1.VPD[n++] = key1;
ManufacturingPage1.VPD[n++] = key2;
c += t;
if (sscanf(c, "VPD_LENGTH=0x%x\n%n", &length, &t) != 1)
{
printf("VPD_LENGTH not found or invalid!\n");
goto error;
}
ManufacturingPage1.VPD[n++] = length;
c += t;
if (strncmp(c, "VPD_DATA=", 9) != 0)
{
printf("VPD_DATA not found or invalid!\n");
goto error;
}
c += 9;
if (key1 == 'R' && key2 == 'V')
{
if (strncasecmp(c, "\"CHECKSUM\"\n", 11) != 0)
{
printf("VPD_DATA not found or invalid!\n");
c -= 11;
goto error;
}
memset(ManufacturingPage1.VPD + n, 0, length);
for (i = 0, t = 0; i < n; i++)
t += ManufacturingPage1.VPD[i];
ManufacturingPage1.VPD[n] = -t;
n += length;
c += 11;
}
else if (key1 == 'R' && key2 == 'W')
{
if (strncasecmp(c, "\"RESERVED\"\n", 11) != 0)
{
printf("VPD_DATA not found or invalid!\n");
c -= 11;
goto error;
}
memset(ManufacturingPage1.VPD + n, 0, length);
n += length;
c += 11;
}
else if (key1 == 'S' && key2 == 'N')
{
printf("Enter serial number: [%d characters or RETURN to quit] ", length);
while (TRUE)
{
t = getStringFromArgs(serial, sizeof serial, stdin);
if (t == 0)
{
free(buf);
return 0;
}
if (t == length)
{
printf("\n");
break;
}
printf("Invalid response, try again: ");
}
memcpy(ManufacturingPage1.VPD + n, serial, length);
n += length;
while (*c != '\0')
if (*c++ == '\n')
break;
}
else
{
if (c[0] != '"' || c[1+length] != '"' || c[2+length] != '\n')
{
printf("VPD_DATA not found or invalid!\n");
c -= 11;
goto error;
}
memcpy(ManufacturingPage1.VPD + n, c + 1, length);
n += length;
c += 3 + length;
}
}
else
break;
}
if (lr_n && lr_n + lr_length != n)
{
printf("VPD large resource tag %02x length is incorrect, is %02x, should be %02x\n",
ManufacturingPage1.VPD[lr_n-3], lr_length, n - lr_n);
}
if (sscanf(c, "SR_END_TAG=0x%x\n%n", &tag, &t) != 1)
{
printf("SR_END_TAG not found or invalid!\n");
goto error;
}
ManufacturingPage1.VPD[n++] = tag;
c += t;
if (tag != 0x78)
{
printf("VPD end tag value is incorrect, is %02x, should be 78\n", tag);
}
if (n != sizeof ManufacturingPage1.VPD)
{
printf("VPD end tag is misplaced, is at offset %02x, should be at offset %02x\n",
n - 1, (int)sizeof ManufacturingPage1.VPD - 1);
}
error:
if (c[0] != '\0')
{
printf("\nExtra lines found in VPD information file!\n");
printf("----\n%s----\n", c);
}
free(buf);
printf("Writing VPD Data to ManufacturingPage1...\n");
// showVpdData(port, &ManufacturingPage1);
doIocInit(port, MPI_WHOINIT_MANUFACTURER);
t = setConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 1, 0,
&ManufacturingPage1, sizeof ManufacturingPage1);
doIocInit(port, port->whoInit);
if (t != 1)
{
printf("Failed to save changes to NVRAM!\n");
return 0;
}
return 1;
}
#if (WIN32 || __linux__ || __sparc__ || DOS || EFI) && REGISTER_ACCESS
int
doEnableDiagAccess(MPT_PORT *port, U32 *diagOrig)
{
U32 diag;
U32 data;
readl(DIAGNOSTIC, diag);
if ((diag & MPI_DIAG_DRWE) == 0)
{
writel(WRITE_SEQUENCE, 0);
writel(WRITE_SEQUENCE, MPI_WRSEQ_KEY_VALUE_MASK);
writel(WRITE_SEQUENCE, MPI_WRSEQ_1ST_KEY_VALUE);
writel(WRITE_SEQUENCE, MPI_WRSEQ_2ND_KEY_VALUE);
writel(WRITE_SEQUENCE, MPI_WRSEQ_3RD_KEY_VALUE);
writel(WRITE_SEQUENCE, MPI_WRSEQ_4TH_KEY_VALUE);
writel(WRITE_SEQUENCE, MPI_WRSEQ_5TH_KEY_VALUE);
}
readl(DIAGNOSTIC, data);
if (port->notOperational)
{
writel(DIAGNOSTIC, data | MPI_DIAG_RW_ENABLE | MPI_DIAG_MEM_ENABLE | MPI_DIAG_DISABLE_ARM);
}
else
{
writel(DIAGNOSTIC, data | MPI_DIAG_RW_ENABLE | MPI_DIAG_MEM_ENABLE);
}
*diagOrig = diag;
return 1;
}
int
doReadChipMemoryRegions(MPT_PORT *port, U32 addr, U32 *buf, int num)
{
U32 flush;
U32 diag;
U32 data;
#ifdef REG_DIAG_READ
U32 base;
#endif
int i;
if (doEnableDiagAccess(port, &diag) != 1)
return 0;
#ifdef REG_DIAG_READ
if (port->deviceId == MPI_MANUFACTPAGE_DEVICEID_FC919 ||
port->deviceId == MPI_MANUFACTPAGE_DEVICEID_FC929)
{
for (i = 0; i < num; i++)
{
writel(TEST_BASE_ADDRESS, addr);
readl(TEST_BASE_ADDRESS, base);
doReadWriteRegister(port, addr - base, &data, REG_DIAG_READ);
buf[i] = data;
}
}
else
#endif
{
writel(DIAG_RW_ADDRESS, addr);
readl(DIAG_RW_ADDRESS, flush);
for (i = 0; i < num; i++)
{
readl(DIAG_RW_DATA, data);
buf[i] = data;
}
writel(DIAG_RW_ADDRESS, 0);
}
writel(DIAGNOSTIC, diag);
return 1;
}
int
doWriteChipMemoryRegions(MPT_PORT *port, U32 addr, U32 *buf, int num)
{
U32 flush;
U32 diag;
U32 data;
#ifdef REG_DIAG_WRITE
U32 base;
#endif
int i;
if (doEnableDiagAccess(port, &diag) != 1)
return 0;
#ifdef REG_DIAG_WRITE
if (port->deviceId == MPI_MANUFACTPAGE_DEVICEID_FC919 ||
port->deviceId == MPI_MANUFACTPAGE_DEVICEID_FC929)
{
for (i = 0; i < num; i++)
{
writel(TEST_BASE_ADDRESS, addr);
readl(TEST_BASE_ADDRESS, base);
data = buf[i];
doReadWriteRegister(port, addr - base, &data, REG_DIAG_WRITE);
}
}
else
#endif
{
writel(DIAG_RW_ADDRESS, addr);
readl(DIAG_RW_ADDRESS, flush);
for (i = 0; i < num; i++)
{
data = buf[i];
writel(DIAG_RW_DATA, data);
readl(DIAG_RW_ADDRESS, flush);
}
writel(DIAG_RW_ADDRESS, 0);
}
writel(DIAGNOSTIC, diag);
return 1;
}
int
doDumpRegisters(MPT_PORT *port)
{
U32 data;
readl(DOORBELL, data);
printf("Doorbell %08x\n", data);
readl(DIAGNOSTIC, data);
printf("Diagnostic %08x\n", data);
readl(HOST_INTERRUPT_STATUS, data);
printf("Interrupt Status %08x\n", data);
readl(HOST_INTERRUPT_MASK, data);
printf("Interrupt Mask %08x\n", data);
return 1;
}
int
readLocalMemory(MPT_PORT *port, U32 addr, U32 *data, U32 temp)
{
ToolboxMemMoveRequest_t req;
ToolboxReply_t rep;
SGESimple32_t *simple32;
if (checkOperational(port, 1) != 1)
return 0;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_TOOLBOX;
req.Tool = MPI_TOOLBOX_MEMORY_MOVE_TOOL;
simple32 = (pSGESimple32_t)&req.SGL;
simple32[0].FlagsLength = set32(4 |
MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
MPI_SGE_FLAGS_LAST_ELEMENT |
MPI_SGE_FLAGS_32_BIT_ADDRESSING |
MPI_SGE_FLAGS_HOST_TO_IOC |
MPI_SGE_FLAGS_LOCAL_ADDRESS |
MPI_SGE_FLAGS_END_OF_BUFFER));
simple32[0].Address = set32(addr);
simple32[1].FlagsLength = set32(4 |
MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
MPI_SGE_FLAGS_LAST_ELEMENT |
MPI_SGE_FLAGS_32_BIT_ADDRESSING |
MPI_SGE_FLAGS_LOCAL_ADDRESS |
MPI_SGE_FLAGS_IOC_TO_HOST |
MPI_SGE_FLAGS_END_OF_BUFFER |
MPI_SGE_FLAGS_END_OF_LIST));
simple32[1].Address = set32(temp);
if (doMptCommand(port, &req, sizeof req - sizeof req.SGL + 2 * sizeof *simple32, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
return 0;
req.SGL.FlagsLength = set32(4 |
MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
MPI_SGE_FLAGS_LAST_ELEMENT |
MPI_SGE_FLAGS_32_BIT_ADDRESSING |
MPI_SGE_FLAGS_LOCAL_ADDRESS |
MPI_SGE_FLAGS_HOST_TO_IOC |
MPI_SGE_FLAGS_END_OF_BUFFER));
req.SGL.u.Address32 = set32(temp);
if (doMptCommand(port, &req, sizeof req - sizeof req.SGL + 1 * sizeof *simple32, &rep, sizeof rep,
data, 4, NULL, 0, SHORT_TIME) != 1)
return 0;
*data = get32x(*data);
return 1;
}
int
doDumpChipMemoryRegions(MPT_PORT *port)
{
FILE *file;
char name[256];
int n;
U32 diag;
U32 start;
U32 end;
U32 data;
int i;
U32 tempaddr;
U32 tempdata;
int binary = 0;
int binfile;
readl(DIAGNOSTIC, diag); // this will return if register access does not work
while (TRUE)
{
printf("Enter starting address: [00000000-FFFFFFFF or RETURN to quit] ");
if (getHexNumberAnswer(&start) == 0)
break;
printf("Enter ending address: [%08x-FFFFFFFF or RETURN to skip] ", start);
while (TRUE)
{
if (getHexNumberAnswer(&end) == 0)
{
printf("Enter number of locations: [1-1000000, default is 1] ");
n = getNumberAnswer(1, 1000000, 1);
end = start + (n - 1) * 4;
break;
}
if (start <= end)
break;
printf("Invalid answer, try again: ");
}
if (numFileNames)
{
n = getFileName(name, sizeof name, stdin, "output", 0);
}
else
{
printf("Enter output filename, or RETURN to send output to the screen: ");
n = getString(name, sizeof name, stdin);
}
if (n > 0)
{
if (gFlag == TRUE)
{
printf("File type: [0=ASCII, 1=Binary, default is 0] ");
binary = getNumberAnswer(0, 1, 0);
}
if (binary)
{
binfile = open(name, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, 0644);
if (binfile < 0)
{
printf("Open failure for file %s\n", name);
perror("Error is");
return 0;
}
file = NULL;
}
else
{
file = fopen(name, "a");
if (file == NULL)
{
printf("Open failure for file %s\n", name);
perror("Error is");
return 0;
}
binfile = -1;
}
}
else
{
file = stdout;
binfile = -1;
printf("\n");
}
start &= ~3;
end &= ~3;
i = 0;
if (end <= 0x10000000 && !port->notOperational)
{
tempaddr = 0;
tempdata = 0;
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
switch (port->deviceId)
{
case MPI_MANUFACTPAGE_DEVICEID_FC919X:
case MPI_MANUFACTPAGE_DEVICEID_FC929X:
if (port->fwVersion >= 0x01021404) // 1.02.20.04 or later...
tempaddr = 0x21000000;
break;
case MPI_MANUFACTPAGE_DEVICEID_FC939X:
case MPI_MANUFACTPAGE_DEVICEID_FC949X:
if (port->fwVersion >= 0x01031101) // 1.03.17.01 or later...
tempaddr = 0x21fc0000;
break;
case MPI_MANUFACTPAGE_DEVICEID_FC949E:
if (port->fwVersion >= 0x01031101) // 1.03.17.01 or later...
tempaddr = 0x21f80000;
break;
}
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
tempaddr = 0x21fffffc;
}
if (tempaddr != 0)
{
doReadChipMemoryRegions(port, tempaddr, &tempdata, 1);
}
while (start <= end)
{
if (tempaddr != 0 && readLocalMemory(port, start, &data, tempaddr) == 1)
{
if (binary)
{
data = set32x(data);
i += write(binfile, &data, 4);
}
else
i += fprintf(file, "%08x: %08x\n", start, data);
start += 4;
}
else
{
printf("Unable to read local memory!\n");
break;
}
}
if (tempaddr != 0)
{
doWriteChipMemoryRegions(port, tempaddr, &tempdata, 1);
}
}
else
{
while (start <= end)
{
doReadChipMemoryRegions(port, start, &data, 1);
if (binary)
{
data = set32x(data);
i += write(binfile, &data, 4);
}
else
i += fprintf(file, "%08x: %08x\n", start, data);
start += 4;
}
}
if (n > 0)
{
printf("\nWrote %d bytes to file %s\n", i, name);
if (binary)
close(binfile);
else if (file != stdout)
fclose(file);
}
printf("\n");
}
return 1;
}
int
doReadModifyChipMemoryLocations(MPT_PORT *port)
{
U32 diag;
U32 addr;
U32 data;
while (TRUE)
{
readl(DIAGNOSTIC, diag); // this will return if register access does not work
printf("Enter address: [00000000-FFFFFFFF or RETURN to quit] ");
if (getHexNumberAnswer(&addr) == 0)
break;
addr &= ~3;
doReadChipMemoryRegions(port, addr, &data, 1);
printf("%08x: %08x\n", addr, data);
printf("Enter value: [00000000-FFFFFFFF or RETURN to skip] ");
if (parseHexNumberChange(&data) == 1)
{
doWriteChipMemoryRegions(port, addr, &data, 1);
}
printf("\n");
}
return 1;
}
int
doDumpFcTraceBuffer(MPT_PORT *port)
{
FILE *file;
char name[256];
int n;
int i = 0;
U32 diag;
U32 addr;
U32 data;
U32 ptr1;
U32 len1;
U32 ptr2;
U32 len2;
switch (port->deviceId)
{
case MPI_MANUFACTPAGE_DEVICEID_FC919: addr = 0x01000000; break;
case MPI_MANUFACTPAGE_DEVICEID_FC929: addr = 0x01000000; break;
case MPI_MANUFACTPAGE_DEVICEID_FC919X: addr = 0x21000000; break;
case MPI_MANUFACTPAGE_DEVICEID_FC929X: addr = 0x21000000; break;
case MPI_MANUFACTPAGE_DEVICEID_FC939X: addr = 0x21fc0000; break;
case MPI_MANUFACTPAGE_DEVICEID_FC949X: addr = 0x21fc0000; break;
case MPI_MANUFACTPAGE_DEVICEID_FC949E: addr = 0x21f80000; break;
default:
printf("Unsupported chip type!\n");
return 0;
}
readl(DIAGNOSTIC, diag); // this will return if register access does not work
doReadChipMemoryRegions(port, addr, &data, 1);
if (data <= addr || data & 3)
{
printf("FC trace buffer address is invalid\n");
return 0;
}
else
{
addr = data;
doReadChipMemoryRegions(port, addr, &data, 1);
if (data != ('T' << 24) + ('R' << 16) + ('A' << 8) + ('C' << 0))
{
printf("FC trace buffer signature is invalid\n");
return 0;
}
}
n = getFileName(name, sizeof name, stdin, "output", 0);
if (n > 0)
{
file = fopen(name, "w");
if (file == NULL)
{
printf("Open failure for file %s\n", name);
perror("Error is");
return 0;
}
}
else
{
printf("Trace buffer won't be dumped\n");
return 1;
}
printf("\n");
printf("TraceInfo %08x\n", addr);
printf("TraceSignature %08x\n", data);
doReadChipMemoryRegions(port, addr + 4, &data, 1);
printf("TraceIndex %08x\n", data);
doReadChipMemoryRegions(port, addr + 8, &data, 1);
printf("TraceHistoryBuf %08x\n", data);
ptr1 = data;
doReadChipMemoryRegions(port, addr + 12, &data, 1);
printf("TraceHistoryBufSize %08x\n", data);
len1 = data;
doReadChipMemoryRegions(port, addr + 16, &data, 1);
printf("TraceCounters %08x\n", data);
ptr2 = data;
doReadChipMemoryRegions(port, addr + 20, &data, 1);
printf("NumTraceCounters %08x\n", data);
len2 = data;
while (len1)
{
doReadChipMemoryRegions(port, ptr1, &data, 1);
i += fprintf(file, "%08x: %08x\n", ptr1, data);
ptr1 += 4;
len1 -= 1;
}
while (len2)
{
doReadChipMemoryRegions(port, ptr2, &data, 1);
i += fprintf(file, "%08x: %08x\n", ptr2, data);
ptr2 += 4;
len2 -= 1;
}
printf("\nWrote %d bytes to file %s\n", i, name);
fclose(file);
return 1;
}
int
doForceFirmwareFault(MPT_PORT *port)
{
printf("Writing C0FFEE to Doorbell...\n");
writel(DOORBELL, 0xc0ffee00);
return 1;
}
#endif
int
doReadWriteExpanderMemory(MPT_PORT *port)
{
int i;
int j;
_U64 sas_address;
U8 physical_port;
U32 addr;
U32 data;
int n;
int action;
int ringFormat;
U16 ringAddr = 0;
int numDwords;
if (selectExpander(port, NULL, NULL, &physical_port, &sas_address, NULL) != 1)
return 0;
printf("\nDo you want to use the AHB (x28/x36/Bobcat/Cobra)\n");
printf("or Ring (x12) format SMP? [0=AHB, 1=Ring, default is 0] ");
ringFormat = getNumberAnswer(0, 1, 0);
while (TRUE)
{
if (ringFormat)
{
printf("\nEnter address: [00000-7FFFF or RETURN to quit] ");
addr = getNumberAnswerHex(0, 0x7FFFF, 0xFFFFFFFF);
if (addr == 0xFFFFFFFF)
break;
}
else
{
printf("\nEnter address: [00000000-FFFFFFFF or RETURN to quit] ");
if (getHexNumberAnswer(&addr) == 0)
break;
}
while (TRUE)
{
printf("\nDo you want to read or write? [0=Read, 1=Write, or RETURN for new address] ");
action = getNumberAnswer(0, 1, -1);
if (action < 0)
break;
printf("\n");
if (action == 0)
{
unsigned char smp_req[8];
unsigned char smp_rsp[1024];
if (ringFormat)
{
printf("Enter number of locations: [1-127, default is 1] ");
n = getNumberAnswer(1, 127, 1);
}
else
{
printf("Enter number of locations: [1-128, default is 1] ");
n = getNumberAnswer(1, 128, 1);
}
addr &= ~3;
memset(smp_req, 0, sizeof smp_req);
smp_req[0] = 0x40;
if (ringFormat)
smp_req[1] = 0x40;
else
smp_req[1] = 0x42;
smp_req[2] = 0xff;
smp_req[3] = n;
if (ringFormat)
{
/* starting address must be on an 8-byte boundary */
ringAddr = (addr >> 3) & 0xFFFF;
put2bytes(smp_req, 4, ringAddr);
}
else
{
put4bytes(smp_req, 4, addr);
}
if (doSmpPassthrough(port, physical_port, sas_address,
smp_req, sizeof smp_req, smp_rsp, sizeof smp_rsp, NULL) == 1)
{
if (smp_rsp[2] != 0)
{
printf("\nRead Memory failed with result %02x\n\n", smp_rsp[2]);
continue;
}
printf("\n");
if (ringFormat)
{
/* this SMP returns 2 DWORDS for each requested location. The
* starting address for returned data is the user supplied address
* with bits 0-2 cleared (i.e. the 8-byte boundary)
*/
numDwords = n*2;
addr = ringAddr << 3;
}
else
numDwords = n;
for (i = 0, j = 0; i < numDwords; i++, j += 4)
{
data = get4bytes(smp_rsp, j + 4);
printf("%08x: %08x\n", addr + j, data);
}
}
}
if (action == 1)
{
unsigned char smp_req[16];
unsigned char smp_rsp[4];
printf("Enter value: [00000000-FFFFFFFF or RETURN to not change] ");
if (getHexNumberAnswer(&data) == 0)
continue;
addr &= ~3;
memset(smp_req, 0, sizeof smp_req);
smp_req[0] = 0x40;
if (ringFormat)
smp_req[1] = 0xc0;
else
smp_req[1] = 0xc2;
smp_req[2] = 0xff;
smp_req[3] = 1;
if (ringFormat)
{
int firstDword;
int byteEnables;
int dataOffset;
/* starting address must be on an 8-byte boundary */
ringAddr = (addr >> 3) & 0xFFFF;
put2bytes(smp_req, 4, ringAddr);
/* determine whether the data is going in the first or second
* dword and which byte enables are needed
*/
firstDword = (addr & 0x04) == 0 ? 1 : 0;
byteEnables = firstDword ? 0x0F : 0xF0;
dataOffset = firstDword ? 8 : 12;
smp_req[6] = byteEnables;
smp_req[7] = byteEnables;
put4bytes(smp_req, dataOffset, data);
}
else
{
put4bytes(smp_req, 4, addr);
put4bytes(smp_req, 8, data);
}
if (doSmpPassthrough(port, physical_port, sas_address,
smp_req, sizeof smp_req, smp_rsp, sizeof smp_rsp, NULL) == 1)
{
if (smp_rsp[2] != 0)
{
printf("\nWrite Memory failed with result %02x\n\n", smp_rsp[2]);
continue;
}
}
}
}
}
return 1;
}
int
doReadWriteExpanderIstwiDevice(MPT_PORT *port)
{
int bus;
int target;
unsigned char desc[4];
unsigned char scan[1];
int i;
int j;
int n;
int t;
char name[256];
FILE *file;
unsigned char *buffer = NULL;
int length;
int offset;
int id;
int channel;
int address;
int size;
int action;
char c[16];
if (selectExpander(port, &bus, &target, NULL, NULL, NULL) != 1)
return 0;
while (TRUE)
{
printf("\nEnter ISTWI device channel: [0-2 or RETURN to quit] ");
channel = getNumberAnswerHex(0, 2, -1);
if (channel < 0)
break;
printf("Enter ISTWI device address: [00-FF or RETURN to quit] ");
address = getNumberAnswerHex(0x00, 0xff, -1);
if (address < 0)
break;
if (address <= 1)
{
j = address == 0;
if (j)
printf("\nScanning for ISTWI devices...\n");
else
printf("\nReading ISTWI devices...\n");
fflush(stdout);
for (i = 0; i < 128; i++)
{
if ((i & 15) == 0)
printf("\n");
address = i << 17;
id = 12 + channel;
if (doReadBufferFull(port, bus, target, 0, 2, id, address, scan, sizeof scan) == 1)
{
if (j)
printf(" %02x", i << 1);
else
printf(" %02x", scan[0]);
}
else
{
printf(" --");
}
fflush(stdout);
}
printf("\n");
continue;
}
address &= ~1;
printf("Enter ISTWI device size in bytes: [0=1, 1=256, 2=8192, or RETURN to quit] ");
size = getNumberAnswer(0, 2, -1);
if (size < 0)
break;
address <<= 16;
id = 12 + channel + size * 3;
if (doReadBufferFull(port, bus, target, 0, 3, id, address, desc, sizeof desc) == 1)
{
size = get3bytes(desc, 1);
}
else
{
printf("ISTWI device size could not be verified, cannot continue!\n");
return 1;
}
while (TRUE)
{
printf("\nDo you want to read or write? [0=Read, 1=Write, or RETURN for new device] ");
action = getNumberAnswer(0, 1, -1);
if (action < 0)
break;
printf("\n");
if (action == 0)
{
if (size > 1)
{
printf("Enter read offset: [0-%X, default is 0] ", size - 1);
offset = getNumberAnswerHex(0, size - 1, 0);
printf("Enter read length: [1-%X, default is %X] ", size - offset, size - offset);
length = getNumberAnswerHex(1, size - offset, size - offset);
}
else
{
offset = 0;
length = 1;
}
buffer = (unsigned char *)malloc(length);
if (doReadBufferFull(port, bus, target, 0, 2, id, address + offset, buffer, length) != 1)
{
printf("Failed to read ISTWI device!\n");
break;
}
if (length <= 16)
{
n = 0;
if (size > 1)
printf("\n");
}
else if (numFileNames)
{
n = getFileName(name, sizeof name, stdin, "output", 0);
}
else
{
printf("Enter output filename, or RETURN to send output to the screen: ");
n = getString(name, sizeof name, stdin);
if (n == 0)
printf("\n");
}
if (n > 0)
{
if (gFlag == TRUE)
{
printf("File type: [0=ASCII, 1=Binary, default is 0] ");
t = getNumberAnswer(0, 1, 0);
}
else
{
t = 0;
}
if (t)
{
int file;
file = open(name, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, 0644);
if (file < 0)
{
printf("Open failure for file %s\n", name);
perror("Error is");
}
else
{
t = write(file, buffer, length);
if (t != length)
{
printf("Write failed for file %s, t = %x\n", name, t);
perror("Error is");
}
else
{
printf("\nWrote %d bytes to file %s\n", length, name);
}
close(file);
}
free(buffer);
continue;
}
else
{
file = fopen(name, "w");
if (file == NULL)
{
printf("Open failure for file %s\n", name);
perror("Error is");
free(buffer);
continue;
}
}
}
else
{
file = stdout;
}
for (i = 0, j = 0; i < length; i++, j++)
{
if (j == 0)
fprintf(file, "%04x : ", i);
fprintf(file, "%02x ", buffer[i]);
if (!isprint(buffer[i]))
c[j] = ' ';
else
c[j] = buffer[i];
if (j == sizeof c - 1)
{
fprintf(file, " ");
for (j = 0; j < sizeof c; j++)
{
fprintf(file, "%c", c[j]);
}
fprintf(file, "\n");
j = -1;
}
}
if (j != 0)
{
for (i = j; i < sizeof c; i++)
fprintf(file, " ");
fprintf(file, " ");
for (i = 0; i < j; i++)
{
fprintf(file, "%c", c[i]);
}
fprintf(file, "\n");
}
if (file != stdout)
fclose(file);
free(buffer);
}
if (action == 1)
{
if (size > 1)
{
printf("Enter write offset: [0-%X, default is 0] ", size - 1);
offset = getNumberAnswerHex(0, size - 1, 0);
}
else
{
offset = 0;
}
printf("Enter value: [00-FF or RETURN to not change] ");
t = getNumberAnswerHex(0x00, 0xff, -1);
if (t < 0)
continue;
scan[0] = t;
if (doWriteBufferFull(port, bus, target, 0, 2, id, address + offset, scan, 1) != 1)
{
printf("Failed to write ISTWI device!\n");
break;
}
}
}
}
return 1;
}
int
doResetExpander(MPT_PORT *port)
{
_U64 sas_address;
U8 physical_port;
U32 addr;
U32 data;
int n;
if (selectExpander(port, NULL, NULL, &physical_port, &sas_address, NULL) != 1)
return 0;
printf("\nResetting expander...\n");
addr = 0xc3800200; // cobra reset address
data = 0x0c0b080a; // cobra reset value
/* first attempt the reset using the cobra reset value (this write will go to
* reserved address space on bobcat and yeti)
*/
if ((n = sendResetExpander(port, physical_port, sas_address, addr, data)) == 2)
{
/* no good. now try yeti */
addr = 0xc0000200; // yeti and bobcat reset address
data = 0x59455449; // yeti reset value
/* attempt the reset using the yeti reset value */
if ((n = sendResetExpander(port, physical_port, sas_address, addr, data)) == 2)
{
/* no good. Try using the bobcat reset value instead */
data = 0x0b0bca70; // bobcat reset value
if ((n = sendResetExpander(port, physical_port, sas_address, addr, data)) != 1)
return 0;
}
}
return n;
}
int
sendResetExpander(MPT_PORT *port, U8 physical_port, _U64 sas_address, U32 addr, U32 data)
{
SmpPassthroughRequest_t req;
SmpPassthroughReply_t rep;
int ioc_status;
unsigned char smp_req[12];
unsigned char smp_rsp[4];
memset(smp_req, 0, sizeof smp_req);
memset(smp_rsp, 0, sizeof smp_rsp);
smp_req[0] = 0x40;
smp_req[1] = 0xc2;
smp_req[3] = 1;
put4bytes(smp_req, 4, addr);
put4bytes(smp_req, 8, data);
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SMP_PASSTHROUGH;
req.PhysicalPort = physical_port;
req.RequestDataLength = set16(sizeof smp_req);
req.SASAddress = sas_address;
if (doMptCommand(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
smp_rsp, sizeof smp_rsp, smp_req, sizeof smp_req, SHORT_TIME) == 1)
{
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status != MPI_IOCSTATUS_SUCCESS &&
ioc_status != MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED)
{
printf("\nSMPPassthrough failed, IOCStatus = %04x (%s)\n", ioc_status, translateIocStatus(ioc_status));
return 0;
}
/* if the SMP function result is 0 (success) or 2 (function failed) then assume it is ok to move on and
* key off the ioc_status. Since writing the cobra values to a bobcat attempts to write to a reserved
* memory region, bobcat might return function failed in that case.
*/
if (smp_rsp[2] != 0 && smp_rsp[2] != 2)
{
printf("\nWrite Memory failed with result %02x\n\n", smp_rsp[2]);
return 0;
}
/* successfully resetting the expander should result in an ioc_status of
* SAS_SMP_REQUEST_FAILED (because the reset happens immediately and an SMP response
* is not sent to the host).
* If we get SUCCESS then assume we sent the wrong reset (i.e. the yeti value to a bobcat)
* and return a 2, indicating to the caller to try a different reset value.
*/
if (ioc_status == MPI_IOCSTATUS_SUCCESS)
return 2;
}
return 1;
}
#if (WIN32 || __linux__ || __sparc__ || DOS || EFI) && REGISTER_ACCESS
int
setFlashWrite(MPT_PORT *port, U32 flash_csr, U32 flash_csr_wr_en, int on)
{
U32 flush;
U32 data;
writel(DIAG_RW_ADDRESS, flash_csr);
readl(DIAG_RW_ADDRESS, flush);
readl(DIAG_RW_DATA, data);
if (on)
data |= flash_csr_wr_en;
else
data &= ~flash_csr_wr_en;
writel(DIAG_RW_ADDRESS, flash_csr);
readl(DIAG_RW_ADDRESS, flush);
writel(DIAG_RW_DATA, data);
readl(DIAG_RW_ADDRESS, flush);
return 1;
}
U32
readFlash(MPT_PORT *port, U32 flash_add, int offset)
{
U32 flush;
U32 addr;
U32 data;
addr = flash_add + offset;
writel(DIAG_RW_ADDRESS, addr);
readl(DIAG_RW_ADDRESS, flush);
readl(DIAG_RW_DATA, data);
// printf("rf %08x %08x\n", addr, data);
return data;
}
int
writeFlash(MPT_PORT *port, U32 flash_add, int offset, U32 data)
{
U32 flush;
U32 addr;
#ifdef REG_DIAG_WRITE_BYTE
U32 base;
#endif
int lane;
lane = offset & 3;
addr = flash_add + offset;
#ifdef REG_DIAG_WRITE_BYTE
switch (port->deviceId)
{
case MPI_MANUFACTPAGE_DEVID_53C1030:
case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
writel(TEST_BASE_ADDRESS, addr);
readl(TEST_BASE_ADDRESS, base);
// printf("wf %08x %02x\n", addr, data);
doReadWriteRegister(port, addr - base, &data, REG_DIAG_WRITE_BYTE);
readl(TEST_BASE_ADDRESS, flush);
return 1;
}
#endif
addr -= lane;
data <<= 24;
data += lane;
// printf("wf %08x %08x\n", addr, data);
writel(DIAG_RW_ADDRESS, addr);
readl(DIAG_RW_ADDRESS, flush);
writel(DIAG_RW_DATA, data);
readl(DIAG_RW_ADDRESS, flush);
return 1;
}
void
resetFlash(MPT_PORT *port, U32 flash_csr, U32 flash_csr_wr_en, U32 flash_add, int intel)
{
setFlashWrite(port, flash_csr, flash_csr_wr_en, 1);
writeFlash(port, flash_add, 0, intel ? FLASH_RESET_INTEL : FLASH_RESET_AMD);
setFlashWrite(port, flash_csr, flash_csr_wr_en, 0);
}
int
doFlashInfo(MPT_PORT *port)
{
U32 diag;
U32 data;
U32 flash_add;
U32 flash_csr;
U32 flash_csr_wr_en;
U32 id;
unsigned char cfi_query[128];
int i;
int t;
if (doEnableDiagAccess(port, &diag) != 1) // this will return if register access does not work
return 0;
switch (port->deviceId)
{
case MPI_MANUFACTPAGE_DEVICEID_FC939X:
case MPI_MANUFACTPAGE_DEVICEID_FC949X:
case MPI_MANUFACTPAGE_DEVICEID_FC949E:
flash_add = 0x3d000000;
flash_csr = 0x3f000004;
flash_csr_wr_en = 1<<16;
break;
#ifdef REG_DIAG_WRITE_BYTE
case MPI_MANUFACTPAGE_DEVID_53C1030:
case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
flash_add = 0x3e000000;
flash_csr = 0x3f000000;
flash_csr_wr_en = 1<<11;
break;
#endif
case MPI_MANUFACTPAGE_DEVICEID_FC919X:
case MPI_MANUFACTPAGE_DEVICEID_FC929X:
case MPI_MANUFACTPAGE_DEVID_SAS1064:
case MPI_MANUFACTPAGE_DEVID_SAS1064E:
case MPI_MANUFACTPAGE_DEVID_SAS1066:
case MPI_MANUFACTPAGE_DEVID_SAS1066E:
case MPI_MANUFACTPAGE_DEVID_SAS1068:
case MPI_MANUFACTPAGE_DEVID_SAS1068E:
flash_add = 0x3e000000;
flash_csr = 0x3f000004;
flash_csr_wr_en = 1<<16;
break;
default:
printf("Unable to gather FLASH information\n");
return 0;
}
data = readFlash(port, flash_add, 0);
t = 0;
if (t == 0)
{
setFlashWrite(port, flash_csr, flash_csr_wr_en, 1);
writeFlash(port, flash_add, 0, FLASH_RESET_INTEL);
writeFlash(port, flash_add, 0, FLASH_IDENTIFY);
setFlashWrite(port, flash_csr, flash_csr_wr_en, 0);
id = readFlash(port, flash_add, 0);
if (id != data && id != 0)
{
printf("Intel-compatible FLASH device, Manufacturer ID = %02x and Device ID = %02x\n",
(id >> 0) & 0xff, (id >> 8) & 0xff);
resetFlash(port, flash_csr, flash_csr_wr_en, flash_add, 1);
t = 1;
}
}
if (t == 0)
{
setFlashWrite(port, flash_csr, flash_csr_wr_en, 1);
writeFlash(port, flash_add, 0, FLASH_RESET_AMD);
writeFlash(port, flash_add, 0x555, 0xaa);
writeFlash(port, flash_add, 0x2aa, 0x55);
writeFlash(port, flash_add, 0x555, FLASH_IDENTIFY);
setFlashWrite(port, flash_csr, flash_csr_wr_en, 0);
id = readFlash(port, flash_add, 0);
if (id != data && id != 0)
{
printf("AMD-compatible 8-bit FLASH device, Manufacturer ID = %02x and Device ID = %02x\n",
(id >> 0) & 0xff, (id >> 8) & 0xff);
resetFlash(port, flash_csr, flash_csr_wr_en, flash_add, 0);
t = 1;
}
}
if (t == 0)
{
setFlashWrite(port, flash_csr, flash_csr_wr_en, 1);
writeFlash(port, flash_add, 0, FLASH_RESET_AMD);
writeFlash(port, flash_add, 0xaaa, 0xaa);
writeFlash(port, flash_add, 0x555, 0x55);
writeFlash(port, flash_add, 0xaaa, FLASH_IDENTIFY);
setFlashWrite(port, flash_csr, flash_csr_wr_en, 0);
id = readFlash(port, flash_add, 0);
if (id != data && id != 0)
{
printf("AMD-compatible 16-bit FLASH device, Manufacturer ID = %02x and Device ID = %02x\n",
(id >> 0) & 0xff, (id >> 16) & 0xff);
resetFlash(port, flash_csr, flash_csr_wr_en, flash_add, 0);
t = 1;
}
}
setFlashWrite(port, flash_csr, flash_csr_wr_en, 1);
writeFlash(port, flash_add, 0, FLASH_RESET_AMD);
writeFlash(port, flash_add, 0x55, FLASH_CFI_QUERY);
setFlashWrite(port, flash_csr, flash_csr_wr_en, 0);
for (i = 0; i < sizeof cfi_query; i += 4)
*((U32 *)(cfi_query + i)) = set32x(readFlash(port, flash_add, i));
resetFlash(port, flash_csr, flash_csr_wr_en, flash_add, 0);
if (cfi_query[16] == 'Q' && cfi_query[17] == 'R' && cfi_query[18] == 'Y')
{
printf("CFI-compatible 8-bit or 16-bit FLASH device\n\n");
displayByteData((unsigned char *)cfi_query, sizeof cfi_query / 2);
writel(DIAGNOSTIC, diag);
return 1;
}
setFlashWrite(port, flash_csr, flash_csr_wr_en, 1);
writeFlash(port, flash_add, 0, FLASH_RESET_AMD);
writeFlash(port, flash_add, 0xaa, FLASH_CFI_QUERY);
setFlashWrite(port, flash_csr, flash_csr_wr_en, 0);
for (i = 0; i < sizeof cfi_query; i += 4)
*((U32 *)(cfi_query + i)) = set32x(readFlash(port, flash_add, i));
resetFlash(port, flash_csr, flash_csr_wr_en, flash_add, 0);
if (cfi_query[32] == 'Q' && cfi_query[34] == 'R' && cfi_query[36] == 'Y')
{
printf("CFI-compatible 16-bit FLASH device in 8-bit mode\n\n");
for (i = 0; i < sizeof cfi_query / 2; i++)
cfi_query[i] = cfi_query[i * 2];
displayByteData((unsigned char *)cfi_query, sizeof cfi_query / 2);
writel(DIAGNOSTIC, diag);
return 1;
}
if (t == 0)
printf("Could not detect FLASH type!\n");
writel(DIAGNOSTIC, diag);
return 0;
}
int
doReadRegister(MPT_PORT *port, U32 offset, U32 *data)
{
int command = REG_MEM_READ;
if (port->deviceId == MPI_MANUFACTPAGE_DEVID_53C1030 &&
(offset == MPI_DIAG_RW_DATA_OFFSET || offset == MPI_DIAG_RW_ADDRESS_OFFSET))
{
command = REG_IO_READ;
}
return doReadWriteRegister(port, offset, data, command);
}
int
doWriteRegister(MPT_PORT *port, U32 offset, U32 *data)
{
int command = REG_MEM_WRITE;
if (port->deviceId == MPI_MANUFACTPAGE_DEVID_53C1030 &&
(offset == MPI_DIAG_RW_DATA_OFFSET || offset == MPI_DIAG_RW_ADDRESS_OFFSET))
{
command = REG_IO_WRITE;
}
return doReadWriteRegister(port, offset, data, command);
}
int
doReadWriteRegister(MPT_PORT *port, U32 offset, U32 *data, int command)
{
#if WIN32
int status;
MPI_REG_ACCESS_SRB srb;
int inLen;
int outLen;
DWORD retLen;
memset(&srb, 0, sizeof srb);
srb.Sic.Length = sizeof srb - sizeof srb.Sic;
srb.Sic.ControlCode = MPI_REG_ACCESS;
srb.Sic.HeaderLength = sizeof srb.Sic;
srb.Sic.Timeout = SHORT_TIME;
memcpy((char *)&srb.Sic.Signature, "4.00 ", 8);
srb.Command = command;
srb.RegOffset = offset;
srb.RegData = *data;
inLen = sizeof srb;
outLen = sizeof srb;
retLen = 0;
status = DeviceIoControl(port->fileHandle, port->ioctlValue,
&srb, inLen, &srb, outLen, &retLen, NULL);
*data = srb.RegData;
return status;
#endif
#if __linux__
#if i386
if (command == REG_IO_READ)
{
if (port->ioPhys == 0)
return 0;
*data = inl(port->ioPhys + offset);
return 1;
}
if (command == REG_IO_WRITE)
{
if (port->ioPhys == 0)
return 0;
outl(*data, port->ioPhys + offset);
return 1;
}
#endif
if (command == REG_MEM_READ)
{
if (port->memPhys == 0)
return 0;
*data = get32x(*(port->memVirt + offset / 4));
return 1;
}
if (command == REG_MEM_WRITE)
{
if (port->memPhys == 0)
return 0;
*(port->memVirt + offset / 4) = set32x(*data);
return 1;
}
if (command == REG_DIAG_READ)
{
if (port->diagPhys == 0)
return 0;
*data = get32x(*(port->diagVirt + offset / 4));
return 1;
}
if (command == REG_DIAG_WRITE)
{
if (port->diagPhys == 0)
return 0;
*(port->diagVirt + offset / 4) = set32x(*data);
return 1;
}
if (command == REG_DIAG_WRITE_BYTE)
{
if (port->diagPhys == 0)
return 0;
*((U8 *)port->diagVirt + offset) = (U8)*data;
return 1;
}
return 0;
#endif
#if __sparc__
int status;
SYM_REG_ACCESS regAccess;
regAccess.Command = command;
regAccess.RegOffset = offset;
regAccess.RegData = *data;
// Not implemented for gen2 SAS driver...just let it fail in that case
status = ioctl(port->fileHandle, SYMIOCTL_REG_ACCESS, &regAccess);
*data = regAccess.RegData;
return status == 0;
#endif
#if DOS || EFI
HANDLE adap = port->fileHandle;
if (command == REG_IO_READ)
{
*data = mpt_read32(adap, offset, adap->io);
return 1;
}
if (command == REG_MEM_READ)
{
*data = mpt_read32(adap, offset, adap->mem);
return 1;
}
if (command == REG_DIAG_READ)
{
*data = mpt_read32(adap, offset, adap->diagmem);
return 1;
}
if (command == REG_IO_WRITE)
{
mpt_write32(adap, offset, *data, adap->io);
return 1;
}
if (command == REG_MEM_WRITE)
{
mpt_write32(adap, offset, *data, adap->mem);
return 1;
}
if (command == REG_DIAG_WRITE)
{
mpt_write32(adap, offset, *data, adap->diagmem);
return 1;
}
if (command == REG_DIAG_WRITE_BYTE)
{
mpt_write8(adap, offset, (U8)*data);
return 1;
}
return 0;
#endif
}
#endif
int
doDumpPciConfigSpace(MPT_PORT *port)
{
#if WIN32
int status;
PCI_CONFIG_SPACE_SRB srb;
int inLen;
int outLen;
DWORD retLen;
U8 *config;
#endif
#if __linux__
char name[64];
HANDLE handle;
U8 config[256];
#endif
#if __sparc__
SYM_PCI_INFO pciInfo;
int status;
U8 *config;
#endif
#if DOS
HANDLE adap = port->fileHandle;
U8 config[256];
int i;
#endif
#if EFI
EFI_STATUS status;
HANDLE adap = port->fileHandle;
U8 config[256];
#endif
if (getBoardInfo(port) == 1)
{
printf("PCI location is Segment %d, Bus %d, Device %d, Function %d (combined: %02x%02x%02x)\n",
port->pciSegment, port->pciBus, port->pciDevice, port->pciFunction,
port->pciSegment, port->pciBus, (port->pciDevice << 3) | port->pciFunction);
}
#if WIN32
memset(&srb, 0, sizeof srb);
srb.Sic.Length = sizeof srb - sizeof srb.Sic;
srb.Sic.ControlCode = DRVR_INFO_IOCTL;
srb.Sic.HeaderLength = sizeof srb.Sic;
srb.Sic.Timeout = SHORT_TIME;
memcpy((char *)&srb.Sic.Signature, "4.00 ", 8);
srb.PageCode = PCI_CONFIG_SPACE_PAGE;
inLen = sizeof srb;
outLen = sizeof srb;
retLen = 0;
status = DeviceIoControl(port->fileHandle, port->ioctlValue,
&srb, inLen, &srb, outLen, &retLen, NULL);
if (status != 1)
return 0;
config = srb.PciConfigSpace;
#endif
#if __linux__
sprintf(name, "/proc/bus/pci/%04x:%02x/%02x.%d",
port->pciSegment, port->pciBus, port->pciDevice, port->pciFunction);
handle = open(name, O_RDWR);
if (handle < 0)
{
sprintf(name, "/proc/bus/pci/%02x/%02x.%d",
port->pciBus, port->pciDevice, port->pciFunction);
handle = open(name, O_RDWR);
if (handle < 0)
return 0;
}
if (read(handle, config, sizeof config) != sizeof config)
return 0;
#endif
#if __sparc__
memset(&pciInfo, 0, sizeof pciInfo);
if (mpi2)
status = ioctl(port->fileHandle, MPTIOCTL_GET_PCI_INFO, &pciInfo);
else
status = ioctl(port->fileHandle, SYMIOCTL_GET_PCI_INFO, &pciInfo);
if (status != 0)
return 0;
config = pciInfo.PciHeader;
#endif
#if DOS
for (i = 0; i < 256; i++)
{
config[i] = PciReadConfigByte(adap->bus_number, adap->device_function, i);
}
#endif
#if EFI
status = adap->pci_io->Pci.Read(adap->pci_io, EfiPciIoWidthUint8, 0,
sizeof config, config);
if (EFI_ERROR(status))
return 0;
#endif
dumpMemoryWide(config, 256, "PCI Config Space");
return 1;
}
char *pageType[32] =
{
"IO Unit",
"IOC",
"BIOS",
"SCSI Port",
"SCSI Device",
"FC Port",
"FC Device",
"LAN",
"RAID Volume",
"Manufacturing",
"RAID PhysDisk",
"Inband",
"Type 0Ch",
"Type 0Dh",
"Type 0Eh",
"Extended",
"SAS IO Unit",
"SAS Expander",
"SAS Device",
"SAS Phy",
"Log",
"Enclosure",
"Type 16h",
"Type 17h",
"Type 18h",
"Type 19h",
"Type 1Ah",
"Type 1Bh",
"Type 1Ch",
"Type 1Dh",
"Type 1Eh",
"Type 1Fh"
};
int
doShowNonDefaultSettings(MPT_PORT *port)
{
ConfigReply_t rep;
int type;
int number;
int attr;
U32 buf_def[255];
U32 buf_cur[255];
int len_def;
int len_cur;
int i;
int len;
printf("Checking for non-default persistent settings...\n");
for (type = 0; type < 32; type++)
{
if (type == MPI_CONFIG_PAGETYPE_RAID_VOLUME ||
type == MPI_CONFIG_PAGETYPE_MANUFACTURING ||
type == MPI_CONFIG_PAGETYPE_RAID_PHYSDISK ||
type == MPI_CONFIG_PAGETYPE_EXTENDED ||
type == MPI_CONFIG_EXTPAGETYPE_LOG)
{
continue;
}
for (number = 0; number < 16; number++)
{
if (type == MPI_CONFIG_PAGETYPE_IO_UNIT && number == 2)
{
continue;
}
if (type == MPI_CONFIG_PAGETYPE_IO_UNIT && number == 3)
{
continue;
}
if (type == MPI_CONFIG_PAGETYPE_BIOS && number == 2)
{
continue;
}
if (getConfigPageHeader(port, type, number, 0, &rep) != 1)
{
continue;
}
attr = rep.Header.PageType & MPI_CONFIG_PAGEATTR_MASK;
if (attr != MPI_CONFIG_PAGEATTR_PERSISTENT)
{
continue;
}
printf("\n%s Page %d is persistent\n", pageType[type], number);
if (type == MPI_CONFIG_PAGETYPE_FC_PORT && number == 3)
{
doFcPersistentMappings(port, 1);
continue;
}
if (type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE && number == 2)
{
if (mpi1)
doSasPersistentMappings(port, 1);
continue;
}
memset(buf_def, 0, sizeof buf_def);
memset(buf_cur, 0, sizeof buf_cur);
if (getConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_READ_DEFAULT,
type, number, 0, buf_def, sizeof buf_def) != 1)
{
continue;
}
if (getConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_READ_NVRAM,
type, number, 0, buf_cur, sizeof buf_cur) != 1)
{
continue;
}
if (type > MPI_CONFIG_PAGETYPE_EXTENDED)
{
len_def = get16(((pConfigExtendedPageHeader_t)buf_def)->ExtPageLength);
len_cur = get16(((pConfigExtendedPageHeader_t)buf_cur)->ExtPageLength);
}
else
{
len_def = ((pConfigPageHeader_t)buf_def)->PageLength;
len_cur = ((pConfigPageHeader_t)buf_cur)->PageLength;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
if (type == MPI_CONFIG_PAGETYPE_IO_UNIT && number == 1)
{
IOUnitPage1_t *def_IOUnitPage1 = (pIOUnitPage1_t)buf_def;
int def_flags = get32(def_IOUnitPage1->Flags);
// default for multi-pathing is ON from the factory, but OFF for older firmware
// flip it on, so the firmware default matches the factory default
def_IOUnitPage1->Flags = set32(def_flags | MPI_IOUNITPAGE1_MULTI_PATHING);
}
}
len = max(len_def, len_cur);
for (i = 0; i < len; i++)
{
if (buf_def[i] != buf_cur[i])
{
printf("Mismatch at offset %04x: default = %08x, current = %08x\n",
i*4, get32x(buf_def[i]), get32x(buf_cur[i]));
}
}
}
}
return 1;
}
int
doRestoreDefaultSettings(MPT_PORT *port)
{
ConfigReply_t rep;
int type;
int number;
int attr;
U32 buf_def[255];
U32 buf_cur[255];
int len_def;
int len_cur;
int i;
int len;
printf("Restoring default persistent settings...\n");
for (type = 0; type < 32; type++)
{
if (type == MPI_CONFIG_PAGETYPE_RAID_VOLUME ||
type == MPI_CONFIG_PAGETYPE_MANUFACTURING ||
type == MPI_CONFIG_PAGETYPE_RAID_PHYSDISK ||
type == MPI_CONFIG_PAGETYPE_EXTENDED ||
type == MPI_CONFIG_EXTPAGETYPE_LOG)
{
continue;
}
for (number = 0; number < 16; number++)
{
if (type == MPI_CONFIG_PAGETYPE_IO_UNIT && number == 2)
{
continue;
}
if (type == MPI_CONFIG_PAGETYPE_IO_UNIT && number == 3)
{
continue;
}
if (type == MPI_CONFIG_PAGETYPE_BIOS && number == 2)
{
continue;
}
if (getConfigPageHeader(port, type, number, 0, &rep) != 1)
{
continue;
}
attr = rep.Header.PageType & MPI_CONFIG_PAGEATTR_MASK;
if (attr != MPI_CONFIG_PAGEATTR_PERSISTENT)
{
continue;
}
printf("\n%s Page %d is persistent\n", pageType[type], number);
if (type == MPI_CONFIG_PAGETYPE_FC_PORT && number == 3)
{
if (yesFlag == FALSE)
{
printf("Do you want to remove all persistent mappings? [Yes or No, default is Yes] ");
}
if (yesFlag == TRUE || getYesNoAnswer(1) == 1)
{
doFcPersistentMappings(port, 4);
}
continue;
}
if (type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE && number == 2)
{
if (mpi2)
continue;
if (yesFlag == FALSE)
{
printf("Do you want to remove all persistent mappings? [Yes or No, default is Yes] ");
}
if (yesFlag == TRUE || getYesNoAnswer(1) == 1)
{
doSasPersistentMappings(port, 10);
}
continue;
}
memset(buf_def, 0, sizeof buf_def);
memset(buf_cur, 0, sizeof buf_cur);
if (getConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_READ_DEFAULT,
type, number, 0, buf_def, sizeof buf_def) != 1)
{
continue;
}
if (getConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_READ_NVRAM,
type, number, 0, buf_cur, sizeof buf_cur) != 1)
{
// continue;
}
if (type > MPI_CONFIG_PAGETYPE_EXTENDED)
{
len_def = get16(((pConfigExtendedPageHeader_t)buf_def)->ExtPageLength);
len_cur = get16(((pConfigExtendedPageHeader_t)buf_cur)->ExtPageLength);
}
else
{
len_def = ((pConfigPageHeader_t)buf_def)->PageLength;
len_cur = ((pConfigPageHeader_t)buf_cur)->PageLength;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
if (type == MPI_CONFIG_PAGETYPE_IO_UNIT && number == 1)
{
IOUnitPage1_t *def_IOUnitPage1 = (pIOUnitPage1_t)buf_def;
IOUnitPage1_t *cur_IOUnitPage1 = (pIOUnitPage1_t)buf_cur;
int def_flags = get32(def_IOUnitPage1->Flags);
int cur_flags = get32(cur_IOUnitPage1->Flags);
if (!(def_flags & MPI_IOUNITPAGE1_MULTI_PATHING))
{
// default for multi-pathing is ON from the factory, but OFF for older firmware
// flip it on, so the firmware default matches the factory default
def_IOUnitPage1->Flags = set32(def_flags | MPI_IOUNITPAGE1_MULTI_PATHING);
if (!(cur_flags & MPI_IOUNITPAGE1_MULTI_PATHING))
printf("restoring factory default for MULTI_PATHING\n");
}
}
}
len = max(len_def, len_cur);
for (i = 0; i < len; i++)
{
if (buf_def[i] != buf_cur[i])
{
if (setConfigPageAction(port, MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM,
type, number, 0, buf_def, len_def * 4) == 1)
{
printf("Defaults restored\n");
}
else
{
printf("Failed to restore defaults!\n");
}
break;
}
}
}
}
return 1;
}
int
doDefaultPhyRegsSettings(MPT_PORT *port)
{
ManufacturingPage3_t *CurManufacturingPage3;
ManufacturingPage3_t *DefManufacturingPage3;
int length;
int t;
int i;
int j;
U32 *p_cur;
U32 *p_def;
printf("Updating default PhyRegs settings...\n");
if (port->deviceId == MPI_MANUFACTPAGE_DEVICEID_FC909)
{
return 0;
}
CurManufacturingPage3 = getConfigPageActionAlloc(port, MPI_CONFIG_ACTION_PAGE_READ_NVRAM,
MPI_CONFIG_PAGETYPE_MANUFACTURING, 3, 0,
&length);
if (CurManufacturingPage3 == NULL)
{
printf("Failed to read non-volatile ManufacturingPage3!\n");
return 0;
}
DefManufacturingPage3 = getConfigPageActionAlloc(port, MPI_CONFIG_ACTION_PAGE_READ_DEFAULT,
MPI_CONFIG_PAGETYPE_MANUFACTURING, 3, 0,
&length);
if (DefManufacturingPage3 == NULL)
{
printf("Failed to read default ManufacturingPage3!\n");
free(CurManufacturingPage3);
return 0;
}
for (i = 0; i < 2; i++)
{
p_cur = (U32 *)CurManufacturingPage3 + 2 + i * 8;
p_def = (U32 *)DefManufacturingPage3 + 2 + i * 8;
// preserve current WWNs for both channels!
for (j = 0; j < 4; j++)
p_def[j] = p_cur[j];
// preserve supported speeds / link type / connector type
p_def[j+3] = p_cur[j+3];
}
doIocInit(port, MPI_WHOINIT_MANUFACTURER);
t = setConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 3, 0, DefManufacturingPage3, length);
doIocInit(port, port->whoInit);
free(CurManufacturingPage3);
free(DefManufacturingPage3);
if (t != 1)
{
printf("Failed to save changes to NVRAM!\n");
return 0;
}
return 1;
}
int
doFcChangePersonalWwn(MPT_PORT *port)
{
FCPortPage1_t FCPortPage1;
ManufacturingPage3_t *ManufacturingPage3;
int length;
int t1;
int t2;
int flags;
U32 *p;
U32 wwnn_l;
U32 wwnn_h;
U32 wwpn_l;
U32 wwpn_h;
ManufacturingPage3 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 3, 0, &length);
if (ManufacturingPage3 == NULL)
return 0;
p = (U32 *)ManufacturingPage3 + 2 + port->iocNumber * 8;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
return 0;
wwnn_l = get32(FCPortPage1.NoSEEPROMWWNN.Low);
wwnn_h = get32(FCPortPage1.NoSEEPROMWWNN.High);
wwpn_l = get32(FCPortPage1.NoSEEPROMWWPN.Low);
wwpn_h = get32(FCPortPage1.NoSEEPROMWWPN.High);
printf("Current Personal FC WWNN = %08x%08x, WWPN = %08x%08x\n\n", wwnn_h, wwnn_l, wwpn_h, wwpn_l);
printf("Enter new WWNN: [16 hex digits or RETURN for none] ");
t1 = getHexDoubleNumberAnswer(&wwnn_h, &wwnn_l);
if (t1 == 0)
{
wwnn_l = get32x(p[2]);
wwnn_h = get32x(p[3]);
}
printf("Enter new WWPN: [16 hex digits or RETURN for none] ");
t2 = getHexDoubleNumberAnswer(&wwpn_h, &wwpn_l);
if (t1 == 0)
{
wwpn_l = get32x(p[0]);
wwpn_h = get32x(p[1]);
}
free(ManufacturingPage3);
FCPortPage1.NoSEEPROMWWNN.Low = set32(wwnn_l);
FCPortPage1.NoSEEPROMWWNN.High = set32(wwnn_h);
FCPortPage1.NoSEEPROMWWPN.Low = set32(wwpn_l);
FCPortPage1.NoSEEPROMWWPN.High = set32(wwpn_h);
flags = get32(FCPortPage1.Flags);
if (t1 || t2)
flags |= MPI_FCPORTPAGE1_FLAGS_FORCE_USE_NOSEEPROM_WWNS;
else
flags &= ~MPI_FCPORTPAGE1_FLAGS_FORCE_USE_NOSEEPROM_WWNS;
FCPortPage1.Flags = set32(flags);
if (setConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, &FCPortPage1, sizeof FCPortPage1) != 1)
{
printf("Failed to save changes to NVRAM!\n");
return 0;
}
return 1;
}
int
doGIEL(MPT_PORT *port)
{
FcCommonTransportSendRequest_t req;
FcCommonTransportSendReply_t rep;
U32 buf_out[256];
U32 buf_in[256];
int ioc_status;
U32 code;
int i;
if (bringOnline(port) != 1)
return 0;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND;
req.AliasIndex = virtInit;
req.MsgFlags_Did = set32(0xfffffa);
req.CTCommandCode = set16(0x0101);
req.FsType = 0xfa;
memset(buf_out, 0, sizeof buf_out);
buf_out[0] = set32x_be(0x01000000);
buf_out[1] = set32x_be(0xfa0101fc);
buf_out[2] = set32x_be(0x01010000);
buf_out[3] = set32x_be(0x00000000);
buf_in[2] = 0;
if (doMptCommand(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
buf_in, sizeof buf_in, buf_out, 16, SHORT_TIME) == 1)
{
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status != MPI_IOCSTATUS_SUCCESS)
{
printf("CTSend failed, IOCStatus = %04x (%s)\n", ioc_status, translateIocStatus(ioc_status));
return 0;
}
code = (get32x_be(buf_in[2]) >> 16) & 0xffff;
if (code == 0x8001)
{
printf("GIEL rejected\n\n");
for (i = 0; i < (int)get32(rep.ResponseLength) / 4; i++)
printf("Word %04d = %08x\n", i, get32x_be(buf_in[i]));
return 0;
}
if (code != 0x8002)
{
printf("GIEL not accepted, code is %04x\n\n", code);
for (i = 0; i < (int)get32(rep.ResponseLength) / 4; i++)
printf("Word %04d = %08x\n", i, get32x_be(buf_in[i]));
return 0;
}
for (i = 0; i < (int)get32(rep.ResponseLength) / 4; i++)
printf("Word %04d = %08x\n", i, get32x_be(buf_in[i]));
}
return 1;
}
int
doGID_FT(MPT_PORT *port)
{
FcCommonTransportSendRequest_t req;
FcCommonTransportSendReply_t rep;
U32 buf_out[256];
U32 buf_in[256];
int ioc_status;
U32 code;
int i;
if (bringOnline(port) != 1)
return 0;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND;
req.AliasIndex = virtInit;
req.MsgFlags_Did = set32(0xfffffc);
req.CTCommandCode = set16(0x0171);
req.FsType = 0xfc;
memset(buf_out, 0, sizeof buf_out);
buf_out[0] = set32x_be(0x01000000);
buf_out[1] = set32x_be(0xfc020000);
buf_out[2] = set32x_be(0x017101fc);
buf_out[3] = set32x_be(0x00000000);
buf_out[4] = set32x_be(0x00000008);
buf_in[2] = 0;
if (doMptCommand(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
buf_in, sizeof buf_in, buf_out, 20, SHORT_TIME) == 1)
{
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status != MPI_IOCSTATUS_SUCCESS)
{
printf("CTSend failed, IOCStatus = %04x (%s)\n", ioc_status, translateIocStatus(ioc_status));
return 0;
}
code = (get32x_be(buf_in[2]) >> 16) & 0xffff;
if (code == 0x8001)
{
printf("GID_FT rejected\n\n");
for (i = 0; i < (int)get32(rep.ResponseLength) / 4; i++)
printf("Word %04d = %08x\n", i, get32x_be(buf_in[i]));
return 0;
}
if (code != 0x8002)
{
printf("GID_FT not accepted, code is %04x\n\n", code);
for (i = 0; i < (int)get32(rep.ResponseLength) / 4; i++)
printf("Word %04d = %08x\n", i, get32x_be(buf_in[i]));
return 0;
}
for (i = 0; i < (int)get32(rep.ResponseLength) / 4; i++)
printf("Word %04d = %08x\n", i, get32x_be(buf_in[i]));
}
return 1;
}
int
doGA_NXT(MPT_PORT *port)
{
FcCommonTransportSendRequest_t req;
FcCommonTransportSendReply_t rep;
U32 buf_out[256];
U32 buf_in[256];
int ioc_status;
U32 code;
int i;
int d_id;
if (bringOnline(port) != 1)
return 0;
printf("Enter D_ID: [000000-FFFFFF or RETURN to quit] ");
d_id = getNumberAnswerHex(0x000000, 0xffffff, -1);
if (d_id < 0)
return 0;
printf("\n");
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND;
req.AliasIndex = virtInit;
req.MsgFlags_Did = set32(0xfffffc);
req.CTCommandCode = set16(0x0100);
req.FsType = 0xfc;
memset(buf_out, 0, sizeof buf_out);
buf_out[0] = set32x_be(0x01000000);
buf_out[1] = set32x_be(0xfc020000);
buf_out[2] = set32x_be(0x010001fc);
buf_out[3] = set32x_be(0x00000000);
buf_out[4] = set32x_be(d_id);
buf_in[2] = 0;
if (doMptCommand(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
buf_in, sizeof buf_in, buf_out, 20, SHORT_TIME) == 1)
{
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status != MPI_IOCSTATUS_SUCCESS)
{
printf("CTSend failed, IOCStatus = %04x (%s)\n", ioc_status, translateIocStatus(ioc_status));
return 0;
}
code = (get32x_be(buf_in[2]) >> 16) & 0xffff;
if (code == 0x8001)
{
printf("GA_NXT rejected\n\n");
for (i = 0; i < (int)get32(rep.ResponseLength) / 4; i++)
printf("Word %04d = %08x\n", i, get32x_be(buf_in[i]));
return 0;
}
if (code != 0x8002)
{
printf("GA_NXT not accepted, code is %04x\n\n", code);
for (i = 0; i < (int)get32(rep.ResponseLength) / 4; i++)
printf("Word %04d = %08x\n", i, get32x_be(buf_in[i]));
return 0;
}
for (i = 0; i < (int)get32(rep.ResponseLength) / 4; i++)
printf("Word %04d = %08x\n", i, get32x_be(buf_in[i]));
}
return 1;
}
int
doExLinkServiceSend(MPT_PORT *port)
{
ExLinkServiceSendRequest_t req;
ExLinkServiceSendReply_t rep;
U32 buf_out[256];
U32 buf_in[256];
int els;
int d_id;
int len;
U32 value;
int i;
int j;
int ioc_status;
U32 code;
int passes;
int delay;
if (bringOnline(port) != 1)
return 0;
printf("Enter ELS code: [00-FF or RETURN to quit] ");
els = getNumberAnswerHex(0x00, 0xff, -1);
if (els < 0)
return 0;
printf("Enter D_ID: [000000-FFFFFF or RETURN to quit] ");
d_id = getNumberAnswerHex(0x000000, 0xffffff, -1);
if (d_id < 0)
return 0;
printf("Enter payload length in words: [1-256 or RETURN to quit] ");
len = getNumberAnswer(0, 256, -1);
if (len < 0)
return 0;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_FC_EX_LINK_SRVC_SEND;
req.AliasIndex = virtInit;
req.MsgFlags_Did = set32(d_id);
req.ElsCommandCode = set32(els);
memset(buf_out, 0, sizeof buf_out);
buf_out[0] = set32x(els);
if (len > 1)
{
while (TRUE)
{
printf("\n");
for (i = 0; i < len; i++)
printf("Word %04d = %08x\n", i, get32x_be(buf_out[i]));
printf("\nEnter word to change: [0-%d or RETURN to quit] ", len - 1);
i = getNumberAnswer(0, len - 1, -1);
if (i < 0)
break;
printf("Enter value: [00000000-FFFFFFFF or RETURN to not change] ");
if (getHexNumberAnswer(&value) == 0)
continue;
if (i == 0)
buf_out[0] = set32x_be((value & 0xffffff) | (els << 24));
else
buf_out[i] = set32x_be(value);
}
}
printf("\nNumber of iterations: [1-1000000, default is 1] ");
passes = getNumberAnswer(1, 1000000, 1);
if (passes > 1)
{
printf("Delay in seconds between iterations: [1-6000, default is 30] ");
delay = getNumberAnswer(1, 6000, 30);
}
else
delay = 0;
for (j = 1; j <= passes; j++)
{
if (passes > 1)
{
if (j > 1)
sleep(delay);
printf("\nPass %d...\n", j);
}
printf("\n");
buf_in[0] = 0;
if (doMptCommand(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
buf_in, sizeof buf_in, buf_out, len * 4, SHORT_TIME) == 1)
{
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status != MPI_IOCSTATUS_SUCCESS)
{
printf("SendELS failed, IOCStatus = %04x (%s)\n", ioc_status, translateIocStatus(ioc_status));
#if WIN32
continue;
#else
return 0;
#endif
}
code = (get32x_be(buf_in[0]) >> 24) & 0xff;
if (code == 0x01)
{
printf("ELS rejected\n");
#if WIN32
continue;
#else
return 0;
#endif
}
if (code != 0x02)
{
printf("ELS not accepted, code is %02x\n", code);
#if WIN32
continue;
#else
return 0;
#endif
}
for (i = 0; i < (int)get32(rep.ResponseLength) / 4; i++)
printf("Word %04d = %08x\n", i, get32x_be(buf_in[i]));
}
}
return 1;
}
int
doResetFcLink(MPT_PORT *port, int flag)
{
FcPrimitiveSendRequest_t req;
FcPrimitiveSendReply_t rep;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_FC_PRIMITIVE_SEND;
if (flag)
req.SendFlags = MPI_FC_PRIM_SEND_FLAGS_ML_RESET_LINK;
else
req.SendFlags = MPI_FC_PRIM_SEND_FLAGS_RESET_LINK;
printf("Resetting FC link...\n");
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doScsiCdb(MPT_PORT *port)
{
SCSIIORequest_t req1;
Mpi2SCSIIORequest_t req2;
Mpi25SCSIIORequest_t req25;
SCSI_REPLY rep1;
SCSI_REPLY2 rep2;
void *req;
int req_size;
void *rep;
int rep_size;
int bus;
int target;
int lun;
unsigned char cdb[80];
unsigned char buf_out[512];
unsigned char buf_in[1024];
int len_out;
int len_in;
int value;
int i;
int j;
int t;
int n;
int ioc_status;
char c[17];
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
printf("LUN: [0-%d or RETURN to quit] ", port->maxLuns - 1);
lun = getNumberAnswer(0, port->maxLuns - 1, -1);
if (lun < 0)
return 1;
printf("CDB: [hex string or RETURN to quit] ");
n = getStringFromArgs((char *)cdb, sizeof cdb, stdin);
switch (n)
{
case 6*2:
case 10*2:
case 12*2:
case 16*2:
break;
default:
printf("CDB must be 6, 10, 12, or 16 bytes (12, 20, 24, or 32 characters)\n");
return 0;
}
for (i = 0; i < n; i++)
{
j = cdb[i];
if (isdigit(j))
{
cdb[i] = j - '0';
}
else if (isxdigit(j))
{
cdb[i] = tolower(j) - 'a' + 10;
}
else
{
printf("invalid hex digit %c at offset %d\n", j, i);
return 0;
}
}
printf("\nEnter input data length in bytes: [0-1024 or RETURN to quit] ");
len_in = getNumberAnswer(0, 1024, -1);
if (len_in < 0)
return 0;
if (len_in)
len_out = 0;
else
{
printf("Enter output data length in bytes: [0-1024 or RETURN to quit] ");
len_out = getNumberAnswer(0, 1024, -1);
if (len_out < 0)
return 0;
}
t = tagType;
if (len_in)
t |= MPI_SCSIIO_CONTROL_READ;
if (len_out)
t |= MPI_SCSIIO_CONTROL_WRITE;
memset(&req1, 0, sizeof req1);
memset(&rep1, 0, sizeof rep1);
req1.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req1.AliasIndex = virtInit;
req1.LUN[1] = lun;
req1.Control = set32(t);
req1.DataLength = set32(len_in + len_out);
for (i = 0, j = 0; j < n; i++, j += 2)
req1.CDB[i] = (cdb[j] << 4) + cdb[j+1];
req1.CDBLength = i;
setName(port, bus, target, &req1);
if (mpi20)
{
memset(&req2, 0, sizeof req2);
memset(&rep2, 0, sizeof rep2);
// convert from MPI 1.x format to MPI 2.x format
req2.Function = req1.Function;
req2.DevHandle = ((pMpi2SCSIIORequest_t)&req1)->DevHandle;
req2.Control = req1.Control;
req2.IoFlags = set16(req1.CDBLength);
req2.DataLength = req1.DataLength;
memcpy(req2.LUN, req1.LUN, sizeof req1.LUN);
memcpy(req2.CDB.CDB32, req1.CDB, sizeof req1.CDB);
req2.SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
req = &req2;
req_size = sizeof req2 - sizeof req2.SGL;
rep = &rep2;
rep_size = sizeof rep2;
}
else if (mpi25)
{
memset(&req25, 0, sizeof req25);
memset(&rep2, 0, sizeof rep2);
// convert from MPI 1.x format to MPI 2.5 format
req25.Function = req1.Function;
req25.DevHandle = ((pMpi25SCSIIORequest_t)&req1)->DevHandle;
req25.Control = req1.Control;
req25.IoFlags = set16(req1.CDBLength);
req25.DataLength = req1.DataLength;
memcpy(req25.LUN, req1.LUN, sizeof req1.LUN);
memcpy(req25.CDB.CDB32, req1.CDB, sizeof req1.CDB);
req25.SGLOffset0 = offsetof(Mpi25SCSIIORequest_t, SGL) / 4;
req = &req25;
req_size = sizeof req25 - sizeof req25.SGL;
rep = &rep2;
rep_size = sizeof rep2;
}
else
{
req = &req1;
req_size = sizeof req1 - sizeof req1.SGL;
rep = &rep1;
rep_size = sizeof rep1;
}
memset(buf_out, 0, sizeof buf_out);
if (len_out)
{
while (TRUE)
{
for (i = 0; i < len_out; i++)
{
if ((i % 16) == 0)
printf("\n%3d : ", i);
printf("%02x ", buf_out[i]);
}
printf("\n");
printf("\nEnter byte to change: [0-%d or RETURN to quit] ", len_out - 1);
i = getNumberAnswer(0, len_out - 1, -1);
if (i < 0)
break;
printf("Enter value: [00-FF or RETURN to not change] ");
value = getNumberAnswerHex(0x00, 0xff, -1);
if (value < 0)
continue;
buf_out[i] = (unsigned char)value;
}
}
memset(buf_in, 0, sizeof buf_in);
if (doMptCommand(port, req, req_size, rep, rep_size,
buf_in, len_in, buf_out, len_out, SHORT_TIME) == 1)
{
if (mpi2)
{
memcpy(&rep1.reply, &rep2.reply, sizeof rep1.reply);
memcpy(&rep1.sense, &rep2.sense, sizeof rep1.sense);
}
printf("\n");
ioc_status = get16(rep1.reply.IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status != MPI_IOCSTATUS_SUCCESS)
{
printf("IOCStatus = %04x (%s)\n", ioc_status, translateIocStatus(ioc_status));
}
t = rep1.reply.SCSIStatus;
if (t != MPI_SCSI_STATUS_SUCCESS)
{
if (t == MPI_SCSI_STATUS_CHECK_CONDITION)
{
printf("Check Condition, Key = %d, ASC/ASCQ = %02Xh/%02Xh\n",
rep1.sense[2] & 0x0f, rep1.sense[12], rep1.sense[13]);
t = get32(rep1.reply.SenseCount);
printf("%d bytes of Sense Data returned\n", t);
printf("\n");
for (i = 0, j = 0; i < t; i++, j++)
{
if (j == 0)
printf("%3d : ", i);
printf("%02x ", rep1.sense[i]);
if (!isprint(rep1.sense[i]))
c[j] = ' ';
else
c[j] = rep1.sense[i];
if (j == sizeof c - 2)
{
c[j+1] = 0;
printf(" %s\n", c);
j = -1;
}
}
if (j != 0)
{
c[j] = 0;
for (i = j; i < sizeof c - 1; i++)
printf(" ");
printf(" %s\n", c);
}
}
else
printf("SCSIStatus = %02x\n", t);
printf("\n");
}
if (ioc_status == MPI_IOCSTATUS_SUCCESS && rep1.reply.SCSIStatus == MPI_SCSI_STATUS_SUCCESS)
t = len_in + len_out;
else
t = get32(rep1.reply.TransferCount);
printf("%d bytes of data transferred\n", t);
if (len_in && t)
{
printf("\n");
for (i = 0, j = 0; i < t; i++, j++)
{
if (j == 0)
printf("%3d : ", i);
printf("%02x ", buf_in[i]);
if (!isprint(buf_in[i]))
c[j] = ' ';
else
c[j] = buf_in[i];
if (j == sizeof c - 2)
{
c[j+1] = 0;
printf(" %s\n", c);
j = -1;
}
}
if (j != 0)
{
c[j] = 0;
for (i = j; i < sizeof c - 1; i++)
printf(" ");
printf(" %s\n", c);
}
}
}
return 1;
}
int
doSataPassthroughSend(MPT_PORT *port)
{
SataPassthroughRequest_t req;
SataPassthroughReply_t rep;
int bus;
int target;
int feature;
int count;
int lbah;
int lbam;
int lbal;
int device;
int command;
unsigned short buf_out[512];
unsigned char buf_in[1024];
int len_out;
int len_in;
int value;
int i;
int j;
int t;
int ioc_status;
char c[21];
if (bringOnline(port) != 1)
return 0;
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 1;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 1;
printf("\n");
if (!isSata(port, bus, target))
{
printf("Can't do SATA Request Send, device is not SATA!\n");
return 1;
}
printf("ATA Word 00 Feature: [0000-FFFF or RETURN to quit] ");
feature = getNumberAnswerHex(0x0000, 0xffff, -1);
if (feature < 0)
return 0;
printf("ATA Word 01 Count: [0000-FFFF or RETURN to quit] ");
count = getNumberAnswerHex(0x0000, 0xffff, -1);
if (count < 0)
return 0;
printf("ATA Word 02 LBA H: [0000-FFFF or RETURN to quit] ");
lbah = getNumberAnswerHex(0x0000, 0xffff, -1);
if (lbah < 0)
return 0;
printf("ATA Word 03 LBA M: [0000-FFFF or RETURN to quit] ");
lbam = getNumberAnswerHex(0x0000, 0xffff, -1);
if (lbam < 0)
return 0;
printf("ATA Word 04 LBA L: [0000-FFFF or RETURN to quit] ");
lbal = getNumberAnswerHex(0x0000, 0xffff, -1);
if (lbal < 0)
return 0;
printf("ATA Word 05 Device: [00-FF or RETURN to quit] ");
device = getNumberAnswerHex(0x0000, 0xffff, -1);
if (device < 0)
return 0;
printf("ATA Word 05 Command: [00-FF or RETURN to quit] ");
command = getNumberAnswerHex(0x0000, 0xffff, -1);
if (command < 0)
return 0;
printf("\nEnter input data length in words: [0-512 or RETURN to quit] ");
len_in = getNumberAnswer(0, 512, -1);
if (len_in < 0)
return 0;
if (len_in)
len_out = 0;
else
{
printf("Enter output data length in words: [0-512 or RETURN to quit] ");
len_out = getNumberAnswer(0, 512, -1);
if (len_out < 0)
return 0;
}
t = 0;
if (len_in)
t |= MPI_SATA_PT_REQ_PT_FLAGS_PIO | MPI_SATA_PT_REQ_PT_FLAGS_READ;
if (len_out)
t |= MPI_SATA_PT_REQ_PT_FLAGS_PIO | MPI_SATA_PT_REQ_PT_FLAGS_WRITE;
printf("SATA PassThrough Flags: [0000-FFFF, default is %04x] ", t);
t = getNumberAnswerHex(0x0000, 0xffff, t);
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SATA_PASSTHROUGH;
req.PassthroughFlags = set16(t);
req.DataLength = set32((len_in + len_out) * 2);
req.CommandFIS[0] = 0x27;
req.CommandFIS[1] = 0x80;
req.CommandFIS[2] = (U8)command;
req.CommandFIS[3] = (U8)feature;
req.CommandFIS[4] = (U8)lbal;
req.CommandFIS[5] = (U8)lbam;
req.CommandFIS[6] = (U8)lbah;
req.CommandFIS[7] = (U8)device;
req.CommandFIS[8] = (U8)(lbal >> 8);
req.CommandFIS[9] = (U8)(lbam >> 8);
req.CommandFIS[10] = (U8)(lbah >> 8);
req.CommandFIS[11] = (U8)(feature >> 8);
req.CommandFIS[12] = (U8)count;
req.CommandFIS[13] = (U8)(count >> 8);
setName(port, bus, target, &req);
memset(buf_out, 0, sizeof buf_out);
if (len_out)
{
while (TRUE)
{
for (i = 0; i < len_out; i++)
{
if ((i % 10) == 0)
printf("\n%3d : ", i / 2);
printf("%04x ", get16x(buf_out[i]));
}
printf("\n");
printf("\nEnter word to change: [0-%d or RETURN to quit] ", len_out - 1);
i = getNumberAnswer(0, len_out - 1, -1);
if (i < 0)
break;
printf("Enter value: [0000-FFFF or RETURN to not change] ");
value = getNumberAnswerHex(0x0000, 0xffff, -1);
if (value < 0)
continue;
buf_out[i] = (unsigned short)set16x(value);
}
}
memset(buf_in, 0, sizeof buf_in);
if (doMptCommand(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
buf_in, len_in * 2, buf_out, len_out * 2, SHORT_TIME) == 1)
{
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status != MPI_IOCSTATUS_SUCCESS)
{
printf("\nSATAPassthrough failed, IOCStatus = %04x (%s)\n", ioc_status, translateIocStatus(ioc_status));
dumpMemory(&req, sizeof req - sizeof req.SGL, "MPT Request");
dumpMemory(&rep, sizeof rep, "MPT Reply");
return 0;
}
printf("\n");
t = get32(rep.StatusControlRegisters);
if (t)
{
printf("StatusControlRegisters = %04x\n\n", t);
}
t = 0;
for (i = 0; i < sizeof rep.StatusFIS; i++)
t += rep.StatusFIS[i];
if (t)
{
printf("ATA Word 00 Error: 00%02x\n", rep.StatusFIS[3]);
printf("ATA Word 01 Count: %02x%02x\n", rep.StatusFIS[13], rep.StatusFIS[12]);
printf("ATA Word 02 LBA H: %02x%02x\n", rep.StatusFIS[10], rep.StatusFIS[6]);
printf("ATA Word 03 LBA M: %02x%02x\n", rep.StatusFIS[9], rep.StatusFIS[5]);
printf("ATA Word 04 LBA L: %02x%02x\n", rep.StatusFIS[8], rep.StatusFIS[4]);
printf("ATA Word 05 Device: %02x \n", rep.StatusFIS[7]);
printf("ATA Word 05 Status: %02x\n\n", rep.StatusFIS[2]);
}
t = get32(rep.TransferCount);
printf("%d words of data transferred\n", t / 2);
if (len_in)
{
printf("\n");
for (i = 0, j = 0; i < t; i++, j++)
{
if (j == 0)
printf("%3d : ", i / 2);
if (i & 1)
printf("%02x ", buf_in[i^1]);
else
printf("%02x", buf_in[i^1]);
if (!isprint(buf_in[i^1]))
c[j] = ' ';
else
c[j] = buf_in[i^1];
if (j == sizeof c - 2)
{
c[j+1] = 0;
printf(" %s\n", c);
j = -1;
}
}
if (j != 0)
{
c[j] = 0;
for (i = j; i < sizeof c - 1; i++)
if (i & 1)
printf(" ");
else
printf(" ");
printf(" %s\n", c);
}
}
}
return 1;
}
int
doSmpPassthroughSend(MPT_PORT *port)
{
SmpPassthroughRequest_t req;
SmpPassthroughReply_t rep;
SasExpanderPage0_t SASExpanderPage0;
unsigned char buf_out[1032];
unsigned char buf_in[1032];
int smp;
int handle;
int len;
int value;
int i;
int j;
int t;
int ioc_status;
U32 result;
U32 wwid_l;
U32 wwid_h;
_U64 sas_address;
U8 physical_port;
if (bringOnline(port) != 1)
return 0;
printf("Enter SMP function code: [00-FF or RETURN to quit] ");
smp = getNumberAnswerHex(0x00, 0xff, -1);
if (smp < 0)
return 0;
printf("Enter handle: [0000-FFFF or RETURN to quit] ");
handle = getNumberAnswerHex(0x0000, 0xffff, -1);
if (handle < 0)
return 0;
if (handle == 0)
{
printf("Enter SASAddress: [16 hex digits or RETURN to quit] ");
t = getHexDoubleNumberAnswer(&wwid_h, &wwid_l);
if (t == 0)
return 0;
printf("Enter port: [0 to %d or RETURN to leave unspecified] ", port->numPhys - 1);
physical_port = (U8)getNumberAnswer(0, port->numPhys - 1, 255);
sas_address.Low = set32(wwid_l);
sas_address.High = set32(wwid_h);
}
else
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0,
(MPI_SAS_EXPAND_PGAD_FORM_HANDLE
<<MPI_SAS_EXPAND_PGAD_FORM_SHIFT) + handle,
&SASExpanderPage0, sizeof SASExpanderPage0) != 1)
{
printf("\nInvalid handle, not an expander!\n");
return 0;
}
physical_port = SASExpanderPage0.PhysicalPort;
sas_address = SASExpanderPage0.SASAddress;
}
printf("Enter frame length in bytes: [8-1032 or RETURN to quit] ");
len = getNumberAnswer(8, 1032, -1);
if (len < 0)
return 0;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SMP_PASSTHROUGH;
req.PhysicalPort = physical_port;
req.RequestDataLength = set16(len - 4);
req.SASAddress = sas_address;
memset(buf_out, 0, sizeof buf_out);
buf_out[0] = 0x40;
buf_out[1] = (unsigned char)smp;
if (len > 1)
{
while (TRUE)
{
printf("\n");
for (i = 0; i < len; i++)
printf("Byte %04d = %02x\n", i, buf_out[i]);
printf("\nEnter byte to change: [2-%d or RETURN to quit] ", len - 5);
i = getNumberAnswer(2, len - 5, -1);
if (i < 0)
break;
printf("Enter value: [00-FF or RETURN to not change] ");
value = getNumberAnswerHex(0x00, 0xff, -1);
if (value < 0)
continue;
buf_out[i] = (unsigned char)value;
}
}
printf("\n");
memset(buf_in, 0, sizeof buf_in);
if (doMptCommand(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
buf_in, sizeof buf_in - 4, buf_out, len - 4, SHORT_TIME) == 1)
{
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status != MPI_IOCSTATUS_SUCCESS)
{
printf("SMPPassthrough failed, IOCStatus = %04x (%s), SASStatus = %02x, IOCLogInfo = %08x\n",
ioc_status, translateIocStatus(ioc_status), rep.SASStatus, get32(rep.IOCLogInfo));
return 0;
}
result = buf_in[2];
if (result != 0x00)
{
printf("SMP request not accepted, result is %02x (%s)\n", result, translateSmpFunctionResult(result));
return 0;
}
len = get16(rep.ResponseDataLength) + 4;
/* zero anything that might be in the CRC bytes as the real CRC is not passed back */
memset(buf_in + len - 4, 0, 4);
printf("SMP request was accepted, and returned %d response bytes\n\n", len);
for (i = 0, j = 0; i < len; i++, j++)
{
if (j == 0)
printf("%04x : ", i);
printf("%02x ", buf_in[i]);
if (j == 15)
{
printf("\n");
j = -1;
}
}
if (j != 0)
{
printf("\n");
}
}
return 1;
}
int
doResetSasLink(MPT_PORT *port, int flag)
{
SasDevicePage0_t SASDevicePage0;
SasExpanderPage0_t SASExpanderPage0;
SasIoUnitControlRequest_t req;
SasIoUnitControlReply_t rep;
int handle;
int phy;
int min_phy;
int max_phy;
int dev_info;
int dev_type;
unsigned char phy_control_req[40];
unsigned char phy_control_rsp[4];
printf("Enter handle: [0000-FFFF or RETURN to quit] ");
handle = getNumberAnswerHex(0x0000, 0xffff, -1);
if (handle < 0)
return 0;
if (handle == 0)
{
min_phy = 0;
max_phy = port->numPhys - 1;
}
else
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0,
(MPI_SAS_DEVICE_PGAD_FORM_HANDLE
<<MPI_SAS_DEVICE_PGAD_FORM_SHIFT) + handle,
&SASDevicePage0, sizeof SASDevicePage0) != 1)
{
printf("\nInvalid handle!\n");
return 0;
}
dev_info = get32(SASDevicePage0.DeviceInfo);
dev_type = dev_info & MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE;
if (SASDevicePage0.ParentDevHandle == 0)
{
min_phy = handle - 1;
max_phy = handle - 1;
}
else if (dev_type == MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
dev_type == MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0,
(MPI_SAS_EXPAND_PGAD_FORM_HANDLE
<<MPI_SAS_EXPAND_PGAD_FORM_SHIFT) + handle,
&SASExpanderPage0, sizeof SASExpanderPage0) != 1)
{
return 0;
}
min_phy = 0;
max_phy = SASExpanderPage0.NumPhys - 1;
}
else if (dev_type == MPI_SAS_DEVICE_INFO_END_DEVICE)
{
min_phy = SASDevicePage0.PhyNum;
max_phy = SASDevicePage0.PhyNum;
handle = get16(SASDevicePage0.ParentDevHandle);
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0,
(MPI_SAS_DEVICE_PGAD_FORM_HANDLE
<<MPI_SAS_DEVICE_PGAD_FORM_SHIFT) + handle,
&SASDevicePage0, sizeof SASDevicePage0) != 1)
{
return 0;
}
if (SASDevicePage0.ParentDevHandle != 0)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0,
(MPI_SAS_EXPAND_PGAD_FORM_HANDLE
<<MPI_SAS_EXPAND_PGAD_FORM_SHIFT) + handle,
&SASExpanderPage0, sizeof SASExpanderPage0) != 1)
{
return 0;
}
}
}
else
{
return 0;
}
}
if (min_phy != max_phy || gFlag == TRUE)
{
printf("Enter phy: [%d-%d or RETURN to quit] ", min_phy, max_phy);
phy = getNumberAnswer(min_phy, max_phy, -1);
if (phy < 0)
return 0;
}
else
{
phy = min_phy;
}
printf("\nResetting SAS link%s...\n", flag ? ", HARD RESET" : "");
if (handle == 0 || SASDevicePage0.ParentDevHandle == 0)
{
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
req.Operation = flag ? MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
req.PhyNum = phy;
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
else
{
memset(phy_control_req, 0, sizeof phy_control_req);
phy_control_req[0] = 0x40;
phy_control_req[1] = 0x91;
phy_control_req[2] = 0xff;
phy_control_req[9] = phy;
phy_control_req[10] = flag ? 0x02 : 0x01;
if (doSmpPassthrough(port, SASExpanderPage0.PhysicalPort, SASExpanderPage0.SASAddress,
phy_control_req, sizeof phy_control_req,
phy_control_rsp, sizeof phy_control_rsp, NULL) == 1)
{
if (phy_control_rsp[2] != 0)
{
printf("%s Reset failed with result %02x\n",
flag ? "Hard" : "Link", phy_control_rsp[2]);
return 0;
}
return 1;
}
else
{
printf("%s Reset failed\n", flag ? "Hard" : "Link");
return 0;
}
}
}
int
doDumpPortState(MPT_PORT *port, int flag)
{
U32 *buf;
U32 *temp_buf;
IOCPage2_t *IOCPage2;
char name[32];
int len;
int i;
int j;
int n;
int b;
int t;
U8 numInterfaces;
len = 255 * 4;
buf = malloc(len);
temp_buf = malloc(len);
if (flag)
doIdentify(port);
if (mpi2)
{
if (getIocFacts2(port, (pMpi2IOCFactsReply_t)buf) == 1)
dumpMemory(buf, ((pMpi2IOCFactsReply_t)buf)->MsgLength * 4, "IOCFactsReply");
if (getPortFacts2(port, (pMpi2PortFactsReply_t)buf) == 1)
dumpMemory(buf, ((pMpi2PortFactsReply_t)buf)->MsgLength * 4, "PortFactsReply");
}
else
{
if (getIocFacts(port, (pIOCFactsReply_t)buf) == 1)
dumpMemory(buf, ((pIOCFactsReply_t)buf)->MsgLength * 4, "IOCFactsReply");
if (getPortFacts(port, (pPortFactsReply_t)buf) == 1)
dumpMemory(buf, ((pPortFactsReply_t)buf)->MsgLength * 4, "PortFactsReply");
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage0", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 1, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage1", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 2, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage2", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 3, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage3", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 4, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage4", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 5, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage5", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 6, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage6", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 7, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage7", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 8, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage8", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 9, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage9", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 10, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage10", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 11, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage11", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 12, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage12", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 13, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage13", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 14, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage14", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 15, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage15", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 16, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage16", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 241, 0, buf, len) == 1)
{
showConfigPage(port, "ManufacturingPage241", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IO_UNIT, 0, 0, buf, len) == 1)
{
showConfigPage(port, "IOUnitPage0", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IO_UNIT, 1, 0, buf, len) == 1)
{
showConfigPage(port, "IOUnitPage1", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IO_UNIT, 2, 0, buf, len) == 1)
{
showConfigPage(port, "IOUnitPage2", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IO_UNIT, 3, 0, buf, len) == 1)
{
showConfigPage(port, "IOUnitPage3", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IO_UNIT, 4, 0, buf, len) == 1)
{
showConfigPage(port, "IOUnitPage4", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IO_UNIT, 5, 0, buf, len) == 1)
{
showConfigPage(port, "IOUnitPage5", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IO_UNIT, 6, 0, buf, len) == 1)
{
showConfigPage(port, "IOUnitPage6", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IO_UNIT, 7, 0, buf, len) == 1)
{
showConfigPage(port, "IOUnitPage7", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 0, 0, buf, len) == 1)
{
showConfigPage(port, "IOCPage0", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 1, 0, buf, len) == 1)
{
showConfigPage(port, "IOCPage1", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 2, 0, buf, len) == 1)
{
showConfigPage(port, "IOCPage2", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 3, 0, buf, len) == 1)
{
showConfigPage(port, "IOCPage3", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 4, 0, buf, len) == 1)
{
showConfigPage(port, "IOCPage4", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 5, 0, buf, len) == 1)
{
showConfigPage(port, "IOCPage5", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 6, 0, buf, len) == 1)
{
showConfigPage(port, "IOCPage6", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 7, 0, buf, len) == 1)
{
showConfigPage(port, "IOCPage7", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 8, 0, buf, len) == 1)
{
showConfigPage(port, "IOCPage8", buf, len);
}
if (port->mptVersion >= MPI_VERSION_01_02)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_BIOS, 1, 0, buf, len) == 1)
{
showConfigPage(port, "BIOSPage1", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_BIOS, 2, 0, buf, len) == 1)
{
showConfigPage(port, "BIOSPage2", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_BIOS, 3, 0, buf, len) == 1)
{
showConfigPage(port, "BIOSPage3", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_BIOS, 4, 0, buf, len) == 1)
{
showConfigPage(port, "BIOSPage4", buf, len);
}
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SCSI)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_SCSI_PORT, 0, 0, buf, len) == 1)
{
showConfigPage(port, "SCSIPortPage0", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_SCSI_PORT, 1, 0, buf, len) == 1)
{
showConfigPage(port, "SCSIPortPage1", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, 0, buf, len) == 1)
{
showConfigPage(port, "SCSIPortPage2", buf, len);
}
for (i = 0; i < 16; i++)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 0, i, buf, len) == 1)
{
sprintf(name, "SCSIDevicePage0 / %d", i);
showConfigPage(port, name, buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 1, i, buf, len) == 1)
{
sprintf(name, "SCSIDevicePage1 / %d", i);
showConfigPage(port, name, buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 2, i, buf, len) == 1)
{
sprintf(name, "SCSIDevicePage2 / %d", i);
showConfigPage(port, name, buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 3, i, buf, len) == 1)
{
sprintf(name, "SCSIDevicePage3 / %d", i);
showConfigPage(port, name, buf, len);
}
}
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 0, 0, buf, len) == 1)
{
showConfigPage(port, "FCPortPage0", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0, buf, len) == 1)
{
showConfigPage(port, "FCPortPage1", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 2, 0, buf, len) == 1)
{
showConfigPage(port, "FCPortPage2", buf, len);
}
if (port->maxPersistentIds * (int)sizeof(PersistentData_t) + (int)sizeof(ConfigPageHeader_t) > len)
{
for (i = 0; i < port->maxPersistentIds; i++)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 3,
MPI_FC_PORT_PGAD_FORM_INDEX + i, buf, len) == 1)
{
if (get16(((pFCPortPage3_t)buf)->Entry->Flags) & MPI_PERSISTENT_FLAGS_ENTRY_VALID)
{
sprintf(name, "FCPortPage3 / %d", i);
showConfigPage(port, name, buf, len);
}
}
}
}
else
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 3, 0, buf, len) == 1)
{
showConfigPage(port, "FCPortPage3", buf, len);
}
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 4, 0, buf, len) == 1)
{
showConfigPage(port, "FCPortPage4", buf, len);
}
for (i = 1; i <= 255; i++)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 5,
MPI_FC_PORT_PGAD_FORM_INDEX + i, buf, len) == 1)
{
if (((pFCPortPage5_t)buf)->AliasInfo.Flags != 0)
{
sprintf(name, "FCPortPage5 / %d", i);
showConfigPage(port, name, buf, len);
}
}
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 6, 0, buf, len) == 1)
{
showConfigPage(port, "FCPortPage6", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 7, 0, buf, len) == 1)
{
showConfigPage(port, "FCPortPage7", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 8, 0, buf, len) == 1)
{
showConfigPage(port, "FCPortPage8", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 9, 0, buf, len) == 1)
{
showConfigPage(port, "FCPortPage9", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 10, 0, buf, len) == 1)
{
showConfigPage(port, "FCPortPage10", buf, len);
}
i = 0xffffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_DEVICE, 0, i, buf, len) == 1)
{
i = get32(((pFCDevicePage0_t)buf)->PortIdentifier);
sprintf(name, "FCDevicePage0 / %06x", i);
showConfigPage(port, name, buf, len);
}
else
break;
}
}
if (mpi1 && getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 2, 0, temp_buf, len) == 1)
{
IOCPage2 = (pIOCPage2_t)temp_buf;
for (i = 0; i < IOCPage2->MaxVolumes; i++)
{
b = IOCPage2->RaidVolume[i].VolumeBus;
t = IOCPage2->RaidVolume[i].VolumeID;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_RAID_VOLUME, 0, (b << 8) + t, buf, len) == 1)
{
sprintf(name, "RAIDVolumePage0 / %d,%d", b, t);
showConfigPage(port, name, buf, len);
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_RAID_VOLUME, 1, i, buf, len) == 1)
{
sprintf(name, "RAIDVolumePage1 / %d,%d", b, t);
showConfigPage(port, name, buf, len);
}
}
}
for (i = 0; i < IOCPage2->MaxPhysDisks; i++)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_RAID_PHYSDISK, 0, i, buf, len) == 1)
{
sprintf(name, "RAIDPhysDiskPage0 / %d", i);
showConfigPage(port, name, buf, len);
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_RAID_PHYSDISK, 1, i, buf, len) == 1)
{
sprintf(name, "RAIDPhysDiskPage1 / %d", i);
showConfigPage(port, name, buf, len);
}
}
}
}
if (mpi2 && port->capabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)
{
i = 0xffff;
while (TRUE)
{
if (getConfigPage(port, MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 0,
MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE + i, buf, len) == 1)
{
i = get16(((pMpi2RaidVolPage0_t)buf)->DevHandle);
sprintf(name, "RAIDVolumePage0 / %04x", i);
showConfigPage(port, name, buf, len);
}
else
break;
}
i = 0xff;
while (TRUE)
{
if (getConfigPage(port, MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK, 0,
MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM + i, buf, len) == 1)
{
i = ((pMpi2RaidPhysDiskPage0_t)buf)->PhysDiskNum;
sprintf(name, "RAIDPhysDiskPage0 / %d", i);
showConfigPage(port, name, buf, len);
}
else
break;
}
i = 0xffff;
while (TRUE)
{
if (getConfigPage(port, MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG, 0,
MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM + i, buf, len) == 1)
{
i = ((pMpi2RaidConfigurationPage0_t)buf)->ConfigNum;
sprintf(name, "RAIDConfigurationPage0 / %d", i);
showConfigPage(port, name, buf, len);
}
else
break;
}
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_LAN, 0, 0, buf, len) == 1)
{
showConfigPage(port, "LANPage0", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_LAN, 1, 0, buf, len) == 1)
{
showConfigPage(port, "LANPage1", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_INBAND, 0, 0, buf, len) == 1)
{
showConfigPage(port, "InbandPage0", buf, len);
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0, buf, len) == 1)
{
showConfigPage(port, "SASIOUnitPage0", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0, buf, len) == 1)
{
showConfigPage(port, "SASIOUnitPage1", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 2, 0, buf, len) == 1)
{
showConfigPage(port, "SASIOUnitPage2", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 3, 0, buf, len) == 1)
{
showConfigPage(port, "SASIOUnitPage3", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 4, 0, buf, len) == 1)
{
showConfigPage(port, "SASIOUnitPage4", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 5, 0, buf, len) == 1)
{
showConfigPage(port, "SASIOUnitPage5", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 6, 0, buf, len) == 1)
{
showConfigPage(port, "SASIOUnitPage6", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 7, 0, buf, len) == 1)
{
showConfigPage(port, "SASIOUnitPage7", buf, len);
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 8, 0, buf, len) == 1)
{
showConfigPage(port, "SASIOUnitPage8", buf, len);
}
i = 0xffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, i, buf, len) == 1)
{
i = get16(((pSasExpanderPage0_t)buf)->DevHandle);
sprintf(name, "SASExpanderPage0 / %04x", i);
showConfigPage(port, name, buf, len);
n = ((pSasExpanderPage0_t)buf)->NumPhys;
for (j = 0; j < n; j++)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 1,
(MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM
<<MPI_SAS_EXPAND_PGAD_FORM_SHIFT) +
(j << MPI_SAS_EXPAND_PGAD_HPN_SHIFT_PHY) + i,
buf, len) == 1)
{
sprintf(name, "SASExpanderPage1 / %04x / %d", i, j);
showConfigPage(port, name, buf, len);
}
}
}
else
break;
}
if (mpi2)
{
i = 0xfff;
while (TRUE)
{
if (getConfigPage(port, MPI2_CONFIG_EXTPAGETYPE_SAS_PORT, 0, i, buf, len) == 1)
{
i = ((pMpi2SasPortPage0_t)buf)->PortNumber;
sprintf(name, "SASPortPage0 / %02x", i);
showConfigPage(port, name, buf, len);
}
else
break;
}
}
i = 0xffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, i, buf, len) == 1)
{
i = get16(((pSasDevicePage0_t)buf)->DevHandle);
sprintf(name, "SASDevicePage0 / %04x", i);
showConfigPage(port, name, buf, len);
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 1,
(MPI_SAS_DEVICE_PGAD_FORM_HANDLE
<<MPI_SAS_DEVICE_PGAD_FORM_SHIFT) + i, buf, len) == 1)
{
sprintf(name, "SASDevicePage1 / %04x", i);
showConfigPage(port, name, buf, len);
}
}
else
break;
}
if (mpi1)
{
for (i = 0; i < (port->maxBuses << 8) + port->maxTargets; i++)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 2,
(MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
<<MPI_SAS_DEVICE_PGAD_FORM_SHIFT) + i,
buf, len) == 1)
{
if (((pSasDevicePage2_t)buf)->PhysicalIdentifier.High != 0 ||
((pSasDevicePage2_t)buf)->PhysicalIdentifier.Low != 0)
{
sprintf(name, "SASDevicePage2 / %d,%d", i >> 8, i & 255);
showConfigPage(port, name, buf, len);
}
}
}
}
for (i = 0; i < 256; i++)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, 0, i, buf, len) == 1)
{
sprintf(name, "SASPhyPage0 / %02x", i);
showConfigPage(port, name, buf, len);
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, 1, i, buf, len) == 1)
{
sprintf(name, "SASPhyPage1 / %02x", i);
showConfigPage(port, name, buf, len);
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, 2, i, buf, len) == 1)
{
sprintf(name, "SASPhyPage2 / %02x", i);
showConfigPage(port, name, buf, len);
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, 3, i, buf, len) == 1)
{
sprintf(name, "SASPhyPage3 / %02x", i);
showConfigPage(port, name, buf, len);
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_PHY, 4, i, buf, len) == 1)
{
sprintf(name, "SASPhyPage4 / %02x", i);
showConfigPage(port, name, buf, len);
}
}
else
break;
}
i = 0xffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_ENCLOSURE, 0, i, buf, len) == 1)
{
i = get16(((pSasEnclosurePage0_t)buf)->EnclosureHandle);
sprintf(name, "SASEnclosurePage0 / %04x", i);
showConfigPage(port, name, buf, len);
}
else
break;
}
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_LOG, 0, 0, buf, len) == 1)
{
showConfigPage(port, "LogPage0", buf, len);
}
if (mpi2)
{
for (i = 0; i < port->maxPersistentIds; i++)
{
if (getConfigPage(port, MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING, 0,
(1<<MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT) + i, buf, len) == 1)
{
if (((pMpi2DriverMappingPage0_t)buf)->Entry.PhysicalIdentifier.High != 0 ||
((pMpi2DriverMappingPage0_t)buf)->Entry.PhysicalIdentifier.Low != 0)
{
sprintf(name, "DriverMappingPage0 / %04x", i);
showConfigPage(port, name, buf, len);
}
}
}
}
if (mpi2)
{
if (getConfigPage(port, MPI2_CONFIG_EXTPAGETYPE_ETHERNET, 0, 0, buf, len) == 1)
{
numInterfaces = ((pMpi2EthernetPage0_t)buf)->NumInterfaces;
for (i = 0; i < numInterfaces; i++)
{
if (getConfigPage(port, MPI2_CONFIG_EXTPAGETYPE_ETHERNET, 0, i, buf, len) == 1)
{
sprintf(name, "EthernetPage0 / %02x", i);
showConfigPage(port, name, buf, len);
}
if (getConfigPage(port, MPI2_CONFIG_EXTPAGETYPE_ETHERNET, 1, i, buf, len) == 1)
{
sprintf(name, "EthernetPage1 / %02x", i);
showConfigPage(port, name, buf, len);
}
}
}
}
free(buf);
free(temp_buf);
return 1;
}
int
doPortStateSummary(MPT_PORT *port)
{
char *temp;
FCPortPage0_t FCPortPage0;
FCPortPage1_t FCPortPage1;
int flags;
int t;
IOCPage1_t IOCPage1;
int timeout;
int depth;
int on;
IOUnitPage1_t IOUnitPage1;
SCSIPortPage2_t SCSIPortPage2;
int settings;
int id;
SasIOUnitPage0_t SASIOUnitPage0;
SasIOUnitPage1_t *SASIOUnitPage1;
Mpi2SasIOUnitPage1_t *SASIOUnitPage1_2;
SasIOUnitPage2_t SASIOUnitPage2;
int length;
int i;
ManufacturingPage5_t *ManufacturingPage5;
Mpi2ManufacturingPage5_t *ManufacturingPage5_2;
int num_phys;
printf("Current Port State\n------------------\n");
showPortInfoHeader(port);
printf("Software Version Information\n----------------------------\n");
doIdentify(port);
printf("\nFirmware Settings\n-----------------\n");
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 0, 0,
&FCPortPage0, sizeof FCPortPage0) != 1)
return 0;
printf("FC WWNN: %08x%08x\n",
get32(FCPortPage0.WWNN.High),
get32(FCPortPage0.WWNN.Low));
printf("FC WWPN: %08x%08x\n",
get32(FCPortPage0.WWPN.High),
get32(FCPortPage0.WWPN.Low));
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 1, 0,
&FCPortPage1, sizeof FCPortPage1) != 1)
return 0;
t = FCPortPage1.TopologyConfig & MPI_FCPORTPAGE1_TOPOLOGY_MASK;
switch (t)
{
case MPI_FCPORTPAGE1_TOPOLOGY_AUTO: temp = "Auto"; break;
case MPI_FCPORTPAGE1_TOPOLOGY_NLPORT: temp = "NL_Port"; break;
case MPI_FCPORTPAGE1_TOPOLOGY_NPORT: temp = "N_Port"; break;
default: temp = "Unknown"; break;
}
printf("Link Topology: %s\n", temp);
if (port->mptVersion < MPI_VERSION_01_01)
temp = "1 Gb";
else
{
t = FCPortPage1.LinkConfig & MPI_FCPORTPAGE1_LCONFIG_SPEED_MASK;
switch (t)
{
case MPI_FCPORTPAGE1_LCONFIG_SPEED_AUTO: temp = "Auto"; break;
case MPI_FCPORTPAGE1_LCONFIG_SPEED_1GIG: temp = "1 Gb"; break;
case MPI_FCPORTPAGE1_LCONFIG_SPEED_2GIG: temp = "2 Gb"; break;
case MPI_FCPORTPAGE1_LCONFIG_SPEED_4GIG: temp = "4 Gb"; break;
case MPI_FCPORTPAGE1_LCONFIG_SPEED_10GIG: temp = "10 Gb"; break;
default: temp = "Unknown"; break;
}
}
printf("Link Speed: %s\n", temp);
flags = get32(FCPortPage1.Flags);
t = (flags & MPI_FCPORTPAGE1_FLAGS_PROT_FCP_INIT) != 0;
printf("FCP Initiator protocol: %s\n", t == 0 ? "Disabled" : "Enabled");
t = (flags & MPI_FCPORTPAGE1_FLAGS_PROT_FCP_TARG) != 0;
printf("FCP Target protocol: %s\n", t == 0 ? "Disabled" : "Enabled");
t = (flags & MPI_FCPORTPAGE1_FLAGS_PROT_LAN) != 0;
printf("LAN protocol: %s\n", t == 0 ? "Disabled" : "Enabled");
t = (flags & MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID) != 0;
printf("Assignment of Bus/Target IDs: %s\n", t == 0 ? "SortByWWN" : "SortByDID");
t = (flags & MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY) != 0;
printf("Immediate Error Reply: %s\n", t == 0 ? "Disabled" : "Enabled");
t = (flags & MPI_FCPORTPAGE1_FLAGS_MAINTAIN_LOGINS) != 0;
printf("Maintain Logins: %s\n", t == 0 ? "Disabled" : "Enabled");
t = FCPortPage1.HardALPA;
printf("Hard AL_PA: %02x\n", t);
t = FCPortPage1.InitiatorDeviceTimeout;
if (t == 0)
t = 60;
printf("Initiator Device Timeout: %d\n", t);
t = FCPortPage1.InitiatorIoPendTimeout;
if (t == 0)
t = 8;
printf("Initiator I/O Pending Timeout: %d\n", t);
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IO_UNIT, 1, 0,
&IOUnitPage1, sizeof IOUnitPage1) != 1)
return 0;
flags = get32(IOUnitPage1.Flags);
t = (flags & MPI_IOUNITPAGE1_MULTI_PATHING) != 0;
printf("Multi-pathing: %s\n", t == 0 ? "Disabled" : "Enabled");
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SCSI)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_SCSI_PORT, 2, 0,
&SCSIPortPage2, sizeof SCSIPortPage2) != 1)
return 0;
flags = get32(SCSIPortPage2.PortFlags);
settings = get32(SCSIPortPage2.PortSettings);
id = settings & MPI_SCSIPORTPAGE2_PORT_HOST_ID_MASK;
printf("Host SCSI ID: %d\n", id);
t = (flags & MPI_SCSIPORTPAGE2_PORT_FLAGS_SCAN_HIGH_TO_LOW) != 0;
printf("Bus scan order: %s\n", t == 0 ? "LowToHigh" : "HighToLow");
t = (flags & MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) != 0;
printf("Avoid SCSI bus reset: %s\n", t == 0 ? "No" : "Yes");
t = (flags & MPI_SCSIPORTPAGE2_PORT_FLAGS_ALTERNATE_CHS) != 0;
printf("CHS mapping: %s\n", t == 0 ? "PlugAndPlay" : "AlternateCHS");
t = (settings & MPI_SCSIPORTPAGE2_PORT_REMOVABLE_MEDIA) >> 6;
switch (t)
{
case 0: temp = "None"; break;
case 1: temp = "BootDrive"; break;
case 2: temp = "AnyWithMedia"; break;
default: temp = "Unknown"; break;
}
printf("Removable media support: %s\n", temp);
t = (settings & MPI_SCSIPORTPAGE2_PORT_SPINUP_DELAY_MASK) >> 8;
printf("Spinup delay (in seconds): %d\n", t);
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
ManufacturingPage5 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 5, 0, &length);
if (ManufacturingPage5 == NULL)
return 0;
ManufacturingPage5_2 = (pMpi2ManufacturingPage5_t)ManufacturingPage5;
if (mpi2)
{
printf("SAS WWID: %08x%08x\n",
get32(ManufacturingPage5_2->Phy[0].WWID.High),
get32(ManufacturingPage5_2->Phy[0].WWID.Low));
}
else
{
printf("SAS WWID: %08x%08x\n",
get32(ManufacturingPage5->BaseWWID.High),
get32(ManufacturingPage5->BaseWWID.Low));
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IO_UNIT, 1, 0,
&IOUnitPage1, sizeof IOUnitPage1) != 1)
return 0;
flags = get32(IOUnitPage1.Flags);
t = (flags & MPI_IOUNITPAGE1_MULTI_PATHING) != 0;
printf("Multi-pathing: %s\n", t == 0 ? "Disabled" : "Enabled");
t = (flags & MPI_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE) == 0;
printf("SATA Native Command Queuing: %s\n", t == 0 ? "Disabled" : "Enabled");
t = (flags & MPI_IOUNITPAGE1_SATA_WRITE_CACHE_DISABLE) == 0;
printf("SATA Write Caching: %s\n", t == 0 ? "Disabled" : "Enabled");
SASIOUnitPage1 = getConfigPageAlloc(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0, &length);
if (SASIOUnitPage1 == NULL)
return 0;
if (getConfigPage(port, MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0,
&SASIOUnitPage0, sizeof SASIOUnitPage0) == 1)
num_phys = SASIOUnitPage0.NumPhys;
else
num_phys = SASIOUnitPage1->NumPhys;
t = SASIOUnitPage1->SATAMaxQDepth;
printf("SATA Maximum Queue Depth: %d\n", t);
if (mpi2)
{
SASIOUnitPage1_2 = (pMpi2SasIOUnitPage1_t)SASIOUnitPage1;
t = get16(SASIOUnitPage1_2->SASNarrowMaxQueueDepth);
printf("SAS Max Queue Depth, Narrow: %d\n", t);
t = get16(SASIOUnitPage1_2->SASWideMaxQueueDepth);
printf("SAS Max Queue Depth, Wide: %d\n", t);
}
t = SASIOUnitPage1->ReportDeviceMissingDelay;
if (t & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16)
t = (t & ~MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) * 16;
printf("Device Missing Report Delay: %d seconds\n", t);
t = SASIOUnitPage1->IODeviceMissingDelay;
printf("Device Missing I/O Delay: %d seconds\n", t);
printf("Phy Parameters for Phynum: ");
for (i = 0; i < num_phys; i++)
printf("%-5d", i);
printf("\n");
printf(" Link Enabled: ");
for (i = 0; i < num_phys; i++)
{
if (mpi2)
t = SASIOUnitPage1->PhyData[i].PhyFlags & MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
else
t = SASIOUnitPage1->PhyData[i].PhyFlags & MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE;
printf("%-5s", t ? "No" : "Yes");
}
printf("\n");
printf(" Link Min Rate: ");
for (i = 0; i < num_phys; i++)
{
t = SASIOUnitPage1->PhyData[i].MaxMinLinkRate & MPI_SAS_IOUNIT1_MIN_RATE_MASK;
printf("%-5s",
t == MPI25_SASIOUNIT1_MIN_RATE_12_0 ? "12.0" :
t == MPI2_SASIOUNIT1_MIN_RATE_6_0 ? "6.0" :
t == MPI_SAS_IOUNIT1_MIN_RATE_3_0 ? "3.0" : "1.5");
}
printf("\n");
printf(" Link Max Rate: ");
for (i = 0; i < num_phys; i++)
{
t = SASIOUnitPage1->PhyData[i].MaxMinLinkRate & MPI_SAS_IOUNIT1_MAX_RATE_MASK;
printf("%-5s",
t == MPI25_SASIOUNIT1_MAX_RATE_12_0 ? "12.0" :
t == MPI2_SASIOUNIT1_MAX_RATE_6_0 ? "6.0" :
t == MPI_SAS_IOUNIT1_MAX_RATE_3_0 ? "3.0" : "1.5");
}
printf("\n");
printf(" SSP Initiator Enabled: ");
for (i = 0; i < num_phys; i++)
{
t = get32(SASIOUnitPage1->PhyData[i].ControllerPhyDeviceInfo) & MPI_SAS_DEVICE_INFO_SSP_INITIATOR;
printf("%-5s", t ? "Yes" : "No");
}
printf("\n");
printf(" SSP Target Enabled: ");
for (i = 0; i < num_phys; i++)
{
t = get32(SASIOUnitPage1->PhyData[i].ControllerPhyDeviceInfo) & MPI_SAS_DEVICE_INFO_SSP_TARGET;
printf("%-5s", t ? "Yes" : "No");
}
printf("\n");
printf(" Port Configuration: ");
for (i = 0; i < num_phys; i++)
{
if (SASIOUnitPage1->PhyData[i].PortFlags & MPI_SAS_IOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG)
printf("%-5s", "Auto");
else
printf("%-5d", SASIOUnitPage1->PhyData[i].Port);
}
printf("\n");
free(SASIOUnitPage1);
if (mpi1)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 2, 0,
&SASIOUnitPage2, sizeof SASIOUnitPage2) != 1)
return 0;
flags = SASIOUnitPage2.Flags;
printf("Target IDs per enclosure: %d\n", SASIOUnitPage2.NumDevsPerEnclosure);
t = (flags & MPI_SAS_IOUNIT2_FLAGS_DISABLE_PERSISTENT_MAPPINGS) == 0;
printf("Persistent mapping: %s\n", t == 0 ? "Disabled" : "Enabled");
t = (flags & MPI_SAS_IOUNIT2_FLAGS_MASK_PHYS_MAP_MODE) >> MPI_SAS_IOUNIT2_FLAGS_SHIFT_PHYS_MAP_MODE;
printf("Physical mapping type: %s\n",
t == MPI_SAS_IOUNIT2_FLAGS_NO_PHYS_MAP ? "None" :
t == MPI_SAS_IOUNIT2_FLAGS_DIRECT_ATTACH_PHYS_MAP ? "Direct Attach" :
t == MPI_SAS_IOUNIT2_FLAGS_ENCLOSURE_SLOT_PHYS_MAP ? "Enclosure/Slot" :
t == MPI_SAS_IOUNIT2_FLAGS_HOST_ASSIGNED_PHYS_MAP ? "Host Assigned" :
"Unknown");
t = (flags & MPI_SAS_IOUNIT2_FLAGS_RESERVE_ID_0_FOR_BOOT) != 0;
printf("Target ID 0 reserved for boot: %s\n", t == 0 ? "No" : "Yes");
t = (flags & MPI_SAS_IOUNIT2_FLAGS_DA_STARTING_SLOT) != 0;
printf("Starting slot (direct attach): %s\n", t == 0 ? "0" : "1");
printf("Target IDs (physical mapping): %d\n", get16(SASIOUnitPage2.MaxNumPhysicalMappedIDs));
}
}
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 1, 0, &IOCPage1, sizeof IOCPage1) != 1)
return 0;
flags = get32(IOCPage1.Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
timeout = get32(IOCPage1.CoalescingTimeout);
depth = IOCPage1.CoalescingDepth;
on = flags != 0 && timeout != 0 && depth != 0;
if (on)
printf("Interrupt Coalescing: Enabled, timeout is %d us, depth is %d\n",
timeout, depth);
else
printf("Interrupt Coalescing: Disabled\n");
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
printf("\nPersistent Mappings\n-------------------\n");
doFcPersistentMappings(port, 1);
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS && mpi1)
{
printf("\nPersistent Mappings\n-------------------\n");
doSasPersistentMappings(port, 1);
}
return 1;
}
int
getChipName(MPT_PORT *port)
{
char *string;
char *chipName;
char *chipNameRev;
int family;
int revision;
char *type;
int i;
U32 seqcodeversion = 0;
family = port->productId & MPI_FW_HEADER_PID_FAMILY_MASK;
revision = port->revisionId;
switch (port->deviceId)
{
case MPI_MANUFACTPAGE_DEVICEID_FC909:
string = "FC909 B1";
type = "PCI";
break;
case MPI_MANUFACTPAGE_DEVICEID_FC919:
string = "FC919 B0";
type = "PCI";
break;
case MPI_MANUFACTPAGE_DEVICEID_FC929:
string = "FC929 B0";
type = "PCI";
break;
case MPI_MANUFACTPAGE_DEVICEID_FC919X:
if (revision < 0x80)
string = "FC919X A0";
else
string = "FC919XL A1";
type = "PCI-X";
break;
case MPI_MANUFACTPAGE_DEVICEID_FC929X:
if (revision < 0x80)
string = "FC929X A0";
else
string = "FC929XL A1";
type = "PCI-X";
break;
case MPI_MANUFACTPAGE_DEVICEID_FC939X:
string = "FC939X A1";
type = "PCI-X";
break;
case MPI_MANUFACTPAGE_DEVICEID_FC949X:
string = "FC949X A1";
type = "PCI-X";
break;
case MPI_MANUFACTPAGE_DEVICEID_FC949E:
switch (revision)
{
case 0x00:
string = "FC949E A0";
break;
case 0x01:
string = "FC949E A1";
break;
case 0x02:
string = "FC949E A2";
break;
default:
string = "FC949E xx";
break;
}
type = "PCI-E";
break;
case MPI_MANUFACTPAGE_DEVID_53C1030:
switch (revision)
{
case 0x00:
string = "53C1030 A0";
break;
case 0x01:
string = "53C1030 B0";
break;
case 0x03:
string = "53C1030 B1";
break;
case 0x07:
string = "53C1030 B2";
break;
case 0x08:
string = "53C1030 C0";
break;
case 0x80:
string = "53C1030T A0";
break;
case 0x83:
string = "53C1030T A2";
break;
case 0x87:
string = "53C1030T A3";
break;
case 0xc1:
string = "53C1020A A1";
break;
default:
string = "53C1030 xx";
break;
}
type = "PCI-X";
break;
case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
switch (revision)
{
case 0x03:
string = "53C1035 A2";
break;
case 0x04:
string = "53C1035 B0";
break;
default:
string = "53C1035 xx";
break;
}
type = "PCI-X";
break;
case MPI_MANUFACTPAGE_DEVID_SAS1064:
switch (revision)
{
case 0x00:
string = "SAS1064 A1"; seqcodeversion = 0x1064a1;
break;
case 0x01:
string = "SAS1064 A2"; seqcodeversion = 0x1064a2;
break;
case 0x02:
string = "SAS1064 A3"; seqcodeversion = 0x1064a3;
break;
case 0x03:
string = "SAS1064 A4"; seqcodeversion = 0x1064a4;
break;
default:
string = "SAS1064 xx"; seqcodeversion = 0x1064ff;
break;
}
type = "PCI-X";
break;
case MPI_MANUFACTPAGE_DEVID_SAS1064E:
switch (revision)
{
case 0x00:
string = "SAS1064E A0"; seqcodeversion = 0x106ea0;
break;
case 0x01:
string = "SAS1064E B0"; seqcodeversion = 0x106eb0;
break;
case 0x02:
string = "SAS1064E B1"; seqcodeversion = 0x106eb1;
break;
case 0x04:
string = "SAS1064E B2"; seqcodeversion = 0x106eb2;
break;
case 0x08:
string = "SAS1064E B3"; seqcodeversion = 0x106eb3;
break;
case 0x10:
string = "SAS1064E C0"; seqcodeversion = 0x106ec0;
break;
default:
string = "SAS1064E xx"; seqcodeversion = 0x106eff;
break;
}
type = "PCI-E";
break;
case MPI_MANUFACTPAGE_DEVID_SAS1066:
string = "SAS1066 xx";
type = "PCI-X";
break;
case MPI_MANUFACTPAGE_DEVID_SAS1066E:
string = "SAS1066E xx";
type = "PCI-E";
break;
case MPI_MANUFACTPAGE_DEVID_SAS1068:
switch (revision)
{
case 0x00:
string = "SAS1068 A0"; seqcodeversion = 0x1068a0;
break;
case 0x01:
string = "SAS1068 B0"; seqcodeversion = 0x1068b0;
break;
case 0x02:
string = "SAS1068 B1"; seqcodeversion = 0x1068b1;
break;
default:
string = "SAS1068 xx"; seqcodeversion = 0x1068ff;
break;
}
type = "PCI-X";
break;
case MPI_MANUFACTPAGE_DEVID_SAS1068E:
switch (revision)
{
case 0x00:
string = "SAS1068E A0"; seqcodeversion = 0x106ea0;
break;
case 0x01:
string = "SAS1068E B0"; seqcodeversion = 0x106eb0;
break;
case 0x02:
string = "SAS1068E B1"; seqcodeversion = 0x106eb1;
break;
case 0x04:
string = "SAS1068E B2"; seqcodeversion = 0x106eb2;
break;
case 0x08:
string = "SAS1068E B3"; seqcodeversion = 0x106eb3;
break;
case 0x10:
string = "SAS1068E C0"; seqcodeversion = 0x106ec0;
break;
default:
string = "SAS1068E xx"; seqcodeversion = 0x106eff;
break;
}
type = "PCI-E";
break;
case MPI_MANUFACTPAGE_DEVID_SAS1078:
switch (revision)
{
case 0x00:
string = "SAS1078 A0"; seqcodeversion = 0x1078a0;
break;
case 0x01:
string = "SAS1078 B0"; seqcodeversion = 0x1078b0;
break;
case 0x02:
string = "SAS1078 C0"; seqcodeversion = 0x1078c0;
break;
case 0x03:
string = "SAS1078 C1"; seqcodeversion = 0x1078c1;
break;
case 0x04:
string = "SAS1078 C2"; seqcodeversion = 0x1078c2;
break;
default:
string = "SAS1078 xx"; seqcodeversion = 0x1078ff;
break;
}
type = "PCI-E";
break;
case MPI2_MFGPAGE_DEVID_SAS2004:
switch (revision)
{
case 0x00:
string = "SAS2004 A0";
break;
case 0x01:
string = "SAS2004 B0";
break;
case 0x02:
string = "SAS2004 B1";
break;
case 0x03:
string = "SAS2004 B2";
break;
default:
string = "SAS2004 xx";
break;
}
type = "PCI-E";
break;
case MPI2_MFGPAGE_DEVID_SAS2008:
switch (revision)
{
case 0x00:
string = "SAS2008 A0";
break;
case 0x01:
string = "SAS2008 B0";
break;
case 0x02:
string = "SAS2008 B1";
break;
case 0x03:
string = "SAS2008 B2";
break;
default:
string = "SAS2008 xx";
break;
}
type = "PCI-E";
break;
case MPI2_MFGPAGE_DEVID_SAS2108_1:
case MPI2_MFGPAGE_DEVID_SAS2108_2:
case MPI2_MFGPAGE_DEVID_SAS2108_3:
switch (revision)
{
case 0x00:
string = "SAS2108 A0";
break;
case 0xFF:
string = "SAS2 FPGA A0";
break;
/* the PCI Revision ID was not bumped between B0 and B1. Since B0 is not supported
* and had limited use (pre-production only), don't worry about identifying it.
* NOTE: PCI config space will always report a 1 for B0 or B1. The firmware
* (IOCPage0->RevisionID) is supposed to report a 1 for B0 and a 2 for B1 but it does not
* always do so. Therefore we consider either a 1 or 2 to be a B1 chip.
*/
case 0x01:
case 0x02:
string = "SAS2108 B1";
break;
case 0x03:
string = "SAS2108 B2";
break;
case 0x04:
string = "SAS2108 B3";
break;
case 0x05:
string = "SAS2108 B4";
break;
default:
string = "SAS2108 xx";
break;
}
type = "PCI-E";
break;
case MPI2_MFGPAGE_DEVID_SAS2116_1:
case MPI2_MFGPAGE_DEVID_SAS2116_2:
switch (revision)
{
case 0x00:
string = "SAS2116 A0";
break;
case 0x01:
string = "SAS2116 B0";
break;
case 0x02:
string = "SAS2116 B1";
break;
default:
string = "SAS2116 xx";
break;
}
type = "PCI-E";
break;
case MPI2_MFGPAGE_DEVID_SAS2208_1:
case MPI2_MFGPAGE_DEVID_SAS2208_2:
case MPI2_MFGPAGE_DEVID_SAS2208_3:
case MPI2_MFGPAGE_DEVID_SAS2208_4:
case MPI2_MFGPAGE_DEVID_SAS2208_5:
case MPI2_MFGPAGE_DEVID_SAS2208_6:
switch (revision)
{
case 0x00:
string = "SAS2208 A0";
break;
case 0x01:
string = "SAS2208 B0";
break;
case 0x02:
string = "SAS2208 C0";
break;
case 0x03:
string = "SAS2208 C1";
break;
case 0x04:
string = "SAS2208 D0";
break;
case 0x05:
string = "SAS2208 D1";
break;
default:
string = "SAS2208 xx";
break;
}
type = "PCI-E";
break;
case MPI2_MFGPAGE_DEVID_SAS2308_1:
case MPI2_MFGPAGE_DEVID_SAS2308_2:
case MPI2_MFGPAGE_DEVID_SAS2308_3:
switch (revision)
{
case 0x00:
string = "SAS2308 A0";
break;
case 0x01:
string = "SAS2308 B0";
break;
case 0x02:
string = "SAS2308 C0";
break;
case 0x03:
string = "SAS2308 C1";
break;
case 0x04:
string = "SAS2308 D0";
break;
case 0x05:
string = "SAS2308 D1";
break;
default:
string = "SAS2308 xx";
break;
}
type = "PCI-E";
break;
case MPI25_MFGPAGE_DEVID_SAS3004:
switch (revision)
{
case 0x00:
string = "SA3004 A0";
break;
case 0x01:
string = "SAS3004 B0";
break;
case 0x02:
string = "SAS3004 C0";
break;
default:
string = "SAS3004 xx";
break;
}
type = "PCI-E";
break;
case MPI25_MFGPAGE_DEVID_SAS3008:
switch (revision)
{
case 0x00:
string = "SA3008 A0";
break;
case 0x01:
string = "SAS3008 B0";
break;
case 0x02:
string = "SAS3008 C0";
break;
default:
string = "SAS3008 xx";
break;
}
type = "PCI-E";
break;
case MPI25_MFGPAGE_DEVID_SAS3108_1:
case MPI25_MFGPAGE_DEVID_SAS3108_2:
case MPI25_MFGPAGE_DEVID_SAS3108_5:
case MPI25_MFGPAGE_DEVID_SAS3108_6:
switch (revision)
{
case 0x00:
string = "SAS3108 A0";
break;
case 0x01:
string = "SAS3108 B0";
break;
case 0x02:
string = "SAS3108 C0";
break;
default:
string = "SAS3108 xx";
break;
}
type = "PCI-E";
break;
#ifdef SAS3108_FPGA_WORKAROUND
case 0x100:
case 0x092:
string = "SAS3108 FPGA";
type = "PCI-E";
break;
#endif
case MPI2_MFGPAGE_DEVID_SSS6200:
switch (revision)
{
case 0x00:
string = "SSS6200 A0";
break;
case 0x01:
string = "SSS6200 B0";
break;
case 0x02:
string = "SSS6200 C0";
break;
default:
string = "SSS6200 xx";
break;
}
type = "PCI-E";
break;
default:
string = "xxxx xx";
type = NULL;
break;
}
port->seqCodeVersion = seqcodeversion;
chipNameRev = malloc(strlen(string) + 1);
strcpy(chipNameRev, string);
i = (int)strlen(chipNameRev) - 2;
if (strncmp(chipNameRev + 0, "xxxx", 4) == 0)
sprintf(chipNameRev + 0, "%04x %02x", port->deviceId, port->revisionId);
else if (strncmp(chipNameRev + i, "xx", 2) == 0)
sprintf(chipNameRev + i, "%02x", port->revisionId);
port->chipNameRev = chipNameRev;
chipName = malloc(strlen(chipNameRev) + 1);
strcpy(chipName, chipNameRev);
i = (int)strlen(chipNameRev) - 3;
chipName[i] = '\0';
port->chipName = chipName;
port->pciType = type;
return 1;
}
int
getPortInfo(MPT_PORT *port)
{
IOCFactsReply_t IOCFacts;
PortFactsReply_t PortFacts;
#if !DOS && !EFI
IOCPage0_t IOCPage0;
#endif
SasIOUnitPage0_t SASIOUnitPage0;
if (checkOperational(port, 0) != 1)
return 1;
port->lastEvent = -1;
port->payOff = 0;
if (getIocFacts(port, &IOCFacts) != 1)
return 0;
// dumpMemoryWide(&IOCFacts, sizeof IOCFacts, "IOCFactsReply");
port->mptVersion = get16(IOCFacts.MsgVersion);
if (mpi2)
return getPortInfo2(port);
port->iocNumber = IOCFacts.IOCNumber;
port->whoInit = IOCFacts.WhoInit;
port->productId = get16(IOCFacts.ProductID);
port->capabilities = get32(IOCFacts.IOCCapabilities);
port->flags = IOCFacts.Flags;
port->fwImageSize = get32(IOCFacts.FWImageSize);
port->payOff = get16(IOCFacts.CurReplyFrameSize);
port->maxBuses = IOCFacts.MaxBuses;
if (port->maxBuses == 0)
port->maxBuses = 1;
port->minTargets = 0;
port->maxTargets = IOCFacts.MaxDevices;
if (port->maxTargets == 0)
port->maxTargets = 255; /* Linux limit! */
port->maxLuns = maxLuns;
if (port->mptVersion < MPI_VERSION_01_02)
port->fwVersion = get16(IOCFacts.Reserved_0101_FWVersion);
else
port->fwVersion = get32(IOCFacts.FWVersion.Word);
if (port->mptVersion < MPI_VERSION_01_02 &&
port->productId == MPI_MANUFACTPAGE_DEVICEID_FC909)
port->productId = MPI_FW_HEADER_PID_FAMILY_909_FC |
MPI_FW_HEADER_PID_TYPE_FC;
port->pidType = port->productId & MPI_FW_HEADER_PID_TYPE_MASK;
if (getPortFacts(port, &PortFacts) != 1)
return 0;
// dumpMemoryWide(&PortFacts, sizeof PortFacts, "PortFactsReply");
port->portType = PortFacts.PortType;
port->maxPersistentIds = get16(PortFacts.MaxPersistentIDs);
port->hostScsiId = get16(PortFacts.PortSCSIID);
port->protocolFlags = get16(PortFacts.ProtocolFlags);
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
if (port->maxTargets > port->hostScsiId + 1)
port->maxTargets = port->hostScsiId + 1;
}
else
{
if (port->maxTargets > get16(PortFacts.MaxDevices))
port->maxTargets = get16(PortFacts.MaxDevices);
}
#if !DOS && !EFI
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_IOC, 0, 0, &IOCPage0, sizeof IOCPage0) != 1)
return 0;
if (get16(IOCPage0.VendorID) != MPI_MANUFACTPAGE_VENDORID_LSILOGIC)
return 0;
port->deviceIdRaw = get16(IOCPage0.DeviceID);
/* the following three want to be set to the device ID that doesnt include ZC*/
if ( (port->deviceIdRaw == MPI_MANUFACTPAGE_DEVID_53C1030ZC) ||
(port->deviceIdRaw == MPI_MANUFACTPAGE_DEVID_1030ZC_53C1035) ||
(port->deviceIdRaw == MPI_MANUFACTPAGE_DEVID_53C1035ZC))
{
port->deviceId = port->deviceIdRaw & ~1;
}
else
{
port->deviceId = port->deviceIdRaw;
}
port->revisionId = IOCPage0.RevisionID;
getChipName(port);
#endif
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0,
&SASIOUnitPage0, sizeof SASIOUnitPage0) == 1)
{
port->numPhys = SASIOUnitPage0.NumPhys;
}
else
{
switch (port->deviceId)
{
case MPI_MANUFACTPAGE_DEVID_SAS1064:
case MPI_MANUFACTPAGE_DEVID_SAS1064E:
port->numPhys = 4;
break;
case MPI_MANUFACTPAGE_DEVID_SAS1066:
case MPI_MANUFACTPAGE_DEVID_SAS1066E:
port->numPhys = 6;
break;
case MPI_MANUFACTPAGE_DEVID_SAS1068:
case MPI_MANUFACTPAGE_DEVID_SAS1068E:
case MPI_MANUFACTPAGE_DEVID_SAS1078:
port->numPhys = 8;
break;
}
}
}
return 1;
}
int
getPortInfo2(MPT_PORT *port)
{
Mpi2IOCFactsReply_t IOCFacts;
Mpi2PortFactsReply_t PortFacts;
#if !DOS && !EFI
Mpi2IOCPage0_t IOCPage0;
#endif
Mpi2SasIOUnitPage0_t SASIOUnitPage0;
if (getIocFacts2(port, &IOCFacts) != 1)
return 0;
// dumpMemoryWide(&IOCFacts, sizeof IOCFacts, "IOCFactsReply");
port->iocNumber = IOCFacts.IOCNumber;
port->whoInit = IOCFacts.WhoInit;
port->productId = get16(IOCFacts.ProductID);
port->capabilities = get32(IOCFacts.IOCCapabilities);
// ReplyFrameSize moved within IOCFacts and went from
// indicating the number of bytes to indicating the
// number of dwords. Maintain backward compatibility
if (mpi25)
{
port->payOff = IOCFacts.ReplyFrameSize * 4;
}
else if (IOCFacts.OldReplyFrameSize)
{
port->payOff = get16(IOCFacts.OldReplyFrameSize);
}
else
{
port->payOff = IOCFacts.ReplyFrameSize * 4;
}
port->maxDevHandle = get16(IOCFacts.MaxDevHandle) + 1;
setMaxBusTarget(port);
port->maxLuns = maxLuns;
port->protocolFlags = get16(IOCFacts.ProtocolFlags);
port->maxPersistentIds = get16(IOCFacts.MaxPersistentEntries);
port->fwVersion = get32(IOCFacts.FWVersion.Word);
port->fastpathCapable = port->capabilities & MPI25_IOCFACTS_CAPABILITY_FAST_PATH_CAPABLE ? 1 : 0;
port->pidType = port->productId & MPI2_FW_HEADER_PID_TYPE_MASK;
if (getPortFacts2(port, &PortFacts) != 1)
return 0;
// dumpMemoryWide(&PortFacts, sizeof PortFacts, "PortFactsReply");
port->portType = PortFacts.PortType;
#if !DOS && !EFI
if (getConfigPage(port, MPI2_CONFIG_PAGETYPE_IOC, 0, 0, &IOCPage0, sizeof IOCPage0) != 1)
return 0;
#if SAS3108_FPGA_WORKAROUND
if (get16(IOCPage0.VendorID) != MPI2_MFGPAGE_VENDORID_LSI && get16(IOCPage0.VendorID) != SAS3108_FPGA_VENDORID)
return 0;
#else
if (get16(IOCPage0.VendorID) != MPI2_MFGPAGE_VENDORID_LSI)
return 0;
#endif
port->deviceIdRaw = get16(IOCPage0.DeviceID);
/* the following three want to be set to the device ID that doesnt include ZC*/
if ( (port->deviceIdRaw == MPI_MANUFACTPAGE_DEVID_53C1030ZC) ||
(port->deviceIdRaw == MPI_MANUFACTPAGE_DEVID_1030ZC_53C1035) ||
(port->deviceIdRaw == MPI_MANUFACTPAGE_DEVID_53C1035ZC))
{
port->deviceId = port->deviceIdRaw & ~1;
}
else
{
port->deviceId = port->deviceIdRaw;
}
port->revisionId = IOCPage0.RevisionID;
getChipName(port);
#endif
if (port->pidType == MPI2_FW_HEADER_PID_TYPE_SAS)
{
if (getConfigPage(port, MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0,
&SASIOUnitPage0, sizeof SASIOUnitPage0) == 1)
{
port->numPhys = SASIOUnitPage0.NumPhys;
}
else
{
switch (port->deviceId)
{
case MPI2_MFGPAGE_DEVID_SAS2004:
case MPI25_MFGPAGE_DEVID_SAS3004:
port->numPhys = 4;
break;
case MPI2_MFGPAGE_DEVID_SAS2008:
case MPI2_MFGPAGE_DEVID_SAS2108_1:
case MPI2_MFGPAGE_DEVID_SAS2108_2:
case MPI2_MFGPAGE_DEVID_SAS2108_3:
case MPI2_MFGPAGE_DEVID_SAS2208_1:
case MPI2_MFGPAGE_DEVID_SAS2208_2:
case MPI2_MFGPAGE_DEVID_SAS2208_3:
case MPI2_MFGPAGE_DEVID_SAS2208_4:
case MPI2_MFGPAGE_DEVID_SAS2208_5:
case MPI2_MFGPAGE_DEVID_SAS2208_6:
case MPI2_MFGPAGE_DEVID_SAS2308_1:
case MPI2_MFGPAGE_DEVID_SAS2308_2:
case MPI2_MFGPAGE_DEVID_SAS2308_3:
case MPI25_MFGPAGE_DEVID_SAS3008:
case MPI25_MFGPAGE_DEVID_SAS3108_1:
case MPI25_MFGPAGE_DEVID_SAS3108_2:
case MPI25_MFGPAGE_DEVID_SAS3108_5:
case MPI25_MFGPAGE_DEVID_SAS3108_6:
case MPI2_MFGPAGE_DEVID_SSS6200:
port->numPhys = 8;
break;
case MPI2_MFGPAGE_DEVID_SAS2116_1:
case MPI2_MFGPAGE_DEVID_SAS2116_2:
port->numPhys = 16;
break;
}
}
}
return 1;
}
int
updatePortInfo(MPT_PORT *port)
{
IOCFactsReply_t IOCFacts;
PortFactsReply_t PortFacts;
if (port->mptVersion == 0)
return getPortInfo(port);
if (getIocFacts(port, &IOCFacts) != 1)
return 0;
port->mptVersion = get16(IOCFacts.MsgVersion);
if (mpi2)
return updatePortInfo2(port);
if (port->mptVersion < MPI_VERSION_01_02)
port->fwVersion = get16(IOCFacts.Reserved_0101_FWVersion);
else
port->fwVersion = get32(IOCFacts.FWVersion.Word);
port->capabilities = get32(IOCFacts.IOCCapabilities);
if (port->portType == MPI_PORTFACTS_PORTTYPE_INACTIVE)
{
if (getPortFacts(port, &PortFacts) != 1)
return 0;
port->portType = PortFacts.PortType;
port->maxPersistentIds = get16(PortFacts.MaxPersistentIDs);
port->hostScsiId = get16(PortFacts.PortSCSIID);
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
if (port->maxTargets > port->hostScsiId + 1)
port->maxTargets = port->hostScsiId + 1;
}
else
{
if (port->maxTargets > get16(PortFacts.MaxDevices))
port->maxTargets = get16(PortFacts.MaxDevices);
}
}
return 1;
}
int
updatePortInfo2(MPT_PORT *port)
{
Mpi2IOCFactsReply_t IOCFacts;
Mpi2PortFactsReply_t PortFacts;
if (getIocFacts2(port, &IOCFacts) != 1)
return 0;
port->fwVersion = get32(IOCFacts.FWVersion.Word);
port->capabilities = get32(IOCFacts.IOCCapabilities);
port->maxDevHandle = get16(IOCFacts.MaxDevHandle) + 1;
setMaxBusTarget(port);
port->maxPersistentIds = get16(IOCFacts.MaxPersistentEntries);
if (port->portType == MPI_PORTFACTS_PORTTYPE_INACTIVE)
{
if (getPortFacts2(port, &PortFacts) != 1)
return 0;
port->portType = PortFacts.PortType;
}
return 1;
}
int
getBoardInfo(MPT_PORT *port)
{
int segment = 0;
int bus = 0;
int device = 0;
int function = 0;
#if WIN32
int status;
DRVR_INFO_SRB srb;
int inLen;
int outLen;
DWORD retLen;
#endif
#if __linux__
int status;
struct mpt_ioctl_iocinfo iocinfo;
#endif
#if __sparc__
SYMHI_DMI_DATA dmiData;
mptsas_pci_info_t pciInfo;
int status;
U32 reg[64];
#endif
#if DOS || EFI
HANDLE adap = port->fileHandle;
#endif
if (port->pciSegment != 0 || port->pciBus != 0 || port->pciDevice != 0 || port->pciFunction != 0)
return 1;
#if WIN32
memset(&srb, 0, sizeof srb);
srb.Sic.Length = sizeof srb - sizeof srb.Sic;
srb.Sic.ControlCode = DRVR_INFO_IOCTL;
srb.Sic.HeaderLength = sizeof srb.Sic;
srb.Sic.Timeout = SHORT_TIME;
memcpy((char *)&srb.Sic.Signature, "4.00 ", 8);
srb.PageCode = ADAPTER_INFO_PAGE;
inLen = sizeof srb;
outLen = sizeof srb;
retLen = 0;
status = DeviceIoControl(port->fileHandle, port->ioctlValue,
&srb, inLen, &srb, outLen, &retLen, NULL);
if (status != 1)
return 0;
if (retLen >= sizeof srb)
segment = srb.AdapterPageOut.PciSegmentId;
else
segment = srb.AdapterPageOut.PciInfo.u.bits.BusNumber >> 8;
bus = srb.AdapterPageOut.PciInfo.u.bits.BusNumber & 0xff;
device = srb.AdapterPageOut.PciInfo.u.bits.DeviceNumber;
function = srb.AdapterPageOut.PciInfo.u.bits.FunctionNumber;
#endif
#if __linux__
memset(&iocinfo, 0, sizeof iocinfo);
iocinfo.hdr.maxDataSize = sizeof iocinfo;
iocinfo.hdr.iocnum = port->portNumber;
if (mpi2)
status = ioctl(port->fileHandle, MPT2IOCINFO, &iocinfo);
else
status = ioctl(port->fileHandle, MPTIOCINFO, &iocinfo);
if (status != 0)
return 0;
segment = iocinfo.pciInfo.segmentID;
bus = iocinfo.pciInfo.u.bits.busNumber;
device = iocinfo.pciInfo.u.bits.deviceNumber;
function = iocinfo.pciInfo.u.bits.functionNumber;
#endif
#if __sparc__
if (mpi2)
{
memset(&pciInfo, 0, sizeof pciInfo);
status = ioctl(port->fileHandle, MPTIOCTL_GET_PCI_INFO, &pciInfo);
if (status == 0)
{
bus = pciInfo.BusNumber;
device = pciInfo.DeviceNumber;
function = pciInfo.FunctionNumber;
}
else
return 0;
}
else
{
memset(&dmiData, 0, sizeof dmiData);
dmiData.StructureLength = sizeof dmiData;
status = ioctl(port->fileHandle, SYMIOCTL_GET_DMI_DATA, &dmiData);
if (status == 0)
{
bus = dmiData.PciBusNumber;
device = dmiData.PciDeviceNumber;
function = dmiData.PciFunctionNumber;
}
else
{
memset(reg, 0, sizeof reg);
status = getProperty(port, "reg", (char *)reg, sizeof reg);
if (status == 0)
return 0;
bus = (reg[0] >> 16) & 0xff;
device = (reg[0] >> 11) & 0x1f;
function = (reg[0] >> 8) & 0x07;
}
}
#endif
#if DOS || EFI
segment = adap->segment_number;
bus = adap->bus_number;
device = (adap->device_function >> 3) & 31;
function = (adap->device_function >> 0) & 7;
#endif
port->pciSegment = segment;
port->pciBus = bus;
port->pciDevice = device;
port->pciFunction = function;
return 1;
}
int
showBoardInfo(MPT_PORT *port, int flag)
{
ManufacturingPage0_t ManufacturingPage0;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
&ManufacturingPage0, sizeof ManufacturingPage0) != 1)
return 0;
if (getBoardInfo(port) == 1)
{
if (flag)
{
printf("Seg/Bus/Dev/Fun Board Name Board Assembly Board Tracer\n");
printf("%2d %2d %2d %2d %-16.16s %-16.16s %-16.16s\n",
port->pciSegment, port->pciBus, port->pciDevice, port->pciFunction,
ManufacturingPage0.BoardName, ManufacturingPage0.BoardAssembly, ManufacturingPage0.BoardTracerNumber);
}
else
{
printf("%-16s %2d %2d %2d %-16.16s %-16.16s %-16.16s\n",
port->portName, port->pciSegment, port->pciBus, port->pciDevice,
ManufacturingPage0.BoardName, ManufacturingPage0.BoardAssembly, ManufacturingPage0.BoardTracerNumber);
}
}
else
{
if (flag)
{
printf("Seg/Bus/Dev/Fun Board Name Board Assembly Board Tracer\n");
printf(" %-16.16s %-16.16s %-16.16s\n",
ManufacturingPage0.BoardName, ManufacturingPage0.BoardAssembly, ManufacturingPage0.BoardTracerNumber);
}
else
{
printf("%-16s %-16.16s %-16.16s %-16.16s\n",
port->portName,
ManufacturingPage0.BoardName, ManufacturingPage0.BoardAssembly, ManufacturingPage0.BoardTracerNumber);
}
}
return 1;
}
int
dumpFcDevicePages(MPT_PORT *port)
{
FCDevicePage0_t FCDevicePage0;
U32 d_id;
printf(" B___T WWNN WWPN PortId ALPA FrSize BBCr Prot Flag\n");
d_id = 0xffffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_DEVICE, 0, d_id,
&FCDevicePage0, sizeof FCDevicePage0) != 1)
break;
d_id = get32(FCDevicePage0.PortIdentifier);
if (FCDevicePage0.Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID)
{
printf("%2d %3d %08x%08x %08x%08x %06x %02x %04x %02x %02x %02x\n",
FCDevicePage0.CurrentBus, FCDevicePage0.CurrentTargetID,
get32(FCDevicePage0.WWNN.High), get32(FCDevicePage0.WWNN.Low),
get32(FCDevicePage0.WWPN.High), get32(FCDevicePage0.WWPN.Low),
d_id, FCDevicePage0.ADISCHardALPA, get16(FCDevicePage0.MaxRxFrameSize),
get16(FCDevicePage0.BBCredit), FCDevicePage0.Protocol, FCDevicePage0.Flags);
}
else
{
printf(" %08x%08x %08x%08x %06x %02x %04x %02x %02x %02x\n",
get32(FCDevicePage0.WWNN.High), get32(FCDevicePage0.WWNN.Low),
get32(FCDevicePage0.WWPN.High), get32(FCDevicePage0.WWPN.Low),
d_id, FCDevicePage0.ADISCHardALPA, get16(FCDevicePage0.MaxRxFrameSize),
get16(FCDevicePage0.BBCredit), FCDevicePage0.Protocol, FCDevicePage0.Flags);
}
}
return 1;
}
int
dumpSasDevicePages(MPT_PORT *port)
{
SasDevicePage0_t SASDevicePage0;
U32 handle;
int bus;
int target;
int flags;
int mapped;
printf(" B___T SASAddress Handle Encl/Slot DevInfo/Flag/Acc Port Parent PhyNum\n");
handle = 0xffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, handle,
&SASDevicePage0, sizeof SASDevicePage0) != 1)
break;
handle = get16(SASDevicePage0.DevHandle);
flags = get16(SASDevicePage0.Flags);
if (mpi1)
{
mapped = flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED;
bus = SASDevicePage0.Bus;
target = SASDevicePage0.TargetID;
}
else
{
mapped = mapDevHandleToBusTarget(port, handle, &bus, &target);
}
if (SASDevicePage0.ParentDevHandle == 0)
{
printf(" %08x%08x %04x\n",
get32(SASDevicePage0.SASAddress.High), get32(SASDevicePage0.SASAddress.Low),
handle);
}
else if (mapped)
{
printf("%2d %3d %08x%08x %04x %04x %2d %08x %04x %02x %2d %04x %2d\n",
bus, target,
get32(SASDevicePage0.SASAddress.High), get32(SASDevicePage0.SASAddress.Low),
handle, get16(SASDevicePage0.EnclosureHandle), get16(SASDevicePage0.Slot),
get32(SASDevicePage0.DeviceInfo), flags, SASDevicePage0.AccessStatus,
SASDevicePage0.PhysicalPort, get16(SASDevicePage0.ParentDevHandle),
SASDevicePage0.PhyNum);
}
else
{
printf(" %08x%08x %04x %04x %2d %08x %04x %02x %2d %04x %2d\n",
get32(SASDevicePage0.SASAddress.High), get32(SASDevicePage0.SASAddress.Low),
handle, get16(SASDevicePage0.EnclosureHandle), get16(SASDevicePage0.Slot),
get32(SASDevicePage0.DeviceInfo), flags, SASDevicePage0.AccessStatus,
SASDevicePage0.PhysicalPort, get16(SASDevicePage0.ParentDevHandle),
SASDevicePage0.PhyNum);
}
}
return 1;
}
int
showPortInfo(MPT_PORT *port)
{
FCPortPage0_t FCPortPage0;
FCDevicePage0_t FCDevicePage0;
int i;
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
char buf[16];
int portId;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 0, 0, &FCPortPage0, sizeof FCPortPage0) != 1)
return 0;
portId = get32(FCPortPage0.PortIdentifier);
sprintf(buf, "%s Port", port->chipName);
printf(" %-24s %08x%08x %06x\n", buf,
get32(FCPortPage0.WWPN.High), get32(FCPortPage0.WWPN.Low), portId);
i = 0xffffff;
while (TRUE)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_DEVICE, 0, i,
&FCDevicePage0, sizeof FCDevicePage0) != 1)
break;
i = get32(FCDevicePage0.PortIdentifier);
if (i == portId)
continue;
if (FCDevicePage0.Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET)
continue;
if (FCDevicePage0.Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
printf(" FCP Initiator %08x%08x %06x\n",
get32(FCDevicePage0.WWPN.High), get32(FCDevicePage0.WWPN.Low), i);
else
printf(" Non-FCP %08x%08x %06x\n",
get32(FCDevicePage0.WWPN.High), get32(FCDevicePage0.WWPN.Low), i);
}
return 1;
}
return 0;
}
int
showPortInfoHeader(MPT_PORT *port)
{
FCPortPage0_t FCPortPage0;
SasIOUnitPage0_t *SASIOUnitPage0;
Mpi2SasIOUnitPage0_t *SASIOUnitPage0_2;
SasIOUnit0PhyData *SASIOUnit0PhyData;
int i;
if (bringOnline(port) != 1)
return 0;
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SCSI)
{
printf("%s's host SCSI ID is %d\n\n", port->chipName, port->hostScsiId);
return 1;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
char *attach;
char *speed;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_PORT, 0, 0, &FCPortPage0, sizeof FCPortPage0) != 1)
return 0;
switch (get32(FCPortPage0.Flags) & MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK)
{
case MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT: attach = NULL; break;
case MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT: attach = "point to point"; break;
case MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP: attach = "private loop"; break;
case MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT: attach = "fabric direct attach"; break;
case MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP: attach = "public loop"; break;
default: attach = "unknown"; break;
}
if (port->mptVersion < MPI_VERSION_01_01)
speed = "1 Gbps";
else
switch (get32(FCPortPage0.CurrentSpeed))
{
case MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT: speed = "1 Gbps"; break;
case MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT: speed = "2 Gbps"; break;
case MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT: speed = "4 Gbps"; break;
case MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT: speed = "10 Gbps"; break;
default: speed = "unknown"; break;
}
if (attach != NULL)
printf("%s's link is online, type is %s, speed is %s\n\n", port->chipName, attach, speed);
else
printf("%s's link is offline\n\n", port->chipName);
return 1;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
int length;
char *speed;
int rate;
SASIOUnitPage0 = getConfigPageAlloc(port, MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0, &length);
if (SASIOUnitPage0 == NULL)
return 0;
SASIOUnitPage0_2 = (pMpi2SasIOUnitPage0_t)SASIOUnitPage0;
if (SASIOUnitPage0->NumPhys == 1)
printf("%s's link is ", port->chipName);
else
printf("%s's links are ", port->chipName);
for (i = 0; i < SASIOUnitPage0->NumPhys; i++)
{
if (i != 0)
printf(", ");
if (mpi2)
{
SASIOUnit0PhyData = (pSasIOUnit0PhyData)&SASIOUnitPage0_2->PhyData[i];
rate = (SASIOUnit0PhyData->NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_LOGICAL) >>
MPI2_SAS_NEG_LINK_RATE_SHIFT_LOGICAL;
}
else
{
SASIOUnit0PhyData = (pSasIOUnit0PhyData)&SASIOUnitPage0->PhyData[i];
rate = SASIOUnit0PhyData->NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL;
}
switch (rate)
{
case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
speed = "down";
break;
case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
speed = "off";
break;
case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
speed = "failed";
break;
case MPI_SAS_IOUNIT0_RATE_1_5:
speed = "1.5 G";
break;
case MPI_SAS_IOUNIT0_RATE_3_0:
speed = "3.0 G";
break;
case MPI2_SAS_NEG_LINK_RATE_6_0:
speed = "6.0 G";
break;
case MPI25_SAS_NEG_LINK_RATE_12_0:
speed = "12.0 G";
break;
default:
speed = "unknown";
break;
}
printf(speed);
}
printf("\n\n");
free(SASIOUnitPage0);
return 1;
}
return 0;
}
int
getDeviceInfo(MPT_PORT *port, int bus, int target, char *buf, int len)
{
SCSIDevicePage0_t SCSIDevicePage0;
FCDevicePage0_t FCDevicePage0;
SasDevicePage0_t SASDevicePage0;
int b_t;
int dev_handle;
int address;
buf[0] = '\0';
b_t = (bus << 8) + mapOsToHwTarget(port, target);
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SCSI)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_SCSI_DEVICE, 0, b_t,
&SCSIDevicePage0, sizeof SCSIDevicePage0) == 1)
{
int parameters = get32(SCSIDevicePage0.NegotiatedParameters);
int speed = parameters & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK;
int width = parameters & MPI_SCSIDEVPAGE0_NP_WIDE;
int mbps;
char *speed_string;
char *width_string;
if ((parameters & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) == 0)
speed = 0;
if (speed == 0)
{
speed_string = "Async";
mbps = 0;
}
else if (speed <= 0x800)
{
speed_string = "Ultra4";
mbps = 160;
}
else if (speed <= 0x900)
{
speed_string = "Ultra3";
mbps = 80;
}
else if (speed <= 0xa00)
{
speed_string = "Ultra2";
mbps = 40;
}
else if (speed <= 0xc00)
{
speed_string = "Ultra";
mbps = 20;
}
else if (speed <= 0x1900)
{
speed_string = "Fast";
mbps = 64000 / speed;
}
else
{
speed_string = "Sync";
mbps = 64000 / speed;
}
if (width == 0)
{
width_string = "Narrow";
}
else
{
width_string = "Wide";
mbps *= 2;
}
if (get32(SCSIDevicePage0.Information) & MPI_SCSIDEVPAGE0_INFO_PARAMS_NEGOTIATED)
{
sprintf(buf, "%s %s", speed_string, width_string);
if (mbps > 0)
sprintf(buf+strlen(buf), ", %d MB/sec", mbps);
return 1;
}
}
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_DEVICE, 0,
MPI_FC_DEVICE_PGAD_FORM_BUS_TID + b_t,
&FCDevicePage0, sizeof FCDevicePage0) == 1)
{
sprintf(buf, "%08x%08x %06x",
get32(FCDevicePage0.WWPN.High), get32(FCDevicePage0.WWPN.Low),
get32(FCDevicePage0.PortIdentifier));
return 1;
}
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
if (mpi2)
{
if (mapBusTargetToDevHandle(port, bus, target, &dev_handle) != 1)
dev_handle = 0;
address = MPI2_SAS_DEVICE_PGAD_FORM_HANDLE + dev_handle;
}
else
{
b_t = (bus << 8) + target;
address = (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
<<MPI_SAS_DEVICE_PGAD_FORM_SHIFT) + b_t;
}
if (getConfigPage(port, MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, address,
&SASDevicePage0, sizeof SASDevicePage0) == 1)
{
sprintf(buf, "%08x%08x %2d",
get32(SASDevicePage0.SASAddress.High),
get32(SASDevicePage0.SASAddress.Low),
SASDevicePage0.PhyNum);
return 1;
}
}
return 0;
}
int
getDeviceInfoHeader(MPT_PORT *port, char *buf, int len)
{
buf[0] = '\0';
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SCSI)
{
sprintf(buf, "Negotiated Speed & Width");
return 1;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
sprintf(buf, " WWPN PortId");
return 1;
}
if (port->pidType == MPI_FW_HEADER_PID_TYPE_SAS)
{
sprintf(buf, " SASAddress PhyNum");
return 1;
}
return 0;
}
int
getIocFacts(MPT_PORT *port, IOCFactsReply_t *rep)
{
IOCFacts_t req;
memset(&req, 0, sizeof req);
memset(rep, 0, sizeof *rep);
req.Function = MPI_FUNCTION_IOC_FACTS;
return doMptCommand(port, &req, sizeof req, rep, sizeof *rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
getIocFacts2(MPT_PORT *port, Mpi2IOCFactsReply_t *rep)
{
Mpi2IOCFactsRequest_t req;
memset(&req, 0, sizeof req);
memset(rep, 0, sizeof *rep);
req.Function = MPI2_FUNCTION_IOC_FACTS;
return doMptCommand(port, &req, sizeof req, rep, sizeof *rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
getPortFacts(MPT_PORT *port, PortFactsReply_t *rep)
{
PortFacts_t req;
memset(&req, 0, sizeof req);
memset(rep, 0, sizeof *rep);
req.Function = MPI_FUNCTION_PORT_FACTS;
return doMptCommand(port, &req, sizeof req, rep, sizeof *rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
getPortFacts2(MPT_PORT *port, Mpi2PortFactsReply_t *rep)
{
Mpi2PortFactsRequest_t req;
memset(&req, 0, sizeof req);
memset(rep, 0, sizeof *rep);
req.Function = MPI2_FUNCTION_PORT_FACTS;
return doMptCommand(port, &req, sizeof req, rep, sizeof *rep, NULL, 0, NULL, 0, SHORT_TIME);
}
int
doConfigPageRequest(MPT_PORT *port, void *req, int reqSize, void *rep, int repSize,
void *payIn, int payInSize, void *payOut, int payOutSize, int timeOut)
{
int i;
for (i = 0; i < 120; i++)
{
if (doMptCommand(port, req, reqSize, rep, repSize, payIn, payInSize, payOut, payOutSize, timeOut) != 1)
return 0;
if (get16(((ConfigReply_t *)rep)->IOCStatus) != MPI_IOCSTATUS_BUSY)
{
if (i > 0)
printf("SUCCESS\n");
return 1;
}
if (i == 0)
printf("Firmware returned busy status, retrying.");
else
printf(".");
fflush(stdout);
sleep(1);
}
printf("\nRetries exhausted. Giving up request!\n");
return 1;
}
int
getConfigPageHeader(MPT_PORT *port, int type, int number, int address, ConfigReply_t *repOut)
{
Config_t req;
ConfigReply_t rep;
int ioc_status;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_CONFIG;
req.AliasIndex = virtInit;
req.Action = MPI_CONFIG_ACTION_PAGE_HEADER;
if (type > MPI_CONFIG_PAGETYPE_EXTENDED)
{
req.Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
req.ExtPageType = type;
}
else
{
req.Header.PageType = type;
}
req.Header.PageNumber = number;
req.PageAddress = set32(address);
if (doConfigPageRequest(port, &req, sizeof req - sizeof req.PageBufferSGE, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
return 0;
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status != MPI_IOCSTATUS_SUCCESS)
return 0;
if (repOut != NULL)
memcpy(repOut, &rep, sizeof rep);
return 1;
}
int
getConfigPageLength(MPT_PORT *port, int type, int number, int address, int *length)
{
Config_t req;
ConfigReply_t rep;
int ioc_status;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_CONFIG;
req.AliasIndex = virtInit;
req.Action = MPI_CONFIG_ACTION_PAGE_HEADER;
if (type > MPI_CONFIG_PAGETYPE_EXTENDED)
{
req.Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
req.ExtPageType = type;
}
else
{
req.Header.PageType = type;
}
req.Header.PageNumber = number;
req.PageAddress = set32(address);
if (doConfigPageRequest(port, &req, sizeof req - sizeof req.PageBufferSGE, &rep, sizeof rep,
NULL, 0, NULL, 0, SHORT_TIME) != 1)
return 0;
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status != MPI_IOCSTATUS_SUCCESS)
return 0;
if (type > MPI_CONFIG_PAGETYPE_EXTENDED)
*length = get16(rep.ExtPageLength) * 4;
else
*length = rep.Header.PageLength * 4;
return 1;
}
int
getConfigPageAction(MPT_PORT *port, int action, int type, int number, int address, void *page, int pageSize)
{
Config_t req;
ConfigReply_t rep, rep1;
ConfigPageHeader_t header;
int length;
int t;
int ioc_status;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
if (getConfigPageHeader(port, type, number, address, &rep) != 1)
return 0;
memcpy(&rep1, &rep, sizeof rep);
header = rep.Header;
length = get16(rep.ExtPageLength);
req.Function = MPI_FUNCTION_CONFIG;
req.AliasIndex = virtInit;
if (action != -1)
req.Action = action;
else if ((rep.Header.PageType & MPI_CONFIG_PAGEATTR_MASK) == MPI_CONFIG_PAGEATTR_PERSISTENT ||
(rep.Header.PageType & MPI_CONFIG_PAGEATTR_MASK) == MPI_CONFIG_PAGEATTR_RO_PERSISTENT)
req.Action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
else
req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
if (req.Action == MPI_CONFIG_ACTION_PAGE_READ_NVRAM && port->mptVersion < MPI_VERSION_01_01)
req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
req.ExtPageType = rep.ExtPageType;
req.ExtPageLength = rep.ExtPageLength;
req.Header = rep.Header;
req.PageAddress = set32(address);
if (doConfigPageRequest(port, &req, sizeof req - sizeof req.PageBufferSGE, &rep, sizeof rep,
page, pageSize, NULL, 0, SHORT_TIME) != 1)
return 0;
port->ioc_status = ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE ||
ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_DATA)
{
if (action == MPI_CONFIG_ACTION_PAGE_READ_NVRAM)
{
printf("\nNon-volatile storage for this page is invalid!\n");
#if 0
printf("The current values for this page will be used instead\n");
req.Action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
#else
return 0;
#endif
}
if (req.Action == MPI_CONFIG_ACTION_PAGE_READ_NVRAM)
{
req.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
if (doConfigPageRequest(port, &req, sizeof req - sizeof req.PageBufferSGE, &rep, sizeof rep,
page, pageSize, NULL, 0, SHORT_TIME) != 1)
return 0;
port->ioc_status = ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
}
}
if (ioc_status != MPI_IOCSTATUS_SUCCESS)
return 0;
if (type > MPI_CONFIG_PAGETYPE_EXTENDED)
{
if (get16(rep.ExtPageLength) == 0)
return 0;
if (memcmp(&header, &rep.Header, sizeof header) != 0)
printf("Warning, header in HEADER reply does not match header in READ reply\n (%08x vs. %08x)\n",
get32x(*(U32 *)&header), get32x(*(U32 *)&rep.Header));
if (length != get16(rep.ExtPageLength))
printf("Warning, length in HEADER reply does not match length in READ reply\n (%d vs. %d)\n",
length, get16(rep.ExtPageLength));
t = get16(((pConfigExtendedPageHeader_t)page)->ExtPageLength);
if (t && get16(rep.ExtPageLength) != t)
printf("Warning, page length in reply does not match page length in buffer\n (%d vs. %d)\n",
get16(rep.ExtPageLength), t);
}
else
{
if (rep.Header.PageLength == 0)
return 0;
if (memcmp(&header, &rep.Header, sizeof header) != 0)
printf("Warning, header in HEADER reply does not match header in READ reply\n (%08x vs. %08x)\n",
get32x(*(U32 *)&header), get32x(*(U32 *)&rep.Header));
t = ((pConfigPageHeader_t)page)->PageLength;
if (t && rep.Header.PageLength != t)
printf("Warning, page length in reply does not match page length in buffer\n (%d vs. %d)\n",
rep.Header.PageLength, t);
}
return 1;
}
int
getConfigPage(MPT_PORT *port, int type, int number, int address, void *page, int pageSize)
{
return getConfigPageAction(port, -1, type, number, address, page, pageSize);
}
void *
getConfigPageActionAlloc(MPT_PORT *port, int action, int type, int number, int address, int *length)
{
void *page;
if (getConfigPageLength(port, type, number, address, length) == 1)
{
page = malloc(*length);
if (getConfigPageAction(port, action, type, number, address, page, *length) == 1)
{
return page;
}
free(page);
}
return NULL;
}
void *
getConfigPageAlloc(MPT_PORT *port, int type, int number, int address, int *length)
{
return getConfigPageActionAlloc(port, -1, type, number, address, length);
}
int
setConfigPageAction(MPT_PORT *port, int action, int type, int number, int address, void *page, int pageSize)
{
Config_t req;
ConfigReply_t rep;
ConfigPageHeader_t header;
int length;
int t;
int ioc_status;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
if (getConfigPageHeader(port, type, number, address, &rep) != 1)
return 0;
header = rep.Header;
length = get16(rep.ExtPageLength);
req.Function = MPI_FUNCTION_CONFIG;
req.AliasIndex = virtInit;
if (action != -1)
req.Action = action;
else if ((rep.Header.PageType & MPI_CONFIG_PAGEATTR_MASK) == MPI_CONFIG_PAGEATTR_PERSISTENT ||
(rep.Header.PageType & MPI_CONFIG_PAGEATTR_MASK) == MPI_CONFIG_PAGEATTR_RO_PERSISTENT)
req.Action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
else
req.Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
req.ExtPageType = rep.ExtPageType;
req.ExtPageLength = rep.ExtPageLength;
req.Header = rep.Header;
req.PageAddress = set32(address);
if (doConfigPageRequest(port, &req, sizeof req - sizeof req.PageBufferSGE, &rep, sizeof rep,
NULL, 0, page, pageSize, SHORT_TIME) != 1)
return 0;
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status != MPI_IOCSTATUS_SUCCESS)
{
if(wFlag)
fprintf(logFile, "IOC Status returned from doConfigPageRequest = [%08X]", ioc_status);
port->ioc_status = ioc_status;
return 0;
}
if (type > MPI_CONFIG_PAGETYPE_EXTENDED)
{
if (get16(rep.ExtPageLength) == 0)
return 0;
if (memcmp(&header, &rep.Header, sizeof header) != 0)
printf("Warning, header in HEADER reply does not match header in WRITE reply\n (%08x vs. %08x)\n",
get32x(*(U32 *)&header), get32x(*(U32 *)&rep.Header));
if (length != get16(rep.ExtPageLength))
printf("Warning, length in HEADER reply does not match length in WRITE reply\n (%d vs. %d)\n",
length, get16(rep.ExtPageLength));
t = get16(((pConfigExtendedPageHeader_t)page)->ExtPageLength);
if (t && get16(rep.ExtPageLength) != t)
printf("Warning, page length in reply does not match page length in buffer\n (%d vs. %d)\n",
get16(rep.ExtPageLength), t);
}
else
{
if (rep.Header.PageLength == 0)
return 0;
if (memcmp(&header, &rep.Header, sizeof header) != 0)
printf("Warning, header in HEADER reply does not match header in WRITE reply\n (%08x vs. %08x)\n",
get32x(*(U32 *)&header), get32x(*(U32 *)&rep.Header));
t = ((pConfigPageHeader_t)page)->PageLength;
if (t && rep.Header.PageLength != t)
printf("Warning, page length in reply does not match page length in buffer\n (%d vs. %d)\n",
rep.Header.PageLength, t);
}
return 1;
}
int
setConfigPage(MPT_PORT *port, int type, int number, int address, void *page, int pageSize)
{
int t;
t = setConfigPageAction(port, -1, type, number, address, page, pageSize);
if (t != 1)
if (wFlag)
fprintf(logFile, "%s: CONFIG write to NVRAM, type %x, number %x: FAIL\n",
logPrefix(port), type, number);
return t;
}
int
showConfigPage(MPT_PORT *port, char *string, void *page, int length)
{
ConfigPageHeader_t *header;
int n;
int numAvailDwords;
header = (pConfigPageHeader_t)page;
if ((header->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED)
n = get16(((pConfigExtendedPageHeader_t)header)->ExtPageLength);
else
n = header->PageLength;
numAvailDwords = min(n, length/4);
dumpMemory(page, numAvailDwords * 4, string);
if (n > length/4)
printf("WARNING: %s Truncated. %d dwords printed but page contains %d dwords\n", string, length/4, n);
return 1;
}
#if __sparc__
int
getProperty(MPT_PORT *port, char *name, char *buf, int bufLen)
{
SYM_GET_PROPERTY getProperty;
getProperty.PtrName = (UINT64)(UINT32)name;
getProperty.PtrBuffer = (UINT64)(UINT32)buf;
getProperty.NameLen = strlen(name);
getProperty.BufferLen = bufLen;
getProperty.PropertyLen = 0;
if (ioctl(port->fileHandle, SYMIOCTL_GET_PROPERTY, &getProperty) == 0)
return getProperty.PropertyLen;
return 0;
}
#endif
void
setName(MPT_PORT *port, int bus, int target, void *req)
{
SCSIIORequest_t *req1 = (pSCSIIORequest_t)req;
Mpi2SCSIIORequest_t *req2 = (pMpi2SCSIIORequest_t)req;
int dev_handle;
if (mpi2)
{
if (mapBusTargetToDevHandle(port, bus, target, &dev_handle) != 1)
dev_handle = 0;
req2->DevHandle = set16(dev_handle);
}
else
{
req1->TargetID = mapOsToHwTarget(port, target);
req1->Bus = bus;
}
}
int
setMaxBusTarget(MPT_PORT *port)
{
/* DOS, EFI, and SAS2 Solaris do not support devHandle to
* bus/target mapping so we "fudge" things here
*/
#if DOS || EFI || __sparc__
int n;
n = port->maxDevHandle;
if (n > 256)
{
port->maxBuses = (n + 255) / 256;
port->maxTargets = 256;
}
else
{
port->maxBuses = 1;
port->maxTargets = n;
}
#else
int maxBuses;
int minTargets;
int maxTargets;
int bus;
int target;
int devHandle;
maxBuses = 0;
minTargets = 0xffff;
maxTargets = 0;
for (devHandle = 0; devHandle < port->maxDevHandle; devHandle++)
{
if (mapDevHandleToBusTarget(port, devHandle, &bus, &target) == 1)
{
if (bus > maxBuses)
maxBuses = bus;
if (target < minTargets)
minTargets = target;
if (target > maxTargets)
maxTargets = target;
}
}
port->maxBuses = maxBuses + 1;
port->minTargets = minTargets == 0xffff ? 0 : minTargets;
port->maxTargets = maxTargets + 1;
#endif
return 1;
}
int
mapDevHandleToBusTarget(MPT_PORT *port, int dev_handle, int *bus, int *target)
{
int t;
if (port == mappedPort && dev_handle == mappedDevHandle)
{
*bus = mappedBus;
*target = mappedTarget;
#if __sparc__
if (*bus == 0xffff || *target == 0xffff)
return 0;
#endif
if (*bus == 0xffffffff || *target == 0xffffffff)
return 0;
else
return 1;
}
*bus = 0xffffffff;
*target = 0xffffffff;
t = mapBTDH(port, bus, target, &dev_handle);
if (t == 1)
{
mappedPort = port;
mappedBus = *bus;
mappedTarget = *target;
mappedDevHandle = dev_handle;
#if __sparc__
if (*bus == 0xffff || *target == 0xffff)
t = 0;
#endif
if (*bus == 0xffffffff || *target == 0xffffffff)
t = 0;
}
return t;
}
int
mapBusTargetToDevHandle(MPT_PORT *port, int bus, int target, int *dev_handle)
{
int t;
if (port == mappedPort && bus == mappedBus && target == mappedTarget)
{
*dev_handle = mappedDevHandle;
if (*dev_handle == 0xffff)
return 0;
else
return 1;
}
*dev_handle = 0xffff;
t = mapBTDH(port, &bus, &target, dev_handle);
if (t == 1)
{
mappedPort = port;
mappedBus = bus;
mappedTarget = target;
mappedDevHandle = *dev_handle;
if (*dev_handle == 0xffff)
t = 0;
}
return t;
}
int
mapBTDH(MPT_PORT *port, int *bus, int *target, int *dev_handle)
{
#if WIN32
int status;
MPI_BTDH_MAP_SRB srb;
int inLen;
int outLen;
DWORD retLen;
memset(&srb, 0, sizeof srb);
srb.Sic.Length = sizeof srb - sizeof srb.Sic;
srb.Sic.ControlCode = MPI_BTDH_MAPPING;
srb.Sic.HeaderLength = sizeof srb.Sic;
srb.Sic.Timeout = SHORT_TIME;
memcpy((char *)&srb.Sic.Signature, "4.00 ", 8);
srb.Bus = *bus;
srb.TargetID = *target;
srb.DevHandle = *dev_handle;
inLen = sizeof srb;
outLen = sizeof srb;
retLen = 0;
status = DeviceIoControl(port->fileHandle, port->ioctlValue,
&srb, inLen, &srb, outLen, &retLen, NULL);
*bus = srb.Bus;
*target = srb.TargetID;
*dev_handle = srb.DevHandle;
return status;
#endif
#if __linux__
int status;
struct mpt2_ioctl_btdh_mapping btdh_mapping;
memset(&btdh_mapping, 0, sizeof btdh_mapping);
btdh_mapping.hdr.ioc_number = port->portNumber;
btdh_mapping.bus = *bus;
btdh_mapping.id = *target;
btdh_mapping.handle = *dev_handle;
status = ioctl(port->fileHandle, MPT2BTDHMAPPING, &btdh_mapping);
*bus = btdh_mapping.bus;
*target = btdh_mapping.id;
*dev_handle = btdh_mapping.handle;
return status == 0;
#endif
#if __sparc__
int status;
SYM_BTDH_MAPPING btdhMapping;
if (port->ioctlValue == MPTIOCTL_PASS_THRU) // this matches the mpt_sas driver
{
if (*bus == 0xffffffff && *target == 0xffffffff && *dev_handle != 0xffff)
{
*bus = (*dev_handle >> 8) & 0xff;
*target = (*dev_handle >> 0) & 0xff;
return 1;
}
if (*bus != 0xffffffff && *target != 0xffffffff && *dev_handle == 0xffff)
{
*dev_handle = ((*bus & 0xff) << 8) | ((*target & 0xff) << 0);
return 1;
}
return 0;
}
else // legacy support for the lsimpt SAS2 driver
{
btdhMapping.Bus = *bus;
btdhMapping.TargetID = *target;
btdhMapping.DevHandle = *dev_handle;
status = ioctl(port->fileHandle, SYMIOCTL_BTDH_MAPPING, &btdhMapping);
*bus = btdhMapping.Bus;
*target = btdhMapping.TargetID;
*dev_handle = btdhMapping.DevHandle;
return status == 0;
}
#endif
#if DOS || EFI
if (*bus == 0xffffffff && *target == 0xffffffff && *dev_handle != 0xffff)
{
*bus = (*dev_handle >> 8) & 0xff;
*target = (*dev_handle >> 0) & 0xff;
return 1;
}
if (*bus != 0xffffffff && *target != 0xffffffff && *dev_handle == 0xffff)
{
*dev_handle = ((*bus & 0xff) << 8) | ((*target & 0xff) << 0);
return 1;
}
return 0;
#endif
}
int
mapOsToHwTarget(MPT_PORT *port, int target)
{
#if __sparc__
if (port->pidType == MPI_FW_HEADER_PID_TYPE_FC)
{
char name[32];
char buffer[16];
U32 wwnh;
U32 wwnl;
U32 port_id;
FCDevicePage0_t FCDevicePage0;
int i;
int t;
if (port == mappedPort && target == mappedTarget)
return mappedValue;
mappedPort = port;
mappedTarget = target;
mappedValue = port->hostScsiId;
sprintf(name, "target-%d-wwn-nv", target);
t = getProperty(port, name, buffer, sizeof buffer);
if (t != 8)
{
sprintf(name, "target-%d-wwn-cf", target);
t = getProperty(port, name, buffer, sizeof buffer);
}
if (t != 8)
{
sprintf(name, "target-%d-wwn-hw", target);
t = getProperty(port, name, buffer, sizeof buffer);
}
if (t == 8)
{
#if i386
wwnl = ((U32 *)buffer)[0];
wwnh = ((U32 *)buffer)[1];
#else
wwnh = ((U32 *)buffer)[0];
wwnl = ((U32 *)buffer)[1];
#endif
for (i = 0; i < 256; i++)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_DEVICE, 0,
MPI_FC_DEVICE_PGAD_FORM_BUS_TID + i,
&FCDevicePage0, sizeof FCDevicePage0) == 1)
{
if (wwnh == get32(FCDevicePage0.WWPN.High) &&
wwnl == get32(FCDevicePage0.WWPN.Low))
{
mappedValue = i;
return i;
}
}
}
return mappedValue;
}
sprintf(name, "target-%d-did-nv", target);
t = getProperty(port, name, buffer, sizeof buffer);
if (t != 4)
{
sprintf(name, "target-%d-did-cf", target);
t = getProperty(port, name, buffer, sizeof buffer);
}
if (t != 4)
{
sprintf(name, "target-%d-did-hw", target);
t = getProperty(port, name, buffer, sizeof buffer);
}
if (t == 4)
{
port_id = ((U32 *)buffer)[0];
for (i = 0; i < 256; i++)
{
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_FC_DEVICE, 0,
MPI_FC_DEVICE_PGAD_FORM_BUS_TID + i,
&FCDevicePage0, sizeof FCDevicePage0) == 1)
{
if (port_id == get32(FCDevicePage0.PortIdentifier))
{
mappedValue = i;
return i;
}
}
}
return mappedValue;
}
target = port->hostScsiId;
}
#endif
return target;
}
int
doTestUnitReady(MPT_PORT *port, int bus, int target, int lun)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 6;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(tagType);
req.CDB[0] = 0x00;
req.CDB[1] = 0;
req.CDB[2] = 0;
req.CDB[3] = 0;
req.CDB[4] = 0;
req.CDB[5] = 0;
return doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, NULL, 0, NULL, 0, IO_TIME);
}
int
doInquiry(MPT_PORT *port, int bus, int target, int lun, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 6;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_READ | tagType);
req.CDB[0] = 0x12;
req.CDB[1] = 0;
req.CDB[2] = 0;
req.CDB[3] = 0;
req.CDB[4] = len;
req.CDB[5] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, buf, len, NULL, 0, IO_TIME);
}
int
doInquiryVpdPage(MPT_PORT *port, int bus, int target, int lun, int page, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 6;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_READ | tagType);
req.CDB[0] = 0x12;
req.CDB[1] = 1;
req.CDB[2] = page;
req.CDB[3] = 0;
req.CDB[4] = len;
req.CDB[5] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, buf, len, NULL, 0, IO_TIME);
}
int
doLogSense(MPT_PORT *port, int bus, int target, int lun, int page, int pc, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 10;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_READ | tagType);
req.CDB[0] = 0x4d;
req.CDB[1] = 0;
req.CDB[2] = (pc << 6) | page;
req.CDB[3] = 0;
req.CDB[4] = 0;
req.CDB[5] = 0;
req.CDB[6] = 0;
req.CDB[7] = len >> 8;
req.CDB[8] = len;
req.CDB[9] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, buf, len, NULL, 0, IO_TIME);
}
int
doLogSelect(MPT_PORT *port, int bus, int target, int lun, int pc, int sp, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 10;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_WRITE | tagType);
req.CDB[0] = 0x4c;
req.CDB[1] = sp << 0;
req.CDB[2] = pc << 6;
req.CDB[3] = 0;
req.CDB[4] = 0;
req.CDB[5] = 0;
req.CDB[6] = 0;
req.CDB[7] = len >> 8;
req.CDB[8] = len;
req.CDB[9] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, NULL, 0, buf, len, IO_TIME);
}
int
doReadBlockLimits(MPT_PORT *port, int bus, int target, int lun, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 6;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_READ | tagType);
req.CDB[0] = 0x05;
req.CDB[1] = 0;
req.CDB[2] = 0;
req.CDB[3] = 0;
req.CDB[4] = 0;
req.CDB[5] = 0;
req.CDB[6] = 0;
req.CDB[7] = 0;
req.CDB[8] = 0;
req.CDB[9] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, buf, len, NULL, 0, IO_TIME);
}
int
doReadCapacity(MPT_PORT *port, int bus, int target, int lun, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 10;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_READ | tagType);
req.CDB[0] = 0x25;
req.CDB[1] = 0;
req.CDB[2] = 0;
req.CDB[3] = 0;
req.CDB[4] = 0;
req.CDB[5] = 0;
req.CDB[6] = 0;
req.CDB[7] = 0;
req.CDB[8] = 0;
req.CDB[9] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, buf, len, NULL, 0, IO_TIME);
}
int
doReadCapacity16(MPT_PORT *port, int bus, int target, int lun, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 16;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_READ | tagType);
req.CDB[0] = 0x9e;
req.CDB[1] = 0x10;
req.CDB[2] = 0;
req.CDB[3] = 0;
req.CDB[4] = 0;
req.CDB[5] = 0;
req.CDB[6] = 0;
req.CDB[7] = 0;
req.CDB[8] = 0;
req.CDB[9] = 0;
req.CDB[10] = len >> 24;
req.CDB[11] = len >> 16;
req.CDB[12] = len >> 8;
req.CDB[13] = len;
req.CDB[14] = 0;
req.CDB[15] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, buf, len, NULL, 0, IO_TIME);
}
int
doModeSense(MPT_PORT *port, int bus, int target, int lun, int page, int control, int dbd, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 6;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_READ | tagType);
req.CDB[0] = 0x1a;
req.CDB[1] = (dbd << 3);
req.CDB[2] = page | (control << 6);
req.CDB[3] = 0;
req.CDB[4] = len;
req.CDB[5] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, buf, len, NULL, 0, IO_TIME);
}
int
doModeSelect(MPT_PORT *port, int bus, int target, int lun, int save, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 6;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_WRITE | tagType);
req.CDB[0] = 0x15;
req.CDB[1] = (1 << 4) | (save << 0);
req.CDB[2] = 0;
req.CDB[3] = 0;
req.CDB[4] = len;
req.CDB[5] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, NULL, 0, buf, len, IO_TIME);
}
int
doReadBuffer(MPT_PORT *port, int bus, int target, int lun, int mode, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 10;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_READ | tagType);
req.CDB[0] = 0x3c;
req.CDB[1] = mode;
req.CDB[2] = 0;
req.CDB[3] = 0;
req.CDB[4] = 0;
req.CDB[5] = 0;
req.CDB[6] = len >> 16;
req.CDB[7] = len >> 8;
req.CDB[8] = len;
req.CDB[9] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, buf, len, NULL, 0, IO_TIME);
}
int
doWriteBuffer(MPT_PORT *port, int bus, int target, int lun, int mode, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 10;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_WRITE | tagType);
req.CDB[0] = 0x3b;
req.CDB[1] = mode;
req.CDB[2] = 0;
req.CDB[3] = 0;
req.CDB[4] = 0;
req.CDB[5] = 0;
req.CDB[6] = len >> 16;
req.CDB[7] = len >> 8;
req.CDB[8] = len;
req.CDB[9] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, NULL, 0, buf, len, IO_TIME);
}
int
doReadBufferFull(MPT_PORT *port, int bus, int target, int lun, int mode, int id, int offset, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 10;
req.LUN[1] = lun;
req.AliasIndex = virtInit;
req.Control = set32(MPI_SCSIIO_CONTROL_READ | tagType);
req.CDB[0] = 0x3c;
req.CDB[1] = mode;
req.CDB[2] = id;
req.CDB[3] = offset >> 16;
req.CDB[4] = offset >> 8;
req.CDB[5] = offset;
req.CDB[6] = len >> 16;
req.CDB[7] = len >> 8;
req.CDB[8] = len;
req.CDB[9] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, buf, len, NULL, 0, LONG_TIME);
}
int
doWriteBufferFull(MPT_PORT *port, int bus, int target, int lun, int mode, int id, int offset, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 10;
req.LUN[1] = lun;
req.AliasIndex = virtInit;
req.Control = set32(MPI_SCSIIO_CONTROL_WRITE | tagType);
req.CDB[0] = 0x3b;
req.CDB[1] = mode;
req.CDB[2] = id;
req.CDB[3] = offset >> 16;
req.CDB[4] = offset >> 8;
req.CDB[5] = offset;
req.CDB[6] = len >> 16;
req.CDB[7] = len >> 8;
req.CDB[8] = len;
req.CDB[9] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, NULL, 0, buf, len, LONG_TIME);
}
int
doRead(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int lbns, int mode, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
int raid = port->raidPassthru && bus == port->raidBus && target == port->raidTarget;
if (mode & 0xf0f)
return doRead32(port, bus, target, lun, lbn, lbns, mode, buf, len);
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 10;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_READ | tagType);
req.CDB[0] = 0x28;
req.CDB[1] = mode & 0xf0;
req.CDB[2] = lbn >> 24;
req.CDB[3] = lbn >> 16;
req.CDB[4] = lbn >> 8;
req.CDB[5] = lbn;
req.CDB[6] = 0;
req.CDB[7] = lbns >> 8;
req.CDB[8] = lbns;
req.CDB[9] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, raid, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, buf, len, NULL, 0, IO_TIME);
}
int
doWrite(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int lbns, int mode, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
int raid = port->raidPassthru && bus == port->raidBus && target == port->raidTarget;
if (mode & 0xf0f)
return doWrite32(port, bus, target, lun, lbn, lbns, mode, buf, len);
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 10;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_WRITE | tagType);
req.CDB[0] = 0x2a;
req.CDB[1] = mode & 0xf0;
req.CDB[2] = lbn >> 24;
req.CDB[3] = lbn >> 16;
req.CDB[4] = lbn >> 8;
req.CDB[5] = lbn;
req.CDB[6] = 0;
req.CDB[7] = lbns >> 8;
req.CDB[8] = lbns;
req.CDB[9] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, raid, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, NULL, 0, buf, len, IO_TIME);
}
int
doVerify(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int lbns, int mode, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
int raid = port->raidPassthru && bus == port->raidBus && target == port->raidTarget;
// if (mode)
// return doVerify32(port, bus, target, lun, lbn, lbns, mode, buf, len);
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 10;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_WRITE | tagType);
req.CDB[0] = 0x2f;
req.CDB[1] = len ? (1<<1) : 0;
req.CDB[2] = lbn >> 24;
req.CDB[3] = lbn >> 16;
req.CDB[4] = lbn >> 8;
req.CDB[5] = lbn;
req.CDB[6] = 0;
req.CDB[7] = lbns >> 8;
req.CDB[8] = lbns;
req.CDB[9] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, raid, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, NULL, 0, buf, len, IO_TIME);
}
int
doRead32(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int lbns, int mode, unsigned char *buf, int len)
{
SCSIIO32Request_t req;
SCSI_REPLY rep;
unsigned char *buf2 = buf;
int len2 = len;
int t;
int flags;
if (mode == 0x201)
{
len += lbns * 8;
buf = malloc(len);
t = doRead(port, bus, target, lun, lbn, lbns, 0x20, buf, len);
if (t == 1)
{
t = checkRemoveT10(port, lbn, lbns, buf, buf2, len2);
}
free(buf);
return t;
}
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_32;
req.AliasIndex = virtInit;
req.CDBLength = 10;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO32_CONTROL_READ | tagType);
req.CDB.EEDP16.CDB[0] = 0x28;
req.CDB.EEDP16.CDB[1] = 0;
req.CDB.EEDP16.CDB[2] = lbn >> 24;
req.CDB.EEDP16.CDB[3] = lbn >> 16;
req.CDB.EEDP16.CDB[4] = lbn >> 8;
req.CDB.EEDP16.CDB[5] = lbn;
req.CDB.EEDP16.CDB[6] = 0;
req.CDB.EEDP16.CDB[7] = lbns >> 8;
req.CDB.EEDP16.CDB[8] = lbns;
req.CDB.EEDP16.CDB[9] = 0;
req.CDB.EEDP16.PrimaryReferenceTag = set32(swap32(lbn));
req.CDB.EEDP16.PrimaryApplicationTagMask = set16(0xffff);
req.DataLength = set32(len);
req.DeviceAddress.SCSIID.Bus = bus;
req.DeviceAddress.SCSIID.TargetID = mapOsToHwTarget(port, target);
flags = MPI_SCSIIO32_EEDPFLAGS_INC_PRI_REFTAG |
MPI_SCSIIO32_EEDPFLAGS_T10_CHK_GUARD |
MPI_SCSIIO32_EEDPFLAGS_T10_CHK_REFTAG |
MPI_SCSIIO32_EEDPFLAGS_T10_CHK_LBATAG;
if (mode == 0x101)
{
len += lbns * 8;
buf = malloc(len);
flags |= MPI_SCSIIO32_EEDPFLAGS_CHK_OP;
req.CDB.EEDP16.CDB[1] = 0x20;
req.DataLength = set32(len);
req.EEDPBlockSize = set32(512 + 8);
}
if (mode == 0x1)
{
flags |= MPI_SCSIIO32_EEDPFLAGS_CHKRM_OP;
req.CDB.EEDP16.CDB[1] = 0x20;
req.EEDPBlockSize = set32(512 + 8);
}
if (mode == 0x102 || mode == 0x2)
{
len += lbns * 8;
buf = malloc(len);
flags |= MPI_SCSIIO32_EEDPFLAGS_CHK_OP;
req.CDB.EEDP16.CDB[5] = lbn & ~7;
req.DataLength = set32(len);
req.EEDPBlockSize = set32(4096 + 64);
}
req.EEDPFlags = set16(flags);
t = doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, buf, len, NULL, 0, IO_TIME);
if (mode == 0x101)
{
if (t == 1)
{
t = checkRemoveT10(port, lbn, lbns, buf, buf2, len2);
}
free(buf);
}
if (mode == 0x102)
{
if (t == 1)
{
// LB CRC not done yet...
// t = checkRemoveLb(port, lbn, lbns, buf, buf2, len2, 1);
t = checkRemoveLb(port, lbn, lbns, buf, buf2, len2, 0);
}
free(buf);
}
if (mode == 0x2)
{
if (t == 1)
{
t = checkRemoveLb(port, lbn, lbns, buf, buf2, len2, 0);
}
free(buf);
}
return t;
}
int
doWrite32(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int lbns, int mode, unsigned char *buf, int len)
{
SCSIIO32Request_t req;
SCSI_REPLY rep;
unsigned char *buf2 = buf;
int t;
int flags;
if (mode == 0x201)
{
len += lbns * 8;
buf = malloc(len);
insertT10(port, lbn, lbns, buf2, buf, len);
t = doWrite(port, bus, target, lun, lbn, lbns, 0x20, buf, len);
free(buf);
return t;
}
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_32;
req.AliasIndex = virtInit;
req.CDBLength = 10;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO32_CONTROL_WRITE | tagType);
req.CDB.EEDP16.CDB[0] = 0x2a;
req.CDB.EEDP16.CDB[1] = 0;
req.CDB.EEDP16.CDB[2] = lbn >> 24;
req.CDB.EEDP16.CDB[3] = lbn >> 16;
req.CDB.EEDP16.CDB[4] = lbn >> 8;
req.CDB.EEDP16.CDB[5] = lbn;
req.CDB.EEDP16.CDB[6] = 0;
req.CDB.EEDP16.CDB[7] = lbns >> 8;
req.CDB.EEDP16.CDB[8] = lbns;
req.CDB.EEDP16.CDB[9] = 0;
req.CDB.EEDP16.PrimaryReferenceTag = set32(swap32(lbn));
req.CDB.EEDP16.PrimaryApplicationTagMask = set16(0xffff);
req.DataLength = set32(len);
req.DeviceAddress.SCSIID.Bus = bus;
req.DeviceAddress.SCSIID.TargetID = mapOsToHwTarget(port, target);
flags = MPI_SCSIIO32_EEDPFLAGS_INC_PRI_REFTAG |
MPI_SCSIIO32_EEDPFLAGS_T10_CHK_GUARD |
MPI_SCSIIO32_EEDPFLAGS_T10_CHK_REFTAG |
MPI_SCSIIO32_EEDPFLAGS_T10_CHK_LBATAG;
if (mode == 0x101)
{
len += lbns * 8;
buf = malloc(len);
flags |= MPI_SCSIIO32_EEDPFLAGS_NOOP_OP;
req.CDB.EEDP16.CDB[1] = 0x20;
req.DataLength = set32(len);
// req.EEDPFlags |= set16(MPI_SCSIIO32_EEDPFLAGS_CHK_OP);
req.EEDPBlockSize = set32(512 + 8);
insertT10(port, lbn, lbns, buf2, buf, len);
}
if (mode == 0x1)
{
flags |= MPI_SCSIIO32_EEDPFLAGS_INSERT_OP;
req.CDB.EEDP16.CDB[1] = 0x20;
req.DataLength = set32(len);
req.EEDPBlockSize = set32(512 + 8);
}
if (mode == 0x102)
{
len += lbns * 8;
buf = malloc(len);
// LB CRC not done yet...
// flags |= MPI_SCSIIO32_EEDPFLAGS_CHKREGEN_OP;
flags |= MPI_SCSIIO32_EEDPFLAGS_REPLACE_OP;
req.CDB.EEDP16.CDB[5] = lbn & ~7;
req.DataLength = set32(len);
req.EEDPBlockSize = set32(4096 + 64);
insertLb(port, lbn, lbns, buf2, buf, len, 1);
}
if (mode == 0x2)
{
len += lbns * 8;
buf = malloc(len);
flags |= MPI_SCSIIO32_EEDPFLAGS_REPLACE_OP;
req.CDB.EEDP16.CDB[5] = lbn & ~7;
req.DataLength = set32(len);
req.EEDPBlockSize = set32(4096 + 64);
insertLb(port, lbn, lbns, buf2, buf, len, 0);
}
req.EEDPFlags = set16(flags);
t = doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, NULL, 0, buf, len, IO_TIME);
if (mode == 0x101 || mode == 0x102 || mode == 0x2)
{
free(buf);
}
return t;
}
int
doReadLong(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int mode, unsigned char *buf, int len, int *resid)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
int raid = port->raidPassthru && bus == port->raidBus && target == port->raidTarget;
int t;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 10;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_READ | tagType);
req.CDB[0] = 0x3e;
req.CDB[1] = 0;
req.CDB[2] = lbn >> 24;
req.CDB[3] = lbn >> 16;
req.CDB[4] = lbn >> 8;
req.CDB[5] = lbn;
req.CDB[6] = 0;
req.CDB[7] = len >> 8;
req.CDB[8] = len;
req.CDB[9] = 0;
req.DataLength = set32(len);
t = doScsiIo(port, bus, target, raid, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, buf, len, NULL, 0, IO_TIME);
if (t == 1)
{
*resid = 0;
return 1;
}
else if (rep.reply.SCSIStatus == MPI_SCSI_STATUS_CHECK_CONDITION)
{
if (rep.sense[0] == 0xf0 && rep.sense[2] & 0x20)
{
*resid = get4bytes(rep.sense, 3);
return 1;
}
}
return 0;
}
int
doWriteLong(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int mode, unsigned char *buf, int len, int *resid)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
int raid = port->raidPassthru && bus == port->raidBus && target == port->raidTarget;
int t;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 10;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_WRITE | tagType);
req.CDB[0] = 0x3f;
req.CDB[1] = len ? 0 : (unsigned char)(1<<6);
req.CDB[2] = lbn >> 24;
req.CDB[3] = lbn >> 16;
req.CDB[4] = lbn >> 8;
req.CDB[5] = lbn;
req.CDB[6] = 0;
req.CDB[7] = len >> 8;
req.CDB[8] = len;
req.CDB[9] = 0;
req.DataLength = set32(len);
t = doScsiIo(port, bus, target, raid, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, NULL, 0, buf, len, IO_TIME);
if (t == 1)
{
*resid = 0;
return 1;
}
else if (rep.reply.SCSIStatus == MPI_SCSI_STATUS_CHECK_CONDITION)
{
if (rep.sense[0] == 0xf0 && rep.sense[2] & 0x20)
{
*resid = get4bytes(rep.sense, 3);
return 1;
}
}
return 0;
}
int
doReportLuns(MPT_PORT *port, int bus, int target, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
int t;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 12;
req.AliasIndex = virtInit;
req.Control = set32(MPI_SCSIIO_CONTROL_READ | tagType);
req.CDB[0] = 0xa0;
req.CDB[1] = 0;
req.CDB[2] = 0;
req.CDB[3] = 0;
req.CDB[4] = 0;
req.CDB[5] = 0;
req.CDB[6] = len >> 24;
req.CDB[7] = len >> 16;
req.CDB[8] = len >> 8;
req.CDB[9] = len;
req.CDB[10] = 0;
req.CDB[11] = 0;
req.DataLength = set32(len);
t = doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, buf, len, NULL, 0, IO_TIME);
if (t == 1)
{
return 1;
}
else if (rep.reply.SCSIStatus == MPI_SCSI_STATUS_CHECK_CONDITION)
{
if (rep.sense[0] == 0xf0 && rep.sense[2] & 0x20)
{
return 1;
}
}
return 0;
}
int
doReceiveDiagnosticResults(MPT_PORT *port, int bus, int target, int lun, int page, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 6;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_READ | tagType);
req.CDB[0] = 0x1c;
req.CDB[1] = 1;
req.CDB[2] = page;
req.CDB[3] = len >> 8;
req.CDB[4] = len;
req.CDB[5] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, buf, len, NULL, 0, IO_TIME);
}
int
doSendDiagnostic(MPT_PORT *port, int bus, int target, int lun, unsigned char *buf, int len)
{
SCSIIORequest_t req;
SCSI_REPLY rep;
memset(&req, 0, sizeof req);
req.Function = MPI_FUNCTION_SCSI_IO_REQUEST;
req.CDBLength = 6;
req.AliasIndex = virtInit;
req.LUN[1] = lun;
req.Control = set32(MPI_SCSIIO_CONTROL_WRITE | tagType);
req.CDB[0] = 0x1d;
req.CDB[1] = 1 << 4;
req.CDB[2] = 0;
req.CDB[3] = len >> 8;
req.CDB[4] = len;
req.CDB[5] = 0;
req.DataLength = set32(len);
return doScsiIo(port, bus, target, 0, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep, NULL, 0, buf, len, LONG_TIME);
}
int
doScsiIo(MPT_PORT *port, int bus, int target, int raid, void *req, int reqSize, SCSI_REPLY *rep1, int rep1Size,
void *payIn, int payInSize, void *payOut, int payOutSize, int timeOut)
{
int ioc_status;
int ioc_loginfo;
SCSIIORequest_t *req1;
Mpi2SCSIIORequest_t req2;
Mpi25SCSIIORequest_t req25;
SCSI_REPLY2 rep2;
void *rep;
int repSize;
int command = -1;
req1 = req;
if (req1->Function == MPI_FUNCTION_SCSI_IO_REQUEST)
{
command = req1->CDB[0];
setName(port, bus, target, req1);
if (raid)
{
req1->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
if (mpi1)
setName(port, 0, port->raidPhysdisk, req1);
}
if (mpi20)
{
memset(&req2, 0, sizeof req2);
// convert from MPI 1.x format to MPI 2.x format
req2.Function = req1->Function;
req2.DevHandle = ((pMpi2SCSIIORequest_t)req1)->DevHandle;
req2.Control = req1->Control;
req2.IoFlags = set16(req1->CDBLength);
req2.DataLength = req1->DataLength;
memcpy(req2.LUN, req1->LUN, sizeof req1->LUN);
memcpy(req2.CDB.CDB32, req1->CDB, sizeof req1->CDB);
req2.SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
req = &req2;
reqSize = sizeof req2 - sizeof req2.SGL;
}
else if (mpi25)
{
memset(&req25, 0, sizeof req25);
// convert from MPI 1.x format to MPI 2.5 format
req25.Function = req1->Function;
req25.DevHandle = ((pMpi25SCSIIORequest_t)req1)->DevHandle;
req25.Control = req1->Control;
req25.IoFlags = set16(req1->CDBLength);
req25.DataLength = req1->DataLength;
memcpy(req25.LUN, req1->LUN, sizeof req1->LUN);
memcpy(req25.CDB.CDB32, req1->CDB, sizeof req1->CDB);
req25.SGLOffset0 = offsetof(Mpi25SCSIIORequest_t, SGL) / 4;
req = &req25;
reqSize = sizeof req25 - sizeof req25.SGL;
}
}
if (mpi2)
{
rep = &rep2;
repSize = sizeof rep2;
}
else
{
rep = rep1;
repSize = rep1Size;
}
memset(rep, 0, repSize);
if (doMptCommand(port, req, reqSize, rep, repSize,
payIn, payInSize, payOut, payOutSize, timeOut) != 1)
{
#if __linux__
if (errno == EFAULT)
printf("SCSI command failed, mptscsih might not be loaded\n");
#endif
return 0;
}
if (mpi2)
{
memcpy(&rep1->reply, &rep2.reply, sizeof rep1->reply);
memcpy(&rep1->sense, &rep2.sense, sizeof rep1->sense);
}
ioc_status = get16(rep1->reply.IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status == MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE)
return 0;
if (ioc_status == MPI_IOCSTATUS_BUSY ||
ioc_status == MPI_IOCSTATUS_SCSI_IOC_TERMINATED ||
ioc_status == MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH ||
(rep1->reply.SCSIStatus == MPI_SCSI_STATUS_CHECK_CONDITION && !(rep1->sense[2] & 0xf0)) ||
rep1->reply.SCSIStatus == MPI_SCSI_STATUS_BUSY ||
rep1->reply.SCSIStatus == MPI_SCSI_STATUS_TASK_SET_FULL)
{
memset(rep, 0, repSize);
if (doMptCommand(port, req, reqSize, rep, repSize,
payIn, payInSize, payOut, payOutSize, timeOut) != 1)
return 0;
if (mpi2)
{
memcpy(&rep1->reply, &rep2.reply, sizeof rep1->reply);
memcpy(&rep1->sense, &rep2.sense, sizeof rep1->sense);
}
ioc_status = get16(rep1->reply.IOCStatus) & MPI_IOCSTATUS_MASK;
}
if (ioc_status != MPI_IOCSTATUS_SUCCESS)
{
if (ioc_status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN ||
ioc_status == MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH)
{
if (rep1->reply.SCSIStatus == MPI_SCSI_STATUS_SUCCESS)
{
if (rep1->reply.TransferCount == 0)
{
// printf("ScsiIo to Bus %d Target %d failed, IOCStatus = %04x (%s)\n",
// bus, target, ioc_status, translateIocStatus(ioc_status));
return 0;
}
else
return 1;
}
}
else
{
if ((get16(rep1->reply.IOCStatus) & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) != 0)
{
ioc_loginfo = get32(rep1->reply.IOCLogInfo);
printf("ScsiIo to Bus %d Target %d failed, IOCStatus = %04x (%s), IOCLogInfo = %08x\n",
bus, target, ioc_status, translateIocStatus(ioc_status), ioc_loginfo);
}
else
printf("ScsiIo to Bus %d Target %d failed, IOCStatus = %04x (%s)\n",
bus, target, ioc_status, translateIocStatus(ioc_status));
return 0;
}
}
if (rep1->reply.SCSIStatus != MPI_SCSI_STATUS_SUCCESS)
{
if (rep1->reply.SCSIStatus == MPI_SCSI_STATUS_CHECK_CONDITION)
{
if (rep1->sense[2] == 5 && rep1->sense[12] == 0x20 && rep1->sense[13] == 0x00)
if (payInSize == 36 || payInSize == 32)
return 0;
if (rep1->sense[2] == 5 && rep1->sense[12] == 0x24 && rep1->sense[13] == 0x00)
if (payInSize == 36 || payInSize == 32 || (command == 0x3c && payInSize <= 4))
return 0;
if (rep1->sense[2] == 5 && rep1->sense[12] == 0x25 && rep1->sense[13] == 0x00)
if (payInSize == 36 || payInSize == 32 || (command == 0x3c && payInSize <= 4))
return 0;
if (rep1->sense[2] == 0 && rep1->sense[12] == 0x00 && rep1->sense[13] == 0x00)
return 0;
if (rep1->sense[2] == 4 && rep1->sense[12] == 0x44 && rep1->sense[13] == 0x00)
return 0;
if (rep1->sense[2] == 0x08)
return 0;
if (rep1->sense[0] == 0xf0 && rep1->sense[2] & 0xf0)
return 0;
if (rep1->sense[0] & 0x80)
printf("ScsiIo to Bus %d Target %d failed, Check Condition, Key = %d, ASC/ASCQ = %02Xh/%02Xh, Info = %08Xh (%d)\n",
bus, target, rep1->sense[2] & 0x0f, rep1->sense[12], rep1->sense[13], get4bytes(rep1->sense, 3), get4bytes(rep1->sense, 3));
else
printf("ScsiIo to Bus %d Target %d failed, Check Condition, Key = %d, ASC/ASCQ = %02Xh/%02Xh\n",
bus, target, rep1->sense[2] & 0x0f, rep1->sense[12], rep1->sense[13]);
// dumpMemory(rep1->sense, get32(rep1->reply.SenseCount), "Sense Data");
}
else
{
printf("ScsiIo to Bus %d Target %d failed, SCSIStatus = %02x\n",
bus, target, rep1->reply.SCSIStatus);
}
return 0;
}
return 1;
}
int
doReadLongSata(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int mode, unsigned char *buf, int len)
{
SataPassthroughRequest_t req;
SataPassthroughReply_t rep;
unsigned char cmd[512];
memset(cmd, 0, sizeof cmd);
cmd[0] = 1;
cmd[2] = 1;
cmd[4] = lbn;
cmd[5] = lbn >> 8;
cmd[6] = lbn >> 16;
cmd[7] = lbn >> 24;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SATA_PASSTHROUGH;
req.PassthroughFlags = set16(MPI_SATA_PT_REQ_PT_FLAGS_PIO | MPI_SATA_PT_REQ_PT_FLAGS_WRITE);
req.DataLength = set32(sizeof cmd);
req.CommandFIS[0] = 0x27;
req.CommandFIS[1] = 0x80;
req.CommandFIS[2] = 0xb0;
req.CommandFIS[3] = 0xd6;
req.CommandFIS[4] = 0xe0;
req.CommandFIS[5] = 0x4f;
req.CommandFIS[6] = 0xc2;
req.CommandFIS[12] = 0x01;
setName(port, bus, target, &req);
if (doMptCommandCheck(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
NULL, 0, cmd, sizeof cmd, SHORT_TIME) != 1)
{
printf("SataPassThrough (SCT / Long Sector Read / E0) failed!\n");
return 0;
}
/* if the statusFIS error field has any bits set, then the request was not successful */
if (rep.StatusFIS[3])
{
printf("SataPassThrough (SCT / Long Sector Read / E0) failed!\n");
return 0;
}
// printf("StatusFIS->Error: %02x\n", rep.StatusFIS[3]);
// printf("StatusFIS->Status: %02x\n", rep.StatusFIS[2]);
req.PassthroughFlags = set16(MPI_SATA_PT_REQ_PT_FLAGS_PIO | MPI_SATA_PT_REQ_PT_FLAGS_READ);
req.DataLength = set32(len);
req.CommandFIS[3] = 0xd5;
req.CommandFIS[4] = 0xe1;
req.CommandFIS[12] = 0x02;
if (doMptCommandCheck(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
buf, len, NULL, 0, SHORT_TIME) != 1)
{
printf("SataPassThrough (SCT / Long Sector Read / E1) failed!\n");
return 0;
}
/* if the statusFIS error field has any bits set, then the request was not successful */
if (rep.StatusFIS[3])
{
printf("SataPassThrough (SCT / Long Sector Read / E1) failed!\n");
return 0;
}
// printf("StatusFIS->Error: %02x\n", rep.StatusFIS[3]);
// printf("StatusFIS->Status: %02x\n", rep.StatusFIS[2]);
return 1;
}
int
doWriteLongSata(MPT_PORT *port, int bus, int target, int lun,
unsigned int lbn, int mode, unsigned char *buf, int len)
{
SataPassthroughRequest_t req;
SataPassthroughReply_t rep;
unsigned char cmd[512];
memset(cmd, 0, sizeof cmd);
cmd[0] = 1;
cmd[2] = 2;
cmd[4] = lbn;
cmd[5] = lbn >> 8;
cmd[6] = lbn >> 16;
cmd[7] = lbn >> 24;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SATA_PASSTHROUGH;
req.PassthroughFlags = set16(MPI_SATA_PT_REQ_PT_FLAGS_PIO | MPI_SATA_PT_REQ_PT_FLAGS_WRITE);
req.DataLength = set32(sizeof cmd);
req.CommandFIS[0] = 0x27;
req.CommandFIS[1] = 0x80;
req.CommandFIS[2] = 0xb0;
req.CommandFIS[3] = 0xd6;
req.CommandFIS[4] = 0xe0;
req.CommandFIS[5] = 0x4f;
req.CommandFIS[6] = 0xc2;
req.CommandFIS[12] = 0x01;
setName(port, bus, target, &req);
if (doMptCommandCheck(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
NULL, 0, cmd, sizeof cmd, SHORT_TIME) != 1)
{
printf("SataPassThrough (SCT / Long Sector Write / E0) failed!\n");
return 0;
}
/* if the statusFIS error field has any bits set, then the request was not successful */
if (rep.StatusFIS[3])
{
printf("SataPassThrough (SCT / Long Sector Write / E0) failed!\n");
return 0;
}
// printf("StatusFIS->Error: %02x\n", rep.StatusFIS[3]);
// printf("StatusFIS->Status: %02x\n", rep.StatusFIS[2]);
req.PassthroughFlags = set16(MPI_SATA_PT_REQ_PT_FLAGS_PIO | MPI_SATA_PT_REQ_PT_FLAGS_WRITE);
req.DataLength = set32(len);
req.CommandFIS[3] = 0xd6;
req.CommandFIS[4] = 0xe1;
req.CommandFIS[12] = 0x02;
if (doMptCommandCheck(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
NULL, 0, buf, len, SHORT_TIME) != 1)
{
printf("SataPassThrough (SCT / Long Sector Write / E1) failed!\n");
return 0;
}
/* if the statusFIS error field has any bits set, then the request was not successful */
if (rep.StatusFIS[3])
{
printf("SataPassThrough (SCT / Long Sector Write / E1) failed!\n");
return 0;
}
// printf("StatusFIS->Error: %02x\n", rep.StatusFIS[3]);
// printf("StatusFIS->Status: %02x\n", rep.StatusFIS[2]);
return 1;
}
int
doFwDownload(MPT_PORT *port, int type, unsigned char *buf, int len, int offset)
{
FWDownload_t *req1; // the MPI 1.x request is a subset of the MPI 2.x request
Mpi2FWDownloadRequest req;
Mpi25FWDownloadRequest req25;
FWDownloadReply_t rep;
FWDownloadTCSGE_t *tc;
int req_size;
int size;
int ioc_status;
int inLen = len;
int mpt_return = 0;
memset(&req, 0, sizeof req);
memset(&req25, 0, sizeof req25);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_FW_DOWNLOAD;
req25.Function = MPI2_FUNCTION_FW_DOWNLOAD;
req.ImageType = type;
req25.ImageType = type;
if (mpi20)
{
tc = (pFWDownloadTCSGE_t)&req.SGL;
req_size = sizeof req - sizeof req.SGL + sizeof *tc;
req.TotalImageSize = set32(len);
}
else if (mpi25)
{
req_size = sizeof req25 - sizeof req25.SGL;
req25.TotalImageSize = set32(len);
}
else
{
req1 = (pFWDownload_t)&req;
tc = (pFWDownloadTCSGE_t)&req1->SGL;
req_size = sizeof *req1 - sizeof req1->SGL + sizeof *tc;
}
if(port->mptVersion < MPI2_VERSION_02_05)
{
tc->ContextSize = 0;
tc->DetailsLength = 12;
tc->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
}
if (port->mptVersion < MPI_VERSION_01_01 && type == MPI_FW_DOWNLOAD_ITYPE_BIOS)
{
int i;
U32 data_l;
U32 data_h;
U32 *p_data_l;
U32 *p_data_h;
p_data_l = (U32 *)&buf[0];
p_data_h = (U32 *)&buf[len] - 1;
for (i = 0; i < len / 8; i++)
{
data_l = *p_data_l;
data_h = *p_data_h;
*p_data_l++ = data_h;
*p_data_h-- = data_l;
}
offset += 0x100000;
buf += len;
}
printf("\nDownloading image...\n");
while (len > 0)
{
if (port->mptVersion < MPI_VERSION_01_01)
{
int i;
U32 checksum;
size = min(len, 0x10000);
if (type == MPI_FW_DOWNLOAD_ITYPE_BIOS)
{
offset -= size;
buf -= size;
}
checksum = 0;
for (i = 0; i < size / 4; i++)
checksum -= get32x(((U32 *)buf)[i]);
tc->Reserved_0100_Checksum = set32(checksum);
}
else
{
size = min(len, CHUNK_SIZE);
if (size == len)
{
req.MsgFlags = MPI_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT;
req25.MsgFlags = MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT;
}
}
if ( port->mptVersion >= MPI2_VERSION_02_05 )
{
req25.ImageSize = set32(size);
req25.ImageOffset = set32(offset);
mpt_return = doMptCommand(port, &req25, req_size, &rep, sizeof rep,
NULL, 0, buf, size, LONG_TIME);
}
else
{
tc->ImageSize = set32(size);
tc->ImageOffset = set32(offset);
mpt_return = doMptCommand(port, &req, req_size, &rep, sizeof rep,
NULL, 0, buf, size, LONG_TIME);
}
if ( mpt_return != 1 )
{
printf("Download failed\n");
if (wFlag)
fprintf(logFile, "%s: Firmware Download (FW_DOWNLOAD) of type %d: FAIL\n",
logPrefix(port), type);
return 0;
}
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status != MPI_IOCSTATUS_SUCCESS)
{
printf("Download failed, IOCStatus = %04x (%s)\n", ioc_status, translateIocStatus(ioc_status));
if (wFlag)
fprintf(logFile, "%s: Firmware Download (FW_DOWNLOAD) of type %d: FAIL\n",
logPrefix(port), type);
return 0;
}
len -= size;
if (!(port->mptVersion < MPI_VERSION_01_01 && type == MPI_FW_DOWNLOAD_ITYPE_BIOS))
{
buf += size;
offset += size;
}
} //while(len>0)
printf("Download succeeded\n");
if (wFlag)
fprintf(logFile, "%s: Firmware Download (FW_DOWNLOAD) of type %d size %x: PASS\n",
logPrefix(port), type, inLen);
return 1;
}
int
doFwUpload(MPT_PORT *port, int type, unsigned char *buf, int len, int offset, int *outLen)
{
FWUpload_t *req1;
Mpi2FWUploadRequest_t req;
Mpi25FWUploadRequest_t req25;
FWUploadReply_t rep;
FWUploadTCSGE_t *tc;
int req_size;
int size;
int actual_size;
int ioc_status;
int mpt_return = 0;
memset(&req, 0, sizeof req);
memset(&req25, 0, sizeof req25);
memset(&rep, 0, sizeof rep);
req.Function = req25.Function = MPI_FUNCTION_FW_UPLOAD;
req.ImageType = req25.ImageType = type;
if (mpi20)
{
tc = (pFWUploadTCSGE_t)&req.SGL;
req_size = sizeof req - sizeof req.SGL + sizeof *tc;
}
else if (mpi25)
{
req_size = sizeof(req25) - sizeof(req25.SGL);
}
else
{
req1 = (pFWUpload_t)&req;
tc = (pFWUploadTCSGE_t)&req1->SGL;
req_size = sizeof *req1 - sizeof req1->SGL + sizeof *tc;
}
if(port->mptVersion < MPI2_VERSION_02_05)
{
tc->ContextSize = 0;
tc->DetailsLength = 12;
tc->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
}
actual_size = 0;
while (len > 0)
{
size = min(len, CHUNK_SIZE);
if (mpi25)
{
req25.ImageSize = set32(size);
req25.ImageOffset = set32(offset);
mpt_return = doMptCommand(port, &req25, req_size, &rep, sizeof rep,
buf, size, NULL, 0, LONG_TIME);
}
else
{
tc->ImageSize = set32(size);
tc->ImageOffset = set32(offset);
mpt_return = doMptCommand(port, &req, req_size, &rep, sizeof rep,
buf, size, NULL, 0, LONG_TIME);
}
if (mpt_return != 1)
{
printf("Upload failed\n");
if (wFlag)
fprintf(logFile, "%s: Firmware Upload (FW_UPLOAD) of type %d: FAIL\n",
logPrefix(port), type);
return 0;
}
ioc_status = get16(rep.IOCStatus) & MPI_IOCSTATUS_MASK;
actual_size = get32(rep.ActualImageSize);
if (ioc_status != MPI_IOCSTATUS_SUCCESS)
{
if (ioc_status == MPI_IOCSTATUS_INVALID_FIELD && actual_size != 0)
{
if (offset + size > actual_size)
{
len = actual_size - offset;
continue;
}
}
printf("Upload failed, IOCStatus = %04x (%s)\n", ioc_status, translateIocStatus(ioc_status));
if (wFlag)
fprintf(logFile, "%s: Firmware Upload (FW_UPLOAD) of type %d: FAIL\n",
logPrefix(port), type);
return 0;
}
buf += size;
len -= size;
offset += size;
}
*outLen = actual_size;
if (wFlag)
fprintf(logFile, "%s: Firmware Upload (FW_UPLOAD) of type %d size %x: PASS\n",
logPrefix(port), type, *outLen);
return 1;
}
int
doIocInit(MPT_PORT *port, int WhoInit)
{
IOCInit_t req;
IOCInitReply_t rep;
IOCFactsReply_t IOCFacts;
if (mpi2)
return 1;
if (getIocFacts(port, &IOCFacts) != 1)
return 0;
if (IOCFacts.WhoInit == WhoInit)
return 1;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_IOC_INIT;
req.WhoInit = WhoInit;
req.Flags = 0;
req.MaxDevices = IOCFacts.MaxDevices;
req.MaxBuses = IOCFacts.MaxBuses;
req.ReplyFrameSize = IOCFacts.CurReplyFrameSize;
req.HostMfaHighAddr = IOCFacts.CurrentHostMfaHighAddr;
req.SenseBufferHighAddr = IOCFacts.CurrentSenseBufferHighAddr;
req.ReplyFifoHostSignalingAddr = IOCFacts.ReplyFifoHostSignalingAddr;
req.HostPageBufferSGE = IOCFacts.HostPageBufferSGE;
req.MsgVersion = set16(MPI_VERSION_01_05);
req.HeaderVersion = set16(MPI_HEADER_VERSION);
if (IOCFacts.Flags & MPI_IOCFACTS_FLAGS_REPLY_FIFO_HOST_SIGNAL)
req.Flags |= MPI_IOCINIT_FLAGS_REPLY_FIFO_HOST_SIGNAL;
#if __linux__
if (oldMptBaseDetected)
{
// make the Linux IOCTL driver a bit happier
if (req.MaxDevices > port->maxTargets)
req.MaxDevices = port->maxTargets;
if (req.MaxDevices == 0)
req.MaxDevices = 255;
}
if (newMptBaseDetected)
{
// make the Linux IOCTL driver a bit happier
req.MaxDevices = 0;
req.MaxBuses = 0;
}
#endif
return doMptCommandCheck(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
}
char *
translateSmpFunctionResult(int functionResult)
{
switch (functionResult)
{
case SMP_RESPONSE_FUNCTION_RESULT_ACCEPTED: return "Function Accepted";
case SMP_RESPONSE_FUNCTION_RESULT_UNKNOWN_SMP_FUNCTION: return "Unknown Function";
case SMP_RESPONSE_FUNCTION_RESULT_SMP_FUNCTION_FAILED: return "Function Failed";
case SMP_RESPONSE_FUNCTION_RESULT_INVALID_REQUEST_LENGTH: return "Invalid Request Length";
case SMP_RESPONSE_FUNCTION_RESULT_INVALID_EXP_CHANGE_COUNT: return "Invalid Expander Change Count";
case SMP_RESPONSE_FUNCTION_RESULT_BUSY: return "Busy";
case SMP_RESPONSE_FUNCTION_RESULT_INCOMPLETE_DESCRIPTOR_LIST: return "Incomplete Descriptor List";
case SMP_RESPONSE_FUNCTION_RESULT_PHY_DOES_NOT_EXIST: return "Phy Does Not Exist";
case SMP_RESPONSE_FUNCTION_RESULT_INDEX_DOES_NOT_EXIST: return "Index Does Not Exist";
case SMP_RESPONSE_FUNCTION_RESULT_PHY_DOES_NOT_SUPPORT_SATA: return "Phy Does Not Support SATA";
case SMP_RESPONSE_FUNCTION_RESULT_UNKNOWN_PHY_OPERATION: return "Unknown Phy Operation";
case SMP_RESPONSE_FUNCTION_RESULT_UNKNOWN_PHY_TEST_FUNCTION: return "Unknown Phy Test Function";
case SMP_RESPONSE_FUNCTION_RESULT_PHY_TEST_FUNCTION_IN_PROG: return "Phy Test Function In Progress";
case SMP_RESPONSE_FUNCTION_RESULT_PHY_VACANT: return "Phy Vacant (No Access)";
case SMP_RESPONSE_FUNCTION_RESULT_UNKNOWN_PHY_EVENT_SOURCE: return "Unknown Phy Event Source";
case SMP_RESPONSE_FUNCTION_RESULT_UNKNOWN_DESCRIPTOR_TYPE: return "Unknown Descriptor Type";
case SMP_RESPONSE_FUNCTION_RESULT_UNKNOWN_PHY_FILTER: return "Unknown Phy Filter";
case SMP_RESPONSE_FUNCTION_RESULT_AFFILIATION_VIOLATION: return "Affiliation Violation";
case SMP_RESPONSE_FUNCTION_RESULT_SMP_ZONE_VIOLATION: return "Zone Violation";
case SMP_RESPONSE_FUNCTION_RESULT_NO_MANAGEMENT_ACCESS_RIGHTS: return "No Management Access Rights";
case SMP_RESPONSE_FUNCTION_RESULT_UNKNOWN_ENABLE_DISABLE_ZONING_VALUE: return "Unknown Enable Disable Zoning Value";
case SMP_RESPONSE_FUNCTION_RESULT_ZONE_LOCK_VIOLATION: return "Zone Lock Violation";
case SMP_RESPONSE_FUNCTION_RESULT_NOT_ACTIVATED: return "Not Activated";
case SMP_RESPONSE_FUNCTION_RESULT_ZONE_GROUP_OUT_OF_RANGE: return "Zone Group Out Of Range";
case SMP_RESPONSE_FUNCTION_RESULT_NO_PHYSICAL_PRESENCE: return "No Physical Presence";
case SMP_RESPONSE_FUNCTION_RESULT_SAVING_NOT_SUPPORTED: return "Saving Not Supported";
case SMP_RESPONSE_FUNCTION_RESULT_SOURCE_ZONE_GROUP_DOES_NOT_EXIST: return "Source Zone Group Does Not Exist";
case SMP_RESPONSE_FUNCTION_RESULT_DISABLED_PASSWORD_NOT_SUPPORTED: return "Disabled Password Not Supported";
}
return "";
}
int
doSmpReportMfg(MPT_PORT *port, _U64 SASAddress, U8 physicalPort, PTR_SMP_REPORT_MANUFACTURER_INFO_RESPONSE smpResp, int *respDataLength)
{
SMP_REPORT_MANUFACTURER_INFO_REQUEST smpReq;
int len;
memset((PTR_SMP_REQUEST_UNION)&smpReq, 0, sizeof smpReq);
smpReq.SMPFrameType = SMP_FRAME_TYPE_SMP_REQUEST;
smpReq.Function = SMP_FUNCTION_REPORT_MANUFACTURER_INFORMATION;
smpReq.ResponseLength = ALLOCATED_RESP_LEN;
smpReq.RequestLength = 0;
if (doSmpPassthrough(port, physicalPort, SASAddress,
(void *)&smpReq, sizeof smpReq, (void *)smpResp, sizeof *smpResp, &len) == 1)
{
if (respDataLength)
{
*respDataLength = len;
}
return 1;
}
return 0;
}
int
doSmpPassthrough(MPT_PORT *port, U8 smpPort, _U64 smpAddr, void *smpReq, int smpReqSize, void *smpRsp, int smpRspSize, int *respDataLen)
{
SmpPassthroughRequest_t req;
SmpPassthroughReply_t rep;
memset(&req, 0, sizeof req);
memset(&rep, 0, sizeof rep);
req.Function = MPI_FUNCTION_SMP_PASSTHROUGH;
req.PhysicalPort = smpPort;
req.RequestDataLength = set16(smpReqSize);
req.SASAddress = smpAddr;
memset(smpRsp, 0, smpRspSize);
if (doMptCommandCheck(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
smpRsp, smpRspSize, smpReq, smpReqSize, SHORT_TIME) == 1)
{
if (respDataLen)
{
*respDataLen = get16(rep.ResponseDataLength) + 4;
}
return 1;
}
else
return 0;
}
int
doResetPort(MPT_PORT *port)
{
int t;
#if WIN32
int status;
MPI_DIAG_RESET_SRB srb;
int inLen;
int outLen;
DWORD retLen;
memset(&srb, 0, sizeof srb);
srb.Sic.Length = sizeof srb - sizeof srb.Sic;
srb.Sic.ControlCode = MPI_DIAG_RESET;
srb.Sic.HeaderLength = sizeof srb.Sic;
srb.Sic.Timeout = RESET_TIME;
memcpy((char *)&srb.Sic.Signature, "v93Ap6Q4", 8);
inLen = sizeof srb;
outLen = sizeof srb;
retLen = 0;
printf("Resetting port...\n");
status = DeviceIoControl(port->fileHandle, port->ioctlValue,
&srb, inLen, &srb, outLen, &retLen, NULL);
t = status;
#endif
#if __linux__ || __alpha__
int status;
struct mpt_ioctl_diag_reset diag_reset;
memset(&diag_reset, 0, sizeof diag_reset);
diag_reset.hdr.iocnum = port->portNumber;
printf("Resetting port...\n");
if (mpi2)
status = ioctl(port->fileHandle, MPT2HARDRESET, &diag_reset);
else
status = ioctl(port->fileHandle, MPTHARDRESET, &diag_reset);
t = status == 0;
#endif
#if __sparc__ || __irix__
int status;
#if __irix__
struct scsi_ha_op scsiioctl;
#endif
printf("Resetting port...\n");
#if __sparc__
if (mpi2)
status = ioctl(port->fileHandle, MPTIOCTL_RESET_ADAPTER);
else
status = ioctl(port->fileHandle, SYMIOCTL_RESET_ADAPTER);
#endif
#if __irix__
scsiioctl.sb_opt = SYMIOCTL_RESET_ADAPTER;
status = ioctl(port->fileHandle, SOP_GETDATA, &scsiioctl);
#endif
t = status == 0;
#endif
#if DOS || EFI
printf("Resetting port...\n");
port->fileHandle->restart_needed = TRUE;
port->fileHandle->port_enable_needed = FALSE;
port->fileHandle->ioc_online = mpt_restart(port->fileHandle);
t = port->fileHandle->ioc_online;
#endif
if (wFlag)
fprintf(logFile, "%s: Reset Adapter: %s\n",
logPrefix(port), t ? "PASS" : "FAIL");
if (t != 1)
printf("Failed to reset port!\n");
return t;
}
void
doLogMptCommandReq(MPT_PORT *port, void *req, int reqSize)
{
int i;
fprintf(logFile, "%s: MPT Req: ", logPrefix(port));
for (i = 0; i < reqSize / 4; i++)
fprintf(logFile, " %08x", get32x(((U32 *)req)[i]));
fprintf(logFile, "\n");
}
void
doLogMptCommandRep(MPT_PORT *port, void *rep, int repSize, int status)
{
int i;
MPIDefaultReply_t *defaultRep;
fprintf(logFile, "%s: MPT Rep: ", logPrefix(port));
if (status == 1)
{
defaultRep = (pMPIDefaultReply_t)rep;
for (i = 0; i < defaultRep->MsgLength; i++)
fprintf(logFile, " %08x", get32x(((U32 *)rep)[i]));
if (defaultRep->Function == MPI_FUNCTION_SCSI_IO_REQUEST ||
defaultRep->Function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
defaultRep->Function == MPI_FUNCTION_SCSI_IO_32)
{
if (defaultRep->MsgLength == 0)
fprintf(logFile, " <SCSI I/O request was successful>");
if (mpi2)
{
SCSI_REPLY2 *scsiRep = (SCSI_REPLY2 *)rep;
if (scsiRep->reply.SCSIStatus == MPI_SCSI_STATUS_CHECK_CONDITION)
{
fprintf(logFile, "\n%s: Sense Data: ", logPrefix(port));
for (i = 0; i < (int)get32(scsiRep->reply.SenseCount); i++)
fprintf(logFile, " %02x", scsiRep->sense[i]);
}
}
else
{
SCSI_REPLY *scsiRep = (SCSI_REPLY *)rep;
if (scsiRep->reply.SCSIStatus == MPI_SCSI_STATUS_CHECK_CONDITION)
{
fprintf(logFile, "\n%s: Sense Data: ", logPrefix(port));
for (i = 0; i < (int)get32(scsiRep->reply.SenseCount); i++)
fprintf(logFile, " %02x", scsiRep->sense[i]);
}
}
}
}
else
{
fprintf(logFile, " <no reply, request did not finish>");
}
fprintf(logFile, "\n");
}
void
logMptCommandReq(MPT_PORT *port, void *req, int reqSize)
{
if (wFlag >= 3)
{
doLogMptCommandReq(port, req, reqSize);
}
}
void
logMptCommandRep(MPT_PORT *port, void *req, int reqSize, void *rep, int repSize, int status)
{
#if DOS || EFI
MPIHeader_t *reqL = (pMPIHeader_t)req;
#endif
MPIDefaultReply_t *repL = (pMPIDefaultReply_t)rep;
int ioc_status = get16(repL->IOCStatus) & MPI_IOCSTATUS_MASK;
#if DOS || EFI
if (req && reqSize && reqL->Function == repL->Function && repL->MsgLength != 0)
{
status = 1; // reply is initially zeroed, so if we get here we can trust it
}
#endif
if (wFlag >= 3)
{
doLogMptCommandRep(port, rep, repSize, status);
}
else if (wFlag >= 2 && (status == 0 || ioc_status != MPI_IOCSTATUS_SUCCESS))
{
if (req && reqSize)
{
doLogMptCommandReq(port, req, reqSize);
}
doLogMptCommandRep(port, rep, repSize, status);
}
}
int
doMptCommand(MPT_PORT *port, void *req, int reqSize, void *rep, int repSize,
void *payIn, int payInSize, void *payOut, int payOutSize, int timeOut)
{
#if WIN32
int cmd;
int status;
SRB_BUFFER srb_buffer;
SRB_BUFFER *srb;
int inLen;
int outLen;
DWORD retLen;
int size;
int retry;
int function = ((pMPIHeader_t)req)->Function;
/*
* Add 8 for IoctlDetails, 128 for maximum request and reply,
* and 256 for maximum sense data (for SCSI I/O requests).
*/
size = 8 + 128 + 256 + max(payInSize, payOutSize);
if (size > sizeof srb->Buf)
srb = malloc(sizeof srb->Sic + size);
else
srb = &srb_buffer;
memset(srb, 0, sizeof srb->Sic + size);
srb->Sic.Length = size;
srb->Sic.ControlCode = MPI_MSG_IOCTL;
srb->Sic.HeaderLength = sizeof srb->Sic;
srb->Sic.Timeout = timeOut;
memcpy((char *)&srb->Sic.Signature, "4.00 ", 8);
if (payInSize != 0 && payOutSize != 0)
cmd = DUAL_SGLS; // data in and data out
else if (payInSize != 0)
cmd = 0; // data in
else if (payOutSize != 0)
cmd = DATA_FROM_APP; // data out
else
cmd = 0; // no data transfer, just say Read
if (function == MPI_FUNCTION_SCSI_IO_REQUEST ||
function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
function == MPI_FUNCTION_SCSI_IO_32)
{
if (function == MPI_FUNCTION_SCSI_IO_REQUEST ||
function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
cmd |= SCSI_IO; // flag SCSI I/O, potentially get sense data
((pMPIHeader_t)req)->MsgContext = 0;
}
*(PUSHORT)&srb->Buf[0] = cmd;
*(PUSHORT)&srb->Buf[2] = reqSize / 4;
if (cmd & DATA_FROM_APP)
*(PULONG)&srb->Buf[4] = payOutSize;
else
*(PULONG)&srb->Buf[4] = payInSize;
if (cmd & DUAL_SGLS)
{
if (payInSize > 0xffff || payOutSize > 0xffff)
{
printf("Payload sizes too large, max is 64 KB!\n");
return 0;
}
*(PUSHORT)&srb->Buf[4] = payInSize;
*(PUSHORT)&srb->Buf[6] = payOutSize;
}
memcpy(&srb->Buf[8], req, reqSize);
if (payOutSize != 0)
memcpy(&srb->Buf[8+reqSize], payOut, payOutSize);
inLen = sizeof srb->Sic + size;
outLen = sizeof srb->Sic + size;
retLen = 0;
logMptCommandReq(port, req, reqSize);
for (retry = 0; retry < 10; retry++)
{
status = DeviceIoControl(port->fileHandle, port->ioctlValue,
srb, inLen, srb, outLen, &retLen, NULL);
if (status == 1)
{
gRetDataLen = retLen - sizeof(SRB_IO_CONTROL) - port->payOff;
memcpy(rep, &srb->Buf[0], repSize);
if (payInSize != 0)
memcpy(payIn, &srb->Buf[port->payOff], payInSize);
if (function == MPI_FUNCTION_SCSI_IO_REQUEST ||
function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
function == MPI_FUNCTION_SCSI_IO_32)
{
if (mpi2)
{
Mpi2SCSIIOReply_t *scsiRep = (pMpi2SCSIIOReply_t)rep;
if (scsiRep->MsgLength == 0)
memset(rep, 0, repSize);
/* copy the sense data to where it is expected to be */
memcpy(scsiRep + 1, &srb->Buf[port->payOff + payInSize], repSize - sizeof *scsiRep);
}
else
{
SCSIIOReply_t *scsiRep = (pSCSIIOReply_t)rep;
if (scsiRep->MsgLength == 0)
memset(rep, 0, repSize);
/* copy the sense data to where it is expected to be */
memcpy(scsiRep + 1, &srb->Buf[port->payOff + payInSize], repSize - sizeof *scsiRep);
}
}
break;
}
if (GetLastError() == ERROR_BUSY)
{
sleep(1);
}
else
{
printf("IOCTL to %s failed due to error %ld\n", port->portName, GetLastError());
break;
}
}
if (status != 1 && retry == 10)
printf("IOCTL to %s failed due to ERROR_BUSY %d times\n", port->portName, retry);
logMptCommandRep(port, req, reqSize, rep, repSize, status);
if (size > sizeof srb->Buf)
free(srb);
return status;
#endif
#if __linux__ || __alpha__
int status;
int extra;
struct mpt_ioctl_command *command;
int retry;
int function = ((pMPIHeader_t)req)->Function;
extra = max(0, reqSize - sizeof command->MF);
command = (struct mpt_ioctl_command *)malloc(sizeof *command + extra);
memset(command, 0, sizeof *command);
command->hdr.iocnum = port->portNumber;
command->timeout = timeOut;
command->replyFrameBufPtr = rep;
command->dataInBufPtr = payIn;
command->dataOutBufPtr = payOut;
command->maxReplyBytes = repSize;
command->dataInSize = payInSize;
command->dataOutSize = payOutSize;
command->dataSgeOffset = reqSize / 4;
if (function == MPI_FUNCTION_SCSI_IO_REQUEST ||
function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
function == MPI_FUNCTION_SCSI_IO_32)
{
if (mpi2)
{
Mpi2SCSIIOReply_t *scsiRep = (pMpi2SCSIIOReply_t)rep;
command->senseDataPtr = (char *)(scsiRep + 1);
command->maxSenseBytes = repSize - sizeof *scsiRep;
command->maxReplyBytes = sizeof *scsiRep;
}
else
{
SCSIIOReply_t *scsiRep = (pSCSIIOReply_t)rep;
command->senseDataPtr = (char *)(scsiRep + 1);
command->maxSenseBytes = repSize - sizeof *scsiRep;
command->maxReplyBytes = sizeof *scsiRep;
}
}
memcpy(command->MF, req, reqSize);
logMptCommandReq(port, req, reqSize);
for (retry = 0; retry < 10; retry++)
{
errno = 0;
if (mpi2)
status = ioctl(port->fileHandle, MPT2COMMAND, command);
else
status = ioctl(port->fileHandle, MPTCOMMAND, command);
if (status != 0 && errno == EAGAIN)
{
sleep(1);
}
else
{
break;
}
}
logMptCommandRep(port, req, reqSize, rep, repSize, status == 0);
#if __linux__
if (status != 0)
{
if (errno == EFAULT)
{
if (((pMPIHeader_t)req)->Function == MPI_FUNCTION_IOC_INIT)
{
IOCInit_t *iocinitReq = (pIOCInit_t)req;
int maxDevices;
free(command);
if (workaroundsTried == TRUE)
return 0;
workaroundsTried = TRUE;
// try to make the Linux IOCTL driver a bit happier
maxDevices = iocinitReq->MaxDevices;
if (iocinitReq->MaxDevices > port->maxTargets)
iocinitReq->MaxDevices = port->maxTargets;
if (iocinitReq->MaxDevices == 0)
iocinitReq->MaxDevices = 255;
if (iocinitReq->MaxDevices != maxDevices)
{
status = doMptCommand(port, req, reqSize, rep, repSize,
payIn, payInSize, payOut, payOutSize, timeOut);
if (status == 1)
{
oldMptBaseDetected = 1;
return 1;
}
}
if (iocinitReq->MaxDevices != 0 || iocinitReq->MaxBuses != 0)
{
iocinitReq->MaxDevices = 0;
iocinitReq->MaxBuses = 0;
status = doMptCommand(port, req, reqSize, rep, repSize,
payIn, payInSize, payOut, payOutSize, timeOut);
if (status == 1)
{
newMptBaseDetected = 1;
return 1;
}
}
return 0;
}
if (((pMPIHeader_t)req)->Function != MPI_FUNCTION_SCSI_IO_REQUEST)
{
printf("Command rejected by mptctl!\n");
}
}
}
#endif
free(command);
return status == 0;
#endif
#if __sparc__ || __irix__
int status;
#if __sparc__
SYM_PASS_THRU_TIMEOUT passThru;
#endif
#if __irix__
struct scsi_ha_op scsiioctl;
SYM_PASS_THRU passThru;
#endif
passThru.PtrRequest = (UINT64)(UINT32)req;
passThru.RequestSize = reqSize;
passThru.PtrReply = (UINT64)(UINT32)rep;
passThru.ReplySize = repSize;
if (payInSize != 0 && payOutSize != 0)
{
passThru.PtrData = (UINT64)(UINT32)payIn;
passThru.DataSize = payInSize;
passThru.PtrDataOut = (UINT64)(UINT32)payOut;
passThru.DataOutSize = payOutSize;
passThru.DataDirection = SYM_PASS_THRU_BOTH;
}
else if (payInSize != 0)
{
passThru.PtrData = (UINT64)(UINT32)payIn;
passThru.DataSize = payInSize;
passThru.DataDirection = SYM_PASS_THRU_READ;
}
else if (payOutSize != 0)
{
passThru.PtrData = (UINT64)(UINT32)payOut;
passThru.DataSize = payOutSize;
passThru.DataDirection = SYM_PASS_THRU_WRITE;
}
else
{
passThru.PtrData = (UINT64)(UINT32)NULL;
passThru.DataSize = 0;
passThru.PtrDataOut = (UINT64)(UINT32)NULL;
passThru.DataOutSize = 0;
passThru.DataDirection = SYM_PASS_THRU_NONE;
}
#if __sparc__
passThru.Timeout = timeOut;
#endif
logMptCommandReq(port, req, reqSize);
#if __sparc__
status = ioctl(port->fileHandle, port->ioctlValue, &passThru);
if (port->ioctlValue == SYMIOCTL_PASS_THRU_TIMEOUT && status != 0)
{
port->ioctlValue = SYMIOCTL_PASS_THRU;
status = ioctl(port->fileHandle, port->ioctlValue, &passThru);
}
#endif
#if __irix__
scsiioctl.sb_opt = SYMIOCTL_PASS_THRU;
scsiioctl.sb_addr = (uintptr_t)&passThru;
status = ioctl(port->fileHandle, SOP_GETDATA, &scsiioctl);
#endif
logMptCommandRep(port, req, reqSize, rep, repSize, status == 0);
return status == 0;
#endif
#if DOS || EFI
HANDLE adap = port->fileHandle;
SGESimple64_t *sgeSimple = (pSGESimple64_t)((U8 *)req + reqSize);
U8 function = ((pMPIHeader_t)req)->Function;
int handshake_okay;
int no_port_enable_okay;
int ioc_status;
int t;
U8 ieee_sgl;
Mpi2IeeeSgeSimple64_t *sgeIeeeSimple = (pMpi2IeeeSgeSimple64_t)((U8 *)req + reqSize);
if (adap->restart_needed == TRUE)
{
mpt_stop(adap, TRUE);
}
if (adap->ioc_online == TRUE)
{
adap->ioc_online = mpt_verify_operational(adap);
}
handshake_okay =
function == MPI_FUNCTION_IOC_INIT ||
function == MPI_FUNCTION_IOC_FACTS ||
function == MPI_FUNCTION_PORT_FACTS ||
function == MPI_FUNCTION_CONFIG ||
((function == MPI_FUNCTION_TOOLBOX ||
function == MPI_FUNCTION_FW_DOWNLOAD) && adap->bootloader) ||
(function == MPI_FUNCTION_FW_UPLOAD && (port->flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT));
ieee_sgl = ((mpi25) &&
(function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
function == MPI2_FUNCTION_SMP_PASSTHROUGH ||
function == MPI2_FUNCTION_SATA_PASSTHROUGH ||
function == MPI2_FUNCTION_FW_UPLOAD ||
function == MPI2_FUNCTION_FW_DOWNLOAD ||
function == MPI2_FUNCTION_TARGET_ASSIST ||
function == MPI2_FUNCTION_TARGET_STATUS_SEND ||
((function == MPI2_FUNCTION_TOOLBOX) && (((pMPI2RequestHeader_t)req)->FunctionDependent1 == MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL))
));
no_port_enable_okay = handshake_okay ||
function == MPI_FUNCTION_TOOLBOX ||
function == MPI_FUNCTION_FW_DOWNLOAD ||
function == MPI_FUNCTION_FW_UPLOAD;
if (adap->ioc_online == FALSE && !handshake_okay)
{
adap->port_enable_needed = !no_port_enable_okay;
adap->ioc_online = mpt_restart(adap);
if (adap->ioc_online == FALSE &&
(adap->bootloader == TRUE || adap->loaddevice == TRUE))
{
printf("MPT Function %02x not supported!\n", function);
errno = EFAULT;
return 0;
}
}
if (adap->ioc_online == TRUE && adap->port_online == FALSE && !no_port_enable_okay)
{
adap->port_online = mpt_port_online(adap);
}
if (payOut && payOutSize)
{
if (payOutSize > sizeof adap->shared->scratch)
{
printf("payOutSize (%x) too big!\n", payOutSize);
return 0;
}
if (ieee_sgl)
{
sgeIeeeSimple->Flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
MPI25_IEEE_SGE_FLAGS_END_OF_LIST |
MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR;
sgeIeeeSimple->Length = set32(payOutSize);
sgeIeeeSimple->Address.Low = set32((U32)adap->shared_ba + offsetof(mpt_shared_t, scratch));
#if DOS
sgeIeeeSimple->Address.High = 0;
#else
sgeIeeeSimple->Address.High = set32((U32)(adap->shared_ba >> 32));
#endif
sgeIeeeSimple++;
reqSize += sizeof(Mpi2IeeeSgeSimple64_t);
}
else
{
sgeSimple->FlagsLength = set32(payOutSize |
MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
MPI_SGE_FLAGS_LAST_ELEMENT |
MPI_SGE_FLAGS_64_BIT_ADDRESSING |
MPI_SGE_FLAGS_HOST_TO_IOC |
MPI_SGE_FLAGS_END_OF_BUFFER |
MPI_SGE_FLAGS_END_OF_LIST));
sgeSimple->Address.Low = set32((U32)adap->shared_ba + offsetof(mpt_shared_t, scratch));
#if DOS
sgeSimple->Address.High = 0;
#else
sgeSimple->Address.High = set32((U32)(adap->shared_ba >> 32));
#endif
sgeSimple++;
reqSize += sizeof(SGESimple64_t);
}
bcopy(payOut, adap->shared->scratch, payOutSize);
}
if (payIn && payInSize)
{
if (payInSize > sizeof adap->shared->scratch)
{
printf("payInSize (%x) too big!\n", payInSize);
return 0;
}
if (ieee_sgl)
{
sgeIeeeSimple->Flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
MPI25_IEEE_SGE_FLAGS_END_OF_LIST |
MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR;
sgeIeeeSimple->Length = set32(payInSize);
sgeIeeeSimple->Address.Low = set32((U32)adap->shared_ba + offsetof(mpt_shared_t, scratch));
#if DOS
sgeIeeeSimple->Address.High = 0;
#else
sgeIeeeSimple->Address.High = set32((U32)(adap->shared_ba >> 32));
#endif
sgeIeeeSimple++;
reqSize += sizeof(Mpi2IeeeSgeSimple64_t);
}
else
{
sgeSimple->FlagsLength = set32(payInSize |
MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
MPI_SGE_FLAGS_LAST_ELEMENT |
MPI_SGE_FLAGS_64_BIT_ADDRESSING |
MPI_SGE_FLAGS_IOC_TO_HOST |
MPI_SGE_FLAGS_END_OF_BUFFER |
MPI_SGE_FLAGS_END_OF_LIST));
sgeSimple->Address.Low = set32((U32)adap->shared_ba + offsetof(mpt_shared_t, scratch));
#if DOS
sgeSimple->Address.High = 0;
#else
sgeSimple->Address.High = set32((U32)(adap->shared_ba >> 32));
#endif
sgeSimple++;
reqSize += sizeof(SGESimple64_t);
}
}
if (mpi2 && !(payOut && payOutSize) && !(payIn && payInSize))
{
if (function == MPI_FUNCTION_SCSI_IO_REQUEST ||
function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
function == MPI_FUNCTION_CONFIG)
{
if (ieee_sgl)
{
sgeIeeeSimple->Flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
MPI25_IEEE_SGE_FLAGS_END_OF_LIST |
MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR;
sgeIeeeSimple->Length = set32(payInSize);
sgeIeeeSimple->Address.Low = 0;
sgeIeeeSimple->Address.High = 0;
sgeIeeeSimple++;
reqSize += sizeof(Mpi2IeeeSgeSimple64_t);
}
else
{
sgeSimple->FlagsLength = set32(payInSize |
MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_SIMPLE_ELEMENT |
MPI_SGE_FLAGS_LAST_ELEMENT |
MPI_SGE_FLAGS_32_BIT_ADDRESSING |
MPI_SGE_FLAGS_END_OF_BUFFER |
MPI_SGE_FLAGS_END_OF_LIST));
sgeSimple->Address.Low = 0;
sgeSimple->Address.High = 0;
sgeSimple++;
reqSize += sizeof(SGESimple64_t);
}
}
}
if (mpi2)
adap->msg_context = PASS_THRU_CONTEXT;
else
((pMPIHeader_t)req)->MsgContext = set32(PASS_THRU_CONTEXT);
if (function == MPI_FUNCTION_SCSI_IO_REQUEST ||
function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
function == MPI_FUNCTION_SCSI_IO_32)
{
if (mpi20)
{
Mpi2SCSIIORequest_t *scsiReq = (pMpi2SCSIIORequest_t)req;
Mpi2SCSIIOReply_t *scsiRep = (pMpi2SCSIIOReply_t)rep;
scsiReq->SenseBufferLowAddress =
set32((U32)adap->shared_ba + offsetof(mpt_shared_t, data) + sizeof *scsiRep);
scsiReq->SenseBufferLength = (U8)(repSize - sizeof *scsiRep);
}
else if (mpi25)
{
Mpi25SCSIIORequest_t *scsiReq = (pMpi25SCSIIORequest_t)req;
Mpi2SCSIIOReply_t *scsiRep = (pMpi2SCSIIOReply_t)rep;
scsiReq->SenseBufferLowAddress =
set32((U32)adap->shared_ba + offsetof(mpt_shared_t, data) + sizeof *scsiRep);
scsiReq->SenseBufferLength = (U8)(repSize - sizeof *scsiRep);
}
else
{
SCSIIORequest_t *scsiReq = (pSCSIIORequest_t)req;
SCSIIOReply_t *scsiRep = (pSCSIIOReply_t)rep;
scsiReq->SenseBufferLowAddr =
set32((U32)adap->shared_ba + offsetof(mpt_shared_t, data) + sizeof *scsiRep);
scsiReq->SenseBufferLength = (U8)(repSize - sizeof *scsiRep);
}
}
bcopy(req, adap->shared->message, reqSize);
logMptCommandReq(port, req, reqSize);
if (adap->ioc_online == TRUE)
{
if (mpt_verify_operational(adap))
{
t = mpt_issue_command_and_wait(adap, timeOut);
if (t != 1)
{
printf("mpt_issue_command_and_wait failed\n");
}
}
else
{
t = 0;
}
}
else
{
time_t limit = time(NULL) + timeOut;
if (mpt_verify_ready(adap) || mpt_verify_operational(adap))
{
t = mpt_send_message(adap, reqSize, limit);
if (t != 1)
{
printf("mpt_send_message failed!\n");
}
else
{
t = mpt_receive_data(adap, repSize, limit);
if (t != 1)
{
if (adap->bootloader == FALSE ||
!(function == MPI_FUNCTION_IOC_INIT ||
function == MPI_FUNCTION_IOC_FACTS ||
function == MPI_FUNCTION_PORT_FACTS ||
function == MPI_FUNCTION_CONFIG))
{
ioc_status = get16(((pMPIDefaultReply_t)adap->shared->data)->IOCStatus) & MPI_IOCSTATUS_MASK;
printf("[%s] mpt_receive_data failed, function = %d, IOCStatus = %04x (%s)\n",
port->portName, function, ioc_status, translateIocStatus(ioc_status));
}
}
}
}
else
{
t = 0;
}
}
bcopy(adap->shared->data, rep, repSize);
logMptCommandRep(port, req, reqSize, rep, repSize, t);
if (payIn && payInSize)
{
bcopy(adap->shared->scratch, payIn, payInSize);
}
return t;
#endif
}
int
doMptCommandCheck(MPT_PORT *port, void *req, int reqSize, void *rep, int repSize,
void *payIn, int payInSize, void *payOut, int payOutSize, int timeOut)
{
MPIDefaultReply_t *defaultRep;
int ioc_status;
int ioc_loginfo;
if (doMptCommand(port, req, reqSize, rep, repSize,
payIn, payInSize, payOut, payOutSize, timeOut) != 1)
{
printf("\nFailed to issue command\n");
return 0;
}
defaultRep = (pMPIDefaultReply_t)rep;
ioc_status = get16(defaultRep->IOCStatus) & MPI_IOCSTATUS_MASK;
if (ioc_status != MPI_IOCSTATUS_SUCCESS)
{
if ((get16(defaultRep->IOCStatus) & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) != 0)
{
ioc_loginfo = get32(defaultRep->IOCLogInfo);
printf("\nCommand failed with IOCStatus = %04x (%s), IOCLogInfo = %08x\n",
ioc_status, translateIocStatus(ioc_status), ioc_loginfo);
}
else
printf("\nCommand failed with IOCStatus = %04x (%s)\n",
ioc_status, translateIocStatus(ioc_status));
return 0;
}
if (defaultRep->Function == MPI_FUNCTION_RAID_ACTION)
{
ioc_loginfo = get32(defaultRep->IOCLogInfo);
if (ioc_loginfo)
{
printf("\nRAID ACTION returned IOCLogInfo = %08x\n", ioc_loginfo);
}
}
return 1;
}
char *
translateIocStatus(int ioc_status)
{
// Bit 15 means "Log Info Available". Therefore,
// we only want bits 0 through 14. Otherwise,
// this routine won't work when log info is available.
ioc_status &= MPI_IOCSTATUS_MASK;
switch (ioc_status)
{
case MPI_IOCSTATUS_SUCCESS: return "Success";
case MPI_IOCSTATUS_INVALID_FUNCTION: return "Invalid Function";
case MPI_IOCSTATUS_BUSY: return "IOC Busy";
case MPI_IOCSTATUS_INVALID_SGL: return "Invalid SGL";
case MPI_IOCSTATUS_INTERNAL_ERROR: return "Internal Error";
case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: return "Insufficient Resources";
case MPI_IOCSTATUS_INVALID_FIELD: return "Invalid Field";
case MPI_IOCSTATUS_INVALID_STATE: return "Invalid State";
case MPI_IOCSTATUS_OP_STATE_NOT_SUPPORTED: return "Operational State Not Supported";
case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: return "Invalid Action";
case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: return "Invalid Type";
case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: return "Invalid Page";
case MPI_IOCSTATUS_CONFIG_INVALID_DATA: return "Invalid Data";
case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: return "No Defaults";
case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: return "Can't Commit";
case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: return "Recovered Error";
case MPI_IOCSTATUS_SCSI_INVALID_BUS: return "Invalid Bus";
case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: return "Invalid Target";
case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: return "Device Not There";
case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: return "Data Overrun";
case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: return "Data Underrun";
case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: return "I/O Data Error";
case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: return "Protocol Error";
case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: return "Task Terminated";
case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: return "Residual Mismatch";
case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: return "Task Managment Failed";
case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: return "IOC Terminated";
case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: return "Externally Terminated";
case MPI_IOCSTATUS_EEDP_GUARD_ERROR: return "EEDP Guard Error";
case MPI_IOCSTATUS_EEDP_REF_TAG_ERROR: return "EEDP Reference Tag Error";
case MPI_IOCSTATUS_EEDP_APP_TAG_ERROR: return "EEDP Application Tag Error";
case MPI_IOCSTATUS_TARGET_PRIORITY_IO: return "Target Priority I/O";
case MPI_IOCSTATUS_TARGET_INVALID_PORT: return "Invalid Port";
case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: return "Invalid I/O Index";
case MPI_IOCSTATUS_TARGET_ABORTED: return "Target Aborted";
case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: return "No Connection, Retryable";
case MPI_IOCSTATUS_TARGET_NO_CONNECTION: return "No Connection";
case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: return "Transfer Count Mismatch";
case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: return "Status Data Not Sent";
case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: return "Data Offset Error";
case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: return "Too Much Write Data";
case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: return "Target IU Too Short";
case MPI_IOCSTATUS_FC_ABORTED: return "FC Aborted";
case MPI_IOCSTATUS_FC_RX_ID_INVALID: return "RX_ID Invalid";
case MPI_IOCSTATUS_FC_DID_INVALID: return "D_ID Invalid";
case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: return "Node Logged Out";
case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: return "Exchange Canceled";
case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: return "LAN Device Not Found";
case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: return "LAN Device Failure";
case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: return "LAN Transmit Error";
case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: return "LAN Transmit Aborted";
case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: return "LAN Receive Error";
case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: return "LAN Receive Aborted";
case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: return "LAN Partial Packet";
case MPI_IOCSTATUS_LAN_CANCELED: return "LAN Canceled";
case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: return "SMP Request Failed";
case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: return "SMP Data Overrun";
case MPI_IOCSTATUS_INBAND_ABORTED: return "Inband Aborted";
case MPI_IOCSTATUS_INBAND_NO_CONNECTION: return "Inband No Connection";
case MPI_IOCSTATUS_DIAGNOSTIC_RELEASED: return "Diagnostic Buffer Released";
case MPI2_IOCSTATUS_RAID_ACCEL_ERROR: return "RAID Accelerator Error";
}
return "";
}
void
displayByteData(unsigned char *buf, int len)
{
int i;
int j;
char c[16];
for (i = 0, j = 0; i < len; i++, j++)
{
if (j == 0)
printf("%04x : ", i);
printf("%02x ", buf[i]);
if (!isprint(buf[i]))
c[j] = ' ';
else
c[j] = buf[i];
if (j == sizeof c - 1)
{
printf(" ");
for (j = 0; j < sizeof c; j++)
{
printf("%c", c[j]);
}
printf("\n");
j = -1;
}
}
if (j != 0)
{
for (i = j; i < sizeof c; i++)
printf(" ");
printf(" ");
for (i = 0; i < j; i++)
{
printf("%c", c[i]);
}
printf("\n");
}
}
void
dumpMemory(void *buf, int len, char *string)
{
U8 *p = (U8 *)buf;
int i;
if (string != NULL)
printf("\n%s\n", string);
for (i = 0; i < len; i += 4)
printf("%04x : %02x%02x%02x%02x %c%c%c%c\n", i,
p[i+3], p[i+2], p[i+1], p[i+0],
isprint(p[i+0]) ? p[i+0] : '.',
isprint(p[i+1]) ? p[i+1] : '.',
isprint(p[i+2]) ? p[i+2] : '.',
isprint(p[i+3]) ? p[i+3] : '.');
}
void
dumpMemoryWide(void *buf, int len, char *string)
{
U32 *p = (U32 *)buf;
int i;
if (string != NULL)
printf("\n%s", string);
for (i = 0; i < len/4; i++)
{
if ((i % 8) == 0)
printf("\n%04x : %08x", i * 4, get32x(p[i]));
else
printf(" %08x", get32x(p[i]));
}
printf("\n");
}
#define POLY 0x8bb7
unsigned short polyTableT10[256];
void
initT10Crc(void)
{
unsigned int data;
unsigned int crc;
unsigned int r_mask;
unsigned int d_mask;
int i;
int j;
r_mask = 1 << (16 - 1);
d_mask = 1 << (8 - 1);
for (i = 0; i < 256; i++)
{
data = i;
crc = 0;
for (j = 0; j < 8; j++)
{
if (( (crc & r_mask) && !(data & d_mask)) ||
(!(crc & r_mask) && (data & d_mask)))
{
crc = ((crc << 1) ^ POLY) & 0xffff;
}
else
{
crc = (crc << 1) & 0xffff;
}
data = data << 1;
}
polyTableT10[i] = crc;
}
}
unsigned int
genT10Crc(unsigned char *buf)
{
unsigned int crc;
unsigned int data;
int i;
crc = 0;
for (i = 0; i < 512; i++)
{
data = buf[i];
crc = ((crc << 8) ^ polyTableT10[data ^ (crc >> 8)]) & 0xffff;
}
return crc;
}
unsigned int
genLbCrc(unsigned char *buf, int len)
{
return 0;
}
int
checkRemoveT10(MPT_PORT *port, unsigned int lbn, int lbns, unsigned char *buf_in, unsigned char *buf_out, int len)
{
int i;
unsigned char *in;
unsigned char *out;
unsigned int crc;
unsigned int crc_in;
unsigned int lba;
unsigned int lba_in;
in = buf_in;
out = buf_out;
for (i = 0, lba = lbn; i < lbns; i++, lba++)
{
if (in[512+2] != 0xff || in[512+3] != 0xff)
{
crc = genT10Crc(in) & 0xffff;
crc_in = get2bytes(in, 512);
if (crc != crc_in)
{
printf("CRC is incorrect: %04x vs %04x\n", crc, crc_in);
return 0;
}
lba_in = get4bytes(in, 512+4);
if (lba != lba_in)
{
printf("LBA Ref Tag is incorrect: %08x vs %08x\n", lba, lba_in);
return 0;
}
}
memcpy(out, in, 512);
in += 512+8;
out += 512;
}
// dumpMemory(buf_out, len, "read with T10");
return 1;
}
int
checkRemoveLb(MPT_PORT *port, unsigned int lbn, int lbns, unsigned char *buf_in, unsigned char *buf_out, int len, int do_crc)
{
int i;
unsigned char *in;
unsigned char *out;
unsigned int crc;
unsigned int crc_in;
unsigned int lba;
unsigned int lba_in;
unsigned int *dif;
unsigned int t;
in = buf_in;
out = buf_out;
for (i = 0, lba = lbn; i < lbns; i += 8, lba += 8)
{
dif = (unsigned int *)(in + 4096);
if (do_crc)
{
crc = genLbCrc(in, 4096);
crc_in = get32x(dif[1]);
if (crc != crc_in)
{
printf("Data CRC is incorrect: %08x vs %08x\n", crc, crc_in);
return 0;
}
t = dif[3];
crc = genLbCrc(in + 4096, 64);
dif[3] = t;
crc_in = get32x(dif[3]);
if (crc != crc_in)
{
printf("DIF CRC is incorrect: %08x vs %08x\n", crc, crc_in);
return 0;
}
}
lba_in = get32x(dif[2]);
if (lba != lba_in)
{
printf("LBA Ref Tag is incorrect: %08x vs %08x\n", lba, lba_in);
return 0;
}
memcpy(out, in, 4096);
in += 4096+64;
out += 4096;
}
// dumpMemory(buf_out, len, "read with LB");
return 1;
}
int
insertT10(MPT_PORT *port, unsigned int lbn, int lbns, unsigned char *buf_in, unsigned char *buf_out, int len)
{
int i;
unsigned char *in;
unsigned char *out;
unsigned int crc;
unsigned int lba;
in = buf_in + (lbns - 1) * 512;
out = buf_out + (lbns - 1) * (512+8);
for (i = 0, lba = lbn + lbns - 1; i < lbns; i++, lba--)
{
crc = genT10Crc(in) & 0xffff;
memcpy(out, in, 512);
memset(out + 512, 0, 8);
put2bytes(out, 512, crc);
put4bytes(out, 516, lba);
// if (lba >= 128 + 12 && lba < 128 + 12 + 16) out[512 + lba - 128 - 12 - 8] ^= 0x69;
in -= 512;
out -= 512+8;
}
// dumpMemory(buf_out, len, "write with T10");
return 1;
}
int
insertLb(MPT_PORT *port, unsigned int lbn, int lbns, unsigned char *buf_in, unsigned char *buf_out, int len, int do_crc)
{
int i;
unsigned char *in;
unsigned char *out;
unsigned int crc;
unsigned int lba;
unsigned int *dif;
in = buf_in + (lbns - 8) * 512;
out = buf_out + (lbns - 8) * (512+8);
for (i = 0, lba = lbn + lbns - 8; i < lbns; i += 8, lba -= 8)
{
dif = (unsigned int *)(out + 4096);
if (do_crc)
crc = genLbCrc(in, 4096);
else
crc = 0;
memcpy(out, in, 4096);
memset(out + 4096, 0, 64);
dif[1] = set32x(crc);
dif[2] = set32x(lba);
dif[4] = set32x(lba);
if (do_crc)
crc = genLbCrc(in + 4096, 64);
else
crc = 0;
dif[3] = crc;
in -= 4096;
out -= 4096+64;
}
// dumpMemory(buf_out, len, "write with LB");
return 1;
}
void
waitForFile(char *name)
{
int file;
while (TRUE)
{
file = open(name, O_RDONLY | O_BINARY);
if (file >= 0)
{
close(file);
break;
}
sleep(1);
}
}
typedef struct
{
CONFIG_PAGE_HEADER Header;
MPI_CHIP_REVISION_ID ChipId;
U8 SubsystemVendorId_0[2];
U8 SubsystemId_0[2];
U8 ClassCode_0[3];
U8 PciMemory;
U8 HardwareConfig[1];
U8 SubsystemVendorId_1[2];
U8 SubsystemId_1[2];
U8 ClassCode_1[3];
U8 Checksum;
U8 Filler[3];
} ManufacturingPage2_929_t;
typedef struct
{
CONFIG_PAGE_HEADER Header;
MPI_CHIP_REVISION_ID ChipId;
U8 SubsystemVendorId_0[2];
U8 SubsystemId_0[2];
U8 ClassCode_0[3];
U8 PciMemory;
U8 HardwareConfig[2];
U8 SubsystemVendorId_1[2];
U8 SubsystemId_1[2];
U8 ClassCode_1[3];
U8 Checksum;
U8 Filler[2];
} ManufacturingPage2_929X_t;
typedef struct
{
CONFIG_PAGE_HEADER Header;
MPI_CHIP_REVISION_ID ChipId;
U8 SubsystemVendorId[2];
U8 SubsystemId[2];
U8 ClassCode[3];
U8 PciMemory;
U8 PciPowerBudgetData[8][3];
U8 Checksum;
U8 Filler[3];
} ManufacturingPage2_949E_t;
typedef struct
{
CONFIG_PAGE_HEADER Header;
MPI_CHIP_REVISION_ID ChipId;
_U64 WWPN_0;
_U64 WWNN_0;
_U32 PhyRegs1_0;
_U32 PhyRegs2_0;
_U32 PhyRegs2_Alt_0;
U8 MfgSupportedSpeeds_0;
U8 MfgLinkType_0;
U8 MfgConnectorType_0;
U8 Filler_0;
_U64 WWPN_1;
_U64 WWNN_1;
_U32 PhyRegs1_1;
_U32 PhyRegs2_1;
_U32 PhyRegs2_Alt_1;
U8 MfgSupportedSpeeds_1;
U8 MfgLinkType_1;
U8 MfgConnectorType_1;
U8 Filler_1;
} ManufacturingPage3_929_t;
typedef struct
{
CONFIG_PAGE_HEADER Header;
MPI_CHIP_REVISION_ID ChipId;
_U64 WWPN_0;
_U64 WWNN_0;
_U32 PhyRegs1_0;
U32 Unused1_0;
U32 Unused2_0;
U8 MfgSupportedSpeeds_0;
U8 MfgLinkType_0;
U8 MfgConnectorType_0;
U8 Filler_0;
_U64 WWPN_1;
_U64 WWNN_1;
_U32 PhyRegs1_1;
U32 Unused1_1;
U32 Unused2_1;
U8 MfgSupportedSpeeds_1;
U8 MfgLinkType_1;
U8 MfgConnectorType_1;
U8 Filler_1;
_U32 PhyRegs234[3*2*3];
} ManufacturingPage3_949_t;
char *
skipLine(char *buf)
{
char *c = buf;
while (*c != '\n')
c++;
c++;
return c;
}
void
removeLine(char *buf)
{
char *c = skipLine(buf);
while (*c)
*buf++ = *c++;
*buf = '\0';
}
int
getNamedItem(MPT_PORT *port, char *name, char *buf, int type, void *address)
{
char *c;
int n;
int t;
n = (int)strlen(name);
while (*buf)
{
if (*buf == '#')
{
c = buf;
c++;
if (*c == ' ')
c++;
if (strncasecmp(name, c, n) == 0)
{
c = skipLine(c);
switch (type)
{
case 1:
t = sscanf(c, "%s", (char *)address);
// if (t == 1) printf("parsed item %s = <%s>\n", name, (char *)address);
break;
case 2:
t = sscanf(c, "%d", (int *)address);
// if (t == 1) printf("parsed item %s = <%d>\n", name, *(int *)address);
break;
case 3:
t = sscanf(c, "0x%x", (int *)address);
// if (t == 1) printf("parsed item %s = <0x%x>\n", name, *(int *)address);
break;
default:
t = 0;
}
if (t == 1)
{
removeLine(buf);
removeLine(buf);
return 1;
}
printf("Parse error on item %s!\n", name);
return 0;
}
}
buf = skipLine(buf);
}
printf("Item %s not found!\n", name);
return 0;
}
int
updateConfigPage(MPT_PORT *port, char *string, void *page)
{
ConfigPageHeader_t *header = (pConfigPageHeader_t)page;
int t;
t = setConfigPage(port, header->PageType & MPI_CONFIG_PAGETYPE_MASK, header->PageNumber, 0,
page, header->PageLength * 4);
if (t != 1)
printf("Failed to save %s to NVRAM!\n", string);
return t;
}
int
doWriteFcManufacturingInfo(MPT_PORT *port)
{
char name[256];
unsigned char *mfginfoBuf = NULL;
int mfginfoLen;
unsigned char *identityBuf = NULL;
int identityLen;
int n;
int i;
int t;
int version;
char *buf;
char temp[64];
char wwn[64];
char tracer[64];
char assembly[64];
char board[64];
char chip[64];
char revision[64];
int wwnl;
int device;
int pcirevision;
int subsys0;
int subsys1;
int subven0;
int subven1;
int pcimemory;
int class0;
int class1;
int hwconfig;
int linkconfig0;
int linkconfig1;
int ieeeident;
int phyreg10;
int phyreg11;
int phyreg20;
int phyreg21;
int phyreg2a0;
int phyreg2a1;
int phyreg234[3*2*3];
int conninfo0;
int conninfo1;
int connect0;
int connect1;
int flags;
int coalflags0;
int coaltime0;
int coaldepth0;
int coalflags1;
int coaltime1;
int coaldepth1;
ManufacturingPage0_t ManufacturingPage0;
ManufacturingPage2_929_t ManufacturingPage2_929;
ManufacturingPage2_929X_t ManufacturingPage2_929X;
ManufacturingPage2_949E_t ManufacturingPage2_949E;
ManufacturingPage3_929_t ManufacturingPage3_929;
ManufacturingPage3_949_t ManufacturingPage3_949;
IOUnitPage1_t IOUnitPage1;
IOCPage1_t IOCPage1;
FCPortPage1_t FCPortPage1;
U8 checksum;
U8 *mp2p;
MPT_PORT *temp_port;
MPT_PORT *partner_port;
char *c;
n = getFileName(name, sizeof name, stdin, "manufacturing information", 0);
if (n > 0)
{
if (readFile(name, &mfginfoBuf, &mfginfoLen) != 1)
return 0;
}
else
{
printf("Manufacturing information won't be programmed\n");
return 0;
}
printf("%d bytes read from %s\n\n", mfginfoLen, name);
*tracer = 0;
*assembly = 0;
*wwn = 0;
n = getFileName(name, sizeof name, stdin, "board identity", 1);
if (n > 0)
{
if (readFile(name, &identityBuf, &identityLen) != 1)
return 0;
printf("%d bytes read from %s\n\n", identityLen, name);
c = strchr((char *)identityBuf, '=');
if (c)
{
c = strchr((char *)identityBuf, '\n');
if (c)
{
if (strncmp(c + 1, "BoardAssembly = ", 16) == 0)
{
sscanf(c + 17, "%s", assembly);
c = strchr(c + 1, '\n');
}
}
if (c)
{
if (strncmp(c + 1, "BoardTracerNumber = ", 20) == 0)
{
sscanf(c + 21, "%s", tracer);
c = strchr(c + 1, '\n');
}
}
if (c)
{
if (strncmp(c + 1, "FC WWNN = ", 10) == 0)
{
sscanf(c + 11 + 10, "%s", wwn);
c = strchr(c + 1, '\n');
}
}
}
else
{
sscanf((char *)identityBuf, "%s", assembly);
c = strchr((char *)identityBuf, '\n');
if (c)
{
sscanf(c + 1, "%s", tracer);
c = strchr(c + 1, '\n');
}
if (c)
{
sscanf(c + 1, "%s", wwn);
c = strchr(c + 1, '\n');
}
}
if (strlen(tracer) != 10 && strlen(tracer) != 11)
{
printf("Board Tracer value <%s> is invalid!\n", tracer);
*tracer = 0;
}
if (strlen(assembly) != 12)
{
printf("Board Assembly value <%s> is invalid!\n", assembly);
*assembly = 0;
}
if (strlen(wwn) != 6 || sscanf(wwn, "%x", &wwnl) != 1)
{
printf("Board WWN value <%s> is invalid!\n", wwn);
*wwn = 0;
}
free(identityBuf);
}
else
{
printf("The board's identity must be entered manually!\n\n");
}
while (!*tracer || !*assembly || !*wwn)
{
printf("Board Tracer ...... %s\n", *tracer ? tracer : "not entered yet, 10 or 11 characters");
printf("Board Assembly .... %s\n", *assembly ? assembly : "not entered yet, 12 characters");
printf("Board WWN ......... %s\n", *wwn ? wwn : "not entered yet, 6 characters");
printf("\nEnter a value: [Tracer, Assembly, WWN, or Quit to quit] ");
while (TRUE)
{
n = getStringFromArgs(temp, sizeof temp, stdin);
if (n == 10 || n == 11)
{
strcpy(tracer, temp);
break;
}
else if (n == 12)
{
strcpy(assembly, temp);
break;
}
else if (n == 6)
{
if (sscanf(temp, "%x", &wwnl) == 1)
strcpy(wwn, temp);
break;
}
else if (n <= 4)
{
if (strncasecmp(temp, "quit", n) == 0)
return 0;
}
printf("Invalid response, try again: ");
}
}
printf("Board Tracer ...... %s\n", tracer);
printf("Board Assembly .... %s\n", assembly);
printf("Board WWN ......... %s\n", wwn);
if (yesFlag == FALSE)
{
printf("\nAre these values correct? [Yes or No, default is No] ");
if (getYesNoAnswer(0) != 1)
return 0;
}
if (wFlag)
{
fprintf(logFile, "%s: Board Tracer ...... %s\n", logPrefix(port), tracer);
fprintf(logFile, "%s: Board Assembly .... %s\n", logPrefix(port), assembly);
fprintf(logFile, "%s: Board WWN ......... %s\n", logPrefix(port), wwn);
}
n = mfginfoLen;
buf = realloc(mfginfoBuf, n + 2);
if (n && buf[n-1] != '\n')
{
mfginfoLen++;
buf[n++] = '\n';
}
buf[n] = '\0';
n = 0;
for (i = 0; i < mfginfoLen; i++)
{
if (buf[i] == '\0' || buf[i] == '\r') // NUL and CR are ignored
continue;
if (buf[i] == '#' && buf[i+1] == '#') // lines starting with ## are ignored
{
while (buf[i] != '\n' && i < mfginfoLen)
i++;
}
if (buf[i] == '(') // text after an open parenthesis is ignored
{
while (buf[i] != '\n' && i < mfginfoLen)
i++;
}
if (buf[i] == ' ' && buf[i+1] == '-' && buf[i+2] == ' ') // turn " - " into " "
{
buf[i+1] = ' ';
}
if (n)
{
if (buf[i] == '\n' && buf[n-1] == '\n') // blank lines are ignored
continue;
if (buf[i] == ' ' && buf[n-1] == ' ') // multiple spaces are collapsed
continue;
}
else
{
if (buf[i] == '\n') // blank lines are ignored
continue;
if (buf[i] == ' ') // leading spaces are collapsed
continue;
}
buf[n++] = buf[i];
}
buf[n] = '\0';
printf("\n");
t = getNamedItem(port, "Version", buf, 2, &version);
if (t != 1)
{
printf("Incorrectly formatted file, failed to find version\n");
return 0;
}
if (version != 3 && version != 4)
{
printf("Incorrectly formatted file, version should be 3 or 4\n");
return 0;
}
printf("Version %d found, processing...\n", version);
t += getNamedItem(port, "Assembly Number", buf, 1, temp);
t += getNamedItem(port, "PCI Device Id", buf, 3, &device);
t += getNamedItem(port, "Chip Revision Id", buf, 3, &pcirevision);
t += getNamedItem(port, "Board Name", buf, 1, board);
t += getNamedItem(port, "Chip Name", buf, 1, chip);
t += getNamedItem(port, "Chip Revision Name", buf, 1, revision);
if (t != 7)
{
printf("Could not read all required manufacturing information from file!\n");
return 0;
}
printf("\nBoard is %s, Assembly is %s, Chip is %s\n", board, temp, chip);
if (wFlag)
fprintf(logFile, "%s: Board is %s, Assembly is %s, Chip is %s\n",
logPrefix(port), board, temp, chip);
if (device != port->deviceIdRaw || pcirevision != port->revisionId ||
(strcasecmp(chip, port->chipName) && strcasecmp(chip + 3, port->chipName)) ||
strcasecmp(temp, assembly))
{
printf("Manufacturing information file is not for this chip!\n");
return 0;
}
device &= ~1;
if (strncmp(board, "LSI74", 5) == 0 || strncmp(board, "LSIFC74", 7) == 0)
{
getBoardInfo(port);
if (port->pciDevice == 6) // this is the second chip on a quad pci-x board
wwnl += 2;
if (port->pciDevice == 0) // this is either the first or second chip on a quad pci-e board
{
n = 1;
partner_port = NULL;
for (i = 0; i < NUM_PORTS; i++) // count how many 949E chips there are
{
temp_port = mptPorts[i];
if (temp_port == NULL || temp_port == port)
continue;
if (getBoardInfo(temp_port) == 1)
{
if (temp_port->deviceId == 0x646 &&
temp_port->pciDevice == 0 &&
temp_port->pciFunction == 0)
{
n++;
partner_port = temp_port;
}
}
}
if (n == 2) // if just two chips, the one with the higher bus is the second chip
{
if (port->pciBus > partner_port->pciBus)
wwnl += 2;
}
else // not the simple case, so ask the user
{
printf("\nIs this the first or second chip on this quad? [1=1st, 2=2nd, default is 1] ");
if (getNumberAnswer(1, 2, 1) == 2)
wwnl += 2;
}
}
}
t += getNamedItem(port, "PCI Memory", buf, 3, &pcimemory);
t += getNamedItem(port, "Subsystem Id 0", buf, 3, &subsys0);
t += getNamedItem(port, "Subsystem Vendor Id 0", buf, 3, &subven0);
t += getNamedItem(port, "Class Code 0", buf, 3, &class0);
if (device != 0x646)
{
t += getNamedItem(port, "Subsystem Id 1", buf, 3, &subsys1);
t += getNamedItem(port, "Subsystem Vendor Id 1", buf, 3, &subven1);
t += getNamedItem(port, "Class Code 1", buf, 3, &class1);
t += getNamedItem(port, "Hardware Config", buf, 3, &hwconfig);
}
t += getNamedItem(port, "IOUnit1Flags", buf, 3, &flags);
t += getNamedItem(port, "IEEE Ident", buf, 3, &ieeeident);
t += getNamedItem(port, "LinkConfig Port 0", buf, 3, &linkconfig0);
t += getNamedItem(port, "PhyReg1 Port 0", buf, 3, &phyreg10);
t += getNamedItem(port, "PhyReg2 Port 0", buf, 3, &phyreg20);
t += getNamedItem(port, "PhyReg2Alt Port 0", buf, 3, &phyreg2a0);
t += getNamedItem(port, "ConnectInfo Port 0", buf, 3, &conninfo0);
t += getNamedItem(port, "Connector Port 0", buf, 3, &connect0);
t += getNamedItem(port, "Coalescing Flags 0", buf, 3, &coalflags0);
t += getNamedItem(port, "Coalescing Microseconds 0", buf, 3, &coaltime0);
t += getNamedItem(port, "Coalescing Depth 0", buf, 3, &coaldepth0);
if (!(flags & MPI_IOUNITPAGE1_SINGLE_FUNCTION))
{
t += getNamedItem(port, "LinkConfig Port 1", buf, 3, &linkconfig1);
t += getNamedItem(port, "PhyReg1 Port 1", buf, 3, &phyreg11);
t += getNamedItem(port, "PhyReg2 Port 1", buf, 3, &phyreg21);
t += getNamedItem(port, "PhyReg2Alt Port 1", buf, 3, &phyreg2a1);
t += getNamedItem(port, "ConnectInfo Port 1", buf, 3, &conninfo1);
t += getNamedItem(port, "Connector Port 1", buf, 3, &connect1);
t += getNamedItem(port, "Coalescing Flags 1", buf, 3, &coalflags1);
t += getNamedItem(port, "Coalescing Depth 1", buf, 3, &coaldepth1);
t += getNamedItem(port, "Coalescing Microseconds 1", buf, 3, &coaltime1);
}
if (device == 0x640 || device == 0x642 || device == 0x646)
{
t += getNamedItem(port, "PhyReg2A1", buf, 3, &phyreg234[0]);
t += getNamedItem(port, "PhyReg3A1", buf, 3, &phyreg234[1]);
t += getNamedItem(port, "PhyReg4A1", buf, 3, &phyreg234[2]);
t += getNamedItem(port, "PhyReg2A2", buf, 3, &phyreg234[3]);
t += getNamedItem(port, "PhyReg3A2", buf, 3, &phyreg234[4]);
t += getNamedItem(port, "PhyReg4A2", buf, 3, &phyreg234[5]);
t += getNamedItem(port, "PhyReg2A4", buf, 3, &phyreg234[6]);
t += getNamedItem(port, "PhyReg3A4", buf, 3, &phyreg234[7]);
t += getNamedItem(port, "PhyReg4A4", buf, 3, &phyreg234[8]);
t += getNamedItem(port, "PhyReg2P1", buf, 3, &phyreg234[9]);
t += getNamedItem(port, "PhyReg3P1", buf, 3, &phyreg234[10]);
t += getNamedItem(port, "PhyReg4P1", buf, 3, &phyreg234[11]);
t += getNamedItem(port, "PhyReg2P2", buf, 3, &phyreg234[12]);
t += getNamedItem(port, "PhyReg3P2", buf, 3, &phyreg234[13]);
t += getNamedItem(port, "PhyReg4P2", buf, 3, &phyreg234[14]);
t += getNamedItem(port, "PhyReg2P4", buf, 3, &phyreg234[15]);
t += getNamedItem(port, "PhyReg3P4", buf, 3, &phyreg234[16]);
t += getNamedItem(port, "PhyReg4P4", buf, 3, &phyreg234[17]);
}
n = 1000;
if (device == 0x622 || device == 0x624)
n = 35;
if (device == 0x626 || device == 0x628)
n = 35;
if (device == 0x640 || device == 0x642)
n = 53;
if (device == 0x646)
n = 49;
if (flags & MPI_IOUNITPAGE1_SINGLE_FUNCTION)
n -= 9;
if (t != n)
{
printf("\nCould not read all required manufacturing information from file!\n");
printf("Parsed %d out of %d items\n", t, n);
return 0;
}
if (strlen(buf))
{
printf("\nExtra lines found in manufacturing information file!\n");
printf("----\n%s----\n", buf);
if (wFlag)
{
fprintf(logFile, "%s: Extra lines found in manufacturing information file!\n", logPrefix(port));
fprintf(logFile, "----\n%s----\n", buf);
}
}
free(buf);
doIocInit(port, MPI_WHOINIT_MANUFACTURER);
memset(&ManufacturingPage0, 0, sizeof ManufacturingPage0);
ManufacturingPage0.Header.PageVersion = MPI_MANUFACTURING0_PAGEVERSION;
ManufacturingPage0.Header.PageLength = sizeof ManufacturingPage0 / 4;
ManufacturingPage0.Header.PageNumber = 0;
ManufacturingPage0.Header.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING |
MPI_CONFIG_PAGEATTR_PERSISTENT;
strcpy((char *)ManufacturingPage0.ChipName, chip);
strcpy((char *)ManufacturingPage0.ChipRevision, revision);
strcpy((char *)ManufacturingPage0.BoardName, board);
strcpy((char *)ManufacturingPage0.BoardAssembly, assembly);
strcpy((char *)ManufacturingPage0.BoardTracerNumber, tracer);
updateConfigPage(port, "ManufacturingPage0", &ManufacturingPage0);
if (device == 0x622 || device == 0x624)
{
memset(&ManufacturingPage2_929, 0, sizeof ManufacturingPage2_929);
ManufacturingPage2_929.Header.PageVersion = MPI_MANUFACTURING2_PAGEVERSION;
ManufacturingPage2_929.Header.PageLength = sizeof ManufacturingPage2_929 / 4;
ManufacturingPage2_929.Header.PageNumber = 2;
ManufacturingPage2_929.Header.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING |
MPI_CONFIG_PAGEATTR_PERSISTENT;
ManufacturingPage2_929.ChipId.DeviceID = set16(port->deviceIdRaw);
ManufacturingPage2_929.ChipId.PCIRevisionID = port->revisionId;
ManufacturingPage2_929.SubsystemVendorId_0[0] = (U8)(subven0 >> 8*0);
ManufacturingPage2_929.SubsystemVendorId_0[1] = (U8)(subven0 >> 8*1);
ManufacturingPage2_929.SubsystemId_0[0] = (U8)(subsys0 >> 8*0);
ManufacturingPage2_929.SubsystemId_0[1] = (U8)(subsys0 >> 8*1);
ManufacturingPage2_929.ClassCode_0[0] = (U8)(class0 >> 8*0);
ManufacturingPage2_929.ClassCode_0[1] = (U8)(class0 >> 8*1);
ManufacturingPage2_929.ClassCode_0[2] = (U8)(class0 >> 8*2);
ManufacturingPage2_929.PciMemory = (U8)(pcimemory >> 8*0);
ManufacturingPage2_929.HardwareConfig[0] = (U8)(hwconfig >> 8*0);
ManufacturingPage2_929.SubsystemVendorId_1[0] = (U8)(subven1 >> 8*0);
ManufacturingPage2_929.SubsystemVendorId_1[1] = (U8)(subven1 >> 8*1);
ManufacturingPage2_929.SubsystemId_1[0] = (U8)(subsys1 >> 8*0);
ManufacturingPage2_929.SubsystemId_1[1] = (U8)(subsys1 >> 8*1);
ManufacturingPage2_929.ClassCode_1[0] = (U8)(class1 >> 8*0);
ManufacturingPage2_929.ClassCode_1[1] = (U8)(class1 >> 8*1);
ManufacturingPage2_929.ClassCode_1[2] = (U8)(class1 >> 8*2);
checksum = 0xa5;
mp2p = (U8 *)&ManufacturingPage2_929;
for (i = sizeof ManufacturingPage2_929.Header + sizeof ManufacturingPage2_929.ChipId;
i < offsetof(ManufacturingPage2_929_t, Checksum);
i++)
{
checksum += mp2p[i];
}
ManufacturingPage2_929.Checksum = -checksum;
updateConfigPage(port, "ManufacturingPage2", &ManufacturingPage2_929);
}
if (device == 0x626 || device == 0x628 || device == 0x640 || device == 0x642)
{
memset(&ManufacturingPage2_929X, 0, sizeof ManufacturingPage2_929X);
ManufacturingPage2_929X.Header.PageVersion = MPI_MANUFACTURING2_PAGEVERSION;
ManufacturingPage2_929X.Header.PageLength = sizeof ManufacturingPage2_929X / 4;
ManufacturingPage2_929X.Header.PageNumber = 2;
ManufacturingPage2_929X.Header.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING |
MPI_CONFIG_PAGEATTR_PERSISTENT;
ManufacturingPage2_929X.ChipId.DeviceID = set16(port->deviceIdRaw);
ManufacturingPage2_929X.ChipId.PCIRevisionID = port->revisionId;
ManufacturingPage2_929X.SubsystemVendorId_0[0] = (U8)(subven0 >> 8*0);
ManufacturingPage2_929X.SubsystemVendorId_0[1] = (U8)(subven0 >> 8*1);
ManufacturingPage2_929X.SubsystemId_0[0] = (U8)(subsys0 >> 8*0);
ManufacturingPage2_929X.SubsystemId_0[1] = (U8)(subsys0 >> 8*1);
ManufacturingPage2_929X.ClassCode_0[0] = (U8)(class0 >> 8*0);
ManufacturingPage2_929X.ClassCode_0[1] = (U8)(class0 >> 8*1);
ManufacturingPage2_929X.ClassCode_0[2] = (U8)(class0 >> 8*2);
ManufacturingPage2_929X.PciMemory = (U8)(pcimemory >> 8*0);
ManufacturingPage2_929X.HardwareConfig[0] = (U8)(hwconfig >> 8*0);
ManufacturingPage2_929X.HardwareConfig[1] = (U8)(hwconfig >> 8*1);
ManufacturingPage2_929X.SubsystemVendorId_1[0] = (U8)(subven1 >> 8*0);
ManufacturingPage2_929X.SubsystemVendorId_1[1] = (U8)(subven1 >> 8*1);
ManufacturingPage2_929X.SubsystemId_1[0] = (U8)(subsys1 >> 8*0);
ManufacturingPage2_929X.SubsystemId_1[1] = (U8)(subsys1 >> 8*1);
ManufacturingPage2_929X.ClassCode_1[0] = (U8)(class1 >> 8*0);
ManufacturingPage2_929X.ClassCode_1[1] = (U8)(class1 >> 8*1);
ManufacturingPage2_929X.ClassCode_1[2] = (U8)(class1 >> 8*2);
checksum = 0xa5;
mp2p = (U8 *)&ManufacturingPage2_929X;
for (i = sizeof ManufacturingPage2_929X.Header + sizeof ManufacturingPage2_929X.ChipId;
i < offsetof(ManufacturingPage2_929X_t, Checksum);
i++)
{
checksum += mp2p[i];
}
ManufacturingPage2_929X.Checksum = -checksum;
updateConfigPage(port, "ManufacturingPage2", &ManufacturingPage2_929X);
}
if (device == 0x646)
{
memset(&ManufacturingPage2_949E, 0, sizeof ManufacturingPage2_949E);
ManufacturingPage2_949E.Header.PageVersion = MPI_MANUFACTURING2_PAGEVERSION;
ManufacturingPage2_949E.Header.PageLength = sizeof ManufacturingPage2_949E / 4;
ManufacturingPage2_949E.Header.PageNumber = 2;
ManufacturingPage2_949E.Header.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING |
MPI_CONFIG_PAGEATTR_PERSISTENT;
ManufacturingPage2_949E.ChipId.DeviceID = set16(port->deviceIdRaw);
ManufacturingPage2_949E.ChipId.PCIRevisionID = port->revisionId;
ManufacturingPage2_949E.SubsystemVendorId[0] = (U8)(subven0 >> 8*0);
ManufacturingPage2_949E.SubsystemVendorId[1] = (U8)(subven0 >> 8*1);
ManufacturingPage2_949E.SubsystemId[0] = (U8)(subsys0 >> 8*0);
ManufacturingPage2_949E.SubsystemId[1] = (U8)(subsys0 >> 8*1);
ManufacturingPage2_949E.ClassCode[0] = (U8)(class0 >> 8*0);
ManufacturingPage2_949E.ClassCode[1] = (U8)(class0 >> 8*1);
ManufacturingPage2_949E.ClassCode[2] = (U8)(class0 >> 8*2);
ManufacturingPage2_949E.PciMemory = (U8)(pcimemory >> 8*0);
checksum = 0xa5;
mp2p = (U8 *)&ManufacturingPage2_949E;
for (i = sizeof ManufacturingPage2_949E.Header + sizeof ManufacturingPage2_949E.ChipId;
i < offsetof(ManufacturingPage2_949E_t, Checksum);
i++)
{
checksum += mp2p[i];
}
ManufacturingPage2_949E.Checksum = -checksum;
updateConfigPage(port, "ManufacturingPage2", &ManufacturingPage2_949E);
}
if (device == 0x622 || device == 0x624 || device == 0x626 || device == 0x628)
{
memset(&ManufacturingPage3_929, 0, sizeof ManufacturingPage3_929);
ManufacturingPage3_929.Header.PageVersion = MPI_MANUFACTURING3_PAGEVERSION;
ManufacturingPage3_929.Header.PageLength = sizeof ManufacturingPage3_929 / 4;
ManufacturingPage3_929.Header.PageNumber = 3;
ManufacturingPage3_929.Header.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING |
MPI_CONFIG_PAGEATTR_PERSISTENT;
ManufacturingPage3_929.ChipId.DeviceID = set16(port->deviceIdRaw);
ManufacturingPage3_929.ChipId.PCIRevisionID = port->revisionId;
ManufacturingPage3_929.WWPN_0.Low = set32((wwnl & 0xffffff) | ((ieeeident & 0xff) << 24));
ManufacturingPage3_929.WWPN_0.High = set32(0x10000000 | ((ieeeident & 0xffff00) >> 8));
ManufacturingPage3_929.WWNN_0.Low = set32((wwnl & 0xffffff) | ((ieeeident & 0xff) << 24));
ManufacturingPage3_929.WWNN_0.High = set32(0x20000000 | ((ieeeident & 0xffff00) >> 8));
ManufacturingPage3_929.PhyRegs1_0 = set32(phyreg10);
ManufacturingPage3_929.PhyRegs2_0 = set32(phyreg20);
ManufacturingPage3_929.PhyRegs2_Alt_0 = set32(phyreg2a0);
ManufacturingPage3_929.MfgSupportedSpeeds_0 = (U8)(conninfo0 >> 8*0);
ManufacturingPage3_929.MfgLinkType_0 = (U8)(conninfo0 >> 8*1);
ManufacturingPage3_929.MfgConnectorType_0 = (U8)(conninfo0 >> 8*2);
if (!(flags & MPI_IOUNITPAGE1_SINGLE_FUNCTION))
{
ManufacturingPage3_929.WWPN_1.Low = set32(get32(ManufacturingPage3_929.WWPN_0.Low) + 1);
ManufacturingPage3_929.WWPN_1.High = ManufacturingPage3_929.WWPN_0.High;
ManufacturingPage3_929.WWNN_1.Low = set32(get32(ManufacturingPage3_929.WWNN_0.Low) + 1);
ManufacturingPage3_929.WWNN_1.High = ManufacturingPage3_929.WWNN_0.High;
ManufacturingPage3_929.PhyRegs1_1 = set32(phyreg11);
ManufacturingPage3_929.PhyRegs2_1 = set32(phyreg21);
ManufacturingPage3_929.PhyRegs2_Alt_1 = set32(phyreg2a1);
ManufacturingPage3_929.MfgSupportedSpeeds_1 = (U8)(conninfo1 >> 8*0);
ManufacturingPage3_929.MfgLinkType_1 = (U8)(conninfo1 >> 8*1);
ManufacturingPage3_929.MfgConnectorType_1 = (U8)(conninfo1 >> 8*2);
}
updateConfigPage(port, "ManufacturingPage3", &ManufacturingPage3_929);
}
if (device == 0x640 || device == 0x642 || device == 0x646)
{
memset(&ManufacturingPage3_949, 0, sizeof ManufacturingPage3_949);
ManufacturingPage3_949.Header.PageVersion = MPI_MANUFACTURING3_PAGEVERSION;
ManufacturingPage3_949.Header.PageLength = sizeof ManufacturingPage3_949 / 4;
ManufacturingPage3_949.Header.PageNumber = 3;
ManufacturingPage3_949.Header.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING |
MPI_CONFIG_PAGEATTR_PERSISTENT;
ManufacturingPage3_949.ChipId.DeviceID = set16(port->deviceIdRaw);
ManufacturingPage3_949.ChipId.PCIRevisionID = port->revisionId;
ManufacturingPage3_949.WWPN_0.Low = set32((wwnl & 0xffffff) | ((ieeeident & 0xff) << 24));
ManufacturingPage3_949.WWPN_0.High = set32(0x10000000 | ((ieeeident & 0xffff00) >> 8));
ManufacturingPage3_949.WWNN_0.Low = set32((wwnl & 0xffffff) | ((ieeeident & 0xff) << 24));
ManufacturingPage3_949.WWNN_0.High = set32(0x20000000 | ((ieeeident & 0xffff00) >> 8));
ManufacturingPage3_949.PhyRegs1_0 = set32(phyreg10);
ManufacturingPage3_949.MfgSupportedSpeeds_0 = (U8)(conninfo0 >> 8*0);
ManufacturingPage3_949.MfgLinkType_0 = (U8)(conninfo0 >> 8*1);
ManufacturingPage3_949.MfgConnectorType_0 = (U8)(conninfo0 >> 8*2);
if (!(flags & MPI_IOUNITPAGE1_SINGLE_FUNCTION))
{
ManufacturingPage3_949.WWPN_1.Low = set32(get32(ManufacturingPage3_949.WWPN_0.Low) + 1);
ManufacturingPage3_949.WWPN_1.High = ManufacturingPage3_949.WWPN_0.High;
ManufacturingPage3_949.WWNN_1.Low = set32(get32(ManufacturingPage3_949.WWNN_0.Low) + 1);
ManufacturingPage3_949.WWNN_1.High = ManufacturingPage3_949.WWNN_0.High;
ManufacturingPage3_949.PhyRegs1_1 = set32(phyreg11);
ManufacturingPage3_949.MfgSupportedSpeeds_1 = (U8)(conninfo1 >> 8*0);
ManufacturingPage3_949.MfgLinkType_1 = (U8)(conninfo1 >> 8*1);
ManufacturingPage3_949.MfgConnectorType_1 = (U8)(conninfo1 >> 8*2);
}
for (i = 0; i < 3*2*3; i++)
ManufacturingPage3_949.PhyRegs234[i] = set32(phyreg234[i]);
updateConfigPage(port, "ManufacturingPage3", &ManufacturingPage3_949);
}
doIocInit(port, port->whoInit);
memset(&IOUnitPage1, 0, sizeof IOUnitPage1);
IOUnitPage1.Header.PageVersion = MPI_IOUNITPAGE1_PAGEVERSION;
IOUnitPage1.Header.PageLength = sizeof IOUnitPage1 / 4;
IOUnitPage1.Header.PageNumber = 1;
IOUnitPage1.Header.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT |
MPI_CONFIG_PAGEATTR_PERSISTENT;
IOUnitPage1.Flags = set32(flags);
updateConfigPage(port, "IOUnitPage1", &IOUnitPage1);
memset(&IOCPage1, 0, sizeof IOCPage1);
IOCPage1.Header.PageVersion = MPI_IOCPAGE1_PAGEVERSION;
IOCPage1.Header.PageLength = sizeof IOCPage1 / 4;
IOCPage1.Header.PageNumber = 1;
IOCPage1.Header.PageType = MPI_CONFIG_PAGETYPE_IOC |
MPI_CONFIG_PAGEATTR_PERSISTENT;
if (port->iocNumber == 0)
{
IOCPage1.Flags = set32(coalflags0);
IOCPage1.CoalescingTimeout = set32(coaltime0);
IOCPage1.CoalescingDepth = coaldepth0;
}
else
{
IOCPage1.Flags = set32(coalflags1);
IOCPage1.CoalescingTimeout = set32(coaltime1);
IOCPage1.CoalescingDepth = coaldepth1;
}
IOCPage1.PCISlotNum = MPI_IOCPAGE1_PCISLOTNUM_UNKNOWN;
updateConfigPage(port, "IOCPage1", &IOCPage1);
memset(&FCPortPage1, 0, sizeof FCPortPage1);
FCPortPage1.Header.PageVersion = MPI_FCPORTPAGE1_PAGEVERSION;
FCPortPage1.Header.PageLength = sizeof FCPortPage1 / 4;
FCPortPage1.Header.PageNumber = 1;
FCPortPage1.Header.PageType = MPI_CONFIG_PAGETYPE_FC_PORT |
MPI_CONFIG_PAGEATTR_PERSISTENT;
FCPortPage1.Flags = set32(MPI_FCPORTPAGE1_FLAGS_SORT_BY_WWN |
MPI_FCPORTPAGE1_FLAGS_PROT_FCP_INIT |
MPI_FCPORTPAGE1_FLAGS_PROT_FCP_TARG |
MPI_FCPORTPAGE1_FLAGS_PROT_LAN |
MPI_FCPORTPAGE1_FLAGS_PROT_LOGBUSADDR);
FCPortPage1.NoSEEPROMWWNN.Low = set32(0x10001000);
FCPortPage1.NoSEEPROMWWNN.High = set32(0x200000a0);
FCPortPage1.NoSEEPROMWWPN.Low = set32(0x10001000);
FCPortPage1.NoSEEPROMWWPN.High = set32(0x100000a0);
FCPortPage1.HardALPA = MPI_FCPORTPAGE1_HARD_ALPA_NOT_USED;
FCPortPage1.TopologyConfig = MPI_FCPORTPAGE1_TOPOLOGY_AUTO;
if (port->iocNumber == 0)
{
FCPortPage1.LinkConfig = linkconfig0;
FCPortPage1.AltConnector = connect0;
}
else
{
FCPortPage1.LinkConfig = linkconfig1;
FCPortPage1.AltConnector = connect1;
}
updateConfigPage(port, "FCPortPage1", &FCPortPage1);
if (flags & MPI_IOUNITPAGE1_SINGLE_FUNCTION)
return 1;
if (getBoardInfo(port) != 1)
return 1;
partner_port = NULL;
for (i = 0; i < NUM_PORTS; i++)
{
temp_port = mptPorts[i];
if (temp_port == NULL || temp_port == port)
continue;
if (getBoardInfo(temp_port) == 1)
{
if (port->pciBus == temp_port->pciBus &&
port->pciDevice == temp_port->pciDevice &&
port->pciFunction == (temp_port->pciFunction ^ 1))
{
partner_port = temp_port;
printf("\nPartner of %s is %s\n", port->portName, partner_port->portName);
if (wFlag)
fprintf(logFile, "%s: Partner is %s\n", logPrefix(port), partner_port->portName);
break;
}
}
}
if (i == NUM_PORTS)
return 1;
temp_port = port;
port = partner_port;
if (port->iocNumber == 0)
{
IOCPage1.Flags = set32(coalflags0);
IOCPage1.CoalescingTimeout = set32(coaltime0);
IOCPage1.CoalescingDepth = coaldepth0;
}
else
{
IOCPage1.Flags = set32(coalflags1);
IOCPage1.CoalescingTimeout = set32(coaltime1);
IOCPage1.CoalescingDepth = coaldepth1;
}
IOCPage1.PCISlotNum = MPI_IOCPAGE1_PCISLOTNUM_UNKNOWN;
updateConfigPage(port, "IOCPage1", &IOCPage1);
if (port->iocNumber == 0)
{
FCPortPage1.LinkConfig = linkconfig0;
FCPortPage1.AltConnector = connect0;
}
else
{
FCPortPage1.LinkConfig = linkconfig1;
FCPortPage1.AltConnector = connect1;
}
updateConfigPage(port, "FCPortPage1", &FCPortPage1);
return 1;
}
int
doWriteSasManufacturingInfo(MPT_PORT *port)
{
char name[256];
unsigned char *identityBuf = NULL;
int identityLen;
int length;
int n;
int t;
char temp[64];
char wwid[64];
char tracer[64];
char assembly[64];
char board[64];
char chip[64];
char revision[64];
int wwidl;
int wwidh;
ManufacturingPage0_t ManufacturingPage0;
ManufacturingPage5_t *ManufacturingPage5;
Mpi2ManufacturingPage5_t *ManufacturingPage5_2;
char *c;
U32 prefix;
int phy_num;
if (getConfigPage(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
&ManufacturingPage0, sizeof ManufacturingPage0) != 1)
{
printf("ManufacturingPage0 is not valid!\n");
return 0;
}
strcpy(board, (char *)ManufacturingPage0.BoardName);
strcpy(chip, (char *)ManufacturingPage0.ChipName);
strcpy(revision, (char *)ManufacturingPage0.ChipRevision);
ManufacturingPage5 = getConfigPageAlloc(port, MPI_CONFIG_PAGETYPE_MANUFACTURING, 5, 0, &length);
if (ManufacturingPage5 == NULL)
{
printf("ManufacturingPage5 is not valid!\n");
return 0;
}
ManufacturingPage5_2 = (pMpi2ManufacturingPage5_t)ManufacturingPage5;
*tracer = 0;
*assembly = 0;
*wwid = 0;
n = getFileName(name, sizeof name, stdin, "board identity", 0);
if (n > 0)
{
if (readFile(name, &identityBuf, &identityLen) != 1)
{
free(ManufacturingPage5);
return 0;
}
printf("%d bytes read from %s\n\n", identityLen, name);
c = strchr((char *)identityBuf, '=');
if (c)
{
c = strchr((char *)identityBuf, '\n');
if (c)
{
if (strncmp(c + 1, "BoardAssembly = ", 16) == 0)
{
sscanf(c + 17, "%s", assembly);
c = strchr(c + 1, '\n');
}
}
if (c)
{
if (strncmp(c + 1, "BoardTracerNumber = ", 20) == 0)
{
sscanf(c + 21, "%s", tracer);
c = strchr(c + 1, '\n');
}
}
if (c)
{
if (strncmp(c + 1, "SAS WWID = ", 11) == 0)
{
sscanf(c + 12, "%s", wwid);
c = strchr(c + 1, '\n');
}
}
}
else
{
sscanf((char *)identityBuf, "%s", assembly);
c = strchr((char *)identityBuf, '\n');
if (c)
{
sscanf(c + 1, "%s", tracer);
c = strchr(c + 1, '\n');
}
if (c)
{
sscanf(c + 2, "%s", wwid); // skip the leading '1' digit!
c = strchr(c + 1, '\n');
}
}
if (strlen(tracer) != 10 && strlen(tracer) != 11 && strlen(tracer) != 14)
{
printf("Board Tracer value <%s> is invalid!\n", tracer);
*tracer = 0;
}
if (strlen(assembly) != 12)
{
printf("Board Assembly value <%s> is invalid!\n", assembly);
*assembly = 0;
}
if ((strlen(wwid) != 9 && strlen(wwid) != 16) ||
sscanf(wwid, "%x", &t) != 1 || sscanf(wwid + 8, "%x", &t) != 1)
{
printf("Board WWID value <%s> is invalid!\n", wwid);
*wwid = 0;
}
free(identityBuf);
}
else
{
printf("The board's identity must be entered manually!\n\n");
}
while (!*tracer || !*assembly || !*wwid)
{
printf("Board Tracer ...... %s\n", *tracer ? tracer : "not entered yet, 10, 11 or 14 characters");
printf("Board Assembly .... %s\n", *assembly ? assembly : "not entered yet, 12 characters");
printf("Board WWID ........ %s\n", *wwid ? wwid : "not entered yet, 9 or 16 characters");
printf("\nEnter a value: [Tracer, Assembly, WWID, or Quit to quit] ");
while (TRUE)
{
n = getStringFromArgs(temp, sizeof temp, stdin);
if (n == 10 || n == 11 || n == 14)
{
strcpy(tracer, temp);
break;
}
else if (n == 12)
{
strcpy(assembly, temp);
break;
}
else if (n == 9 || n == 16)
{
if (sscanf(temp, "%x", &wwidl) == 1 && sscanf(temp + 8, "%x", &wwidl) == 1)
strcpy(wwid, temp);
break;
}
else if (n <= 4)
{
if (strncasecmp(temp, "quit", n) == 0)
{
free(ManufacturingPage5);
return 0;
}
}
printf("Invalid response, try again: ");
}
}
printf("Board Tracer ...... %s\n", tracer);
printf("Board Assembly .... %s\n", assembly);
printf("Board WWID ........ %s\n", wwid);
if (yesFlag == FALSE)
{
printf("\nAre these values correct? [Yes or No, default is No] ");
if (getYesNoAnswer(0) != 1)
{
free(ManufacturingPage5);
return 0;
}
}
if (wFlag)
{
fprintf(logFile, "%s: Board Tracer ...... %s\n", logPrefix(port), tracer);
fprintf(logFile, "%s: Board Assembly .... %s\n", logPrefix(port), assembly);
fprintf(logFile, "%s: Board WWID ........ %s\n", logPrefix(port), wwid);
}
if (strlen(wwid) == 9)
{
sscanf(wwid + 1, "%x", &wwidl);
wwid[1] = '\0';
sscanf(wwid, "%x", &wwidh);
if (mpi2)
prefix = get32(ManufacturingPage5_2->Phy[0].WWID.High) >> 4;
else
prefix = get32(ManufacturingPage5->BaseWWID.High) >> 4;
if (prefix == 0)
{
if (port->deviceId == MPI_MANUFACTPAGE_DEVID_SAS1064 ||
port->deviceId == MPI_MANUFACTPAGE_DEVID_SAS1064E)
{
prefix = 0x500062b;
}
else
{
prefix = 0x500605b;
}
printf("Enter the SAS WWID prefix: [7 hex digits, default is %07x] ", prefix);
getHexNumberAnswer(&prefix);
}
wwidh |= prefix << 4;
}
else
{
sscanf(wwid + 8, "%x", &wwidl);
wwid[8] = '\0';
sscanf(wwid, "%x", &wwidh);
}
printf("\nBoard is %s, Assembly is %s, Chip is %s\n", board, assembly, chip);
if (wFlag)
fprintf(logFile, "%s: Board is %s, Assembly is %s, Chip is %s\n",
logPrefix(port), board, temp, chip);
strcpy((char *)ManufacturingPage0.BoardAssembly, assembly);
strcpy((char *)ManufacturingPage0.BoardTracerNumber, tracer);
if (mpi2)
{
for(phy_num = 0; phy_num < port->numPhys; phy_num++)
{
ManufacturingPage5_2->Phy[phy_num].WWID.Low = set32(wwidl + phy_num);
ManufacturingPage5_2->Phy[phy_num].WWID.High = set32(wwidh);
}
}
else
{
ManufacturingPage5->BaseWWID.Low = set32(wwidl);
ManufacturingPage5->BaseWWID.High = set32(wwidh);
}
doIocInit(port, MPI_WHOINIT_MANUFACTURER);
updateConfigPage(port, "ManufacturingPage0", &ManufacturingPage0);
updateConfigPage(port, "ManufacturingPage5", ManufacturingPage5);
doIocInit(port, port->whoInit);
free(ManufacturingPage5);
return 1;
}
#undef mpi1
#undef mpi2
#undef mpi20
#undef mpi25
#undef MPI1
#undef MPI2
#undef MPI20
#undef MPI25
typedef struct
{
_U32 Signature;
U8 State;
U8 Checksum;
_U16 TotalBytes;
_U16 NvdataVersion;
_U16 MpiVersion;
U8 CdhSize;
U8 CdeSize;
U8 PphSize;
U8 ProdIdSize;
_U32 NbrDirEntries;
_U32 NbrPersistDirEntries;
_U32 SeepromFwVarsOffset;
_U32 SeepromBufferOffset;
U32 Reserved;
} CONFIG_DIR_HEADER;
typedef struct
{
_U32 Signature;
U8 State;
U8 Reserved1;
_U16 TotalBytes;
_U16 NvdataVersion;
_U16 MpiVersion;
U8 CdhSize;
U8 CdeSize;
U8 PphSize;
U8 ProdIdSize;
_U32 NbrDirEntries;
_U32 NbrPersistDirEntries;
U32 Reserved3;
_U16 ProductIdOffset;
_U16 DirEntryOffset;
_U32 VendorNvramVersion;
} CONFIG_DIR_HEADER2;
#define CONFIG_DIR_HEADER_SIGNATURE (0x4E69636B)
#define CONFIG_DIR_HEADER_STATE_ERASED (0xFF)
#define CONFIG_DIR_HEADER_STATE_INITIALIZATION (CONFIG_DIR_HEADER_STATE_ERASED & ~0x01)
#define CONFIG_DIR_HEADER_STATE_RCV_DATA (CONFIG_DIR_HEADER_STATE_INITIALIZATION & ~0x02)
#define CONFIG_DIR_HEADER_STATE_VALID (CONFIG_DIR_HEADER_STATE_RCV_DATA & ~0x04)
#define CONFIG_DIR_HEADER_STATE_XFER_COMPLETE (CONFIG_DIR_HEADER_STATE_VALID & ~0x08)
typedef struct
{
_U32 Signature;
U8 VendorId[8];
U8 ProductId[16];
U8 ProductRevision[4];
U32 Reserved1;
U32 Reserved2;
U32 Reserved3;
U32 Reserved4;
U32 Reserved5;
U32 Reserved6;
U32 Reserved7;
U32 Reserved8;
} CONFIG_PROD_ID;
#define CONFIG_PROD_ID_SIGNATURE (0x4672617A)
typedef struct
{
U32 State : 4;
U32 AllocUnits : 12;
U32 PageType : 8;
U32 PageNum : 4;
U32 ForceNvdataUpdate : 1;
U32 PersistPageUpdated : 1;
U32 FlagRsvd1 : 1;
U32 FlagRsvd2 : 1;
U32 DwordOffset : 15;
U32 IocNum : 1;
U32 PageAddress : 16;
} CONFIG_DIR_ENTRY;
typedef struct
{
U8 State;
U8 Reserved;
_U16 AllocUnits;
U8 PageType;
U8 PageNum;
U8 UpdateFlags;
U8 IocNum;
_U32 DwordOffset;
_U32 PageAddress;
} CONFIG_DIR_ENTRY2;
#define CONFIG_DIR_ENTRY_STATE_ERASED (0xF)
#define CONFIG_DIR_ENTRY_STATE_BEGIN_UPDATE (CONFIG_DIR_ENTRY_STATE_ERASED & ~0x1)
#define CONFIG_DIR_ENTRY_STATE_IN_USE (CONFIG_DIR_ENTRY_STATE_BEGIN_UPDATE & ~0x2)
typedef struct
{
U8 State;
U8 Checksum;
_U16 DwordOffset;
} PERSISTENT_PAGE_HEADER;
typedef struct
{
U8 State;
U8 Checksum;
U16 Reserved;
_U32 DwordOffset;
} PERSISTENT_PAGE_HEADER2;
#define CONFIG_PERSISTENT_HEADER_STATE_ERASED (0xFF)
#define CONFIG_PERSISTENT_HEADER_STATE_BEGIN_UPATE (CONFIG_PERSISTENT_HEADER_STATE_ERASED & ~0x01)
#define CONFIG_PERSISTENT_HEADER_STATE_UPDATE_COMPLETE (CONFIG_PERSISTENT_HEADER_STATE_BEGIN_UPATE & ~0x02)
#define CONFIG_PERSISTENT_HEADER_STATE_USE_NEXT_COPY (CONFIG_PERSISTENT_HEADER_STATE_UPDATE_COMPLETE & ~0x04)
#if VERIFY_ENDIANNESS && EFIEBC
int
concatenateSasFirmwareNvdata(void)
{
return 0;
}
#else
typedef struct
{
CONFIG_PAGE_HEADER Header;
MPI_CHIP_REVISION_ID ChipId;
U16 SubSystemIDFunc0;
U16 SubSystemVendorIDFunc0;
U8 PCIMemDiagSize;
U8 Reserved05;
U16 SubSystemIDFunc1;
U16 SubSystemVendorIDFunc1;
U8 AutoDownloadChecksum;
U8 Reserved0B;
U8 VendorIDDeviceIDLock;
U8 Reserved0D;
U16 VendorID0;
U16 DeviceID0;
U16 VendorID1;
U16 DeviceID1;
U8 ClassCode0[3];
U8 Reserved19;
U8 ClassCode1[3];
U8 Reserved1D;
U16 HardwareConfig;
U32 OptionRomOffset0;
U32 OptionRomOffset1;
} ManufacturingPage2_SAS_t, *pManufacturingPage2_SAS_t;
typedef struct
{
MPI2_CONFIG_PAGE_HEADER Header;
MPI2_CHIP_REVISION_ID ChipId;
U32 Foo[19];
} ManufacturingPage2_SAS2_t, *pManufacturingPage2_SAS2_t;
#define IOC_MFG_PAGE3_GPIO_DEFS (8)
#define IOC_MFG_PAGE3_NUM_PHYS_PER_QUAD (4)
#define IOC_MFG_PAGE3_NUM_QUADS (2)
typedef struct
{
U32 GigablazeConfig[4];
U32 Reserved[1];
} IOC_PHY_CONFIG;
typedef struct
{
U8 HotPlugTimeout;
U8 MaxCmdFrames;
U16 Reserved1;
U32 Reserved2[4];
IOC_PHY_CONFIG PhyConfig[IOC_MFG_PAGE3_NUM_PHYS_PER_QUAD];
} IOC_QUAD_CONFIG;
typedef struct
{
CONFIG_PAGE_HEADER Header;
MPI_CHIP_REVISION_ID ChipId;
U16 GPIODefinition[IOC_MFG_PAGE3_GPIO_DEFS];
U8 FlashTime;
U8 NVTime;
U8 Flag;
U8 RuntimeConfig;
U8 SGPIOType;
U8 SEPType;
U8 PCIELaneConfig;
U8 Reserved0;
U32 PCIEConfig2;
U32 Reserved2;
U8 Reserved3[2];
U8 Reserved4;
U8 Reserved5;
IOC_QUAD_CONFIG QuadConfig[IOC_MFG_PAGE3_NUM_QUADS];
} ManufacturingPage3_SAS_t, *pManufacturingPage3_SAS_t;
#define IOC_MFG_PAGE3_NUM_PHYS (16)
typedef struct _IOC_PHY_GROUP
{
U32 Misc;
U32 Sas1G1Low;
U32 Sas1G1High;
U32 Sas1G2Low;
U32 Sas1G2High;
U32 SasOobLow;
U32 SasOobHigh;
U32 Sas2G1Low;
U32 Sas2G1High;
U32 Sas2G2Low;
U32 Sas2G2High;
U32 Sas2G3Low;
U32 Sas2G3High;
U32 SataG1Low;
U32 SataG1High;
U32 SataG2Low;
U32 SataG2High;
U32 SataG3Low;
U32 SataG3High;
U32 SataOobLow;
U32 SataOobHigh;
} IOC_PHY_GROUP;
typedef struct
{
MPI2_CONFIG_PAGE_HEADER Header;
MPI2_CHIP_REVISION_ID ChipId;
U32 Reserved1;
U32 Reserved2;
U32 Reserved3;
U32 Reserved4;
IOC_PHY_GROUP PhyGroup[4];
U8 NumPhys;
U8 Reserved5;
U8 Reserved6;
U8 Reserved7;
U32 Phy[IOC_MFG_PAGE3_NUM_PHYS];
} ManufacturingPage3_SAS2_t, *pManufacturingPage3_SAS2_t;
#define IOC_MFG_PAGE6_GPIO_DEFS (32)
typedef struct
{
U8 FunctionCode;
U8 Flags;
U8 Param1;
U8 Param2;
U32 Param3;
} IOC_CFG_MFG_6_GPIO_DEF;
typedef struct
{
MPI2_CONFIG_PAGE_HEADER Header;
U8 NumGPIO;
U8 Reserved1[3];
U32 Reserved2;
U32 Reserved3;
IOC_CFG_MFG_6_GPIO_DEF GPIODefinition[IOC_MFG_PAGE6_GPIO_DEFS];
} ManufacturingPage6_SAS2_t, *pManufacturingPage6_SAS2_t;
#define IOC_CFG_MFG9_NUMBER_OF_RESOURCES (13)
typedef struct
{
U32 Maximum;
U32 Decrement;
U32 Minimum;
U32 Actual;
} IOC_CFG_MFG9_RESOURCE;
typedef struct
{
MPI2_CONFIG_PAGE_HEADER Header;
U32 MaxAttempts;
U32 NumResources;
U32 Reserved1;
U32 Reserved2;
IOC_CFG_MFG9_RESOURCE ResourceArray[IOC_CFG_MFG9_NUMBER_OF_RESOURCES];
} ManufacturingPage9_SAS2_t, *pManufacturingPage9_SAS2_t;
typedef struct
{
U8 Flags;
U8 MoreFlags;
U16 TO;
U32 BaudRate;
} IOC_CFG_UART_SETTINGS;
typedef struct
{
MPI2_CONFIG_PAGE_HEADER Header;
U8 FlashTime;
U8 NVTime;
U8 Flag;
U8 Reserved1;
U8 HotPlugTimeout;
U8 Reserved[3];
U8 MaxCmdFrames[4];
U32 SysRefClk;
U32 Reserved2;
U32 ExtUartClk;
IOC_CFG_UART_SETTINGS UartSettings[2];
} ManufacturingPage11_SAS2_t, *pManufacturingPage11_SAS2_t;
#define IOC_MAN_PAGE_12_SGPIO_INFO_ENTRIES (4)
typedef struct
{
U32 Flags;
U32 BitOrderSelect[12];
} SGPIO_CONFIG_INFO;
typedef struct
{
MPI2_CONFIG_PAGE_HEADER Header;
U32 Flags;
U32 Reserved1;
U32 Reserved2;
U32 SGPIOCfg1;
U8 NumSGPIO;
U8 SGPIOType;
U16 ClkDivide;
U32 DefaultTxCtrl;
U32 SGPIOPatDef0;
U32 SGPIOPatDef1;
U32 SGPIOPatDef2;
U32 SGPIOPatDef3;
SGPIO_CONFIG_INFO SGPIOInfo[IOC_MAN_PAGE_12_SGPIO_INFO_ENTRIES];
} ManufacturingPage12_SAS2_t, *pManufacturingPage12_SAS2_t;
#define IOC_MAN_PAGE_13_SGPIO_ENTRIES (4)
typedef struct _SGPIO_TRANSLATION_DATA
{
U32 Mask;
U32 SlotStatus;
U8 TxControl[4];
} SGPIO_TRANSLATION_DATA, *PTR_SGPIO_TRANSLATION_DATA;
typedef struct
{
MPI2_CONFIG_PAGE_HEADER Header;
U8 NumSgpioEntries;
U8 Reserved0;
U16 Reserved1;
U32 Reserved2;
SGPIO_TRANSLATION_DATA SGPIOData[IOC_MAN_PAGE_13_SGPIO_ENTRIES];
} ManufacturingPage13_SAS2_t, *pManufacturingPage13_SAS2_t;
typedef struct
{
SAS_ADDRESS SasAddress;
U32 Reserved;
} SAS_PERSISTENT_ID_ENTRY;
#define SAS_NUM_PERSIST_IDS_PER_PAGE (0x01)
typedef struct
{
CONFIG_EXTENDED_PAGE_HEADER Header;
SAS_PERSISTENT_ID_ENTRY PersistId[SAS_NUM_PERSIST_IDS_PER_PAGE];
} PersistentId_SAS_t, *pPersistentId_SAS_t;
#define STR (1<<0) // item is a string
#define OPT (1<<1) // item is optional
#define DUP (1<<2) // item is a duplicate
#define BIT (1<<3) // item size is in bits, not bytes
#define IGN (1<<4) // item should be ignored if zero
#define MPI1 (1<<5) // item only applies to MPI 1.x
#define MPI2 (1<<6) // item only applies to MPI 2.0
//TMC: MPI2.5 TODO
typedef struct
{
char *name;
int offset;
int size;
int flags;
} ITEM;
#define EXT (1<<0) // section is an extended config page
#define GEN (1<<1) // section is "General"
#define PID (1<<2) // section is "Persistent ID"
#define MP2 (1<<3) // section is "Manufacturing Page 2"
typedef struct
{
char *name;
ITEM *items;
int size;
int flags;
} SECTION;
typedef struct
{
U8 SasAddress[6];
U8 UserVersion;
U8 VendorId[8];
U8 ProductId[16];
U8 ProductRevision[4];
} GeneralData_t, *pGeneralData_t;
#undef data
#define data(x) (int)(size_t)&((pGeneralData_t)0)->x, sizeof(((pGeneralData_t)0)->x)
ITEM general_data_items[] =
{
{"SAS_ADRS_PREFIX", data(SasAddress), STR | OPT},
{"USER_VERSION", data(UserVersion), 0},
{"NVDATA_VENDORID", data(VendorId), STR},
{"NVDATA_PRODUCTID", data(ProductId), STR},
{"NVDATA_PRODUCT_REVISION", data(ProductRevision), STR},
{0}
};
ITEM special_item =
{
" SPECIAL ", 0, 0, OPT
};
ITEM forceupdate_item =
{
"FORCEUPDATE", 0, 1, BIT
};
#undef data
#define data(x) (int)(size_t)&((pConfigPageHeader_t)0)->x, sizeof(((pConfigPageHeader_t)0)->x)
ITEM header_items[] =
{
{"PAGE_VERSION", data(PageVersion), 0},
{"PAGE_LENGTH", data(PageLength), 0},
{"PAGE_NUMBER", data(PageNumber), 0},
{"PAGE_TYPE", data(PageType), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pConfigExtendedPageHeader_t)0)->x, sizeof(((pConfigExtendedPageHeader_t)0)->x)
ITEM ext_header_items[] =
{
{"PAGE_VERSION", data(PageVersion), 0},
{"RESERVED1", data(Reserved1), OPT},
{"CONFIG_EXTENDED_PAGE_HEADER_RESERVED1", data(Reserved1), OPT},
{"PAGE_NUMBER", data(PageNumber), 0},
{"PAGE_TYPE", data(PageType), 0},
{"EXT_PAGE_LENGTH", data(ExtPageLength), 0},
{"EXT_PAGE_TYPE", data(ExtPageType), 0},
{"RESERVED2", data(Reserved2), OPT},
{"CONFIG_EXTENDED_PAGE_HEADER_RESERVED2", data(Reserved2), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pManufacturingPage0_t)0)->x, sizeof(((pManufacturingPage0_t)0)->x)
ITEM manufacturing_page_0_items[] =
{
{"CHIP_NAME", data(ChipName), STR},
{"CHIP_REVISION", data(ChipRevision), STR},
{"BOARD_NAME", data(BoardName), STR},
{"BOARD_ASSEMBLY", data(BoardAssembly), STR},
{"BOARD_TRACER_NUMBER", data(BoardTracerNumber), STR},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pManufacturingPage1_t)0)->x, sizeof(((pManufacturingPage1_t)0)->x)
ITEM manufacturing_page_1_items[] =
{
{"VPD", data(VPD), STR},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pManufacturingPage2_SAS_t)0)->x, sizeof(((pManufacturingPage2_SAS_t)0)->x)
ITEM manufacturing_page_2_items[] =
{
{"DEVICE_ID", data(ChipId.DeviceID), 0},
{"PCI_REVISION", data(ChipId.PCIRevisionID), 0},
{"MPI_CHIP_REVISION_ID_RESERVED", data(ChipId.Reserved), OPT},
{"RESERVED", data(ChipId.Reserved), OPT},
{"SSID_FCN_0", data(SubSystemIDFunc0), 0},
{"SSVID_FCN_0", data(SubSystemVendorIDFunc0), 0},
{"PCI_MEM_DIAG_SIZE", data(PCIMemDiagSize), 0},
{"RESERVED0", data(Reserved05), OPT},
{"RESERVED05", data(Reserved05), OPT},
{"SSID_FCN_1", data(SubSystemIDFunc1), 0},
{"SSVID_FCN_1", data(SubSystemVendorIDFunc1), 0},
{"AUTODOWNLOAD_CHECKSUM", data(AutoDownloadChecksum), 0},
{"RESERVED1", data(Reserved0B), OPT},
{"RESERVED0B", data(Reserved0B), OPT},
{"VENDORIDDEVICEIDLOCK", data(VendorIDDeviceIDLock), 0},
{"RESERVED2", data(Reserved0D), OPT},
{"RESERVED0D", data(Reserved0D), OPT},
{"VENDOR_ID_0", data(VendorID0), 0},
{"DEVICE_ID_0", data(DeviceID0), 0},
{"VENDOR_ID_1", data(VendorID1), 0},
{"DEVICE_ID_1", data(DeviceID1), 0},
{"CC_0_SPECIFIC_CLASS", data(ClassCode0[0]), 0},
{"CC_0_SUB_CLASS", data(ClassCode0[1]), 0},
{"CC_0_BASE_CLASS", data(ClassCode0[2]), 0},
{"RESERVED3", data(Reserved19), OPT},
{"RESERVED19", data(Reserved19), OPT},
{"CC_1_SPECIFIC_CLASS", data(ClassCode1[0]), 0},
{"CC_1_SUB_CLASS", data(ClassCode1[1]), 0},
{"CC_1_BASE_CLASS", data(ClassCode1[2]), 0},
{"RESERVED4", data(Reserved1D), OPT},
{"RESERVED1D", data(Reserved1D), OPT},
{"HARDWARECONFIG", data(HardwareConfig), 0},
{"OPTIONROMOFFSETFUNC0", data(OptionRomOffset0), 0},
{"OPTIONROMOFFSETFUNC1", data(OptionRomOffset1), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pManufacturingPage2_SAS2_t)0)->x, sizeof(((pManufacturingPage2_SAS2_t)0)->x)
ITEM manufacturing_page_2_items2[] =
{
{"DEVICE_ID", data(ChipId.DeviceID), 0},
{"PCI_REVISION", data(ChipId.PCIRevisionID), 0},
{"MPI_CHIP_REVISION_ID_RESERVED", data(ChipId.Reserved), OPT},
// {"FOO_0", data(Foo[0]), 0},
// {"FOO_1", data(Foo[1]), 0},
// {"FOO_2", data(Foo[2]), 0},
// {"FOO_3", data(Foo[3]), 0},
// {"FOO_4", data(Foo[4]), 0},
// {"FOO_5", data(Foo[5]), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pManufacturingPage3_SAS_t)0)->x, sizeof(((pManufacturingPage3_SAS_t)0)->x)
ITEM manufacturing_page_3_items[] =
{
{"DEVICE_ID", data(ChipId.DeviceID), 0},
{"PCI_REVISION_ID", data(ChipId.PCIRevisionID), 0},
{"RESERVED", data(ChipId.Reserved), OPT},
{"MPI_CHIP_REVISION_ID_RESERVED", data(ChipId.Reserved), OPT},
{"GPIODEFINITION_0", data(GPIODefinition[0]), 0},
{"GPIODEFINITION_1", data(GPIODefinition[1]), 0},
{"GPIODEFINITION_2", data(GPIODefinition[2]), 0},
{"GPIODEFINITION_3", data(GPIODefinition[3]), 0},
{"GPIODEFINITION_4", data(GPIODefinition[4]), 0},
{"GPIODEFINITION_5", data(GPIODefinition[5]), 0},
{"GPIODEFINITION_6", data(GPIODefinition[6]), 0},
{"GPIODEFINITION_7", data(GPIODefinition[7]), 0},
{"FLASH_TIME", data(FlashTime), 0},
{"NVS_TIME", data(NVTime), 0},
{"FLAG", data(Flag), 0},
{"RUNTIMECONFIG", data(RuntimeConfig), 0},
{"SGPIOTYPE", data(SGPIOType), 0},
{"MP3_SEPTYPE", data(SEPType), 0},
{"PCIELANECONFIG", data(PCIELaneConfig), OPT},
{"RESERVED", data(PCIELaneConfig), OPT},
{"RESERVED0", data(Reserved0), OPT},
{"PCIECONFIG2", data(PCIEConfig2), OPT},
{"RESERVED1", data(PCIEConfig2), OPT},
{"RESERVED2", data(Reserved2), OPT},
{"RESERVED3_0", data(Reserved3[0]), OPT},
{"RESERVED3_1", data(Reserved3[1]), OPT},
{"RESERVED4", data(Reserved4), OPT},
{"RESERVED5", data(Reserved5), OPT},
{"HOT_PLUG_TIM_OUT", data(QuadConfig[0].HotPlugTimeout), DUP},
{"IOC_QUAD_CONFIG0_HOT_PLUG_TIM_OUT", data(QuadConfig[0].HotPlugTimeout), 0},
{"MAX_CMD_FRAMES", data(QuadConfig[0].MaxCmdFrames), DUP},
{"IOC_QUAD_CONFIG0_MAX_CMD_FRAMES", data(QuadConfig[0].MaxCmdFrames), 0},
{"RESERVED1", data(QuadConfig[0].Reserved1), OPT},
{"IOC_QUAD_CONFIG0_RESERVED1", data(QuadConfig[0].Reserved1), OPT},
{"RESERVED2", data(QuadConfig[0].Reserved2), OPT},
{"IOC_QUAD_CONFIG0_RESERVED2_0", data(QuadConfig[0].Reserved2[0]), OPT},
{"IOC_QUAD_CONFIG0_RESERVED2_1", data(QuadConfig[0].Reserved2[1]), OPT},
{"IOC_QUAD_CONFIG0_RESERVED2_2", data(QuadConfig[0].Reserved2[2]), OPT},
{"IOC_QUAD_CONFIG0_RESERVED2_3", data(QuadConfig[0].Reserved2[3]), OPT},
{"QUAD0_PHY0_GIG_CONFIG0", data(QuadConfig[0].PhyConfig[0].GigablazeConfig[0]), 0},
{"QUAD0_PHY0_GIG_CONFIG1", data(QuadConfig[0].PhyConfig[0].GigablazeConfig[1]), 0},
{"QUAD0_PHY0_GIG_CONFIG2", data(QuadConfig[0].PhyConfig[0].GigablazeConfig[2]), 0},
{"QUAD0_PHY0_GIG_CONFIG3", data(QuadConfig[0].PhyConfig[0].GigablazeConfig[3]), 0},
{"RESERVED1", data(QuadConfig[0].PhyConfig[0].Reserved), OPT},
{"QUAD0_PHY0_GIG_CONFIG3_RESERVED", data(QuadConfig[0].PhyConfig[0].Reserved), OPT},
{"QUAD0_PHY1_GIG_CONFIG0", data(QuadConfig[0].PhyConfig[1].GigablazeConfig[0]), 0},
{"QUAD0_PHY1_GIG_CONFIG1", data(QuadConfig[0].PhyConfig[1].GigablazeConfig[1]), 0},
{"QUAD0_PHY1_GIG_CONFIG2", data(QuadConfig[0].PhyConfig[1].GigablazeConfig[2]), 0},
{"QUAD0_PHY1_GIG_CONFIG3", data(QuadConfig[0].PhyConfig[1].GigablazeConfig[3]), 0},
{"RESERVED1", data(QuadConfig[0].PhyConfig[1].Reserved), OPT},
{"QUAD0_PHY1_GIG_CONFIG3_RESERVED", data(QuadConfig[0].PhyConfig[1].Reserved), OPT},
{"QUAD0_PHY2_GIG_CONFIG0", data(QuadConfig[0].PhyConfig[2].GigablazeConfig[0]), 0},
{"QUAD0_PHY2_GIG_CONFIG1", data(QuadConfig[0].PhyConfig[2].GigablazeConfig[1]), 0},
{"QUAD0_PHY2_GIG_CONFIG2", data(QuadConfig[0].PhyConfig[2].GigablazeConfig[2]), 0},
{"QUAD0_PHY2_GIG_CONFIG3", data(QuadConfig[0].PhyConfig[2].GigablazeConfig[3]), 0},
{"RESERVED1", data(QuadConfig[0].PhyConfig[2].Reserved), OPT},
{"QUAD0_PHY2_GIG_CONFIG3_RESERVED", data(QuadConfig[0].PhyConfig[2].Reserved), OPT},
{"QUAD0_PHY3_GIG_CONFIG0", data(QuadConfig[0].PhyConfig[3].GigablazeConfig[0]), 0},
{"QUAD0_PHY3_GIG_CONFIG1", data(QuadConfig[0].PhyConfig[3].GigablazeConfig[1]), 0},
{"QUAD0_PHY3_GIG_CONFIG2", data(QuadConfig[0].PhyConfig[3].GigablazeConfig[2]), 0},
{"QUAD0_PHY3_GIG_CONFIG3", data(QuadConfig[0].PhyConfig[3].GigablazeConfig[3]), 0},
{"RESERVED1", data(QuadConfig[0].PhyConfig[3].Reserved), OPT},
{"QUAD0_PHY3_GIG_CONFIG3_RESERVED", data(QuadConfig[0].PhyConfig[3].Reserved), OPT},
{"HOT_PLUG_TIM_OUT", data(QuadConfig[1].HotPlugTimeout), DUP},
{"IOC_QUAD_CONFIG1_HOT_PLUG_TIM_OUT", data(QuadConfig[1].HotPlugTimeout), 0},
{"MAX_CMD_FRAMES", data(QuadConfig[1].MaxCmdFrames), DUP},
{"IOC_QUAD_CONFIG1_MAX_CMD_FRAMES", data(QuadConfig[1].MaxCmdFrames), 0},
{"RESERVED1", data(QuadConfig[1].Reserved1), OPT},
{"IOC_QUAD_CONFIG1_RESERVED1", data(QuadConfig[1].Reserved1), OPT},
{"RESERVED2", data(QuadConfig[1].Reserved2), OPT},
{"IOC_QUAD_CONFIG1_RESERVED2_0", data(QuadConfig[1].Reserved2[0]), OPT},
{"IOC_QUAD_CONFIG1_RESERVED2_1", data(QuadConfig[1].Reserved2[1]), OPT},
{"IOC_QUAD_CONFIG1_RESERVED2_2", data(QuadConfig[1].Reserved2[2]), OPT},
{"IOC_QUAD_CONFIG1_RESERVED2_3", data(QuadConfig[1].Reserved2[3]), OPT},
{"QUAD1_PHY0_GIG_CONFIG0", data(QuadConfig[1].PhyConfig[0].GigablazeConfig[0]), 0},
{"QUAD1_PHY0_GIG_CONFIG1", data(QuadConfig[1].PhyConfig[0].GigablazeConfig[1]), 0},
{"QUAD1_PHY0_GIG_CONFIG2", data(QuadConfig[1].PhyConfig[0].GigablazeConfig[2]), 0},
{"QUAD1_PHY0_GIG_CONFIG3", data(QuadConfig[1].PhyConfig[0].GigablazeConfig[3]), 0},
{"RESERVED1", data(QuadConfig[1].PhyConfig[0].Reserved), OPT},
{"QUAD1_PHY0_GIG_CONFIG3_RESERVED", data(QuadConfig[1].PhyConfig[0].Reserved), OPT},
{"QUAD1_PHY1_GIG_CONFIG0", data(QuadConfig[1].PhyConfig[1].GigablazeConfig[0]), 0},
{"QUAD1_PHY1_GIG_CONFIG1", data(QuadConfig[1].PhyConfig[1].GigablazeConfig[1]), 0},
{"QUAD1_PHY1_GIG_CONFIG2", data(QuadConfig[1].PhyConfig[1].GigablazeConfig[2]), 0},
{"QUAD1_PHY1_GIG_CONFIG3", data(QuadConfig[1].PhyConfig[1].GigablazeConfig[3]), 0},
{"RESERVED1", data(QuadConfig[1].PhyConfig[1].Reserved), OPT},
{"QUAD1_PHY1_GIG_CONFIG3_RESERVED", data(QuadConfig[1].PhyConfig[1].Reserved), OPT},
{"QUAD1_PHY2_GIG_CONFIG0", data(QuadConfig[1].PhyConfig[2].GigablazeConfig[0]), 0},
{"QUAD1_PHY2_GIG_CONFIG1", data(QuadConfig[1].PhyConfig[2].GigablazeConfig[1]), 0},
{"QUAD1_PHY2_GIG_CONFIG2", data(QuadConfig[1].PhyConfig[2].GigablazeConfig[2]), 0},
{"QUAD1_PHY2_GIG_CONFIG3", data(QuadConfig[1].PhyConfig[2].GigablazeConfig[3]), 0},
{"RESERVED1", data(QuadConfig[1].PhyConfig[2].Reserved), OPT},
{"QUAD1_PHY2_GIG_CONFIG3_RESERVED", data(QuadConfig[1].PhyConfig[2].Reserved), OPT},
{"QUAD1_PHY3_GIG_CONFIG0", data(QuadConfig[1].PhyConfig[3].GigablazeConfig[0]), 0},
{"QUAD1_PHY3_GIG_CONFIG1", data(QuadConfig[1].PhyConfig[3].GigablazeConfig[1]), 0},
{"QUAD1_PHY3_GIG_CONFIG2", data(QuadConfig[1].PhyConfig[3].GigablazeConfig[2]), 0},
{"QUAD1_PHY3_GIG_CONFIG3", data(QuadConfig[1].PhyConfig[3].GigablazeConfig[3]), 0},
{"RESERVED1", data(QuadConfig[1].PhyConfig[3].Reserved), OPT},
{"QUAD1_PHY3_GIG_CONFIG3_RESERVED", data(QuadConfig[1].PhyConfig[3].Reserved), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pManufacturingPage3_SAS2_t)0)->x, sizeof(((pManufacturingPage3_SAS2_t)0)->x)
ITEM manufacturing_page_3_items2[] =
{
{"DEVICE_ID", data(ChipId.DeviceID), 0},
{"PCI_REVISION_ID", data(ChipId.PCIRevisionID), 0},
{"MPI_CHIP_REVISION_ID_RESERVED", data(ChipId.Reserved), OPT},
{"RESERVED1", data(Reserved1), OPT},
{"RESERVED2", data(Reserved2), OPT},
{"RESERVED3", data(Reserved3), OPT},
{"RESERVED4", data(Reserved4), OPT},
{"GROUP0_MISC", data(PhyGroup[0].Misc), 0},
{"GROUP0_SAS1G1LOW", data(PhyGroup[0].Sas1G1Low), 0},
{"GROUP0_SAS1G1HIGH", data(PhyGroup[0].Sas1G1High), 0},
{"GROUP0_SAS1G2LOW", data(PhyGroup[0].Sas1G2Low), 0},
{"GROUP0_SAS1G2HIGH", data(PhyGroup[0].Sas1G2High), 0},
{"GROUP0_SASOOBLOW", data(PhyGroup[0].SasOobLow), 0},
{"GROUP0_SASOOBHIGH", data(PhyGroup[0].SasOobHigh), 0},
{"GROUP0_SAS2G1LOW", data(PhyGroup[0].Sas2G1Low), 0},
{"GROUP0_SAS2G1HIGH", data(PhyGroup[0].Sas2G1High), 0},
{"GROUP0_SAS2G2LOW", data(PhyGroup[0].Sas2G2Low), 0},
{"GROUP0_SAS2G2HIGH", data(PhyGroup[0].Sas2G2High), 0},
{"GROUP0_SAS2G3LOW", data(PhyGroup[0].Sas2G3Low), 0},
{"GROUP0_SAS2G3HIGH", data(PhyGroup[0].Sas2G3High), 0},
{"GROUP0_SATAG1LOW", data(PhyGroup[0].SataG1Low), 0},
{"GROUP0_SATAG1HIGH", data(PhyGroup[0].SataG1High), 0},
{"GROUP0_SATAG2LOW", data(PhyGroup[0].SataG2Low), 0},
{"GROUP0_SATAG2HIGH", data(PhyGroup[0].SataG2High), 0},
{"GROUP0_SATAG3LOW", data(PhyGroup[0].SataG3Low), 0},
{"GROUP0_SATAG3HIGH", data(PhyGroup[0].SataG3High), 0},
{"GROUP0_SATAOOBLOW", data(PhyGroup[0].SataOobLow), 0},
{"GROUP0_SATAOOBHIGH", data(PhyGroup[0].SataOobHigh), 0},
{"GROUP1_MISC", data(PhyGroup[1].Misc), 0},
{"GROUP1_SAS1G1LOW", data(PhyGroup[1].Sas1G1Low), 0},
{"GROUP1_SAS1G1HIGH", data(PhyGroup[1].Sas1G1High), 0},
{"GROUP1_SAS1G2LOW", data(PhyGroup[1].Sas1G2Low), 0},
{"GROUP1_SAS1G2HIGH", data(PhyGroup[1].Sas1G2High), 0},
{"GROUP1_SASOOBLOW", data(PhyGroup[1].SasOobLow), 0},
{"GROUP1_SASOOBHIGH", data(PhyGroup[1].SasOobHigh), 0},
{"GROUP1_SAS2G1LOW", data(PhyGroup[1].Sas2G1Low), 0},
{"GROUP1_SAS2G1HIGH", data(PhyGroup[1].Sas2G1High), 0},
{"GROUP1_SAS2G2LOW", data(PhyGroup[1].Sas2G2Low), 0},
{"GROUP1_SAS2G2HIGH", data(PhyGroup[1].Sas2G2High), 0},
{"GROUP1_SAS2G3LOW", data(PhyGroup[1].Sas2G3Low), 0},
{"GROUP1_SAS2G3HIGH", data(PhyGroup[1].Sas2G3High), 0},
{"GROUP1_SATAG1LOW", data(PhyGroup[1].SataG1Low), 0},
{"GROUP1_SATAG1HIGH", data(PhyGroup[1].SataG1High), 0},
{"GROUP1_SATAG2LOW", data(PhyGroup[1].SataG2Low), 0},
{"GROUP1_SATAG2HIGH", data(PhyGroup[1].SataG2High), 0},
{"GROUP1_SATAG3LOW", data(PhyGroup[1].SataG3Low), 0},
{"GROUP1_SATAG3HIGH", data(PhyGroup[1].SataG3High), 0},
{"GROUP1_SATAOOBLOW", data(PhyGroup[1].SataOobLow), 0},
{"GROUP1_SATAOOBHIGH", data(PhyGroup[1].SataOobHigh), 0},
{"GROUP2_MISC", data(PhyGroup[2].Misc), 0},
{"GROUP2_SAS1G1LOW", data(PhyGroup[2].Sas1G1Low), 0},
{"GROUP2_SAS1G1HIGH", data(PhyGroup[2].Sas1G1High), 0},
{"GROUP2_SAS1G2LOW", data(PhyGroup[2].Sas1G2Low), 0},
{"GROUP2_SAS1G2HIGH", data(PhyGroup[2].Sas1G2High), 0},
{"GROUP2_SASOOBLOW", data(PhyGroup[2].SasOobLow), 0},
{"GROUP2_SASOOBHIGH", data(PhyGroup[2].SasOobHigh), 0},
{"GROUP2_SAS2G1LOW", data(PhyGroup[2].Sas2G1Low), 0},
{"GROUP2_SAS2G1HIGH", data(PhyGroup[2].Sas2G1High), 0},
{"GROUP2_SAS2G2LOW", data(PhyGroup[2].Sas2G2Low), 0},
{"GROUP2_SAS2G2HIGH", data(PhyGroup[2].Sas2G2High), 0},
{"GROUP2_SAS2G3LOW", data(PhyGroup[2].Sas2G3Low), 0},
{"GROUP2_SAS2G3HIGH", data(PhyGroup[2].Sas2G3High), 0},
{"GROUP2_SATAG1LOW", data(PhyGroup[2].SataG1Low), 0},
{"GROUP2_SATAG1HIGH", data(PhyGroup[2].SataG1High), 0},
{"GROUP2_SATAG2LOW", data(PhyGroup[2].SataG2Low), 0},
{"GROUP2_SATAG2HIGH", data(PhyGroup[2].SataG2High), 0},
{"GROUP2_SATAG3LOW", data(PhyGroup[2].SataG3Low), 0},
{"GROUP2_SATAG3HIGH", data(PhyGroup[2].SataG3High), 0},
{"GROUP2_SATAOOBLOW", data(PhyGroup[2].SataOobLow), 0},
{"GROUP2_SATAOOBHIGH", data(PhyGroup[2].SataOobHigh), 0},
{"GROUP3_MISC", data(PhyGroup[3].Misc), 0},
{"GROUP3_SAS1G1LOW", data(PhyGroup[3].Sas1G1Low), 0},
{"GROUP3_SAS1G1HIGH", data(PhyGroup[3].Sas1G1High), 0},
{"GROUP3_SAS1G2LOW", data(PhyGroup[3].Sas1G2Low), 0},
{"GROUP3_SAS1G2HIGH", data(PhyGroup[3].Sas1G2High), 0},
{"GROUP3_SASOOBLOW", data(PhyGroup[3].SasOobLow), 0},
{"GROUP3_SASOOBHIGH", data(PhyGroup[3].SasOobHigh), 0},
{"GROUP3_SAS2G1LOW", data(PhyGroup[3].Sas2G1Low), 0},
{"GROUP3_SAS2G1HIGH", data(PhyGroup[3].Sas2G1High), 0},
{"GROUP3_SAS2G2LOW", data(PhyGroup[3].Sas2G2Low), 0},
{"GROUP3_SAS2G2HIGH", data(PhyGroup[3].Sas2G2High), 0},
{"GROUP3_SAS2G3LOW", data(PhyGroup[3].Sas2G3Low), 0},
{"GROUP3_SAS2G3HIGH", data(PhyGroup[3].Sas2G3High), 0},
{"GROUP3_SATAG1LOW", data(PhyGroup[3].SataG1Low), 0},
{"GROUP3_SATAG1HIGH", data(PhyGroup[3].SataG1High), 0},
{"GROUP3_SATAG2LOW", data(PhyGroup[3].SataG2Low), 0},
{"GROUP3_SATAG2HIGH", data(PhyGroup[3].SataG2High), 0},
{"GROUP3_SATAG3LOW", data(PhyGroup[3].SataG3Low), 0},
{"GROUP3_SATAG3HIGH", data(PhyGroup[3].SataG3High), 0},
{"GROUP3_SATAOOBLOW", data(PhyGroup[3].SataOobLow), 0},
{"GROUP3_SATAOOBHIGH", data(PhyGroup[3].SataOobHigh), 0},
{"NUM_PHYS", data(NumPhys), 0},
{"RESERVED5", data(Reserved5), OPT},
{"RESERVED6", data(Reserved6), OPT},
{"RESERVED7", data(Reserved7), OPT},
{"PHY_0", data(Phy[0]), 0},
{"PHY_1", data(Phy[1]), 0},
{"PHY_2", data(Phy[2]), 0},
{"PHY_3", data(Phy[3]), 0},
{"PHY_4", data(Phy[4]), 0},
{"PHY_5", data(Phy[5]), 0},
{"PHY_6", data(Phy[6]), 0},
{"PHY_7", data(Phy[7]), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pManufacturingPage4_t)0)->x, sizeof(((pManufacturingPage4_t)0)->x)
#define off(x) (int)(size_t)&((pManufacturingPage4_t)0)->x
ITEM manufacturing_page_4_items[] =
{
{"RESERVED1", data(Reserved1), OPT},
{"INFO_OFFSET_0", data(InfoOffset0), 0},
{"INFO_SIZE_0", data(InfoSize0), 0},
{"INFO_OFFSET_1", data(InfoOffset1), 0},
{"INFO_SIZE_1", data(InfoSize1), 0},
{"INQUIRY_SIZE", data(InquirySize), 0},
{"MP4_FLAGS", data(Flags), 0},
{"RESERVED2", data(ExtFlags), OPT},
{"EXTENDED_FLAGS", data(ExtFlags), OPT},
{"DEVICE_TYPE", off(InquiryData[0]), 1, 0},
{"DEVICE_TYPE_MOD", off(InquiryData[1]), 1, 0},
{"VERSIONS", off(InquiryData[2]), 1, 0},
{"DATA_FORMAT", off(InquiryData[3]), 1, 0},
{"ADDITIONAL_LENGTH", off(InquiryData[4]), 1, 0},
{"CAPABILITY_BITS", off(InquiryData[7]), 1, 0},
{"VENDOR_ID", off(InquiryData[8]), 8, STR},
{"PRODUCT_ID", off(InquiryData[16]), 16, STR},
{"PRODUCT_REV", off(InquiryData[32]), 4, STR},
{"VENDOR_SPECIFIC", off(InquiryData[36]), 20, STR},
{"ISVOLUMESETTINGS", data(ISVolumeSettings), 0},
{"IMEVOLUMESETTINGS", data(IMEVolumeSettings), 0},
{"IMVOLUMESETTINGS", data(IMVolumeSettings), 0},
{"RESERVED3", data(Reserved3), OPT},
{"RESERVED4", data(Reserved4), OPT},
{"RESERVED5", data(Reserved5), OPT},
{"IME_DATASCRUBRATE", data(IMEDataScrubRate), 0},
{"IME_RESYNCRATE", data(IMEResyncRate), 0},
{"RESERVED6", data(Reserved6), OPT},
{"IM_DATASCRUBRATE", data(IMDataScrubRate), 0},
{"IM_RESYNCRATE", data(IMResyncRate), 0},
{"RESERVED7", data(Reserved7), OPT},
{"RESERVED8", data(Reserved8), OPT},
{"RESERVED9", data(Reserved9), OPT},
{0}
};
#undef off
#undef data
#define data(x) (int)(size_t)&((pMpi2ManufacturingPage4_t)0)->x, sizeof(((pMpi2ManufacturingPage4_t)0)->x)
#define off(x) (int)(size_t)&((pMpi2ManufacturingPage4_t)0)->x
ITEM manufacturing_page_4_items2[] =
{
{"RESERVED1", data(Reserved1), OPT},
{"FLAGS", data(Flags), 0},
{"INQUIRY_SIZE", data(InquirySize), 0},
{"RESERVED2", data(Reserved2), OPT},
{"RESERVED3", data(Reserved3), OPT},
{"DEVICE_TYPE", off(InquiryData[0]), 1, 0},
{"DEVICE_TYPE_MOD", off(InquiryData[1]), 1, 0},
{"VERSIONS", off(InquiryData[2]), 1, 0},
{"DATA_FORMAT", off(InquiryData[3]), 1, 0},
{"ADDITIONAL_LENGTH", off(InquiryData[4]), 1, 0},
{"CAPABILITY_BITS", off(InquiryData[7]), 1, 0},
{"VENDOR_ID", off(InquiryData[8]), 8, STR},
{"PRODUCT_ID", off(InquiryData[16]), 16, STR},
{"PRODUCT_REV", off(InquiryData[32]), 4, STR},
{"VENDOR_SPECIFIC", off(InquiryData[36]), 20, STR},
{"RAID0VOLUMESETTINGS", data(RAID0VolumeSettings), 0},
{"RAID1EVOLUMESETTINGS", data(RAID1EVolumeSettings), 0},
{"RAID1VOLUMESETTINGS", data(RAID1VolumeSettings), 0},
{"RAID10VOLUMESETTINGS", data(RAID10VolumeSettings), 0},
{"RESERVED4", data(Reserved4), OPT},
{"RESERVED5", data(Reserved5), OPT},
{"POWERSAVEFLAGS", data(PowerSaveSettings.PowerSaveFlags), 0},
{"INTOPSLEEPTIME", data(PowerSaveSettings.InternalOperationsSleepTime), 0},
{"INTOPRUNTIME", data(PowerSaveSettings.InternalOperationsRunTime), 0},
{"HOSTIDLETIME", data(PowerSaveSettings.HostIdleTime), 0},
{"MAXOCEDISKS", data(MaxOCEDisks), 0},
{"RESYNCRATE", data(ResyncRate), 0},
{"DATASCRUBDURATION", data(DataScrubDuration), 0},
{"MAXHOTSPARES", data(MaxHotSpares), 0},
{"MAXPHYSDISKSPERVOL", data(MaxPhysDisksPerVol), 0},
{"MAXPHYSDISKS", data(MaxPhysDisks), 0},
{"MAXVOLUMES", data(MaxVolumes), 0},
{0}
};
#undef off
#undef data
#define data(x) (int)(size_t)&((pManufacturingPage5_t)0)->x, sizeof(((pManufacturingPage5_t)0)->x)
ITEM manufacturing_page_5_items_25[] =
{
{"Base_WWID_Low", data(BaseWWID.Low), 0},
{"Base_WWID_Hi", data(BaseWWID.High), 0},
{"MANUFACT_5_FLAGS", data(Flags), 0},
{0}
};
#define manufacturing_page_5_size_25 (int)(size_t)&((pManufacturingPage5_t)0)->Reserved3
ITEM manufacturing_page_5_items[] =
{
{"Base_WWID_Low", data(BaseWWID.Low), 0},
{"Base_WWID_Hi", data(BaseWWID.High), 0},
{"MANUFACT_5_FLAGS", data(Flags), 0},
{"MAN_5_NUM_FORCE_WWID", data(NumForceWWID), 0},
{"MAN_5_RESERVED", data(Reserved2), OPT},
{"RESERVED2", data(Reserved2), OPT},
{"RESERVED3", data(Reserved3), OPT},
{"RESERVED4", data(Reserved4), OPT},
{"FORCE_WWID_0_LOW", data(ForceWWID[0].Low), 0},
{"FORCE_WWID_0_HI", data(ForceWWID[0].High), 0},
{"FORCE_WWID_1_LOW", data(ForceWWID[1].Low), 0},
{"FORCE_WWID_1_HI", data(ForceWWID[1].High), 0},
{"FORCE_WWID_2_LOW", data(ForceWWID[2].Low), 0},
{"FORCE_WWID_2_HI", data(ForceWWID[2].High), 0},
{"FORCE_WWID_3_LOW", data(ForceWWID[3].Low), 0},
{"FORCE_WWID_3_HI", data(ForceWWID[3].High), 0},
{"FORCE_WWID_4_LOW", data(ForceWWID[4].Low), 0},
{"FORCE_WWID_4_HI", data(ForceWWID[4].High), 0},
{"FORCE_WWID_5_LOW", data(ForceWWID[5].Low), 0},
{"FORCE_WWID_5_HI", data(ForceWWID[5].High), 0},
{"FORCE_WWID_6_LOW", data(ForceWWID[6].Low), 0},
{"FORCE_WWID_6_HI", data(ForceWWID[6].High), 0},
{"FORCE_WWID_7_LOW", data(ForceWWID[7].Low), 0},
{"FORCE_WWID_7_HI", data(ForceWWID[7].High), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pMpi2ManufacturingPage5_t)0)->x, sizeof(((pMpi2ManufacturingPage5_t)0)->x)
ITEM manufacturing_page_5_items2[] =
{
{"NUM_PHYS", data(NumPhys), 0},
{"RESERVED1", data(Reserved1), OPT},
{"RESERVED2", data(Reserved2), OPT},
{"RESERVED3", data(Reserved3), OPT},
{"RESERVED4", data(Reserved4), OPT},
{"PHY0_WWID_LOW", data(Phy[0].WWID.Low), 0},
{"PHY0_WWID_HI", data(Phy[0].WWID.High), 0},
{"PHY0_DEVICENAME_LOW", data(Phy[0].DeviceName.Low), 0},
{"PHY0_DEVICENAME_HI", data(Phy[0].DeviceName.High), 0},
{"PHY1_WWID_LOW", data(Phy[1].WWID.Low), 0},
{"PHY1_WWID_HI", data(Phy[1].WWID.High), 0},
{"PHY1_DEVICENAME_LOW", data(Phy[1].DeviceName.Low), 0},
{"PHY1_DEVICENAME_HI", data(Phy[1].DeviceName.High), 0},
{"PHY2_WWID_LOW", data(Phy[2].WWID.Low), 0},
{"PHY2_WWID_HI", data(Phy[2].WWID.High), 0},
{"PHY2_DEVICENAME_LOW", data(Phy[2].DeviceName.Low), 0},
{"PHY2_DEVICENAME_HI", data(Phy[2].DeviceName.High), 0},
{"PHY3_WWID_LOW", data(Phy[3].WWID.Low), 0},
{"PHY3_WWID_HI", data(Phy[3].WWID.High), 0},
{"PHY3_DEVICENAME_LOW", data(Phy[3].DeviceName.Low), 0},
{"PHY3_DEVICENAME_HI", data(Phy[3].DeviceName.High), 0},
{"PHY4_WWID_LOW", data(Phy[4].WWID.Low), 0},
{"PHY4_WWID_HI", data(Phy[4].WWID.High), 0},
{"PHY4_DEVICENAME_LOW", data(Phy[4].DeviceName.Low), 0},
{"PHY4_DEVICENAME_HI", data(Phy[4].DeviceName.High), 0},
{"PHY5_WWID_LOW", data(Phy[5].WWID.Low), 0},
{"PHY5_WWID_HI", data(Phy[5].WWID.High), 0},
{"PHY5_DEVICENAME_LOW", data(Phy[5].DeviceName.Low), 0},
{"PHY5_DEVICENAME_HI", data(Phy[5].DeviceName.High), 0},
{"PHY6_WWID_LOW", data(Phy[6].WWID.Low), 0},
{"PHY6_WWID_HI", data(Phy[6].WWID.High), 0},
{"PHY6_DEVICENAME_LOW", data(Phy[6].DeviceName.Low), 0},
{"PHY6_DEVICENAME_HI", data(Phy[6].DeviceName.High), 0},
{"PHY7_WWID_LOW", data(Phy[7].WWID.Low), 0},
{"PHY7_WWID_HI", data(Phy[7].WWID.High), 0},
{"PHY7_DEVICENAME_LOW", data(Phy[7].DeviceName.Low), 0},
{"PHY7_DEVICENAME_HI", data(Phy[7].DeviceName.High), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pManufacturingPage6_SAS2_t)0)->x, sizeof(((pManufacturingPage6_SAS2_t)0)->x)
ITEM manufacturing_page_6_items2[] =
{
{"NUM_GPIO", data(NumGPIO), 0},
{"RESERVED1_0", data(Reserved1[0]), OPT},
{"RESERVED1_1", data(Reserved1[1]), OPT},
{"RESERVED1_2", data(Reserved1[2]), OPT},
{"RESERVED2", data(Reserved2), OPT},
{"RESERVED3", data(Reserved3), OPT},
{"GPIO_0_FUNC_CODE", data(GPIODefinition[0].FunctionCode), 0},
{"GPIO_0_FLAGS", data(GPIODefinition[0].Flags), 0},
{"GPIO_0_PARAM1", data(GPIODefinition[0].Param1), 0},
{"GPIO_0_PARAM2", data(GPIODefinition[0].Param2), 0},
{"GPIO_0_PARAM3", data(GPIODefinition[0].Param3), 0},
{"GPIO_1_FUNC_CODE", data(GPIODefinition[1].FunctionCode), 0},
{"GPIO_1_FLAGS", data(GPIODefinition[1].Flags), 0},
{"GPIO_1_PARAM1", data(GPIODefinition[1].Param1), 0},
{"GPIO_1_PARAM2", data(GPIODefinition[1].Param2), 0},
{"GPIO_1_PARAM3", data(GPIODefinition[1].Param3), 0},
{"GPIO_2_FUNC_CODE", data(GPIODefinition[2].FunctionCode), 0},
{"GPIO_2_FLAGS", data(GPIODefinition[2].Flags), 0},
{"GPIO_2_PARAM1", data(GPIODefinition[2].Param1), 0},
{"GPIO_2_PARAM2", data(GPIODefinition[2].Param2), 0},
{"GPIO_2_PARAM3", data(GPIODefinition[2].Param3), 0},
{"GPIO_3_FUNC_CODE", data(GPIODefinition[3].FunctionCode), 0},
{"GPIO_3_FLAGS", data(GPIODefinition[3].Flags), 0},
{"GPIO_3_PARAM1", data(GPIODefinition[3].Param1), 0},
{"GPIO_3_PARAM2", data(GPIODefinition[3].Param2), 0},
{"GPIO_3_PARAM3", data(GPIODefinition[3].Param3), 0},
{"GPIO_4_FUNC_CODE", data(GPIODefinition[4].FunctionCode), 0},
{"GPIO_4_FLAGS", data(GPIODefinition[4].Flags), 0},
{"GPIO_4_PARAM1", data(GPIODefinition[4].Param1), 0},
{"GPIO_4_PARAM2", data(GPIODefinition[4].Param2), 0},
{"GPIO_4_PARAM3", data(GPIODefinition[4].Param3), 0},
{"GPIO_5_FUNC_CODE", data(GPIODefinition[5].FunctionCode), 0},
{"GPIO_5_FLAGS", data(GPIODefinition[5].Flags), 0},
{"GPIO_5_PARAM1", data(GPIODefinition[5].Param1), 0},
{"GPIO_5_PARAM2", data(GPIODefinition[5].Param2), 0},
{"GPIO_5_PARAM3", data(GPIODefinition[5].Param3), 0},
{"GPIO_6_FUNC_CODE", data(GPIODefinition[6].FunctionCode), 0},
{"GPIO_6_FLAGS", data(GPIODefinition[6].Flags), 0},
{"GPIO_6_PARAM1", data(GPIODefinition[6].Param1), 0},
{"GPIO_6_PARAM2", data(GPIODefinition[6].Param2), 0},
{"GPIO_6_PARAM3", data(GPIODefinition[6].Param3), 0},
{"GPIO_7_FUNC_CODE", data(GPIODefinition[7].FunctionCode), 0},
{"GPIO_7_FLAGS", data(GPIODefinition[7].Flags), 0},
{"GPIO_7_PARAM1", data(GPIODefinition[7].Param1), 0},
{"GPIO_7_PARAM2", data(GPIODefinition[7].Param2), 0},
{"GPIO_7_PARAM3", data(GPIODefinition[7].Param3), 0},
{"GPIO_8_FUNC_CODE", data(GPIODefinition[8].FunctionCode), 0},
{"GPIO_8_FLAGS", data(GPIODefinition[8].Flags), 0},
{"GPIO_8_PARAM1", data(GPIODefinition[8].Param1), 0},
{"GPIO_8_PARAM2", data(GPIODefinition[8].Param2), 0},
{"GPIO_8_PARAM3", data(GPIODefinition[8].Param3), 0},
{"GPIO_9_FUNC_CODE", data(GPIODefinition[9].FunctionCode), 0},
{"GPIO_9_FLAGS", data(GPIODefinition[9].Flags), 0},
{"GPIO_9_PARAM1", data(GPIODefinition[9].Param1), 0},
{"GPIO_9_PARAM2", data(GPIODefinition[9].Param2), 0},
{"GPIO_9_PARAM3", data(GPIODefinition[9].Param3), 0},
{"GPIO_10_FUNC_CODE", data(GPIODefinition[10].FunctionCode), 0},
{"GPIO_10_FLAGS", data(GPIODefinition[10].Flags), 0},
{"GPIO_10_PARAM1", data(GPIODefinition[10].Param1), 0},
{"GPIO_10_PARAM2", data(GPIODefinition[10].Param2), 0},
{"GPIO_10_PARAM3", data(GPIODefinition[10].Param3), 0},
{"GPIO_11_FUNC_CODE", data(GPIODefinition[11].FunctionCode), 0},
{"GPIO_11_FLAGS", data(GPIODefinition[11].Flags), 0},
{"GPIO_11_PARAM1", data(GPIODefinition[11].Param1), 0},
{"GPIO_11_PARAM2", data(GPIODefinition[11].Param2), 0},
{"GPIO_11_PARAM3", data(GPIODefinition[11].Param3), 0},
{"GPIO_12_FUNC_CODE", data(GPIODefinition[12].FunctionCode), 0},
{"GPIO_12_FLAGS", data(GPIODefinition[12].Flags), 0},
{"GPIO_12_PARAM1", data(GPIODefinition[12].Param1), 0},
{"GPIO_12_PARAM2", data(GPIODefinition[12].Param2), 0},
{"GPIO_12_PARAM3", data(GPIODefinition[12].Param3), 0},
{"GPIO_13_FUNC_CODE", data(GPIODefinition[13].FunctionCode), 0},
{"GPIO_13_FLAGS", data(GPIODefinition[13].Flags), 0},
{"GPIO_13_PARAM1", data(GPIODefinition[13].Param1), 0},
{"GPIO_13_PARAM2", data(GPIODefinition[13].Param2), 0},
{"GPIO_13_PARAM3", data(GPIODefinition[13].Param3), 0},
{"GPIO_14_FUNC_CODE", data(GPIODefinition[14].FunctionCode), 0},
{"GPIO_14_FLAGS", data(GPIODefinition[14].Flags), 0},
{"GPIO_14_PARAM1", data(GPIODefinition[14].Param1), 0},
{"GPIO_14_PARAM2", data(GPIODefinition[14].Param2), 0},
{"GPIO_14_PARAM3", data(GPIODefinition[14].Param3), 0},
{"GPIO_15_FUNC_CODE", data(GPIODefinition[15].FunctionCode), 0},
{"GPIO_15_FLAGS", data(GPIODefinition[15].Flags), 0},
{"GPIO_15_PARAM1", data(GPIODefinition[15].Param1), 0},
{"GPIO_15_PARAM2", data(GPIODefinition[15].Param2), 0},
{"GPIO_15_PARAM3", data(GPIODefinition[15].Param3), 0},
{"GPIO_16_FUNC_CODE", data(GPIODefinition[16].FunctionCode), 0},
{"GPIO_16_FLAGS", data(GPIODefinition[16].Flags), 0},
{"GPIO_16_PARAM1", data(GPIODefinition[16].Param1), 0},
{"GPIO_16_PARAM2", data(GPIODefinition[16].Param2), 0},
{"GPIO_16_PARAM3", data(GPIODefinition[16].Param3), 0},
{"GPIO_17_FUNC_CODE", data(GPIODefinition[17].FunctionCode), 0},
{"GPIO_17_FLAGS", data(GPIODefinition[17].Flags), 0},
{"GPIO_17_PARAM1", data(GPIODefinition[17].Param1), 0},
{"GPIO_17_PARAM2", data(GPIODefinition[17].Param2), 0},
{"GPIO_17_PARAM3", data(GPIODefinition[17].Param3), 0},
{"GPIO_18_FUNC_CODE", data(GPIODefinition[18].FunctionCode), 0},
{"GPIO_18_FLAGS", data(GPIODefinition[18].Flags), 0},
{"GPIO_18_PARAM1", data(GPIODefinition[18].Param1), 0},
{"GPIO_18_PARAM2", data(GPIODefinition[18].Param2), 0},
{"GPIO_18_PARAM3", data(GPIODefinition[18].Param3), 0},
{"GPIO_19_FUNC_CODE", data(GPIODefinition[19].FunctionCode), 0},
{"GPIO_19_FLAGS", data(GPIODefinition[19].Flags), 0},
{"GPIO_19_PARAM1", data(GPIODefinition[19].Param1), 0},
{"GPIO_19_PARAM2", data(GPIODefinition[19].Param2), 0},
{"GPIO_19_PARAM3", data(GPIODefinition[19].Param3), 0},
{"GPIO_20_FUNC_CODE", data(GPIODefinition[20].FunctionCode), 0},
{"GPIO_20_FLAGS", data(GPIODefinition[20].Flags), 0},
{"GPIO_20_PARAM1", data(GPIODefinition[20].Param1), 0},
{"GPIO_20_PARAM2", data(GPIODefinition[20].Param2), 0},
{"GPIO_20_PARAM3", data(GPIODefinition[20].Param3), 0},
{"GPIO_21_FUNC_CODE", data(GPIODefinition[21].FunctionCode), 0},
{"GPIO_21_FLAGS", data(GPIODefinition[21].Flags), 0},
{"GPIO_21_PARAM1", data(GPIODefinition[21].Param1), 0},
{"GPIO_21_PARAM2", data(GPIODefinition[21].Param2), 0},
{"GPIO_21_PARAM3", data(GPIODefinition[21].Param3), 0},
{"GPIO_22_FUNC_CODE", data(GPIODefinition[22].FunctionCode), 0},
{"GPIO_22_FLAGS", data(GPIODefinition[22].Flags), 0},
{"GPIO_22_PARAM1", data(GPIODefinition[22].Param1), 0},
{"GPIO_22_PARAM2", data(GPIODefinition[22].Param2), 0},
{"GPIO_22_PARAM3", data(GPIODefinition[22].Param3), 0},
{"GPIO_23_FUNC_CODE", data(GPIODefinition[23].FunctionCode), 0},
{"GPIO_23_FLAGS", data(GPIODefinition[23].Flags), 0},
{"GPIO_23_PARAM1", data(GPIODefinition[23].Param1), 0},
{"GPIO_23_PARAM2", data(GPIODefinition[23].Param2), 0},
{"GPIO_23_PARAM3", data(GPIODefinition[23].Param3), 0},
{"GPIO_24_FUNC_CODE", data(GPIODefinition[24].FunctionCode), 0},
{"GPIO_24_FLAGS", data(GPIODefinition[24].Flags), 0},
{"GPIO_24_PARAM1", data(GPIODefinition[24].Param1), 0},
{"GPIO_24_PARAM2", data(GPIODefinition[24].Param2), 0},
{"GPIO_24_PARAM3", data(GPIODefinition[24].Param3), 0},
{"GPIO_25_FUNC_CODE", data(GPIODefinition[25].FunctionCode), 0},
{"GPIO_25_FLAGS", data(GPIODefinition[25].Flags), 0},
{"GPIO_25_PARAM1", data(GPIODefinition[25].Param1), 0},
{"GPIO_25_PARAM2", data(GPIODefinition[25].Param2), 0},
{"GPIO_25_PARAM3", data(GPIODefinition[25].Param3), 0},
{"GPIO_26_FUNC_CODE", data(GPIODefinition[26].FunctionCode), 0},
{"GPIO_26_FLAGS", data(GPIODefinition[26].Flags), 0},
{"GPIO_26_PARAM1", data(GPIODefinition[26].Param1), 0},
{"GPIO_26_PARAM2", data(GPIODefinition[26].Param2), 0},
{"GPIO_26_PARAM3", data(GPIODefinition[26].Param3), 0},
{"GPIO_27_FUNC_CODE", data(GPIODefinition[27].FunctionCode), 0},
{"GPIO_27_FLAGS", data(GPIODefinition[27].Flags), 0},
{"GPIO_27_PARAM1", data(GPIODefinition[27].Param1), 0},
{"GPIO_27_PARAM2", data(GPIODefinition[27].Param2), 0},
{"GPIO_27_PARAM3", data(GPIODefinition[27].Param3), 0},
{"GPIO_28_FUNC_CODE", data(GPIODefinition[28].FunctionCode), 0},
{"GPIO_28_FLAGS", data(GPIODefinition[28].Flags), 0},
{"GPIO_28_PARAM1", data(GPIODefinition[28].Param1), 0},
{"GPIO_28_PARAM2", data(GPIODefinition[28].Param2), 0},
{"GPIO_28_PARAM3", data(GPIODefinition[28].Param3), 0},
{"GPIO_29_FUNC_CODE", data(GPIODefinition[29].FunctionCode), 0},
{"GPIO_29_FLAGS", data(GPIODefinition[29].Flags), 0},
{"GPIO_29_PARAM1", data(GPIODefinition[29].Param1), 0},
{"GPIO_29_PARAM2", data(GPIODefinition[29].Param2), 0},
{"GPIO_29_PARAM3", data(GPIODefinition[29].Param3), 0},
{"GPIO_30_FUNC_CODE", data(GPIODefinition[30].FunctionCode), 0},
{"GPIO_30_FLAGS", data(GPIODefinition[30].Flags), 0},
{"GPIO_30_PARAM1", data(GPIODefinition[30].Param1), 0},
{"GPIO_30_PARAM2", data(GPIODefinition[30].Param2), 0},
{"GPIO_30_PARAM3", data(GPIODefinition[30].Param3), 0},
{"GPIO_31_FUNC_CODE", data(GPIODefinition[31].FunctionCode), 0},
{"GPIO_31_FLAGS", data(GPIODefinition[31].Flags), 0},
{"GPIO_31_PARAM1", data(GPIODefinition[31].Param1), 0},
{"GPIO_31_PARAM2", data(GPIODefinition[31].Param2), 0},
{"GPIO_31_PARAM3", data(GPIODefinition[31].Param3), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pManufacturingPage7_t)0)->x, sizeof(((pManufacturingPage7_t)0)->x)
ITEM manufacturing_page_7_items[] =
{
{"RESERVED1", data(Reserved1), OPT},
{"RESERVED2", data(Reserved2), OPT},
{"MP7_FLAGS", data(Flags), 0},
{"ENCLOSURE_NAME", data(EnclosureName), STR},
{"NUM_PHYS", data(NumPhys), 0},
{"RESERVED3", data(Reserved3), OPT},
{"RESERVED4", data(Reserved4), OPT},
{"CONN_INFO_0_PINOUT", data(ConnectorInfo[0].Pinout), 0},
{"CONN_INFO_0_CONNECTOR", data(ConnectorInfo[0].Connector), STR},
{"CONN_INFO_0_LOCATION", data(ConnectorInfo[0].Location), 0},
{"CONN_INFO_0_RESERVED1", data(ConnectorInfo[0].Reserved1), OPT},
{"CONN_INFO_0_SLOT", data(ConnectorInfo[0].Slot), 0},
{"CONN_INFO_0_RESERVED2", data(ConnectorInfo[0].Reserved2), OPT},
{"CONN_INFO_1_PINOUT", data(ConnectorInfo[1].Pinout), 0},
{"CONN_INFO_1_CONNECTOR", data(ConnectorInfo[1].Connector), STR},
{"CONN_INFO_1_LOCATION", data(ConnectorInfo[1].Location), 0},
{"CONN_INFO_1_RESERVED1", data(ConnectorInfo[1].Reserved1), OPT},
{"CONN_INFO_1_SLOT", data(ConnectorInfo[1].Slot), 0},
{"CONN_INFO_1_RESERVED2", data(ConnectorInfo[1].Reserved2), OPT},
{"CONN_INFO_2_PINOUT", data(ConnectorInfo[2].Pinout), 0},
{"CONN_INFO_2_CONNECTOR", data(ConnectorInfo[2].Connector), STR},
{"CONN_INFO_2_LOCATION", data(ConnectorInfo[2].Location), 0},
{"CONN_INFO_2_RESERVED1", data(ConnectorInfo[2].Reserved1), OPT},
{"CONN_INFO_2_SLOT", data(ConnectorInfo[2].Slot), 0},
{"CONN_INFO_2_RESERVED2", data(ConnectorInfo[2].Reserved2), OPT},
{"CONN_INFO_3_PINOUT", data(ConnectorInfo[3].Pinout), 0},
{"CONN_INFO_3_CONNECTOR", data(ConnectorInfo[3].Connector), STR},
{"CONN_INFO_3_LOCATION", data(ConnectorInfo[3].Location), 0},
{"CONN_INFO_3_RESERVED1", data(ConnectorInfo[3].Reserved1), OPT},
{"CONN_INFO_3_SLOT", data(ConnectorInfo[3].Slot), 0},
{"CONN_INFO_3_RESERVED2", data(ConnectorInfo[3].Reserved2), OPT},
{"CONN_INFO_4_PINOUT", data(ConnectorInfo[4].Pinout), 0},
{"CONN_INFO_4_CONNECTOR", data(ConnectorInfo[4].Connector), STR},
{"CONN_INFO_4_LOCATION", data(ConnectorInfo[4].Location), 0},
{"CONN_INFO_4_RESERVED1", data(ConnectorInfo[4].Reserved1), OPT},
{"CONN_INFO_4_SLOT", data(ConnectorInfo[4].Slot), 0},
{"CONN_INFO_4_RESERVED2", data(ConnectorInfo[4].Reserved2), OPT},
{"CONN_INFO_5_PINOUT", data(ConnectorInfo[5].Pinout), 0},
{"CONN_INFO_5_CONNECTOR", data(ConnectorInfo[5].Connector), STR},
{"CONN_INFO_5_LOCATION", data(ConnectorInfo[5].Location), 0},
{"CONN_INFO_5_RESERVED1", data(ConnectorInfo[5].Reserved1), OPT},
{"CONN_INFO_5_SLOT", data(ConnectorInfo[5].Slot), 0},
{"CONN_INFO_5_RESERVED2", data(ConnectorInfo[5].Reserved2), OPT},
{"CONN_INFO_6_PINOUT", data(ConnectorInfo[6].Pinout), 0},
{"CONN_INFO_6_CONNECTOR", data(ConnectorInfo[6].Connector), STR},
{"CONN_INFO_6_LOCATION", data(ConnectorInfo[6].Location), 0},
{"CONN_INFO_6_RESERVED1", data(ConnectorInfo[6].Reserved1), OPT},
{"CONN_INFO_6_SLOT", data(ConnectorInfo[6].Slot), 0},
{"CONN_INFO_6_RESERVED2", data(ConnectorInfo[6].Reserved2), OPT},
{"CONN_INFO_7_PINOUT", data(ConnectorInfo[7].Pinout), 0},
{"CONN_INFO_7_CONNECTOR", data(ConnectorInfo[7].Connector), STR},
{"CONN_INFO_7_LOCATION", data(ConnectorInfo[7].Location), 0},
{"CONN_INFO_7_RESERVED1", data(ConnectorInfo[7].Reserved1), OPT},
{"CONN_INFO_7_SLOT", data(ConnectorInfo[7].Slot), 0},
{"CONN_INFO_7_RESERVED2", data(ConnectorInfo[7].Reserved2), OPT},
{"CONN_INFO_8_PINOUT", data(ConnectorInfo[8].Pinout), OPT},
{"CONN_INFO_8_CONNECTOR", data(ConnectorInfo[8].Connector), STR | OPT},
{"CONN_INFO_8_LOCATION", data(ConnectorInfo[8].Location), OPT},
{"CONN_INFO_8_RESERVED1", data(ConnectorInfo[8].Reserved1), OPT},
{"CONN_INFO_8_SLOT", data(ConnectorInfo[8].Slot), OPT},
{"CONN_INFO_8_RESERVED2", data(ConnectorInfo[8].Reserved2), OPT},
{"CONN_INFO_9_PINOUT", data(ConnectorInfo[9].Pinout), OPT},
{"CONN_INFO_9_CONNECTOR", data(ConnectorInfo[9].Connector), STR | OPT},
{"CONN_INFO_9_LOCATION", data(ConnectorInfo[9].Location), OPT},
{"CONN_INFO_9_RESERVED1", data(ConnectorInfo[9].Reserved1), OPT},
{"CONN_INFO_9_SLOT", data(ConnectorInfo[9].Slot), OPT},
{"CONN_INFO_9_RESERVED2", data(ConnectorInfo[9].Reserved2), OPT},
{"CONN_INFO_10_PINOUT", data(ConnectorInfo[10].Pinout), OPT},
{"CONN_INFO_10_CONNECTOR", data(ConnectorInfo[10].Connector), STR | OPT},
{"CONN_INFO_10_LOCATION", data(ConnectorInfo[10].Location), OPT},
{"CONN_INFO_10_RESERVED1", data(ConnectorInfo[10].Reserved1), OPT},
{"CONN_INFO_10_SLOT", data(ConnectorInfo[10].Slot), OPT},
{"CONN_INFO_10_RESERVED2", data(ConnectorInfo[10].Reserved2), OPT},
{"CONN_INFO_11_PINOUT", data(ConnectorInfo[11].Pinout), OPT},
{"CONN_INFO_11_CONNECTOR", data(ConnectorInfo[11].Connector), STR | OPT},
{"CONN_INFO_11_LOCATION", data(ConnectorInfo[11].Location), OPT},
{"CONN_INFO_11_RESERVED1", data(ConnectorInfo[11].Reserved1), OPT},
{"CONN_INFO_11_SLOT", data(ConnectorInfo[11].Slot), OPT},
{"CONN_INFO_11_RESERVED2", data(ConnectorInfo[11].Reserved2), OPT},
{"CONN_INFO_12_PINOUT", data(ConnectorInfo[12].Pinout), OPT},
{"CONN_INFO_12_CONNECTOR", data(ConnectorInfo[12].Connector), STR | OPT},
{"CONN_INFO_12_LOCATION", data(ConnectorInfo[12].Location), OPT},
{"CONN_INFO_12_RESERVED1", data(ConnectorInfo[12].Reserved1), OPT},
{"CONN_INFO_12_SLOT", data(ConnectorInfo[12].Slot), OPT},
{"CONN_INFO_12_RESERVED2", data(ConnectorInfo[12].Reserved2), OPT},
{"CONN_INFO_13_PINOUT", data(ConnectorInfo[13].Pinout), OPT},
{"CONN_INFO_13_CONNECTOR", data(ConnectorInfo[13].Connector), STR | OPT},
{"CONN_INFO_13_LOCATION", data(ConnectorInfo[13].Location), OPT},
{"CONN_INFO_13_RESERVED1", data(ConnectorInfo[13].Reserved1), OPT},
{"CONN_INFO_13_SLOT", data(ConnectorInfo[13].Slot), OPT},
{"CONN_INFO_13_RESERVED2", data(ConnectorInfo[13].Reserved2), OPT},
{"CONN_INFO_14_PINOUT", data(ConnectorInfo[14].Pinout), OPT},
{"CONN_INFO_14_CONNECTOR", data(ConnectorInfo[14].Connector), STR | OPT},
{"CONN_INFO_14_LOCATION", data(ConnectorInfo[14].Location), OPT},
{"CONN_INFO_14_RESERVED1", data(ConnectorInfo[14].Reserved1), OPT},
{"CONN_INFO_14_SLOT", data(ConnectorInfo[14].Slot), OPT},
{"CONN_INFO_14_RESERVED2", data(ConnectorInfo[14].Reserved2), OPT},
{"CONN_INFO_15_PINOUT", data(ConnectorInfo[15].Pinout), OPT},
{"CONN_INFO_15_CONNECTOR", data(ConnectorInfo[15].Connector), STR | OPT},
{"CONN_INFO_15_LOCATION", data(ConnectorInfo[15].Location), OPT},
{"CONN_INFO_15_RESERVED1", data(ConnectorInfo[15].Reserved1), OPT},
{"CONN_INFO_15_SLOT", data(ConnectorInfo[15].Slot), OPT},
{"CONN_INFO_15_RESERVED2", data(ConnectorInfo[15].Reserved2), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pManufacturingPage8_t)0)->x, sizeof(((pManufacturingPage8_t)0)->x)
ITEM manufacturing_page_8_items2[] =
{
{"PRODSPECIFICINFO", data(ProductSpecificInfo), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pManufacturingPage9_SAS2_t)0)->x, sizeof(((pManufacturingPage9_SAS2_t)0)->x)
ITEM manufacturing_page_9_items2[] =
{
{"MAX_ATTEMPTS", data(MaxAttempts), 0},
{"NUM_RESOURCES", data(NumResources), 0},
{"RESERVED1", data(Reserved1), OPT},
{"RESERVED2", data(Reserved2), OPT},
{"NUM_VFS_MAX", data(ResourceArray[0].Maximum), 0},
{"NUM_VFS_DEC", data(ResourceArray[0].Decrement), 0},
{"NUM_VFS_MIN", data(ResourceArray[0].Minimum), 0},
{"NUM_VFS_ACT", data(ResourceArray[0].Actual), 0},
{"NUM_VPS_MAX", data(ResourceArray[1].Maximum), 0},
{"NUM_VPS_DEC", data(ResourceArray[1].Decrement), 0},
{"NUM_VPS_MIN", data(ResourceArray[1].Minimum), 0},
{"NUM_VPS_ACT", data(ResourceArray[1].Actual), 0},
{"HOST_CRED_PER_VF_MAX", data(ResourceArray[2].Maximum), 0},
{"HOST_CRED_PER_VF_DEC", data(ResourceArray[2].Decrement), 0},
{"HOST_CRED_PER_VF_MIN", data(ResourceArray[2].Minimum), 0},
{"HOST_CRED_PER_VF_ACT", data(ResourceArray[2].Actual), 0},
{"HIPRI_QDEPTH_PER_VF_MAX", data(ResourceArray[3].Maximum), 0},
{"HIPRI_QDEPTH_PER_VF_DEC", data(ResourceArray[3].Decrement), 0},
{"HIPRI_QDEPTH_PER_VF_MIN", data(ResourceArray[3].Minimum), 0},
{"HIPRI_QDEPTH_PER_VF_ACT", data(ResourceArray[3].Actual), 0},
{"TARGETS_MAX", data(ResourceArray[4].Maximum), 0},
{"TARGETS_DEC", data(ResourceArray[4].Decrement), 0},
{"TARGETS_MIN", data(ResourceArray[4].Minimum), 0},
{"TARGETS_ACT", data(ResourceArray[4].Actual), 0},
{"INITIATORS_MAX", data(ResourceArray[5].Maximum), 0},
{"INITIATORS_DEC", data(ResourceArray[5].Decrement), 0},
{"INITIATORS_MIN", data(ResourceArray[5].Minimum), 0},
{"INITIATORS_ACT", data(ResourceArray[5].Actual), 0},
{"TGT_CMD_BUFS_PER_VP_MAX", data(ResourceArray[6].Maximum), 0},
{"TGT_CMD_BUFS_PER_VP_DEC", data(ResourceArray[6].Decrement), 0},
{"TGT_CMD_BUFS_PER_VP_MIN", data(ResourceArray[6].Minimum), 0},
{"TGT_CMD_BUFS_PER_VP_ACT", data(ResourceArray[6].Actual), 0},
{"EXPANDERS_MAX", data(ResourceArray[7].Maximum), 0},
{"EXPANDERS_DEC", data(ResourceArray[7].Decrement), 0},
{"EXPANDERS_MIN", data(ResourceArray[7].Minimum), 0},
{"EXPANDERS_ACT", data(ResourceArray[7].Actual), 0},
{"PHYS_MAX", data(ResourceArray[8].Maximum), 0},
{"PHYS_DEC", data(ResourceArray[8].Decrement), 0},
{"PHYS_MIN", data(ResourceArray[8].Minimum), 0},
{"PHYS_ACT", data(ResourceArray[8].Actual), 0},
{"ENCLOSURES_MAX", data(ResourceArray[9].Maximum), 0},
{"ENCLOSURES_DEC", data(ResourceArray[9].Decrement), 0},
{"ENCLOSURES_MIN", data(ResourceArray[9].Minimum), 0},
{"ENCLOSURES_ACT", data(ResourceArray[9].Actual), 0},
{"RING_BUF_SIZE_MAX", data(ResourceArray[10].Maximum), 0},
{"RING_BUF_SIZE_DEC", data(ResourceArray[10].Decrement), 0},
{"RING_BUF_SIZE_MIN", data(ResourceArray[10].Minimum), 0},
{"RING_BUF_SIZE_ACT", data(ResourceArray[10].Actual), 0},
{"IR_BUFFER_SIZE_MAX", data(ResourceArray[11].Maximum), 0},
{"IR_BUFFER_SIZE_DEC", data(ResourceArray[11].Decrement), 0},
{"IR_BUFFER_SIZE_MIN", data(ResourceArray[11].Minimum), 0},
{"IR_BUFFER_SIZE_ACT", data(ResourceArray[11].Actual), 0},
{"NUM_ROUTE_TABLE_ENT_MAX", data(ResourceArray[12].Maximum), 0},
{"NUM_ROUTE_TABLE_ENT_DEC", data(ResourceArray[12].Decrement), 0},
{"NUM_ROUTE_TABLE_ENT_MIN", data(ResourceArray[12].Minimum), 0},
{"NUM_ROUTE_TABLE_ENT_ACT", data(ResourceArray[12].Actual), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pManufacturingPage10_t)0)->x, sizeof(((pManufacturingPage10_t)0)->x)
ITEM manufacturing_page_10_items2[] =
{
{"PRODSPECIFICINFO", data(ProductSpecificInfo), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pManufacturingPage11_SAS2_t)0)->x, sizeof(((pManufacturingPage11_SAS2_t)0)->x)
ITEM manufacturing_page_11_items2[] =
{
{"FLASH_TIME", data(FlashTime), 0},
{"NVS_TIME", data(NVTime), 0},
{"FLAG", data(Flag), 0},
{"RESERVED1", data(Reserved1), OPT},
{"HOT_PLUG_TIM_OUT", data(HotPlugTimeout), 0},
{"RESERVED_0", data(Reserved[0]), OPT},
{"RESERVED_1", data(Reserved[1]), OPT},
{"RESERVED_2", data(Reserved[2]), OPT},
{"MAX_CMD_FRAMES_0", data(MaxCmdFrames[0]), 0},
{"MAX_CMD_FRAMES_1", data(MaxCmdFrames[1]), 0},
{"MAX_CMD_FRAMES_2", data(MaxCmdFrames[2]), 0},
{"MAX_CMD_FRAMES_3", data(MaxCmdFrames[3]), 0},
{"SYS_REF_CLK", data(SysRefClk), 0},
{"RESERVED2", data(Reserved2), OPT},
{"EXT_UART_CLK", data(ExtUartClk), 0},
{"UART0_FLAGS", data(UartSettings[0].Flags), 0},
{"UART0_MORE_FLAGS", data(UartSettings[0].MoreFlags), 0},
{"UART0_TO", data(UartSettings[0].TO), 0},
{"UART0_BAUD_RATE", data(UartSettings[0].BaudRate), 0},
{"UART1_FLAGS", data(UartSettings[1].Flags), 0},
{"UART1_MORE_FLAGS", data(UartSettings[1].MoreFlags), 0},
{"UART1_TO", data(UartSettings[1].TO), 0},
{"UART1_BAUD_RATE", data(UartSettings[1].BaudRate), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pManufacturingPage12_SAS2_t)0)->x, sizeof(((pManufacturingPage12_SAS2_t)0)->x)
ITEM manufacturing_page_12_items2[] =
{
{"COMMON_FLAGS", data(Flags), 0},
{"RESERVED1", data(Reserved1), OPT},
{"RESERVED2", data(Reserved2), OPT},
{"SGPIO_CFG1", data(SGPIOCfg1), 0},
{"NUM_SGPIO", data(NumSGPIO), 0},
{"SGPIO_TYPE", data(SGPIOType), 0},
{"CLK_DIVIDE", data(ClkDivide), 0},
{"DEFAULT_TX_CTRL", data(DefaultTxCtrl), 0},
{"SGPIO_PAT_DEF0", data(SGPIOPatDef0), 0},
{"SGPIO_PAT_DEF1", data(SGPIOPatDef1), 0},
{"SGPIO_PAT_DEF2", data(SGPIOPatDef2), 0},
{"SGPIO_PAT_DEF3", data(SGPIOPatDef3), 0},
{"SGPIO_0_FLAGS", data(SGPIOInfo[0].Flags), 0},
{"SGPIO_0_BIT_ORDER_0", data(SGPIOInfo[0].BitOrderSelect[0]), 0},
{"SGPIO_0_BIT_ORDER_1", data(SGPIOInfo[0].BitOrderSelect[1]), 0},
{"SGPIO_0_BIT_ORDER_2", data(SGPIOInfo[0].BitOrderSelect[2]), 0},
{"SGPIO_0_BIT_ORDER_3", data(SGPIOInfo[0].BitOrderSelect[3]), 0},
{"SGPIO_0_BIT_ORDER_4", data(SGPIOInfo[0].BitOrderSelect[4]), 0},
{"SGPIO_0_BIT_ORDER_5", data(SGPIOInfo[0].BitOrderSelect[5]), 0},
{"SGPIO_0_BIT_ORDER_6", data(SGPIOInfo[0].BitOrderSelect[6]), 0},
{"SGPIO_0_BIT_ORDER_7", data(SGPIOInfo[0].BitOrderSelect[7]), 0},
{"SGPIO_0_BIT_ORDER_8", data(SGPIOInfo[0].BitOrderSelect[8]), 0},
{"SGPIO_0_BIT_ORDER_9", data(SGPIOInfo[0].BitOrderSelect[9]), 0},
{"SGPIO_0_BIT_ORDER_10", data(SGPIOInfo[0].BitOrderSelect[10]), 0},
{"SGPIO_0_BIT_ORDER_11", data(SGPIOInfo[0].BitOrderSelect[11]), 0},
{"SGPIO_1_FLAGS", data(SGPIOInfo[1].Flags), 0},
{"SGPIO_1_BIT_ORDER_0", data(SGPIOInfo[1].BitOrderSelect[0]), 0},
{"SGPIO_1_BIT_ORDER_1", data(SGPIOInfo[1].BitOrderSelect[1]), 0},
{"SGPIO_1_BIT_ORDER_2", data(SGPIOInfo[1].BitOrderSelect[2]), 0},
{"SGPIO_1_BIT_ORDER_3", data(SGPIOInfo[1].BitOrderSelect[3]), 0},
{"SGPIO_1_BIT_ORDER_4", data(SGPIOInfo[1].BitOrderSelect[4]), 0},
{"SGPIO_1_BIT_ORDER_5", data(SGPIOInfo[1].BitOrderSelect[5]), 0},
{"SGPIO_1_BIT_ORDER_6", data(SGPIOInfo[1].BitOrderSelect[6]), 0},
{"SGPIO_1_BIT_ORDER_7", data(SGPIOInfo[1].BitOrderSelect[7]), 0},
{"SGPIO_1_BIT_ORDER_8", data(SGPIOInfo[1].BitOrderSelect[8]), 0},
{"SGPIO_1_BIT_ORDER_9", data(SGPIOInfo[1].BitOrderSelect[9]), 0},
{"SGPIO_1_BIT_ORDER_10", data(SGPIOInfo[1].BitOrderSelect[10]), 0},
{"SGPIO_1_BIT_ORDER_11", data(SGPIOInfo[1].BitOrderSelect[11]), 0},
{"SGPIO_2_FLAGS", data(SGPIOInfo[2].Flags), 0},
{"SGPIO_2_BIT_ORDER_0", data(SGPIOInfo[2].BitOrderSelect[0]), 0},
{"SGPIO_2_BIT_ORDER_1", data(SGPIOInfo[2].BitOrderSelect[1]), 0},
{"SGPIO_2_BIT_ORDER_2", data(SGPIOInfo[2].BitOrderSelect[2]), 0},
{"SGPIO_2_BIT_ORDER_3", data(SGPIOInfo[2].BitOrderSelect[3]), 0},
{"SGPIO_2_BIT_ORDER_4", data(SGPIOInfo[2].BitOrderSelect[4]), 0},
{"SGPIO_2_BIT_ORDER_5", data(SGPIOInfo[2].BitOrderSelect[5]), 0},
{"SGPIO_2_BIT_ORDER_6", data(SGPIOInfo[2].BitOrderSelect[6]), 0},
{"SGPIO_2_BIT_ORDER_7", data(SGPIOInfo[2].BitOrderSelect[7]), 0},
{"SGPIO_2_BIT_ORDER_8", data(SGPIOInfo[2].BitOrderSelect[8]), 0},
{"SGPIO_2_BIT_ORDER_9", data(SGPIOInfo[2].BitOrderSelect[9]), 0},
{"SGPIO_2_BIT_ORDER_10", data(SGPIOInfo[2].BitOrderSelect[10]), 0},
{"SGPIO_2_BIT_ORDER_11", data(SGPIOInfo[2].BitOrderSelect[11]), 0},
{"SGPIO_3_FLAGS", data(SGPIOInfo[3].Flags), 0},
{"SGPIO_3_BIT_ORDER_0", data(SGPIOInfo[3].BitOrderSelect[0]), 0},
{"SGPIO_3_BIT_ORDER_1", data(SGPIOInfo[3].BitOrderSelect[1]), 0},
{"SGPIO_3_BIT_ORDER_2", data(SGPIOInfo[3].BitOrderSelect[2]), 0},
{"SGPIO_3_BIT_ORDER_3", data(SGPIOInfo[3].BitOrderSelect[3]), 0},
{"SGPIO_3_BIT_ORDER_4", data(SGPIOInfo[3].BitOrderSelect[4]), 0},
{"SGPIO_3_BIT_ORDER_5", data(SGPIOInfo[3].BitOrderSelect[5]), 0},
{"SGPIO_3_BIT_ORDER_6", data(SGPIOInfo[3].BitOrderSelect[6]), 0},
{"SGPIO_3_BIT_ORDER_7", data(SGPIOInfo[3].BitOrderSelect[7]), 0},
{"SGPIO_3_BIT_ORDER_8", data(SGPIOInfo[3].BitOrderSelect[8]), 0},
{"SGPIO_3_BIT_ORDER_9", data(SGPIOInfo[3].BitOrderSelect[9]), 0},
{"SGPIO_3_BIT_ORDER_10", data(SGPIOInfo[3].BitOrderSelect[10]), 0},
{"SGPIO_3_BIT_ORDER_11", data(SGPIOInfo[3].BitOrderSelect[11]), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pManufacturingPage13_SAS2_t)0)->x, sizeof(((pManufacturingPage13_SAS2_t)0)->x)
ITEM manufacturing_page_13_items2[] =
{
{"NUM_SGPIO_ENTRIES", data(NumSgpioEntries), 0},
{"RESERVED0", data(Reserved0), OPT},
{"RESERVED1", data(Reserved1), OPT},
{"RESERVED2", data(Reserved2), OPT},
{"SGPIO_0_MASK", data(SGPIOData[0].Mask), 0},
{"SGPIO_0_SLOT_STATUS", data(SGPIOData[0].SlotStatus), 0},
{"SGPIO_0_TX_CTRL_0", data(SGPIOData[0].TxControl[0]), 0},
{"SGPIO_0_TX_CTRL_1", data(SGPIOData[0].TxControl[1]), 0},
{"SGPIO_0_TX_CTRL_2", data(SGPIOData[0].TxControl[2]), 0},
{"SGPIO_0_TX_CTRL_3", data(SGPIOData[0].TxControl[3]), 0},
{"SGPIO_1_MASK", data(SGPIOData[0].Mask), 0},
{"SGPIO_1_SLOT_STATUS", data(SGPIOData[1].SlotStatus), 0},
{"SGPIO_1_TX_CTRL_0", data(SGPIOData[1].TxControl[0]), 0},
{"SGPIO_1_TX_CTRL_1", data(SGPIOData[1].TxControl[1]), 0},
{"SGPIO_1_TX_CTRL_2", data(SGPIOData[1].TxControl[2]), 0},
{"SGPIO_1_TX_CTRL_3", data(SGPIOData[1].TxControl[3]), 0},
{"SGPIO_2_MASK", data(SGPIOData[1].Mask), 0},
{"SGPIO_2_SLOT_STATUS", data(SGPIOData[2].SlotStatus), 0},
{"SGPIO_2_TX_CTRL_0", data(SGPIOData[2].TxControl[0]), 0},
{"SGPIO_2_TX_CTRL_1", data(SGPIOData[2].TxControl[1]), 0},
{"SGPIO_2_TX_CTRL_2", data(SGPIOData[2].TxControl[2]), 0},
{"SGPIO_2_TX_CTRL_3", data(SGPIOData[2].TxControl[3]), 0},
{"SGPIO_3_MASK", data(SGPIOData[3].Mask), 0},
{"SGPIO_3_SLOT_STATUS", data(SGPIOData[3].SlotStatus), 0},
{"SGPIO_3_TX_CTRL_0", data(SGPIOData[3].TxControl[0]), 0},
{"SGPIO_3_TX_CTRL_1", data(SGPIOData[3].TxControl[1]), 0},
{"SGPIO_3_TX_CTRL_2", data(SGPIOData[3].TxControl[2]), 0},
{"SGPIO_3_TX_CTRL_3", data(SGPIOData[3].TxControl[3]), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pIOUnitPage0_t)0)->x, sizeof(((pIOUnitPage0_t)0)->x)
ITEM io_unit_page_0_items[] =
{
{"UNIQUE_VALUE", data(UniqueValue), DUP},
{"UNIQUE_VALUE_LOW", data(UniqueValue.Low), 0},
{"UNIQUE_VALUE_HI", data(UniqueValue.High), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pIOUnitPage1_t)0)->x, sizeof(((pIOUnitPage1_t)0)->x)
ITEM io_unit_page_1_items[] =
{
{"IO_UNIT_PAGE_1_FLAGS", data(Flags), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pIOUnitPage2_t)0)->x, sizeof(((pIOUnitPage2_t)0)->x)
ITEM io_unit_page_2_items[] =
{
{"IO_UNIT_PAGE_2_FLAGS", data(Flags), 0},
{"BIOS_VERSION", data(BiosVersion), 0},
{"PCI_BUS_NUMBER", data(AdapterOrder[0].PciBusNumber), DUP},
{"PCI_BUS_NUMBER_0", data(AdapterOrder[0].PciBusNumber), 0},
{"PCI_DEVICE_FUNCTION", data(AdapterOrder[0].PciDeviceAndFunctionNumber), DUP},
{"PCI_DEVICE_FUNCTION_0", data(AdapterOrder[0].PciDeviceAndFunctionNumber), 0},
{"ADAPTER_FLAGS", data(AdapterOrder[0].AdapterFlags), DUP},
{"ADAPTER_FLAGS_0", data(AdapterOrder[0].AdapterFlags), 0},
{"PCI_BUS_NUMBER_1", data(AdapterOrder[1].PciBusNumber), OPT},
{"PCI_DEVICE_FUNCTION_1", data(AdapterOrder[1].PciDeviceAndFunctionNumber), OPT},
{"ADAPTER_FLAGS_1", data(AdapterOrder[1].AdapterFlags), OPT},
{"PCI_BUS_NUMBER_2", data(AdapterOrder[2].PciBusNumber), OPT},
{"PCI_DEVICE_FUNCTION_2", data(AdapterOrder[2].PciDeviceAndFunctionNumber), OPT},
{"ADAPTER_FLAGS_2", data(AdapterOrder[2].AdapterFlags), OPT},
{"PCI_BUS_NUMBER_3", data(AdapterOrder[3].PciBusNumber), OPT},
{"PCI_DEVICE_FUNCTION_3", data(AdapterOrder[3].PciDeviceAndFunctionNumber), OPT},
{"ADAPTER_FLAGS_3", data(AdapterOrder[3].AdapterFlags), OPT},
{"RESERVED1", data(Reserved1), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pIOUnitPage3_t)0)->x, sizeof(((pIOUnitPage3_t)0)->x)
#define io_unit_page_3_size_25 (int)(size_t)&((pIOUnitPage3_t)0)->GPIOVal[8]
ITEM io_unit_page_3_items[] =
{
{"GPIOCOUNT", data(GPIOCount), 0},
{"RESERVED1", data(Reserved1), OPT},
{"RESERVED2", data(Reserved2), OPT},
{"GPIOVAL_0", data(GPIOVal[0]), 0},
{"GPIOVAL_1", data(GPIOVal[1]), 0},
{"GPIOVAL_2", data(GPIOVal[2]), 0},
{"GPIOVAL_3", data(GPIOVal[3]), 0},
{"GPIOVAL_4", data(GPIOVal[4]), 0},
{"GPIOVAL_5", data(GPIOVal[5]), 0},
{"GPIOVAL_6", data(GPIOVal[6]), 0},
{"GPIOVAL_7", data(GPIOVal[7]), 0},
{"GPIOVAL_8", data(GPIOVal[8]), OPT},
{"GPIOVAL_9", data(GPIOVal[9]), OPT},
{"GPIOVAL_10", data(GPIOVal[10]), OPT},
{"GPIOVAL_11", data(GPIOVal[11]), OPT},
{"GPIOVAL_12", data(GPIOVal[12]), OPT},
{"GPIOVAL_13", data(GPIOVal[13]), OPT},
{"GPIOVAL_14", data(GPIOVal[14]), OPT},
{"GPIOVAL_15", data(GPIOVal[15]), OPT},
{"GPIOVAL_16", data(GPIOVal[16]), OPT},
{"GPIOVAL_17", data(GPIOVal[17]), OPT},
{"GPIOVAL_18", data(GPIOVal[18]), OPT},
{"GPIOVAL_19", data(GPIOVal[19]), OPT},
{"GPIOVAL_20", data(GPIOVal[20]), OPT},
{"GPIOVAL_21", data(GPIOVal[21]), OPT},
{"GPIOVAL_22", data(GPIOVal[22]), OPT},
{"GPIOVAL_23", data(GPIOVal[23]), OPT},
{"GPIOVAL_24", data(GPIOVal[24]), OPT},
{"GPIOVAL_25", data(GPIOVal[25]), OPT},
{"GPIOVAL_26", data(GPIOVal[26]), OPT},
{"GPIOVAL_27", data(GPIOVal[27]), OPT},
{"GPIOVAL_28", data(GPIOVal[28]), OPT},
{"GPIOVAL_29", data(GPIOVal[29]), OPT},
{"GPIOVAL_30", data(GPIOVal[30]), OPT},
{"GPIOVAL_31", data(GPIOVal[31]), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pIOUnitPage4_t)0)->x, sizeof(((pIOUnitPage4_t)0)->x)
ITEM io_unit_page_4_items[] =
{
{"IOUNIT_4_RESERVED1", data(Reserved1), OPT},
{"FWIMAGE_FLAGS", data(FWImageSGE.FlagsLength), 0},
{"FWIMAGE_64HIGH", data(FWImageSGE.u.Address64.High), 0},
{"FWIMAGE_64LOW", data(FWImageSGE.u.Address64.Low), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pIOCPage0_t)0)->x, sizeof(((pIOCPage0_t)0)->x)
ITEM ioc_page_0_items[] =
{
{"TOTAL_NV_STORE", data(TotalNVStore), 0},
{"FREE_NV_STORE", data(FreeNVStore), 0},
{"VENDOR_ID", data(VendorID), 0},
{"DEVICE_ID", data(DeviceID), 0},
{"REVISION_ID", data(RevisionID), 0},
{"RESERVED", data(Reserved), OPT},
{"RESERVED_0", data(Reserved[0]), OPT},
{"RESERVED_1", data(Reserved[1]), OPT},
{"RESERVED_2", data(Reserved[2]), OPT},
{"CLASS_CODE", data(ClassCode), 0},
{"SS_VNDR_ID", data(SubsystemVendorID), 0},
{"SS_ID", data(SubsystemID), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pIOCPage1_t)0)->x, sizeof(((pIOCPage1_t)0)->x)
ITEM ioc_page_1_items[] =
{
{"IOC_PAGE_1_FLAGS", data(Flags), 0},
{"COALESCING_TIMEOUT", data(CoalescingTimeout), 0},
{"COALESCING_DEPTH", data(CoalescingDepth), 0},
{"PCI_SLOT_NUM", data(PCISlotNum), 0},
{"RESERVED", data(Reserved), OPT},
{"RESERVED_0", data(Reserved[0]), OPT},
{"RESERVED_1", data(Reserved[1]), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pMpi2IOCPage1_t)0)->x, sizeof(((pMpi2IOCPage1_t)0)->x)
ITEM ioc_page_1_items2[] =
{
{"IOC_PAGE_1_FLAGS", data(Flags), 0},
{"COALESCING_TIMEOUT", data(CoalescingTimeout), 0},
{"COALESCING_DEPTH", data(CoalescingDepth), 0},
{"PCI_SLOT_NUM", data(PCISlotNum), 0},
{"PCI_BUS_NUM", data(PCIBusNum), 0},
{"PCI_DOMAIN_SEGMENT", data(PCIDomainSegment), 0},
{"RESERVED1", data(Reserved1), OPT},
{"RESERVED2", data(Reserved2), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pIOCPage2_t)0)->x, sizeof(((pIOCPage2_t)0)->x)
ITEM ioc_page_2_items[] =
{
{"CAP_FLAGS", data(CapabilitiesFlags), 0},
{"NUM_ACTIVE_VOLS", data(NumActiveVolumes), 0},
{"MAX_VOLS", data(MaxVolumes), 0},
{"NUM_ACTIVE_PHYS_DSKS", data(NumActivePhysDisks), 0},
{"MAX_PHYS_DSKS", data(MaxPhysDisks), 0},
{"VOL_ID", data(RaidVolume[0].VolumeID), 0},
{"VOL_BUS", data(RaidVolume[0].VolumeBus), 0},
{"VOL_IOC", data(RaidVolume[0].VolumeIOC), 0},
{"VOL_PAGE_NUM", data(RaidVolume[0].VolumePageNumber), 0},
{"VOL_TYPE", data(RaidVolume[0].VolumeType), 0},
{"FLAGS", data(RaidVolume[0].Flags), 0},
{"RESERVED", data(RaidVolume[0].Reserved3), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pIOCPage3_t)0)->x, sizeof(((pIOCPage3_t)0)->x)
ITEM ioc_page_3_items[] =
{
{"NUM_PHYS_DSKS", data(NumPhysDisks), 0},
{"RESERVED1", data(Reserved1), OPT},
{"RESERVED2", data(Reserved2), OPT},
{"PHYS_DSK_ID", data(PhysDisk[0].PhysDiskID), 0},
{"PHYS_DSK_BUS", data(PhysDisk[0].PhysDiskBus), 0},
{"PHYS_DSK_IOC", data(PhysDisk[0].PhysDiskIOC), 0},
{"PHYS_DSE_NUM", data(PhysDisk[0].PhysDiskNum), DUP},
{"PHYS_DSK_NUM", data(PhysDisk[0].PhysDiskNum), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pIOCPage4_t)0)->x, sizeof(((pIOCPage4_t)0)->x)
ITEM ioc_page_4_items[] =
{
{"ACTIVE_SEP", data(ActiveSEP), 0},
{"MAX_SEP", data(MaxSEP), 0},
{"RESERVED", data(Reserved1), OPT},
{"RESERVED1", data(Reserved1), OPT},
{"SEP_TARGET_ID", data(SEP[0].SEPTargetID), 0},
{"SEP_BUS", data(SEP[0].SEPBus), 0},
{"RESERVED", data(SEP[0].Reserved), OPT},
{"IOC_4_SEP_RESERVED", data(SEP[0].Reserved), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pIOCPage5_t)0)->x, sizeof(((pIOCPage5_t)0)->x)
ITEM ioc_page_5_items[] =
{
{"RESERVED1", data(Reserved1), OPT},
{"NUM_HOT_SPARES", data(NumHotSpares), 0},
{"RESERVED2", data(Reserved2), OPT},
{"RESERVED3", data(Reserved3), OPT},
{"PHYS_DSK_NUM", data(HotSpare[0].PhysDiskNum), 0},
{"RESERVED", data(HotSpare[0].Reserved), OPT},
{"IOC_5_HOT_SPARE_RESERVED", data(HotSpare[0].Reserved), OPT},
{"HOT_SPARE_POOL", data(HotSpare[0].HotSparePool), 0},
{"FLAGS", data(HotSpare[0].Flags), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pIOCPage6_t)0)->x, sizeof(((pIOCPage6_t)0)->x)
ITEM ioc_page_6_items[] =
{
{"CAPABILITIES_FLAGS", data(CapabilitiesFlags), OPT},
{"MAX_DRIVES_IS", data(MaxDrivesIS), OPT},
{"MAX_DRIVES_IM", data(MaxDrivesIM), OPT},
{"MAX_DRIVES_IME", data(MaxDrivesIME), OPT},
{"RESERVED1", data(Reserved1), OPT},
{"MIN_DRIVES_IS", data(MinDrivesIS), OPT},
{"MIN_DRIVES_IM", data(MinDrivesIM), OPT},
{"MIN_DRIVES_IME", data(MinDrivesIME), OPT},
{"RESERVED2", data(Reserved2), OPT},
{"MAX_GLOBAL_HOTSPARES", data(MaxGlobalHotSpares), OPT},
{"RESERVED3", data(Reserved3), OPT},
{"RESERVED4", data(Reserved4), OPT},
{"RESERVED5", data(Reserved5), OPT},
{"SUPPORTED_STRIPE_SIZE_MAP_IS", data(SupportedStripeSizeMapIS), OPT},
{"SUPPORTED_STRIPE_SIZE_MAP_IME", data(SupportedStripeSizeMapIME), OPT},
{"RESERVED6", data(Reserved6), OPT},
{"METADATA_SIZE", data(MetadataSize), OPT},
{"RESERVED7", data(Reserved7), OPT},
{"RESERVED8", data(Reserved8), OPT},
{"MAX_BAD_BLOCK_TABLE_ENTRIES", data(MaxBadBlockTableEntries), OPT},
{"RESERVED9", data(Reserved9), OPT},
{"IR_NVSRAM_USAGE", data(IRNvsramUsage), OPT},
{"RESERVED10", data(Reserved10), OPT},
{"IR_NVSRAM_VERSION", data(IRNvsramVersion), OPT},
{"RESERVED11", data(Reserved11), OPT},
{"RESERVED12", data(Reserved12), OPT},
{"ALL", sizeof(ConfigPageHeader_t), sizeof(IOCPage6_t) - sizeof(ConfigPageHeader_t), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pMpi2IOCPage8_t)0)->x, sizeof(((pMpi2IOCPage8_t)0)->x)
ITEM ioc_page_8_items2[] =
{
{"NUM_DEVS_PER_ENCL", data(NumDevsPerEnclosure), 0},
{"RESERVED1", data(Reserved1), OPT},
{"RESERVED2", data(Reserved2), OPT},
{"MAX_PERSIST_ENTRIES", data(MaxPersistentEntries), 0},
{"MAX_NUM_PHYS_MAPPED_IDS", data(MaxNumPhysicalMappedIDs), 0},
{"FLAGS", data(Flags), 0},
{"RESERVED3", data(Reserved3), OPT},
{"IR_VOLUME_MAPPING_FLAGS", data(IRVolumeMappingFlags), 0},
{"RESERVED4", data(Reserved4), OPT},
{"RESERVED5", data(Reserved5), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pSasIOUnitPage0_t)0)->x, sizeof(((pSasIOUnitPage0_t)0)->x)
ITEM sas_io_unit_page_0_items[] =
{
{"NVDATA_VER_DEFAULT", data(NvdataVersionDefault), 0},
{"NVDATA_VER_PERSISTENT", data(NvdataVersionPersistent), 0},
{"NUM_PHYS", data(NumPhys), 0},
{"RESERVED2", data(Reserved2), OPT},
{"RESERVED1", data(Reserved3), OPT},
{"RESERVED3", data(Reserved3), OPT},
{"PORT", data(PhyData[0].Port), 0},
{"PORT_FLGS", data(PhyData[0].PortFlags), 0},
{"PHY_FLGS", data(PhyData[0].PhyFlags), 0},
{"NEGOT_LINK_RATE", data(PhyData[0].NegotiatedLinkRate), 0},
{"CNTLR_PHY_DEV_INFO", data(PhyData[0].ControllerPhyDeviceInfo), 0},
{"ATTCH_DEV_HNDL", data(PhyData[0].AttachedDeviceHandle), 0},
{"CNTLR_DEV_HNDL", data(PhyData[0].ControllerDevHandle), 0},
{"SAS0_DISCOVERYSTATUS", data(PhyData[0].DiscoveryStatus), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pSasIOUnitPage1_t)0)->x, sizeof(((pSasIOUnitPage1_t)0)->x)
ITEM sas_io_unit_page_1_items[] =
{
{"CONTROLFLAGS", data(ControlFlags), 0},
{"MAXSATATARGETS", data(MaxNumSATATargets), 0},
{"ADDCONTROLFLAGS", data(AdditionalControlFlags), 0},
{"RESERVED1", data(Reserved1), OPT},
{"NUM_PHYS", data(NumPhys), 0},
{"SATAMAXQDEPTH", data(SATAMaxQDepth), 0},
{"REPDEVMISSINGDELAY", data(ReportDeviceMissingDelay), 0},
{"IODEVMISSINGDELAY", data(IODeviceMissingDelay), 0},
{"Port", data(PhyData[0].Port), DUP},
{"SAS_IO_UNIT1_PHY_0_PORT", data(PhyData[0].Port), 0},
{"Port_Flgs", data(PhyData[0].PortFlags), DUP},
{"SAS_IO_UNIT1_PHY_0_PORT_FLGS", data(PhyData[0].PortFlags), 0},
{"PHY_FLGS", data(PhyData[0].PhyFlags), DUP},
{"SAS_IO_UNIT1_PHY_0_PHY_FLGS", data(PhyData[0].PhyFlags), 0},
{"MIN_MAX_LINK_RATE", data(PhyData[0].MaxMinLinkRate), DUP},
{"SAS_IO_UNIT1_PHY_0_MIN_MAX_LINK_RATE", data(PhyData[0].MaxMinLinkRate), 0},
{"CNTLR_PHY_DEV_INFO", data(PhyData[0].ControllerPhyDeviceInfo), DUP},
{"SAS_IO_UNIT1_PHY_0_CNTLR_PHY_DEV_INFO", data(PhyData[0].ControllerPhyDeviceInfo), 0},
{"MAX_TARG_PORT_CONN_TIME", data(PhyData[0].MaxTargetPortConnectTime), DUP},
{"SAS_IO_UNIT1_PHY_0_MAX_TARG_PORT_CONN_TIME", data(PhyData[0].MaxTargetPortConnectTime), 0},
{"RESERVED", data(PhyData[0].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_0_RESERVED1", data(PhyData[0].Reserved1), OPT},
{"Port", data(PhyData[1].Port), DUP},
{"SAS_IO_UNIT1_PHY_1_PORT", data(PhyData[1].Port), 0},
{"Port_Flgs", data(PhyData[1].PortFlags), DUP},
{"SAS_IO_UNIT1_PHY_1_PORT_FLGS", data(PhyData[1].PortFlags), 0},
{"PHY_FLGS", data(PhyData[1].PhyFlags), DUP},
{"SAS_IO_UNIT1_PHY_1_PHY_FLGS", data(PhyData[1].PhyFlags), 0},
{"MIN_MAX_LINK_RATE", data(PhyData[1].MaxMinLinkRate), DUP},
{"SAS_IO_UNIT1_PHY_1_MIN_MAX_LINK_RATE", data(PhyData[1].MaxMinLinkRate), 0},
{"CNTLR_PHY_DEV_INFO", data(PhyData[1].ControllerPhyDeviceInfo), DUP},
{"SAS_IO_UNIT1_PHY_1_CNTLR_PHY_DEV_INFO", data(PhyData[1].ControllerPhyDeviceInfo), 0},
{"MAX_TARG_PORT_CONN_TIME", data(PhyData[1].MaxTargetPortConnectTime), DUP},
{"SAS_IO_UNIT1_PHY_1_MAX_TARG_PORT_CONN_TIME", data(PhyData[1].MaxTargetPortConnectTime), 0},
{"RESERVED", data(PhyData[1].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_1_RESERVED1", data(PhyData[1].Reserved1), OPT},
{"Port", data(PhyData[2].Port), DUP},
{"SAS_IO_UNIT1_PHY_2_PORT", data(PhyData[2].Port), 0},
{"Port_Flgs", data(PhyData[2].PortFlags), DUP},
{"SAS_IO_UNIT1_PHY_2_PORT_FLGS", data(PhyData[2].PortFlags), 0},
{"PHY_FLGS", data(PhyData[2].PhyFlags), DUP},
{"SAS_IO_UNIT1_PHY_2_PHY_FLGS", data(PhyData[2].PhyFlags), 0},
{"MIN_MAX_LINK_RATE", data(PhyData[2].MaxMinLinkRate), DUP},
{"SAS_IO_UNIT1_PHY_2_MIN_MAX_LINK_RATE", data(PhyData[2].MaxMinLinkRate), 0},
{"CNTLR_PHY_DEV_INFO", data(PhyData[2].ControllerPhyDeviceInfo), DUP},
{"SAS_IO_UNIT1_PHY_2_CNTLR_PHY_DEV_INFO", data(PhyData[2].ControllerPhyDeviceInfo), 0},
{"MAX_TARG_PORT_CONN_TIME", data(PhyData[2].MaxTargetPortConnectTime), DUP},
{"SAS_IO_UNIT1_PHY_2_MAX_TARG_PORT_CONN_TIME", data(PhyData[2].MaxTargetPortConnectTime), 0},
{"RESERVED", data(PhyData[2].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_2_RESERVED1", data(PhyData[2].Reserved1), OPT},
{"Port", data(PhyData[3].Port), DUP},
{"SAS_IO_UNIT1_PHY_3_PORT", data(PhyData[3].Port), 0},
{"Port_Flgs", data(PhyData[3].PortFlags), DUP},
{"SAS_IO_UNIT1_PHY_3_PORT_FLGS", data(PhyData[3].PortFlags), 0},
{"PHY_FLGS", data(PhyData[3].PhyFlags), DUP},
{"SAS_IO_UNIT1_PHY_3_PHY_FLGS", data(PhyData[3].PhyFlags), 0},
{"MIN_MAX_LINK_RATE", data(PhyData[3].MaxMinLinkRate), DUP},
{"SAS_IO_UNIT1_PHY_3_MIN_MAX_LINK_RATE", data(PhyData[3].MaxMinLinkRate), 0},
{"CNTLR_PHY_DEV_INFO", data(PhyData[3].ControllerPhyDeviceInfo), DUP},
{"SAS_IO_UNIT1_PHY_3_CNTLR_PHY_DEV_INFO", data(PhyData[3].ControllerPhyDeviceInfo), 0},
{"MAX_TARG_PORT_CONN_TIME", data(PhyData[3].MaxTargetPortConnectTime), DUP},
{"SAS_IO_UNIT1_PHY_3_MAX_TARG_PORT_CONN_TIME", data(PhyData[3].MaxTargetPortConnectTime), 0},
{"RESERVED", data(PhyData[3].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_3_RESERVED1", data(PhyData[3].Reserved1), OPT},
{"Port", data(PhyData[4].Port), DUP},
{"SAS_IO_UNIT1_PHY_4_PORT", data(PhyData[4].Port), 0},
{"Port_Flgs", data(PhyData[4].PortFlags), DUP},
{"SAS_IO_UNIT1_PHY_4_PORT_FLGS", data(PhyData[4].PortFlags), 0},
{"PHY_FLGS", data(PhyData[4].PhyFlags), DUP},
{"SAS_IO_UNIT1_PHY_4_PHY_FLGS", data(PhyData[4].PhyFlags), 0},
{"MIN_MAX_LINK_RATE", data(PhyData[4].MaxMinLinkRate), DUP},
{"SAS_IO_UNIT1_PHY_4_MIN_MAX_LINK_RATE", data(PhyData[4].MaxMinLinkRate), 0},
{"CNTLR_PHY_DEV_INFO", data(PhyData[4].ControllerPhyDeviceInfo), DUP},
{"SAS_IO_UNIT1_PHY_4_CNTLR_PHY_DEV_INFO", data(PhyData[4].ControllerPhyDeviceInfo), 0},
{"MAX_TARG_PORT_CONN_TIME", data(PhyData[4].MaxTargetPortConnectTime), DUP},
{"SAS_IO_UNIT1_PHY_4_MAX_TARG_PORT_CONN_TIME", data(PhyData[4].MaxTargetPortConnectTime), 0},
{"RESERVED", data(PhyData[4].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_4_RESERVED1", data(PhyData[4].Reserved1), OPT},
{"Port", data(PhyData[5].Port), DUP},
{"SAS_IO_UNIT1_PHY_5_PORT", data(PhyData[5].Port), 0},
{"Port_Flgs", data(PhyData[5].PortFlags), DUP},
{"SAS_IO_UNIT1_PHY_5_PORT_FLGS", data(PhyData[5].PortFlags), 0},
{"PHY_FLGS", data(PhyData[5].PhyFlags), DUP},
{"SAS_IO_UNIT1_PHY_5_PHY_FLGS", data(PhyData[5].PhyFlags), 0},
{"MIN_MAX_LINK_RATE", data(PhyData[5].MaxMinLinkRate), DUP},
{"SAS_IO_UNIT1_PHY_5_MIN_MAX_LINK_RATE", data(PhyData[5].MaxMinLinkRate), 0},
{"CNTLR_PHY_DEV_INFO", data(PhyData[5].ControllerPhyDeviceInfo), DUP},
{"SAS_IO_UNIT1_PHY_5_CNTLR_PHY_DEV_INFO", data(PhyData[5].ControllerPhyDeviceInfo), 0},
{"MAX_TARG_PORT_CONN_TIME", data(PhyData[5].MaxTargetPortConnectTime), DUP},
{"SAS_IO_UNIT1_PHY_5_MAX_TARG_PORT_CONN_TIME", data(PhyData[5].MaxTargetPortConnectTime), 0},
{"RESERVED", data(PhyData[5].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_5_RESERVED1", data(PhyData[5].Reserved1), OPT},
{"Port", data(PhyData[6].Port), DUP},
{"SAS_IO_UNIT1_PHY_6_PORT", data(PhyData[6].Port), 0},
{"Port_Flgs", data(PhyData[6].PortFlags), DUP},
{"SAS_IO_UNIT1_PHY_6_PORT_FLGS", data(PhyData[6].PortFlags), 0},
{"PHY_FLGS", data(PhyData[6].PhyFlags), DUP},
{"SAS_IO_UNIT1_PHY_6_PHY_FLGS", data(PhyData[6].PhyFlags), 0},
{"MIN_MAX_LINK_RATE", data(PhyData[6].MaxMinLinkRate), DUP},
{"SAS_IO_UNIT1_PHY_6_MIN_MAX_LINK_RATE", data(PhyData[6].MaxMinLinkRate), 0},
{"CNTLR_PHY_DEV_INFO", data(PhyData[6].ControllerPhyDeviceInfo), DUP},
{"SAS_IO_UNIT1_PHY_6_CNTLR_PHY_DEV_INFO", data(PhyData[6].ControllerPhyDeviceInfo), 0},
{"MAX_TARG_PORT_CONN_TIME", data(PhyData[6].MaxTargetPortConnectTime), DUP},
{"SAS_IO_UNIT1_PHY_6_MAX_TARG_PORT_CONN_TIME", data(PhyData[6].MaxTargetPortConnectTime), 0},
{"RESERVED", data(PhyData[6].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_6_RESERVED1", data(PhyData[6].Reserved1), OPT},
{"Port", data(PhyData[7].Port), DUP},
{"SAS_IO_UNIT1_PHY_7_PORT", data(PhyData[7].Port), 0},
{"Port_Flgs", data(PhyData[7].PortFlags), DUP},
{"SAS_IO_UNIT1_PHY_7_PORT_FLGS", data(PhyData[7].PortFlags), 0},
{"PHY_FLGS", data(PhyData[7].PhyFlags), DUP},
{"SAS_IO_UNIT1_PHY_7_PHY_FLGS", data(PhyData[7].PhyFlags), 0},
{"MIN_MAX_LINK_RATE", data(PhyData[7].MaxMinLinkRate), DUP},
{"SAS_IO_UNIT1_PHY_7_MIN_MAX_LINK_RATE", data(PhyData[7].MaxMinLinkRate), 0},
{"CNTLR_PHY_DEV_INFO", data(PhyData[7].ControllerPhyDeviceInfo), DUP},
{"SAS_IO_UNIT1_PHY_7_CNTLR_PHY_DEV_INFO", data(PhyData[7].ControllerPhyDeviceInfo), 0},
{"MAX_TARG_PORT_CONN_TIME", data(PhyData[7].MaxTargetPortConnectTime), DUP},
{"SAS_IO_UNIT1_PHY_7_MAX_TARG_PORT_CONN_TIME", data(PhyData[7].MaxTargetPortConnectTime), 0},
{"RESERVED", data(PhyData[7].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_7_RESERVED1", data(PhyData[7].Reserved1), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pMpi2SasIOUnitPage1_t)0)->x, sizeof(((pMpi2SasIOUnitPage1_t)0)->x)
ITEM sas_io_unit_page_1_items2[] =
{
{"CONTROLFLAGS", data(ControlFlags), 0},
{"SASNARROWMAXQDEPTH", data(SASNarrowMaxQueueDepth), 0},
{"ADDCONTROLFLAGS", data(AdditionalControlFlags), 0},
{"SASWIDEMAXQDEPTH", data(SASWideMaxQueueDepth), 0},
{"NUM_PHYS", data(NumPhys), 0},
{"SATAMAXQDEPTH", data(SATAMaxQDepth), 0},
{"REPDEVMISSINGDELAY", data(ReportDeviceMissingDelay), 0},
{"IODEVMISSINGDELAY", data(IODeviceMissingDelay), 0},
{"SAS_IO_UNIT1_PHY_0_PORT", data(PhyData[0].Port), 0},
{"SAS_IO_UNIT1_PHY_0_PORT_FLGS", data(PhyData[0].PortFlags), 0},
{"SAS_IO_UNIT1_PHY_0_PHY_FLGS", data(PhyData[0].PhyFlags), 0},
{"SAS_IO_UNIT1_PHY_0_MIN_MAX_LINK_RATE", data(PhyData[0].MaxMinLinkRate), 0},
{"SAS_IO_UNIT1_PHY_0_CNTLR_PHY_DEV_INFO", data(PhyData[0].ControllerPhyDeviceInfo), 0},
{"SAS_IO_UNIT1_PHY_0_MAX_TARG_PORT_CONN_TIME", data(PhyData[0].MaxTargetPortConnectTime), 0},
{"SAS_IO_UNIT1_PHY_0_RESERVED1", data(PhyData[0].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_1_PORT", data(PhyData[1].Port), 0},
{"SAS_IO_UNIT1_PHY_1_PORT_FLGS", data(PhyData[1].PortFlags), 0},
{"SAS_IO_UNIT1_PHY_1_PHY_FLGS", data(PhyData[1].PhyFlags), 0},
{"SAS_IO_UNIT1_PHY_1_MIN_MAX_LINK_RATE", data(PhyData[1].MaxMinLinkRate), 0},
{"SAS_IO_UNIT1_PHY_1_CNTLR_PHY_DEV_INFO", data(PhyData[1].ControllerPhyDeviceInfo), 0},
{"SAS_IO_UNIT1_PHY_1_MAX_TARG_PORT_CONN_TIME", data(PhyData[1].MaxTargetPortConnectTime), 0},
{"SAS_IO_UNIT1_PHY_1_RESERVED1", data(PhyData[1].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_2_PORT", data(PhyData[2].Port), 0},
{"SAS_IO_UNIT1_PHY_2_PORT_FLGS", data(PhyData[2].PortFlags), 0},
{"SAS_IO_UNIT1_PHY_2_PHY_FLGS", data(PhyData[2].PhyFlags), 0},
{"SAS_IO_UNIT1_PHY_2_MIN_MAX_LINK_RATE", data(PhyData[2].MaxMinLinkRate), 0},
{"SAS_IO_UNIT1_PHY_2_CNTLR_PHY_DEV_INFO", data(PhyData[2].ControllerPhyDeviceInfo), 0},
{"SAS_IO_UNIT1_PHY_2_MAX_TARG_PORT_CONN_TIME", data(PhyData[2].MaxTargetPortConnectTime), 0},
{"SAS_IO_UNIT1_PHY_2_RESERVED1", data(PhyData[2].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_3_PORT", data(PhyData[3].Port), 0},
{"SAS_IO_UNIT1_PHY_3_PORT_FLGS", data(PhyData[3].PortFlags), 0},
{"SAS_IO_UNIT1_PHY_3_PHY_FLGS", data(PhyData[3].PhyFlags), 0},
{"SAS_IO_UNIT1_PHY_3_MIN_MAX_LINK_RATE", data(PhyData[3].MaxMinLinkRate), 0},
{"SAS_IO_UNIT1_PHY_3_CNTLR_PHY_DEV_INFO", data(PhyData[3].ControllerPhyDeviceInfo), 0},
{"SAS_IO_UNIT1_PHY_3_MAX_TARG_PORT_CONN_TIME", data(PhyData[3].MaxTargetPortConnectTime), 0},
{"SAS_IO_UNIT1_PHY_3_RESERVED1", data(PhyData[3].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_4_PORT", data(PhyData[4].Port), 0},
{"SAS_IO_UNIT1_PHY_4_PORT_FLGS", data(PhyData[4].PortFlags), 0},
{"SAS_IO_UNIT1_PHY_4_PHY_FLGS", data(PhyData[4].PhyFlags), 0},
{"SAS_IO_UNIT1_PHY_4_MIN_MAX_LINK_RATE", data(PhyData[4].MaxMinLinkRate), 0},
{"SAS_IO_UNIT1_PHY_4_CNTLR_PHY_DEV_INFO", data(PhyData[4].ControllerPhyDeviceInfo), 0},
{"SAS_IO_UNIT1_PHY_4_MAX_TARG_PORT_CONN_TIME", data(PhyData[4].MaxTargetPortConnectTime), 0},
{"SAS_IO_UNIT1_PHY_4_RESERVED1", data(PhyData[4].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_5_PORT", data(PhyData[5].Port), 0},
{"SAS_IO_UNIT1_PHY_5_PORT_FLGS", data(PhyData[5].PortFlags), 0},
{"SAS_IO_UNIT1_PHY_5_PHY_FLGS", data(PhyData[5].PhyFlags), 0},
{"SAS_IO_UNIT1_PHY_5_MIN_MAX_LINK_RATE", data(PhyData[5].MaxMinLinkRate), 0},
{"SAS_IO_UNIT1_PHY_5_CNTLR_PHY_DEV_INFO", data(PhyData[5].ControllerPhyDeviceInfo), 0},
{"SAS_IO_UNIT1_PHY_5_MAX_TARG_PORT_CONN_TIME", data(PhyData[5].MaxTargetPortConnectTime), 0},
{"SAS_IO_UNIT1_PHY_5_RESERVED1", data(PhyData[5].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_6_PORT", data(PhyData[6].Port), 0},
{"SAS_IO_UNIT1_PHY_6_PORT_FLGS", data(PhyData[6].PortFlags), 0},
{"SAS_IO_UNIT1_PHY_6_PHY_FLGS", data(PhyData[6].PhyFlags), 0},
{"SAS_IO_UNIT1_PHY_6_MIN_MAX_LINK_RATE", data(PhyData[6].MaxMinLinkRate), 0},
{"SAS_IO_UNIT1_PHY_6_CNTLR_PHY_DEV_INFO", data(PhyData[6].ControllerPhyDeviceInfo), 0},
{"SAS_IO_UNIT1_PHY_6_MAX_TARG_PORT_CONN_TIME", data(PhyData[6].MaxTargetPortConnectTime), 0},
{"SAS_IO_UNIT1_PHY_6_RESERVED1", data(PhyData[6].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_7_PORT", data(PhyData[7].Port), 0},
{"SAS_IO_UNIT1_PHY_7_PORT_FLGS", data(PhyData[7].PortFlags), 0},
{"SAS_IO_UNIT1_PHY_7_PHY_FLGS", data(PhyData[7].PhyFlags), 0},
{"SAS_IO_UNIT1_PHY_7_MIN_MAX_LINK_RATE", data(PhyData[7].MaxMinLinkRate), 0},
{"SAS_IO_UNIT1_PHY_7_CNTLR_PHY_DEV_INFO", data(PhyData[7].ControllerPhyDeviceInfo), 0},
{"SAS_IO_UNIT1_PHY_7_MAX_TARG_PORT_CONN_TIME", data(PhyData[7].MaxTargetPortConnectTime), 0},
{"SAS_IO_UNIT1_PHY_7_RESERVED1", data(PhyData[7].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_8_PORT", data(PhyData[8].Port), 0},
{"SAS_IO_UNIT1_PHY_8_PORT_FLGS", data(PhyData[8].PortFlags), 0},
{"SAS_IO_UNIT1_PHY_8_PHY_FLGS", data(PhyData[8].PhyFlags), 0},
{"SAS_IO_UNIT1_PHY_8_MIN_MAX_LINK_RATE", data(PhyData[8].MaxMinLinkRate), 0},
{"SAS_IO_UNIT1_PHY_8_CNTLR_PHY_DEV_INFO", data(PhyData[8].ControllerPhyDeviceInfo), 0},
{"SAS_IO_UNIT1_PHY_8_MAX_TARG_PORT_CONN_TIME", data(PhyData[8].MaxTargetPortConnectTime), 0},
{"SAS_IO_UNIT1_PHY_8_RESERVED1", data(PhyData[8].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_9_PORT", data(PhyData[9].Port), 0},
{"SAS_IO_UNIT1_PHY_9_PORT_FLGS", data(PhyData[9].PortFlags), 0},
{"SAS_IO_UNIT1_PHY_9_PHY_FLGS", data(PhyData[9].PhyFlags), 0},
{"SAS_IO_UNIT1_PHY_9_MIN_MAX_LINK_RATE", data(PhyData[9].MaxMinLinkRate), 0},
{"SAS_IO_UNIT1_PHY_9_CNTLR_PHY_DEV_INFO", data(PhyData[9].ControllerPhyDeviceInfo), 0},
{"SAS_IO_UNIT1_PHY_9_MAX_TARG_PORT_CONN_TIME", data(PhyData[9].MaxTargetPortConnectTime), 0},
{"SAS_IO_UNIT1_PHY_9_RESERVED1", data(PhyData[9].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_10_PORT", data(PhyData[10].Port), 0},
{"SAS_IO_UNIT1_PHY_10_PORT_FLGS", data(PhyData[10].PortFlags), 0},
{"SAS_IO_UNIT1_PHY_10_PHY_FLGS", data(PhyData[10].PhyFlags), 0},
{"SAS_IO_UNIT1_PHY_10_MIN_MAX_LINK_RATE", data(PhyData[10].MaxMinLinkRate), 0},
{"SAS_IO_UNIT1_PHY_10_CNTLR_PHY_DEV_INFO", data(PhyData[10].ControllerPhyDeviceInfo), 0},
{"SAS_IO_UNIT1_PHY_10_MAX_TARG_PORT_CONN_TIME", data(PhyData[10].MaxTargetPortConnectTime), 0},
{"SAS_IO_UNIT1_PHY_10_RESERVED1", data(PhyData[10].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_11_PORT", data(PhyData[11].Port), 0},
{"SAS_IO_UNIT1_PHY_11_PORT_FLGS", data(PhyData[11].PortFlags), 0},
{"SAS_IO_UNIT1_PHY_11_PHY_FLGS", data(PhyData[11].PhyFlags), 0},
{"SAS_IO_UNIT1_PHY_11_MIN_MAX_LINK_RATE", data(PhyData[11].MaxMinLinkRate), 0},
{"SAS_IO_UNIT1_PHY_11_CNTLR_PHY_DEV_INFO", data(PhyData[11].ControllerPhyDeviceInfo), 0},
{"SAS_IO_UNIT1_PHY_11_MAX_TARG_PORT_CONN_TIME", data(PhyData[11].MaxTargetPortConnectTime), 0},
{"SAS_IO_UNIT1_PHY_11_RESERVED1", data(PhyData[11].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_12_PORT", data(PhyData[12].Port), 0},
{"SAS_IO_UNIT1_PHY_12_PORT_FLGS", data(PhyData[12].PortFlags), 0},
{"SAS_IO_UNIT1_PHY_12_PHY_FLGS", data(PhyData[12].PhyFlags), 0},
{"SAS_IO_UNIT1_PHY_12_MIN_MAX_LINK_RATE", data(PhyData[12].MaxMinLinkRate), 0},
{"SAS_IO_UNIT1_PHY_12_CNTLR_PHY_DEV_INFO", data(PhyData[12].ControllerPhyDeviceInfo), 0},
{"SAS_IO_UNIT1_PHY_12_MAX_TARG_PORT_CONN_TIME", data(PhyData[12].MaxTargetPortConnectTime), 0},
{"SAS_IO_UNIT1_PHY_12_RESERVED1", data(PhyData[12].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_13_PORT", data(PhyData[13].Port), 0},
{"SAS_IO_UNIT1_PHY_13_PORT_FLGS", data(PhyData[13].PortFlags), 0},
{"SAS_IO_UNIT1_PHY_13_PHY_FLGS", data(PhyData[13].PhyFlags), 0},
{"SAS_IO_UNIT1_PHY_13_MIN_MAX_LINK_RATE", data(PhyData[13].MaxMinLinkRate), 0},
{"SAS_IO_UNIT1_PHY_13_CNTLR_PHY_DEV_INFO", data(PhyData[13].ControllerPhyDeviceInfo), 0},
{"SAS_IO_UNIT1_PHY_13_MAX_TARG_PORT_CONN_TIME", data(PhyData[13].MaxTargetPortConnectTime), 0},
{"SAS_IO_UNIT1_PHY_13_RESERVED1", data(PhyData[13].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_14_PORT", data(PhyData[14].Port), 0},
{"SAS_IO_UNIT1_PHY_14_PORT_FLGS", data(PhyData[14].PortFlags), 0},
{"SAS_IO_UNIT1_PHY_14_PHY_FLGS", data(PhyData[14].PhyFlags), 0},
{"SAS_IO_UNIT1_PHY_14_MIN_MAX_LINK_RATE", data(PhyData[14].MaxMinLinkRate), 0},
{"SAS_IO_UNIT1_PHY_14_CNTLR_PHY_DEV_INFO", data(PhyData[14].ControllerPhyDeviceInfo), 0},
{"SAS_IO_UNIT1_PHY_14_MAX_TARG_PORT_CONN_TIME", data(PhyData[14].MaxTargetPortConnectTime), 0},
{"SAS_IO_UNIT1_PHY_14_RESERVED1", data(PhyData[14].Reserved1), OPT},
{"SAS_IO_UNIT1_PHY_15_PORT", data(PhyData[15].Port), 0},
{"SAS_IO_UNIT1_PHY_15_PORT_FLGS", data(PhyData[15].PortFlags), 0},
{"SAS_IO_UNIT1_PHY_15_PHY_FLGS", data(PhyData[15].PhyFlags), 0},
{"SAS_IO_UNIT1_PHY_15_MIN_MAX_LINK_RATE", data(PhyData[15].MaxMinLinkRate), 0},
{"SAS_IO_UNIT1_PHY_15_CNTLR_PHY_DEV_INFO", data(PhyData[15].ControllerPhyDeviceInfo), 0},
{"SAS_IO_UNIT1_PHY_15_MAX_TARG_PORT_CONN_TIME", data(PhyData[15].MaxTargetPortConnectTime), 0},
{"SAS_IO_UNIT1_PHY_15_RESERVED1", data(PhyData[15].Reserved1), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pSasIOUnitPage2_t)0)->x, sizeof(((pSasIOUnitPage2_t)0)->x)
ITEM sas_io_unit_page_2_items[] =
{
{"SAS2_NUMDEVICESPERENCLOSURE", data(NumDevsPerEnclosure), 0},
{"MAX_PERSIST_IDS", data(MaxPersistentIDs), 0},
{"MAX_PERSIST_IDS_USED", data(NumPersistentIDsUsed), 0},
{"STATUS", data(Status), 0},
{"FLAGS", data(Flags), 0},
{"SAS2_MAXNUMPHYMAPPEDID", data(MaxNumPhysicalMappedIDs), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pSasIOUnitPage3_t)0)->x, sizeof(((pSasIOUnitPage3_t)0)->x)
ITEM sas_io_unit_page_3_items[] =
{
{"RESERVED1", data(Reserved1), OPT},
{"MAX_INVALID_DWRD_CNT", data(MaxInvalidDwordCount), 0},
{"INVALID_DWRD_CNT_TIME", data(InvalidDwordCountTime), 0},
{"MAX_RUNNING_DISPARE_ERR_CNT", data(MaxRunningDisparityErrorCount), 0},
{"RUNNING_DISPARE_ERR_TIME", data(RunningDisparityErrorTime), 0},
{"MAX_LOSS_DWRD_SYNC_CNT", data(MaxLossDwordSynchCount), 0},
{"LOSS_DWRD_SYNC_CNT_TIME", data(LossDwordSynchCountTime), 0},
{"MAX_PHY_RESET_PROB_CNT", data(MaxPhyResetProblemCount), 0},
{"PHY_RESET_PROB_TIME", data(PhyResetProblemTime), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pMpi2SasIOUnitPage4_t)0)->x, sizeof(((pMpi2SasIOUnitPage4_t)0)->x)
ITEM sas_io_unit_page_4_items2[] =
{
{"GROUP0_MAX_TARGET_SPINUP", data(SpinupGroupParameters[0].MaxTargetSpinup), 0},
{"GROUP0_SPINUP_DELAY", data(SpinupGroupParameters[0].SpinupDelay), 0},
{"GROUP0_RESERVED1", data(SpinupGroupParameters[0].Reserved1), OPT},
{"GROUP1_MAX_TARGET_SPINUP", data(SpinupGroupParameters[1].MaxTargetSpinup), 0},
{"GROUP1_SPINUP_DELAY", data(SpinupGroupParameters[1].SpinupDelay), 0},
{"GROUP1_RESERVED1", data(SpinupGroupParameters[1].Reserved1), OPT},
{"GROUP2_MAX_TARGET_SPINUP", data(SpinupGroupParameters[2].MaxTargetSpinup), 0},
{"GROUP2_SPINUP_DELAY", data(SpinupGroupParameters[2].SpinupDelay), 0},
{"GROUP2_RESERVED1", data(SpinupGroupParameters[2].Reserved1), OPT},
{"GROUP3_MAX_TARGET_SPINUP", data(SpinupGroupParameters[3].MaxTargetSpinup), 0},
{"GROUP3_SPINUP_DELAY", data(SpinupGroupParameters[3].SpinupDelay), 0},
{"GROUP3_RESERVED1", data(SpinupGroupParameters[3].Reserved1), OPT},
{"RESERVED1", data(Reserved1), OPT},
{"RESERVED2", data(Reserved2), OPT},
{"RESERVED3", data(Reserved3), OPT},
{"RESERVED4", data(Reserved4), OPT},
{"NUM_PHYS", data(NumPhys), 0},
{"PE_INIT_SPINUP_DELAY", data(PEInitialSpinupDelay), 0},
{"PE_REPLY_DELAY", data(PEReplyDelay), 0},
{"FLAGS", data(Flags), 0},
{"PHY_0", data(PHY[0]), 0},
{"PHY_1", data(PHY[1]), 0},
{"PHY_2", data(PHY[2]), 0},
{"PHY_3", data(PHY[3]), 0},
{"PHY_4", data(PHY[4]), 0},
{"PHY_5", data(PHY[5]), 0},
{"PHY_6", data(PHY[6]), 0},
{"PHY_7", data(PHY[7]), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pSasExpanderPage0_t)0)->x, sizeof(((pSasExpanderPage0_t)0)->x)
ITEM sas_expander_page_0_items[] =
{
{"SAS_EXP0_PHYSICALPORT", data(PhysicalPort), 0},
{"SAS_EXP0_ENCLOSUREHANDLE", data(EnclosureHandle), 0},
{"SASADRSHIGH", data(SASAddress.High), 0},
{"SASADRSLOW", data(SASAddress.Low), 0},
{"SAS_EXP0_DISCOVERYSTATUS", data(DiscoveryStatus), 0},
{"DEVHNDL", data(DevHandle), 0},
{"PARENTDEVHNDL", data(ParentDevHandle), 0},
{"EXPNDRCHGCNT", data(ExpanderChangeCount), 0},
{"EXPNDRROUTEINDX", data(ExpanderRouteIndexes), 0},
{"NUMPHYS", data(NumPhys), 0},
{"SASLEVEL", data(SASLevel), 0},
{"FLAGS", data(Flags), 0},
{"DISCOVERYSTATUS", data(Reserved3), OPT},
{"RESERVED3", data(Reserved3), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pSasExpanderPage1_t)0)->x, sizeof(((pSasExpanderPage1_t)0)->x)
ITEM sas_expander_page_1_items[] =
{
{"SAS_EXP1_PHYSICALPORT", data(PhysicalPort), 0},
{"NUMPHYS", data(NumPhys), 0},
{"PHY", data(Phy), 0},
{"SAS_EXP1_NUMTBLENTRIESPROG", data(NumTableEntriesProgrammed), 0},
{"PROGLINKRATE", data(ProgrammedLinkRate), 0},
{"HWLINKRATE", data(HwLinkRate), 0},
{"ATTCHDDEVHANDLE", data(AttachedDevHandle), 0},
{"PHYINFO", data(PhyInfo), 0},
{"ATTCHDDEVINFO", data(AttachedDeviceInfo), 0},
{"OWNERDEVHNDL", data(OwnerDevHandle), 0},
{"CHGCNT", data(ChangeCount), 0},
{"NEGLNKRATE", data(NegotiatedLinkRate), 0},
{"PHYIDENTIFIER", data(PhyIdentifier), 0},
{"ATTCHDPHYIDENT", data(AttachedPhyIdentifier), 0},
{"RESERVED3", data(Reserved3), OPT},
{"DISCOVERYInfo", data(DiscoveryInfo), DUP},
{"DISCOVERYINFO", data(DiscoveryInfo), 0},
{"RESERVED4", data(Reserved4), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pSasDevicePage0_t)0)->x, sizeof(((pSasDevicePage0_t)0)->x)
ITEM sas_device_page_0_items[] =
{
{"SLOT", data(Slot), 0},
{"ENCLOSURE_HANDLE", data(EnclosureHandle), 0},
{"SASADRSHIGH", data(SASAddress.High), 0},
{"SASADRSLOW", data(SASAddress.Low), 0},
{"SAS_DEV0_PARENTDEVHANDLE", data(ParentDevHandle), 0},
{"SAS_DEV0_PHYNUM", data(PhyNum), 0},
{"SAS_DEV0_ACCESSSTATUS", data(AccessStatus), 0},
{"DEVHNDL", data(DevHandle), 0},
{"TARGETID", data(TargetID), 0},
{"BUS", data(Bus), 0},
{"DEVICEINFO", data(DeviceInfo), 0},
{"FLAGS", data(Flags), 0},
{"RESERVED2", data(Reserved2), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pSasDevicePage1_t)0)->x, sizeof(((pSasDevicePage1_t)0)->x)
ITEM sas_device_page_1_items[] =
{
{"RESERVED1", data(Reserved1), OPT},
{"SASADRSHIGH", data(SASAddress.High), 0},
{"SASADRSLOW", data(SASAddress.Low), 0},
{"RESERVED2", data(Reserved2), OPT},
{"DEVHNDL", data(DevHandle), 0},
{"TARGETID", data(TargetID), 0},
{"BUS", data(Bus), 0},
{"INITREGDEVICEFIS", data(InitialRegDeviceFIS), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pSasDevicePage2_t)0)->x, sizeof(((pSasDevicePage2_t)0)->x)
ITEM sas_device_page_2_items[] =
{
{"SAS_DEV2_PHYSICALIDHIGH", data(PhysicalIdentifier.High), 0},
{"SAS_DEV2_PHYSICALIDLOW", data(PhysicalIdentifier.Low), 0},
{"SAS_DEV2_ENCLOSURE_MAPPING", data(EnclosureMapping), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pSasPhyPage0_t)0)->x, sizeof(((pSasPhyPage0_t)0)->x)
ITEM sas_phy_page_0_items[] =
{
{"SAS_PHY0_OWNER_DEV_HANDLE", data(OwnerDevHandle), 0},
{"RESERVED1", data(Reserved1), OPT},
{"SASADRSHIGH", data(SASAddress.High), 0},
{"SASADRSLOW", data(SASAddress.Low), 0},
{"ATTCHDDEVHNDL", data(AttachedDevHandle), 0},
{"ATTCHDPHYIDENTIFIER", data(AttachedPhyIdentifier), 0},
{"RESERVED2", data(Reserved2), OPT},
{"ATTCHDDEVINFO", data(AttachedDeviceInfo), 0},
{"PRGMDLINKRATE", data(ProgrammedLinkRate), 0},
{"HWLINKRATE", data(HwLinkRate), 0},
{"CHNGCOUNT", data(ChangeCount), 0},
{"SAS_PHY0_FLAGS", data(Flags), 0},
{"PHYINFO", data(PhyInfo), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pSasPhyPage1_t)0)->x, sizeof(((pSasPhyPage1_t)0)->x)
ITEM sas_phy_page_1_items[] =
{
{"RESERVED1", data(Reserved1), OPT},
{"INVALIDDWRDCNT", data(InvalidDwordCount), 0},
{"RUNNGDISPARITYERRCNT", data(RunningDisparityErrorCount), 0},
{"LOSSDWRDSYNCCNT", data(LossDwordSynchCount), 0},
{"PHYRESETPROBCNT", data(PhyResetProblemCount), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pSasEnclosurePage0_t)0)->x, sizeof(((pSasEnclosurePage0_t)0)->x)
ITEM sas_enclosure_page_0_items[] =
{
{"RESERVED1", data(Reserved1), OPT},
{"ENCLOSURELOGICALID_HIGH", data(EnclosureLogicalID.High), 0},
{"ENCLOSURELOGICALID_LOW", data(EnclosureLogicalID.Low), 0},
{"FLAGS", data(Flags), 0},
{"ENCLOSUREHANDLE", data(EnclosureHandle), 0},
{"NUMSLOTS", data(NumSlots), 0},
{"STARTSLOT", data(StartSlot), 0},
{"STARTTARGETID", data(StartTargetID), 0},
{"STARTBUS", data(StartBus), 0},
{"SEPTARGETID", data(SEPTargetID), 0},
{"SEPBUS", data(SEPBus), 0},
{"RESERVED2", data(Reserved2), OPT},
{"RESERVED3", data(Reserved3), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pPersistentId_SAS_t)0)->x, sizeof(((pPersistentId_SAS_t)0)->x)
ITEM sas_persistent_id_items[] =
{
{"PERSISTID_SASADDRESS_HIGH_0", data(PersistId[0].SasAddress.Word.High), 0},
{"PERSISTID_SASADDRESS_LOW_0", data(PersistId[0].SasAddress.Word.Low), 0},
{"PERSISTID_RESERVED_0", data(PersistId[0].Reserved), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pRaidVolumePage0_t)0)->x, sizeof(((pRaidVolumePage0_t)0)->x)
ITEM raid_volume_page_0_items[] =
{
{"ALL", sizeof(ConfigPageHeader_t), sizeof(RaidVolumePage0_t) - sizeof(ConfigPageHeader_t), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pRaidVolumePage1_t)0)->x, sizeof(((pRaidVolumePage1_t)0)->x)
ITEM raid_volume_page_1_items[] =
{
{"RAIDVOL1_VOLUMEID", data(VolumeID), 0},
{"RAIDVOL1_VOLUMEBUS", data(VolumeBus), 0},
{"RAIDVOL1_VOLUMEIOC", data(VolumeIOC), 0},
{"RAIDVOL1_WWID_HIGH", data(WWID.High), 0},
{"RAIDVOL1_WWID_LOW", data(WWID.Low), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pRaidPhysDiskPage0_t)0)->x, sizeof(((pRaidPhysDiskPage0_t)0)->x)
ITEM raid_physdisk_page_0_items[] =
{
{"ALL", sizeof(ConfigPageHeader_t), sizeof(RaidPhysDiskPage0_t) - sizeof(ConfigPageHeader_t), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pRaidPhysDiskPage1_t)0)->x, sizeof(((pRaidPhysDiskPage1_t)0)->x)
ITEM raid_physdisk_page_1_items[] =
{
{"RAIDPHYDISK1_NUMPHYSDISKPATH", data(NumPhysDiskPaths), 0},
{"RAIDPHYDISK1_PHYSDISKNUM", data(PhysDiskNum), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pBIOSPage1_t)0)->x, sizeof(((pBIOSPage1_t)0)->x)
ITEM bios_page_1_items[] =
{
{"BIOSOPTIONS", data(BiosOptions), 0},
{"IOCSETTINGS", data(IOCSettings), 0},
{"BIOS_RESERVED1", data(Reserved1), OPT},
{"RESERVED1", data(Reserved1), OPT},
{"DEVSETTINGS", data(DeviceSettings), 0},
{"BIOS_NUMDEVS", data(NumberOfDevices), 0},
{"BIOS1_EXPANDERSPINUP", data(ExpanderSpinup), MPI1},
{"RESERVED2", data(Reserved2), OPT},
{"IOTIMOUTBLKDEVSNONRM", data(IOTimeoutBlockDevicesNonRM), 0},
{"IOTIMOUTSEQUENTIAL", data(IOTimeoutSequential), 0},
{"IOTIMOUTOTHER", data(IOTimeoutOther), 0},
{"IOTIMOUTBLKDEVSRM", data(IOTimeoutBlockDevicesRM), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pBIOSPage2_t)0)->x, sizeof(((pBIOSPage2_t)0)->x)
ITEM bios_page_2_items[] =
{
{"RESERVED1", data(Reserved1), OPT},
{"RESERVED2", data(Reserved2), OPT},
{"RESERVED3", data(Reserved3), OPT},
{"RESERVED4", data(Reserved4), OPT},
{"RESERVED5", data(Reserved5), OPT},
{"RESERVED6", data(Reserved6), OPT},
{"BIOS2_BOOTDEVICEFORM", data(BootDeviceForm), 0},
{"BIOS2_PREVBOOTDEVFORM", data(PrevBootDeviceForm), 0},
{"RESERVED8", data(Reserved8), OPT},
{"BIOS2_SASADDRESS_HIGH", data(BootDevice.SasWwn.SASAddress.High), 0},
{"BIOS2_SASADDRESS_LOW", data(BootDevice.SasWwn.SASAddress.Low), 0},
{"BIOS2_SASADDRESS_LUN", data(BootDevice.SasWwn.LUN[1]), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pMpi2BiosPage2_t)0)->x, sizeof(((pMpi2BiosPage2_t)0)->x)
ITEM bios_page_2_items2[] =
{
{"RESERVED1", data(Reserved1), OPT},
{"RESERVED2", data(Reserved2), OPT},
{"RESERVED3", data(Reserved3), OPT},
{"RESERVED4", data(Reserved4), OPT},
{"RESERVED5", data(Reserved5), OPT},
{"RESERVED6", data(Reserved6), OPT},
{"REQ_BOOTDEVICEFORM", data(ReqBootDeviceForm), 0},
{"RESERVED7", data(Reserved7), OPT},
{"RESERVED8", data(Reserved8), OPT},
{"REQ_SASADDRESS_LOW", data(RequestedBootDevice.SasWwid.SASAddress.Low), IGN},
{"REQ_SASADDRESS_HI", data(RequestedBootDevice.SasWwid.SASAddress.High), IGN},
{"REQ_SASADDRESS_LUN", data(RequestedBootDevice.SasWwid.LUN[1]), IGN},
{"REQ_DEVICENAME_LOW", data(RequestedBootDevice.DeviceName.DeviceName.Low), IGN},
{"REQ_DEVICENAME_HI", data(RequestedBootDevice.DeviceName.DeviceName.High), IGN},
{"REQ_DEVICENAME_LUN", data(RequestedBootDevice.DeviceName.LUN[1]), IGN},
{"REQ_ENCLOSUREID_LOW", data(RequestedBootDevice.EnclosureSlot.EnclosureLogicalID.Low), IGN},
{"REQ_ENCLOSUREID_HI", data(RequestedBootDevice.EnclosureSlot.EnclosureLogicalID.High), IGN},
{"REQ_SLOTNUMBER", data(RequestedBootDevice.EnclosureSlot.SlotNumber), IGN},
{"REQALT_BOOTDEVICEFORM", data(ReqAltBootDeviceForm), 0},
{"RESERVED9", data(Reserved9), OPT},
{"RESERVED10", data(Reserved10), OPT},
{"REQALT_SASADDRESS_LOW", data(RequestedAltBootDevice.SasWwid.SASAddress.Low), IGN},
{"REQALT_SASADDRESS_HI", data(RequestedAltBootDevice.SasWwid.SASAddress.High), IGN},
{"REQALT_SASADDRESS_LUN", data(RequestedAltBootDevice.SasWwid.LUN[1]), IGN},
{"REQALT_DEVICENAME_LOW", data(RequestedAltBootDevice.DeviceName.DeviceName.Low), IGN},
{"REQALT_DEVICENAME_HI", data(RequestedAltBootDevice.DeviceName.DeviceName.High), IGN},
{"REQALT_DEVICENAME_LUN", data(RequestedAltBootDevice.DeviceName.LUN[1]), IGN},
{"REQALT_ENCLOSUREID_LOW", data(RequestedAltBootDevice.EnclosureSlot.EnclosureLogicalID.Low), IGN},
{"REQALT_ENCLOSUREID_HI", data(RequestedAltBootDevice.EnclosureSlot.EnclosureLogicalID.High), IGN},
{"REQALT_SLOTNUMBER", data(RequestedAltBootDevice.EnclosureSlot.SlotNumber), IGN},
{"CURR_BOOTDEVICEFORM", data(CurrentBootDeviceForm), 0},
{"RESERVED11", data(Reserved11), OPT},
{"RESERVED12", data(Reserved12), OPT},
{"CURR_SASADDRESS_LOW", data(CurrentBootDevice.SasWwid.SASAddress.Low), IGN},
{"CURR_SASADDRESS_HI", data(CurrentBootDevice.SasWwid.SASAddress.High), IGN},
{"CURR_SASADDRESS_LUN", data(CurrentBootDevice.SasWwid.LUN[1]), IGN},
{"CURR_DEVICENAME_LOW", data(CurrentBootDevice.DeviceName.DeviceName.Low), IGN},
{"CURR_DEVICENAME_HI", data(CurrentBootDevice.DeviceName.DeviceName.High), IGN},
{"CURR_DEVICENAME_LUN", data(CurrentBootDevice.DeviceName.LUN[1]), IGN},
{"CURR_ENCLOSUREID_LOW", data(CurrentBootDevice.EnclosureSlot.EnclosureLogicalID.Low), IGN},
{"CURR_ENCLOSUREID_HI", data(CurrentBootDevice.EnclosureSlot.EnclosureLogicalID.High), IGN},
{"CURR_SLOTNUMBER", data(CurrentBootDevice.EnclosureSlot.SlotNumber), IGN},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pMpi2BiosPage3_t)0)->x, sizeof(((pMpi2BiosPage3_t)0)->x)
ITEM bios_page_3_items2[] =
{
{"GLOBAL_FLAGS", data(GlobalFlags), 0},
{"BIOS_VERSION", data(BiosVersion), 0},
{"PCI_BUS_NUMBER_0", data(AdapterOrder[0].PciBusNumber), 0},
{"PCI_DEVICE_FUNCTION_0", data(AdapterOrder[0].PciDeviceAndFunctionNumber), 0},
{"ADAPTER_FLAGS_0", data(AdapterOrder[0].AdapterFlags), 0},
{"PCI_BUS_NUMBER_1", data(AdapterOrder[1].PciBusNumber), OPT},
{"PCI_DEVICE_FUNCTION_1", data(AdapterOrder[1].PciDeviceAndFunctionNumber), OPT},
{"ADAPTER_FLAGS_1", data(AdapterOrder[1].AdapterFlags), OPT},
{"PCI_BUS_NUMBER_2", data(AdapterOrder[2].PciBusNumber), OPT},
{"PCI_DEVICE_FUNCTION_2", data(AdapterOrder[2].PciDeviceAndFunctionNumber), OPT},
{"ADAPTER_FLAGS_2", data(AdapterOrder[2].AdapterFlags), OPT},
{"PCI_BUS_NUMBER_3", data(AdapterOrder[3].PciBusNumber), OPT},
{"PCI_DEVICE_FUNCTION_3", data(AdapterOrder[3].PciDeviceAndFunctionNumber), OPT},
{"ADAPTER_FLAGS_3", data(AdapterOrder[3].AdapterFlags), OPT},
{"RESERVED1", data(Reserved1), OPT},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pBIOSPage4_t)0)->x, sizeof(((pBIOSPage4_t)0)->x)
ITEM bios_page_4_items[] =
{
{"BIOS4_REASSIGNMENTBASEWWID_HIGH", data(ReassignmentBaseWWID.High), 0},
{"BIOS4_REASSIGNMENTBASEWWID_LOW", data(ReassignmentBaseWWID.Low), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pMpi2BiosPage4_t)0)->x, sizeof(((pMpi2BiosPage4_t)0)->x)
ITEM bios_page_4_items2[] =
{
{"NUM_PHYS", data(NumPhys), 0},
{"RESERVED1", data(Reserved1), OPT},
{"RESERVED2", data(Reserved2), OPT},
{"REASSIGN_WWID_LOW_0", data(Phy[0].ReassignmentWWID.Low), 0},
{"REASSIGN_WWID_HIGH_0", data(Phy[0].ReassignmentWWID.High), 0},
{"REASSIGN_DEVNAME_LOW_0", data(Phy[0].ReassignmentDeviceName.Low), 0},
{"REASSIGN_DEVNAME_HIGH_0", data(Phy[0].ReassignmentDeviceName.High), 0},
{"REASSIGN_WWID_LOW_1", data(Phy[1].ReassignmentWWID.Low), 0},
{"REASSIGN_WWID_HIGH_1", data(Phy[1].ReassignmentWWID.High), 0},
{"REASSIGN_DEVNAME_LOW_1", data(Phy[1].ReassignmentDeviceName.Low), 0},
{"REASSIGN_DEVNAME_HIGH_1", data(Phy[1].ReassignmentDeviceName.High), 0},
{"REASSIGN_WWID_LOW_2", data(Phy[2].ReassignmentWWID.Low), 0},
{"REASSIGN_WWID_HIGH_2", data(Phy[2].ReassignmentWWID.High), 0},
{"REASSIGN_DEVNAME_LOW_2", data(Phy[2].ReassignmentDeviceName.Low), 0},
{"REASSIGN_DEVNAME_HIGH_2", data(Phy[2].ReassignmentDeviceName.High), 0},
{"REASSIGN_WWID_LOW_3", data(Phy[3].ReassignmentWWID.Low), 0},
{"REASSIGN_WWID_HIGH_3", data(Phy[3].ReassignmentWWID.High), 0},
{"REASSIGN_DEVNAME_LOW_3", data(Phy[3].ReassignmentDeviceName.Low), 0},
{"REASSIGN_DEVNAME_HIGH_3", data(Phy[3].ReassignmentDeviceName.High), 0},
{"REASSIGN_WWID_LOW_4", data(Phy[4].ReassignmentWWID.Low), 0},
{"REASSIGN_WWID_HIGH_4", data(Phy[4].ReassignmentWWID.High), 0},
{"REASSIGN_DEVNAME_LOW_4", data(Phy[4].ReassignmentDeviceName.Low), 0},
{"REASSIGN_DEVNAME_HIGH_4", data(Phy[4].ReassignmentDeviceName.High), 0},
{"REASSIGN_WWID_LOW_5", data(Phy[5].ReassignmentWWID.Low), 0},
{"REASSIGN_WWID_HIGH_5", data(Phy[5].ReassignmentWWID.High), 0},
{"REASSIGN_DEVNAME_LOW_5", data(Phy[5].ReassignmentDeviceName.Low), 0},
{"REASSIGN_DEVNAME_HIGH_5", data(Phy[5].ReassignmentDeviceName.High), 0},
{"REASSIGN_WWID_LOW_6", data(Phy[6].ReassignmentWWID.Low), 0},
{"REASSIGN_WWID_HIGH_6", data(Phy[6].ReassignmentWWID.High), 0},
{"REASSIGN_DEVNAME_LOW_6", data(Phy[6].ReassignmentDeviceName.Low), 0},
{"REASSIGN_DEVNAME_HIGH_6", data(Phy[6].ReassignmentDeviceName.High), 0},
{"REASSIGN_WWID_LOW_7", data(Phy[7].ReassignmentWWID.Low), 0},
{"REASSIGN_WWID_HIGH_7", data(Phy[7].ReassignmentWWID.High), 0},
{"REASSIGN_DEVNAME_LOW_7", data(Phy[7].ReassignmentDeviceName.Low), 0},
{"REASSIGN_DEVNAME_HIGH_7", data(Phy[7].ReassignmentDeviceName.High), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pLogPage0_t)0)->x, sizeof(((pLogPage0_t)0)->x)
ITEM log_page_0_items[] =
{
{"ALL", sizeof(ConfigExtendedPageHeader_t), sizeof(LogPage0_t) - sizeof(ConfigExtendedPageHeader_t), 0},
{0}
};
#undef data
#define data(x) (int)(size_t)&((pMpi2DriverMappingPage0_t)0)->x, sizeof(((pMpi2DriverMappingPage0_t)0)->x)
ITEM driver_mapping_page_0_items2[] =
{
{"PHYSICAL_IDENTIFIER_LOW", data(Entry.PhysicalIdentifier.Low), 0},
{"PHYSICAL_IDENTIFIER_HIGH", data(Entry.PhysicalIdentifier.High), 0},
{"MAPPING_INFORMATION", data(Entry.MappingInformation), 0},
{"DEVICE_INDEX", data(Entry.DeviceIndex), 0},
{"PHYSICAL_BITS_MAPPING", data(Entry.PhysicalBitsMapping), 0},
{"RESERVED1", data(Entry.Reserved1), OPT},
{0}
};
#undef data
#define data(x) sizeof(x)
#define plus(x,y,z) data(x) + sizeof(((p##x)0)->y) * z
SECTION sections[] =
{
{"SECTION_GENERAL_DATA", general_data_items, data(GeneralData_t), GEN},
{"SECTION_MANUFACTURING_PAGE_0", manufacturing_page_0_items, data(ManufacturingPage0_t), 0},
{"SECTION_MANUFACTURING_PAGE_1", manufacturing_page_1_items, data(ManufacturingPage1_t), 0},
{"SECTION_IOC_MFG_PAGE_2", manufacturing_page_2_items, data(ManufacturingPage2_SAS_t), MP2},
{"SECTION_IOC_MFG_PAGE_3", manufacturing_page_3_items, data(ManufacturingPage3_SAS_t), 0},
{"SECTION_MANUFACTURING_PAGE_4", manufacturing_page_4_items, data(ManufacturingPage4_t), 0},
{"SECTION_MANUFACTURING_PAGE_5", manufacturing_page_5_items, plus(ManufacturingPage5_t, ForceWWID, 7), 0},
{"SECTION_MANUFACTURING_PAGE_7", manufacturing_page_7_items, plus(ManufacturingPage7_t, ConnectorInfo, 7), 0},
{"SECTION_IO_UNIT_PAGE_0", io_unit_page_0_items, data(IOUnitPage0_t), 0},
{"SECTION_IO_UNIT_PAGE_1", io_unit_page_1_items, data(IOUnitPage1_t), 0},
{"SECTION_IO_UNIT_PAGE_2", io_unit_page_2_items, data(IOUnitPage2_t), 0},
{"SECTION_IO_UNIT_PAGE_3", io_unit_page_3_items, plus(IOUnitPage3_t, GPIOVal, 31), 0},
{"SECTION_IO_UNIT_PAGE_4", io_unit_page_4_items, data(IOUnitPage4_t), 0},
{"SECTION_IOC_PAGE_0", ioc_page_0_items, data(IOCPage0_t), 0},
{"SECTION_IOC_PAGE_1", ioc_page_1_items, data(IOCPage1_t), 0},
{"SECTION_IOC_PAGE_2", ioc_page_2_items, data(IOCPage2_t), 0},
{"SECTION_IOC_PAGE_3", ioc_page_3_items, data(IOCPage3_t), 0},
{"SECTION_IOC_PAGE_4", ioc_page_4_items, data(IOCPage4_t), 0},
{"SECTION_IOC_PAGE_5", ioc_page_5_items, data(IOCPage5_t), 0},
{"SECTION_IOC_PAGE_6", ioc_page_6_items, data(IOCPage6_t), 0},
{"SECTION_SAS_IO_UNIT_0", sas_io_unit_page_0_items, plus(SasIOUnitPage0_t, PhyData, 7), EXT},
{"SECTION_SAS_IO_UNIT_1", sas_io_unit_page_1_items, plus(SasIOUnitPage1_t, PhyData, 7), EXT},
{"SECTION_SAS_IO_UNIT_2", sas_io_unit_page_2_items, data(SasIOUnitPage2_t), EXT},
{"SECTION_SAS_IO_UNIT_3", sas_io_unit_page_3_items, data(SasIOUnitPage3_t), EXT},
{"SECTION_SAS_EXPANDER_0", sas_expander_page_0_items, data(SasExpanderPage0_t), EXT},
{"SECTION_SAS_EXPANDER_1", sas_expander_page_1_items, data(SasExpanderPage1_t), EXT},
{"SECTION_SAS_DEVICE_0", sas_device_page_0_items, data(SasDevicePage0_t), EXT},
{"SECTION_SAS_DEVICE_1", sas_device_page_1_items, data(SasDevicePage1_t), EXT},
{"SECTION_SAS_DEVICE_2", sas_device_page_2_items, data(SasDevicePage2_t), EXT},
{"SECTION_SAS_PHY_0", sas_phy_page_0_items, data(SasPhyPage0_t), EXT},
{"SECTION_SAS_PHY_1", sas_phy_page_1_items, data(SasPhyPage1_t), EXT},
{"SECTION_SAS_ENCLOSURE_0", sas_enclosure_page_0_items, data(SasEnclosurePage0_t), EXT},
{"SECTION_PERSISTENT_ID", sas_persistent_id_items, data(PersistentId_SAS_t), EXT | PID},
{"SECTION_RAID_VOL_PAGE_0", raid_volume_page_0_items, data(RaidVolumePage0_t), 0},
{"SECTION_RAID_VOL_PAGE_1", raid_volume_page_1_items, data(RaidVolumePage1_t), 0},
{"SECTION_RAID_PHYS_DISK_PAGE_0", raid_physdisk_page_0_items, data(RaidPhysDiskPage0_t), 0},
{"SECTION_RAID_PHYS_DISK_PAGE_1", raid_physdisk_page_1_items, data(RaidPhysDiskPage1_t), 0},
{"SECTION_BIOS_1", bios_page_1_items, data(BIOSPage1_t), 0},
{"SECTION_BIOS_2", bios_page_2_items, data(BIOSPage2_t), 0},
{"SECTION_BIOS_4", bios_page_4_items, data(BIOSPage4_t), 0},
{"SECTION_LOG_0", log_page_0_items, data(LogPage0_t), EXT},
{0}
};
SECTION sections2[] =
{
{"SECTION_GENERAL_DATA", general_data_items, data(GeneralData_t), GEN},
{"SECTION_MANUFACTURING_PAGE_0", manufacturing_page_0_items, data(ManufacturingPage0_t), 0},
{"SECTION_MANUFACTURING_PAGE_1", manufacturing_page_1_items, data(ManufacturingPage1_t), 0},
{"SECTION_IOC_MFG_PAGE_2", manufacturing_page_2_items2, data(ManufacturingPage2_SAS2_t), MP2},
{"SECTION_IOC_MFG_PAGE_3", manufacturing_page_3_items2, data(ManufacturingPage3_SAS2_t), 0},
{"SECTION_MANUFACTURING_PAGE_4", manufacturing_page_4_items2, data(Mpi2ManufacturingPage4_t), 0},
{"SECTION_MANUFACTURING_PAGE_5", manufacturing_page_5_items2, plus(Mpi2ManufacturingPage5_t, Phy, 15), 0},
{"SECTION_IOC_MFG_PAGE_6", manufacturing_page_6_items2, data(ManufacturingPage6_SAS2_t), 0},
{"SECTION_MANUFACTURING_PAGE_7", manufacturing_page_7_items, plus(ManufacturingPage7_t, ConnectorInfo, 15), 0},
{"SECTION_MANUFACTURING_PAGE_8", manufacturing_page_8_items2, data(ManufacturingPage8_t), 0},
{"SECTION_IOC_MFG_PAGE_9", manufacturing_page_9_items2, data(ManufacturingPage9_SAS2_t), 0},
{"SECTION_MANUFACTURING_PAGE_10", manufacturing_page_10_items2, data(ManufacturingPage10_t), 0},
{"SECTION_IOC_MFG_PAGE_11", manufacturing_page_11_items2, data(ManufacturingPage11_SAS2_t), 0},
{"SECTION_IOC_MFG_PAGE_12", manufacturing_page_12_items2, data(ManufacturingPage12_SAS2_t), 0},
{"SECTION_IOC_MFG_PAGE_13", manufacturing_page_13_items2, data(ManufacturingPage13_SAS2_t), 0},
{"SECTION_IO_UNIT_PAGE_1", io_unit_page_1_items, data(IOUnitPage1_t), 0},
{"SECTION_IOC_PAGE_1", ioc_page_1_items2, data(Mpi2IOCPage1_t), 0},
{"SECTION_IOC_PAGE_8", ioc_page_8_items2, data(Mpi2IOCPage8_t), 0},
{"SECTION_BIOS_1", bios_page_1_items, data(BIOSPage1_t), 0},
{"SECTION_BIOS_2", bios_page_2_items2, data(Mpi2BiosPage2_t), 0},
{"SECTION_BIOS_3", bios_page_3_items2, data(Mpi2BiosPage3_t), 0},
{"SECTION_BIOS_4", bios_page_4_items2, plus(Mpi2BiosPage4_t, Phy, 15), 0},
{"SECTION_SAS_IO_UNIT_1", sas_io_unit_page_1_items2, plus(Mpi2SasIOUnitPage1_t, PhyData, 15), EXT},
{"SECTION_SAS_IO_UNIT_4", sas_io_unit_page_4_items2, plus(Mpi2SasIOUnitPage4_t, PHY, 3), EXT},
{"SECTION_DRIVER_MAPPING_0", driver_mapping_page_0_items2, data(Mpi2DriverMappingPage0_t), EXT},
{0}
};
#undef data
#undef plus
int
getSectionItem(SECTION *section, ITEM *item, char *buf, U8 *page)
{
char *c;
char x;
U8 *p;
int n;
int t;
int i;
int j;
int k;
n = (int)strlen(section->name);
while (*buf)
{
if (strncmp(buf, section->name, n) == 0)
break;
buf = skipLine(buf);
}
if (!*buf)
{
printf("%s not found!\n", section->name);
return 0;
}
buf = skipLine(buf);
if (item->size == 0) // special!
{
while (*buf)
{
if (strncmp(buf, "SECTION", 7) == 0)
return 1;
if (strncmp(buf, "END_SECTION", 11) == 0)
return 1;
c = NULL;
k = 0;
if (sscanf(buf, "BYTE_%d=%n", &i, &n) == 1)
{
c = buf + n;
j = i;
k = 1;
}
if (sscanf(buf, "BYTES_%d_%d=%n", &j, &i, &n) == 2)
{
c = buf + n;
if (j < i)
{
k = i;
i = j;
j = k;
}
k = j - i + 1;
if (k > 4)
{
c--;
x = *c;
*c = '\0';
printf("Byte range too large for %s in %s!\n", buf, section->name);
*c = x;
buf = skipLine(buf);
continue;
}
}
if (c == NULL)
{
buf = skipLine(buf);
continue;
}
if (sscanf(c, "%x%n", &t, &n) == 1)
{
if (c[n] != '\n')
{
c--;
x = *c;
*c = '\0';
printf("Incorrectly formed number for %s in %s!\n", buf, section->name);
*c = x;
buf = skipLine(buf);
continue;
}
if (n > 8 || (k < 4 && (U32)t > ((U32)1 << (k * 8))))
{
c--;
x = *c;
*c = '\0';
printf("Number too large for %s in %s!\n", buf, section->name);
*c = x;
buf = skipLine(buf);
continue;
}
p = page + i;
switch(k)
{
default:
case 4:
p[3] = (U8)(t >> 24);
case 3:
p[2] = (U8)(t >> 16);
case 2:
p[1] = (U8)(t >> 8);
case 1:
p[0] = (U8)t;
}
// c--;
// x = *c;
// *c = '\0';
// printf("%-32.32s %-28.28s %x\n", section->name, buf, t);
// *c = x;
removeLine(buf);
continue;
}
}
}
n = (int)strlen(item->name);
c = NULL;
while (*buf)
{
if (strncmp(buf, "SECTION", 7) == 0)
break;
if (strncmp(buf, "END_SECTION", 11) == 0)
break;
if (strncmp(buf, item->name, n) == 0 && buf[n] == '=')
{
c = buf + n + 1;
break;
}
buf = skipLine(buf);
}
if (c == NULL)
{
if (item->flags & OPT)
return 1;
if (item->flags & DUP)
return 0;
printf("%s not found in %s\n", item->name, section->name);
return 0;
}
p = page + item->offset;
t = 0;
if (item->flags & STR)
{
if (*c++ == '"')
{
n = 0;
while (*c != '\n' && *c != '\0')
{
if (*c == '"')
break;
p[n++] = *c++;
}
if (c[1] != '\n')
{
printf("Incorrectly formed string for %s in %s!\n", item->name, section->name);
return 0;
}
if (n != 0 || !(item->flags & IGN))
p[n] = '\0';
// printf("%-32.32s %-28.28s %s\n", section->name, item->name, p);
removeLine(buf);
return 1;
}
}
else
{
if (sscanf(c, "%x%n", &t, &n) == 1)
{
if (c[n] != '\n')
{
printf("Incorrectly formed number for %s in %s!\n", item->name, section->name);
return 0;
}
k = item->size * ((item->flags & BIT) ? 1 : 8);
if (n > 8 || (k < 32 && (U32)t > ((U32)1 << k)))
{
printf("Number too large for %s in %s!\n", item->name, section->name);
return 0;
}
if (t != 0 || !(item->flags & IGN))
{
switch((k + 7) / 8)
{
default:
case 4:
p[3] = (U8)(t >> 24);
case 3:
p[2] = (U8)(t >> 16);
case 2:
p[1] = (U8)(t >> 8);
case 1:
p[0] = (U8)t;
}
// printf("%-32.32s %-28.28s %x\n", section->name, item->name, t);
}
removeLine(buf);
return 1;
}
}
printf("Parse error on %s in %s!\n", item->name, section->name);
return 0;
}
U8
pageChecksum(U8 *page, int size, int skip)
{
int i;
int checksum;
checksum = 0;
for (i = skip; i < size; i++)
checksum -= page[i];
return checksum & 0xff;
}
#define NVDATA_SIZE 4096
#define NUM_CONFIG_PAGES (sizeof(sections)/sizeof(sections[0]) - 2) // ignore sentinel and GEN
#define NUM_CONFIG_PAGES2 (sizeof(sections2)/sizeof(sections2[0]) - 2) // ignore sentinel and GEN
int
concatenateSasFirmwareNvdata(void)
{
int file;
char name[256];
unsigned char *imageBuf = NULL;
int imageLen;
unsigned char *nvdataBuf = NULL;
int nvdataLen;
int len;
int n;
char *buf;
MpiFwHeader_t *fwHeader;
Mpi2FWImageHeader_t *fwHeader2;
MpiExtImageHeader_t *fwExtImageHeader;
Mpi2ExtImageHeader_t *fwExtImageHeader2;
Mpi2SupportedDevicesData_t *fwSupportedDevices = NULL;
MpiExtImageHeader_t *fwNvdataHeader = NULL;
Mpi2InitImageFooter_t *fwFooter;
U32 fwNextImage;
U32 fwLastImage = 0;
int i;
int t;
U32 checksum;
SECTION *section;
ITEM *item;
U8 *nvdata;
int length;
int headOff;
int pageOff;
CONFIG_DIR_HEADER *cdh;
CONFIG_DIR_HEADER2 *cdh2;
CONFIG_PROD_ID *cpi;
CONFIG_DIR_ENTRY *cde;
CONFIG_DIR_ENTRY2 *cde2;
PERSISTENT_PAGE_HEADER *pph;
PERSISTENT_PAGE_HEADER2 *pph2;
U8 page[512];
U8 update;
int header;
char *c1;
char *c2;
int pageType;
int pageNumber;
int pageLength;
int offset;
int size;
int fwFamily;
int fwDeviceId1 = 0;
int fwDeviceId2 = 0;
int nvDeviceId;
int fwVersion;
int nvVersion;
int mpi1;
int mpi2;
int ncp;
int npcp;
ITEM *section_items;
int section_size;
n = getFileName(name, sizeof name, stdin, "firmware", 0);
if (n > 0)
{
if (readFile(name, &imageBuf, &imageLen) != 1)
return 0;
}
else
{
printf("Image won't be processed\n");
return 1;
}
printf("Read %d bytes from file %s\n", imageLen, name);
checksum = 0;
for (i = 0; i < imageLen / 4; i++)
checksum += get32x(((U32 *)imageBuf)[i]);
if (checksum != 0)
{
printf("Image's checksum is invalid!\n");
free(imageBuf);
return 0;
}
fwHeader = (pMpiFwHeader_t)imageBuf;
fwHeader2 = (pMpi2FWImageHeader_t)fwHeader;
mpi1 = get32(fwHeader->Signature0) == MPI_FW_HEADER_SIGNATURE_0 &&
get32(fwHeader->Signature1) == MPI_FW_HEADER_SIGNATURE_1 &&
get32(fwHeader->Signature2) == MPI_FW_HEADER_SIGNATURE_2;
mpi2 = get32(fwHeader2->Signature0) == MPI2_FW_HEADER_SIGNATURE0 &&
get32(fwHeader2->Signature1) == MPI2_FW_HEADER_SIGNATURE1 &&
get32(fwHeader2->Signature2) == MPI2_FW_HEADER_SIGNATURE2;
if (!mpi1 && !mpi2)
{
printf("Image's signatures are invalid!\n");
free(imageBuf);
return 0;
}
fwExtImageHeader = NULL;
len = get32(fwHeader->ImageSize);
fwNextImage = get32(fwHeader->NextImageHeaderOffset);
while (fwNextImage != 0)
{
if (fwNextImage > imageLen - sizeof *fwExtImageHeader)
{
printf("Image's NextImageHeaderOffset field is invalid!\n");
free(imageBuf);
return 0;
}
fwExtImageHeader = (pMpiExtImageHeader_t)(imageBuf + fwNextImage);
fwExtImageHeader2 = (pMpi2ExtImageHeader_t)fwExtImageHeader;
if (fwExtImageHeader->ImageType == MPI_EXT_IMAGE_TYPE_NVDATA)
{
if (mpi1)
fwLastImage = fwNextImage;
fwNvdataHeader = fwExtImageHeader;
if (get32(fwExtImageHeader->NextImageHeaderOffset) != 0 ||
get32(fwExtImageHeader->ImageSize) != sizeof(MpiExtImageHeader_t))
{
printf("Image's attached NVDATA is incorrectly formed!\n");
free(imageBuf);
return 0;
}
}
if (fwExtImageHeader->ImageType == MPI2_EXT_IMAGE_TYPE_SUPPORTED_DEVICES)
{
fwSupportedDevices = (pMpi2SupportedDevicesData_t)(fwExtImageHeader2 + 1);
}
len += get32(fwExtImageHeader->ImageSize);
fwNextImage = get32(fwExtImageHeader->NextImageHeaderOffset);
if (fwExtImageHeader->ImageType == MPI2_EXT_IMAGE_TYPE_BOOTLOADER)
{
if (mpi2)
fwLastImage = fwNextImage;
}
}
if (len != imageLen)
{
printf("Image's length is invalid!\n");
free(imageBuf);
return 0;
}
if (mpi1)
{
if (fwNvdataHeader == NULL)
{
printf("Image's attached NVDATA is missing!\n");
free(imageBuf);
return 0;
}
printf("\nFirmware is %s for %X\n", fwHeader->VersionName, get32(fwHeader->SeqCodeVersion));
fwFamily = get16(fwHeader->ProductId) & MPI_FW_HEADER_PID_FAMILY_MASK;
switch (fwFamily)
{
case MPI_FW_HEADER_PID_FAMILY_1064_SAS:
fwDeviceId1 = MPI_MANUFACTPAGE_DEVID_SAS1064;
break;
case MPI_FW_HEADER_PID_FAMILY_1068_SAS:
fwDeviceId1 = MPI_MANUFACTPAGE_DEVID_SAS1068;
break;
case MPI_FW_HEADER_PID_FAMILY_1078_SAS:
fwDeviceId1 = MPI_MANUFACTPAGE_DEVID_SAS1078;
break;
case MPI_FW_HEADER_PID_FAMILY_106xE_SAS:
fwDeviceId1 = MPI_MANUFACTPAGE_DEVID_SAS1064E;
fwDeviceId2 = MPI_MANUFACTPAGE_DEVID_SAS1068E;
break;
}
if (fwDeviceId2)
printf("Firmware ProductId Family is %x, DeviceId is %X/%X\n",
get16(fwHeader->ProductId) & MPI_FW_HEADER_PID_FAMILY_MASK, fwDeviceId1, fwDeviceId2);
else
printf("Firmware ProductId Family is %x, DeviceId is %X\n",
get16(fwHeader->ProductId) & MPI_FW_HEADER_PID_FAMILY_MASK, fwDeviceId1);
fwVersion = (get32(fwHeader->ArmBranchInstruction1) >> 8) & 0xff;
printf("Firmware NVDATA Version is %x\n", fwVersion);
if (fwVersion != 0x25 && fwVersion != 0x28 && fwVersion != 0x29 &&
fwVersion != 0x2b && fwVersion != 0x2d)
{
printf("Expecting Version 25, 28, 29, 2B, or 2D -- can't process this image!\n");
free(imageBuf);
return 0;
}
}
else
{
if (fwNvdataHeader != NULL)
{
printf("Image's NVDATA is already attached!\n");
free(imageBuf);
return 0;
}
if (fwLastImage == 0)
{
printf("Image's BootLoader is missing!\n");
free(imageBuf);
return 0;
}
if (fwSupportedDevices == NULL)
{
printf("Image's Supported Device List is missing!\n");
free(imageBuf);
return 0;
}
if (fwSupportedDevices->NumberOfDevices == 0)
{
printf("Image's Supported Device List is empty!\n");
free(imageBuf);
return 0;
}
printf("\nFirmware is %s\n", fwHeader2->FirmwareVersionName);
for (i = 0; i < fwSupportedDevices->NumberOfDevices; i++)
{
if (fwSupportedDevices->SupportedDevice[i].LowPCIRev ==
fwSupportedDevices->SupportedDevice[i].HighPCIRev)
{
printf("Firmware supports DeviceId %X, RevisionId %X\n",
get16(fwSupportedDevices->SupportedDevice[i].DeviceID),
fwSupportedDevices->SupportedDevice[i].LowPCIRev);
}
else
{
printf("Firmware supports DeviceId %X, RevisionId %X to %X\n",
get16(fwSupportedDevices->SupportedDevice[i].DeviceID),
fwSupportedDevices->SupportedDevice[i].LowPCIRev,
fwSupportedDevices->SupportedDevice[i].HighPCIRev);
}
}
fwVersion = (get32(fwHeader2->NVDATAVersion.Word) >> 8) & 0xff;
if (fwVersion == 0x25) // sfs
{
printf("Expecting Version 30, found 25 -- you can slide for now\n");
fwVersion = 0x30;
}
printf("Firmware NVDATA Version is %x\n", fwVersion);
if (fwVersion != 0x30)
{
printf("Expecting Version 30 -- can't process this image!\n");
free(imageBuf);
return 0;
}
}
printf("\n");
n = getFileName(name, sizeof name, stdin, "NVDATA", 1);
if (n > 0)
{
if (readFile(name, &nvdataBuf, &nvdataLen) != 1)
{
free(imageBuf);
return 0;
}
}
else
{
printf("Image won't be processed\n");
free(imageBuf);
return 1;
}
printf("Read %d bytes from file %s\n", nvdataLen, name);
n = nvdataLen;
buf = realloc(nvdataBuf, n + 2);
if (n && buf[n-1] != '\n')
{
nvdataLen++;
buf[n++] = '\n';
}
buf[n] = '\0';
n = 0;
for (i = 0; i < nvdataLen; i++)
{
if (buf[i] == '\0' || buf[i] == '\r') // NUL and CR are ignored
continue;
if (buf[i] == ';') // lines starting with ; are ignored
{
while (buf[i] != '\n' && i < nvdataLen)
i++;
}
if (n)
{
if (buf[i] == '\n' && buf[n-1] == '\n') // blank lines are ignored
continue;
if (buf[i] == ' ' && buf[n-1] == '\n') // leading spaces are ignored
continue;
while (buf[i] == '\n' && buf[n-1] == ' ') // trailing spaces are ignored
n--;
}
else
{
if (buf[i] == '\n') // blank lines are ignored
continue;
if (buf[i] == ' ') // leading spaces are ignored
continue;
}
buf[n++] = buf[i];
}
buf[n] = '\0';
if (sscanf(buf, "SASDATA_VERSION_CHECK=%x", &nvVersion) == 1)
{
printf("\nNVDATA Version is %x\n", nvVersion);
if (fwVersion != nvVersion)
{
printf("Firmware Version does not match NVDATA Version, can't process this NVDATA file!\n");
free(imageBuf);
free(buf);
return 0;
}
}
removeLine(buf);
nvdata = malloc(NVDATA_SIZE);
memset(nvdata, 0, NVDATA_SIZE);
length = 0;
headOff = 0;
cdh = (CONFIG_DIR_HEADER *)(nvdata + headOff);
if (mpi1)
{
cdh->Signature = set32(CONFIG_DIR_HEADER_SIGNATURE);
cdh->State = CONFIG_DIR_HEADER_STATE_VALID;
cdh->CdhSize = sizeof *cdh / 4;
cdh->CdeSize = sizeof *cde / 4;
cdh->PphSize = sizeof *pph / 4;
cdh->ProdIdSize = sizeof *cpi / 4;
length += sizeof *cdh;
headOff += sizeof *cdh;
}
else
{
cdh2 = (CONFIG_DIR_HEADER2 *)cdh;
cdh2->Signature = set32(CONFIG_DIR_HEADER_SIGNATURE);
cdh2->State = CONFIG_DIR_HEADER_STATE_VALID;
cdh2->CdhSize = sizeof *cdh2 / 4;
cdh2->CdeSize = sizeof *cde2 / 4;
cdh2->PphSize = sizeof *pph2 / 4;
cdh2->ProdIdSize = sizeof *cpi / 4;
cdh2->NvdataVersion = set16(MPI2_VERSION);
cdh2->ProductIdOffset = set16(cdh2->CdhSize);
cdh2->DirEntryOffset = set16(cdh2->CdhSize + cdh->ProdIdSize);
length += sizeof *cdh2;
headOff += sizeof *cdh2;
}
ncp = 0;
npcp = 0;
n = mpi1 ? sizeof *cde * NUM_CONFIG_PAGES : sizeof *cde2 * NUM_CONFIG_PAGES2;
pageOff = length + sizeof *cpi + n;
if (nvVersion < 0x2d)
pageOff -= sizeof *cde; // skipping BIOSPage4
for (section = (mpi1 ? sections : sections2); section->name; section++)
{
section_items = section->items;
section_size = section->size;
if (nvVersion < 0x28)
{
if (section_items == manufacturing_page_5_items)
{
section_items = manufacturing_page_5_items_25;
section_size = manufacturing_page_5_size_25;
}
}
if (nvVersion < 0x29)
{
if (section_items == io_unit_page_3_items)
{
section_size = io_unit_page_3_size_25;
}
}
if (nvVersion < 0x2d)
{
if (section_items == bios_page_4_items)
{
continue;
}
}
memset(page, 0, sizeof page);
if (section->flags & GEN)
{
for (item = section_items; item->name; item++)
{
getSectionItem(section, item, buf, page);
}
cpi = (CONFIG_PROD_ID *)(nvdata + headOff);
memcpy(cpi->VendorId, ((pGeneralData_t)page)->VendorId, sizeof cpi->VendorId);
memcpy(cpi->ProductId, ((pGeneralData_t)page)->ProductId, sizeof cpi->ProductId);
memcpy(cpi->ProductRevision, ((pGeneralData_t)page)->ProductRevision, sizeof cpi->ProductRevision);
cpi->Signature = set32(CONFIG_PROD_ID_SIGNATURE);
cdh->NvdataVersion = set16((nvVersion << 8) | ((pGeneralData_t)page)->UserVersion);
length += sizeof *cpi;
headOff += sizeof *cpi;
continue;
}
getSectionItem(section, &forceupdate_item, buf, &update);
if (section->flags & EXT)
{
for (item = ext_header_items; item->name; item++)
{
t = getSectionItem(section, item, buf, page);
}
}
else
{
for (item = header_items; item->name; item++)
{
t = getSectionItem(section, item, buf, page);
}
}
for (item = section_items; item->name; item++)
{
if (item->flags & MPI1 && !mpi1)
continue;
if (item->flags & MPI2 && !mpi2)
continue;
t = getSectionItem(section, item, buf, page);
if (t == 1)
if (item->flags & DUP)
item++;
}
getSectionItem(section, &special_item, buf, page);
if (section->flags & EXT)
{
pageType = ((pConfigExtendedPageHeader_t)page)->ExtPageType;
pageNumber = ((pConfigExtendedPageHeader_t)page)->PageNumber;
pageLength = get16(((pConfigExtendedPageHeader_t)page)->ExtPageLength);
header = sizeof(ConfigExtendedPageHeader_t);
size = section_size / 4;
if (size != pageLength && yesFlag == TRUE)
printf("incorrect EXT_PAGE_LENGTH %x vs. %x for %s\n", pageLength, size, section->name);
}
else
{
pageType = ((pConfigPageHeader_t)page)->PageType & MPI_CONFIG_PAGETYPE_MASK;
pageNumber = ((pConfigPageHeader_t)page)->PageNumber;
pageLength = ((pConfigPageHeader_t)page)->PageLength;
header = sizeof(ConfigPageHeader_t);
size = section_size / 4;
if (size != pageLength && yesFlag == TRUE)
printf("incorrect PAGE_LENGTH %x vs. %x for %s\n", pageLength, size, section->name);
}
if (section->flags & PID)
offset = 0x7fff;
else
offset = pageOff / 4;
size = (section_size - header) / 4;
cde = (CONFIG_DIR_ENTRY *)(nvdata + headOff);
if (mpi1)
{
#if !__linux__ && !__sparc__
// safe to use bit field definitions on little-endian machines
cde->State = CONFIG_DIR_ENTRY_STATE_IN_USE;
cde->PageType = pageType;
cde->PageNum = pageNumber;
cde->AllocUnits = size;
cde->ForceNvdataUpdate = update;
cde->DwordOffset = offset;
#else
// can't use bit field definitions on big-endian machines
((U8 *)cde)[0] = (U8)(CONFIG_DIR_ENTRY_STATE_IN_USE | ((size & 0x00f) << 4));
((U8 *)cde)[1] = (U8)((size & 0xff0) >> 4);
((U8 *)cde)[2] = (U8)(pageType & 0xff);
((U8 *)cde)[3] = (U8)(((update & 1) << 4) | (pageNumber & 0xf));
((U8 *)cde)[4] = (U8)(offset & 0x00ff);
((U8 *)cde)[5] = (U8)((offset & 0x7f00) >> 8);
#endif
n = sizeof *cde;
}
else
{
cde2 = (CONFIG_DIR_ENTRY2 *)cde;
cde2->State = CONFIG_DIR_ENTRY_STATE_IN_USE;
cde2->PageType = pageType;
cde2->PageNum = pageNumber;
cde2->AllocUnits = set16(size);
cde2->UpdateFlags = update;
cde2->DwordOffset = set32(offset);
n = sizeof *cde2;
}
length += n;
headOff += n;
ncp++;
if (((pConfigPageHeader_t)page)->PageType & MPI_CONFIG_PAGEATTR_PERSISTENT)
npcp++;
if (section->flags & PID)
{
continue;
}
if (section->flags & MP2)
{
nvDeviceId = get16(((pManufacturingPage2_SAS_t)page)->ChipId.DeviceID);
printf("NVDATA DeviceId is %X\n", nvDeviceId);
if (mpi1)
{
if (nvDeviceId != fwDeviceId1 && nvDeviceId != fwDeviceId2)
{
printf("\nNVDATA DeviceId does not match Firmware DeviceId!\n");
free(imageBuf);
free(nvdata);
return 0;
}
}
else
{
for (i = 0; i < fwSupportedDevices->NumberOfDevices; i++)
{
if (nvDeviceId == get16(fwSupportedDevices->SupportedDevice[i].DeviceID))
break;
}
if (i == fwSupportedDevices->NumberOfDevices)
{
printf("\nNVDATA DeviceId does not match any Firmware DeviceId!\n");
free(imageBuf);
free(nvdata);
return 0;
}
}
if (mpi1)
{
((pManufacturingPage2_SAS_t)page)->AutoDownloadChecksum = 0xa5;
checksum = 0;
for (i = 8; i < 38; i++)
checksum -= page[i];
((pManufacturingPage2_SAS_t)page)->AutoDownloadChecksum = (U8)checksum;
}
}
pph = (PERSISTENT_PAGE_HEADER *)(nvdata + pageOff);
pph->State = CONFIG_PERSISTENT_HEADER_STATE_UPDATE_COMPLETE;
pph->Checksum = pageChecksum(page, section_size, header);
if (mpi1)
{
pph->DwordOffset = set16(0x7fff);
n = sizeof *pph;
}
else
{
pph2 = (PERSISTENT_PAGE_HEADER2 *)pph;
pph2->DwordOffset = set32(0xffffffff);
n = sizeof *pph2;
}
length += n;
pageOff += n;
memcpy(nvdata + pageOff, page + header, section_size - header);
length += section_size - header;
pageOff += section_size - header;
}
cdh->TotalBytes = set16(length);
cdh->NbrDirEntries = set32(ncp);
cdh->NbrPersistDirEntries = set32(npcp);
c1 = buf;
while (*c1)
{
if (strncmp(c1, "SECTION", 7) == 0)
{
c2 = skipLine(c1);
if (*c2 == '\0' || strncmp(c2, "SECTION", 7) == 0)
{
removeLine(c1);
continue;
}
if (*c2 == '\0' || strncmp(c2, "END_SECTION", 11) == 0)
{
removeLine(c1);
removeLine(c1);
continue;
}
}
c1 = skipLine(c1);
}
if (strlen(buf))
{
printf("\nExtra lines found in NVDATA file!\n");
printf("----\n%s----\n", buf);
}
free(buf);
printf("\n");
n = getFileName(name, sizeof name, stdin, "output", 2);
if (n > 0)
{
file = open(name, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, 0644);
if (file < 0)
{
printf("Open failure for file %s\n", name);
perror("Error is");
free(imageBuf);
free(nvdata);
return 0;
}
}
else
{
printf("Image won't be saved\n");
free(imageBuf);
free(nvdata);
return 1;
}
if (mpi2)
n = sizeof(Mpi2ExtImageHeader_t);
else
n = 0;
imageBuf = realloc(imageBuf, imageLen + length + n);
fwExtImageHeader = (pMpiExtImageHeader_t)(imageBuf + fwLastImage);
if (mpi2)
{
fwExtImageHeader2 = (pMpi2ExtImageHeader_t)fwExtImageHeader;
for (i = imageLen - 1; i >= (int)fwLastImage; i--)
imageBuf[i + length + n] = imageBuf[i];
memset(fwExtImageHeader2, 0, n);
fwExtImageHeader2->ImageType = MPI2_EXT_IMAGE_TYPE_NVDATA;
fwExtImageHeader2->ImageSize = set32(n);
fwExtImageHeader2->NextImageHeaderOffset = set32(fwLastImage);
strcpy((char *)fwExtImageHeader2->IdentifyString, "@(#)NVDATA");
checksum = 0;
for (i = 0; i < n / 4; i++)
checksum -= get32x(((U32 *)fwExtImageHeader2)[i]);
fwExtImageHeader2->Checksum = set32(checksum);
memcpy(imageBuf + fwLastImage + n, nvdata, length);
}
else
{
memcpy(imageBuf + imageLen, nvdata, length);
}
checksum = get32(fwExtImageHeader->Checksum);
len = get32(fwExtImageHeader->ImageSize);
fwExtImageHeader->ImageSize = set32(len + length);
checksum -= length;
for (i = 0; i < (length + 3) / 4; i++)
checksum -= get32x(((U32 *)nvdata)[i]);
fwExtImageHeader->Checksum = set32(checksum);
while ((fwNextImage = get32(fwExtImageHeader->NextImageHeaderOffset)) != 0)
{
checksum = get32(fwExtImageHeader->Checksum);
fwNextImage += length + n;
checksum -= length + n;
fwExtImageHeader->NextImageHeaderOffset = set32(fwNextImage);
fwExtImageHeader->Checksum = set32(checksum);
fwExtImageHeader = (pMpiExtImageHeader_t)(imageBuf + fwNextImage);
fwLastImage = fwNextImage;
}
if (fwExtImageHeader->ImageType == MPI2_EXT_IMAGE_TYPE_INITIALIZATION)
{
len = get32(fwExtImageHeader->ImageSize);
fwFooter = (pMpi2InitImageFooter_t)(imageBuf + fwLastImage + len) - 1;
len = get32(fwFooter->ImageSize);
checksum = get32(fwExtImageHeader->Checksum);
checksum += len;
// the footer's ImageSize is big-endian!
len = swap32(len);
len += length + n;
len = swap32(len);
checksum -= len;
fwFooter->ImageSize = set32(len);
fwExtImageHeader->Checksum = set32(checksum);
}
t = write(file, imageBuf, imageLen + length + n);
if (t != imageLen + length + n)
{
printf("Write failed for file %s, t = %x\n", name, t);
perror("Error is");
close(file);
free(imageBuf);
free(nvdata);
return 0;
}
printf("Wrote %d bytes to file %s\n", imageLen + length + n, name);
close(file);
free(imageBuf);
free(nvdata);
return 1;
}
#endif
char *
getSasProductId(char *nvdata)
{
CONFIG_DIR_HEADER *cdh;
CONFIG_PROD_ID *cpi;
cdh = (CONFIG_DIR_HEADER *)nvdata;
cpi = (CONFIG_PROD_ID *)((char *)cdh + cdh->CdhSize * 4);
return (char *)cpi->ProductId;
}
int
selectAltaDevice(MPT_PORT *port, int *dev_bus, int *dev_target)
{
int bus;
int target;
unsigned char inq[36];
unsigned char inqvpd[600];
int i;
int n;
if (kFlag == TRUE)
{
if (port->maxBuses > 1 || gFlag == TRUE)
{
printf("Bus: [0-%d or RETURN to quit] ", port->maxBuses - 1);
bus = getNumberAnswer(0, port->maxBuses - 1, -1);
if (bus < 0)
return 0;
}
else
{
bus = 0;
}
printf("Target: [0-%d or RETURN to quit] ", port->maxTargets - 1);
target = getNumberAnswer(0, port->maxTargets - 1, -1);
if (target < 0)
return 0;
*dev_bus = bus;
*dev_target = target;
return 1;
}
showPortInfoHeader(port);
printf(" B___T Type Vendor Product Rev\n");
n = 0;
for (bus = 0; bus < port->maxBuses; bus++)
{
for (target = port->minTargets; target < port->maxTargets; target++)
{
if (doInquiry(port, bus, target, 0, inq, sizeof inq) != 1)
{
#if __linux__ || DOS || EFI
if (errno == EFAULT)
return 0;
#endif
continue;
}
if (doInquiryVpdPage(port, bus, target, 0, 0x89, inqvpd, sizeof inqvpd) != 1)
{
#if __linux__ || DOS || EFI
if (errno == EFAULT)
return 0;
#endif
continue;
}
if ((inq[0] & 0x1f) == 0x1f)
continue;
if ((inq[0] & 0xe0) == 0x20)
continue;
if ((inq[0] & 0xe0) == 0x60)
continue;
if ((strncmp((char *)inqvpd+8, "LSI", 3) != 0) ||
(strncmp((char *)inqvpd+16, "LSISS25x0", 9) != 0))
continue;
for (i = 8; i < 36; i++)
if (!isprint(inq[i]))
inq[i] = ' ';
diag_targets[n].bus = bus;
diag_targets[n].target = target;
n++;
printf("%2d. %2d %3d %-9s %-8.8s %-16.16s %-4.4s\n",
n, bus, target, deviceType[inq[0] & 0x1f],
inq+8, inq+16, inq+32);
if (n == MAX_DEVICES)
break;
}
if (n == MAX_DEVICES)
break;
}
if (n == 0)
{
printf("\nNo devices are available for this test\n");
return 0;
}
printf("\nSelect a device: [1-%d or RETURN to quit] ", n);
n = getNumberAnswer(1, n, 0);
if (n == 0)
return 0;
n--;
bus = diag_targets[n].bus;
target = diag_targets[n].target;
*dev_bus = bus;
*dev_target = target;
return 1;
}
int
doAltaDiagnostics(MPT_PORT *port, int command)
{
int t;
if (bringOnline(port) != 1)
return 0;
switch (command)
{
case 1:
t = doAltaProgramManufacturingInfo(port);
if (t == 1)
printf("Programming completed successfully.\n");
else
printf("Programming completed with errors.\n");
if (wFlag)
fprintf(logFile, "%s: Alta Program Manufacturing Information: %s\n",
logPrefix(port), t ? "PASS" : "FAIL");
break;
case 2:
doAltaDisplayManufacturingInfo(port);
break;
case 3:
doResetAlta(port);
break;
default:
printf("Invalid selection!\n");
break;
}
return 1;
}
int
doAltaProgramManufacturingInfo(MPT_PORT *port)
{
char name[256];
unsigned char *identityBuf = NULL;
int identityLen;
int n;
int t;
char wwid[64];
char serial[64];
char mfgdate[64];
char rwkdate[64];
char partnum[64];
char tmpstr[64];
int skipmfg = FALSE;
int skiprwk = FALSE;
int skipwwid = FALSE;
unsigned char data[255];
U32 wwidl;
U32 wwidh;
int bus;
int target;
char *c;
int foundOne;
int passed;
U32 wwidlChk;
U32 wwidhChk;
int wwidError = TRUE;
*serial = 0;
*mfgdate = 0;
*rwkdate = 0;
*partnum = 0;
*wwid = 0;
if (gFlag)
{
printf("\nError if WWID not found in config? [Yes or No, default is Yes] ");
n = getYesNoAnswer(1);
if (n==0)
{
wwidError = FALSE;
}
}
if (selectAltaDevice(port, &bus, &target) != 1)
return 0;
n = getFileName(name, sizeof name, stdin, "Alta parameters", 0);
if (n > 0)
{
if (readFile(name, &identityBuf, &identityLen) != 1)
{
return 0;
}
printf("%d bytes read from %s\n\n", identityLen, name);
/* start processing the file data one line at a time */
c = (char *)identityBuf;
while (!*wwid || !*serial || !*partnum || !*mfgdate || !*rwkdate)
{
foundOne = FALSE;
if (strncmp(c, "WWN=", 4) == 0)
{
// Check to see if "WWN=" is in the file (null value).
// If that's the case, then we need to check
// line endings to move 'c' forward the appropriate
// amount. Otherwise, `sscanf(c + 4, "%s", wwid);`
// will simply load the next line, which is
// definitely not what we want.
if(strncmp(c,"WWN=\n", 5) == 0)
{
wwid[0] = '\0';
c += 5;
}
else if (strncmp(c,"WWN=\r\n", 6) == 0)
{
wwid[0] = '\0';
c += 6;
}
else
{
sscanf(c + 4, "%s", wwid);
c = strchr(c + 1, '\n');
if (c)
c++;
else
break;
}
}
if (strncmp(c, "SN=", 3) == 0)
{
foundOne = TRUE;
sscanf(c + 3, "%s", serial);
c = strchr(c + 1, '\n');
if (c)
c++;
else
break;
}
if (strncmp(c, "PARTNUM=", 8) == 0)
{
foundOne = TRUE;
// Fix for a customer to allow the format "PARTNUM=P/N TCA-00347-01-A"
if(strncmp(c + 8, "P/N ", 4) == 0)
{
sscanf(c + 8 + 4, "%s", partnum);
}
else
{
sscanf(c + 8, "%s", partnum);
}
c = strchr(c + 1, '\n');
if (c)
c++;
else
break;
}
if (strncmp(c, "MFGDATE=", 8) == 0)
{
foundOne = TRUE;
sscanf(c + 8, "%s", mfgdate);
c = strchr(c + 1, '\n');
if (c)
c++;
else
break;
}
if (strncmp(c, "RWKDATE=", 8) == 0)
{
foundOne = TRUE;
sscanf(c + 8, "%s", rwkdate);
c = strchr(c + 1, '\n');
if (c)
c++;
else
break;
}
/* if we didn't find a required key, see if any more lines are available to check */
if (!foundOne)
{
c = strchr(c, '\n');
if (c)
c++;
else
break;
}
}
if( (wwidError==FALSE) && (!*wwid || strlen(wwid) == 0 ) )
skipwwid = TRUE;
if ((!skipwwid && !wwid) || !*serial || !*partnum || !*mfgdate || !*rwkdate)
{
printf("Parameters file missing required keys:%s%s%s%s%s\n",
!skipwwid && !*wwid ? " WWN" : "", !*serial ? " SN" : "",
!*partnum ? " PARTNUM" : "", !*mfgdate ? " MFGDATE" : "",
!*rwkdate ? " RWKDATE" : "");
if (wFlag)
fprintf(logFile, "%s: Parameters file missing required keys:%s%s%s%s%s\n",
logPrefix(port), !skipwwid && !*wwid ? " WWN" : "", !*serial ? " SN" : "",
!*partnum ? " PARTNUM" : "", !*mfgdate ? " MFGDATE" : "",
!*rwkdate ? " RWKDATE" : "");
return 0;
}
if (skipwwid == FALSE && (strlen(wwid) != 9 ||
sscanf(wwid, "%x", &t) != 1 || sscanf(wwid + 8, "%x", &t) != 1))
{
printf("Alta WWN value <%s> is invalid!\n", wwid);
if (wFlag)
fprintf(logFile, "%s: Alta WWN value <%s> is invalid: FAIL\n",
logPrefix(port), wwid);
*wwid = 0;
}
if (strlen(serial) > 16)
{
printf("Alta SN value <%s> is invalid!\n", serial);
if (wFlag)
fprintf(logFile, "%s: Alta SN value <%s> is invalid: FAIL\n",
logPrefix(port), serial);
*serial = 0;
}
if (strlen(mfgdate) != 8 || sscanf(mfgdate, "%x", &t) != 1)
{
printf("Alta MFGDATE value <%s> is invalid!\n", mfgdate);
if (wFlag)
fprintf(logFile, "%s: Alta MFGDATE value <%s> is invalid: FAIL\n",
logPrefix(port), mfgdate);
*mfgdate = 0;
}
if (strlen(rwkdate) != 8 || sscanf(rwkdate, "%x", &t) != 1)
{
printf("Alta RWKDATE value <%s> is invalid!\n", rwkdate);
if (wFlag)
fprintf(logFile, "%s: Alta RWKDATE value <%s> is invalid: FAIL\n",
logPrefix(port), rwkdate);
*rwkdate = 0;
}
if (strlen(partnum) > 16)
{
printf("Alta PARTNUM value <%s> is invalid!\n", partnum);
if (wFlag)
fprintf(logFile, "%s: Alta PARTNUM value <%s> is invalid: FAIL\n",
logPrefix(port), partnum);
*partnum = 0;
}
free(identityBuf);
}
else
{
printf("The Alta's manufacturing information will not be updated!\n\n");
}
if ((!skipwwid && !*wwid) || !*serial || !*partnum || !*mfgdate || !*rwkdate)
return 0;
if (strncmp(mfgdate, "00000000", 8) == 0)
skipmfg = TRUE;
if (strncmp(rwkdate, "00000000", 8) == 0)
skiprwk = TRUE;
printf("Alta WWN .......... %s%s\n", wwid, skipwwid == TRUE ? " (Will not be changed)" : "");
printf("Alta SN ........... %s\n", serial);
printf("Alta MFGDATE ...... %s%s\n", mfgdate, skipmfg == TRUE ? " (Will not be changed)" : "");
printf("Alta RWKDATE ...... %s%s\n", rwkdate, skiprwk == TRUE ? " (Will not be changed)" : "");
printf("Alta PARTNUM ...... %s\n", partnum);
if (yesFlag == FALSE)
{
printf("\nAre these values correct? [Yes or No, default is No] ");
if (getYesNoAnswer(0) != 1)
{
return 0;
}
}
if (wFlag)
{
fprintf(logFile, "%s: Alta WWN .......... %s\n", logPrefix(port), wwid);
fprintf(logFile, "%s: Alta SN ........... %s\n", logPrefix(port), serial);
fprintf(logFile, "%s: Alta MFGDATE ...... %s%s\n", logPrefix(port), mfgdate,
skipmfg == TRUE ? " (Will not be changed)" : "");
fprintf(logFile, "%s: Alta RWKDATE ...... %s%s\n", logPrefix(port), rwkdate,
skiprwk == TRUE ? " (Will not be changed)" : "");
fprintf(logFile, "%s: Alta PARTNUM ...... %s\n", logPrefix(port), partnum);
}
/* start by assuming success */
passed = TRUE;
printf("\nProgramming Alta...\n");
// The WWID may not need to be programmed
if(skipwwid == FALSE)
{
/* program wwn */
sscanf(wwid + 1, "%x", &wwidl);
wwid[1] = '\0';
sscanf(wwid, "%x", &wwidh);
/* add the LSI prefix to the WWN */
wwidh |= 0x500605b << 4;
t = doModeSense(port, bus, target, 0, 0x32, 0, 0, data, sizeof data);
n = data[0] + 1;
if ((t == 1) && (n >= 31))
{
/* replace the current WWN with the value we are programming */
put4bytes(data, 12+11, wwidh);
put4bytes(data, 12+15, wwidl);
/* update the WWN gen type field */
data[12+5] = (unsigned char)(data[12+5] | 1<<5);
if (doModeSelect(port, bus, target, 0, 1, data, n) != 1)
{
printf("Mode select page 0x32 for programmed WWN failed!\n");
if (wFlag)
fprintf(logFile, "%s: Mode select page 0x32 for programmed WWN: FAIL\n",
logPrefix(port));
passed = FALSE;
}
else
{
/* lets read it back and make sure it seems to have written correctly */
memset(data, 0, sizeof data);
t = doModeSense(port, bus, target, 0, 0x32, 0, 0, data, sizeof data);
n = data[0] + 1;
if ((t == 1) && (n >= 31))
{
wwidhChk = get4bytes(data, 12+11);
wwidlChk = get4bytes(data, 12+15);
if (wwidh != wwidhChk || wwidl != wwidlChk)
{
printf("Verify of programmed WWN failed! (found <%08x%08x>, expected <%08x%08x>)\n",
wwidhChk, wwidlChk, wwidh, wwidl);
if (wFlag)
fprintf(logFile, "%s: Mode sense verify of programmed WWN (found <%08x%08x>, expected <%08x%08x>): FAIL\n",
logPrefix(port), wwidhChk, wwidlChk, wwidh, wwidl);
passed = FALSE;
}
else
if (wFlag)
fprintf(logFile, "%s: Mode sense verify of programmed WWN: PASS\n",
logPrefix(port));
}
else
{
printf("Mode sense page 0x32 for verify of programmed WWN failed!\n");
if (wFlag)
fprintf(logFile, "%s: Mode sense page 0x32 for verify of programmed WWN: FAIL\n",
logPrefix(port));
passed = FALSE;
}
}
}
else
{
printf("Mode sense page 0x32 for programmed WWN failed!\n");
if (wFlag)
fprintf(logFile, "%s: Mode sense page 0x32 for programmed WWN: FAIL\n",
logPrefix(port));
passed = FALSE;
}
} //skipwwid
/* program serial number, part number, and dates */
memset(data, 0, sizeof data);
t = doLogSense(port, bus, target, 0, 0x35, 1, data, sizeof data);
n = get2bytes(data, 2) + 4;
if ((t == 1) && (n >= 158))
{
/* replace the current serial number with the value we are programming */
strncpy((char *)(data+16), serial, strlen(serial)); // 16:31
/* pad the rest with spaces (20h) */
memset((void *)(data+16+strlen(serial)), 0x20, 16 - strlen(serial));
/* replace the current part number with the value we are programming */
strncpy((char *)(data+58), partnum, strlen(partnum)); // 58:73
/* pad the rest with spaces (20h) */
memset((void *)(data+58+strlen(partnum)), 0x20, 16 - strlen(partnum));
if (skipmfg == FALSE)
{
/* mfg date is in ASCII in bytes 102-109 */
strncpy((char *)(data+102), mfgdate, 8);
}
if (skiprwk == FALSE)
{
/* rework date is in ASCII in bytes 118-125 */
strncpy((char *)(data+118), rwkdate, 8);
}
if (doLogSelect(port, bus, target, 0, 1, 1, data, n) != 1)
{
printf("Log select page 0x35 for programmed serial number, part number, and dates failed!\n");
if (wFlag)
fprintf(logFile, "%s: Log select page 0x35 for programmed serial number, part number, and dates: FAIL\n",
logPrefix(port));
passed = FALSE;
}
else
{
/* lets read it back and make sure it seems to have written correctly */
memset(data, 0, sizeof data);
t = doLogSense(port, bus, target, 0, 0x35, 1, data, sizeof data);
n = get2bytes(data, 2) + 4;
if ((t == 1) && (n >= 158))
{
/* check the serial number */
if (strncmp((char *)data+16, serial, strlen(serial)) != 0)
{
printf("Verify of programmed serial number failed! (found <%16.16s>, expected <%16.16s>)\n",
data+16, serial);
if (wFlag)
fprintf(logFile, "%s: Log sense verify of programmed serial number (SN) (found <%10.10s>, expected <%10.10s>): FAIL\n",
logPrefix(port), data+16, serial);
passed = FALSE;
}
else
if (wFlag)
fprintf(logFile, "%s: Log sense verify of programmed serial number (SN): PASS\n",
logPrefix(port));
/* check the manufacture date */
if (skipmfg == FALSE)
{
if (strncmp((char *)data+102, mfgdate, 8) != 0)
{
printf("Verify of programmed manufacture date failed! (found <%8.8s>, expected <%8.8s>)\n",
data+102, mfgdate);
if (wFlag)
fprintf(logFile, "%s: Log sense verify of programmed manufacture date (MFGDATE) (found <%8.8s>, expected <%8.8s>): FAIL\n",
logPrefix(port), data+102, mfgdate);
passed = FALSE;
}
else
if (wFlag)
fprintf(logFile, "%s: Log sense verify of programmed manufacture date (MFGDATE): PASS\n",
logPrefix(port));
}
else
if (wFlag)
fprintf(logFile, "%s: Log sense verify of programmed manufacture date (unchanged) (MFGDATE): PASS\n",
logPrefix(port));
/* check the rework date */
if (skiprwk == FALSE)
{
if (strncmp((char *)data+118, rwkdate, 8) != 0)
{
printf("Verify of programmed rework date failed! (found <%8.8s>, expected <%8.8s>)\n",
data+118, rwkdate);
if (wFlag)
fprintf(logFile, "%s: Log sense verify of programmed rework date (RWKDATE) (found <%8.8s>, expected <%8.8s>): FAIL\n",
logPrefix(port), data+118, rwkdate);
passed = FALSE;
}
else
if (wFlag)
fprintf(logFile, "%s: Log sense verify of programmed rework date (RWKDATE): PASS\n",
logPrefix(port));
}
else
if (wFlag)
fprintf(logFile, "%s: Log sense verify of programmed rework date (unchanged) (RWKDATE): PASS\n",
logPrefix(port));
/* check the part number */
if (strncmp((char *)data+58, partnum, strlen(partnum)) != 0)
{
strncpy(tmpstr, (char *)data+58, strlen(partnum));
tmpstr[strlen(partnum)] = '\0';
printf("Verify of programmed part number failed! (found <%s>, expected <%s>)\n",
tmpstr, partnum);
if (wFlag)
fprintf(logFile, "%s: Log sense verify of programmed part number (PARTNUM) (found <%s>, expected <%s>): FAIL\n",
logPrefix(port), tmpstr, partnum);
passed = FALSE;
}
else
if (wFlag)
fprintf(logFile, "%s: Log sense verify of programmed part number (PARTNUM): PASS\n",
logPrefix(port));
}
else
{
printf("Log sense page 0x35 for verify of programmed serial number, part number, and dates failed!\n");
if (wFlag)
fprintf(logFile, "%s: Log sense page 0x35 for verify of programmed serial number, part number, and dates: FAIL\n",
logPrefix(port));
passed = FALSE;
}
}
#if 0 //debug
t = doLogSense(port, bus, target, 0, 0x35, 1, data, sizeof data);
n = get2bytes(data, 2) + 4;
printf("written new log sense buffer:\n");
displayByteData(data, n);
#endif
}
else
{
printf("Log sense page 0x35 for programmed serial number, part number, and dates failed!\n");
if (wFlag)
fprintf(logFile, "%s: Log sense page 0x35 for programmed serial number, part number, and dates: FAIL\n",
logPrefix(port));
passed = FALSE;
}
return passed;
}
int
doAltaDisplayManufacturingInfo(MPT_PORT *port)
{
int bus;
int target;
unsigned char data[255];
int t;
int n;
U32 wwn_h;
U32 wwn_l;
char tmpstr[64];
int i;
if (selectAltaDevice(port, &bus, &target) != 1)
return 0;
t = doModeSense(port, bus, target, 0, 0x32, 0, 0, data, sizeof data);
n = data[0] + 1;
if ((t == 1) && (n >= 12+19))
{
wwn_h = get4bytes(data, 12+11);
wwn_l = get4bytes(data, 12+15);
}
else
{
wwn_h = 0;
wwn_l = 0;
printf("Read of mode page 0x32 for programmed WWN failed!\n");
if (wFlag)
fprintf(logFile, "%s: read of mode page 0x32 for programmed WWN: FAIL\n",
logPrefix(port));
}
t = doLogSense(port, bus, target, 0, 0x35, 1, data, sizeof data);
n = get2bytes(data, 2) + 4;
if ((t == 1) && (n >= 158))
{
/* display the firmware version */
strncpy(tmpstr, (char *)data+126, 12);
for (i = 0; i < 12; i++)
if ( tmpstr[i] == ' ')
break;
tmpstr[i] = '\0';
printf("Running firmware version is <%-s>\n", tmpstr);
if (wFlag)
fprintf(logFile, "%s: AltaDisplayManufacturingInfo - FWVERSION=%-s\n",
logPrefix(port), tmpstr);
/* display the bootloader version */
strncpy(tmpstr, (char *)data+138, 12);
for (i = 0; i < 12; i++)
if ( tmpstr[i] == ' ')
break;
tmpstr[i] = '\0';
printf("Running bootloader version is <%-s>\n", tmpstr);
if (wFlag)
fprintf(logFile, "%s: AltaDisplayManufacturingInfo - BLVERSION=%-s\n",
logPrefix(port), tmpstr);
/* display the WWN */
printf("Programmed WWN is <%08x%08x>\n", wwn_h, wwn_l);
if (wFlag)
fprintf(logFile, "%s: AltaDisplayManufacturingInfo - WWN=%08x%08x\n",
logPrefix(port), wwn_h, wwn_l);
/* display the serial number */
printf("Programmed serial number is <%16.16s>\n", data+16);
if (wFlag)
fprintf(logFile, "%s: AltaDisplayManufacturingInfo - SN=%16.16s\n",
logPrefix(port), data+16);
/* display the manufacturing date */
printf("Programmed manufacture date is <%-8.8s>\n", data+102);
if (wFlag)
fprintf(logFile, "%s: AltaDisplayManufacturingInfo - MFGDATE=%-8.8s\n",
logPrefix(port), data+102);
/* display the rework date */
printf("Programmed rework date is <%-8.8s>\n", data+118);
if (wFlag)
fprintf(logFile, "%s: AltaDisplayManufacturingInfo - RWKDATE=%-8.8s\n",
logPrefix(port), data+118);
/* display the part number */
strncpy(tmpstr, (char *)data+58, 16);
for (i = 0; i < 16; i++)
if ( tmpstr[i] == ' ')
break;
tmpstr[i] = '\0';
printf("Programmed part number is <%-s>\n", tmpstr);
if (wFlag)
fprintf(logFile, "%s: AltaDisplayManufacturingInfo - PARTNUM=%-s\n",
logPrefix(port), tmpstr);
}
else
{
printf("Log sense page 0x35 for programmed serial number, part number, and dates failed!\n");
if (wFlag)
fprintf(logFile, "%s: Log sense page 0x35 for programmed serial number, part number, and dates: FAIL\n",
logPrefix(port));
}
return 1;
}
int
doResetAlta(MPT_PORT *port)
{
int bus;
int target;
unsigned char data[128];
int t;
int n;
if (selectAltaDevice(port, &bus, &target) != 1)
return 0;
t = doModeSense(port, bus, target, 0, 0x32, 0, 0, data, sizeof data);
n = data[0] + 1;
if ((t == 1) && (n >= 12+6))
{
/* set the reboot bit */
data[12+5] = (unsigned char)(data[12+5] | 1<<3);
}
else
{
printf("Read of mode page 0x32 failed!\n");
if (wFlag)
fprintf(logFile, "%s: Read of mode page 0x32 for device reset: FAIL\n",
logPrefix(port));
return 0;
}
if (doModeSelect(port, bus, target, 0, 1, data, n) != 1)
{
printf("Write of mode select page 0x32 failed!\n");
if (wFlag)
fprintf(logFile, "%s: Write of mode select page 0x32 for device reset: FAIL\n",
logPrefix(port));
return 0;
}
printf("Alta reset complete\n");
return 1;
}
char *
translateExpanderEventCode(int code)
{
switch (code)
{
case 1: return "POST_EVENT ";
case 2: return "SOD_EVENT ";
case 3: return "TSTAMP_RESET";
case 4: return "FAULT_EVENT ";
case 5: return "WDOG_RESET ";
case 6: return "SES_EVENT ";
case 7: return "SCE_EVENT ";
case 0xFF: return "INVALID ";
}
return "ERROR ";
}
int
decodeExpanderLogEntries(FILE *file, unsigned char *buf, int length)
{
int offset;
U32 tstamp;
U32 eventid;
U8 size;
U8 pad;
int i;
fprintf(file, "Timestamp Event Event Data\n");
fprintf(file, "===============================================================================\n");
offset = 0;
while (offset < length)
{
/* timestamp is number of microseconds since start of day. This will wrap every 72 minutes or so. */
tstamp = get32x(*(U32 *)&(buf[offset]));
if (tstamp == 0xffffffff)
break;
offset += 4;
eventid = get32x(*(U32 *)&(buf[offset]));
offset += 4;
pad = (buf[offset] & 0xc0) >> 6;
/* data size is the size field minus the size field itself, the pad bytes, and the sizeClone field */
size = ((buf[offset] & 0x3f) * 4) - 1 - pad - 1;
/* move the offset to the start of the data bytes */
offset++;
fprintf(file, "%02d:%02d.%06d %12.12s ", tstamp / (60 * 1000 * 1000),
(tstamp % (60 * 1000 * 1000)) / (1000 * 1000),
tstamp % (1000 * 1000),
translateExpanderEventCode(eventid));
for (i=0; i < size; i++)
fprintf(file, "%c", buf[offset + i]);
fprintf(file, "\n");
offset += size + pad + 1; //the +1 is for the sizeClone field
}
return 1;
}
#define EXPANDER_LOG_SIGNATURE 0x74655065
int
doDisplayExpanderLogEntries(MPT_PORT *port)
{
int bus;
int target;
FILE *file;
int n;
unsigned char desc[4];
char name[256];
int length;
int offset;
unsigned char *region1Buf = NULL;
int region1Len;
unsigned char *region2Buf = NULL;
int region2Len;
U32 r1Unused;
U32 r2Unused;
int r1Valid = TRUE;
int r2Valid = TRUE;
int firstEntryOffset;
int expanderType;
if (selectExpander(port, &bus, &target, NULL, NULL, &expanderType) != 1)
return 0;
if (expanderType != EXPANDER_TYPE_LSI_GEN1_YETI)
{
printf("This option is only supported on LSI SAS1 expanders (Yeti).\n");
return 0;
}
n = getFileName(name, sizeof name, stdin, "output", 0);
if (n > 0)
{
file = fopen(name, "w");
if (file == NULL)
{
printf("Open failure for file %s\n", name);
perror("Error is");
return 0;
}
}
else
{
printf("Event log won't be saved\n");
return 1;
}
/* read all the data from the first region */
if (doReadBufferFull(port, bus, target, 0, 3, 6, 0, desc, sizeof desc) == 1)
{
region1Len = get3bytes(desc, 1);
if (region1Len == 0)
r1Valid = FALSE;
}
else
{
printf("Buffer 6 length is unknown, considering region 1 invalid\n");
r1Valid = FALSE;
region1Len = 0;
}
if (r1Valid)
{
length = CHUNK_SIZE;
if (length > region1Len)
length = region1Len;
region1Buf = (unsigned char *)malloc(region1Len);
offset = 0;
while (TRUE)
{
if (doReadBufferFull(port, bus, target, 0, 2, 6, offset, region1Buf+offset, length) != 1)
{
printf("There as a problem reading buffer ID 6, considering region 1 invalid\n");
r1Valid = FALSE;
break;
}
offset += length;
if (offset >= region1Len)
break;
if (length > region1Len - offset)
length = region1Len - offset;
}
}
/* read all the data from the second region */
if (doReadBufferFull(port, bus, target, 0, 3, 7, 0, desc, sizeof desc) == 1)
{
region2Len = get3bytes(desc, 1);
if (region2Len == 0)
r2Valid = FALSE;
}
else
{
printf("Buffer 7 length is unknown, considering region 2 invalid\n");
r2Valid = FALSE;
region2Len = 0;
}
if (r2Valid)
{
length = CHUNK_SIZE;
if (length > region2Len)
length = region2Len;
region2Buf = (unsigned char *)malloc(region2Len);
offset = 0;
while (TRUE)
{
if (doReadBufferFull(port, bus, target, 0, 2, 7, offset, region2Buf+offset, length) != 1)
{
printf("There as a problem reading buffer ID 7, considering region 2 invalid\n");
r2Valid = FALSE;
break;
}
offset += length;
if (offset >= region2Len)
break;
if (length > region2Len - offset)
length = region2Len - offset;
}
}
if (!r1Valid || get32x(*(U32 *)&(region1Buf[0])) != EXPANDER_LOG_SIGNATURE)
{
printf("Region 1 does not have a valid event log signature\n");
fprintf(file, "Region 1 does not have a valid event log signature\n");
r1Valid = FALSE;
r1Unused = 0;
}
else
{
fprintf(file, "- Region 1 Details -\n");
fprintf(file, " Region Length = %d bytes\n", region1Len);
fprintf(file, " Header Timestamp: %08x\n", get32x(*(U32 *)&(region1Buf[4])));
r1Unused = get32x(*(U32 *)&(region1Buf[8]));
fprintf(file, " UnusedBytes: %08x\n", r1Unused);
fprintf(file, " SizeOfLog: %04x\n", get16x(*(U16 *)&(region1Buf[12])));
fprintf(file, " FirstEntryOffset: %02x\n", region1Buf[14]);
fprintf(file, " RegionType: %02x\n", region1Buf[15]);
fprintf(file, " HeaderVersion: %02x\n", region1Buf[16]);
fprintf(file, " SequenceNumber: %02x\n\n", region1Buf[18]);
}
if (!r2Valid || get32x(*(U32 *)&(region2Buf[0])) != EXPANDER_LOG_SIGNATURE)
{
printf("Region 2 does not have a valid event log signature\n");
fprintf(file, "Region 2 does not have a valid event log signature\n");
r2Valid = FALSE;
r2Unused = 0;
}
else
{
fprintf(file, "- Region 2 Details -\n");
fprintf(file, " Region Length = %d bytes\n", region2Len);
fprintf(file, " Header Timestamp: %08x\n", get32x(*(U32 *)&(region2Buf[4])));
r2Unused = get32x(*(U32 *)&(region2Buf[8]));
fprintf(file, " UnusedBytes: %08x\n", r2Unused);
fprintf(file, " SizeOfLog: %04x\n", get16x(*(U16 *)&(region1Buf[12])));
fprintf(file, " FirstEntryOffset: %02x\n", region2Buf[14]);
fprintf(file, " RegionType: %02x\n", region2Buf[15]);
fprintf(file, " HeaderVersion: %02x\n", region2Buf[16]);
fprintf(file, " SequenceNumber: %02x\n\n", region2Buf[18]);
}
if (r1Valid && r1Unused == 0xFFFFFFFF)
{
/* region 1 is actively in use, so if region 2 is valid then it
* contains the older entries so print it first
*/
if (r2Valid)
{
if (r2Unused == 0xFFFFFFFF)
{
printf("Strange, both regions appear to be active!!\n");
fprintf(file, "Strange, both regions appear to be active!!\n");
}
fprintf(file, "\n-------------- Events from Region 2 -------------\n\n");
firstEntryOffset = region2Buf[14];
decodeExpanderLogEntries(file, &region2Buf[firstEntryOffset], region2Len - firstEntryOffset);
}
fprintf(file, "\n-------------- Events from Region 1 -------------\n\n");
firstEntryOffset = region1Buf[14];
decodeExpanderLogEntries(file, &region1Buf[firstEntryOffset], region1Len - firstEntryOffset);
}
else if (r2Valid && r2Unused == 0xFFFFFFFF)
{
/* region 2 is actively in use, so if region 1 is valid then it
* contains the older entries so print it first
*/
if (r1Valid)
{
fprintf(file, "\n-------------- Events from Region 1 -------------\n\n");
firstEntryOffset = region1Buf[14];
decodeExpanderLogEntries(file, &region1Buf[firstEntryOffset], region1Len - firstEntryOffset);
}
fprintf(file, "\n-------------- Events from Region 2 -------------\n\n");
firstEntryOffset = region2Buf[14];
decodeExpanderLogEntries(file, &region2Buf[firstEntryOffset], region2Len - firstEntryOffset);
}
else
{
printf("No valid log regions found!\n");
fprintf(file, "No valid log regions found!\n");
}
if (r1Valid)
free(region1Buf);
if (r2Valid)
free(region2Buf);
fclose(file);
return 1;
}
int
doClearExpanderLogEntries(MPT_PORT *port)
{
int bus;
int target;
unsigned char buf[4];
int expanderType;
if (selectExpander(port, &bus, &target, NULL, NULL, &expanderType) != 1)
return 0;
if (expanderType != EXPANDER_TYPE_LSI_GEN1_YETI)
{
printf("This option is only supported on LSI SAS1 expanders (Yeti).\n");
return 0;
}
printf("\nAfter clearing the log regions, no logging will occur until the expander is reset\n");
if (yesFlag == FALSE)
{
printf("\nAre you sure you want to continue? [Yes or No, default is No] ");
}
if (getYesNoAnswer(0) != 1)
return 0;
memset(buf, 0, sizeof buf);
if (doWriteBufferFull(port, bus, target, 0, 2, 6, 0, buf, sizeof buf) != 1)
printf("Error clearing region 1 (buffer ID 6)\n");
if (doWriteBufferFull(port, bus, target, 0, 2, 7, 0, buf, sizeof buf) != 1)
printf("Error clearing region 2 (buffer ID 7)\n");
printf("Clearing expander log entries is complete.\n");
return 1;
}
#define UART_DEFAULT_BUF_SIZE 1024 // 1MB
#if DOS || EFI
#define UART_MAX_BUF_SIZE 1024 // 1MB - limited by mpt_shared_t's scratch[] buffer in mpt.c
#else
#define UART_MAX_BUF_SIZE 16384 // 16MB
#endif
int
doUartDebugConsole(MPT_PORT *port)
{
Mpi2ToolboxDiagnosticCliRequest_t req;
Mpi2ToolboxDiagnosticCliReply_t rep;
int n, m;
U32 x;
U8 *output;
char name[256];
FILE *out_file;
char input[16];
int lines;
U32 size;
U32 newsize;
int firstTime;
time_t now;
U32 dataLen;
U32 finalRetLength;
#if WIN32
int maxPages;
#endif
lines = 0;
size = 0;
#if WIN32
getAdapterPropertiesMaxPages(port, &maxPages);
if (maxPages)
{
/* calculate buffer size. generally expect maxPages to return 257.
* Subtract one page to account for possible partial page and
* assume a 4k page size
*/
size = ((maxPages - 1) * 4) * 1024;
}
#endif
if (size == 0)
{
size = UART_DEFAULT_BUF_SIZE * 1024;
}
output = NULL;
if (gFlag == FALSE)
{
output = (U8 *)malloc(size);
if (output == NULL)
printf("ERROR: Unable to allocate a %d KB buffer\n", size/1024);
}
if (gFlag == TRUE || output == NULL)
{
while (1)
{
printf("Allocated buffer size for displaying CLI command output: [in KB, max is %d, default is %d] ",
UART_MAX_BUF_SIZE, size/1024);
lines++;
newsize = getNumberAnswer(1, UART_MAX_BUF_SIZE, UART_DEFAULT_BUF_SIZE) * 1024;
output = (U8 *)malloc(newsize);
if (output == NULL)
printf("ERROR: Unable to allocate a %d KB buffer\n", newsize/1024);
else
break;
}
size = newsize;
}
out_file = stdout;
while (1)
{
printf("Enter output file, or RETURN to send output to the screen: ");
lines++;
m = getStringFromArgs(name, sizeof name, stdin);
if (m > 0)
{
out_file = fopen(name, "a");
if (out_file == NULL)
{
printf("Open failure for file %s\n", name);
perror("Error is");
continue;
}
}
break;
}
printf("\n-- Starting UART Debug Console --\n(Type 'exit' to quit)\n\n");
printf("NOTE: Messages asynchronously printed to the UART console\n");
printf(" are NOT visible through this interface.\n\n");
lines+=3;
if (out_file != stdout)
{
time(&now);
fprintf(out_file, "\n%s\nStarting UART Debug Console\n(Type 'exit' to quit)\n\n", ctime(&now));
fprintf(out_file, "NOTE: Messages asynchronously printed to the UART console\n");
fprintf(out_file, " are NOT visible through this interface.\n\n");
}
firstTime = TRUE;
while (1)
{
memset(&req, 0, sizeof req);
if (firstTime)
{
strcpy((char *)req.DiagnosticCliCommand, "help");
n = 4;
}
else
{
// print the console prompt and get the user input
printf("%%");
n = getStringFromArgs((char *)(req.DiagnosticCliCommand), sizeof req.DiagnosticCliCommand, stdin);
}
if (n > 0)
{
if ( strncmp((const char *)(req.DiagnosticCliCommand), "exit", 4) == 0 )
{
break;
}
/* if writing output to a file then echo the CLI command to the file */
if (out_file != stdout && !firstTime)
fprintf(out_file, "%%%s\n", req.DiagnosticCliCommand);
memset(&rep, 0, sizeof rep);
memset(output, 0, size);
req.Function = MPI_FUNCTION_TOOLBOX;
req.Tool = MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL;
req.DataLength = set32(size);
if (doMptCommandCheck(port, &req, sizeof req - sizeof req.SGL, &rep, sizeof rep,
output, size, NULL, 0, SHORT_TIME) == 1)
{
dataLen = get32(rep.ReturnedDataLength);
#if WIN32
finalRetLength = min(dataLen, gRetDataLen);
#else
finalRetLength = dataLen;
#endif
lines = 0;
for ( x=0; x < min(finalRetLength, size); x++ )
{
fputc(output[x], out_file);
if (paged && out_file == stdout)
{
if (output[x] == '\n')
lines++;
if (lines >= paged)
{
fputs("\n--more, hit RETURN ('p' then RETURN to stop paging, 'q' then RETURN to quit)--", stdout);
if (fgets(input, 15, stdin));
printf("\n");
if (input[0] == 'p')
{
paged = 0;
}
if (input[0] == 'q')
{
break;
}
lines = 0;
}
}
}
if (!firstTime)
{
/* strictly speaking the following should just be a '>' comparison, but some
* revisions of the firmware set ReturnedDataLength as the number of bytes
* returned rather than the number of bytes that could be returned if the
* allocated buffer was large enough Using '>=' helps indicate a possible
* issue in the output.
*/
if (dataLen >= size)
{
/* print warnings to the screen as well as the output file if one is in use */
printf("\n\nWARNING: The command output was truncated!\n");
printf("The output contains %d bytes but the allocated buffer is only %d bytes\n",
dataLen, size);
lines+=2;
if (out_file != stdout)
{
printf("\n%d bytes of output written to %s\n", size, name);
lines++;
fprintf(out_file, "\n\nWARNING: The command output was truncated!\n");
fprintf(out_file, "The output contains %d bytes but the allocated buffer is only %d bytes\n",
dataLen, size);
}
}
#if WIN32
else if ( gRetDataLen < size )
{
/* print warnings to the screen as well as the output file if one is in use */
printf("\n\nWARNING: The command output was truncated!\n");
printf("The output contains %d bytes and the allocated buffer is %d bytes\n", dataLen, size);
printf("however, the MPT driver was forced to truncate the output at %d bytes.\n", gRetDataLen);
printf("This was likely due to system memory fragmentation.\n");
lines+=4;
if (out_file != stdout)
{
printf("\n%d bytes of output written to %s\n", gRetDataLen, name);
lines++;
fprintf(out_file, "\n\nWARNING: The command output was truncated!\n");
fprintf(out_file, "The output contains %d bytes and the allocated buffer is %d bytes\n", dataLen, size);
fprintf(out_file, "however, the MPT driver was forced to truncate the output at %d bytes.\n", gRetDataLen);
fprintf(out_file, "This was likely due to system memory fragmentation.\n");
}
}
#endif
else
{
if (out_file != stdout)
{
printf("\n%d bytes of output written to %s\n", dataLen, name);
lines++;
}
}
}
}
else if (firstTime &&
(get16(rep.IOCStatus) == MPI_IOCSTATUS_INVALID_FIELD ||
get16(rep.IOCStatus) == MPI_IOCSTATUS_INVALID_FUNCTION))
{
printf("There was a problem getting the UART console data.\n");
printf("This firmware may not support the UART passthrough feature.\n");
}
}
firstTime = FALSE;
}
if (out_file != stdout)
fclose(out_file);
free(output);
return 1;
}
#if WIN32
int
getAdapterPropertiesMaxPages(MPT_PORT *port, int *maxPages)
{
int status;
STORAGE_PROPERTY_QUERY query;
DWORD retLen;
STORAGE_ADAPTER_DESCRIPTOR desc;
memset(&query, 0, sizeof(query));
memset(&desc, 0, sizeof(desc));
query.PropertyId = StorageAdapterProperty;
query.QueryType = PropertyStandardQuery;
retLen = 0;
status = DeviceIoControl(port->fileHandle, IOCTL_STORAGE_QUERY_PROPERTY,
&query, sizeof(query), &desc, sizeof(desc), &retLen, NULL);
if (status == 1)
{
*maxPages = desc.MaximumPhysicalPages;
return 1;
}
else
{
*maxPages = 0;
return 0;
}
}
#endif
int
doSendPowerManagementControlMPI(MPT_PORT *port)
{
MPI2_PWR_MGMT_CONTROL_REQUEST req;
MPI2_PWR_MGMT_CONTROL_REPLY rep;
int input;
int mpt_return;
memset( &req, 0, sizeof(req) );
memset( &rep, 0, sizeof(rep) );
req.Function = MPI2_FUNCTION_PWR_MGMT_CONTROL;
// Query for the data
input = 0x01;
printf("Feature: [1=DA_PHY, 2=Port Width Mod, 3=PCIE, 4=IOC, 5=Global, default is %d] ", input);
input = getNumberAnswer(0, 255, input);
req.Feature = input;
input = 0x00;
printf("Chain Offset: [0 to 255, default is %d] ", input);
input = getNumberAnswer(0, 255, input);
req.ChainOffset = input;
switch (req.Feature)
{
case MPI2_PM_CONTROL_FEATURE_IOC_SPEED:
input = 0x01;
printf("IOC Speed (Parameter1): [1=100%%, 2=50%%, 4=25%%, 8=12.5%%, default is %d] ", input);
input = getNumberAnswer(0, 255, input);
req.Parameter1 = input;
break;
case MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND:
input = 0x00;
printf("PHY number (Parameter1): [0 to 255, default is %d] ", input);
input = getNumberAnswer(0, 255, input);
req.Parameter1 = input;
input = 0x01;
printf("IOC Action (Parameter2): [1=Partial, 2=Slumber, 3=Exit, default is %d] ", input);
input = getNumberAnswer(0, 255, input);
req.Parameter2 = input;
break;
case MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION:
input = 0x00;
printf("Modulation Group Number (Parameter1): [0 to 255, default is %d] ", input);
input = getNumberAnswer(0, 255, input);
req.Parameter1 = input;
input = 0x01;
printf("IOC Action (Parameter2): [1=Request, 2=Change, 3=Relinquish, default is %d] ", input);
input = getNumberAnswer(0, 255, input);
req.Parameter2 = input;
if ( req.Parameter2 == MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION )
{
input = 0x03;
printf("New Level (Parameter3): [0=25%%, 1=50%%, 2=75%%, 3=100%%, default is %d] ", input);
input = getNumberAnswer(0, 255, input);
req.Parameter3 = input;
}
break;
case MPI2_PM_CONTROL_FEATURE_PCIE_LINK:
input = 0x00;
printf("Speed (Parameter1): [0=2.5G, 1=5G, 2=8G, default is %d] ", input);
input = getNumberAnswer(0, 255, input);
req.Parameter1 = input;
input = 0x01;
printf("Width (Parameter2): [1=X1, 2=X2, 4=X4, 8=X8, default is %d] ", input);
input = getNumberAnswer(0, 255, input);
req.Parameter2 = input;
break;
case MPI2_PM_CONTROL_FEATURE_GLOBAL_PWR_MGMT_MODE:
input = 0x01;
printf("Action (Parameter1): [1=Take, 2=Change, 3=Release, default is %d] ", input);
input = getNumberAnswer(0, 255, input);
req.Parameter1 = input;
if (req.Parameter1 == MPI2_PM_CONTROL_PARAM1_CHANGE_GLOBAL_MODE)
{
input = 0x01;
printf("Mode (Parameter2): [1=Full, 8=Reduced, 64=Standby, default is %d] ", input);
input = getNumberAnswer(0, 255, input);
req.Parameter2 = input;
}
break;
default:
input = 0x00;
printf("Parameter1: [0 to 255, default is %d] ", input);
input = getNumberAnswer(0, 255, input);
req.Parameter1 = input;
input = 0x00;
printf("Parameter2: [0 to 255, default is %d] ", input);
input = getNumberAnswer(0, 255, input);
req.Parameter2 = input;
input = 0x00;
printf("Parameter3: [0 to 255, default is %d] ", input);
input = getNumberAnswer(0, 255, input);
req.Parameter3 = input;
input = 0x00;
printf("Parameter4: [0 to 255, default is %d] ", input);
input = getNumberAnswer(0, 255, input);
req.Parameter4 = input;
break;
} //switch(function)
// Send the message
mpt_return = doMptCommand(port, &req, sizeof req, &rep, sizeof rep, NULL, 0, NULL, 0, SHORT_TIME);
if(mpt_return != 1)
{
printf("ERROR: Could not send MPI message\n");
return -1;
}
printf("\n\n Reply:\n");
printf(" Feature: [0x%08X]\n", rep.Feature);
printf(" IOCStatus: [0x%08X] (%s)\n", get16(rep.IOCStatus), translateIocStatus(get16(rep.IOCStatus)));
printf(" IOCLogInfo: [0x%08X]\n", get32(rep.IOCLogInfo));
return 1;
}
// IoUnit7 is Read-only, so this function only displays the info contained in the page
int
doIoUnit7Settings(MPT_PORT *port)
{
Mpi2IOUnitPage7_t page;
if (getConfigPage(port, MPI2_CONFIG_PAGETYPE_IO_UNIT, 7, 0, &page, sizeof page) != 1)
{
printf("Couldn't get IOUnitPage7\n");
printf(" IOC Status: %s", translateIocStatus(port->ioc_status) );
return 0;
}
printf(" CurrentPowerMode: 0x%02X\n", page.CurrentPowerMode );
printf(" PreviousPowerMode: 0x%02X\n", page.PreviousPowerMode );
printf(" PCIeWidth: 0x%02X\n", page.PCIeWidth );
printf(" PCIeSpeed: 0x%02X\n", page.PCIeSpeed );
printf(" ProcessorState: 0x%08X\n", get32(page.ProcessorState) );
printf(" PowerManagementCapabilities: 0x%08X\n", get32(page.PowerManagementCapabilities) );
printf(" IOCTemperature: 0x%04X\n", get16(page.IOCTemperature) );
printf(" IOCTemperatureUnits: 0x%02X\n", page.IOCTemperatureUnits );
printf(" IOCSpeed: 0x%02X\n", page.IOCSpeed );
printf(" BoardTemperature: 0x%04X\n", get16(page.BoardTemperature) );
printf(" BoardTemperatureUnits: 0x%02X\n", page.BoardTemperatureUnits );
return 1;
}
int
doSasIoUnit8Settings(MPT_PORT *port)
{
Mpi2SasIOUnitPage8_t page;
int input;
memset( &page, 0, sizeof(page) );
if (getConfigPage(port, MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 8, 0, &page, sizeof page) != 1)
{
printf("\nCouldn't get SasIoUnitPage8\n");
printf(" IOC Status: %s", translateIocStatus(port->ioc_status) );
return 0;
}
// Dump the page first
printf(" PowerManagementCapabilities: 0x%08X\n", get32(page.PowerManagementCapabilities) );
printf(" TxRxSleepStatus: 0x%02X\n\n", page.TxRxSleepStatus );
printf("Edit this page? [0=no, 1=yes, default is %d] ", 0);
input = getNumberAnswer(0, 1, 0);
if(input == 1)
{
input = page.PowerManagementCapabilities;
printf("PowerManagementCapabilities: [0 to 0xFFFFFFF, default is %x] ", input);
input = getNumberAnswerHex(0, 0xFFFFFFF, input);
page.PowerManagementCapabilities = set32(input);
input = page.TxRxSleepStatus;
printf("TxRxSleepStatus: [0 to 0xFF, default is %x] ", input);
input = getNumberAnswerHex(0, 0xFF, input);
page.TxRxSleepStatus = input;
if (setConfigPage(port, MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 8, 0, &page, sizeof page) != 1)
{
printf("\nFailed to save changes to NVRAM!\n");
printf(" IOC Status: %s", translateIocStatus(port->ioc_status) );
return 0;
}
}
return 1;
}
int
dumpSasDevicePage0sLong(MPT_PORT *port)
{
Mpi2SasDevicePage0_t SASDevicePage0;
U32 handle;
int flags;
int deviceIndex;
U32 info;
int bit;
deviceIndex = 0;
handle = 0xffff;
// Decode DeviceInfo first
printf(" | |S|S|S|S|S|S|S|S| | |A| |\n");
printf(" |T|A|M|T|S|A|M|T|S| | |T| |\n");
printf(" |y|T|P|P|P|T|P|P|P| |L|A|S|\n");
printf(" |p|A|i|i|i|A|t|t|t|D|S|P|E|\n");
printf("SASAddress PhyNum Handle |e|h|n|n|n|d|a|a|a|A|I|I|P|\n");
printf("---------------------------------|-|-|-|-|-|-|-|-|-|-|-|-|-|\n");
while (TRUE)
{
if (getConfigPage(port, MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, handle,
&SASDevicePage0, sizeof SASDevicePage0) != 1)
break;
handle = get16(SASDevicePage0.DevHandle);
info = get32(SASDevicePage0.DeviceInfo);
printf("%08x%08x", get32(SASDevicePage0.SASAddress.High), get32(SASDevicePage0.SASAddress.Low));
printf(" %04d", SASDevicePage0.PhyNum );
printf(" %04d", handle );
printf(" |%d|", info & 0x03); // Device type
for( bit = 3; bit <= 14; bit++)
{
printf("%d|", info & (1<<bit) ? 1 : 0);
}
if(wFlag)
printf( " %08x", info);
printf("\n");
deviceIndex++;
} // next device
printf("\n\n");
deviceIndex = 0;
handle = 0xffff;
//Now decode the flags 0 1 2 3 4 5 6 7 8 9 a b c d e f
printf(" |P| | | | | |S|4|U|P|A|P|S|F|F|U|\n");
printf(" |r| | |S| | |M|8|s|r|s|a|l|P|P|n|\n");
printf(" |e| | |A|F|N|A|L|u|e|y|r|u|C|E|a|\n");
printf(" |s| | |T|A|C|R|B|p|s|n|t|m|a|n|u|\n");
printf("SASAddress PhyNum Handle |e| | |A|U|Q|T|A|p|e|c|i|b|p|a|t|\n");
printf("---------------------------------|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|\n");
while (TRUE)
{
if (getConfigPage(port, MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, handle,
&SASDevicePage0, sizeof SASDevicePage0) != 1)
break;
handle = get16(SASDevicePage0.DevHandle);
flags = get16(SASDevicePage0.Flags);
printf("%08x%08x", get32(SASDevicePage0.SASAddress.High), get32(SASDevicePage0.SASAddress.Low));
printf(" %04d", SASDevicePage0.PhyNum );
printf(" %04d", handle );
printf(" |");
for( bit = 0; bit <= 15; bit++)
{
printf("%d|", flags & (1<<bit) ? 1 : 0);
}
if(wFlag)
printf( " %08x", flags);
printf("\n");
deviceIndex++;
} // next device
return 1;
}
int
doExpanderUart(MPT_PORT *port)
{
int bus;
int target;
FILE *out_file;
char input[16];
char name[256];
unsigned char command[85];
unsigned char output[1024];
time_t now;
int n;
int offset;
int index;
int lines;
U16 *cmd_seq_id;
U16 seq_id;
U16 ret_seq_id;
U16 bytes_read;
U8 transfer_complete;
U8 drop_paged_output;
lines = 0;
if (bringOnline(port) != 1)
return 0;
if (selectExpander(port, &bus, &target, NULL, NULL, NULL) != 1)
return 0;
out_file = stdout;
while (1)
{
printf("Enter output file, or RETURN to send output to the screen: ");
lines++;
n = getStringFromArgs(name, sizeof name, stdin);
if (n > 0)
{
out_file = fopen(name, "a");
if (out_file == NULL)
{
printf("Open failure for file %s\n", name);
perror("Error is");
out_file = stdout;
continue;
}
}
break;
}
printf("\n-- Starting Expander UART Console --\n(Type 'exit' to quit)\n\n");
printf("NOTE: Messages asynchronously printed to the UART console\n");
printf(" are NOT visible through this interface.\n\n");
lines+=3;
if (out_file != stdout)
{
time(&now);
fprintf(out_file, "\n%s\nStarting Expander UART Console --\n(Type 'exit' to quit)\n\n", ctime(&now));
fprintf(out_file, "NOTE: Messages asynchronously printed to the UART console\n");
fprintf(out_file, " are NOT visible through this interface.\n\n");
}
cmd_seq_id = (U16*)(&command[2]);
seq_id = 0;
command[0] = 0x0;
command[1] = 0x0;
while (1)
{
drop_paged_output = 0;
printf("\n cmd >");
memset(&(command[4]), 0x0, 81);
n = getStringFromArgs((char*)&(command[4]), 80, stdin);
if (n > 0)
{
if (strncmp ((const char *)(&(command[4])), "exit", 5) == 0)
{
break;
}
/* if writing output to a file then echo the CLI command to the file */
if (out_file != stdout)
fprintf(out_file, "\n cmd >%s\n", &(command[4]));
*cmd_seq_id = set16x(seq_id);
doWriteBufferFull(port, bus, target, 0, 1, 0xc4, 0, command, sizeof command);
transfer_complete = 0;
}
else
{
transfer_complete = 1;
}
offset = 0;
lines = 0;
memset(output, 0, sizeof output);
while (!transfer_complete)
{
n = doReadBufferFull(port, bus, target, 0, 1, 0xc4, offset, output, sizeof output);
if (!n)
{
if (out_file != stdout && out_file != NULL)
{
fclose(out_file);
}
return 0;
}
transfer_complete = output[0] & 0x8;
ret_seq_id = get16x(*(U16*)(&output[2]));
bytes_read = get16x(*(U16*)(&output[4]));
/* offset is incremented by the number of bytes of data plus the
read response header size
*/
offset += ( bytes_read + 6 );
if (ret_seq_id != seq_id)
{
printf("Sequence ID mismatch \n");
lines++;
}
/* Output data starts at byte 6, only print if not dumping output
and index is within valid ranges for the response bytes and the
output buffer
*/
for ( index=6;
drop_paged_output == 0 && index < bytes_read + 6 && index < sizeof output;
index++ )
{
fputc(output[index], out_file);
if (paged && out_file == stdout)
{
if (output[index] == '\n')
lines++;
if (lines >= paged)
{
fputs("\n--more, hit RETURN ('p' then RETURN to stop paging, 'q' then RETURN to quit)--", stdout);
if (fgets(input, 15, stdin));
printf("\n");
if (input[0] == 'p')
{
paged = 0;
}
if (input[0] == 'q')
{
drop_paged_output = 1;
break;
}
lines = 0;
}
}
}
if (out_file != stdout)
{
printf("\n%d bytes of output written to %s\n", bytes_read, name);
lines++;
}
/* Sleep for a second if the expander didn't output anything
before checking again
*/
if (!transfer_complete && ( bytes_read == 0 ))
sleep(1);
} // keep getting more response data
seq_id++;
} // next command
if (out_file != stdout && out_file != NULL)
fclose(out_file);
return 1;
}
#if EFI
#undef main
#undef malloc
#undef free
#include "helper.c"
#endif
/* vi: set sw=4 ts=4 sts=4 et :iv */