/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <hbaapi.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <errno.h>
#include <libdevice.h>
#include <config_admin.h>
#include <sys/byteorder.h>
#include "common.h"
#include "sun_fc_version.h"
LUN_SIZE + \
struct lun_val {
};
struct rep_luns_rsp {
};
/* Extracted from the old scsi.h file */
struct capacity_data_struct {
};
/* Structure to handle the inq. page 0x80 serial number */
struct page80 {
};
extern char *dtype[];
extern int Options;
extern const int OPTION_P;
int skip_hba(int i);
/*
* The routines within this file operate against the T11
* HBA API interface. In some cases, proprietary Sun driver
* interface are also called to add additional information
* above what the standard library supports.
*/
}
switch (status) {
case HBA_STATUS_OK:
return;
case HBA_STATUS_ERROR:
return;
return;
return;
case HBA_STATUS_ERROR_ARG:
return;
return;
return;
return;
return;
return;
case HBA_STATUS_ERROR_BUSY:
return;
return;
return;
default:
return;
}
}
if (count == 0) {
"\nERROR: No Fibre Channel Adapters found.\n"));
}
return (count);
}
/*
* Returns non-zero on failure (aka, HBA_STATUS_ERROR_*
* Will handle retries if applicable.
*/
int
int count = 0;
/* Loop as long as we have a retryable error */
while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
if (status == HBA_STATUS_OK) {
break;
}
(void) sleep(1);
}
if (status != HBA_STATUS_OK) {
/* We encountered a non-retryable error */
"\nERROR: Unable to retrieve adapter port details (%s)"),
name);
}
return (status);
}
/*
* Returns non-zero on failure (aka, HBA_STATUS_ERROR_*
* Will handle retries if applicable.
*/
int
int count = 0;
/* Loop as long as we have a retryable error */
while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
if (status == HBA_STATUS_OK) {
break;
}
/* The odds of this occuring are very slim, but possible. */
if (status == HBA_STATUS_ERROR_STALE_DATA) {
/*
* If we hit a stale data scenario,
* we'll just tell the user to try again.
*/
break;
}
sleep(1);
}
if (status != HBA_STATUS_OK) {
/* We encountered a non-retryable error */
"\nERROR: Unable to retrieve adapter port details (%s)"),
name);
}
return (status);
}
/*
* Returns non-zero on failure (aka, HBA_STATUS_ERROR_*
* Will handle retries if applicable.
*/
int
int count = 0;
/* Loop as long as we have a retryable error */
while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
if (status == HBA_STATUS_OK) {
break;
}
/* The odds of this occuring are very slim, but possible. */
if (status == HBA_STATUS_ERROR_STALE_DATA) {
/*
* If we hit a stale data scenario, we'll just tell the
* user to try again.
*/
break;
}
sleep(1);
}
if (status != HBA_STATUS_OK) {
/* We encountered a non-retryable error */
"\nERROR: Unable to retrieve target port details (%s)"),
name);
}
return (status);
}
/*ARGSUSED*/
int
{
int retval = 0;
if ((retval = loadLibrary())) {
return (retval);
}
count = getNumberOfAdapters();
if (skip_hba(adapterIndex)) {
continue;
}
if (status != HBA_STATUS_OK) {
/* Just skip it, maybe it was DR'd */
continue;
}
if (handle == 0) {
/* Just skip it, maybe it was DR'd */
continue;
}
/* This should never happen, we'll just skip the adapter */
continue;
}
portIndex++) {
&portAttrs)) {
continue;
}
if (physical) {
if (tmp) {
*tmp = '\0';
physical);
} else {
physical);
}
} else {
}
if (portAttrs.NumberofDiscoveredPorts > 0) {
} else {
}
}
}
(void) HBA_FreeLibrary();
return (retval);
}
/*
* so we can ensure uniqueness
*/
struct path_entry {
};
}
return (tmp);
}
}
return (NULL);
}
}
}
int
int i;
for (i = 0; i < 16; i++) {
return (0);
}
}
return (1);
}
return (0);
}
int
return (0);
}
return (1);
}
/* We take a wild guess for our first get target mappings call */
int loop = 0;
int count = 0;
sizeof (HBA_FCPTARGETMAPPINGV2));
/* Loop as long as we have a retryable error */
while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
status == HBA_STATUS_ERROR_BUSY ||
if (status == HBA_STATUS_OK) {
break;
} else if (status == HBA_STATUS_ERROR_MORE_DATA) {
sizeof (HBA_FCPTARGETMAPPINGV2));
continue;
}
sleep(1);
}
if (status != HBA_STATUS_OK) {
/* We encountered a non-retryable error */
"\nERROR: Unable to retrieve SCSI device paths "
"(HBA Port WWN %016llx)"),
}
return (status);
}
/*
* Returns the index of the first match, or -1 if no match
*/
int
int mapIndex;
char *tmp;
int wwnCompare = 0;
return (-1);
}
wwnCompare = 1;
} else {
/* Convert the paths to phsyical paths */
}
if (wwnCompare) {
if (wwn == wwnConversion(
wwn == wwnConversion(
return (mapIndex);
}
} else {
return (mapIndex);
}
}
}
}
if (physical) {
}
return (-1);
}
/*
* returns non-zero on failure (aka HBA_STATUS_ERROR_*
*/
int
loadLibrary() {
if (status != HBA_STATUS_OK) {
"ERROR: Unable to load HBA API library: "));
}
return (status);
}
int
if (loadLibrary()) {
return (-1);
}
count = getNumberOfAdapters();
/* Loop over all HBAs */
if (skip_hba(adapterIndex)) {
continue;
}
if (status != HBA_STATUS_OK) {
/* May have been DR'd */
continue;
}
if (handle == 0) {
/* May have been DR'd */
continue;
}
/* Should not happen, just skip it */
continue;
}
/* Loop over all HBA Ports */
portIndex++) {
&portAttrs)) {
continue;
}
continue;
}
/* Loop over all target Mapping entries */
mapIndex ++) {
int doInquiry = 0;
if (!head) {
sizeof (struct path_entry));
sizeof (HBA_UINT8) * 8);
doInquiry = 1;
doInquiry = 0;
} else {
doInquiry = 1;
}
} else {
tmpPath = (struct path_entry *)
sizeof (HBA_UINT8) * 8);
doInquiry = 1;
}
if (doInquiry) {
lun, 0, 0,
&inq, &inquirySize,
if (status != HBA_STATUS_OK) {
}
}
}
}
}
if (head) {
printf(" ");
"Reserved"));
} else {
"Unknown"));
}
printf("\n ");
printf("\n");
/* We probably shouldn't be using a g_fc interface here */
char *phys_path =
}
}
}
}
return (0);
}
int
{
int ret = 0;
if (loadLibrary()) {
return (-1);
}
found = 0;
wwnCompare = 1;
argv[path_index]);
ret = -1;
continue;
}
if (!wwnCompare) {
/* Convert the paths to phsyical paths */
if (!physical) {
"Error: Invalid pathname (%s)"),
argv[path_index]);
ret = -1;
continue;
}
}
count = getNumberOfAdapters();
/* Loop over all HBAs */
if (skip_hba(adapterIndex)) {
continue;
}
if (status != HBA_STATUS_OK) {
/* May have been DR'd */
continue;
}
if (handle == 0) {
/* May have been DR'd */
continue;
}
/* Should never happen */
continue;
}
/* Loop over all HBA Ports */
portIndex++) {
&portAttrs)) {
continue;
}
continue;
}
mapIndex ++) {
matched = 0;
if (wwnCompare) {
if (wwn == wwnConversion(
wwn == wwnConversion(
matched = 1;
}
} else {
MAXPATHLEN) == 0)) {
matched = 1;
}
}
if (matched) {
lun, 0, 0,
&inq, &inquirySize,
if (status == HBA_STATUS_OK) {
/*
* Call the inquiry cmd on page 0x80 only if
* the vendor supports page 0x80
*/
lun, 0x80))) {
&serial, &serialSize,
if (status != HBA_STATUS_OK) {
(char *)serial.inq_serial,
"Unavailable",
sizeof (serial.inq_serial));
}
} else {
"Unsupported",
sizeof (serial.inq_serial));
}
/*
* we are adding serial number information
* from 0x80. If length is less than 39,
* then we want to increase length to 52 to
* reflect the fact that we have serial number
* information
*/
}
sizeof (serial.inq_serial));
if (! wwnCompare) {
found = 1;
break;
}
} else {
"Error: I/O failure communicating with %s "),
}
}
}
if (found == 1) {
break;
}
}
if (found == 1) {
break;
}
}
if (physical) {
}
if (!goodPath) {
argv[path_index]);
ret = -1;
}
}
return (ret);
}
int
{
int path_index = 0;
int matched;
int done;
int ret = 0;
if (loadLibrary()) {
return (-1);
}
argv[path_index]);
ret = -1;
continue;
}
count = getNumberOfAdapters();
done = 0;
/* Loop over all HBAs */
adapterIndex ++) {
if (skip_hba(adapterIndex)) {
continue;
}
if (status != HBA_STATUS_OK) {
/* May have been DR'd */
continue;
}
if (handle == 0) {
/* May have been DR'd */
continue;
}
/* Should never happen */
continue;
}
/* Loop over all HBA Ports */
portIndex++) {
&portAttrs)) {
continue;
}
matched = 0;
if (wwn == wwnConversion(
wwn == wwnConversion(
matched = 1;
}
} else {
STANDARD_DEVNAME_HANDLING)) != NULL) &&
STANDARD_DEVNAME_HANDLING)) != NULL)) {
if (tmp) {
*tmp = '\0';
} else {
if (tmp) {
*tmp = '\0';
}
}
matched = 1;
}
}
if (physical) {
}
if (comp_phys) {
}
}
if (mapIndex >= 0) {
matched = 1;
}
} else {
continue;
}
if (matched) {
"Pos Port_ID Hard_Addr Port WWN"
" Node WWN Type\n"));
for (discIndex = 0;
discIndex++) {
discIndex, &discPortAttrs)) {
/* Move on to the next target */
continue;
}
printf("%-4d %-6x %-6x %016llx %016llx",
/*
* devices are not all required to respond to
* Scsi Inquiry calls sent to LUN 0. We must
* fisrt issue a ReportLUN and then send the
* SCSI Inquiry call to the first LUN Returned
* from the ReportLUN call
*/
if (status == HBA_STATUS_OK) {
lun_resp =
(struct rep_luns_rsp *)
(unsigned long)raw_luns;
} else {
/*
* in case we are unable to retrieve report
* LUN data, we will blindly try sending the
* INQUIRY to lun 0.
*/
lun = 0;
}
lun, 0, 0,
&inq, &inquirySize,
if (status != HBA_STATUS_OK) {
}
}
/* Now dump this HBA's stats */
printf("%-4d %-6x %-6x %016llx %016llx",
done = 1;
}
}
}
if (!goodPath) {
argv[path_index]);
ret = -1;
}
}
return (ret);
}
int
{
int path_index = 0;
int matched;
int ret = 0;
if (loadLibrary()) {
return (-1);
}
argv[path_index]);
ret = -1;
continue;
}
count = getNumberOfAdapters();
/* Loop over all HBAs */
if (skip_hba(adapterIndex)) {
continue;
}
if (status != HBA_STATUS_OK) {
/* May have been DR'd */
continue;
}
if (handle == 0) {
/* May have been DR'd */
continue;
}
/* Should never happen */
continue;
}
/* Loop over all HBA Ports */
portIndex++) {
&portAttrs)) {
continue;
}
matched = 0;
if (wwn == wwnConversion(
wwn == wwnConversion(
matched = 1;
}
} else {
STANDARD_DEVNAME_HANDLING)) != NULL) &&
STANDARD_DEVNAME_HANDLING)) != NULL)) {
if (tmp) {
*tmp = '\0';
} else {
if (tmp) {
*tmp = '\0';
}
}
matched = 1;
}
}
if (physical) {
}
if (comp_phys) {
}
}
if (!matched) {
continue;
}
}
" sync loss signal loss sequence err"
" invalid word CRC\n"));
for (discIndex = 0;
discIndex++) {
discIndex, &discPortAttrs)) {
continue;
}
if (status != HBA_STATUS_OK) {
}
"%x\t%-12d%-12d%-14d%-15d%-15d%-12d\n",
} else {
"%x\t%-12u%-12u%-14u%-15u%-15u%-12u\n",
}
}
/* Now dump this HBA's stats */
if (status != HBA_STATUS_OK) {
}
"%x\t%-12d%-12d%-14d%-15d%-15d%-12d\n",
} else {
"%x\t%-12u%-12u%-14u%-15u%-15u%-12u\n",
}
}
}
}
if (!goodPath) {
argv[path_index]);
ret = -1;
}
}
" cleared by a reset, only power cycles.\n"
"These counts must be compared"
" to previously read counts.\n"));
return (ret);
}
typedef struct _PathInformation {
struct lun_tracking {
/* Points to another lun_tracking instance with the same map->LUID */
/* Points to next lun_tracking with a different map->LUID */
};
static void
{
int retval = 0;
/* Only proceed if we are an mpxio path */
return;
}
/* First get the controller path */
/* Now skip over the leading "../.." */
return;
}
/* Now chop off the trailing ":xxx" portion if present */
if (trailingCruft) {
trailingCruft[0] = '\0';
}
} else {
return;
}
if (retval != 0) {
exit(-1);
}
for (i = 0; i < pathcnt; i++) {
/* This could break someday if MPxIO changes devaddr */
prop_buf_size, &nvl, 0);
if (retval != 0) {
"UNKNOWN PROB");
} else {
&path_class_val) == 0) {
} else {
}
}
found++;
break;
}
}
}
if (!found) {
}
/* free everything we alloced */
}
}
/* Utility routine to add new entries to the list (ignores dups) */
static void
{
sizeof (HBA_LUID)) == 0) {
/* Ensure this isn't a duplicate */
return;
}
}
return;
}
/* We have a new entry to add */
sizeof (struct lun_tracking));
path);
return;
}
}
/* Append a new LUN at the end of the list */
sizeof (struct lun_tracking));
path);
}
/*ARGSUSED*/
int
{
int path_index = 0;
float lunMbytes;
int offset;
int mpxio = 0;
int wwnCompare = 0;
int ret = 0;
if ((status = loadLibrary())) {
return (-1);
}
wwnCompare = 1;
argv[path_index]);
ret = -1;
continue;
}
if (!wwnCompare) {
/* Convert the paths to phsyical paths */
if (!physical) {
"Error: Invalid pathname (%s)"),
argv[path_index]);
ret = -1;
continue;
}
}
count = getNumberOfAdapters();
/*
* We have to loop twice to ensure we don't miss any
* extra paths for other targets in a multi-target device
*/
if (skip_hba(adapterIndex)) {
continue;
}
if (status != HBA_STATUS_OK) {
/* May have been DR'd */
continue;
}
if (handle == 0) {
/* May have been DR'd */
continue;
}
/* Should never happen */
continue;
}
/* Loop over all HBA Ports */
portIndex++) {
int matched = 0;
int mapIndex;
char *tmp;
&portAttrs)) {
continue;
}
continue;
}
mapIndex ++) {
matched = 0;
if (wwnCompare) {
if (wwn == wwnConversion(
wwn == wwnConversion(
matched = 1;
}
} else {
MAXPATHLEN) == 0)) {
matched = 1;
}
}
sizeof (struct lun_tracking));
} else if (matched) {
}
}
}
}
if (physical) {
}
/* Now do it again and look for matching LUIDs (aka GUIDs) */
if (skip_hba(adapterIndex)) {
continue;
}
if (status != HBA_STATUS_OK) {
/* May have been DR'd */
continue;
}
if (handle == 0) {
/* May have been DR'd */
continue;
}
/* Should never happen */
continue;
}
/* Loop over all HBA Ports */
portIndex++) {
int matched = 0;
int mapIndex;
&portAttrs)) {
continue;
}
continue;
}
mapIndex ++) {
matched = 0;
sizeof (HBA_LUID)) == 0) {
matched = 1;
break;
}
}
if (matched) {
break;
}
}
sizeof (struct lun_tracking));
} else if (matched) {
}
}
}
}
if (!goodPath) {
argv[path_index]);
ret = -1;
/* Just bomb out instead of going on */
return (ret);
}
}
/* Now display all the LUNs that we found that matched */
{
/* Change behavior if this is an MPxIO device */
mpxio = 1;
}
}
/* continue to next online path */
continue;
}
if (status != HBA_STATUS_OK) {
"Error: Failed to get handle for %s "),
/* continue to next path */
continue;
}
lun, 0, 0,
&inq, &inquirySize,
if (status == HBA_STATUS_OK) {
break;
}
}
"Error: I/O failure communicating with %s "),
continue;
}
case DTYPE_DIRECT:
"DEVICE PROPERTIES for disk: %s\n"),
break;
case DTYPE_SEQUENTIAL: /* Tape */
"DEVICE PROPERTIES for tape: %s\n"),
break;
default:
"DEVICE PROPERTIES for: %s\n"),
break;
}
/*
* Call the inquiry cmd on page 0x80 only if the vendor
* supports page 0x80.
*/
&serial, &serialSize,
if (status == HBA_STATUS_OK) {
sizeof (serial.inq_serial), 0);
} else {
}
} else {
}
/* Read capacity wont work on standby paths, so try till OK */
/* continue to next online path */
continue;
}
if (status != HBA_STATUS_OK) {
/* continue to next path */
continue;
}
if (status == HBA_STATUS_OK) {
break;
} else if (status == HBA_STATUS_SCSI_CHECK_CONDITION &&
/*
* retry for check-condition state when unit attention
* condition has been established
*/
if (status == HBA_STATUS_OK) {
break;
}
}
}
}
if (handle != HBA_HANDLE_INVALID) {
}
if (status != HBA_STATUS_OK) {
/* Make sure we don't display garbage */
cap_data.block_size = 0;
cap_data.last_block_addr = 0;
}
if (cap_data.block_size > 0 &&
cap_data.last_block_addr > 0) {
"Unformatted capacity:\t%6.3f MBytes"), lunMbytes);
}
/*
* get mode page information for FC device.
* do not do mode sense if this is a tape device.
* mode sense will rewind the tape
*/
&pg_buf) == 0) {
mode_header_ptr = (struct mode_header_g1 *)
(void *)pg_buf;
offset = sizeof (struct mode_header_g1) +
sizeof (mode_header_ptr->length))) {
pg8_buf = (struct mode_caching *)
(void *)pg_hdr;
" Write Cache:\t\t"
"Enabled\n"));
}
" Read Cache:\t\t"
"Enabled\n"));
" Minimum prefetch:\t0x%x\n"
" Maximum prefetch:\t0x%x\n"),
}
break;
}
sizeof (struct mode_page);
}
}
}
} else {
/* dtype of 0x1f is returned */
}
}
/* Now display all paths to this LUN */
/* Display the controller information */
" Device Address\t\t%016llx,%x\n"),
" Host controller port WWN\t%016llx\n"),
if (mpxio) {
}
}
}
printf("\n");
}
}
return (ret);
}
/*
* handle expert-mode hotplug commands
*
* return 0 iff all is okay
*/
int
{
int exit_code;
if (todo != DEV_ONLINE &&
todo != DEV_OFFLINE) {
return (-1);
}
/* Convert the paths to phsyical paths */
if (!path_phys) {
"Error: Invalid pathname (%s)"),
argv[0]);
return (-1);
}
if (verbose_flag) {
MSGSTR(5516,
"phys path = \"%s\"\n"),
}
/* acquire rights to hack on device */
"Error: can't acquire \"%s\": %s\n"),
return (1);
}
switch (todo) {
case DEV_ONLINE:
break;
case DEV_OFFLINE:
break;
}
if (exit_code != 0) {
}
/* all done now -- release device */
if (path_phys) {
}
return (exit_code);
}
/*
* Returns non zero if we should use FC-HBA.
* For x86, luxadm uses FC-HBA.
*/
int
{
#ifdef __x86
return (1);
#else
return (0);
#endif
}
/*
* Returns non-zero if we should skip the HBA at index "i"
*/
int
skip_hba(int i) {
(void) HBA_GetVendorLibraryAttributes(i, &lib_attrs);
return (0);
}
return (1);
}
/*
* Function to determine if the given page is supported by vendor.
*/
int
{
int index;
if (status == HBA_STATUS_OK) {
return (1);
}
}
}
return (0);
}