summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/cfgadm_plugins/scsi/common/cfga_ctl.c62
-rw-r--r--usr/src/lib/cfgadm_plugins/scsi/common/cfga_cvt.c181
-rw-r--r--usr/src/lib/cfgadm_plugins/scsi/common/cfga_list.c381
-rw-r--r--usr/src/lib/cfgadm_plugins/scsi/common/cfga_rcm.c25
-rw-r--r--usr/src/lib/cfgadm_plugins/scsi/common/cfga_scsi.c14
-rw-r--r--usr/src/lib/cfgadm_plugins/scsi/common/cfga_scsi.h23
-rw-r--r--usr/src/lib/cfgadm_plugins/scsi/common/cfga_utils.c241
-rw-r--r--usr/src/lib/fm/topo/modules/common/disk/disk_common.c15
-rw-r--r--usr/src/lib/libdevice/llib-ldevice59
-rw-r--r--usr/src/lib/libdevid/libdevid.h1
-rw-r--r--usr/src/lib/libdevid/mapfile-vers1
-rw-r--r--usr/src/lib/libdevinfo/devinfo.c14
-rw-r--r--usr/src/lib/libdevinfo/libdevinfo.h2
-rw-r--r--usr/src/lib/libdevinfo/mapfile-vers1
-rw-r--r--usr/src/lib/mpapi/libmpscsi_vhci/common/MP_GetMultipathLusPlugin.c50
15 files changed, 863 insertions, 207 deletions
diff --git a/usr/src/lib/cfgadm_plugins/scsi/common/cfga_ctl.c b/usr/src/lib/cfgadm_plugins/scsi/common/cfga_ctl.c
index c9ce0c6e4f..f81b54a804 100644
--- a/usr/src/lib/cfgadm_plugins/scsi/common/cfga_ctl.c
+++ b/usr/src/lib/cfgadm_plugins/scsi/common/cfga_ctl.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "cfga_scsi.h"
struct larg {
@@ -299,44 +297,54 @@ dev_change_state(
break;
}
- /* When unconfiguring a device, first offline it through RCM. */
- if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
- if (cmd == SCFGA_DEV_UNCONFIGURE) {
- dev_list[0] = get_node_path(apidp->path);
- if (dev_list[0] == NULL) {
- ret = SCFGA_ERR;
- break;
- }
- if ((ret = scsi_rcm_offline(dev_list,
- errstring, flags)) != SCFGA_OK) {
- break;
+ if (apidp->dyntype == PATH_APID) {
+ /* call a scsi_vhci ioctl to do online/offline path. */
+ ret = path_apid_state_change(apidp, cmd,
+ flags, errstring, &l_errno, errid);
+ } else {
+ /*
+ * When unconfiguring a device, first offline it
+ * through RCM.
+ */
+ if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
+ if (cmd == SCFGA_DEV_UNCONFIGURE) {
+ dev_list[0] =
+ get_node_path(apidp->path);
+ if (dev_list[0] == NULL) {
+ ret = SCFGA_ERR;
+ break;
+ }
+ if ((ret = scsi_rcm_offline(dev_list,
+ errstring, flags)) != SCFGA_OK) {
+ break;
+ }
}
}
- }
- ret = devctl_cmd(apidp->path, cmd, NULL, &l_errno);
- if (ret != SCFGA_OK) {
- cfga_err(errstring, l_errno, errid, 0);
+ ret = devctl_cmd(apidp->path, cmd, NULL, &l_errno);
+ if (ret != SCFGA_OK) {
+ cfga_err(errstring, l_errno, errid, 0);
/*
* If an unconfigure fails, cancel the RCM offline.
* Discard any RCM failures so that the devctl
* failure will still be reported.
*/
- if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
- if (cmd == SCFGA_DEV_UNCONFIGURE)
- (void) scsi_rcm_online(dev_list,
- errstring, flags);
+ if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
+ if (cmd == SCFGA_DEV_UNCONFIGURE)
+ (void) scsi_rcm_online(dev_list,
+ errstring, flags);
+ }
+ break;
}
- break;
- }
- if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
+ if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
/*
* Unconfigure succeeded, call the RCM notify_remove.
*/
- if (cmd == SCFGA_DEV_UNCONFIGURE)
- (void) scsi_rcm_remove(dev_list,
+ if (cmd == SCFGA_DEV_UNCONFIGURE)
+ (void) scsi_rcm_remove(dev_list,
errstring, flags);
+ }
}
break;
diff --git a/usr/src/lib/cfgadm_plugins/scsi/common/cfga_cvt.c b/usr/src/lib/cfgadm_plugins/scsi/common/cfga_cvt.c
index e41debdb87..e3e260f9f5 100644
--- a/usr/src/lib/cfgadm_plugins/scsi/common/cfga_cvt.c
+++ b/usr/src/lib/cfgadm_plugins/scsi/common/cfga_cvt.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 1999, 2001-2002 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "cfga_scsi.h"
typedef struct {
@@ -78,6 +75,8 @@ static scfga_ret_t drv_to_dyncomp(di_node_t node, const char *phys,
char **dyncompp, int *l_errnop);
static scfga_ret_t get_hba_devlink(const char *hba_phys,
char **hba_logpp, int *l_errnop);
+static scfga_ret_t path_apid_dyn_to_path(const char *hba_phys, const char *dyn,
+ char **pathpp, int *l_errnop);
/* Globals */
@@ -263,19 +262,152 @@ apid_to_path(
/*
* If the dynamic component has a '/', it was derived from a devlink
* Else it was derived from driver name and instance number.
+ * If it is pathinfo instance number based ap id, it will have a format
+ * path#.???.
*/
if (strchr(dyncomp, '/') != NULL) {
ret = devlink_dyn_to_devpath(hba_phys, dyncomp, pathpp,
l_errnop);
+ } else if (strstr(dyncomp, PATH_APID_DYN_SEP) != NULL) {
+ ret = path_apid_dyn_to_path(hba_phys, dyncomp, pathpp,
+ l_errnop);
} else {
ret = drv_dyn_to_devpath(hba_phys, dyncomp, pathpp, l_errnop);
}
-
assert(ret != SCFGA_OK || *pathpp != NULL);
+
return (ret);
}
+/*
+ * Get the devfs path of pathinfo node that is associated with
+ * the given dynamic component.
+ *
+ * input
+ * hba_phys: physical path of HBA
+ * dyn : bus address of pathinfo node
+ * output:
+ * pathpp: devfs path of the pathinfo node.
+ */
+static scfga_ret_t
+path_apid_dyn_to_path(
+ const char *hba_phys,
+ const char *dyn,
+ char **pathpp,
+ int *l_errnop)
+{
+
+ di_node_t root, walk_root;
+ di_path_t pi_node = DI_PATH_NIL;
+ char *root_path, *devpath, *cp;
+ int len;
+
+ *l_errnop = 0;
+
+ /* *pathpp should be NULL if pathpp is not NULL. */
+ if ((hba_phys == NULL) || (pathpp != NULL) && (*pathpp != NULL)) {
+ return (SCFGA_LIB_ERR);
+ }
+
+ if ((root_path = strdup(hba_phys)) == NULL) {
+ *l_errnop = errno;
+ return (SCFGA_LIB_ERR);
+ }
+
+ /* Fix up path for di_init() */
+ len = strlen(DEVICES_DIR);
+ if (strncmp(root_path, DEVICES_DIR SLASH,
+ len + strlen(SLASH)) == 0) {
+ cp = root_path + len;
+ (void) memmove(root_path, cp, strlen(cp) + 1);
+ } else if (*root_path != '/') {
+ *l_errnop = 0;
+ S_FREE(root_path);
+ return (SCFGA_ERR);
+ }
+
+ /* Remove dynamic component if any */
+ if ((cp = GET_DYN(root_path)) != NULL) {
+ *cp = '\0';
+ }
+
+ /* Remove minor name if any */
+ if ((cp = strrchr(root_path, ':')) != NULL) {
+ *cp = '\0';
+ }
+
+ /*
+ * Cached snapshots are always rooted at "/"
+ */
+
+ /* Get a snapshot */
+ if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
+ *l_errnop = errno;
+ S_FREE(root_path);
+ return (SCFGA_ERR);
+ }
+
+ /*
+ * Lookup the subtree of interest
+ */
+ walk_root = di_lookup_node(root, root_path);
+
+ if (walk_root == DI_NODE_NIL) {
+ *l_errnop = errno;
+ di_fini(root);
+ S_FREE(root_path);
+ return (SCFGA_LIB_ERR);
+ }
+
+ S_FREE(root_path);
+
+ if ((pi_node = di_path_next_client(walk_root, pi_node)) ==
+ DI_PATH_NIL) {
+ di_fini(root);
+ return (SCFGA_APID_NOEXIST);
+ }
+
+ /*
+ * now parse the path info node.
+ */
+ do {
+ /* check the length first. */
+ if (strlen(di_path_bus_addr(pi_node)) != strlen(dyn)) {
+ continue;
+ }
+
+ if (strcmp(di_path_bus_addr(pi_node), dyn) == 0) {
+ /* get the devfspath of pathinfo node. */
+ devpath = di_path_devfs_path(pi_node);
+ if (devpath == NULL) {
+ *l_errnop = errno;
+ di_fini(root);
+ return (SCFGA_ERR);
+ }
+
+ len = strlen(DEVICES_DIR) + strlen(devpath) + 1;
+ *pathpp = calloc(1, len);
+ if (*pathpp == NULL) {
+ *l_errnop = errno;
+ di_devfs_path_free(devpath);
+ di_fini(root);
+ return (SCFGA_ERR);
+ } else {
+ (void) snprintf(*pathpp, len, "%s%s",
+ DEVICES_DIR, devpath);
+ di_devfs_path_free(devpath);
+ di_fini(root);
+ return (SCFGA_OK);
+ }
+ }
+ pi_node = di_path_next_client(walk_root, pi_node);
+ } while (pi_node != DI_PATH_NIL);
+
+ di_fini(root);
+ return (SCFGA_APID_NOEXIST);
+}
+
static scfga_ret_t
drv_dyn_to_devpath(
const char *hba_phys,
@@ -497,7 +629,7 @@ make_dyncomp(
path = (char *)physpath;
} else {
match_minor = 1;
- snprintf(pathbuf, MAXPATHLEN, "%s:%s", physpath,
+ (void) snprintf(pathbuf, MAXPATHLEN, "%s:%s", physpath,
di_minor_name(minor));
path = pathbuf;
}
@@ -527,6 +659,36 @@ make_dyncomp(
return (ret);
}
+/*
+ * Create a dynamic component of path ap_id for the given path info node.
+ * The caller should free the buffer for the dynamic component.
+ */
+scfga_ret_t
+make_path_dyncomp(
+ di_path_t path,
+ char **dyncompp,
+ int *l_errnop)
+{
+ char *pi_addr;
+
+ if ((path == DI_PATH_NIL) || (*dyncompp != NULL)) {
+ return (SCFGA_LIB_ERR);
+ }
+
+ if ((pi_addr = di_path_bus_addr(path)) != NULL) {
+ *dyncompp = calloc(1, strlen(pi_addr) + 1);
+ if (*dyncompp == NULL) {
+ *l_errnop = errno;
+ return (SCFGA_LIB_ERR);
+ }
+ (void) strncpy(*dyncompp, pi_addr, strlen(pi_addr));
+ } else {
+ return (SCFGA_LIB_ERR);
+ }
+
+ return (SCFGA_OK);
+}
+
/*ARGSUSED*/
static scfga_ret_t
drv_to_dyncomp(di_node_t node, const char *phys, char **dyncompp, int *l_errnop)
@@ -723,7 +885,8 @@ tape_devlink_to_dyncomp(dyn_t *dyntp)
cp = strrchr(dyntp->dyncomp, '/');
/* Remove the mode part */
- while (isdigit(*(++cp)));
+ while (isdigit(*(++cp))) {
+ };
*cp = '\0';
diff --git a/usr/src/lib/cfgadm_plugins/scsi/common/cfga_list.c b/usr/src/lib/cfgadm_plugins/scsi/common/cfga_list.c
index a58847e280..5a010a3dd1 100644
--- a/usr/src/lib/cfgadm_plugins/scsi/common/cfga_list.c
+++ b/usr/src/lib/cfgadm_plugins/scsi/common/cfga_list.c
@@ -41,6 +41,7 @@ typedef struct {
uint_t itype;
const char *ntype;
const char *name;
+ const char *pathname;
} scfga_devtype_t;
/* The TYPE field is parseable and should not contain spaces */
@@ -57,28 +58,30 @@ static scfga_ret_t do_stat_dev(const di_node_t node, const char *nodepath,
scfga_list_t *lap, int limited_dev_stat);
static cfga_stat_t bus_devinfo_to_recep_state(uint_t bus_di_state);
static cfga_stat_t dev_devinfo_to_occupant_state(uint_t dev_di_state);
-static char *get_device_type(di_node_t);
-static void get_hw_info(di_node_t node, cfga_list_data_t *clp);
+static char *get_device_type(di_node_t, dyncomp_t);
+static void get_hw_info(di_node_t node, cfga_list_data_t *clp, dyncomp_t type);
+static scfga_ret_t create_pathinfo_ldata(di_path_t pi_node, scfga_list_t *lap,
+ int *l_errnop);
static scfga_devtype_t device_list[] = {
- { DTYPE_DIRECT, DDI_NT_BLOCK_CHAN, "disk"},
- { DTYPE_DIRECT, DDI_NT_BLOCK, "disk"},
- { DTYPE_DIRECT, DDI_NT_BLOCK_WWN, "disk"},
- { DTYPE_DIRECT, DDI_NT_BLOCK_FABRIC, "disk"},
- { DTYPE_DIRECT, DDI_NT_BLOCK_SAS, "disk"},
- { DTYPE_SEQUENTIAL, DDI_NT_TAPE, "tape"},
- { DTYPE_PRINTER, NULL, "printer"},
- { DTYPE_PROCESSOR, NULL, "processor"},
- { DTYPE_WORM, NULL, "WORM"},
- { DTYPE_RODIRECT, DDI_NT_CD_CHAN, "CD-ROM"},
- { DTYPE_RODIRECT, DDI_NT_CD, "CD-ROM"},
- { DTYPE_SCANNER, NULL, "scanner"},
- { DTYPE_OPTICAL, NULL, "optical"},
- { DTYPE_CHANGER, NULL, "med-changer"},
- { DTYPE_COMM, NULL, "comm-device"},
- { DTYPE_ARRAY_CTRL, NULL, "array-ctrl"},
- { DTYPE_ESI, NULL, "ESI"}
+ { DTYPE_DIRECT, DDI_NT_BLOCK_CHAN, "disk", "disk-path"},
+ { DTYPE_DIRECT, DDI_NT_BLOCK, "disk", "disk-path"},
+ { DTYPE_DIRECT, DDI_NT_BLOCK_WWN, "disk", "disk-path"},
+ { DTYPE_DIRECT, DDI_NT_BLOCK_FABRIC, "disk", "disk-path"},
+ { DTYPE_DIRECT, DDI_NT_BLOCK_SAS, "disk", "disk-path"},
+ { DTYPE_SEQUENTIAL, DDI_NT_TAPE, "tape", "tape-path"},
+ { DTYPE_PRINTER, NULL, "printer", "printer-path"},
+ { DTYPE_PROCESSOR, NULL, "processor", "PRCS-path"},
+ { DTYPE_WORM, NULL, "WORM", "WORM-path"},
+ { DTYPE_RODIRECT, DDI_NT_CD_CHAN, "CD-ROM", "CD-ROM-path"},
+ { DTYPE_RODIRECT, DDI_NT_CD, "CD-ROM", "CD-ROM-path"},
+ { DTYPE_SCANNER, NULL, "scanner", "scanner-path"},
+ { DTYPE_OPTICAL, NULL, "optical", "optical-path"},
+ { DTYPE_CHANGER, NULL, "med-changer", "MEDCHGR-path"},
+ { DTYPE_COMM, NULL, "comm-device", "COMDEV-path"},
+ { DTYPE_ARRAY_CTRL, NULL, "array-ctrl", "ARRCTRL-path"},
+ { DTYPE_ESI, NULL, "ESI", "ESI-path"}
};
#define N_DEVICE_TYPES (sizeof (device_list) / sizeof (device_list[0]))
@@ -182,15 +185,42 @@ do_list(
}
/* we need to stat at least 1 device for all commands */
- u.node_args.flags = DI_WALK_CLDFIRST;
- u.node_args.fcn = stat_dev;
+ if (apidp->dyntype == PATH_APID) {
+ /*
+ * When cmd is SCFGA_STAT_DEV and the ap id is pathinfo
+ * related.
+ */
+ ret = walk_tree(apidp->hba_phys, &larg, init_flag, NULL,
+ SCFGA_WALK_PATH, &larg.l_errno);
+ } else {
+ /* we need to stat at least 1 device for all commands */
+ u.node_args.flags = DI_WALK_CLDFIRST;
+ u.node_args.fcn = stat_dev;
- /*
- * Subtree is ALWAYS rooted at the HBA (not at the device) as
- * otherwise deadlock may occur if bus is disconnected.
- */
- ret = walk_tree(apidp->hba_phys, &larg, init_flag, &u,
- SCFGA_WALK_NODE, &larg.l_errno);
+ /*
+ * Subtree is ALWAYS rooted at the HBA (not at the device) as
+ * otherwise deadlock may occur if bus is disconnected.
+ */
+ ret = walk_tree(apidp->hba_phys, &larg, init_flag, &u,
+ SCFGA_WALK_NODE, &larg.l_errno);
+
+ /*
+ * Check path info on the following conditions.
+ *
+ * - chld_config is still set to CFGA_STAT_UNCONFIGURED for
+ * SCFGA_STAT_BUS cmd after walking any child node.
+ * - walking node succeeded for SCFGA_STAT_ALL cmd(Continue on
+ * stating path info node).
+ * - apid is pathinfo associated and larg.ret is still set to
+ * SCFGA_APID_NOEXIST for SCFGA_STAT_DEV cmd.
+ */
+ if (((cmd == SCFGA_STAT_BUS) &&
+ (larg.chld_config == CFGA_STAT_UNCONFIGURED)) ||
+ ((cmd == SCFGA_STAT_ALL) && (ret == SCFGA_OK))) {
+ ret = walk_tree(apidp->hba_phys, &larg, init_flag, NULL,
+ SCFGA_WALK_PATH, &larg.l_errno);
+ }
+ }
if (ret != SCFGA_OK || (ret = larg.ret) != SCFGA_OK) {
if (ret != SCFGA_APID_NOEXIST) {
@@ -380,10 +410,189 @@ out:
return (rv);
}
+/*
+ * Create list date entry and add to ldata list.
+ */
+static scfga_ret_t
+create_pathinfo_ldata(di_path_t pi_node, scfga_list_t *lap, int *l_errnop)
+{
+ ldata_list_t *listp = NULL;
+ cfga_list_data_t *clp;
+ di_node_t client_node = DI_NODE_NIL;
+ di_minor_t minor;
+ scfga_ret_t ret;
+ di_path_state_t pi_state;
+ char *dyncomp = NULL, *client_path = NULL;
+ char pathbuf[MAXPATHLEN], *client_devlink = NULL;
+ int match_minor;
+
+ listp = calloc(1, sizeof (ldata_list_t));
+ if (listp == NULL) {
+ lap->l_errno = errno;
+ return (SCFGA_LIB_ERR);
+ }
+ clp = &listp->ldata;
+ ret = make_path_dyncomp(pi_node, &dyncomp, &lap->l_errno);
+ if (ret != SCFGA_OK) {
+ S_FREE(listp);
+ return (ret);
+ }
+
+ client_node = di_path_client_node(pi_node);
+ if (client_node == DI_NODE_NIL) {
+ *l_errnop = errno;
+ S_FREE(dyncomp);
+ return (SCFGA_LIB_ERR);
+ }
+
+ /* Create logical and physical ap_id */
+ (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s%s%s",
+ lap->hba_logp, DYN_SEP, dyncomp);
+
+ (void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s%s%s",
+ lap->apidp->hba_phys, DYN_SEP, dyncomp);
+
+ S_FREE(dyncomp);
+
+ /* ap class filled in by libcfgadm */
+ clp->ap_class[0] = '\0';
+ clp->ap_r_state = lap->hba_rstate;
+ /* path info exist so set to configured. */
+ clp->ap_o_state = CFGA_STAT_CONFIGURED;
+
+ /* now fill up ap_info field with client dev link and instance #. */
+ client_path = di_devfs_path(client_node);
+ if (client_path) {
+ /* get first minor node. */
+ minor = di_minor_next(client_node, DI_MINOR_NIL);
+ if (minor == DI_MINOR_NIL) {
+ match_minor = 0;
+ (void) snprintf(pathbuf, MAXPATHLEN, "%s:%s",
+ DEVICES_DIR, client_path);
+ } else {
+ match_minor = 1;
+ (void) snprintf(pathbuf, MAXPATHLEN, "%s%s:%s",
+ DEVICES_DIR, client_path, di_minor_name(minor));
+ }
+ (void) physpath_to_devlink(pathbuf, &client_devlink, l_errnop,
+ match_minor);
+ di_devfs_path_free(client_path);
+ }
+
+ if (client_devlink) {
+ (void) snprintf(clp->ap_info, CFGA_INFO_LEN,
+ "%s: %s", "Client Device", client_devlink);
+ S_FREE(client_devlink);
+ }
+
+ get_hw_info(client_node, clp, PATH_APID);
+
+ if ((pi_state = di_path_state(pi_node)) == DI_PATH_STATE_OFFLINE) {
+ clp->ap_o_state = CFGA_STAT_UNCONFIGURED;
+ }
+
+ if (pi_state == DI_PATH_STATE_FAULT) {
+ clp->ap_cond = CFGA_COND_FAILED;
+ } else {
+ clp->ap_cond = CFGA_COND_UNKNOWN;
+ }
+
+ /* no way to determine state change */
+ clp->ap_busy = 0;
+ clp->ap_status_time = (time_t)-1;
+
+ /* Link it in */
+ listp->next = lap->listp;
+ lap->listp = listp;
+
+ return (SCFGA_OK);
+}
+
+/*
+ * Routine to stat pathinfo nodes.
+ *
+ * No pathinfo founds returns a success.
+ * When cmd is SCFGA_STAT_DEV, finds a matching pathinfo node and
+ * and create ldata if found.
+ * When cmd is SCFGA_STAT_ALL, create ldata for each pathinfo node.
+ * When cmd is SCFGA_STAT_BUS, checks if any pathinfo exist.
+ *
+ * Return:
+ * 0 for success
+ * -1 for failure.
+ */
+int
+stat_path_info(
+ di_node_t root,
+ void *arg,
+ int *l_errnop)
+{
+ scfga_list_t *lap = (scfga_list_t *)arg;
+ di_path_t pi_node;
+
+ if (root == DI_NODE_NIL) {
+ return (-1);
+ }
+
+ /*
+ * when there is no path_info node return SCFGA_OK.
+ */
+ if (di_path_next_client(root, DI_PATH_NIL) == DI_PATH_NIL) {
+ return (0);
+ }
+
+ if (lap->cmd == SCFGA_STAT_BUS) {
+ lap->chld_config = CFGA_STAT_CONFIGURED;
+ return (0);
+ } else if (lap->cmd == SCFGA_STAT_DEV) {
+ assert(lap->apidp->dyntype == PATH_APID);
+ for (pi_node = di_path_next_client(root, DI_PATH_NIL); pi_node;
+ pi_node = di_path_next_client(root, pi_node)) {
+ /*
+ * NOTE: apidt_create() validated pathinfo apid so
+ * the apid should have a valid format.
+ */
+
+ /* check the length first. */
+ if (strlen(di_path_bus_addr(pi_node)) !=
+ strlen(lap->apidp->dyncomp)) {
+ continue;
+ }
+
+ /* check for full match. */
+ if (strcmp(di_path_bus_addr(pi_node),
+ lap->apidp->dyncomp)) {
+ continue;
+ }
+
+ /* found match, record information */
+ if (create_pathinfo_ldata(pi_node, lap,
+ l_errnop) == SCFGA_OK) {
+ lap->ret = SCFGA_OK;
+ return (0);
+ } else {
+ return (-1);
+ }
+ }
+ } else { /* cmd = STAT_ALL */
+ /* set child config to configured */
+ lap->chld_config = CFGA_STAT_CONFIGURED;
+ for (pi_node = di_path_next_client(root, DI_PATH_NIL); pi_node;
+ pi_node = di_path_next_client(root, pi_node)) {
+ /* continue on even if there is an error on one path. */
+ (void) create_pathinfo_ldata(pi_node, lap, l_errnop);
+ }
+ }
+
+ lap->ret = SCFGA_OK;
+ return (0);
+
+}
struct bus_state {
int b_state;
int b_retired;
+ char iconnect_type[16];
};
static scfga_ret_t
@@ -395,6 +604,8 @@ do_stat_bus(scfga_list_t *lap, int limited_bus_stat)
struct bus_state bstate = {0};
walkarg_t u;
scfga_ret_t ret;
+ int i;
+ char itypelower[MAXNAMELEN];
assert(lap->hba_logp != NULL);
@@ -437,8 +648,24 @@ do_stat_bus(scfga_list_t *lap, int limited_bus_stat)
clp->ap_status_time = (time_t)-1;
clp->ap_info[0] = '\0';
- (void) snprintf(clp->ap_type, sizeof (clp->ap_type), "%s",
- SCFGA_BUS_TYPE);
+ if (bstate.iconnect_type) {
+ /*
+ * For SPI type, keep the existing SCFGA_BUS_TYPE.
+ * For other types, the ap type will be scsi-'interconnct-type'.
+ */
+ if (strcmp(bstate.iconnect_type, "SPI") == 0) {
+ (void) snprintf(clp->ap_type, sizeof (clp->ap_type),
+ "%s", SCFGA_BUS_TYPE);
+ } else {
+ for (i = 0; i < strlen(bstate.iconnect_type); i++) {
+ itypelower[i] =
+ tolower(bstate.iconnect_type[i]);
+ }
+ itypelower[i] = '\0';
+ (void) snprintf(clp->ap_type, sizeof (clp->ap_type),
+ "%s-%s", "scsi", itypelower);
+ }
+ }
/* Link it in */
listp->next = lap->listp;
@@ -451,9 +678,17 @@ static int
get_bus_state(di_node_t node, void *arg)
{
struct bus_state *bsp = (struct bus_state *)arg;
+ char *itype = NULL;
bsp->b_state = di_state(node);
bsp->b_retired = di_retired(node);
+ (void) di_prop_lookup_strings(DDI_DEV_T_ANY,
+ node, "initiator-interconnect-type", &itype);
+ if (itype != NULL) {
+ (void) strlcpy(bsp->iconnect_type, itype, 16);
+ } else {
+ bsp->iconnect_type[0] = '\0';
+ }
return (DI_WALK_TERMINATE);
}
@@ -521,7 +756,7 @@ do_stat_dev(
clp->ap_busy = 0; /* no way to determine state change */
clp->ap_status_time = (time_t)-1;
- get_hw_info(node, clp);
+ get_hw_info(node, clp, DEV_APID);
/* Link it in */
listp->next = lap->listp;
@@ -532,29 +767,50 @@ do_stat_dev(
/* fill in device type, vid, pid from properties */
static void
-get_hw_info(di_node_t node, cfga_list_data_t *clp)
+get_hw_info(di_node_t node, cfga_list_data_t *clp, dyncomp_t type)
{
char *cp = NULL;
char *inq_vid, *inq_pid;
+ char client_inst[MAXNAMELEN];
/*
* Fill in type information
*/
- cp = (char *)get_device_type(node);
+ cp = (char *)get_device_type(node, type);
if (cp == NULL) {
cp = (char *)GET_MSG_STR(ERR_UNAVAILABLE);
}
(void) snprintf(clp->ap_type, sizeof (clp->ap_type), "%s", S_STR(cp));
- /*
- * Fill in vendor and product ID.
- */
- if ((di_prop_lookup_strings(DDI_DEV_T_ANY, node,
- "inquiry-product-id", &inq_pid) == 1) &&
- (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
- "inquiry-vendor-id", &inq_vid) == 1)) {
- (void) snprintf(clp->ap_info, sizeof (clp->ap_info),
- "%s %s", inq_vid, inq_pid);
+ if (type == DEV_APID) {
+ /*
+ * Fill in vendor and product ID.
+ */
+ if ((di_prop_lookup_strings(DDI_DEV_T_ANY, node,
+ "inquiry-product-id", &inq_pid) == 1) &&
+ (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
+ "inquiry-vendor-id", &inq_vid) == 1)) {
+ (void) snprintf(clp->ap_info, sizeof (clp->ap_info),
+ "%s %s", inq_vid, inq_pid);
+ }
+ } else {
+ if ((di_driver_name(node) != NULL) &&
+ (di_instance(node) != -1)) {
+ if (clp->ap_info == NULL) {
+ (void) snprintf(client_inst, MAXNAMELEN - 1,
+ "%s%d", di_driver_name(node),
+ di_instance(node));
+ (void) snprintf(clp->ap_info, MAXNAMELEN - 1,
+ "Client Device: %s", client_inst);
+ } else {
+ (void) snprintf(client_inst, MAXNAMELEN - 1,
+ "(%s%d)", di_driver_name(node),
+ di_instance(node));
+ (void) strlcat(clp->ap_info, client_inst,
+ CFGA_INFO_LEN);
+ }
+ }
+
}
}
@@ -563,7 +819,7 @@ get_hw_info(di_node_t node, cfga_list_data_t *clp)
* derive it from minor node type
*/
static char *
-get_device_type(di_node_t node)
+get_device_type(di_node_t node, dyncomp_t type)
{
char *name = NULL;
int *inq_dtype;
@@ -582,7 +838,9 @@ get_device_type(di_node_t node)
if (device_list[i].itype == DTYPE_UNKNOWN)
continue;
if (itype == device_list[i].itype) {
- name = (char *)device_list[i].name;
+ name = (type == DEV_APID) ?
+ (char *)device_list[i].name :
+ (char *)device_list[i].pathname;
break;
}
}
@@ -599,7 +857,9 @@ get_device_type(di_node_t node)
if (device_list[i].ntype &&
(strcmp(nodetype, device_list[i].ntype)
== 0)) {
- name = (char *)device_list[i].name;
+ name = (type == DEV_APID) ?
+ (char *)device_list[i].name :
+ (char *)device_list[i].pathname;
break;
}
}
@@ -665,23 +925,10 @@ list_ext_postprocess(
static cfga_stat_t
bus_devinfo_to_recep_state(uint_t bus_di_state)
{
- cfga_stat_t rs;
+ if (bus_di_state & (DI_BUS_QUIESCED | DI_BUS_DOWN))
+ return (CFGA_STAT_DISCONNECTED);
- switch (bus_di_state) {
- case DI_BUS_QUIESCED:
- case DI_BUS_DOWN:
- rs = CFGA_STAT_DISCONNECTED;
- break;
- /*
- * NOTE: An explicit flag for active should probably be added to
- * libdevinfo.
- */
- default:
- rs = CFGA_STAT_CONNECTED;
- break;
- }
-
- return (rs);
+ return (CFGA_STAT_CONNECTED);
}
/*
@@ -690,15 +937,11 @@ bus_devinfo_to_recep_state(uint_t bus_di_state)
static cfga_stat_t
dev_devinfo_to_occupant_state(uint_t dev_di_state)
{
- /* Driver attached ? */
- if ((dev_di_state & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) {
+ if (dev_di_state & (DI_DEVICE_OFFLINE | DI_DEVICE_DOWN))
+ return (CFGA_STAT_UNCONFIGURED);
+
+ if (!(dev_di_state & DI_DRIVER_DETACHED))
return (CFGA_STAT_CONFIGURED);
- }
- if ((dev_di_state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE ||
- (dev_di_state & DI_DEVICE_DOWN) == DI_DEVICE_DOWN) {
- return (CFGA_STAT_UNCONFIGURED);
- } else {
- return (CFGA_STAT_NONE);
- }
+ return (CFGA_STAT_NONE);
}
diff --git a/usr/src/lib/cfgadm_plugins/scsi/common/cfga_rcm.c b/usr/src/lib/cfgadm_plugins/scsi/common/cfga_rcm.c
index 44bb5293c3..f65867f4ba 100644
--- a/usr/src/lib/cfgadm_plugins/scsi/common/cfga_rcm.c
+++ b/usr/src/lib/cfgadm_plugins/scsi/common/cfga_rcm.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "cfga_scsi.h"
#define MAX_FORMAT 80
@@ -59,7 +56,11 @@ scsi_rcm_offline(char **rsrclist, char **errstring, cfga_flags_t flags)
if ((rret = rcm_request_offline_list(rcm_handle, rsrclist, rflags,
&rinfo)) != RCM_SUCCESS) {
- cfga_err(errstring, 0, ERRARG_RCM_OFFLINE, 0);
+ if ((flags & FLAG_CLIENT_DEV) == FLAG_CLIENT_DEV) {
+ cfga_err(errstring, 0, ERRARG_RCM_CLIENT_OFFLINE, 0);
+ } else {
+ cfga_err(errstring, 0, ERRARG_RCM_OFFLINE, 0);
+ }
if (rinfo) {
(void) scsi_rcm_info_table(rinfo, errstring);
rcm_free_info(rinfo);
@@ -69,7 +70,7 @@ scsi_rcm_offline(char **rsrclist, char **errstring, cfga_flags_t flags)
rflags & ~RCM_FORCE, NULL);
ret = SCFGA_BUSY;
}
- rcm_free_handle(rcm_handle);
+ (void) rcm_free_handle(rcm_handle);
return (ret);
}
@@ -102,7 +103,7 @@ scsi_rcm_online(char **rsrclist, char **errstring, cfga_flags_t flags)
}
ret = SCFGA_BUSY;
}
- rcm_free_handle(rcm_handle);
+ (void) rcm_free_handle(rcm_handle);
return (ret);
}
@@ -136,7 +137,7 @@ scsi_rcm_remove(char **rsrclist, char **errstring, cfga_flags_t flags)
ret = SCFGA_BUSY;
}
- rcm_free_handle(rcm_handle);
+ (void) rcm_free_handle(rcm_handle);
return (ret);
}
@@ -182,7 +183,7 @@ scsi_rcm_suspend(char **rsrclist, char **errstring, cfga_flags_t flags,
(rflags & (~RCM_FORCE)), NULL);
ret = SCFGA_BUSY;
}
- rcm_free_handle(rcm_handle);
+ (void) rcm_free_handle(rcm_handle);
return (ret);
}
@@ -220,7 +221,7 @@ scsi_rcm_resume(char **rsrclist, char **errstring, cfga_flags_t flags,
}
ret = SCFGA_BUSY;
}
- rcm_free_handle(rcm_handle);
+ (void) rcm_free_handle(rcm_handle);
return (ret);
}
diff --git a/usr/src/lib/cfgadm_plugins/scsi/common/cfga_scsi.c b/usr/src/lib/cfgadm_plugins/scsi/common/cfga_scsi.c
index 07391c22d3..c11f48165f 100644
--- a/usr/src/lib/cfgadm_plugins/scsi/common/cfga_scsi.c
+++ b/usr/src/lib/cfgadm_plugins/scsi/common/cfga_scsi.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,13 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-
#include "cfga_scsi.h"
/*
@@ -142,6 +138,10 @@ cfga_private_func(
return (err_cvt(ret));
}
+ if (apidt.dyntype == PATH_APID) {
+ return (CFGA_OPNOTSUPP);
+ }
+
if (options != NULL)
apidt.flags |= FLAG_DISABLE_RCM;
diff --git a/usr/src/lib/cfgadm_plugins/scsi/common/cfga_scsi.h b/usr/src/lib/cfgadm_plugins/scsi/common/cfga_scsi.h
index 8e4748c4cf..b0aab187a7 100644
--- a/usr/src/lib/cfgadm_plugins/scsi/common/cfga_scsi.h
+++ b/usr/src/lib/cfgadm_plugins/scsi/common/cfga_scsi.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _CFGA_SCSI_H
#define _CFGA_SCSI_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -118,6 +116,7 @@ typedef enum {
SCFGA_REPLACE_DEV,
SCFGA_WALK_NODE,
SCFGA_WALK_MINOR,
+ SCFGA_WALK_PATH,
SCFGA_BUS_QUIESCE,
SCFGA_BUS_UNQUIESCE,
SCFGA_BUS_GETSTATE,
@@ -141,6 +140,12 @@ typedef enum {
SCFGA_CONTINUE
} scfga_recur_t;
+typedef enum {
+ NODYNCOMP = 1,
+ DEV_APID,
+ PATH_APID
+} dyncomp_t;
+
/* Structures for tree walking code */
@@ -180,7 +185,8 @@ typedef struct {
typedef struct {
char *hba_phys;
char *dyncomp;
- char *path;
+ dyncomp_t dyntype; /* is pathinfo or dev apid? */
+ char *path; /* for apid with device dyn comp. */
uint_t flags;
} apid_t;
@@ -192,6 +198,9 @@ typedef struct {
#define FLAG_DISABLE_RCM 0x01
#define FLAG_USE_DIFORCE 0x02
+/* internal use for handling pathinfo */
+#define FLAG_CLIENT_DEV 0x04
+
/* Message ids */
typedef enum {
@@ -239,6 +248,7 @@ ERR_RCM_HANDLE,
ERRARG_RCM_SUSPEND,
ERRARG_RCM_RESUME,
ERRARG_RCM_OFFLINE,
+ERRARG_RCM_CLIENT_OFFLINE,
ERRARG_RCM_ONLINE,
ERRARG_RCM_REMOVE,
@@ -323,6 +333,7 @@ typedef struct {
#define DYN_SEP "::"
#define MINOR_SEP ":"
+#define PATH_APID_DYN_SEP ","
#define S_FREE(x) (((x) != NULL) ? (free(x), (x) = NULL) : (void *)0)
#define S_STR(x) (((x) == NULL) ? "" : (x))
@@ -376,6 +387,7 @@ scfga_ret_t do_list(apid_t *apidp, scfga_cmd_t cmd,
ldata_list_t **llpp, int *nelem, char **errstring);
scfga_ret_t list_ext_postprocess(ldata_list_t **llpp, int nelem,
cfga_list_data_t **ap_id_list, int *nlistp, char **errstring);
+int stat_path_info(di_node_t root, void *arg, int *l_errnop);
/* Conversion routines */
@@ -385,6 +397,7 @@ scfga_ret_t apid_to_path(const char *hba_phys, const char *dyncomp,
char **pathpp, int *l_errnop);
scfga_ret_t make_dyncomp(di_node_t node, const char *physpath,
char **dyncompp, int *l_errnop);
+scfga_ret_t make_path_dyncomp(di_path_t path, char **dyncomp, int *l_errnop);
/* RCM routines */
@@ -411,6 +424,8 @@ void list_free(ldata_list_t **llpp);
int known_state(di_node_t node);
scfga_ret_t devctl_cmd(const char *ap_id, scfga_cmd_t cmd,
uint_t *statep, int *l_errnop);
+scfga_ret_t path_apid_state_change(apid_t *apidp, scfga_cmd_t cmd,
+ cfga_flags_t flags, char **errstring, int *l_errnop, msgid_t errid);
scfga_ret_t invoke_cmd(const char *func, apid_t *apidt, prompt_t *prp,
cfga_flags_t flags, char **errstring);
diff --git a/usr/src/lib/cfgadm_plugins/scsi/common/cfga_utils.c b/usr/src/lib/cfgadm_plugins/scsi/common/cfga_utils.c
index 65c4e9f96c..db570fd22a 100644
--- a/usr/src/lib/cfgadm_plugins/scsi/common/cfga_utils.c
+++ b/usr/src/lib/cfgadm_plugins/scsi/common/cfga_utils.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "cfga_scsi.h"
#include <libgen.h>
#include <limits.h>
@@ -125,6 +123,7 @@ msgcvt_t str_tbl[] = {
{ERRARG_RCM_SUSPEND, 0, 1, "failed to suspend: "},
{ERRARG_RCM_RESUME, 0, 1, "failed to resume: "},
{ERRARG_RCM_OFFLINE, 0, 1, "failed to offline: "},
+{ERRARG_RCM_CLIENT_OFFLINE, 0, 1, "failed to offline a client device: "},
{ERRARG_RCM_ONLINE, 0, 1, "failed to online: "},
{ERRARG_RCM_REMOVE, 0, 1, "failed to remove: "},
@@ -327,6 +326,7 @@ pathdup(const char *path, int *l_errnop)
return (dup);
}
+
scfga_ret_t
apidt_create(const char *ap_id, apid_t *apidp, char **errstring)
{
@@ -355,11 +355,22 @@ apidt_create(const char *ap_id, apid_t *apidp, char **errstring)
/* Remove the dynamic component from the base */
*dyn = '\0';
+ } else {
+ apidp->dyntype = NODYNCOMP;
+ }
+
+ /* get dyn comp type */
+ if (dyncomp != NULL) {
+ if (strstr(dyncomp, PATH_APID_DYN_SEP) != NULL) {
+ apidp->dyntype = PATH_APID;
+ } else {
+ apidp->dyntype = DEV_APID;
+ }
}
/* Create the path */
- if ((ret = apid_to_path(hba_phys, dyncomp, &path, &l_errno))
- != SCFGA_OK) {
+ if ((ret = apid_to_path(hba_phys, dyncomp, &path,
+ &l_errno)) != SCFGA_OK) {
cfga_err(errstring, l_errno, ERR_OP_FAILED, 0);
goto err;
}
@@ -471,6 +482,8 @@ walk_tree(
if (cmd == SCFGA_WALK_NODE) {
rv = di_walk_node(walk_root, up->node_args.flags, arg,
up->node_args.fcn);
+ } else if (cmd == SCFGA_WALK_PATH) {
+ rv = stat_path_info(walk_root, arg, l_errnop);
} else {
assert(cmd == SCFGA_WALK_MINOR);
rv = di_walk_minor(walk_root, up->minor_args.nodetype, 0, arg,
@@ -509,7 +522,8 @@ invoke_cmd(
* Determine if the func has an equal sign; only compare up to
* the equals
*/
- for (len = 0; func[len] != 0 && func[len] != '='; len++);
+ for (len = 0; func[len] != 0 && func[len] != '='; len++) {
+ };
for (i = 0; i < N_HW_CMDS; i++) {
const char *s = GET_MSG_STR(hw_cmds[i].str_id);
@@ -617,10 +631,10 @@ cfga_led_msg(struct cfga_msg *msgp, apid_t *apidp, led_strid_t led,
if ((apidp == NULL) || (apidp->dyncomp == NULL)) {
return;
}
- snprintf(led_msg, sizeof (led_msg), "%-23s\t%s=%s\n",
- basename(apidp->dyncomp),
- dgettext(TEXT_DOMAIN, led_strs[led]),
- dgettext(TEXT_DOMAIN, led_mode_strs[mode]));
+ (void) snprintf(led_msg, sizeof (led_msg), "%-23s\t%s=%s\n",
+ basename(apidp->dyncomp),
+ dgettext(TEXT_DOMAIN, led_strs[led]),
+ dgettext(TEXT_DOMAIN, led_mode_strs[mode]));
(void) (*msgp->message_routine)(msgp->appdata_ptr, led_msg);
}
@@ -722,6 +736,211 @@ out:
}
}
+/*
+ * Check to see if the given pi_node is the last path to the client device.
+ *
+ * Return:
+ * 0: if there is another path avialable.
+ * -1: if no other paths available.
+ */
+static int
+check_available_path(
+ di_node_t client_node,
+ di_path_t pi_node)
+{
+ di_path_state_t pi_state;
+ di_path_t next_pi = DI_PATH_NIL;
+
+ if (((pi_state = di_path_state(pi_node)) != DI_PATH_STATE_ONLINE) &&
+ (pi_state != DI_PATH_STATE_STANDBY)) {
+ /* it is not last available path */
+ return (0);
+ }
+
+ while (next_pi = di_path_client_next_path(client_node, next_pi)) {
+ /* if anohter pi node is avaialble, return 0 */
+ if ((next_pi != pi_node) &&
+ (((pi_state = di_path_state(next_pi)) ==
+ DI_PATH_STATE_ONLINE) ||
+ pi_state == DI_PATH_STATE_STANDBY)) {
+ return (0);
+ }
+ }
+ return (-1);
+}
+
+scfga_ret_t
+path_apid_state_change(
+ apid_t *apidp,
+ scfga_cmd_t cmd,
+ cfga_flags_t flags,
+ char **errstring,
+ int *l_errnop,
+ msgid_t errid)
+{
+ di_node_t root, walk_root, client_node;
+ di_path_t pi_node = DI_PATH_NIL;
+ char *root_path, *cp, *client_path, devpath[MAXPATHLEN];
+ int len, found = 0;
+ scfga_ret_t ret;
+ char *dev_list[2] = {NULL};
+
+ *l_errnop = 0;
+
+ /* Make sure apid is pathinfo associated apid. */
+ if ((apidp->dyntype != PATH_APID) || (apidp->dyncomp == NULL)) {
+ return (SCFGA_LIB_ERR);
+ }
+
+ if ((cmd != SCFGA_DEV_CONFIGURE) && (cmd != SCFGA_DEV_UNCONFIGURE)) {
+ return (SCFGA_LIB_ERR);
+ }
+
+ if ((root_path = strdup(apidp->hba_phys)) == NULL) {
+ *l_errnop = errno;
+ return (SCFGA_LIB_ERR);
+ }
+
+ /* Fix up path for di_init() */
+ len = strlen(DEVICES_DIR);
+ if (strncmp(root_path, DEVICES_DIR SLASH,
+ len + strlen(SLASH)) == 0) {
+ cp = root_path + len;
+ (void) memmove(root_path, cp, strlen(cp) + 1);
+ } else if (*root_path != '/') {
+ *l_errnop = 0;
+ S_FREE(root_path);
+ return (SCFGA_ERR);
+ }
+
+ /* Remove dynamic component if any */
+ if ((cp = GET_DYN(root_path)) != NULL) {
+ *cp = '\0';
+ }
+
+ /* Remove minor name if any */
+ if ((cp = strrchr(root_path, ':')) != NULL) {
+ *cp = '\0';
+ }
+
+ /*
+ * Cached snapshots are always rooted at "/"
+ */
+
+ /* Get a snapshot */
+ if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
+ *l_errnop = errno;
+ S_FREE(root_path);
+ return (SCFGA_ERR);
+ }
+
+ /*
+ * Lookup the subtree of interest
+ */
+ walk_root = di_lookup_node(root, root_path);
+
+ if (walk_root == DI_NODE_NIL) {
+ *l_errnop = errno;
+ di_fini(root);
+ S_FREE(root_path);
+ return (SCFGA_LIB_ERR);
+ }
+
+
+ if ((pi_node = di_path_next_client(walk_root, pi_node)) ==
+ DI_PATH_NIL) {
+ /* the path apid not found */
+ di_fini(root);
+ S_FREE(root_path);
+ return (SCFGA_APID_NOEXIST);
+ }
+
+ do {
+ /* check the length first. */
+ if (strlen(di_path_bus_addr(pi_node)) !=
+ strlen(apidp->dyncomp)) {
+ continue;
+ }
+
+ /* compare bus addr. */
+ if (strcmp(di_path_bus_addr(pi_node), apidp->dyncomp) == 0) {
+ found = 1;
+ break;
+ }
+ pi_node = di_path_next_client(root, pi_node);
+ } while (pi_node != DI_PATH_NIL);
+
+ if (!found) {
+ di_fini(root);
+ S_FREE(root_path);
+ return (SCFGA_APID_NOEXIST);
+ }
+
+ /* Get client node path. */
+ client_node = di_path_client_node(pi_node);
+ if (client_node == DI_NODE_NIL) {
+ di_fini(root);
+ S_FREE(root_path);
+ return (SCFGA_ERR);
+ } else {
+ client_path = di_devfs_path(client_node);
+ if (client_path == NULL) {
+ di_fini(root);
+ S_FREE(root_path);
+ return (SCFGA_ERR);
+ }
+
+ if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
+ if (cmd == SCFGA_DEV_UNCONFIGURE) {
+ if (check_available_path(client_node,
+ pi_node) != 0) {
+ /*
+ * last path. check if unconfiguring
+ * is okay.
+ */
+ (void) snprintf(devpath,
+ strlen(DEVICES_DIR) +
+ strlen(client_path) + 1, "%s%s",
+ DEVICES_DIR, client_path);
+ dev_list[0] = devpath;
+ flags |= FLAG_CLIENT_DEV;
+ ret = scsi_rcm_offline(dev_list,
+ errstring, flags);
+ if (ret != SCFGA_OK) {
+ di_fini(root);
+ di_devfs_path_free(client_path);
+ S_FREE(root_path);
+ return (ret);
+ }
+ }
+ }
+ }
+ }
+
+ ret = devctl_cmd(apidp->path, cmd, NULL, l_errnop);
+ if (ret != SCFGA_OK) {
+ cfga_err(errstring, *l_errnop, errid, 0);
+
+ /*
+ * If an unconfigure fails, cancel the RCM offline.
+ * Discard any RCM failures so that the devctl
+ * failure will still be reported.
+ */
+ if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
+ if (cmd == SCFGA_DEV_UNCONFIGURE)
+ (void) scsi_rcm_online(dev_list,
+ errstring, flags);
+ }
+ }
+
+ di_devfs_path_free(client_path);
+ di_fini(root);
+ S_FREE(root_path);
+
+ return (ret);
+}
+
+
scfga_ret_t
devctl_cmd(
const char *physpath,
@@ -840,7 +1059,7 @@ known_state(di_node_t node)
* offline.
*/
if ((state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE ||
- (state & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) {
+ (state & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) {
return (1);
}
diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk_common.c b/usr/src/lib/fm/topo/modules/common/disk/disk_common.c
index 174d2dc64e..867e8a252e 100644
--- a/usr/src/lib/fm/topo/modules/common/disk/disk_common.c
+++ b/usr/src/lib/fm/topo/modules/common/disk/disk_common.c
@@ -611,7 +611,7 @@ disk_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp)
pnode = NULL;
while ((pnode = di_path_client_next_path(node, pnode)) != NULL) {
if ((ret = di_path_prop_lookup_strings(pnode,
- "target-port", &s)) > 0)
+ SCSI_ADDR_PROP_TARGET_PORT, &s)) > 0)
portcount += ret;
pathcount++;
}
@@ -627,16 +627,17 @@ disk_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp)
goto error;
if ((ret = di_prop_lookup_strings(DDI_DEV_T_ANY, node,
- "target-port", &s)) > 0) {
+ SCSI_ADDR_PROP_TARGET_PORT, &s)) > 0) {
if ((dnode->ddn_target_port = topo_mod_zalloc(mod,
ret * sizeof (uintptr_t))) == NULL)
goto error;
-
dnode->ddn_target_port_count = ret;
for (i = 0; i < ret; i++) {
if ((dnode->ddn_target_port[i] =
- topo_mod_strdup(mod, s)) == NULL)
+ topo_mod_strdup(mod,
+ scsi_wwnstr_skip_ua_prefix(s))) ==
+ NULL)
goto error;
s += strlen(s) + 1;
@@ -672,10 +673,12 @@ disk_di_node_add(di_node_t node, char *devid, disk_cbdata_t *cbp)
goto error;
if ((ret = di_path_prop_lookup_strings(pnode,
- "target-port", &s)) > 0) {
+ SCSI_ADDR_PROP_TARGET_PORT, &s)) > 0) {
for (i = 0; i < ret; i++) {
if ((dnode->ddn_target_port[portcount] =
- topo_mod_strdup(mod, s)) == NULL)
+ topo_mod_strdup(mod,
+ scsi_wwnstr_skip_ua_prefix(s))) ==
+ NULL)
goto error;
portcount++;
diff --git a/usr/src/lib/libdevice/llib-ldevice b/usr/src/lib/libdevice/llib-ldevice
index cb8c831cad..e836d588c6 100644
--- a/usr/src/lib/libdevice/llib-ldevice
+++ b/usr/src/lib/libdevice/llib-ldevice
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -23,60 +22,10 @@
/* PROTOLIB1 */
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
+#include <sys/devctl.h>
#include "libdevice.h"
-
-/*
- * usr/src/lib/libdevice
- */
-
-/* devctl.c */
-devctl_hdl_t devctl_device_acquire(char *devfs_path, uint_t flags);
-devctl_hdl_t devctl_bus_acquire(char *devfs_path, uint_t flags);
-void devctl_release(devctl_hdl_t hdl);
-int devctl_pm_raisepower(devctl_hdl_t hdl);
-int devctl_pm_changepowerlow(devctl_hdl_t hdl);
-int devctl_pm_changepowerhigh(devctl_hdl_t hdl);
-int devctl_pm_idlecomponent(devctl_hdl_t hdl);
-int devctl_pm_busycomponent(devctl_hdl_t hdl);
-int devctl_pm_testbusy(devctl_hdl_t hdl, uint_t *busyp);
-int devctl_pm_failsuspend(devctl_hdl_t hdl);
-int devctl_pm_bus_teststrict(devctl_hdl_t hdl, uint_t *strict);
-int devctl_pm_device_changeonresume(devctl_hdl_t hdl);
-int devctl_pm_device_no_lower_power(devctl_hdl_t hdl);
-int devctl_pm_bus_no_invol(devctl_hdl_t hdl);
-int devctl_pm_device_promprintf(devctl_hdl_t hdl);
-int devctl_device_offline(devctl_hdl_t hdl);
-int devctl_device_online(devctl_hdl_t hdl);
-int devctl_device_reset(devctl_hdl_t hdl);
-int devctl_device_getstate(devctl_hdl_t hdl, uint_t *statep);
-int devctl_bus_quiesce(devctl_hdl_t hdl);
-int devctl_bus_unquiesce(devctl_hdl_t hdl);
-int devctl_bus_reset(devctl_hdl_t hdl);
-int devctl_bus_resetall(devctl_hdl_t hdl);
-int devctl_bus_getstate(devctl_hdl_t hdl, uint_t *statep);
-devctl_hdl_t devctl_ap_acquire(char *devfs_path, uint_t flags);
-devctl_hdl_t devctl_pm_dev_acquire(char *devfs_path, uint_t flags);
-devctl_hdl_t devctl_pm_bus_acquire(char *devfs_path, uint_t flags);
-int devctl_ap_insert(devctl_hdl_t hdl, nvlist_t *ap_data);
-int devctl_ap_remove(devctl_hdl_t hdl, nvlist_t *ap_data);
-int devctl_ap_connect(devctl_hdl_t hdl, nvlist_t *ap_data);
-int devctl_ap_disconnect(devctl_hdl_t hdl, nvlist_t *ap_data);
-int devctl_ap_configure(devctl_hdl_t hdl, nvlist_t *ap_data);
-int devctl_ap_unconfigure(devctl_hdl_t hdl, nvlist_t *ap_data);
-int devctl_ap_getstate(devctl_hdl_t hdl, nvlist_t *ap_data,
- devctl_ap_state_t *statep);
-devctl_ddef_t devctl_ddef_alloc(char *, int);
-void devctl_ddef_free(devctl_ddef_t);
-int devctl_ddef_int(devctl_ddef_t, char *, int32_t);
-int devctl_ddef_int_array(devctl_ddef_t, char *, int, int32_t *value);
-int devctl_ddef_string(devctl_ddef_t ddef_hdl, char *name, char *value);
-int devctl_ddef_string_array(devctl_ddef_t, char *, int, char **);
-int devctl_ddef_byte_array(devctl_ddef_t, char *, int, uchar_t *value);
-int devctl_bus_dev_create(devctl_hdl_t, devctl_ddef_t, uint_t, devctl_hdl_t *);
-char *devctl_get_pathname(devctl_hdl_t, char *, size_t);
diff --git a/usr/src/lib/libdevid/libdevid.h b/usr/src/lib/libdevid/libdevid.h
index f5df7c10e6..50a0dcd142 100644
--- a/usr/src/lib/libdevid/libdevid.h
+++ b/usr/src/lib/libdevid/libdevid.h
@@ -53,6 +53,7 @@ extern int scsi_wwnstr_to_wwn(const char *wwnstr, uint64_t *wwnp);
extern char *scsi_wwn_to_wwnstr(uint64_t wwn,
int unit_address_form, char *wwnstr);
extern void scsi_wwnstr_hexcase(char *wwnstr, int lower_case);
+extern const char *scsi_wwnstr_skip_ua_prefix(const char *wwnstr);
extern void scsi_free_wwnstr(char *wwnstr);
#ifdef SCSI_ADDR_PROP_LUN64
diff --git a/usr/src/lib/libdevid/mapfile-vers b/usr/src/lib/libdevid/mapfile-vers
index 48d9e987ad..fca14daa8f 100644
--- a/usr/src/lib/libdevid/mapfile-vers
+++ b/usr/src/lib/libdevid/mapfile-vers
@@ -67,6 +67,7 @@ SUNWprivate_1.1 {
scsi_lun_to_lun64;
scsi_wwn_to_wwnstr;
scsi_wwnstr_hexcase;
+ scsi_wwnstr_skip_ua_prefix;
scsi_wwnstr_to_wwn;
local:
*;
diff --git a/usr/src/lib/libdevinfo/devinfo.c b/usr/src/lib/libdevinfo/devinfo.c
index db6a62cab1..2431c87a96 100644
--- a/usr/src/lib/libdevinfo/devinfo.c
+++ b/usr/src/lib/libdevinfo/devinfo.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Interfaces for getting device configuration data from kernel
* through the devinfo driver.
@@ -977,9 +975,11 @@ di_state(di_node_t node)
if (DI_NODE(node)->state & DEVI_DEVICE_OFFLINE)
result |= DI_DEVICE_OFFLINE;
if (DI_NODE(node)->state & DEVI_DEVICE_DOWN)
- result |= DI_DEVICE_OFFLINE;
+ result |= DI_DEVICE_DOWN;
if (DI_NODE(node)->state & DEVI_DEVICE_DEGRADED)
result |= DI_DEVICE_DEGRADED;
+ if (DI_NODE(node)->state & DEVI_DEVICE_REMOVED)
+ result |= DI_DEVICE_REMOVED;
if (DI_NODE(node)->state & DEVI_BUS_QUIESCED)
result |= DI_BUS_QUIESCED;
if (DI_NODE(node)->state & DEVI_BUS_DOWN)
@@ -2028,6 +2028,12 @@ di_path_state(di_path_t path)
return ((di_path_state_t)DI_PATH(path)->path_state);
}
+uint_t
+di_path_flags(di_path_t path)
+{
+ return (DI_PATH(path)->path_flags);
+}
+
char *
di_path_node_name(di_path_t path)
{
diff --git a/usr/src/lib/libdevinfo/libdevinfo.h b/usr/src/lib/libdevinfo/libdevinfo.h
index 8103c3407f..520e5fb7a1 100644
--- a/usr/src/lib/libdevinfo/libdevinfo.h
+++ b/usr/src/lib/libdevinfo/libdevinfo.h
@@ -81,6 +81,7 @@ extern "C" {
#define DI_DEVICE_OFFLINE 0x1
#define DI_DEVICE_DOWN 0x2
#define DI_DEVICE_DEGRADED 0x4
+#define DI_DEVICE_REMOVED 0x8
#define DI_BUS_QUIESCED 0x100
#define DI_BUS_DOWN 0x200
@@ -192,6 +193,7 @@ extern char *di_path_node_name(di_path_t path);
extern char *di_path_bus_addr(di_path_t path);
extern int di_path_instance(di_path_t path);
extern di_path_state_t di_path_state(di_path_t path);
+extern uint_t di_path_flags(di_path_t path);
extern char *di_path_devfs_path(di_path_t path);
extern char *di_path_client_devfs_path(di_path_t path);
diff --git a/usr/src/lib/libdevinfo/mapfile-vers b/usr/src/lib/libdevinfo/mapfile-vers
index b1d9b5a9e8..2f3527c3f0 100644
--- a/usr/src/lib/libdevinfo/mapfile-vers
+++ b/usr/src/lib/libdevinfo/mapfile-vers
@@ -206,6 +206,7 @@ SUNWprivate_1.1 {
di_minor_devinfo;
di_node_state;
di_parent_private_data;
+ di_path_flags;
# XXX remove: di_path_(addr,next,next_client,next_phci)
di_path_addr;
di_path_next;
diff --git a/usr/src/lib/mpapi/libmpscsi_vhci/common/MP_GetMultipathLusPlugin.c b/usr/src/lib/mpapi/libmpscsi_vhci/common/MP_GetMultipathLusPlugin.c
index b15a807dfa..2f4315fb56 100644
--- a/usr/src/lib/mpapi/libmpscsi_vhci/common/MP_GetMultipathLusPlugin.c
+++ b/usr/src/lib/mpapi/libmpscsi_vhci/common/MP_GetMultipathLusPlugin.c
@@ -32,9 +32,40 @@
#include <libdevinfo.h>
+/*
+ * Checks whether there is online path or not.
+ * - no path found returns -1.
+ * - online/standby path found returns 1.
+ * - path exists but no online/standby path found returns 0.
+ */
+static int checkAvailablePath(di_node_t node)
+{
+ di_path_t path;
+ di_path_state_t state;
+
+ if ((path = di_path_client_next_path(node, DI_PATH_NIL))
+ == DI_PATH_NIL) {
+ log(LOG_INFO, "checkAvailalblePath()",
+ " - No path found");
+ return (-1);
+ }
+
+ do {
+ /* ignore the path that is neither online nor standby. */
+ if (((state = di_path_state(path)) == DI_PATH_STATE_ONLINE) ||
+ (state == DI_PATH_STATE_STANDBY)) {
+ return (1);
+ }
+ } while ((path = di_path_client_next_path(node, path)) != DI_PATH_NIL);
+
+ /* return 0 for the case that there is no online path to the node. */
+ log(LOG_INFO, "checkAvailalblePath()", " - No online path found");
+ return (0);
+}
+
static int getOidList(di_node_t root_node, MP_OID_LIST *pOidList)
{
- int numNodes = 0;
+ int numNodes = 0, state;
MP_UINT64 instNum = 0;
@@ -59,8 +90,21 @@ static int getOidList(di_node_t root_node, MP_OID_LIST *pOidList)
while (DI_NODE_NIL != sv_child_node) {
- /* Skip the node which is not online. */
- if (di_state(sv_child_node) != 0) {
+ /* skip the node which is offline, down or detached. */
+ state = di_state(sv_child_node);
+ if ((state & DI_DEVICE_DOWN) ||
+ (state & DI_DEVICE_OFFLINE)) {
+ sv_child_node = di_sibling_node(sv_child_node);
+ continue;
+ }
+
+ /*
+ * skip if the node doesn't have any path avaialble.
+ * If any path is found from the DINFOCACHE snaphost
+ * that means the driver keeps track of the path regadless
+ * of state.
+ */
+ if (checkAvailablePath(sv_child_node) == -1) {
sv_child_node = di_sibling_node(sv_child_node);
continue;
}