root/usr/src/cmd/sasinfo/printAttrs.c
/*
 * 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
 * or http://www.opensolaris.org/os/licensing.
 * 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 <ctype.h>
#include <printAttrs.h>

static SAS_STATE hbastatus_string[] = {
        HBA_STATUS_OK,                          "Okay",
        HBA_STATUS_ERROR,                       "Error",
        HBA_STATUS_ERROR_NOT_SUPPORTED,         "Not Supported",
        HBA_STATUS_ERROR_INVALID_HANDLE,        "Invalid Handle",
        HBA_STATUS_ERROR_ARG,                   "Argument Error",
        HBA_STATUS_ERROR_ILLEGAL_WWN,           "Illegal WWN",
        HBA_STATUS_ERROR_ILLEGAL_INDEX,         "Illegal Index",
        HBA_STATUS_ERROR_MORE_DATA,             "Not Enough Buffer for Data",
        HBA_STATUS_ERROR_STALE_DATA,            "Stale Data",
        HBA_STATUS_SCSI_CHECK_CONDITION,        "SCSI Check Condition",
        HBA_STATUS_ERROR_BUSY,                  "Busy",
        HBA_STATUS_ERROR_TRY_AGAIN,             "Try Again",
        HBA_STATUS_ERROR_UNAVAILABLE,           "Unavailable",
        HBA_STATUS_ERROR_ELS_REJECT,            "ELS Reject",
        HBA_STATUS_ERROR_INVALID_LUN,           "Invalid LUN",
        HBA_STATUS_ERROR_INCOMPATIBLE,          "Request Incompatible",
        HBA_STATUS_ERROR_AMBIGUOUS_WWN,         "Ambiguous WWN",
        HBA_STATUS_ERROR_LOCAL_BUS,             "Local Bus Error",
        HBA_STATUS_ERROR_LOCAL_TARGET,          "Local Target Error",
        HBA_STATUS_ERROR_LOCAL_LUN,             "Local LUN Error",
        HBA_STATUS_ERROR_LOCAL_SCSIID_BOUND,    "Local SCSIID Bound",
        HBA_STATUS_ERROR_TARGET_FCID,           "Target FCID Error",
        HBA_STATUS_ERROR_TARGET_NODE_WWN,       "Target Node WWN Error",
        HBA_STATUS_ERROR_TARGET_PORT_WWN,       "Target Port WWN Error",
        HBA_STATUS_ERROR_TARGET_LUN,            "Target LUN Error",
        HBA_STATUS_ERROR_TARGET_LUID,           "Target LUID Error",
        HBA_STATUS_ERROR_NO_SUCH_BINDING,       "No Such Binding",
        HBA_STATUS_ERROR_NOT_A_TARGET,          "Not a Target",
        HBA_STATUS_ERROR_UNSUPPORTED_FC4,       "Unsupported FC4",
        HBA_STATUS_ERROR_INCAPABLE,             "Incapable",
        HBA_STATUS_ERROR_TARGET_BUSY,           "Target Busy",
        HBA_STATUS_ERROR_NOT_LOADED,            "Not Loaded",
        HBA_STATUS_ERROR_ALREADY_LOADED,        "Alreday Loaded",
        HBA_STATUS_ERROR_ILLEGAL_FCID,          "Illegal FCID",
        HBA_STATUS_ERROR_NOT_ASCSIDEVICE,       "Not a SCSI Device",
        HBA_STATUS_ERROR_INVALID_PROTOCOL_TYPE, "Invalid Protocol Type",
        HBA_STATUS_ERROR_BAD_EVENT_TYPE,        "Bad Event Type",
        -1,                                     NULL
};

SAS_STATE porttype_string[] = {
        HBA_PORTTYPE_UNKNOWN,           "UNKNOWN",
        HBA_PORTTYPE_OTHER,             "OTHER",
        HBA_PORTTYPE_NOTPRESENT,        "NOT Present",
        HBA_PORTTYPE_SASDEVICE,         "SAS Device",
        HBA_PORTTYPE_SATADEVICE,        "SATA Device",
        HBA_PORTTYPE_SASEXPANDER,       "SAS Expander",
        -1,                             NULL,
};

SAS_STATE portstate_string[] = {
        HBA_PORTSTATE_UNKNOWN,          "unknown",
        HBA_PORTSTATE_ONLINE,           "online",
        HBA_PORTSTATE_OFFLINE,          "offline",
        HBA_PORTSTATE_BYPASSED,         "bypassed",
        HBA_PORTSTATE_DIAGNOSTICS,      "diagnostics",
        HBA_PORTSTATE_LINKDOWN,         "link Down",
        HBA_PORTSTATE_ERROR,            "port Error",
        HBA_PORTSTATE_LOOPBACK,         "loopback",
        HBA_PORTSTATE_DEGRADED,         "degraded",
        -1,                             NULL,
};

static SAS_STATE phystate_string[] = {
        HBA_SASSTATE_UNKNOWN,           "unknown",
        HBA_SASSTATE_DISABLED,          "disabled",
        HBA_SASSTATE_FAILED,            "failed",
        HBA_SASSTATE_SATASPINUP,        "sata-spinup",
        HBA_SASSTATE_SATAPORTSEL,       "sata-portselector",
        HBA_SASSPEED_1_5GBIT,           "1.5Gbit",
        HBA_SASSPEED_3GBIT,             "3Gbit",
        HBA_SASSPEED_6GBIT,             "6Gbit",
        HBA_SASSPEED_12GBIT,            "12Gbit",
        -1,                             NULL,
};

static SAS_STATE dtype_string[] = {
        DTYPE_DIRECT,                   "Disk Device",
        DTYPE_SEQUENTIAL,               "Tape Device",
        DTYPE_PRINTER,                  "Printer Device",
        DTYPE_PROCESSOR,                "Processor Device",
        DTYPE_WORM,                     "WORM Device",
        DTYPE_RODIRECT,                 "CD/DVD Device",
        DTYPE_SCANNER,                  "Scanner Device",
        DTYPE_OPTICAL,                  "Optical Memory Device",
        DTYPE_CHANGER,                  "Medium Changer Device",
        DTYPE_COMM,                     "Communications Device",
        DTYPE_ARRAY_CTRL,               "Storage Array Controller Device",
        DTYPE_ESI,                      "Enclosure Services Device",
        DTYPE_RBC,                      "Simplified Direct-access Device",
        DTYPE_OCRW,                     "Optical Card Reader/Writer Device",
        DTYPE_BCC,                      "Bridge Controller Commands",
        DTYPE_OSD,                      "Object-based Storage Device",
        DTYPE_ADC,                      "Automation/Drive Interface",
        DTYPE_WELLKNOWN,                "Well Known Logical Unit",
        DTYPE_UNKNOWN,                  "Unknown Device",
        -1,                             NULL
};

static char *getPhyStateString(HBA_UINT32 key, phystat_type phyt);

char *
getIndentSpaces(int number)
{
        int             i = 0;
        /* the maximum indent with terminator '\0' */
        static char     ret[MAXINDENT+1];

        if (number > MAXINDENT)
                number = MAXINDENT;

        for (i = 0; i < number; i++) {
                ret[i] = ' ';
        }
        ret[i] = '\0';
        return (ret);
}

