diff options
Diffstat (limited to 'usr/src/lib')
-rw-r--r-- | usr/src/lib/cfgadm_plugins/scsi/common/cfga_ctl.c | 62 | ||||
-rw-r--r-- | usr/src/lib/cfgadm_plugins/scsi/common/cfga_cvt.c | 181 | ||||
-rw-r--r-- | usr/src/lib/cfgadm_plugins/scsi/common/cfga_list.c | 381 | ||||
-rw-r--r-- | usr/src/lib/cfgadm_plugins/scsi/common/cfga_rcm.c | 25 | ||||
-rw-r--r-- | usr/src/lib/cfgadm_plugins/scsi/common/cfga_scsi.c | 14 | ||||
-rw-r--r-- | usr/src/lib/cfgadm_plugins/scsi/common/cfga_scsi.h | 23 | ||||
-rw-r--r-- | usr/src/lib/cfgadm_plugins/scsi/common/cfga_utils.c | 241 | ||||
-rw-r--r-- | usr/src/lib/fm/topo/modules/common/disk/disk_common.c | 15 | ||||
-rw-r--r-- | usr/src/lib/libdevice/llib-ldevice | 59 | ||||
-rw-r--r-- | usr/src/lib/libdevid/libdevid.h | 1 | ||||
-rw-r--r-- | usr/src/lib/libdevid/mapfile-vers | 1 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/devinfo.c | 14 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/libdevinfo.h | 2 | ||||
-rw-r--r-- | usr/src/lib/libdevinfo/mapfile-vers | 1 | ||||
-rw-r--r-- | usr/src/lib/mpapi/libmpscsi_vhci/common/MP_GetMultipathLusPlugin.c | 50 |
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; } |