/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <printAttrs.h>
#include <smhbaapi.h>
typedef struct inputArgs {
int wwnCount;
char **wwn_argv;
char *hbaName;
int pflag;
int *wwn_flag;
} inputArg_t;
typedef struct tgt_mapping {
/*
* Remote port tree node structure.
*/
typedef struct smhba_rp_tree {
int printed;
/*
* Report LUN data structure.
*/
struct lun {
};
typedef struct rep_luns_rsp {
/*
* The following flag is used for printing HBA header on-demand.
*/
static int g_printHBA = 0;
/*
* The following structure is for sorted output of HBA and HBA Port.
*/
typedef struct _sas_elem {
int index;
/*
* The following two functions are for generating hierachy of expander
* subcommand.
*/
static int
static int
int *printPort);
static int
static int
/* processes for hanlding local HBA info */
int numberOfPorts, const char *adapterName);
/* process for handling expander info */
/* process for handling target port info */
/* process for handling logical unit info */
/* process for target port SCSI processing */
static int
struct targetPortConfig *configData);
/* process for target port config processing */
/* process for logical-unit config processing */
static int
/* get domain port out of hba-port phy attr. */
static int
static void
/*
* function for hba subcommand
*
* Arguments:
* wwnCount - count of the number of WWNs in wwn_argv
* if wwnCount > 0, then we will only print information for
* the hba ports listed in wwn_argv
* if wwnCount == 0, then we will print information on all hba ports
* wwn_argv - argument array of hba port WWNs
* options - any options specified by the caller
*
* returns:
* 0 if successful
* >0 otherwise
*/
int
{
int processHBA_flags = 0;
int err_cnt = 0;
/* process each of the options */
case 'v':
break;
default:
break;
}
}
gettext("Failed to load SM-HBA libraries."
err_cnt++;
return (err_cnt);
}
/* utilize wwnCount and wwn_argv for hbaCount and hba_argv */
/*
* Process and filter for every local hba,
* when the hba is not specificed, print all hba(s).
*/
(void) HBA_FreeLibrary();
return (err_cnt);
}
/*
* function for hba-port subcommand
*
* Arguments:
* wwnCount - count of the number of WWNs in wwn_argv
* if wwnCount > 0, then we will only print information for
* the hba ports listed in wwn_argv
* if wwnCount == 0, then we will print information on all hba ports
* wwn_argv - argument array of hba port WWNs
* options - any options specified by the caller
*
* returns:
* 0 if successful
* >0 otherwise
*/
int
{
int processHBA_flags = 0;
int err_cnt = 0;
/* process each of the options */
case 'a':
break;
case 'y':
break;
case 'l':
break;
case 'v':
break;
default:
break;
}
}
gettext("Failed to load SM-HBA libraries."
err_cnt++;
return (err_cnt);
}
/*
* Process and filter for every local hba-port,
* when the hba-port is not specificed, print all hba-port(s).
*/
(void) HBA_FreeLibrary();
return (err_cnt);
}
/*
* function for expander subcommand
*
* Arguments:
* wwnCount - the number of Remote Port SAS Address in wwn_argv
* if wwnCount == 0, then print information on all
* expander devices.
* if wwnCount > 0, then print information for the exapnders
* given in wwn_argv.
* wwn_argv - array of WWNs
* options - options specified by the caller
*
* returns:
* 0 if successful
* >0 otherwise
*/
int
{
int processHBA_flags = 0;
int err_cnt = 0;
/* process each of the options */
case 'p':
sizeof (hbaPort));
break;
case 't':
break;
case 'v':
break;
default:
break;
}
}
gettext("Failed to load SM-HBA libraries."
err_cnt++;
return (err_cnt);
}
/*
* Process and filter for every hba-port,
* when the hba-port is not specificed, print all hba-port(s).
*/
(void) HBA_FreeLibrary();
return (err_cnt);
}
/*
* function for target-port subcommand
*
* Arguments:
* wwnCount - the number of Remote Port SAS Address in wwn_argv
* if wwnCount == 0, then print information on all
* target ports.
* if wwnCount > 0, then print information for the target ports
* given in wwn_argv.
* wwn_argv - array of WWNs
* options - options specified by the caller
*
* returns:
* 0 if successful
* >0 otherwise
*/
int
{
int processHBA_flags = 0;
int err_cnt = 0;
/* process each of the options */
case 's':
break;
case 'v':
break;
default:
break;
}
}
gettext("Failed to load SM-HBA libraries."
err_cnt++;
return (err_cnt);
}
/*
* Process and filter for every hba-port,
* when the hba-port is not specificed, print all hba-port(s).
*/
if (tpCount == 0) {
/* list all target port */
}
} else {
/*
* When operands provided, we should set the error code
* only if there are issues related with the operands.
*/
err_cnt = 0;
/*
* list any paths not found first
* this gives the user cleaner output
*/
errno = 0;
err_cnt++;
continue;
}
tpListWalk != NULL;
break;
}
}
"Error: Target Port %s Not Found \n",
err_cnt++;
}
}
/* list all paths requested in order requested */
errno = 0;
continue;
}
tpListWalk != NULL;
}
}
}
}
(void) HBA_FreeLibrary();
return (err_cnt);
}
/*
* This function will enumerate all the hba and hba ports,
* call the callback function to proceed with futher process.
*
* Arguments:
* input - contains all the input parameters.
* processPort - a callback function when handling each port.
*
* Return Value:
* 0 sucessfully processed handle
* >0 error has occured
*/
static int
{
int numAdapters = 0;
int matchedHBAs = 0;
int matchedHBAPorts = 0;
int hbaPortExist = 0;
int portIndex = 0;
int remote_avail = 0;
int local_avail = 0;
if (numAdapters == 0) {
gettext("Error: No Adapters Found."));
return (++ret);
}
/*
* array of flags for each operands.
*/
(processPort != handleLogicalUnit)) {
gettext("No enough memory on heap"));
return (++ret);
}
}
if (adpt_array == NULL) {
gettext("No enough memory on heap"));
}
return (++ret);
}
for (i = 0; i < numAdapters; i++) {
status =
/*
* If we get SAS incompatible library warning here,
* just skip the following steps.
*/
if (status != 1) {
continue;
}
if (status != HBA_STATUS_OK) {
gettext("Error: Failed to get the name for"
" HBA index"),
i, gettext("Reason:"),
ret++;
continue;
}
adpt_array[i].index = i;
}
/* Sort the HBA Name in place. */
for (i = 0; i < numAdapters; i++) {
int times = 0;
== 0) {
gettext("Error: Failed to open adapter"),
adpt_array[i].name);
ret++;
continue;
}
} else {
continue;
}
/*
* We need to support an adapter without hba port.
* So get attributes anyway.
*/
while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
status == HBA_STATUS_ERROR_BUSY) &&
times++ < HBA_MAX_RETRIES) {
(void) sleep(1);
&attrs);
}
if (status != HBA_STATUS_OK) {
gettext("Error: Failed to get attributes"
gettext("Reason:"),
ret++;
continue;
}
if (status != HBA_STATUS_OK) {
gettext("Error: Failed to get number of ports "
gettext("Reason:"),
ret++;
continue;
}
/*
* Deal with each subcommand for hba filter here,
* processPort is NULL for hba subcommand.
*/
if (processPort == NULL) {
continue;
} else if (processPort == handleHBAPort) {
adpt_array[i].name) == 0) {
matchedHBAs++;
} else {
continue;
}
} else {
matchedHBAs++;
}
} else {
matchedHBAs++;
}
/*
* In order to have a sorted output for HBA Port, we should
* do the sorting before moving on.
*/
if (numberOfPorts) {
}
gettext("Failed to get adapter port type "
gettext("Reason:"),
ret++;
continue;
}
if (porttype != HBA_PORTTYPE_SASDEVICE) {
/* skip any non-sas hba port */
continue;
}
if ((status = SMHBA_GetAdapterPortAttributes(
/*
* Not able to get port attributes.
* print out error message and
* move on to the next port
*/
gettext("Error: Failed to get port "
gettext("Reason:"),
ret++;
continue;
}
}
/* Sort the HBA Port Name here. */
if (port_array) {
}
/*
* Sum up the local hba ports available.
*/
/*
* Clear g_printHBA flag for expander subcommand.
*/
g_printHBA = 0;
/* process each port on the given adapter */
for (portIndex = 0;
portIndex++) {
/*
* We only handle the port which is valid.
*/
continue;
}
(void) SMHBA_GetAdapterPortAttributes(handle,
/*
* We have different things to do for the three
* sub-commands here.
*/
if (processPort == handleHBAPort) {
/*
* For hba-port, we will check whether the
* specified hba port exist first.
* But if no hba port specified, we should
* by pass this check(just let hbaPortExist
* be 1).
*/
if (isStringInArgv(input,
port.OSDeviceName)) {
hbaPortExist = 1;
if (g_printHBA == 0) {
"%s %s\n",
"HBA Name:",
adpt_array[i].name);
g_printHBA = 1;
}
}
} else {
hbaPortExist = 1;
if (g_printHBA == 0) {
"%s %s\n",
"HBA Name:",
adpt_array[i].name);
g_printHBA = 1;
}
}
}
if (processPort == handleExpander) {
/*
* For expander device, input->hbaName is
* the hba port name specified on the
* command line(with -p option).
*/
port.OSDeviceName) == 0)
hbaPortExist = 1;
} else
hbaPortExist = 1;
}
if (processPort == handleTargetPort) {
/*
* For target port, we don't need to check the
* hba port address, so let it go here.
*/
hbaPortExist = 1;
}
if (processPort == handleLogicalUnit) {
/*
* For lu, we don't need to check the hba
* port address, so let it go here.
*/
hbaPortExist = 1;
}
if (hbaPortExist) {
remote_avail++;
}
adpt_array[i].name,
/*
* We should reset the hbaPortExist flag
* here for next round of check and count
* for the machedHBAPorts.
*/
hbaPortExist = 0;
}
}
if (port_array) {
port_array = NULL;
}
}
if (adpt_array) {
adpt_array = NULL;
}
/*
* When we are here, we have traversed all the hba and hba ports.
*/
if (matchedHBAs == 0) {
gettext("Error: Matching HBA not found."));
}
return (++ret);
} else if (processPort == NULL) {
/*
* processPort == NULL signifies hba subcommand.
* If enter here, it means we have at least one matching
* hba, we need to check if there are mismatching ones.
*/
gettext("Error: HBA"),
gettext("not found."));
ret++;
}
}
} else {
if (local_avail > 0 && matchedHBAPorts == 0) {
gettext("Error: Matching HBA Port "
"not found."));
}
return (++ret);
} else if (local_avail == 0) {
gettext("Error: No HBA Port Configured."));
}
return (++ret);
} else if (processPort == handleHBAPort) {
/*
* If enter here, we have at least one HBA port
* matched. For hba-port subcommand, we shall check
* whether there are operands mismatching.
*/
gettext("Error: HBA Port"),
gettext("not found."));
ret++;
}
}
}
}
/*
* For expander subcommand, we need to check if the
*/
if (processPort == handleExpander) {
sum = 0;
}
/*
* If sum is zero, it means that for all the given
* operands matching count is zero. So none of the
* specified SAS address exist actually.
*/
if (sum == 0) {
"Matching SAS Address not found.\n"));
return (++ret);
}
/*
* If we get here, it means that some of the specified
* sas address exist, we will know through looping the
* wwn_flag array.
*/
gettext("Error: SAS Address"),
gettext("not found."));
ret++;
}
}
}
/* even if no remote port is found it is not an error. */
}
}
return (ret);
}
/*
* This function will handle the phy stuff for hba-port subcommand.
*
* Arguments:
* handle - handle to hba port.
* portIndex - the index of hba port currently being processed.
* port - pointer to hba port attributes.
* pflag - options user specified.
*
* Return Value:
* 0 sucessfully processed handle
* >0 error has occured
*/
static int
{
return (++err_cnt);
if (numphys == 0)
return (0);
else
return (0);
if (status != HBA_STATUS_OK) {
gettext("Failed to get SAS Phy attributes"
"phyIndex"), phyIndex,
gettext("Reason:"),
err_cnt++;
continue;
}
if (pflag & PRINT_PHY_LINKSTAT)
}
return (err_cnt);
}
/*
* This function will handle the phy stuff for hba-port subcommand.
*
* Arguments:
* handle - handle to hba port.
* portIndex - the index of hba port currently being processed.
* port - pointer to hba port attributes.
* pflag - options user specified.
*
* Return Value:
* 0 sucessfully processed handle
* >0 error has occured
*/
static int
{
}
if (status != HBA_STATUS_OK) {
" Link Error Statistics:");
gettext(" Failed to retrieve Link "
"Error Statistics!"));
return (1);
}
return (0);
}
/*
* Check whether the pWWN exist in the WWNs list which specified by user.
*
* Arguments:
* input - contains all the input parameters.
* pWWN - pointer to the hba port sas address.
*
* Return Value:
* 1 true, the pWWN exist in the sas address list specified.
* 0 false.
*/
static int
{
int port_wwn_counter = 0;
int portfound = 0;
/* list only ports given in wwn_argv */
for (port_wwn_counter = 0;
port_wwn_counter++) {
16);
continue;
}
portfound = 1;
}
}
return (portfound);
}
/*
* Check whether the string value exists in the input list,
* which specified by user.
*
* Arguments:
* input - contains all the input parameters.
* stringName - could be hba adapter name
* hba-port name.
*
* Return Value:
* 1 true, the HBA exists in the list specified.
* 0 false.
*/
static int
{
int counter = 0;
int found = 0;
/* list only hba(s) given in wwn_argv */
for (counter = 0;
counter++) {
stringName) == 0) {
found = 1;
}
}
return (found);
}
/*
* Callback function for hba subcommand.
*
* Arguments:
* attrs - pointer to adapter attributes currently being processed.
* input - contains all the input parameters.
* numberOfPorts - number of ports of this HBA.
*
* Return Value:
* matching number
*/
int numberOfPorts, const char *adapterName)
{
} else {
} else {
matchingHBA = 0;
}
}
return (matchingHBA);
}
/*
* Callback function for hba-port subcommand.
*
* Arguments:
* handle - handle to hba port.
* portIndex - the index of hba port currently being processed.
* port - pointer to hba port attributes.
* attrs - pointer to adapter attributes currently being processed.
* input - contains all the input parameters.
*
* Return Value:
* 0 sucessfully processed handle
* >0 error has occured
*/
/*ARGSUSED*/
{
int ret = 0;
return (ret);
}
/*
* Callback function for expander subcommand.
*
* Arguments:
* handle - handle to hba port.
* portIndex - the index of hba port currently being processed.
* port - pointer to hba port attributes.
* attrs - pointer to adapter attributes currently being processed.
* input - contains all the input parameters.
*
* Return Value:
* 0 sucessfully processed handle
* >0 error has occured
*/
/*ARGSUSED*/
{
int ret = 0;
int i, numberOfRP;
int printPort = 0;
int numberOfEXP = 0;
int unsolved_inserted = 0;
int unsolved_left = 0;
int disco_port_fail = 0;
/*
* Retrive all expander device from this hba port first.
*/
NumberofDiscoveredPorts) == 0) {
/* no remote port. just return 0. */
return (ret);
}
for (i = 0; i < numberOfRP; i++) {
if (status != HBA_STATUS_OK) {
ret++;
continue;
}
numberOfEXP++;
}
/*
* We will try to insert this expander device and target
* ports into the topology tree. If we failed, we can chain
* them together and try again when we have all the
* discovered port information in hands.
*/
sizeof (HBA_WWN)) == 0) {
/*
* The root node of tree should
* be set up first.
*/
} else {
/*
* If we can not set up the root node of
* the tree or we failed to insert
* the disocvered port node, queue it up then.
*/
if (unsolved_head == NULL) {
} else {
}
}
}
}
if (disco_port_fail) {
gettext("Error: Failed to get attributes for"),
gettext("connected ports of HBA port"),
port->OSDeviceName);
}
/* no expander found. No need further processing. */
if (numberOfEXP == 0) {
while (unsolved_head) {
}
return (ret);
}
/*
* When we're here, we should already have all information,
* now we try again to insert them into the topology tree.
* unsolved_head is the pointer which point to the head of
* unsolved rpnode linked list.
* unsolved_tail is the pointer which point to the tail of
* unsolved rpnode linked list.
* unsolved_sentinel is for insertion failure detection.
* When we're trying to insert the rpnodes from unsolved
* linked list, it may happen that some of the rpnodes can
* not be inserted no matter how many times we loop through
* this linked list. So we use unsolved_sentinel to identify
* the tail of last round of scanning, and unsolved_inserted
* which is a counter will be used to count how many rpnodes
* have been inserted from last round, if it is zero, which
* means that we can not insert rpnodes into rptree any more,
* and we should stop and deallocate the memory they occupied.
*/
while (unsolved_head) {
if (unsolved_head == NULL)
if (rpnode == unsolved_sentinel) {
/*
* We just scanned one round for the
* unsolved list. Check to see whether we
* have nodes inserted, if none, we should
* break in case of an indefinite loop.
*/
if (unsolved_inserted == 0) {
/*
* Indicate there is unhandled node.
* Chain free the whole unsolved
* list here.
*/
break;
} else {
unsolved_inserted = 0;
}
}
} else {
/*
* We just inserted one rpnode, increment the
* unsolved_inserted counter. We will utilize this
* counter to detect an indefinite insertion loop.
*/
}
}
/* check if there is left out discovered ports. */
if (unsolved_left) {
ret++;
gettext("Error: Failed to establish expander topology on"),
port->OSDeviceName);
gettext(" Folowing port(s) are unresolved."));
while (unsolved_head) {
}
/* still print what we have */
} else {
}
return (ret);
}
/*
* Callback function for target-port subcommand.
*
* Arguments:
* handle - handle to hba port.
* portIndex - the index of hba port currently being processed.
* port - pointer to hba port attributes.
* attrs - pointer to adapter attributes currently being processed.
* input - contains all the input parameters.
*
* Return Value:
* 0 sucessfully processed handle
* >0 error has occured
*/
/*ARGSUSED*/
{
int i;
int ret = 0;
int disco_port_fail = 0;
NumberofDiscoveredPorts; i++) {
portIndex, i, &targetattr);
if (status != HBA_STATUS_OK) {
} else {
/* skip expander device */
}
}
}
if (disco_port_fail) {
ret++;
gettext("Error: Failed to get attributes for"),
gettext("connected ports of HBA port"),
port->OSDeviceName);
}
return (ret);
}
/*
* ****************************************************************************
*
* compareLUName -
* compare names directly and also check if disk namees match with
* different slice number or /devices path are speicified and matches.
*
* cmdArg - first string to compare
* osName - os name from attributes
*
* returns B_TRUE if the strings match either directly or via devid
* B_FALSE otherwise
*
* ****************************************************************************
*/
static boolean_t
{
} else {
/* user input didn't match, try to match the core of args. */
/* is this /devices path */
}
/* is this a /dev link */
/* if it is disk link */
}
}
} else {
/* other dev links */
}
}
}
} /* compare */
return (isSame);
}
/*
* Process logical-unit(lu) subcommand.
*
* Arguments:
* luCount - number of OS device name(s) specified by user.
* luArgv - array of OS device name(s) specified by user.
* options - all the options specified by user.
*
* Return Value:
* 0 sucessfully processed handle
* >0 error has occured
*/
int
{
int processHBA_flags = 0;
int lu;
int err_cnt = 0;
}
}
/* HBA_LoadLibrary() */
gettext("Failed to load SM-HBA libraries."
err_cnt++;
return (err_cnt);
}
if (luCount == 0) {
/* list all paths */
}
} else {
/*
* When operands provided, we should set the error code
* only if there are issues related with the operands.
*/
err_cnt = 0;
/*
* list any paths not found first
* this gives the user cleaner output
*/
LUListWalk != NULL;
LUListWalk->OSDeviceName)) {
break;
}
}
"Error: Logical Unit %s Not Found \n",
err_cnt++;
}
}
/* list all paths requested in order requested */
LUListWalk->OSDeviceName)) {
verbose);
}
}
}
}
(void) HBA_FreeLibrary();
return (err_cnt);
}
/*
* Callback function for logical-unit(lu) subcommand.
*
* Arguments:
* handle - handle to hba port.
* portIndex - the index of hba port currently being processed.
* port - pointer to hba port attributes.
* attrs - pointer to adapter attributes currently being processed.
* input - contains all the input parameters.
*
* Return Value:
* 0 sucessfully processed handle
* >0 error has occured
*/
/*ARGSUSED*/
{
int numentries;
int count = 0;
int ret = 0;
switch (status) {
case HBA_STATUS_OK:
break;
/* don't increase error flag for no phy configuration */
return (ret);
case HBA_STATUS_ERROR:
default:
return (++ret);
}
gettext("No enough memory on heap."));
return (++ret);
}
/*
* First, we need to get the target mapping data from this hba
* port.
*/
if (status == HBA_STATUS_ERROR_MORE_DATA) {
(numentries * sizeof (SMHBA_SCSIENTRY)));
gettext("No enough memory on heap."));
return (++ret);
}
}
if (status != HBA_STATUS_OK) {
gettext("Error: Failed to get SCSI mapping data for "
gettext("Reason:"),
return (++ret);
}
/*
* By iterating each entry of the targetmapping data, we will
* construct a global list of logical unit.
*/
ret += searchDevice(
}
return (ret);
}
/*
* Search the matching targetmapping data for given target port and SAM LUN
* and return target mapping data if found.
*
* Arguments:
* handle - handle to hba port.
* portIndex - hba port index
* port - hba port attributes.
* targetportWWN - target port SAS address.
* domainportWWN - domain port SAS address.
* domainportttr - target port SAS attributes.
* samLUN - samLUN from report LUNs data.
* data - matching target mapping data.
*
* Return Value:
* 0 sucessfully processed handle
* >0 error has occured
*/
static int
struct targetPortConfig *configData)
{
int ret = 0;
if (status == HBA_STATUS_OK) {
gettext("No enough memory on heap."));
return (++ret);
}
domainPortWWN, map);
if (status == HBA_STATUS_ERROR_MORE_DATA) {
(numentries * sizeof (SMHBA_SCSIENTRY)));
gettext("No enough memory on heap."));
return (++ret);
}
}
if (status != HBA_STATUS_OK) {
/* continue to build mapping data based SCSI info */
ret++;
}
}
/*
* Get report lun data.
*/
senseSize = sizeof (struct scsi_extended_sense);
(void *)rawLUNs,
/*
* if HBA_STATUS_ERROR_NOT_A_TARGET is return, we can assume this is
* a remote HBA and move on
*/
if (status != HBA_STATUS_OK) {
/*
* Let's search mapping data and indicate that Report
* LUNs failed.
*/
sizeof (HBA_WWN)) == 0) {
/* allocate mapping data for each LUN */
sizeof (targetPortMappingData_t));
gettext("No enough "
"memory."));
return (++ret);
}
sizeof (TPMapData->osDeviceName));
} else {
}
}
}
}
return (++ret);
}
sizeof (tmp_lunlength));
/* allocate mapping data for each LUN */
sizeof (targetPortMappingData_t));
gettext("No enough memory."));
return (++ret);
}
/*
* now issue standard inquiry to get Vendor
* and product information
*/
responseSize = sizeof (struct scsi_inquiry);
senseSize = sizeof (struct scsi_extended_sense);
0,
0,
(void *) &inq, &responseSize,
if (status != HBA_STATUS_OK) {
/* indicate that inquiry for this lun is failed */
} else {
}
sizeof (HBA_WWN)) == 0) &&
sizeof (SMHBA_SCSILUN))
== 0)) {
sizeof (TPMapData->osDeviceName));
break;
}
}
lun_string[1];
}
} else {
/* Not able to get any target mapping information */
lun_string[1];
}
} else {
}
}
return (ret);
}
/*
* Search the discovered LUs and construct the global LU list.
*
* Arguments:
* handle - handle to hba port.
* portIndex - hba port index
* port - hba port attributes.
* targetattr - target port attributes.
* sasattr - target port SAS attributes.
* pflag - options the user specified.
*
* Return Value:
* 0 sucessfully processed handle
* >0 error has occured
*/
static int
{
int ret = 0;
int status;
int expanderValid = 0;
switch (status) {
case HBA_STATUS_OK:
break;
/* don't increase error flag for no phy configuration */
return (ret);
case HBA_STATUS_ERROR:
default:
return (++ret);
}
/*
* First, we will iterate the already constructed target port
* list to see whether there is a target port already exist with
* matching target port SAS address.
*/
sizeof (HBA_WWN)) == 0) {
/*
* if the target port exist and
* verbose is not set, just return
*/
if (((pflag & PRINT_VERBOSE) == 0) &&
((pflag & PRINT_TARGET_SCSI) == 0)) {
return (ret);
}
break;
}
}
/*
* If there is a target port already exist, we should
* add more information on the target port to construct the
* whole topology.
* Here we will check whether the current hba port name
* has already been added.
*/
/* first get the expander SAS address compare */
/* NO expander */
sizeof (HBA_WWN));
expanderValid = 1;
} else {
!= 0) {
/* expander exist. We should verify it. */
sizeof (HBA_WWN));
(void *) memset(&tgtsasport, 0,
sizeof (tgtsasport));
= &tgtsasport;
&tgtattr);
== HBA_PORTTYPE_SASEXPANDER) {
expanderValid = 1;
}
}
}
port->OSDeviceName) == 0) &&
sizeof (HBA_WWN)) == 0)) {
break;
}
}
/*
* sas address for this discovered target port.
*/
if (foundConfig == B_FALSE) {
sizeof (targetPortConfig_t));
return (++ret);
}
} else {
TPConfig->hbaPortName) > 0) {
}
if (TPConfig == prevConfig) {
/* Should be inserted in the head. */
} else {
}
}
/* if scsi option is not set return */
if ((pflag & PRINT_TARGET_SCSI) == 0) {
return (0);
} else {
return (searchTargetPortMappingData(
}
}
} else {
/*
* Here we got a new target port which has not ever exist
* in our global target port list. So add it to the list.
* list.
*/
sizeof (targetPortList_t));
return (++ret);
}
sizeof (SMHBA_PORTATTRIBUTES));
sizeof (SMHBA_SAS_PORT));
sizeof (targetPortConfig_t));
return (++ret);
}
sizeof (newConfig->hbaPortName));
/* NO expander */
0, sizeof (HBA_WWN));
} else {
/* expander exist. We should verify it. */
sizeof (HBA_WWN));
&tgtattr);
expanderValid = 1;
}
}
/* if scsi option is not set return */
if ((pflag & PRINT_TARGET_SCSI) == 0) {
return (0);
} else {
return (searchTargetPortMappingData(
}
}
return (ret);
}
/*
* Search the discovered LUs and construct the global LU list.
*
* Arguments:
* entryP - one of the target mapping data.
* handle - handle to hba port.
* hbaPortWWN - hba port sas address.
* domainPortWWN - domain port WWN for this sas domain.
* portName - HBA port OS Device Name.
* pflag - options the user specified.
*
* Return Value:
* 0 sucessfully processed handle
* >0 error has occured
*/
static int
{
int ret = 0;
/* if OSDeviceName is not set, we don't need to search */
return (ret);
}
/*
* First, we will iterate the already constructed discovered LU
* list to see whether there is a LU already exist with the same OS
* device name as current target mapping data entry.
*/
discoveredLU->OSDeviceName) == 0) {
/*
* if there is existing OS Device Name and
* verbose is not set, just return
*/
if ((pflag & PRINT_VERBOSE) == 0) {
return (ret);
}
break;
}
}
if (foundDevice == B_TRUE) {
/*
* If there is a discovered LU already exist, we should
* add more information on this LU to construct the whole
* topology.
* Here we will check whether the current hba port has
* already been added.
*/
portName) == 0) {
break;
}
}
/*
* If we get here, it means that it is a new hba port name
* for this discovered LU.
*/
return (++ret);
}
> 0) {
}
/* Insert in the head of list. */
} else {
}
/* add Target Port */
sizeof (tgtPortWWNList));
return (++ret);
}
sizeof (HBA_WWN));
/* Set LUN data */
} else {
/*
* Otherwise, we just need to add the target port
* sas address information.
*/
TgtWWNList != NULL;
sizeof (HBA_WWN)) == 0)
return (0);
}
/* add it to existing */
sizeof (tgtPortWWNList));
return (++ret);
}
/* insert at head */
sizeof (HBA_WWN));
/* Set LUN data */
}
} else {
/*
* Here we got a new discovered LU which has not ever exist
* in our global LU list. So add it into our global LU
* list.
*/
sizeof (discoveredDevice));
return (++ret);
}
/* copy device name */
sizeof (newDevice->OSDeviceName));
/* if verbose is not set return */
if ((pflag & PRINT_VERBOSE) == 0) {
return (0);
}
/* copy WWN data */
sizeof (portList));
return (++ret);
}
return (++ret);
}
sizeof (HBA_WWN));
responseSize = sizeof (struct scsi_inquiry);
senseSize = sizeof (struct scsi_extended_sense);
sizeof (smhbaLUN));
/*
* Retrieve the VPD data for the newly found discovered LU.
*/
0,
0,
(void *) &inq, &responseSize,
if (status != HBA_STATUS_OK) {
/* initialize inq status */
ret++;
} else {
/* initialize inq status */
}
}
return (ret);
}
/*
* Function we use to insert a newly discovered port.
* Return:
* 0 - success
* >0 - failed
*/
static int
{
int ret = 0;
gettext("Error: NULL rproot"));
return (1);
}
gettext("Error: NULL rpnode"));
return (1);
}
return (0);
}
/*
* If the attched sas address is equal to the local sas address,
* then this should be a child node of current root node.
*/
/*
* If the attached sas address is equal to the attached sas
* address of current root node, then this should be a
* sibling node.
*/
} else {
/*
* Insert the SAS Expander at the tail of sibling
* list.
*/
}
} else {
/*
* If enter here, we should first try to insert the discovered
* port node into the child sub-tree, then try to insert to the
* sibling sub-trees. If we failed to insert the discovered
* port node, return 1. The caller will queue this node
* up and retry insertion later.
*/
}
rpnode);
} else
ret = 1;
}
return (ret);
}
return (0);
}
/*
* Function which will print out the whole disocvered port topology.
* Here we use the Preorder Traversal algorithm.
* The indentation rules are:
* 1 * TABLEN - for attributes
*/
static int
{
return (ret);
/*
* We assume that all the nodes are disocvered ports(sas device or
* expander).
*/
/* Adjust local indentation if a discovered port specified. */
/*
* Check whether current node match one of the specified
* SAS addresses.
*/
/*
* Step down to child tree first.
*/
/*
* Then check the sibling tree.
*/
return (ret);
}
}
/*
* We should print the header(HBA Name + HBA Port Name)
* on-demand. It means that, if we have expander device
* address specified on the command line, we should print
* the header once we find a matching one. Or we will
* print the header from the beginning of the output.
*/
if (g_printHBA == 0) {
"HBA Name:", adapterName);
g_printHBA = 1;
}
if (*printPort == 0) {
*printPort = 1;
}
}
/*
* If operands provided with "-t" option specified, we will print
* the immediate child nodes information under the expander.
*/
/* no operand. ignore the option. */
}
}
}
/*
* Here we use DFS(Depth First Search) algorithm to traverse the
* whole tree.
*/
return (ret);
}
/*
* Function which will destroy the whole discovered port tree.
* Here we use the Postorder Traversal algorithm.
*/
{
return;
/*
* Free child tree first.
*/
}
/*
* Free sibling trees then.
*/
}
/*
* Free root node at last.
*/
}
}
/*
* Function used to print out all the descendant nodes.
* handle - handle to HBA.
* port - port attributes of current HBA port.
* desc - the root node of a subtree which will be processed.
* input - input argument.
* lident - local indentation for shifting indentation.
* gident - global indentation, can also be used to obtain Tier number.
*/
/*ARGSUSED*/
static int
{
int ret = 0;
return (ret);
/*
* Walk through the subtree of desc by Pre-Order Traversal Algo.
*/
}
return (ret);
}
/*
* Function used to print the information of specified SAS address.
* handle - handle to a HBA.
* port - port attributes of a HBA port.
* rpnode - discovered port which will be processed.
* lident - local indentation used for shifting indentation.
* gident - global indentation used for calculating "Tier" number.
*/
static int
{
int ret = 0;
"Expander SAS Address",
} else {
"Target Port SAS Address:",
}
"Type:",
} else {
"OS Device Name:",
"State: ",
}
}
return (ret);
}
/*
* Function used to get the correct domainPortWWN as needed by some of the
* SMHBA APIs.
* handle - handle to a HBA.
* portIndex - index to locate the port.
* port - pointer to the structure holding port attributes.
* pdomainPort - pointer to the buffer holding domainPortWWN.
*/
{
/*
* Since iport can exist without any phys,
* sasinfo hba-port -v has indicated numberOfPhys;
* if there is no phys within the hba, just return OK.
*/
if (sasport->NumberofPhys > 0) {
0, &phyattr);
if (status != HBA_STATUS_OK)
return (status);
sizeof (HBA_WWN));
} else {
/* return not supported for no phy configured */
return (HBA_STATUS_ERROR_NOT_SUPPORTED);
}
return (HBA_STATUS_OK);
}
/*
* Comparison function for comparing names possibly ending with digits.
* Return:
* <0 - name1 is less than name2.
* 0 - name1 is equal with name2.
* >0 - name1 is more than name2.
*/
static int
{
int i = 0;
return (0);
i++;
/* If neither of name1[i] and name2[i] is '\0'. */
/* One of name1[i] and name2[i] is not digit. */
}
/*
* arg1 - first argument of type sas_elem_t.
* arg2 - second argument of type sas_elem_t.
* Return:
* <0 - arg1 is less than arg2.
* 0 - arg1 is equal with arg2.
* >0 - arg1 is more than arg2.
*/
static int
{
}
/*
* array - elements array of type sas_elem_t.
* nelem - number of elements in array of type sas_elem_t.
*/
static void
{
}