char *
getStateString(HBA_UINT32 key, SAS_STATE *stat_string)
{
        static char ret[64];
        while (stat_string->key != -1) {
                if (stat_string->key == key) {
                        return ((char *)stat_string->value);
                }
                stat_string++;
        }
        (void) sprintf(ret, "Undefined value (%d)", key);
        return (ret);
}

static char *
getPhyStateString(HBA_UINT32 key, phystat_type phyt)
{
        int i = 0, len = 0, match = 0;
        HBA_UINT32 physpeed[] = {
                HBA_SASSPEED_1_5GBIT,
                HBA_SASSPEED_3GBIT,
                HBA_SASSPEED_6GBIT,
                HBA_SASSPEED_12GBIT
        };

        len = sizeof (physpeed) / sizeof (HBA_UINT32);
        for (i = 0; i < len; i++) {
                if (key == physpeed[i]) {
                        match = 1;
                        break;
                }
        }

        if (match == 1) {
                if (phyt == PHY_STATE)
                        return ("enabled");
                else
                        return (getStateString(key, phystate_string));
        } else {
                if (phyt == PHY_STATE)
                        return (getStateString(key, phystate_string));
                else
                        return ("not available");
        }
}

char *
getHBAStatus(HBA_STATUS key)
{
        return (getStateString(key, hbastatus_string));
}

/*
 * return device type description
 *
 * Arguments:
 *      dType - Device type returned from Standard INQUIRY
 * Returns:
 *      char string description for device type
 */
char *
getDTypeString(uchar_t dType)
{
        return (getStateString((dType & DTYPE_MASK), dtype_string));
}

uint64_t
wwnConversion(uchar_t *wwn)
{
        uint64_t tmp;
        (void) memcpy(&tmp, wwn, sizeof (uint64_t));
        return (ntohll(tmp));
}

