mirror of
https://github.com/Fohdeesha/lab-docu.git
synced 2024-11-29 11:15:23 +01:00
43218 lines
1.4 MiB
43218 lines
1.4 MiB
/***************************************************************************
|
|
* *
|
|
* 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(×tamp));
|
|
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, ®Access);
|
|
|
|
*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, ®ion2Buf[firstEntryOffset], region2Len - firstEntryOffset);
|
|
}
|
|
fprintf(file, "\n-------------- Events from Region 1 -------------\n\n");
|
|
firstEntryOffset = region1Buf[14];
|
|
decodeExpanderLogEntries(file, ®ion1Buf[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, ®ion1Buf[firstEntryOffset], region1Len - firstEntryOffset);
|
|
}
|
|
fprintf(file, "\n-------------- Events from Region 2 -------------\n\n");
|
|
firstEntryOffset = region2Buf[14];
|
|
decodeExpanderLogEntries(file, ®ion2Buf[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 */
|