#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <printAttrs.h>
#include <smhbaapi.h>
#define TABLEN 2
typedef struct inputArgs {
int wwnCount;
char **wwn_argv;
uint64_t portWWN;
char *hbaName;
int pflag;
int *wwn_flag;
} inputArg_t;
typedef struct tgt_mapping {
SMHBA_SCSIENTRY tgtentry;
uchar_t inq_vid[8];
uchar_t inq_pid[16];
uchar_t inq_dtype;
struct tgt_mapping *next;
}tgt_mapping;
typedef struct smhba_rp_tree {
SMHBA_PORTATTRIBUTES portattr;
SMHBA_SAS_PORT sasattr;
tgt_mapping *first_entry;
int printed;
struct smhba_rp_tree *parent;
struct smhba_rp_tree *child;
struct smhba_rp_tree *sibling;
}rp_tree_t;
struct lun {
uchar_t val[8];
};
typedef struct rep_luns_rsp {
uint32_t length;
uint32_t rsrvd;
struct lun lun[1];
} rep_luns_rsp_t;
static int g_printHBA = 0;
typedef struct _sas_elem {
char name[256];
int index;
}sas_elem_t;
static int
sas_rp_tree_insert(rp_tree_t **rproot, rp_tree_t *rpnode);
static int
sas_rp_tree_print(HBA_HANDLE handle, char *adapterName,
HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
rp_tree_t *rpnode, inputArg_t *input, int gident,
int *printPort);
static int
sas_rp_tree_print_desc(HBA_HANDLE handle, HBA_UINT32 portIndex,
SMHBA_PORTATTRIBUTES *port, rp_tree_t *desc,
inputArg_t *input, int lident, int gident);
static int
sas_print_rpnode(inputArg_t *input,
rp_tree_t *rpnode, int lident, int gident);
static void sas_rp_tree_free(rp_tree_t *rproot);
typedef int (*processPortFunc)(HBA_HANDLE handle, char *adapterName,
HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
static int processHBA(inputArg_t *input,
processPortFunc processPort);
static int isPortWWNInArgv(inputArg_t *input, PHBA_WWN pWWN);
static int isStringInArgv(inputArg_t *input, const char *adapterName);
static boolean_t compareLUName(char *cmdArg, char *osName);
static discoveredDevice *LUList = NULL;
static targetPortList_t *gTargetPortList = NULL;
static int handleHBA(SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input,
int numberOfPorts, const char *adapterName);
static int handleHBAPort(HBA_HANDLE handle, char *adapterName,
HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
static int processHBAPortPhyInfo(HBA_HANDLE handle, HBA_UINT32 portIndex,
SMHBA_PORTATTRIBUTES *port, int pflag);
static int processHBAPortPhyStat(HBA_HANDLE handle, HBA_UINT32 portIndex,
int phyIndex, PSMHBA_SAS_PHY phyattrs, int pflag);
static int handleExpander(HBA_HANDLE handle, char *adapterName,
HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
static int handleTargetPort(HBA_HANDLE handle, char *adapterName,
HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
static int handleLogicalUnit(HBA_HANDLE handle, char *adapterName,
HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
static int
searchTargetPortMappingData(HBA_HANDLE handle, HBA_UINT32 portIndex,
SMHBA_PORTATTRIBUTES *port, SMHBA_SAS_PORT *sasattr,
struct targetPortConfig *configData);
static int searchTargetPort(HBA_HANDLE handle, HBA_UINT32 portIndex,
SMHBA_PORTATTRIBUTES *port, SMHBA_PORTATTRIBUTES *targetattr,
SMHBA_SAS_PORT *sasattr, int pflag);
static int
searchDevice(PSMHBA_SCSIENTRY entryP, HBA_HANDLE handle, HBA_WWN hbaPortWWN,
HBA_WWN domainPortWWN, char *portName, int pflag);
HBA_STATUS get_domainPort(HBA_HANDLE handle,
int portindex, PSMHBA_PORTATTRIBUTES port,
HBA_WWN *pdomainPort);
static int
sas_name_comp(const char *name1, const char *name2);
static void
sas_elem_sort(sas_elem_t *array, int nelem);
int
sas_util_list_hba(int hbaCount, char **hba_argv, cmdOptions_t *options)
{
HBA_STATUS status;
int processHBA_flags = 0;
inputArg_t input;
int err_cnt = 0;
for (; options->optval; options++) {
switch (options->optval) {
case 'v':
processHBA_flags |= PRINT_VERBOSE;
break;
default:
break;
}
}
if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
(void) fprintf(stderr, "%s %s\n",
gettext("Failed to load SM-HBA libraries."
"Reason:"), getHBAStatus(status));
err_cnt++;
return (err_cnt);
}
(void) memset(&input, 0, sizeof (input));
input.wwnCount = hbaCount;
input.wwn_argv = hba_argv;
input.pflag = processHBA_flags;
err_cnt += processHBA(&input, NULL);
(void) HBA_FreeLibrary();
return (err_cnt);
}
int
sas_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options)
{
HBA_STATUS status;
int processHBA_flags = 0;
inputArg_t input;
int err_cnt = 0;
char hbaName[256] = {'\0'};
for (; options->optval; options++) {
switch (options->optval) {
case 'a':
(void) strlcpy(hbaName,
options->optarg, sizeof (hbaName));
break;
case 'y':
processHBA_flags |= PRINT_PHY;
break;
case 'l':
processHBA_flags |= PRINT_PHY_LINKSTAT;
break;
case 'v':
processHBA_flags |= PRINT_VERBOSE;
break;
default:
break;
}
}
if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
(void) fprintf(stderr, "%s %s\n",
gettext("Failed to load SM-HBA libraries."
"Reason:"), getHBAStatus(status));
err_cnt++;
return (err_cnt);
}
(void) memset(&input, 0, sizeof (input));
input.wwnCount = wwnCount;
input.wwn_argv = wwn_argv;
input.hbaName = hbaName;
input.pflag = processHBA_flags;
err_cnt += processHBA(&input, handleHBAPort);
(void) HBA_FreeLibrary();
return (err_cnt);
}
int
sas_util_list_expander(int wwnCount, char **wwn_argv, cmdOptions_t *options)
{
HBA_STATUS status;
int processHBA_flags = 0;
char hbaPort[MAXPATHLEN + 1] = {0};
inputArg_t input;
int err_cnt = 0;
for (; options->optval; options++) {
switch (options->optval) {
case 'p':
(void) strlcpy(hbaPort, options->optarg,
sizeof (hbaPort));
break;
case 't':
processHBA_flags |= PRINT_TARGET_PORT;
break;
case 'v':
processHBA_flags |= PRINT_VERBOSE;
break;
default:
break;
}
}
if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
(void) fprintf(stderr, "%s %s\n",
gettext("Failed to load SM-HBA libraries."
"Reason:"), getHBAStatus(status));
err_cnt++;
return (err_cnt);
}
(void) memset(&input, 0, sizeof (input));
input.wwnCount = wwnCount;
input.wwn_argv = wwn_argv;
input.pflag = processHBA_flags;
input.hbaName = hbaPort;
err_cnt += processHBA(&input, handleExpander);
(void) HBA_FreeLibrary();
return (err_cnt);
}
int
sas_util_list_targetport(int tpCount, char **tpArgv, cmdOptions_t *options)
{
HBA_STATUS status;
int processHBA_flags = 0;
int tp, tpFound;
inputArg_t input;
targetPortList_t *tpListWalk;
int err_cnt = 0;
uint64_t tmpAddr;
for (; options->optval; options++) {
switch (options->optval) {
case 's':
processHBA_flags |= PRINT_TARGET_SCSI;
break;
case 'v':
processHBA_flags |= PRINT_VERBOSE;
break;
default:
break;
}
}
if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
(void) fprintf(stderr, "%s %s\n",
gettext("Failed to load SM-HBA libraries."
"Reason:"), getHBAStatus(status));
err_cnt++;
return (err_cnt);
}
(void) memset(&input, 0, sizeof (input));
input.wwnCount = tpCount;
input.wwn_argv = tpArgv;
input.pflag = processHBA_flags;
err_cnt += processHBA(&input, handleTargetPort);
if (tpCount == 0) {
for (tpListWalk = gTargetPortList; tpListWalk != NULL;
tpListWalk = tpListWalk->next) {
err_cnt += printTargetPortInfo(tpListWalk, input.pflag);
}
} else {
err_cnt = 0;
for (tp = 0; tp < tpCount; tp++) {
errno = 0;
tmpAddr = strtoull(tpArgv[tp], NULL, 16);
if ((tmpAddr == 0) && (errno != 0)) {
err_cnt++;
continue;
}
for (tpListWalk = gTargetPortList, tpFound = B_FALSE;
tpListWalk != NULL;
tpListWalk = tpListWalk->next) {
if (wwnConversion(tpListWalk->sasattr.
LocalSASAddress.wwn) == tmpAddr) {
tpFound = B_TRUE;
break;
}
}
if (tpFound == B_FALSE) {
(void) fprintf(stderr,
"Error: Target Port %s Not Found \n",
tpArgv[tp]);
err_cnt++;
}
}
for (tp = 0; tp < tpCount; tp++) {
errno = 0;
tmpAddr = strtoull(tpArgv[tp], NULL, 16);
if ((tmpAddr == 0) && (errno != 0)) {
continue;
}
for (tpListWalk = gTargetPortList, tpFound = B_FALSE;
tpListWalk != NULL;
tpListWalk = tpListWalk->next) {
if (wwnConversion(tpListWalk->sasattr.
LocalSASAddress.wwn) == tmpAddr) {
err_cnt += printTargetPortInfo(
tpListWalk,
processHBA_flags);
}
}
}
}
(void) HBA_FreeLibrary();
return (err_cnt);
}
static int
processHBA(inputArg_t *input, processPortFunc processPort)
{
int numAdapters = 0;
int matchedHBAs = 0;
int matchedHBAPorts = 0;
int hbaPortExist = 0;
HBA_STATUS status;
HBA_HANDLE handle;
HBA_UINT32 numberOfPorts = 0;
int portIndex = 0;
HBA_PORTTYPE porttype;
SMHBA_LIBRARYATTRIBUTES libattrs;
SMHBA_ADAPTERATTRIBUTES attrs;
SMHBA_PORTATTRIBUTES port;
SMHBA_SAS_PORT sasattrs;
int i, sum, ret = 0;
int remote_avail = 0;
int local_avail = 0;
sas_elem_t *adpt_array = NULL;
sas_elem_t *port_array = NULL;
numAdapters = HBA_GetNumberOfAdapters();
if (numAdapters == 0) {
(void) fprintf(stderr, "%s\n",
gettext("Error: No Adapters Found."));
return (++ret);
}
if (input->wwnCount && (processPort != handleTargetPort) &&
(processPort != handleLogicalUnit)) {
input->wwn_flag = calloc(input->wwnCount, sizeof (int));
if (input->wwn_flag == NULL) {
(void) fprintf(stderr, "%s\n",
gettext("No enough memory on heap"));
return (++ret);
}
}
adpt_array = calloc(numAdapters, sizeof (sas_elem_t));
if (adpt_array == NULL) {
(void) fprintf(stderr, "%s\n",
gettext("No enough memory on heap"));
if (input->wwn_flag) {
free(input->wwn_flag);
input->wwn_flag = NULL;
}
return (++ret);
}
for (i = 0; i < numAdapters; i++) {
status =
SMHBA_GetVendorLibraryAttributes(i, &libattrs);
if (status != 1) {
continue;
}
status = HBA_GetAdapterName(i, adpt_array[i].name);
if (status != HBA_STATUS_OK) {
(void) fprintf(stderr, "%s %d %s %s\n",
gettext("Error: Failed to get the name for"
" HBA index"),
i, gettext("Reason:"),
getHBAStatus(status));
ret++;
continue;
}
adpt_array[i].index = i;
}
sas_elem_sort(adpt_array, numAdapters);
for (i = 0; i < numAdapters; i++) {
int times = 0;
if (adpt_array[i].name[0] != '\0') {
if ((handle = HBA_OpenAdapter(adpt_array[i].name))
== 0) {
(void) fprintf(stderr, "%s %s.\n",
gettext("Error: Failed to open adapter"),
adpt_array[i].name);
ret++;
continue;
}
} else {
continue;
}
(void) memset(&attrs, 0, sizeof (attrs));
status = SMHBA_GetAdapterAttributes(handle, &attrs);
while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
status == HBA_STATUS_ERROR_BUSY) &&
times++ < HBA_MAX_RETRIES) {
(void) sleep(1);
status = SMHBA_GetAdapterAttributes(handle,
&attrs);
}
if (status != HBA_STATUS_OK) {
(void) fprintf(stderr, "%s %s %s %s\n",
gettext("Error: Failed to get attributes"
" for HBA "), adpt_array[i].name,
gettext("Reason:"),
getHBAStatus(status));
HBA_CloseAdapter(handle);
ret++;
continue;
}
status = SMHBA_GetNumberOfPorts(handle, &numberOfPorts);
if (status != HBA_STATUS_OK) {
(void) fprintf(stderr, "%s %s %s %s\n",
gettext("Error: Failed to get number of ports "
"for HBA"), adpt_array[i].name,
gettext("Reason:"),
getHBAStatus(status));
HBA_CloseAdapter(handle);
ret++;
continue;
}
if (processPort == NULL) {
matchedHBAs += handleHBA(&attrs, input,
numberOfPorts, adpt_array[i].name);
HBA_CloseAdapter(handle);
continue;
} else if (processPort == handleHBAPort) {
if (input->hbaName[0] != '\0') {
if (strcmp(input->hbaName,
adpt_array[i].name) == 0) {
matchedHBAs++;
} else {
continue;
}
} else {
matchedHBAs++;
}
} else {
matchedHBAs++;
}
if (numberOfPorts) {
port_array = calloc(numberOfPorts, sizeof (sas_elem_t));
}
for (portIndex = 0; portIndex < numberOfPorts; portIndex++) {
if ((status = SMHBA_GetPortType(handle,
portIndex, &porttype)) != HBA_STATUS_OK) {
(void) fprintf(stderr, "%s %s %s %s\n",
gettext("Failed to get adapter port type "
"for HBA"), adpt_array[i].name,
gettext("Reason:"),
getHBAStatus(status));
ret++;
continue;
}
if (porttype != HBA_PORTTYPE_SASDEVICE) {
continue;
}
(void) memset(&port, 0, sizeof (port));
(void) memset(&sasattrs, 0, sizeof (sasattrs));
port.PortSpecificAttribute.SASPort = &sasattrs;
if ((status = SMHBA_GetAdapterPortAttributes(
handle, portIndex, &port)) != HBA_STATUS_OK) {
(void) fprintf(stderr, "%s %s %s %d %s %s\n",
gettext("Error: Failed to get port "
"attributes for HBA"), adpt_array[i].name,
gettext("port index"), portIndex,
gettext("Reason:"),
getHBAStatus(status));
ret++;
continue;
}
(void) strlcpy(port_array[portIndex].name,
port.OSDeviceName,
sizeof (port_array[portIndex].name));
port_array[portIndex].index = portIndex;
}
if (port_array) {
sas_elem_sort(port_array, numberOfPorts);
}
local_avail += numberOfPorts;
g_printHBA = 0;
for (portIndex = 0;
portIndex < numberOfPorts;
portIndex++) {
if (port_array[portIndex].name[0] == '\0') {
continue;
}
(void) memset(&port, 0, sizeof (port));
(void) memset(&sasattrs, 0, sizeof (sasattrs));
port.PortSpecificAttribute.SASPort = &sasattrs;
(void) SMHBA_GetAdapterPortAttributes(handle,
port_array[portIndex].index, &port);
if (processPort == handleHBAPort) {
if (input->wwnCount > 0) {
if (isStringInArgv(input,
port.OSDeviceName)) {
hbaPortExist = 1;
if (g_printHBA == 0) {
(void) fprintf(stdout,
"%s %s\n",
"HBA Name:",
adpt_array[i].name);
g_printHBA = 1;
}
}
} else {
hbaPortExist = 1;
if (g_printHBA == 0) {
(void) fprintf(stdout,
"%s %s\n",
"HBA Name:",
adpt_array[i].name);
g_printHBA = 1;
}
}
}
if (processPort == handleExpander) {
if (input->hbaName[0] != '\0') {
if (strcmp(input->hbaName,
port.OSDeviceName) == 0)
hbaPortExist = 1;
} else
hbaPortExist = 1;
}
if (processPort == handleTargetPort) {
hbaPortExist = 1;
}
if (processPort == handleLogicalUnit) {
hbaPortExist = 1;
}
if (hbaPortExist) {
if (port.PortSpecificAttribute.SASPort->
NumberofDiscoveredPorts) {
remote_avail++;
}
ret += (*processPort)(handle,
adpt_array[i].name,
port_array[portIndex].index, &port,
&attrs, input);
hbaPortExist = 0;
matchedHBAPorts++;
}
}
if (port_array) {
free(port_array);
port_array = NULL;
}
HBA_CloseAdapter(handle);
}
if (adpt_array) {
free(adpt_array);
adpt_array = NULL;
}
if (matchedHBAs == 0) {
(void) fprintf(stderr, "%s\n",
gettext("Error: Matching HBA not found."));
if (input->wwn_flag) {
free(input->wwn_flag);
input->wwn_flag = NULL;
}
return (++ret);
} else if (processPort == NULL) {
for (i = 0; i < input->wwnCount; i++) {
if (input->wwn_flag[i] == 0) {
(void) fprintf(stderr, "%s %s %s\n",
gettext("Error: HBA"),
input->wwn_argv[i],
gettext("not found."));
ret++;
}
}
} else {
if (local_avail > 0 && matchedHBAPorts == 0) {
(void) fprintf(stderr, "%s\n",
gettext("Error: Matching HBA Port "
"not found."));
if (input->wwn_flag) {
free(input->wwn_flag);
input->wwn_flag = NULL;
}
return (++ret);
} else if (local_avail == 0) {
(void) fprintf(stderr, "%s\n",
gettext("Error: No HBA Port Configured."));
if (input->wwn_flag) {
free(input->wwn_flag);
input->wwn_flag = NULL;
}
return (++ret);
} else if (processPort == handleHBAPort) {
for (i = 0; i < input->wwnCount; i++) {
if (input->wwn_flag[i] == 0) {
(void) fprintf(stderr, "%s %s %s\n",
gettext("Error: HBA Port"),
input->wwn_argv[i],
gettext("not found."));
ret++;
}
}
}
}
if (processPort == handleExpander) {
if (input->wwnCount > 0) {
sum = 0;
for (i = 0; i < input->wwnCount; i++) {
sum += input->wwn_flag[i];
}
if (sum == 0) {
(void) fprintf(stderr, gettext("Error: "
"Matching SAS Address not found.\n"));
free(input->wwn_flag);
input->wwn_flag = NULL;
return (++ret);
}
for (i = 0; i < input->wwnCount; i++) {
if (input->wwn_flag[i] == 0) {
(void) fprintf(stderr, "%s %s %s\n",
gettext("Error: SAS Address"),
input->wwn_argv[i],
gettext("not found."));
ret++;
}
}
}
}
if (input->wwn_flag) {
free(input->wwn_flag);
input->wwn_flag = NULL;
}
return (ret);
}
static int
processHBAPortPhyInfo(HBA_HANDLE handle, HBA_UINT32 portIndex,
SMHBA_PORTATTRIBUTES *port, int pflag)
{
int phyIndex = 0, err_cnt = 0;
HBA_UINT32 numphys = 0;
HBA_STATUS status = 0;
SMHBA_SAS_PHY phyattrs;
if (port == NULL)
return (++err_cnt);
numphys = port->PortSpecificAttribute.SASPort->NumberofPhys;
if (numphys == 0)
return (0);
if ((pflag & PRINT_PHY) || (pflag & PRINT_PHY_LINKSTAT))
(void) fprintf(stdout, "%s\n", " Phy Information:");
else
return (0);
for (phyIndex = 0; phyIndex < numphys; phyIndex++) {
(void) memset(&phyattrs, 0, sizeof (phyattrs));
status = SMHBA_GetSASPhyAttributes(
handle, portIndex, phyIndex, &phyattrs);
if (status != HBA_STATUS_OK) {
(void) fprintf(stderr, "%s %d %s %s\n",
gettext("Failed to get SAS Phy attributes"
"phyIndex"), phyIndex,
gettext("Reason:"),
getHBAStatus(status));
err_cnt++;
continue;
}
if (pflag & PRINT_PHY)
printHBAPortPhyInfo(&phyattrs);
if (pflag & PRINT_PHY_LINKSTAT)
err_cnt += processHBAPortPhyStat(handle,
portIndex, phyIndex, &phyattrs, pflag);
}
return (err_cnt);
}
static int
processHBAPortPhyStat(HBA_HANDLE handle, HBA_UINT32 portIndex, int phyIndex,
PSMHBA_SAS_PHY phyattrs, int pflag)
{
HBA_STATUS status = 0;
SMHBA_PHYSTATISTICS phystat;
SMHBA_SASPHYSTATISTICS sasphystat;
if ((pflag & PRINT_PHY) == 0) {
(void) fprintf(stdout, "%s %d\n",
" Identifier:", phyattrs->PhyIdentifier);
}
(void) memset(&phystat, 0, sizeof (phystat));
(void) memset(&sasphystat, 0, sizeof (sasphystat));
phystat.SASPhyStatistics = &sasphystat;
status = SMHBA_GetPhyStatistics(handle, portIndex, phyIndex, &phystat);
if (status != HBA_STATUS_OK) {
(void) fprintf(stdout, "%s\n",
" Link Error Statistics:");
(void) fprintf(stderr, "%s\n",
gettext(" Failed to retrieve Link "
"Error Statistics!"));
return (1);
}
printHBAPortPhyStatistics(phystat.SASPhyStatistics);
return (0);
}
static int
isPortWWNInArgv(inputArg_t *input, PHBA_WWN pWWN)
{
int port_wwn_counter = 0;
int portfound = 0;
uint64_t hbaWWN;
for (port_wwn_counter = 0;
port_wwn_counter < input->wwnCount;
port_wwn_counter++) {
hbaWWN = strtoull(input->wwn_argv[port_wwn_counter], NULL,
16);
if (hbaWWN == 0 && errno != 0)
continue;
if (wwnConversion(pWWN->wwn) == hbaWWN) {
if (input->wwn_flag) {
input->wwn_flag[port_wwn_counter]++;
}
portfound = 1;
}
}
return (portfound);
}
static int
isStringInArgv(inputArg_t *input, const char *stringName)
{
int counter = 0;
int found = 0;
for (counter = 0;
counter < input->wwnCount;
counter++) {
if (strcmp(input->wwn_argv[counter],
stringName) == 0) {
if (input->wwn_flag)
input->wwn_flag[counter]++;
found = 1;
}
}
return (found);
}
static int handleHBA(SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input,
int numberOfPorts, const char *adapterName)
{
int matchingHBA = 1;
if (input->wwnCount == 0) {
printHBAInfo(attrs, input->pflag, numberOfPorts, adapterName);
} else {
if (isStringInArgv(input, adapterName)) {
printHBAInfo(attrs,
input->pflag, numberOfPorts, adapterName);
} else {
matchingHBA = 0;
}
}
return (matchingHBA);
}
static int handleHBAPort(HBA_HANDLE handle, char *adapterName,
HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
{
int ret = 0;
printHBAPortInfo(port, attrs, input->pflag);
ret = processHBAPortPhyInfo(handle, portIndex, port, input->pflag);
return (ret);
}
static int handleExpander(HBA_HANDLE handle, char *adapterName,
HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
{
SMHBA_PORTATTRIBUTES attr;
SMHBA_SAS_PORT sasport;
HBA_STATUS status;
int ret = 0;
int i, numberOfRP;
rp_tree_t *rpnode;
rp_tree_t *rproot = NULL;
rp_tree_t *unsolved_head = NULL;
rp_tree_t *unsolved_tail = NULL;
rp_tree_t *unsolved_sentinel = NULL;
int printPort = 0;
int numberOfEXP = 0;
int unsolved_inserted = 0;
int unsolved_left = 0;
int disco_port_fail = 0;
boolean_t firstPrinted = B_FALSE;
(void) memset(&attr, 0, sizeof (attr));
(void) memset(&sasport, 0, sizeof (sasport));
attr.PortSpecificAttribute.SASPort = &sasport;
if ((numberOfRP = port->PortSpecificAttribute.SASPort->
NumberofDiscoveredPorts) == 0) {
return (ret);
}
for (i = 0; i < numberOfRP; i++) {
rpnode = calloc(1, sizeof (rp_tree_t));
rpnode->portattr.PortSpecificAttribute.SASPort =
&rpnode->sasattr;
status = SMHBA_GetDiscoveredPortAttributes(handle,
portIndex, i, &rpnode->portattr);
if (status != HBA_STATUS_OK) {
disco_port_fail++;
free(rpnode);
ret++;
continue;
}
if (rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) {
numberOfEXP++;
}
if (rproot == NULL && memcmp(port->
PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
rpnode->sasattr.AttachedSASAddress.wwn,
sizeof (HBA_WWN)) == 0) {
rproot = rpnode;
} else {
if (rproot == NULL ||
sas_rp_tree_insert(&rproot, rpnode) != 0) {
if (unsolved_head == NULL) {
unsolved_head = rpnode;
unsolved_tail = rpnode;
} else {
rpnode->sibling = unsolved_head;
unsolved_head = rpnode;
}
}
}
}
if (disco_port_fail) {
(void) fprintf(stderr, "%s %d %s %s\n",
gettext("Error: Failed to get attributes for"),
disco_port_fail,
gettext("connected ports of HBA port"),
port->OSDeviceName);
}
if (numberOfEXP == 0) {
while (unsolved_head) {
unsolved_tail =
unsolved_head->sibling;
free(unsolved_head);
unsolved_head = unsolved_tail;
}
if (rproot) sas_rp_tree_free(rproot);
return (ret);
}
unsolved_sentinel = unsolved_tail;
while (unsolved_head) {
rpnode = unsolved_head;
unsolved_head = unsolved_head->sibling;
if (unsolved_head == NULL)
unsolved_tail = NULL;
rpnode->sibling = NULL;
if (sas_rp_tree_insert(&rproot, rpnode) != 0) {
unsolved_tail->sibling = rpnode;
unsolved_tail = rpnode;
if (rpnode == unsolved_sentinel) {
if (unsolved_inserted == 0) {
unsolved_left++;
break;
} else {
unsolved_inserted = 0;
unsolved_sentinel = unsolved_tail;
}
}
} else {
unsolved_inserted++;
}
}
if (unsolved_left) {
ret++;
(void) fprintf(stderr, "%s %s\n",
gettext("Error: Failed to establish expander topology on"),
port->OSDeviceName);
(void) fprintf(stderr, "%s\n",
gettext(" Folowing port(s) are unresolved."));
while (unsolved_head) {
unsolved_tail =
unsolved_head->sibling;
(void) fprintf(stderr, "%s%016llx ",
firstPrinted ? "" : "\t",
wwnConversion(unsolved_head->sasattr.
LocalSASAddress.wwn));
if (firstPrinted == B_FALSE) firstPrinted = B_TRUE;
free(unsolved_head);
unsolved_head = unsolved_tail;
}
(void) fprintf(stderr, "\n");
ret += sas_rp_tree_print(handle, adapterName, portIndex,
port, rproot, input, 2 * TABLEN, &printPort);
} else {
ret += sas_rp_tree_print(handle, adapterName, portIndex,
port, rproot, input, 2 * TABLEN, &printPort);
}
if (rproot) sas_rp_tree_free(rproot);
return (ret);
}
static int handleTargetPort(HBA_HANDLE handle, char *adapterName,
HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
{
HBA_STATUS status;
SMHBA_PORTATTRIBUTES targetattr;
SMHBA_SAS_PORT sasattr;
int i;
int ret = 0;
int disco_port_fail = 0;
targetattr.PortSpecificAttribute.SASPort = &sasattr;
for (i = 0; i < port->PortSpecificAttribute.SASPort->
NumberofDiscoveredPorts; i++) {
status = SMHBA_GetDiscoveredPortAttributes(handle,
portIndex, i, &targetattr);
if (status != HBA_STATUS_OK) {
disco_port_fail++;
} else {
if (targetattr.PortType != HBA_PORTTYPE_SASEXPANDER) {
ret += searchTargetPort(handle, portIndex, port,
&targetattr, &sasattr, input->pflag);
}
}
}
if (disco_port_fail) {
ret++;
(void) fprintf(stderr, "%s %d %s %s\n",
gettext("Error: Failed to get attributes for"),
disco_port_fail,
gettext("connected ports of HBA port"),
port->OSDeviceName);
}
return (ret);
}
static boolean_t
compareLUName(char *cmdArg, char *osName)
{
boolean_t isSame = B_FALSE;
char dev1[MAXPATHLEN], dev2[MAXPATHLEN];
char *ch1, *ch2;
if (strcmp(cmdArg, osName) == 0) {
isSame = B_TRUE;
} else {
(void) strlcpy(dev1, cmdArg, MAXPATHLEN);
(void) strlcpy(dev2, osName, MAXPATHLEN);
if (((ch1 = strrchr(dev1, ',')) != NULL) &&
((ch2 = strrchr(dev2, ',')) != NULL)) {
*ch1 = *ch2 = '\0';
if (strcmp(dev1, dev2) == 0) {
isSame = B_TRUE;
}
} else if ((strncmp(dev1, "/dev/", 5) == 0) &&
(strncmp(dev2, "/dev/", 5) == 0)) {
if ((strstr(dev1, "dsk") != NULL) &&
((strstr(dev2, "dsk") != NULL))) {
if (((ch1 = strrchr(dev1, 's')) != NULL) &&
((ch2 = strrchr(dev2, 's')) != NULL)) {
*ch1 = *ch2 = '\0';
if (strcmp(dev1, dev2) == 0) {
isSame = B_TRUE;
}
}
} else {
if (strcmp(dev1, dev2) == 0) {
isSame = B_TRUE;
}
}
}
}
return (isSame);
}
int
sas_util_list_logicalunit(int luCount, char **luArgv, cmdOptions_t *options)
{
HBA_STATUS status;
int processHBA_flags = 0;
int lu;
boolean_t pathFound;
boolean_t verbose;
inputArg_t input;
discoveredDevice *LUListWalk = NULL;
int err_cnt = 0;
for (; options->optval; options++) {
if (options->optval == 'v') {
processHBA_flags |= PRINT_VERBOSE;
}
}
if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
(void) fprintf(stderr, "%s %s\n",
gettext("Failed to load SM-HBA libraries."
"Reason:"), getHBAStatus(status));
err_cnt++;
return (err_cnt);
}
(void) memset(&input, 0, sizeof (input));
input.pflag = processHBA_flags;
input.wwnCount = luCount;
input.wwn_argv = luArgv;
err_cnt += processHBA(&input, handleLogicalUnit);
verbose = (input.pflag & PRINT_VERBOSE) ? B_TRUE : B_FALSE;
if (luCount == 0) {
for (LUListWalk = LUList; LUListWalk != NULL;
LUListWalk = LUListWalk->next) {
err_cnt += printOSDeviceNameInfo(LUListWalk, verbose);
}
} else {
err_cnt = 0;
for (lu = 0; lu < luCount; lu++) {
for (LUListWalk = LUList, pathFound = B_FALSE;
LUListWalk != NULL;
LUListWalk = LUListWalk->next) {
if (compareLUName(luArgv[lu],
LUListWalk->OSDeviceName)) {
pathFound = B_TRUE;
break;
}
}
if (pathFound == B_FALSE) {
(void) fprintf(stderr,
"Error: Logical Unit %s Not Found \n",
luArgv[lu]);
err_cnt++;
}
}
for (lu = 0; lu < luCount; lu++) {
for (LUListWalk = LUList; LUListWalk != NULL;
LUListWalk = LUListWalk->next) {
if (compareLUName(luArgv[lu],
LUListWalk->OSDeviceName)) {
err_cnt += printOSDeviceNameInfo(
LUListWalk,
verbose);
}
}
}
}
(void) HBA_FreeLibrary();
return (err_cnt);
}
static int handleLogicalUnit(HBA_HANDLE handle, char *adapterName,
HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
{
HBA_STATUS status;
SMHBA_TARGETMAPPING *map;
HBA_WWN hbaPortWWN, domainPortWWN;
char *portName = NULL;
int numentries;
int count = 0;
int ret = 0;
hbaPortWWN = port->PortSpecificAttribute.SASPort->LocalSASAddress;
portName = port->OSDeviceName;
status = get_domainPort(handle, portIndex, port, &domainPortWWN);
switch (status) {
case HBA_STATUS_OK:
break;
case HBA_STATUS_ERROR_NOT_SUPPORTED:
return (ret);
case HBA_STATUS_ERROR:
default:
return (++ret);
}
if ((map = calloc(1, sizeof (*map))) == NULL) {
(void) fprintf(stderr, "%s\n",
gettext("No enough memory on heap."));
return (++ret);
}
map->NumberOfEntries = 1;
status = SMHBA_GetTargetMapping(handle,
hbaPortWWN, domainPortWWN, map);
if (status == HBA_STATUS_ERROR_MORE_DATA) {
numentries = map->NumberOfEntries;
free(map);
map = calloc(1, sizeof (HBA_UINT32) +
(numentries * sizeof (SMHBA_SCSIENTRY)));
if (map == NULL) {
(void) fprintf(stderr, "%s\n",
gettext("No enough memory on heap."));
return (++ret);
}
map->NumberOfEntries = numentries;
status = SMHBA_GetTargetMapping(handle,
hbaPortWWN, domainPortWWN, map);
}
if (status != HBA_STATUS_OK) {
(void) fprintf(stderr, "%s %016llx %s %s\n",
gettext("Error: Failed to get SCSI mapping data for "
"the HBA port"), wwnConversion(hbaPortWWN.wwn),
gettext("Reason:"),
getHBAStatus(status));
free(map);
return (++ret);
}
for (count = 0; count < map->NumberOfEntries; count++) {
ret += searchDevice(
&(map->entry[count]), handle, hbaPortWWN, domainPortWWN,
portName, input->pflag);
}
free(map);
return (ret);
}
static int
searchTargetPortMappingData(HBA_HANDLE handle, HBA_UINT32 portIndex,
SMHBA_PORTATTRIBUTES *port, SMHBA_SAS_PORT *sasattr,
struct targetPortConfig *configData)
{
int ret = 0;
HBA_STATUS status;
SMHBA_TARGETMAPPING *map = NULL;
HBA_WWN hbaPortWWN, domainPortWWN;
int numentries, count;
targetPortMappingData_t *TPMapData;
struct scsi_inquiry inq;
struct scsi_extended_sense sense;
HBA_UINT32 responseSize, senseSize = 0;
uchar_t rawLUNs[DEFAULT_LUN_LENGTH], *lun_string;
HBA_UINT8 scsiStatus;
rep_luns_rsp_t *lun_resp;
int lunNum, numberOfLun, lunCount;
uint32_t lunlength, tmp_lunlength;
uint64_t sasLUN;
SMHBA_SCSILUN smhbaLUN;
hbaPortWWN = port->PortSpecificAttribute.SASPort->
LocalSASAddress;
status = get_domainPort(handle, portIndex, port, &domainPortWWN);
if (status == HBA_STATUS_OK) {
if ((map = calloc(1, sizeof (*map))) == NULL) {
(void) fprintf(stderr, "%s\n",
gettext("No enough memory on heap."));
return (++ret);
}
map->NumberOfEntries = 1;
status = SMHBA_GetTargetMapping(handle, hbaPortWWN,
domainPortWWN, map);
if (status == HBA_STATUS_ERROR_MORE_DATA) {
numentries = map->NumberOfEntries;
free(map);
map = calloc(1, sizeof (HBA_UINT32) +
(numentries * sizeof (SMHBA_SCSIENTRY)));
if (map == NULL) {
(void) fprintf(stderr, "%s\n",
gettext("No enough memory on heap."));
return (++ret);
}
map->NumberOfEntries = numentries;
status = SMHBA_GetTargetMapping(handle,
hbaPortWWN, domainPortWWN, map);
}
if (status != HBA_STATUS_OK) {
ret++;
free(map);
map = NULL;
}
}
responseSize = DEFAULT_LUN_LENGTH;
senseSize = sizeof (struct scsi_extended_sense);
(void) memset(&sense, 0, sizeof (sense));
status = SMHBA_ScsiReportLUNs(
handle,
hbaPortWWN,
sasattr->LocalSASAddress,
domainPortWWN,
(void *)rawLUNs,
&responseSize,
&scsiStatus,
(void *) &sense, &senseSize);
if (status != HBA_STATUS_OK) {
configData->reportLUNsFailed = B_TRUE;
if (map != NULL) {
for (count = 0; count < map->NumberOfEntries; count++) {
if (memcmp(map->entry[count].PortLun.
PortWWN.wwn, sasattr->LocalSASAddress.wwn,
sizeof (HBA_WWN)) == 0) {
TPMapData = calloc(1,
sizeof (targetPortMappingData_t));
if (TPMapData == NULL) {
(void) fprintf(stderr, "%s\n",
gettext("No enough "
"memory."));
free(map);
return (++ret);
}
TPMapData->mappingExist = B_TRUE;
TPMapData->osLUN =
map->entry[count].ScsiId.ScsiOSLun;
(void) strlcpy(TPMapData->osDeviceName,
map->entry[count].ScsiId.
OSDeviceName,
sizeof (TPMapData->osDeviceName));
TPMapData->inq_vid[0] = '\0';
TPMapData->inq_pid[0] = '\0';
TPMapData->inq_dtype = DTYPE_UNKNOWN;
if (configData->map == NULL) {
configData->map = TPMapData;
} else {
TPMapData->next =
configData->map->next;
configData->map = TPMapData;
}
}
}
}
(void) free(map);
return (++ret);
}
lun_resp = (rep_luns_rsp_t *)((void *)rawLUNs);
(void) memcpy(&tmp_lunlength, &(lun_resp->length),
sizeof (tmp_lunlength));
lunlength = ntohl(tmp_lunlength);
(void) memcpy(&numberOfLun, &lunlength, sizeof (numberOfLun));
for (lunCount = 0; lunCount < (numberOfLun / 8); lunCount++) {
TPMapData = calloc(1,
sizeof (targetPortMappingData_t));
if (TPMapData == NULL) {
(void) fprintf(stderr, "%s\n",
gettext("No enough memory."));
free(map);
return (++ret);
}
(void) memcpy(&TPMapData->reportLUN, lun_resp->
lun[lunCount].val, sizeof (SMHBA_SCSILUN));
responseSize = sizeof (struct scsi_inquiry);
senseSize = sizeof (struct scsi_extended_sense);
(void) memset(&inq, 0, sizeof (struct scsi_inquiry));
(void) memset(&sense, 0, sizeof (sense));
sasLUN = ntohll(wwnConversion(lun_resp->lun[lunCount].val));
(void) memcpy(&smhbaLUN, &sasLUN, sizeof (SMHBA_SCSILUN));
status = SMHBA_ScsiInquiry(
handle,
hbaPortWWN,
sasattr->LocalSASAddress,
domainPortWWN,
smhbaLUN,
0,
0,
(void *) &inq, &responseSize,
&scsiStatus,
(void *) &sense, &senseSize);
if (status != HBA_STATUS_OK) {
TPMapData->inq_vid[0] = '\0';
TPMapData->inq_pid[0] = '\0';
TPMapData->inq_dtype = DTYPE_UNKNOWN;
TPMapData->inquiryFailed = B_TRUE;
} else {
(void) memcpy(TPMapData->inq_vid, inq.inq_vid,
sizeof (TPMapData->inq_vid));
(void) memcpy(TPMapData->inq_pid, inq.inq_pid,
sizeof (TPMapData->inq_pid));
TPMapData->inq_dtype = inq.inq_dtype;
}
if (map != NULL) {
for (count = 0; count < map->NumberOfEntries; count++) {
if ((memcmp(map->entry[count].PortLun.
PortWWN.wwn, sasattr->LocalSASAddress.wwn,
sizeof (HBA_WWN)) == 0) &&
(memcmp(&(map->entry[count].PortLun.
TargetLun), &smhbaLUN,
sizeof (SMHBA_SCSILUN))
== 0)) {
TPMapData->mappingExist = B_TRUE;
TPMapData->osLUN =
map->entry[count].ScsiId.ScsiOSLun;
(void) strlcpy(TPMapData->osDeviceName,
map->entry[count].ScsiId.
OSDeviceName,
sizeof (TPMapData->osDeviceName));
break;
}
}
if (count == map->NumberOfEntries) {
TPMapData->osDeviceName[0] = '\0';
lun_string = lun_resp->lun[lunCount].val;
lunNum = ((lun_string[0] & 0x3F) << 8) |
lun_string[1];
TPMapData->osLUN = lunNum;
}
} else {
TPMapData->osDeviceName[0] = '\0';
lun_string = lun_resp->lun[lunCount].val;
lunNum = ((lun_string[0] & 0x3F) << 8) |
lun_string[1];
TPMapData->osLUN = lunNum;
}
if (configData->map == NULL) {
configData->map = TPMapData;
} else {
TPMapData->next = configData->map->next;
configData->map = TPMapData;
}
}
free(map);
return (ret);
}
static int
searchTargetPort(HBA_HANDLE handle, HBA_UINT32 portIndex,
SMHBA_PORTATTRIBUTES *port, SMHBA_PORTATTRIBUTES *targetattr,
SMHBA_SAS_PORT *sasattr, int pflag)
{
int ret = 0;
HBA_WWN expander;
HBA_WWN domainPortWWN;
targetPortList_t *discoveredTP, *newTP;
targetPortConfig_t *TPConfig, *newConfig, *prevConfig;
boolean_t foundTP = B_FALSE;
boolean_t foundConfig = B_FALSE;
int status;
SMHBA_PORTATTRIBUTES tgtattr;
SMHBA_SAS_PORT tgtsasport;
int expanderValid = 0;
status = get_domainPort(handle, portIndex, port, &domainPortWWN);
switch (status) {
case HBA_STATUS_OK:
break;
case HBA_STATUS_ERROR_NOT_SUPPORTED:
return (ret);
case HBA_STATUS_ERROR:
default:
return (++ret);
}
for (discoveredTP = gTargetPortList; discoveredTP != NULL;
discoveredTP = discoveredTP->next) {
if (memcmp((void *)sasattr->LocalSASAddress.wwn,
(void *)discoveredTP->sasattr.LocalSASAddress.wwn,
sizeof (HBA_WWN)) == 0) {
if (((pflag & PRINT_VERBOSE) == 0) &&
((pflag & PRINT_TARGET_SCSI) == 0)) {
return (ret);
}
foundTP = B_TRUE;
break;
}
}
if (foundTP == B_TRUE) {
if (memcmp((void *)port->PortSpecificAttribute.SASPort->
LocalSASAddress.wwn, (void *)sasattr->
AttachedSASAddress.wwn, sizeof (HBA_WWN)) == 0) {
(void) memset((void *)expander.wwn, 0,
sizeof (HBA_WWN));
expanderValid = 1;
} else {
if (wwnConversion(sasattr->AttachedSASAddress.wwn)
!= 0) {
(void) memcpy((void *)expander.wwn,
(void *)sasattr->AttachedSASAddress.wwn,
sizeof (HBA_WWN));
(void) memset(&tgtattr, 0, sizeof (tgtattr));
(void) memset(&tgtsasport, 0,
sizeof (tgtsasport));
tgtattr.PortSpecificAttribute.SASPort
= &tgtsasport;
status = SMHBA_GetPortAttributesByWWN(handle,
sasattr->AttachedSASAddress, domainPortWWN,
&tgtattr);
if (status == HBA_STATUS_OK && tgtattr.PortType
== HBA_PORTTYPE_SASEXPANDER) {
expanderValid = 1;
}
}
}
for (TPConfig = discoveredTP->configEntry,
foundConfig = B_FALSE; TPConfig != NULL;
TPConfig = TPConfig->next) {
if ((strcmp(TPConfig->hbaPortName,
port->OSDeviceName) == 0) &&
(memcmp((void *)expander.wwn, (void *)TPConfig->
expanderSASAddr.wwn,
sizeof (HBA_WWN)) == 0)) {
foundConfig = B_TRUE;
break;
}
}
if (foundConfig == B_FALSE) {
newConfig = (targetPortConfig_t *)calloc(1,
sizeof (targetPortConfig_t));
if (newConfig == NULL) {
(void) fprintf(stderr,
"%s\n", strerror(errno));
return (++ret);
}
(void) strlcpy(newConfig->hbaPortName, port->
OSDeviceName, sizeof (newConfig->hbaPortName));
(void) memcpy((void *)newConfig->expanderSASAddr.wwn,
(void *)expander.wwn, sizeof (HBA_WWN));
newConfig->expanderValid = expanderValid;
if (discoveredTP->configEntry == NULL) {
discoveredTP->configEntry = newConfig;
} else {
TPConfig = discoveredTP->configEntry;
prevConfig = TPConfig;
while (TPConfig != NULL &&
sas_name_comp(newConfig->hbaPortName,
TPConfig->hbaPortName) > 0) {
prevConfig = TPConfig;
TPConfig = TPConfig->next;
}
if (TPConfig == prevConfig) {
newConfig->next = TPConfig;
discoveredTP->configEntry = newConfig;
} else {
newConfig->next = TPConfig;
prevConfig->next = newConfig;
}
}
if ((pflag & PRINT_TARGET_SCSI) == 0) {
return (0);
} else {
return (searchTargetPortMappingData(
handle, portIndex, port,
sasattr, newConfig));
}
}
} else {
newTP = (targetPortList_t *)calloc(1,
sizeof (targetPortList_t));
if (newTP == NULL) {
(void) fprintf(stderr, "%s\n", strerror(errno));
return (++ret);
}
(void) memcpy((void *)&newTP->targetattr, (void *)targetattr,
sizeof (SMHBA_PORTATTRIBUTES));
(void) memcpy((void *)&newTP->sasattr, (void *)sasattr,
sizeof (SMHBA_SAS_PORT));
newConfig = (targetPortConfig_t *)calloc(1,
sizeof (targetPortConfig_t));
if (newConfig == NULL) {
(void) fprintf(stderr, "%s\n", strerror(errno));
free(newTP);
return (++ret);
}
(void) strlcpy(newConfig->hbaPortName, port->OSDeviceName,
sizeof (newConfig->hbaPortName));
if (memcmp((void *)port->PortSpecificAttribute.SASPort->
LocalSASAddress.wwn, (void *)sasattr->
AttachedSASAddress.wwn, sizeof (HBA_WWN)) == 0) {
(void) memset((void *)newConfig->expanderSASAddr.wwn,
0, sizeof (HBA_WWN));
} else {
(void) memcpy((void *)newConfig->expanderSASAddr.wwn,
(void *)sasattr->AttachedSASAddress.wwn,
sizeof (HBA_WWN));
(void) memset(&tgtattr, 0, sizeof (tgtattr));
(void) memset(&tgtsasport, 0, sizeof (tgtsasport));
tgtattr.PortSpecificAttribute.SASPort = &tgtsasport;
status = SMHBA_GetPortAttributesByWWN(handle,
sasattr->AttachedSASAddress, domainPortWWN,
&tgtattr);
if (status == HBA_STATUS_OK && tgtattr.PortType ==
HBA_PORTTYPE_SASEXPANDER) {
expanderValid = 1;
}
newConfig->expanderValid = expanderValid;
}
newTP->configEntry = newConfig;
newTP->next = gTargetPortList;
gTargetPortList = newTP;
if ((pflag & PRINT_TARGET_SCSI) == 0) {
return (0);
} else {
return (searchTargetPortMappingData(
handle, portIndex, port, sasattr, newConfig));
}
}
return (ret);
}
static int
searchDevice(PSMHBA_SCSIENTRY entryP,
HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN domainPortWWN,
char *portName, int pflag)
{
HBA_STATUS status;
int ret = 0;
discoveredDevice *discoveredLU, *newDevice;
portList *portElem, *newPort, *prevElem;
tgtPortWWNList *newTgtWWN, *TgtWWNList;
boolean_t foundDevice = B_FALSE;
boolean_t foundPort = B_FALSE;
struct scsi_inquiry inq;
HBA_UINT32 responseSize, senseSize = 0;
HBA_UINT8 inq_status;
SMHBA_SCSILUN smhbaLUN;
struct scsi_extended_sense sense;
if (entryP->ScsiId.OSDeviceName[0] == '\0') {
return (ret);
}
for (discoveredLU = LUList; discoveredLU != NULL;
discoveredLU = discoveredLU->next) {
if (strcmp(entryP->ScsiId.OSDeviceName,
discoveredLU->OSDeviceName) == 0) {
if ((pflag & PRINT_VERBOSE) == 0) {
return (ret);
}
foundDevice = B_TRUE;
break;
}
}
if (foundDevice == B_TRUE) {
for (portElem = discoveredLU->HBAPortList,
foundPort = B_FALSE; portElem != NULL;
portElem = portElem->next) {
if (strcmp(portElem->portName,
portName) == 0) {
foundPort = B_TRUE;
break;
}
}
if (foundPort == B_FALSE) {
newPort = (portList *)calloc(1, sizeof (portList));
if (newPort == NULL) {
(void) fprintf(stderr, "%s\n", strerror(errno));
return (++ret);
}
(void) strlcpy(newPort->portName, portName,
sizeof (newPort->portName));
portElem = discoveredLU->HBAPortList;
prevElem = portElem;
while (portElem != NULL &&
sas_name_comp(newPort->portName, portElem->portName)
> 0) {
prevElem = portElem;
portElem = portElem->next;
}
if (portElem == prevElem) {
newPort->next = portElem;
discoveredLU->HBAPortList = newPort;
} else {
newPort->next = portElem;
prevElem->next = newPort;
}
newPort->tgtPortWWN = (tgtPortWWNList *)calloc(1,
sizeof (tgtPortWWNList));
if (newPort->tgtPortWWN == NULL) {
(void) fprintf(stderr, "%s\n", strerror(errno));
return (++ret);
}
(void) memcpy((void *)&(newPort->tgtPortWWN->portWWN),
(void *)&(entryP->PortLun.PortWWN),
sizeof (HBA_WWN));
newPort->tgtPortWWN->scsiOSLun =
entryP->ScsiId.ScsiOSLun;
} else {
for (TgtWWNList = portElem->tgtPortWWN;
TgtWWNList != NULL;
TgtWWNList = TgtWWNList->next) {
if (memcmp(&TgtWWNList->portWWN,
&entryP->PortLun.PortWWN,
sizeof (HBA_WWN)) == 0)
return (0);
}
newTgtWWN = (tgtPortWWNList *)calloc(1,
sizeof (tgtPortWWNList));
if (newTgtWWN == NULL) {
(void) fprintf(stderr, "%s\n", strerror(errno));
return (++ret);
}
newTgtWWN->next = portElem->tgtPortWWN;
portElem->tgtPortWWN = newTgtWWN;
(void) memcpy((void *)&(newTgtWWN->portWWN),
(void *)&(entryP->PortLun.PortWWN),
sizeof (HBA_WWN));
newTgtWWN->scsiOSLun =
entryP->ScsiId.ScsiOSLun;
}
} else {
newDevice = (discoveredDevice *)calloc(1,
sizeof (discoveredDevice));
if (newDevice == NULL) {
(void) fprintf(stderr, "%s\n", strerror(errno));
return (++ret);
}
newDevice->next = LUList;
LUList = newDevice;
(void) strlcpy(newDevice->OSDeviceName,
entryP->ScsiId.OSDeviceName,
sizeof (newDevice->OSDeviceName));
if ((pflag & PRINT_VERBOSE) == 0) {
return (0);
}
newDevice->HBAPortList = (portList *)calloc(1,
sizeof (portList));
if (newDevice->HBAPortList == NULL) {
(void) fprintf(stderr, "%s\n", strerror(errno));
return (++ret);
}
(void) strlcpy(newDevice->HBAPortList->portName,
portName, sizeof (newDevice->HBAPortList->portName));
newDevice->HBAPortList->tgtPortWWN =
(tgtPortWWNList *)calloc(1, sizeof (tgtPortWWNList));
if (newDevice->HBAPortList->tgtPortWWN == NULL) {
(void) fprintf(stderr, "%s\n", strerror(errno));
return (++ret);
}
(void) memcpy((void *)&(newDevice->HBAPortList->\
tgtPortWWN->portWWN),
(void *)&(entryP->PortLun.PortWWN),
sizeof (HBA_WWN));
newDevice->HBAPortList->tgtPortWWN->scsiOSLun =
entryP->ScsiId.ScsiOSLun;
responseSize = sizeof (struct scsi_inquiry);
senseSize = sizeof (struct scsi_extended_sense);
(void) memset(&inq, 0, sizeof (struct scsi_inquiry));
(void) memset(&sense, 0, sizeof (sense));
(void) memcpy(&smhbaLUN, &entryP->PortLun.TargetLun,
sizeof (smhbaLUN));
status = SMHBA_ScsiInquiry(
handle,
hbaPortWWN,
entryP->PortLun.PortWWN,
domainPortWWN,
smhbaLUN,
0,
0,
(void *) &inq, &responseSize,
&inq_status,
(void *) &sense, &senseSize);
if (status != HBA_STATUS_OK) {
newDevice->VID[0] = '\0';
newDevice->PID[0] = '\0';
newDevice->dType = DTYPE_UNKNOWN;
newDevice->inquiryFailed = B_TRUE;
ret++;
} else {
(void) memcpy(newDevice->VID, inq.inq_vid,
sizeof (newDevice->VID));
(void) memcpy(newDevice->PID, inq.inq_pid,
sizeof (newDevice->PID));
newDevice->dType = inq.inq_dtype;
newDevice->inquiryFailed = B_FALSE;
}
}
return (ret);
}
static int
sas_rp_tree_insert(rp_tree_t **rproot,
rp_tree_t *rpnode)
{
HBA_UINT8 *wwn1, *wwn2, *wwn3;
rp_tree_t *node_ptr;
int ret = 0;
if (rproot == NULL) {
(void) fprintf(stderr, "%s\n",
gettext("Error: NULL rproot"));
return (1);
}
if (rpnode == NULL) {
(void) fprintf(stderr, "%s\n",
gettext("Error: NULL rpnode"));
return (1);
}
if (*rproot == NULL) {
*rproot = rpnode;
return (0);
}
wwn1 = (*rproot)->sasattr.LocalSASAddress.wwn;
wwn2 = (*rproot)->sasattr.AttachedSASAddress.wwn;
wwn3 = rpnode->sasattr.AttachedSASAddress.wwn;
if (memcmp(wwn1, wwn3, sizeof (HBA_WWN)) == 0) {
(void) sas_rp_tree_insert(&(*rproot)->child, rpnode);
rpnode->parent = *rproot;
} else if (memcmp(wwn2, wwn3, sizeof (HBA_WWN)) == 0) {
if (rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) {
rpnode->sibling = *rproot;
*rproot = rpnode;
} else {
node_ptr = *rproot;
while (node_ptr->sibling != NULL)
node_ptr = node_ptr->sibling;
node_ptr->sibling = rpnode;
}
rpnode->parent = (*rproot)->parent;
} else {
if ((*rproot)->child) {
ret = sas_rp_tree_insert(&(*rproot)->child, rpnode);
}
if ((*rproot)->child == NULL || ret != 0) {
if ((*rproot)->sibling) {
ret = sas_rp_tree_insert(&(*rproot)->sibling,
rpnode);
} else
ret = 1;
}
return (ret);
}
return (0);
}
static int
sas_rp_tree_print(HBA_HANDLE handle, char *adapterName,
HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
rp_tree_t *rpnode, inputArg_t *input,
int gident, int *printPort)
{
int ret = 0, lident;
if (rpnode == NULL)
return (ret);
lident = gident;
if (input->wwnCount > 0) {
lident = 2 * TABLEN;
if ((rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) ||
!isPortWWNInArgv(input,
&rpnode->sasattr.LocalSASAddress)) {
ret += sas_rp_tree_print(handle, adapterName,
portIndex, port, rpnode->child, input,
gident + 2 * TABLEN, printPort);
ret += sas_rp_tree_print(handle, adapterName,
portIndex, port, rpnode->sibling, input,
gident, printPort);
return (ret);
}
}
if ((rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) ||
(input->pflag & PRINT_TARGET_PORT)) {
if (g_printHBA == 0) {
(void) fprintf(stdout, "%s %s\n",
"HBA Name:", adapterName);
g_printHBA = 1;
}
if (*printPort == 0) {
(void) fprintf(stdout, "%s%s %s\n",
getIndentSpaces(TABLEN),
"HBA Port Name:", port->OSDeviceName);
*printPort = 1;
}
ret += sas_print_rpnode(input, rpnode, lident, gident);
}
if (input->pflag & PRINT_TARGET_PORT) {
if (input->wwnCount > 0) {
if (rpnode->portattr.PortType ==
HBA_PORTTYPE_SASEXPANDER) {
ret += sas_rp_tree_print_desc(handle,
portIndex, port, rpnode->child,
input,
lident + 2 * TABLEN,
gident + 2 * TABLEN);
}
}
}
ret += sas_rp_tree_print(handle, adapterName,
portIndex, port, rpnode->child, input,
gident + 2 * TABLEN, printPort);
ret += sas_rp_tree_print(handle, adapterName,
portIndex, port, rpnode->sibling, input,
gident, printPort);
return (ret);
}
static void sas_rp_tree_free(rp_tree_t *rproot)
{
tgt_mapping *cur, *next;
if (rproot == NULL)
return;
if (rproot->child) {
sas_rp_tree_free(rproot->child);
}
if (rproot->sibling) {
sas_rp_tree_free(rproot->sibling);
}
cur = rproot->first_entry;
while (cur != NULL) {
next = cur->next;
free(cur);
cur = next;
}
free(rproot);
}
static int
sas_rp_tree_print_desc(HBA_HANDLE handle, HBA_UINT32 portIndex,
SMHBA_PORTATTRIBUTES *port, rp_tree_t *desc,
inputArg_t *input, int lident, int gident)
{
int ret = 0;
rp_tree_t *rp_node;
if (desc == NULL)
return (ret);
for (rp_node = desc; rp_node != NULL; rp_node = rp_node->sibling) {
ret += sas_print_rpnode(input, rp_node, lident, gident);
}
return (ret);
}
static int
sas_print_rpnode(inputArg_t *input,
rp_tree_t *rpnode, int lident, int gident)
{
int ret = 0;
if (rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) {
(void) fprintf(stdout, "%s%s(Tier %d): %016llx\n",
getIndentSpaces(lident),
"Expander SAS Address",
gident / (2 * TABLEN),
wwnConversion(rpnode->sasattr.LocalSASAddress.wwn));
} else {
(void) fprintf(stdout, "%s%s %016llx\n",
getIndentSpaces(lident),
"Target Port SAS Address:",
wwnConversion(rpnode->sasattr.LocalSASAddress.wwn));
}
if (input->pflag & PRINT_VERBOSE) {
if (rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) {
(void) fprintf(stdout, "%s%s %s\n",
getIndentSpaces(TABLEN + lident),
"Type:",
getStateString(rpnode->portattr.PortType,
porttype_string));
} else {
(void) fprintf(stdout, "%s%s %s\n",
getIndentSpaces(TABLEN + lident),
"OS Device Name:",
rpnode->portattr.OSDeviceName);
(void) fprintf(stdout, "%s%s %s\n",
getIndentSpaces(TABLEN + lident),
"State: ",
getStateString(rpnode->portattr.PortState,
portstate_string));
}
}
rpnode->printed = 1;
return (ret);
}
HBA_STATUS
get_domainPort(HBA_HANDLE handle,
int portIndex, PSMHBA_PORTATTRIBUTES port,
HBA_WWN *pdomainPort)
{
HBA_STATUS status;
PSMHBA_SAS_PORT sasport;
SMHBA_SAS_PHY phyattr;
sasport = port->PortSpecificAttribute.SASPort;
(void) memset(pdomainPort, 0, sizeof (HBA_WWN));
if (sasport->NumberofPhys > 0) {
status = SMHBA_GetSASPhyAttributes(handle, portIndex,
0, &phyattr);
if (status != HBA_STATUS_OK)
return (status);
(void) memcpy(pdomainPort, &phyattr.domainPortWWN,
sizeof (HBA_WWN));
} else {
return (HBA_STATUS_ERROR_NOT_SUPPORTED);
}
return (HBA_STATUS_OK);
}
static int
sas_name_comp(const char *name1, const char *name2)
{
int i = 0;
if (name1 == name2)
return (0);
while ((name1[i] == name2[i]) && (name1[i] != '\0'))
i++;
if (isdigit(name1[i]) && isdigit(name2[i]))
return (atoi(&name1[i]) - atoi(&name2[i]));
return (name1[i] - name2[i]);
}
static int
sas_elem_compare(const void *arg1, const void *arg2)
{
sas_elem_t *p1, *p2;
p1 = (sas_elem_t *)arg1;
p2 = (sas_elem_t *)arg2;
return (sas_name_comp(p1->name, p2->name));
}
static void
sas_elem_sort(sas_elem_t *array, int nelem)
{
qsort((void *)array, nelem, sizeof (sas_elem_t), sas_elem_compare);
}