/*
 * prints out HBA information
 */
void
printHBAInfo(SMHBA_ADAPTERATTRIBUTES *attrs, int pflag, int numberOfPorts,
    const char *adapterName)
{

        (void) fprintf(stdout, "%s %s\n", "HBA Name:", adapterName);

        if (pflag & PRINT_VERBOSE) {
                (void) fprintf(stdout, "%s%s %s\n",
                    getIndentSpaces(4), "Manufacturer:",
                    attrs->Manufacturer[0] == 0?
                    "not available":attrs->Manufacturer);
                (void) fprintf(stdout, "%s%s %s\n",
                    getIndentSpaces(4), "Model: ",
                    attrs->Model[0] == 0? "not available":attrs->Model);
                (void) fprintf(stdout, "%s%s %s\n",
                    getIndentSpaces(4),
                    "Firmware Version:",
                    attrs->FirmwareVersion[0] == 0? "not available":
                    attrs->FirmwareVersion);
                (void) fprintf(stdout, "%s%s %s\n",
                    getIndentSpaces(4),
                    "FCode/BIOS Version:",
                    attrs->OptionROMVersion[0] == 0? "not available":
                    attrs->OptionROMVersion);
                (void) fprintf(stdout, "%s%s %s\n",
                    getIndentSpaces(4),
                    "Serial Number:",
                    attrs->SerialNumber[0] == 0? "not available":
                    attrs->SerialNumber);
                (void) fprintf(stdout, "%s%s %s\n",
                    getIndentSpaces(4),
                    "Driver Name:",
                    attrs->DriverName[0] == 0? "not available":
                    attrs->DriverName);
                (void) fprintf(stdout, "%s%s %s\n",
                    getIndentSpaces(4),
                    "Driver Version:",
                    attrs->DriverVersion[0] == 0? "not available":
                    attrs->DriverVersion);
                (void) fprintf(stdout, "%s%s %d\n",
                    getIndentSpaces(4),
                    "Number of HBA Ports:",
                    numberOfPorts);
        }
}

/*
 * prints out all the HBA port information
 */
void
printHBAPortInfo(SMHBA_PORTATTRIBUTES *port,
    SMHBA_ADAPTERATTRIBUTES *attrs, int pflag) {

        if ((port == NULL) || (attrs == NULL)) {
                return;
        }

        (void) fprintf(stdout, "%s%s %s\n",
            getIndentSpaces(2),
            "HBA Port Name:",
            port->OSDeviceName);

        if (!(pflag & PRINT_VERBOSE)) {
                return;
        }

        if (port->PortType != HBA_PORTTYPE_SASDEVICE)
                return;

        (void) fprintf(stdout, "%s%s %s\n",
            getIndentSpaces(4),
            "Type:",
            getStateString(port->PortType, porttype_string));
        (void) fprintf(stdout, "%s%s %s\n",
            getIndentSpaces(4),
            "State:",
            getStateString(port->PortState, portstate_string));

        (void) fprintf(stdout, "%s%s %016llx\n",
            getIndentSpaces(4),
            "Local SAS Address:",
            wwnConversion(port->PortSpecificAttribute.SASPort->\
            LocalSASAddress.wwn));

        (void) fprintf(stdout, "%s%s %016llx\n",
            getIndentSpaces(4),
            "Attached SAS Address:",
            wwnConversion(port->PortSpecificAttribute.SASPort->\
            AttachedSASAddress.wwn));

        (void) fprintf(stdout, "%s%s %d\n",
            getIndentSpaces(4),
            "Number of Phys:",
            port->PortSpecificAttribute.SASPort->NumberofPhys);
}

void
printHBAPortPhyInfo(SMHBA_SAS_PHY *phyinfo)
{
        if (phyinfo == NULL)
                return;

        (void) fprintf(stdout, "%s%s %u\n",
            getIndentSpaces(6),
            "Identifier:",
            phyinfo->PhyIdentifier);

        (void) fprintf(stdout, "%s%s %s\n",
            getIndentSpaces(8),
            "State: ",
            getPhyStateString(phyinfo->NegotiatedLinkRate, PHY_STATE));
        (void) fprintf(stdout, "%s%s %s/%s\n",
            getIndentSpaces(8),
            "HardwareLinkRate(Min/Max):",
            getPhyStateString(phyinfo->HardwareMinLinkRate, PHY_SPEED),
            getPhyStateString(phyinfo->HardwareMaxLinkRate, PHY_SPEED));
        (void) fprintf(stdout, "%s%s %s/%s\n",
            getIndentSpaces(8),
            "ProgrammedLinkRate(Min/Max):",
            getPhyStateString(phyinfo->ProgrammedMinLinkRate, PHY_SPEED),
            getPhyStateString(phyinfo->ProgrammedMaxLinkRate, PHY_SPEED));
        (void) fprintf(stdout, "%s%s %s\n",
            getIndentSpaces(8),
            "NegotiatedLinkRate:",
            getPhyStateString(phyinfo->NegotiatedLinkRate, PHY_SPEED));
}

