/*
* 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 "cfga_fp.h"
/*
* This file contains helper routines for the FP plugin
*/
#if !defined(TEXT_DOMAIN)
#endif
typedef struct strlist {
const char *str;
} strlist_t;
typedef struct {
} errcvt_t;
typedef struct {
int type;
typedef struct {
int type;
/* defines for nftw() */
#define NFTW_CONTINUE 0
/* Function prototypes */
/* Globals */
struct {
void *arg;
/*
* The string table contains most of the strings used by the fp cfgadm plugin.
* All strings which are to be internationalized must be in this table.
* Some strings which are not internationalized are also included here.
* Arguments to messages are NOT internationalized.
*/
/*
* The first element (ERR_UNKNOWN) MUST always be present in the array.
*/
/* msg_code num_args, I18N msg_string */
/* ERRORS */
{ERR_CONF_OK_UPD_REP, 0, 1,
"Configuration successful, but Repository update failed"},
{ERR_UNCONF_OK_UPD_REP, 0, 1,
"Unconfiguration successful, but Repository update failed"},
{ERR_PARTIAL_SUCCESS, 0, 1,
"Operation partially successful. Some failures seen"},
{ERR_HBA_LOAD_LIBRARY, 0, 1,
"HBA load library failed"},
{ERR_MATCHING_HBA_PORT, 0, 1,
"No match HBA port found"},
{ERR_NO_ADAPTER_FOUND, 0, 1,
"No Fibre Channel adapters found"},
/* Errors with arguments */
"failed to create device node... Device may be unconfigurable: "},
/* Fibre Channel operation Errors */
"Failed to initialize device map for: "},
/* MPXIO Errors */
/* RCM Errors */
/* Commands */
{CMD_INSERT_DEV, 0, 0, "insert_device"},
{CMD_REMOVE_DEV, 0, 0, "remove_device"},
{CMD_REPLACE_DEV, 0, 0, "replace_device"},
{CMD_RESET_DEV, 0, 0, "reset_device"},
{CMD_RESET_BUS, 0, 0, "reset_bus"},
{CMD_RESET_ALL, 0, 0, "reset_all"},
/* help messages */
{MSG_HELP_USAGE, 0, 0,
"\t-c configure -o force_update ap_id [ap_id..]\n"
"\t-c configure -o no_update ap_id [ap_id...]\n"
"\t-c unconfigure -o force_update ap_id [ap_id... ]\n"
"\t-c unconfigure -o no_update ap_id [ap_id... ]\n"},
/* hotplug messages */
/* Hotplugging confirmation prompts */
"This operation will suspend activity on FC bus: "},
{CONF_UNQUIESCE, 0, 1,
"FC bus quiesced successfully.\n"
"It is now safe to proceed with hotplug operation."
"\nEnter y if operation is complete or n to abort"},
/* Misc. */
{WARN_DISCONNECT, 0, 1,
"WARNING: Disconnecting critical partitions may cause system hang."
"\nContinue"}
};
{ FPCFGA_LIB_ERR, CFGA_LIB_ERROR },
{ FPCFGA_NACK, CFGA_NACK },
{ FPCFGA_BUSY, CFGA_BUSY },
{ FPCFGA_PRIV, CFGA_PRIV },
{ FPCFGA_UNKNOWN_ERR, CFGA_ERROR },
{ FPCFGA_ERR, CFGA_ERROR }
};
#define DEV_OP 0
};
};
/* Order is important. Earlier directories are searched first */
static const char *dev_dir_hints[] = {
};
/*
* Routine to search the /dev directory or a subtree of /dev.
* If the entire /dev hierarchy is to be searched, the most likely directories
* are searched first.
*/
const char *basedir,
void *arg,
{
errno = 0;
goto out;
}
/*
* Search certain selected subdirectories first if basedir == "/dev".
* Ignore errors as some of these directories may not exist.
*/
for (i = 0; i < N_DEV_DIR_HINTS; i++) {
errno = 0;
FTW_PHYS)) == NFTW_TERMINATE) {
break;
}
}
/*FALLTHRU*/
out:
}
/*ARGSUSED*/
static int
const char *path,
int type,
{
/* We want only VALID symlinks */
return (NFTW_CONTINUE);
}
/* terminate prematurely, but may not be error */
errno = 0;
return (NFTW_TERMINATE);
} else {
return (NFTW_CONTINUE);
}
}
{
int i;
for (i = 0; i < N_ERR_CVT_TBL; i++) {
return (err_cvt_tbl[i].cfga_err);
}
}
return (CFGA_ERROR);
}
/*
* Removes duplicate slashes from a pathname and any trailing slashes.
* Returns "/" if input is "/"
*/
char *
{
int prev_was_slash = 0;
*l_errnop = 0;
return (NULL);
}
return (NULL);
}
prev_was_slash = 0;
if (!prev_was_slash || c != '/') {
*dp++ = c;
}
if (c == '/') {
prev_was_slash = 1;
} else {
prev_was_slash = 0;
}
}
/* Remove trailing slash except if it is the first char */
*(--dp) = '\0';
} else {
*dp = '\0';
}
return (dup);
}
{
int l_errno = 0;
return (FPCFGA_LIB_ERR);
}
/* Extract the base(hba) and dynamic(device) component if any */
goto err;
}
if (GET_LUN_DYN(dyncomp)) {
goto err;
}
/* Remove the dynamic component from the base. */
*dyn = '\0';
}
/* Get the path of dynamic attachment point if already configured. */
goto err;
}
}
return (FPCFGA_OK);
err:
return (ret);
}
static void
{
}
}
void
{
return;
}
const char *physpath,
void *arg,
int *l_errnop)
{
int rv;
char *devfs_fp_path;
int found = 0;
*l_errnop = 0;
return (FPCFGA_LIB_ERR);
}
/* Fix up path for di_init() */
} else if (*root_path != '/') {
*l_errnop = 0;
ret = FPCFGA_ERR;
goto out;
}
/* Remove dynamic component if any */
*cp = '\0';
}
/* Remove minor name if any */
*cp = '\0';
}
/*
* If force_flag is set
* do di_init with DINFOFORCE flag and get to the input fp node
* from the device tree.
*
* In order to get the link between path_info node and scsi_vhci node
* it is required to take the snapshot of the whole device tree.
* this behavior of libdevinfo is inefficient. For a specific
* fca port DINFOPROP was sufficient on the fca path prior to
* scsi_vhci node support.
*
*/
} else {
}
if (tree_root == DI_NODE_NIL) {
goto out;
}
while (fpnode) {
found = 1;
break;
}
}
if (!(found)) {
goto out;
} else {
}
/* Walk the tree */
errno = 0;
if (cmd == FPCFGA_WALK_NODE) {
} else {
}
if (rv != 0) {
} else {
} else {
*l_errnop = 0;
}
}
/*FALLTHRU*/
out:
return (ret);
}
int
{
int idx = 0;
/* The string table index and the error id may or may not be same */
} else {
break;
}
}
}
return (idx);
}
/*
* cfga_err() accepts a variable number of message IDs and constructs
* a corresponding error string which is returned via the errstring argument.
* cfga_err() calls dgettext() to internationalize proper messages.
* May be called with a NULL argument.
*/
void
{
int append_newline = 0;
return;
}
/*
* Don't append a newline, the application (for example cfgadm)
* should do that.
*/
append_newline = 0;
*errstring = tmp_err_str;
return;
}
/*
* *errstring != NULL
* There was something in errstring prior to this call.
* So, concatenate the old and new strings
*/
/* In case of error, retain only the earlier message */
return;
}
}
/*
* This routine accepts a variable number of message IDs and constructs
* a corresponding message string which is printed via the message print
* routine argument.
*/
void
{
char *p = NULL;
return;
}
/* Append a newline after message */
append_newline = 1;
l_errno = 0;
S_FREE(p);
}
/*
* Get internationalized string corresponding to message id
* Caller must free the memory allocated.
*/
char *
{
char *p = NULL;
int l_errno = 0;
return (p);
}
static void
{
int a = 0;
int i = 0, n = 0;
return;
}
n = GET_MSG_NARGS(a); /* 0 implies no additional args */
for (i = 0; i <= n; i++) {
goto out;
}
if (i == 0 && GET_MSG_INTL(a)) {
} else if (i == 0) {
} else {
}
}
}
s = t = NULL;
if (l_errno) {
}
}
if (append_newline) {
len++;
}
goto out;
}
**msgpp = '\0';
}
}
if (append_newline) {
}
/* FALLTHROUGH */
out:
}
}
const char *physpath,
int *l_errnop)
{
int (*func)(const devctl_hdl_t);
*l_errnop = 0;
state_func = NULL;
type = 0;
for (i = 0; i < N_GET_STATE_CMDS; i++) {
break;
}
}
if (state_func == NULL) {
for (i = 0; i < N_SET_STATE_CMDS; i++) {
break;
}
}
}
return (FPCFGA_ERR);
}
/*
* Fix up path for calling devctl.
*/
return (FPCFGA_LIB_ERR);
}
/* Remove dynamic component if any */
*cp = '\0';
}
/* Remove minor name */
*cp = '\0';
}
errno = 0;
} else {
}
return (FPCFGA_ERR);
}
errno = 0;
/* Only getstate functions require a second argument */
} else {
rv = -1;
*l_errnop = 0;
}
}
/*
* Is device in a known state ? (One of BUSY, ONLINE, OFFLINE)
* BUSY --> One or more device special files are open. Implies online
* ONLINE --> driver attached
* OFFLINE --> CF1 with offline flag set.
* UNKNOWN --> None of the above
*/
int
{
/*
* CF1 without offline flag set is considered unknown state.
* We are in a known state if either CF2 (driver attached) or
* offline.
*/
return (1);
}
return (0);
}
void
{
}
}
/*
* Obtain the devlink from a /devices path
*/
const char *basedir,
char *xport_phys,
char **xport_logpp,
int *l_errnop,
int match_minor)
{
/*
* Search the /dev hierarchy starting at basedir.
*/
} else {
}
*xport_logpp = NULL;
}
return (ret);
}
static fpcfga_recur_t
{
return (FPCFGA_CONTINUE);
}
/* Is this the physical path we are looking for */
return (FPCFGA_CONTINUE);
}
} else {
}
return (FPCFGA_TERMINATE);
}
/* Compare HBA physical ap_id and device path */
int
{
int rv;
/* Remove dynamic component if any */
*cp = '\0';
}
*cp = '\0';
}
/* Remove minor names */
*cp = '\0';
}
*cp = '\0';
}
/* Check if HBA path is component of device path */
return (rv);
}
/* devpath must have '/' and 1 char in addition to hba path */
return (0);
} else {
return (-1);
}
}
int
{
int rv;
*mn1 = '\0';
}
*mn2 = '\0';
}
/* Separate out the minor names */
*mn1++ = '\0';
}
*mn2++ = '\0';
}
return (rv);
}
/*
* Compare minor names
*/
return (0);
return (-1);
return (1);
} else {
}
}
/*
* 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 ||
status == HBA_STATUS_ERROR_BUSY) &&
count++ < HBA_MAX_RETRIES) {
if (status == HBA_STATUS_OK) {
break;
}
sleep(1);
}
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 ||
status == HBA_STATUS_ERROR_BUSY) &&
count++ < HBA_MAX_RETRIES) {
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);
}
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 ||
status == HBA_STATUS_ERROR_BUSY) &&
count++ < HBA_MAX_RETRIES) {
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);
}
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 ||
status == HBA_STATUS_ERROR_BUSY) &&
count++ < HBA_MAX_RETRIES) {
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);
}
return (status);
}
/*
* Find the Adapter port that matches the portPath.
* When the matching port is found the caller have to close handle
* and free library.
*/
char **errstring)
{
status = HBA_LoadLibrary();
if (status != HBA_STATUS_OK) {
return (FPCFGA_LIB_ERR);
}
if (count == 0) {
return (FPCFGA_LIB_ERR);
}
/* Loop over all HBAs */
if (status != HBA_STATUS_OK) {
/* May have been DR'd */
continue;
}
if (handle == 0) {
/* May have been DR'd */
continue;
}
do {
/* Should never happen */
continue;
}
/* Loop over all HBA Ports */
for (portIndex = 0;
&portAttrs)) != HBA_STATUS_OK) {
/* Need to refresh adapter */
if (status ==
break;
} else {
continue;
}
}
/*
* link or the physical path
*/
strlen(CFGA_DEV_DIR)) != 0) {
if (matchingHandle)
if (matchingPortIndex)
if (matchingPortAttrs)
return (FPCFGA_OK);
}
} else {
/*
* the OSDeviceName make sure that the
* OSDeviceName is at least
* second 1 is to make sure there is
* somthing after
*/
continue;
if (logical_apid == NULL) {
/*
* the portPath
*/
if (make_xport_logid(portPath,
ERR_LIST, 0);
return
}
}
/* compare logical ap_id */
if (strcmp(logical_apid,
cfg_ptr) == 0) {
if (matchingHandle)
if (matchingPortIndex)
if (matchingPortAttrs)
return (FPCFGA_OK);
}
}
}
if (logical_apid != NULL)
} while ((status == HBA_STATUS_ERROR_STALE_DATA) &&
(retry++ < HBA_MAX_RETRIES));
}
/* Got here. No matching adapter port found. */
return (FPCFGA_LIB_ERR);
}