void
printHBAPortPhyStatistics(SMHBA_SASPHYSTATISTICS *phystat)
{
        if (phystat == NULL)
                return;

        (void) fprintf(stdout, "%s%s\n",
            getIndentSpaces(8),
            "Link Error Statistics:");
        (void) fprintf(stdout, "%s%s %llu\n",
            getIndentSpaces(12),
            "Invalid Dword:",
            phystat->InvalidDwordCount);
        (void) fprintf(stdout, "%s%s %llu\n",
            getIndentSpaces(12),
            "Running Disparity Error:",
            phystat->RunningDisparityErrorCount);
        (void) fprintf(stdout, "%s%s %llu\n",
            getIndentSpaces(12),
            "Loss of Dword Sync:",
            phystat->LossofDwordSyncCount);
        (void) fprintf(stdout, "%s%s %llu\n",
            getIndentSpaces(12),
            "Reset Problem:",
            phystat->PhyResetProblemCount);
}

/*
 * print the OS device name for the logical-unit object
 *
 * Arguments:
 *      devListWalk - OS device path info
 *      verbose - boolean indicating whether to display additional info
 *
 * returns:
 *      0 - we're good.
 *      >0 - we met issues.
 */
int
printTargetPortInfo(targetPortList_t *TPListWalk, int pflag)
{
        targetPortConfig_t      *configList;
        targetPortMappingData_t *mapList;
        int                     count, i;
        int                     ret = 0;

        (void) fprintf(stdout, "Target Port SAS Address: %016llx\n",
            wwnConversion(TPListWalk->sasattr.LocalSASAddress.wwn));
        if ((pflag & PRINT_VERBOSE) || (pflag & PRINT_TARGET_SCSI)) {
                (void) fprintf(stdout, "%sType: %s\n", getIndentSpaces(4),
                    getStateString(TPListWalk->targetattr.PortType,
                    porttype_string));
                for (configList = TPListWalk->configEntry;
                    configList != NULL; configList = configList->next) {
                        (void) fprintf(stdout, "%sHBA Port Name: %s\n",
                            getIndentSpaces(4), configList->hbaPortName);
                        if (wwnConversion(configList->expanderSASAddr.wwn) !=
                            0) {
                                if (configList->expanderValid) {
                                        (void) fprintf(stdout,
                                            "%sExpander Device SAS Address:"
                                            " %016llx",
                                            getIndentSpaces(8),
                                            wwnConversion(configList->
                                            expanderSASAddr.wwn));
                                } else {
                                        (void) fprintf(stdout,
                                            "%sExpander Device SAS Address:"
                                            " %016llx (Failed to Validate"
                                            " Attached Port.)",
                                            getIndentSpaces(8),
                                            wwnConversion(configList->
                                            expanderSASAddr.wwn));
                                        ret++;
                                }
                        } else {
                                if (configList->expanderValid) {
                                        (void) fprintf(stdout,
                                            "%sExpander Device SAS Address: %s",
                                            getIndentSpaces(8),
                                            "None (direct attached)");
                                } else {
                                        (void) fprintf(stdout,
                                            "%sExpander Device SAS Address: %s",
                                            getIndentSpaces(8),
                                            "None (Failed to Get"
                                            " Attached Port)");
                                }
                        }
                        (void) fprintf(stdout, "\n");
                        if (pflag & PRINT_TARGET_SCSI) {

                                if (configList->reportLUNsFailed) {
                                        (void) fprintf(stdout,
                                            "%s %016llx\n",
                                            gettext("Error: Failed to get "
                                            "ReportLun Data on"),
                                            wwnConversion(TPListWalk->
                                            sasattr.LocalSASAddress.wwn));
                                        ret++;
                                        continue;
                                }

                                for (mapList = configList->map;
                                    mapList != NULL; mapList = mapList->next) {
                                        (void) fprintf(stdout, "%sLUN : %d\n",
                                            getIndentSpaces(12),
                                            mapList->osLUN);
                                        if (mapList->mappingExist) {
                                                (void) fprintf(stdout,
                                                    "%sOS Device Name : %s\n",
                                                    getIndentSpaces(14),
                                                    (mapList->osDeviceName[0] ==
                                                    '\0') ?  "Not avaialble" :
                                                    mapList->osDeviceName);
                                        } else {
                                                (void) fprintf(stdout,
                                                    "%sOS Device Name : %s\n",
                                                    getIndentSpaces(14), "No "
                                                    "matching OS Device "
                                                    "found.");
                                                ret++;
                                        }
                /* indentation changed here */
                if (mapList->inquiryFailed) {
                        (void) fprintf(stdout, "%s %s LUN %d\n",
                            gettext("Error: Failed to get Inquiry Data on"),
                            mapList->osDeviceName, mapList->osLUN);
                        ret++;
                } else {
                        (void) fprintf(stdout, "%sVendor: ",
                            getIndentSpaces(14));
                        for (count = sizeof (mapList->inq_vid), i = 0;
                            i < count; i++) {
                                if (isprint(mapList->inq_vid[i]))
                                        (void) fprintf(stdout, "%c",
                                            mapList->inq_vid[i]);
                        }

                        (void) fprintf(stdout, "\n%sProduct: ",
                            getIndentSpaces(14));
                        for (count = sizeof (mapList->inq_pid), i = 0;
                            i < count; i++) {
                                if (isprint(mapList->inq_pid[i]))
                                        (void) fprintf(stdout, "%c",
                                            mapList->inq_pid[i]);
                        }

                        (void) fprintf(stdout, "\n%sDevice Type: %s\n",
                            getIndentSpaces(14),
                            getDTypeString(mapList->inq_dtype));
                }
                /* indentation changed back */
                                }
                        }
                }
        }
        return (ret);
}

/*
 * print the OS device name for the logical-unit object
 *
 * Arguments:
 *      devListWalk - OS device path info
 *      verbose - boolean indicating whether to display additional info
 *
 * returns:
 *      0 - we're good.
 *      >0 - we met issues.
 */
int
printOSDeviceNameInfo(discoveredDevice *devListWalk, boolean_t verbose)
{
        portList                *portElem;
        tgtPortWWNList          *tgtWWNList;
        int                     i, count;
        int                     ret = 0;

        (void) fprintf(stdout, "OS Device Name: %s\n",
            devListWalk->OSDeviceName);
        if (verbose == B_TRUE) {
                for (portElem = devListWalk->HBAPortList;
                    portElem != NULL; portElem = portElem->next) {
                        (void) fprintf(stdout, "%sHBA Port Name: ",
                            getIndentSpaces(4));
                        (void) fprintf(stdout, "%s", portElem->portName);
                        for (tgtWWNList = portElem->tgtPortWWN;
                            tgtWWNList != NULL; tgtWWNList = tgtWWNList->next) {
                                (void) fprintf(stdout,
                                    "\n%sTarget Port SAS Address: ",
                                    getIndentSpaces(8));
                                (void) fprintf(stdout, "%016llx",
                                    wwnConversion(tgtWWNList->portWWN.wwn));
                                (void) fprintf(stdout, "\n%sLUN: %u",
                                    getIndentSpaces(12),
                                    tgtWWNList->scsiOSLun);
                        }
                        (void) fprintf(stdout, "\n");
                }

                if (devListWalk->inquiryFailed) {
                        (void) fprintf(stdout, "%s %s\n",
                            gettext("Error: Failed to get Inquiry data "
                            "on device"), devListWalk->OSDeviceName);
                        ret++;
                } else {
                        (void) fprintf(stdout, "%sVendor: ",
                            getIndentSpaces(4));
                        for (count = sizeof (devListWalk->VID), i = 0;
                            i < count; i++) {
                                if (isprint(devListWalk->VID[i]))
                                        (void) fprintf(stdout, "%c",
                                            devListWalk->VID[i]);
                        }

                        (void) fprintf(stdout, "\n%sProduct: ",
                            getIndentSpaces(4));
                        for (count = sizeof (devListWalk->PID), i = 0;
                            i < count; i++) {
                                if (isprint(devListWalk->PID[i]))
                                        (void) fprintf(stdout, "%c",
                                            devListWalk->PID[i]);
                        }

                        (void) fprintf(stdout, "\n%sDevice Type: %s\n",
                            getIndentSpaces(4),
                            getDTypeString(devListWalk->dType));
                }
        }
        return (ret);
}