17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
525e8c5aaSvikram * Common Development and Distribution License (the "License").
625e8c5aaSvikram * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22d88e498aSjiang wu - Sun Microsystems - Beijing China * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate #include "cfga_scsi.h"
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate /* Structure for walking the tree */
297c478bd9Sstevel@tonic-gate typedef struct {
307c478bd9Sstevel@tonic-gate apid_t *apidp;
317c478bd9Sstevel@tonic-gate char *hba_logp;
327c478bd9Sstevel@tonic-gate ldata_list_t *listp;
337c478bd9Sstevel@tonic-gate scfga_cmd_t cmd;
347c478bd9Sstevel@tonic-gate cfga_stat_t chld_config;
357c478bd9Sstevel@tonic-gate cfga_stat_t hba_rstate;
367c478bd9Sstevel@tonic-gate scfga_ret_t ret;
377c478bd9Sstevel@tonic-gate int l_errno;
387c478bd9Sstevel@tonic-gate } scfga_list_t;
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate typedef struct {
417c478bd9Sstevel@tonic-gate uint_t itype;
427c478bd9Sstevel@tonic-gate const char *ntype;
437c478bd9Sstevel@tonic-gate const char *name;
44*4c06356bSdh const char *pathname;
457c478bd9Sstevel@tonic-gate } scfga_devtype_t;
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gate /* The TYPE field is parseable and should not contain spaces */
487c478bd9Sstevel@tonic-gate #define SCFGA_BUS_TYPE "scsi-bus"
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate /* Function prototypes */
517c478bd9Sstevel@tonic-gate static scfga_ret_t postprocess_list_data(const ldata_list_t *listp,
527c478bd9Sstevel@tonic-gate scfga_cmd_t cmd, cfga_stat_t chld_config, int *np);
537c478bd9Sstevel@tonic-gate static int stat_dev(di_node_t node, void *arg);
547c478bd9Sstevel@tonic-gate static scfga_ret_t do_stat_bus(scfga_list_t *lap, int limited_bus_stat);
557c478bd9Sstevel@tonic-gate static int get_bus_state(di_node_t node, void *arg);
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate static scfga_ret_t do_stat_dev(const di_node_t node, const char *nodepath,
587c478bd9Sstevel@tonic-gate scfga_list_t *lap, int limited_dev_stat);
597c478bd9Sstevel@tonic-gate static cfga_stat_t bus_devinfo_to_recep_state(uint_t bus_di_state);
607c478bd9Sstevel@tonic-gate static cfga_stat_t dev_devinfo_to_occupant_state(uint_t dev_di_state);
61*4c06356bSdh static char *get_device_type(di_node_t, dyncomp_t);
62*4c06356bSdh static void get_hw_info(di_node_t node, cfga_list_data_t *clp, dyncomp_t type);
63*4c06356bSdh static scfga_ret_t create_pathinfo_ldata(di_path_t pi_node, scfga_list_t *lap,
64*4c06356bSdh int *l_errnop);
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate static scfga_devtype_t device_list[] = {
68*4c06356bSdh { DTYPE_DIRECT, DDI_NT_BLOCK_CHAN, "disk", "disk-path"},
69*4c06356bSdh { DTYPE_DIRECT, DDI_NT_BLOCK, "disk", "disk-path"},
70*4c06356bSdh { DTYPE_DIRECT, DDI_NT_BLOCK_WWN, "disk", "disk-path"},
71*4c06356bSdh { DTYPE_DIRECT, DDI_NT_BLOCK_FABRIC, "disk", "disk-path"},
72*4c06356bSdh { DTYPE_DIRECT, DDI_NT_BLOCK_SAS, "disk", "disk-path"},
73*4c06356bSdh { DTYPE_SEQUENTIAL, DDI_NT_TAPE, "tape", "tape-path"},
74*4c06356bSdh { DTYPE_PRINTER, NULL, "printer", "printer-path"},
75*4c06356bSdh { DTYPE_PROCESSOR, NULL, "processor", "PRCS-path"},
76*4c06356bSdh { DTYPE_WORM, NULL, "WORM", "WORM-path"},
77*4c06356bSdh { DTYPE_RODIRECT, DDI_NT_CD_CHAN, "CD-ROM", "CD-ROM-path"},
78*4c06356bSdh { DTYPE_RODIRECT, DDI_NT_CD, "CD-ROM", "CD-ROM-path"},
79*4c06356bSdh { DTYPE_SCANNER, NULL, "scanner", "scanner-path"},
80*4c06356bSdh { DTYPE_OPTICAL, NULL, "optical", "optical-path"},
81*4c06356bSdh { DTYPE_CHANGER, NULL, "med-changer", "MEDCHGR-path"},
82*4c06356bSdh { DTYPE_COMM, NULL, "comm-device", "COMDEV-path"},
83*4c06356bSdh { DTYPE_ARRAY_CTRL, NULL, "array-ctrl", "ARRCTRL-path"},
84*4c06356bSdh { DTYPE_ESI, NULL, "ESI", "ESI-path"}
857c478bd9Sstevel@tonic-gate };
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate #define N_DEVICE_TYPES (sizeof (device_list) / sizeof (device_list[0]))
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate scfga_ret_t
do_list(apid_t * apidp,scfga_cmd_t cmd,ldata_list_t ** llpp,int * nelemp,char ** errstring)907c478bd9Sstevel@tonic-gate do_list(
917c478bd9Sstevel@tonic-gate apid_t *apidp,
927c478bd9Sstevel@tonic-gate scfga_cmd_t cmd,
937c478bd9Sstevel@tonic-gate ldata_list_t **llpp,
947c478bd9Sstevel@tonic-gate int *nelemp,
957c478bd9Sstevel@tonic-gate char **errstring)
967c478bd9Sstevel@tonic-gate {
977c478bd9Sstevel@tonic-gate int n = -1, l_errno = 0, limited_bus_stat;
987c478bd9Sstevel@tonic-gate walkarg_t u;
997c478bd9Sstevel@tonic-gate scfga_list_t larg = {NULL};
1007c478bd9Sstevel@tonic-gate scfga_ret_t ret;
1017c478bd9Sstevel@tonic-gate int init_flag;
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate assert(apidp->hba_phys != NULL && apidp->path != NULL);
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate if (*llpp != NULL || *nelemp != 0) {
1067c478bd9Sstevel@tonic-gate return (SCFGA_ERR);
1077c478bd9Sstevel@tonic-gate }
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate /* Create the HBA logid (also base component of logical ap_id) */
1107c478bd9Sstevel@tonic-gate ret = make_hba_logid(apidp->hba_phys, &larg.hba_logp, &l_errno);
1117c478bd9Sstevel@tonic-gate if (ret != SCFGA_OK) {
1127c478bd9Sstevel@tonic-gate cfga_err(errstring, l_errno, ERR_LIST, 0);
1137c478bd9Sstevel@tonic-gate return (SCFGA_ERR);
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate assert(larg.hba_logp != NULL);
1177c478bd9Sstevel@tonic-gate
1187c478bd9Sstevel@tonic-gate larg.cmd = cmd;
1197c478bd9Sstevel@tonic-gate larg.apidp = apidp;
1207c478bd9Sstevel@tonic-gate larg.hba_rstate = CFGA_STAT_NONE;
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate * For all list commands, the bus and 1 or more devices
1257c478bd9Sstevel@tonic-gate * needs to be stat'ed
1267c478bd9Sstevel@tonic-gate */
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate /*
1297c478bd9Sstevel@tonic-gate * By default we use DINFOCACHE to get a "full" snapshot
1307c478bd9Sstevel@tonic-gate * This much faster than DINFOFORCE which actually
1317c478bd9Sstevel@tonic-gate * attaches devices. DINFOFORCE used only if caller
1327c478bd9Sstevel@tonic-gate * explicitly requests it via a private option.
1337c478bd9Sstevel@tonic-gate */
1347c478bd9Sstevel@tonic-gate init_flag = (apidp->flags & FLAG_USE_DIFORCE) ? DINFOFORCE : DINFOCACHE;
1357c478bd9Sstevel@tonic-gate limited_bus_stat = 0;
1367c478bd9Sstevel@tonic-gate
1377c478bd9Sstevel@tonic-gate switch (larg.cmd) {
1387c478bd9Sstevel@tonic-gate case SCFGA_STAT_DEV:
1397c478bd9Sstevel@tonic-gate limited_bus_stat = 1; /* We need only bus state */
1407c478bd9Sstevel@tonic-gate /*FALLTHRU*/
1417c478bd9Sstevel@tonic-gate case SCFGA_STAT_ALL:
1427c478bd9Sstevel@tonic-gate break;
1437c478bd9Sstevel@tonic-gate case SCFGA_STAT_BUS:
1447c478bd9Sstevel@tonic-gate /* limited_bus_stat = 0 and no DINFOCACHE/DINFOFORCE */
1457c478bd9Sstevel@tonic-gate init_flag = 0;
1467c478bd9Sstevel@tonic-gate break;
1477c478bd9Sstevel@tonic-gate default:
1487c478bd9Sstevel@tonic-gate cfga_err(errstring, EINVAL, ERR_LIST, 0);
1497c478bd9Sstevel@tonic-gate goto out;
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate /*
1537c478bd9Sstevel@tonic-gate * DINFOCACHE implies DINFOCPYALL. DINFOCPYALL shouldn't
1547c478bd9Sstevel@tonic-gate * be ORed with DINFOCACHE, else libdevinfo will return
1557c478bd9Sstevel@tonic-gate * error
1567c478bd9Sstevel@tonic-gate */
1577c478bd9Sstevel@tonic-gate if (init_flag != DINFOCACHE)
1587c478bd9Sstevel@tonic-gate init_flag |= DINFOCPYALL;
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate if ((ret = do_stat_bus(&larg, limited_bus_stat)) != SCFGA_OK) {
1617c478bd9Sstevel@tonic-gate cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
1627c478bd9Sstevel@tonic-gate goto out;
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate
1657c478bd9Sstevel@tonic-gate #ifdef DEBUG
1667c478bd9Sstevel@tonic-gate if (limited_bus_stat) {
1677c478bd9Sstevel@tonic-gate assert(larg.listp == NULL);
1687c478bd9Sstevel@tonic-gate } else {
1697c478bd9Sstevel@tonic-gate assert(larg.listp != NULL);
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate #endif
1727c478bd9Sstevel@tonic-gate
1737c478bd9Sstevel@tonic-gate /* Assume that the bus has no configured children */
1747c478bd9Sstevel@tonic-gate larg.chld_config = CFGA_STAT_UNCONFIGURED;
1757c478bd9Sstevel@tonic-gate
1767c478bd9Sstevel@tonic-gate /*
1777c478bd9Sstevel@tonic-gate * If stat'ing a specific device, we don't know if it exists yet.
1787c478bd9Sstevel@tonic-gate * If stat'ing a bus or a bus and child devices, we have at least the
1797c478bd9Sstevel@tonic-gate * bus stat data at this point.
1807c478bd9Sstevel@tonic-gate */
1817c478bd9Sstevel@tonic-gate if (larg.cmd == SCFGA_STAT_DEV) {
1827c478bd9Sstevel@tonic-gate larg.ret = SCFGA_APID_NOEXIST;
1837c478bd9Sstevel@tonic-gate } else {
1847c478bd9Sstevel@tonic-gate larg.ret = SCFGA_OK;
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate
1877c478bd9Sstevel@tonic-gate /* we need to stat at least 1 device for all commands */
188*4c06356bSdh if (apidp->dyntype == PATH_APID) {
189*4c06356bSdh /*
190*4c06356bSdh * When cmd is SCFGA_STAT_DEV and the ap id is pathinfo
191*4c06356bSdh * related.
192*4c06356bSdh */
193*4c06356bSdh ret = walk_tree(apidp->hba_phys, &larg, init_flag, NULL,
194*4c06356bSdh SCFGA_WALK_PATH, &larg.l_errno);
195*4c06356bSdh } else {
196*4c06356bSdh /* we need to stat at least 1 device for all commands */
197*4c06356bSdh u.node_args.flags = DI_WALK_CLDFIRST;
198*4c06356bSdh u.node_args.fcn = stat_dev;
1997c478bd9Sstevel@tonic-gate
200*4c06356bSdh /*
201*4c06356bSdh * Subtree is ALWAYS rooted at the HBA (not at the device) as
202*4c06356bSdh * otherwise deadlock may occur if bus is disconnected.
203*4c06356bSdh */
204*4c06356bSdh ret = walk_tree(apidp->hba_phys, &larg, init_flag, &u,
205*4c06356bSdh SCFGA_WALK_NODE, &larg.l_errno);
206*4c06356bSdh
207*4c06356bSdh /*
208*4c06356bSdh * Check path info on the following conditions.
209*4c06356bSdh *
210*4c06356bSdh * - chld_config is still set to CFGA_STAT_UNCONFIGURED for
211*4c06356bSdh * SCFGA_STAT_BUS cmd after walking any child node.
212*4c06356bSdh * - walking node succeeded for SCFGA_STAT_ALL cmd(Continue on
213*4c06356bSdh * stating path info node).
214*4c06356bSdh * - apid is pathinfo associated and larg.ret is still set to
215*4c06356bSdh * SCFGA_APID_NOEXIST for SCFGA_STAT_DEV cmd.
216*4c06356bSdh */
217*4c06356bSdh if (((cmd == SCFGA_STAT_BUS) &&
218*4c06356bSdh (larg.chld_config == CFGA_STAT_UNCONFIGURED)) ||
219*4c06356bSdh ((cmd == SCFGA_STAT_ALL) && (ret == SCFGA_OK))) {
220*4c06356bSdh ret = walk_tree(apidp->hba_phys, &larg, init_flag, NULL,
221*4c06356bSdh SCFGA_WALK_PATH, &larg.l_errno);
222*4c06356bSdh }
223*4c06356bSdh }
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate if (ret != SCFGA_OK || (ret = larg.ret) != SCFGA_OK) {
2267c478bd9Sstevel@tonic-gate if (ret != SCFGA_APID_NOEXIST) {
2277c478bd9Sstevel@tonic-gate cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate goto out;
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate
2327c478bd9Sstevel@tonic-gate assert(larg.listp != NULL);
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate n = 0;
2357c478bd9Sstevel@tonic-gate ret = postprocess_list_data(larg.listp, cmd, larg.chld_config, &n);
2367c478bd9Sstevel@tonic-gate if (ret != SCFGA_OK) {
2377c478bd9Sstevel@tonic-gate cfga_err(errstring, 0, ERR_LIST, 0);
2387c478bd9Sstevel@tonic-gate ret = SCFGA_LIB_ERR;
2397c478bd9Sstevel@tonic-gate goto out;
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate *nelemp = n;
2437c478bd9Sstevel@tonic-gate *llpp = larg.listp;
2447c478bd9Sstevel@tonic-gate ret = SCFGA_OK;
2457c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
2467c478bd9Sstevel@tonic-gate out:
2477c478bd9Sstevel@tonic-gate if (ret != SCFGA_OK) list_free(&larg.listp);
2487c478bd9Sstevel@tonic-gate S_FREE(larg.hba_logp);
2497c478bd9Sstevel@tonic-gate return (ret);
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate static scfga_ret_t
postprocess_list_data(const ldata_list_t * listp,scfga_cmd_t cmd,cfga_stat_t chld_config,int * np)2537c478bd9Sstevel@tonic-gate postprocess_list_data(
2547c478bd9Sstevel@tonic-gate const ldata_list_t *listp,
2557c478bd9Sstevel@tonic-gate scfga_cmd_t cmd,
2567c478bd9Sstevel@tonic-gate cfga_stat_t chld_config,
2577c478bd9Sstevel@tonic-gate int *np)
2587c478bd9Sstevel@tonic-gate {
2597c478bd9Sstevel@tonic-gate ldata_list_t *tmplp = NULL;
2607c478bd9Sstevel@tonic-gate cfga_list_data_t *hba_ldatap = NULL;
2617c478bd9Sstevel@tonic-gate int i;
2627c478bd9Sstevel@tonic-gate
2637c478bd9Sstevel@tonic-gate
2647c478bd9Sstevel@tonic-gate *np = 0;
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate if (listp == NULL) {
2677c478bd9Sstevel@tonic-gate return (SCFGA_ERR);
2687c478bd9Sstevel@tonic-gate }
2697c478bd9Sstevel@tonic-gate
2707c478bd9Sstevel@tonic-gate hba_ldatap = NULL;
2717c478bd9Sstevel@tonic-gate tmplp = (ldata_list_t *)listp;
2727c478bd9Sstevel@tonic-gate for (i = 0; tmplp != NULL; tmplp = tmplp->next) {
2737c478bd9Sstevel@tonic-gate i++;
2747c478bd9Sstevel@tonic-gate if (GET_DYN(tmplp->ldata.ap_phys_id) == NULL) {
2757c478bd9Sstevel@tonic-gate /* A bus stat data */
2767c478bd9Sstevel@tonic-gate assert(GET_DYN(tmplp->ldata.ap_log_id) == NULL);
2777c478bd9Sstevel@tonic-gate hba_ldatap = &tmplp->ldata;
2787c478bd9Sstevel@tonic-gate #ifdef DEBUG
2797c478bd9Sstevel@tonic-gate } else {
2807c478bd9Sstevel@tonic-gate assert(GET_DYN(tmplp->ldata.ap_log_id) != NULL);
2817c478bd9Sstevel@tonic-gate #endif
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate switch (cmd) {
2867c478bd9Sstevel@tonic-gate case SCFGA_STAT_DEV:
2877c478bd9Sstevel@tonic-gate if (i != 1 || hba_ldatap != NULL) {
2887c478bd9Sstevel@tonic-gate return (SCFGA_LIB_ERR);
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate break;
2917c478bd9Sstevel@tonic-gate case SCFGA_STAT_BUS:
2927c478bd9Sstevel@tonic-gate if (i != 1 || hba_ldatap == NULL) {
2937c478bd9Sstevel@tonic-gate return (SCFGA_LIB_ERR);
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate break;
2967c478bd9Sstevel@tonic-gate case SCFGA_STAT_ALL:
2977c478bd9Sstevel@tonic-gate if (i < 1 || hba_ldatap == NULL) {
2987c478bd9Sstevel@tonic-gate return (SCFGA_LIB_ERR);
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate break;
3017c478bd9Sstevel@tonic-gate default:
3027c478bd9Sstevel@tonic-gate return (SCFGA_LIB_ERR);
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate
3057c478bd9Sstevel@tonic-gate *np = i;
3067c478bd9Sstevel@tonic-gate
3077c478bd9Sstevel@tonic-gate /* Fill in the occupant (child) state. */
3087c478bd9Sstevel@tonic-gate if (hba_ldatap != NULL) {
3097c478bd9Sstevel@tonic-gate hba_ldatap->ap_o_state = chld_config;
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate return (SCFGA_OK);
3127c478bd9Sstevel@tonic-gate }
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate static int
stat_dev(di_node_t node,void * arg)3157c478bd9Sstevel@tonic-gate stat_dev(di_node_t node, void *arg)
3167c478bd9Sstevel@tonic-gate {
3177c478bd9Sstevel@tonic-gate scfga_list_t *lap = NULL;
3187c478bd9Sstevel@tonic-gate char *devfsp = NULL, *nodepath = NULL;
3197c478bd9Sstevel@tonic-gate size_t len = 0;
3207c478bd9Sstevel@tonic-gate int limited_dev_stat = 0, match_minor, rv;
3217c478bd9Sstevel@tonic-gate scfga_ret_t ret;
3227c478bd9Sstevel@tonic-gate
3237c478bd9Sstevel@tonic-gate lap = (scfga_list_t *)arg;
3247c478bd9Sstevel@tonic-gate
3257c478bd9Sstevel@tonic-gate /* Skip stub nodes */
3267c478bd9Sstevel@tonic-gate if (IS_STUB_NODE(node)) {
3277c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE);
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate /* Skip partial nodes */
3317c478bd9Sstevel@tonic-gate if (!known_state(node)) {
3327c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE);
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate
3357c478bd9Sstevel@tonic-gate devfsp = di_devfs_path(node);
3367c478bd9Sstevel@tonic-gate if (devfsp == NULL) {
3377c478bd9Sstevel@tonic-gate rv = DI_WALK_CONTINUE;
3387c478bd9Sstevel@tonic-gate goto out;
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate
3417c478bd9Sstevel@tonic-gate len = strlen(DEVICES_DIR) + strlen(devfsp) + 1;
3427c478bd9Sstevel@tonic-gate
3437c478bd9Sstevel@tonic-gate nodepath = calloc(1, len);
3447c478bd9Sstevel@tonic-gate if (nodepath == NULL) {
3457c478bd9Sstevel@tonic-gate lap->l_errno = errno;
3467c478bd9Sstevel@tonic-gate lap->ret = SCFGA_LIB_ERR;
3477c478bd9Sstevel@tonic-gate rv = DI_WALK_TERMINATE;
3487c478bd9Sstevel@tonic-gate goto out;
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate (void) snprintf(nodepath, len, "%s%s", DEVICES_DIR, devfsp);
3527c478bd9Sstevel@tonic-gate
3537c478bd9Sstevel@tonic-gate /* Skip node if it is HBA */
3547c478bd9Sstevel@tonic-gate match_minor = 0;
3557c478bd9Sstevel@tonic-gate if (!dev_cmp(lap->apidp->hba_phys, nodepath, match_minor)) {
3567c478bd9Sstevel@tonic-gate rv = DI_WALK_CONTINUE;
3577c478bd9Sstevel@tonic-gate goto out;
3587c478bd9Sstevel@tonic-gate }
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gate /* If stat'ing a specific device, is this that device */
3617c478bd9Sstevel@tonic-gate if (lap->cmd == SCFGA_STAT_DEV) {
3627c478bd9Sstevel@tonic-gate assert(lap->apidp->path != NULL);
3637c478bd9Sstevel@tonic-gate if (dev_cmp(lap->apidp->path, nodepath, match_minor)) {
3647c478bd9Sstevel@tonic-gate rv = DI_WALK_CONTINUE;
3657c478bd9Sstevel@tonic-gate goto out;
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate
3697c478bd9Sstevel@tonic-gate /*
3707c478bd9Sstevel@tonic-gate * If stat'ing a bus only, we look at device nodes only to get
3717c478bd9Sstevel@tonic-gate * bus configuration status. So a limited stat will suffice.
3727c478bd9Sstevel@tonic-gate */
3737c478bd9Sstevel@tonic-gate if (lap->cmd == SCFGA_STAT_BUS) {
3747c478bd9Sstevel@tonic-gate limited_dev_stat = 1;
3757c478bd9Sstevel@tonic-gate } else {
3767c478bd9Sstevel@tonic-gate limited_dev_stat = 0;
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate /*
3807c478bd9Sstevel@tonic-gate * Ignore errors if stat'ing a bus or listing all
3817c478bd9Sstevel@tonic-gate */
3827c478bd9Sstevel@tonic-gate ret = do_stat_dev(node, nodepath, lap, limited_dev_stat);
3837c478bd9Sstevel@tonic-gate if (ret != SCFGA_OK) {
3847c478bd9Sstevel@tonic-gate if (lap->cmd == SCFGA_STAT_DEV) {
3857c478bd9Sstevel@tonic-gate lap->ret = ret;
3867c478bd9Sstevel@tonic-gate rv = DI_WALK_TERMINATE;
3877c478bd9Sstevel@tonic-gate } else {
3887c478bd9Sstevel@tonic-gate rv = DI_WALK_CONTINUE;
3897c478bd9Sstevel@tonic-gate }
3907c478bd9Sstevel@tonic-gate goto out;
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate /* Are we done ? */
3947c478bd9Sstevel@tonic-gate rv = DI_WALK_CONTINUE;
3957c478bd9Sstevel@tonic-gate if (lap->cmd == SCFGA_STAT_BUS &&
3967c478bd9Sstevel@tonic-gate lap->chld_config == CFGA_STAT_CONFIGURED) {
3977c478bd9Sstevel@tonic-gate rv = DI_WALK_TERMINATE;
3987c478bd9Sstevel@tonic-gate } else if (lap->cmd == SCFGA_STAT_DEV) {
3997c478bd9Sstevel@tonic-gate /*
4007c478bd9Sstevel@tonic-gate * If stat'ing a specific device, we are done at this point.
4017c478bd9Sstevel@tonic-gate */
4027c478bd9Sstevel@tonic-gate lap->ret = SCFGA_OK;
4037c478bd9Sstevel@tonic-gate rv = DI_WALK_TERMINATE;
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate
4067c478bd9Sstevel@tonic-gate /*FALLTHRU*/
4077c478bd9Sstevel@tonic-gate out:
4087c478bd9Sstevel@tonic-gate S_FREE(nodepath);
4097c478bd9Sstevel@tonic-gate if (devfsp != NULL) di_devfs_path_free(devfsp);
4107c478bd9Sstevel@tonic-gate return (rv);
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate
413*4c06356bSdh /*
414*4c06356bSdh * Create list date entry and add to ldata list.
415*4c06356bSdh */
416*4c06356bSdh static scfga_ret_t
create_pathinfo_ldata(di_path_t pi_node,scfga_list_t * lap,int * l_errnop)417*4c06356bSdh create_pathinfo_ldata(di_path_t pi_node, scfga_list_t *lap, int *l_errnop)
418*4c06356bSdh {
419*4c06356bSdh ldata_list_t *listp = NULL;
420*4c06356bSdh cfga_list_data_t *clp;
421*4c06356bSdh di_node_t client_node = DI_NODE_NIL;
422*4c06356bSdh di_minor_t minor;
423*4c06356bSdh scfga_ret_t ret;
424*4c06356bSdh di_path_state_t pi_state;
425*4c06356bSdh char *dyncomp = NULL, *client_path = NULL;
426*4c06356bSdh char pathbuf[MAXPATHLEN], *client_devlink = NULL;
427*4c06356bSdh int match_minor;
428*4c06356bSdh
429*4c06356bSdh listp = calloc(1, sizeof (ldata_list_t));
430*4c06356bSdh if (listp == NULL) {
431*4c06356bSdh lap->l_errno = errno;
432*4c06356bSdh return (SCFGA_LIB_ERR);
433*4c06356bSdh }
434*4c06356bSdh clp = &listp->ldata;
435*4c06356bSdh ret = make_path_dyncomp(pi_node, &dyncomp, &lap->l_errno);
436*4c06356bSdh if (ret != SCFGA_OK) {
437*4c06356bSdh S_FREE(listp);
438*4c06356bSdh return (ret);
439*4c06356bSdh }
440*4c06356bSdh
441*4c06356bSdh client_node = di_path_client_node(pi_node);
442*4c06356bSdh if (client_node == DI_NODE_NIL) {
443*4c06356bSdh *l_errnop = errno;
444*4c06356bSdh S_FREE(dyncomp);
445*4c06356bSdh return (SCFGA_LIB_ERR);
446*4c06356bSdh }
447*4c06356bSdh
448*4c06356bSdh /* Create logical and physical ap_id */
449*4c06356bSdh (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s%s%s",
450*4c06356bSdh lap->hba_logp, DYN_SEP, dyncomp);
451*4c06356bSdh
452*4c06356bSdh (void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s%s%s",
453*4c06356bSdh lap->apidp->hba_phys, DYN_SEP, dyncomp);
454*4c06356bSdh
455*4c06356bSdh S_FREE(dyncomp);
456*4c06356bSdh
457*4c06356bSdh /* ap class filled in by libcfgadm */
458*4c06356bSdh clp->ap_class[0] = '\0';
459*4c06356bSdh clp->ap_r_state = lap->hba_rstate;
460*4c06356bSdh /* path info exist so set to configured. */
461*4c06356bSdh clp->ap_o_state = CFGA_STAT_CONFIGURED;
462*4c06356bSdh
463*4c06356bSdh /* now fill up ap_info field with client dev link and instance #. */
464*4c06356bSdh client_path = di_devfs_path(client_node);
465*4c06356bSdh if (client_path) {
466*4c06356bSdh /* get first minor node. */
467*4c06356bSdh minor = di_minor_next(client_node, DI_MINOR_NIL);
468*4c06356bSdh if (minor == DI_MINOR_NIL) {
469*4c06356bSdh match_minor = 0;
470*4c06356bSdh (void) snprintf(pathbuf, MAXPATHLEN, "%s:%s",
471*4c06356bSdh DEVICES_DIR, client_path);
472*4c06356bSdh } else {
473*4c06356bSdh match_minor = 1;
474*4c06356bSdh (void) snprintf(pathbuf, MAXPATHLEN, "%s%s:%s",
475*4c06356bSdh DEVICES_DIR, client_path, di_minor_name(minor));
476*4c06356bSdh }
477*4c06356bSdh (void) physpath_to_devlink(pathbuf, &client_devlink, l_errnop,
478*4c06356bSdh match_minor);
479*4c06356bSdh di_devfs_path_free(client_path);
480*4c06356bSdh }
481*4c06356bSdh
482*4c06356bSdh if (client_devlink) {
483*4c06356bSdh (void) snprintf(clp->ap_info, CFGA_INFO_LEN,
484*4c06356bSdh "%s: %s", "Client Device", client_devlink);
485*4c06356bSdh S_FREE(client_devlink);
486*4c06356bSdh }
487*4c06356bSdh
488*4c06356bSdh get_hw_info(client_node, clp, PATH_APID);
489*4c06356bSdh
490*4c06356bSdh if ((pi_state = di_path_state(pi_node)) == DI_PATH_STATE_OFFLINE) {
491*4c06356bSdh clp->ap_o_state = CFGA_STAT_UNCONFIGURED;
492*4c06356bSdh }
493*4c06356bSdh
494*4c06356bSdh if (pi_state == DI_PATH_STATE_FAULT) {
495*4c06356bSdh clp->ap_cond = CFGA_COND_FAILED;
496*4c06356bSdh } else {
497*4c06356bSdh clp->ap_cond = CFGA_COND_UNKNOWN;
498*4c06356bSdh }
499*4c06356bSdh
500*4c06356bSdh /* no way to determine state change */
501*4c06356bSdh clp->ap_busy = 0;
502*4c06356bSdh clp->ap_status_time = (time_t)-1;
503*4c06356bSdh
504*4c06356bSdh /* Link it in */
505*4c06356bSdh listp->next = lap->listp;
506*4c06356bSdh lap->listp = listp;
507*4c06356bSdh
508*4c06356bSdh return (SCFGA_OK);
509*4c06356bSdh }
510*4c06356bSdh
511*4c06356bSdh /*
512*4c06356bSdh * Routine to stat pathinfo nodes.
513*4c06356bSdh *
514*4c06356bSdh * No pathinfo founds returns a success.
515*4c06356bSdh * When cmd is SCFGA_STAT_DEV, finds a matching pathinfo node and
516*4c06356bSdh * and create ldata if found.
517*4c06356bSdh * When cmd is SCFGA_STAT_ALL, create ldata for each pathinfo node.
518*4c06356bSdh * When cmd is SCFGA_STAT_BUS, checks if any pathinfo exist.
519*4c06356bSdh *
520*4c06356bSdh * Return:
521*4c06356bSdh * 0 for success
522*4c06356bSdh * -1 for failure.
523*4c06356bSdh */
524*4c06356bSdh int
stat_path_info(di_node_t root,void * arg,int * l_errnop)525*4c06356bSdh stat_path_info(
526*4c06356bSdh di_node_t root,
527*4c06356bSdh void *arg,
528*4c06356bSdh int *l_errnop)
529*4c06356bSdh {
530*4c06356bSdh scfga_list_t *lap = (scfga_list_t *)arg;
531*4c06356bSdh di_path_t pi_node;
532*4c06356bSdh
533*4c06356bSdh if (root == DI_NODE_NIL) {
534*4c06356bSdh return (-1);
535*4c06356bSdh }
536*4c06356bSdh
537*4c06356bSdh /*
538*4c06356bSdh * when there is no path_info node return SCFGA_OK.
539*4c06356bSdh */
540*4c06356bSdh if (di_path_next_client(root, DI_PATH_NIL) == DI_PATH_NIL) {
541*4c06356bSdh return (0);
542*4c06356bSdh }
543*4c06356bSdh
544*4c06356bSdh if (lap->cmd == SCFGA_STAT_BUS) {
545*4c06356bSdh lap->chld_config = CFGA_STAT_CONFIGURED;
546*4c06356bSdh return (0);
547*4c06356bSdh } else if (lap->cmd == SCFGA_STAT_DEV) {
548*4c06356bSdh assert(lap->apidp->dyntype == PATH_APID);
549*4c06356bSdh for (pi_node = di_path_next_client(root, DI_PATH_NIL); pi_node;
550*4c06356bSdh pi_node = di_path_next_client(root, pi_node)) {
551*4c06356bSdh /*
552*4c06356bSdh * NOTE: apidt_create() validated pathinfo apid so
553*4c06356bSdh * the apid should have a valid format.
554*4c06356bSdh */
555*4c06356bSdh
556*4c06356bSdh /* check the length first. */
557*4c06356bSdh if (strlen(di_path_bus_addr(pi_node)) !=
558*4c06356bSdh strlen(lap->apidp->dyncomp)) {
559*4c06356bSdh continue;
560*4c06356bSdh }
561*4c06356bSdh
562*4c06356bSdh /* check for full match. */
563*4c06356bSdh if (strcmp(di_path_bus_addr(pi_node),
564*4c06356bSdh lap->apidp->dyncomp)) {
565*4c06356bSdh continue;
566*4c06356bSdh }
567*4c06356bSdh
568*4c06356bSdh /* found match, record information */
569*4c06356bSdh if (create_pathinfo_ldata(pi_node, lap,
570*4c06356bSdh l_errnop) == SCFGA_OK) {
571*4c06356bSdh lap->ret = SCFGA_OK;
572*4c06356bSdh return (0);
573*4c06356bSdh } else {
574*4c06356bSdh return (-1);
575*4c06356bSdh }
576*4c06356bSdh }
577*4c06356bSdh } else { /* cmd = STAT_ALL */
578*4c06356bSdh /* set child config to configured */
579*4c06356bSdh lap->chld_config = CFGA_STAT_CONFIGURED;
580*4c06356bSdh for (pi_node = di_path_next_client(root, DI_PATH_NIL); pi_node;
581*4c06356bSdh pi_node = di_path_next_client(root, pi_node)) {
582*4c06356bSdh /* continue on even if there is an error on one path. */
583*4c06356bSdh (void) create_pathinfo_ldata(pi_node, lap, l_errnop);
584*4c06356bSdh }
585*4c06356bSdh }
586*4c06356bSdh
587*4c06356bSdh lap->ret = SCFGA_OK;
588*4c06356bSdh return (0);
589*4c06356bSdh
590*4c06356bSdh }
5917c478bd9Sstevel@tonic-gate
59225e8c5aaSvikram struct bus_state {
59325e8c5aaSvikram int b_state;
59425e8c5aaSvikram int b_retired;
595*4c06356bSdh char iconnect_type[16];
59625e8c5aaSvikram };
59725e8c5aaSvikram
5987c478bd9Sstevel@tonic-gate static scfga_ret_t
do_stat_bus(scfga_list_t * lap,int limited_bus_stat)5997c478bd9Sstevel@tonic-gate do_stat_bus(scfga_list_t *lap, int limited_bus_stat)
6007c478bd9Sstevel@tonic-gate {
6017c478bd9Sstevel@tonic-gate cfga_list_data_t *clp = NULL;
6027c478bd9Sstevel@tonic-gate ldata_list_t *listp = NULL;
6037c478bd9Sstevel@tonic-gate int l_errno = 0;
60425e8c5aaSvikram struct bus_state bstate = {0};
6057c478bd9Sstevel@tonic-gate walkarg_t u;
6067c478bd9Sstevel@tonic-gate scfga_ret_t ret;
607*4c06356bSdh int i;
608*4c06356bSdh char itypelower[MAXNAMELEN];
6097c478bd9Sstevel@tonic-gate
6107c478bd9Sstevel@tonic-gate assert(lap->hba_logp != NULL);
6117c478bd9Sstevel@tonic-gate
6127c478bd9Sstevel@tonic-gate /* Get bus state */
6137c478bd9Sstevel@tonic-gate u.node_args.flags = 0;
6147c478bd9Sstevel@tonic-gate u.node_args.fcn = get_bus_state;
6157c478bd9Sstevel@tonic-gate
61625e8c5aaSvikram ret = walk_tree(lap->apidp->hba_phys, &bstate, DINFOPROP, &u,
6177c478bd9Sstevel@tonic-gate SCFGA_WALK_NODE, &l_errno);
6187c478bd9Sstevel@tonic-gate if (ret == SCFGA_OK) {
61925e8c5aaSvikram lap->hba_rstate = bus_devinfo_to_recep_state(bstate.b_state);
6207c478bd9Sstevel@tonic-gate } else {
6217c478bd9Sstevel@tonic-gate lap->hba_rstate = CFGA_STAT_NONE;
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate
6247c478bd9Sstevel@tonic-gate if (limited_bus_stat) {
6257c478bd9Sstevel@tonic-gate /* We only want to know bus(receptacle) connect status */
6267c478bd9Sstevel@tonic-gate return (SCFGA_OK);
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate
6297c478bd9Sstevel@tonic-gate listp = calloc(1, sizeof (ldata_list_t));
6307c478bd9Sstevel@tonic-gate if (listp == NULL) {
6317c478bd9Sstevel@tonic-gate lap->l_errno = errno;
6327c478bd9Sstevel@tonic-gate return (SCFGA_LIB_ERR);
6337c478bd9Sstevel@tonic-gate }
6347c478bd9Sstevel@tonic-gate
6357c478bd9Sstevel@tonic-gate clp = &listp->ldata;
6367c478bd9Sstevel@tonic-gate
6377c478bd9Sstevel@tonic-gate (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s",
6387c478bd9Sstevel@tonic-gate lap->hba_logp);
6397c478bd9Sstevel@tonic-gate (void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s",
6407c478bd9Sstevel@tonic-gate lap->apidp->hba_phys);
6417c478bd9Sstevel@tonic-gate
6427c478bd9Sstevel@tonic-gate clp->ap_class[0] = '\0'; /* Filled by libcfgadm */
6437c478bd9Sstevel@tonic-gate clp->ap_r_state = lap->hba_rstate;
6447c478bd9Sstevel@tonic-gate clp->ap_o_state = CFGA_STAT_NONE; /* filled in later by the plug-in */
64525e8c5aaSvikram clp->ap_cond =
64625e8c5aaSvikram (bstate.b_retired) ? CFGA_COND_FAILED : CFGA_COND_UNKNOWN;
6477c478bd9Sstevel@tonic-gate clp->ap_busy = 0;
6487c478bd9Sstevel@tonic-gate clp->ap_status_time = (time_t)-1;
6497c478bd9Sstevel@tonic-gate clp->ap_info[0] = '\0';
6507c478bd9Sstevel@tonic-gate
651*4c06356bSdh if (bstate.iconnect_type) {
652*4c06356bSdh /*
653*4c06356bSdh * For SPI type, keep the existing SCFGA_BUS_TYPE.
654*4c06356bSdh * For other types, the ap type will be scsi-'interconnct-type'.
655*4c06356bSdh */
656*4c06356bSdh if (strcmp(bstate.iconnect_type, "SPI") == 0) {
657*4c06356bSdh (void) snprintf(clp->ap_type, sizeof (clp->ap_type),
658*4c06356bSdh "%s", SCFGA_BUS_TYPE);
659*4c06356bSdh } else {
660*4c06356bSdh for (i = 0; i < strlen(bstate.iconnect_type); i++) {
661*4c06356bSdh itypelower[i] =
662*4c06356bSdh tolower(bstate.iconnect_type[i]);
663*4c06356bSdh }
664*4c06356bSdh itypelower[i] = '\0';
665*4c06356bSdh (void) snprintf(clp->ap_type, sizeof (clp->ap_type),
666*4c06356bSdh "%s-%s", "scsi", itypelower);
667*4c06356bSdh }
668*4c06356bSdh }
6697c478bd9Sstevel@tonic-gate
6707c478bd9Sstevel@tonic-gate /* Link it in */
6717c478bd9Sstevel@tonic-gate listp->next = lap->listp;
6727c478bd9Sstevel@tonic-gate lap->listp = listp;
6737c478bd9Sstevel@tonic-gate
6747c478bd9Sstevel@tonic-gate return (SCFGA_OK);
6757c478bd9Sstevel@tonic-gate }
6767c478bd9Sstevel@tonic-gate
6777c478bd9Sstevel@tonic-gate static int
get_bus_state(di_node_t node,void * arg)6787c478bd9Sstevel@tonic-gate get_bus_state(di_node_t node, void *arg)
6797c478bd9Sstevel@tonic-gate {
68025e8c5aaSvikram struct bus_state *bsp = (struct bus_state *)arg;
681*4c06356bSdh char *itype = NULL;
6827c478bd9Sstevel@tonic-gate
68325e8c5aaSvikram bsp->b_state = di_state(node);
68425e8c5aaSvikram bsp->b_retired = di_retired(node);
685*4c06356bSdh (void) di_prop_lookup_strings(DDI_DEV_T_ANY,
686*4c06356bSdh node, "initiator-interconnect-type", &itype);
687*4c06356bSdh if (itype != NULL) {
688*4c06356bSdh (void) strlcpy(bsp->iconnect_type, itype, 16);
689*4c06356bSdh } else {
690*4c06356bSdh bsp->iconnect_type[0] = '\0';
691*4c06356bSdh }
6927c478bd9Sstevel@tonic-gate
6937c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE);
6947c478bd9Sstevel@tonic-gate }
6957c478bd9Sstevel@tonic-gate
6967c478bd9Sstevel@tonic-gate static scfga_ret_t
do_stat_dev(const di_node_t node,const char * nodepath,scfga_list_t * lap,int limited_dev_stat)6977c478bd9Sstevel@tonic-gate do_stat_dev(
6987c478bd9Sstevel@tonic-gate const di_node_t node,
6997c478bd9Sstevel@tonic-gate const char *nodepath,
7007c478bd9Sstevel@tonic-gate scfga_list_t *lap,
7017c478bd9Sstevel@tonic-gate int limited_dev_stat)
7027c478bd9Sstevel@tonic-gate {
7037c478bd9Sstevel@tonic-gate uint_t devinfo_state = 0;
7047c478bd9Sstevel@tonic-gate char *dyncomp = NULL;
7057c478bd9Sstevel@tonic-gate cfga_list_data_t *clp = NULL;
7067c478bd9Sstevel@tonic-gate ldata_list_t *listp = NULL;
7077c478bd9Sstevel@tonic-gate cfga_stat_t ostate;
7087c478bd9Sstevel@tonic-gate scfga_ret_t ret;
7097c478bd9Sstevel@tonic-gate
7107c478bd9Sstevel@tonic-gate assert(lap->apidp->hba_phys != NULL);
7117c478bd9Sstevel@tonic-gate assert(lap->hba_logp != NULL);
7127c478bd9Sstevel@tonic-gate
7137c478bd9Sstevel@tonic-gate devinfo_state = di_state(node);
7147c478bd9Sstevel@tonic-gate ostate = dev_devinfo_to_occupant_state(devinfo_state);
7157c478bd9Sstevel@tonic-gate
7167c478bd9Sstevel@tonic-gate /* If child device is configured, record it */
7177c478bd9Sstevel@tonic-gate if (ostate == CFGA_STAT_CONFIGURED) {
7187c478bd9Sstevel@tonic-gate lap->chld_config = CFGA_STAT_CONFIGURED;
7197c478bd9Sstevel@tonic-gate }
7207c478bd9Sstevel@tonic-gate
7217c478bd9Sstevel@tonic-gate if (limited_dev_stat) {
7227c478bd9Sstevel@tonic-gate /* We only want to know device config state */
7237c478bd9Sstevel@tonic-gate return (SCFGA_OK);
7247c478bd9Sstevel@tonic-gate }
7257c478bd9Sstevel@tonic-gate
7267c478bd9Sstevel@tonic-gate listp = calloc(1, sizeof (ldata_list_t));
7277c478bd9Sstevel@tonic-gate if (listp == NULL) {
7287c478bd9Sstevel@tonic-gate lap->l_errno = errno;
7297c478bd9Sstevel@tonic-gate return (SCFGA_LIB_ERR);
7307c478bd9Sstevel@tonic-gate }
7317c478bd9Sstevel@tonic-gate
7327c478bd9Sstevel@tonic-gate clp = &listp->ldata;
7337c478bd9Sstevel@tonic-gate
7347c478bd9Sstevel@tonic-gate /* Create the dynamic component */
7357c478bd9Sstevel@tonic-gate ret = make_dyncomp(node, nodepath, &dyncomp, &lap->l_errno);
7367c478bd9Sstevel@tonic-gate if (ret != SCFGA_OK) {
7377c478bd9Sstevel@tonic-gate S_FREE(listp);
7387c478bd9Sstevel@tonic-gate return (ret);
7397c478bd9Sstevel@tonic-gate }
7407c478bd9Sstevel@tonic-gate
7417c478bd9Sstevel@tonic-gate assert(dyncomp != NULL);
7427c478bd9Sstevel@tonic-gate
7437c478bd9Sstevel@tonic-gate /* Create logical and physical ap_id */
7447c478bd9Sstevel@tonic-gate (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s%s%s",
7457c478bd9Sstevel@tonic-gate lap->hba_logp, DYN_SEP, dyncomp);
7467c478bd9Sstevel@tonic-gate
7477c478bd9Sstevel@tonic-gate (void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s%s%s",
7487c478bd9Sstevel@tonic-gate lap->apidp->hba_phys, DYN_SEP, dyncomp);
7497c478bd9Sstevel@tonic-gate
7507c478bd9Sstevel@tonic-gate S_FREE(dyncomp);
7517c478bd9Sstevel@tonic-gate
7527c478bd9Sstevel@tonic-gate clp->ap_class[0] = '\0'; /* Filled in by libcfgadm */
7537c478bd9Sstevel@tonic-gate clp->ap_r_state = lap->hba_rstate;
7547c478bd9Sstevel@tonic-gate clp->ap_o_state = ostate;
75525e8c5aaSvikram clp->ap_cond = di_retired(node) ? CFGA_COND_FAILED : CFGA_COND_UNKNOWN;
7567c478bd9Sstevel@tonic-gate clp->ap_busy = 0; /* no way to determine state change */
7577c478bd9Sstevel@tonic-gate clp->ap_status_time = (time_t)-1;
7587c478bd9Sstevel@tonic-gate
759*4c06356bSdh get_hw_info(node, clp, DEV_APID);
7607c478bd9Sstevel@tonic-gate
7617c478bd9Sstevel@tonic-gate /* Link it in */
7627c478bd9Sstevel@tonic-gate listp->next = lap->listp;
7637c478bd9Sstevel@tonic-gate lap->listp = listp;
7647c478bd9Sstevel@tonic-gate
7657c478bd9Sstevel@tonic-gate return (SCFGA_OK);
7667c478bd9Sstevel@tonic-gate }
7677c478bd9Sstevel@tonic-gate
7687c478bd9Sstevel@tonic-gate /* fill in device type, vid, pid from properties */
7697c478bd9Sstevel@tonic-gate static void
get_hw_info(di_node_t node,cfga_list_data_t * clp,dyncomp_t type)770*4c06356bSdh get_hw_info(di_node_t node, cfga_list_data_t *clp, dyncomp_t type)
7717c478bd9Sstevel@tonic-gate {
7727c478bd9Sstevel@tonic-gate char *cp = NULL;
7737c478bd9Sstevel@tonic-gate char *inq_vid, *inq_pid;
774*4c06356bSdh char client_inst[MAXNAMELEN];
7757c478bd9Sstevel@tonic-gate
7767c478bd9Sstevel@tonic-gate /*
7777c478bd9Sstevel@tonic-gate * Fill in type information
7787c478bd9Sstevel@tonic-gate */
779*4c06356bSdh cp = (char *)get_device_type(node, type);
7807c478bd9Sstevel@tonic-gate if (cp == NULL) {
7817c478bd9Sstevel@tonic-gate cp = (char *)GET_MSG_STR(ERR_UNAVAILABLE);
7827c478bd9Sstevel@tonic-gate }
7837c478bd9Sstevel@tonic-gate (void) snprintf(clp->ap_type, sizeof (clp->ap_type), "%s", S_STR(cp));
7847c478bd9Sstevel@tonic-gate
785*4c06356bSdh if (type == DEV_APID) {
786*4c06356bSdh /*
787*4c06356bSdh * Fill in vendor and product ID.
788*4c06356bSdh */
789*4c06356bSdh if ((di_prop_lookup_strings(DDI_DEV_T_ANY, node,
790*4c06356bSdh "inquiry-product-id", &inq_pid) == 1) &&
791*4c06356bSdh (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
792*4c06356bSdh "inquiry-vendor-id", &inq_vid) == 1)) {
793*4c06356bSdh (void) snprintf(clp->ap_info, sizeof (clp->ap_info),
794*4c06356bSdh "%s %s", inq_vid, inq_pid);
795*4c06356bSdh }
796*4c06356bSdh } else {
797*4c06356bSdh if ((di_driver_name(node) != NULL) &&
798*4c06356bSdh (di_instance(node) != -1)) {
799*4c06356bSdh if (clp->ap_info == NULL) {
800*4c06356bSdh (void) snprintf(client_inst, MAXNAMELEN - 1,
801*4c06356bSdh "%s%d", di_driver_name(node),
802*4c06356bSdh di_instance(node));
803*4c06356bSdh (void) snprintf(clp->ap_info, MAXNAMELEN - 1,
804*4c06356bSdh "Client Device: %s", client_inst);
805*4c06356bSdh } else {
806*4c06356bSdh (void) snprintf(client_inst, MAXNAMELEN - 1,
807*4c06356bSdh "(%s%d)", di_driver_name(node),
808*4c06356bSdh di_instance(node));
809*4c06356bSdh (void) strlcat(clp->ap_info, client_inst,
810*4c06356bSdh CFGA_INFO_LEN);
811*4c06356bSdh }
812*4c06356bSdh }
813*4c06356bSdh
8147c478bd9Sstevel@tonic-gate }
8157c478bd9Sstevel@tonic-gate }
8167c478bd9Sstevel@tonic-gate
8177c478bd9Sstevel@tonic-gate /*
8187c478bd9Sstevel@tonic-gate * Get dtype from "inquiry-device-type" property. If not present,
8197c478bd9Sstevel@tonic-gate * derive it from minor node type
8207c478bd9Sstevel@tonic-gate */
8217c478bd9Sstevel@tonic-gate static char *
get_device_type(di_node_t node,dyncomp_t type)822*4c06356bSdh get_device_type(di_node_t node, dyncomp_t type)
8237c478bd9Sstevel@tonic-gate {
8247c478bd9Sstevel@tonic-gate char *name = NULL;
8257c478bd9Sstevel@tonic-gate int *inq_dtype;
8267c478bd9Sstevel@tonic-gate int i;
8277c478bd9Sstevel@tonic-gate
828936b7af6Sjw if (di_prop_find(DDI_DEV_T_ANY, node, "smp-device") != DI_PROP_NIL) {
829936b7af6Sjw return ("smp");
830936b7af6Sjw }
831936b7af6Sjw
8327c478bd9Sstevel@tonic-gate /* first, derive type based on inquiry property */
8337c478bd9Sstevel@tonic-gate if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "inquiry-device-type",
8347c478bd9Sstevel@tonic-gate &inq_dtype) == 1) {
8357c478bd9Sstevel@tonic-gate int itype = (*inq_dtype) & DTYPE_MASK;
8367c478bd9Sstevel@tonic-gate
8377c478bd9Sstevel@tonic-gate for (i = 0; i < N_DEVICE_TYPES; i++) {
8387c478bd9Sstevel@tonic-gate if (device_list[i].itype == DTYPE_UNKNOWN)
8397c478bd9Sstevel@tonic-gate continue;
8407c478bd9Sstevel@tonic-gate if (itype == device_list[i].itype) {
841*4c06356bSdh name = (type == DEV_APID) ?
842*4c06356bSdh (char *)device_list[i].name :
843*4c06356bSdh (char *)device_list[i].pathname;
8447c478bd9Sstevel@tonic-gate break;
8457c478bd9Sstevel@tonic-gate }
8467c478bd9Sstevel@tonic-gate }
8477c478bd9Sstevel@tonic-gate }
8487c478bd9Sstevel@tonic-gate
8497c478bd9Sstevel@tonic-gate /* if property fails, use minor nodetype */
8507c478bd9Sstevel@tonic-gate if (name == NULL) {
8517c478bd9Sstevel@tonic-gate char *nodetype;
8527c478bd9Sstevel@tonic-gate di_minor_t minor = di_minor_next(node, DI_MINOR_NIL);
8537c478bd9Sstevel@tonic-gate
8547c478bd9Sstevel@tonic-gate if ((minor != DI_MINOR_NIL) &&
8557c478bd9Sstevel@tonic-gate ((nodetype = di_minor_nodetype(minor)) != NULL)) {
8567c478bd9Sstevel@tonic-gate for (i = 0; i < N_DEVICE_TYPES; i++) {
8577c478bd9Sstevel@tonic-gate if (device_list[i].ntype &&
8587c478bd9Sstevel@tonic-gate (strcmp(nodetype, device_list[i].ntype)
8597c478bd9Sstevel@tonic-gate == 0)) {
860*4c06356bSdh name = (type == DEV_APID) ?
861*4c06356bSdh (char *)device_list[i].name :
862*4c06356bSdh (char *)device_list[i].pathname;
8637c478bd9Sstevel@tonic-gate break;
8647c478bd9Sstevel@tonic-gate }
8657c478bd9Sstevel@tonic-gate }
8667c478bd9Sstevel@tonic-gate }
8677c478bd9Sstevel@tonic-gate }
8687c478bd9Sstevel@tonic-gate
8697c478bd9Sstevel@tonic-gate if (name == NULL) /* default to unknown */
8707c478bd9Sstevel@tonic-gate name = "unknown";
8717c478bd9Sstevel@tonic-gate return (name);
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate
8747c478bd9Sstevel@tonic-gate /* Transform linked list into an array */
8757c478bd9Sstevel@tonic-gate scfga_ret_t
list_ext_postprocess(ldata_list_t ** llpp,int nelem,cfga_list_data_t ** ap_id_list,int * nlistp,char ** errstring)8767c478bd9Sstevel@tonic-gate list_ext_postprocess(
8777c478bd9Sstevel@tonic-gate ldata_list_t **llpp,
8787c478bd9Sstevel@tonic-gate int nelem,
8797c478bd9Sstevel@tonic-gate cfga_list_data_t **ap_id_list,
8807c478bd9Sstevel@tonic-gate int *nlistp,
8817c478bd9Sstevel@tonic-gate char **errstring)
8827c478bd9Sstevel@tonic-gate {
8837c478bd9Sstevel@tonic-gate cfga_list_data_t *ldatap = NULL;
8847c478bd9Sstevel@tonic-gate ldata_list_t *tmplp = NULL;
8857c478bd9Sstevel@tonic-gate int i = -1;
8867c478bd9Sstevel@tonic-gate
8877c478bd9Sstevel@tonic-gate *ap_id_list = NULL;
8887c478bd9Sstevel@tonic-gate *nlistp = 0;
8897c478bd9Sstevel@tonic-gate
8907c478bd9Sstevel@tonic-gate if (*llpp == NULL || nelem < 0) {
8917c478bd9Sstevel@tonic-gate return (SCFGA_LIB_ERR);
8927c478bd9Sstevel@tonic-gate }
8937c478bd9Sstevel@tonic-gate
8947c478bd9Sstevel@tonic-gate if (nelem == 0) {
8957c478bd9Sstevel@tonic-gate return (SCFGA_APID_NOEXIST);
8967c478bd9Sstevel@tonic-gate }
8977c478bd9Sstevel@tonic-gate
8987c478bd9Sstevel@tonic-gate ldatap = calloc(nelem, sizeof (cfga_list_data_t));
8997c478bd9Sstevel@tonic-gate if (ldatap == NULL) {
9007c478bd9Sstevel@tonic-gate cfga_err(errstring, errno, ERR_LIST, 0);
9017c478bd9Sstevel@tonic-gate return (SCFGA_LIB_ERR);
9027c478bd9Sstevel@tonic-gate }
9037c478bd9Sstevel@tonic-gate
9047c478bd9Sstevel@tonic-gate /* Extract the list_data structures from the linked list */
9057c478bd9Sstevel@tonic-gate tmplp = *llpp;
9067c478bd9Sstevel@tonic-gate for (i = 0; i < nelem && tmplp != NULL; i++) {
9077c478bd9Sstevel@tonic-gate ldatap[i] = tmplp->ldata;
9087c478bd9Sstevel@tonic-gate tmplp = tmplp->next;
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate if (i < nelem || tmplp != NULL) {
9127c478bd9Sstevel@tonic-gate S_FREE(ldatap);
9137c478bd9Sstevel@tonic-gate return (SCFGA_LIB_ERR);
9147c478bd9Sstevel@tonic-gate }
9157c478bd9Sstevel@tonic-gate
9167c478bd9Sstevel@tonic-gate *nlistp = nelem;
9177c478bd9Sstevel@tonic-gate *ap_id_list = ldatap;
9187c478bd9Sstevel@tonic-gate
9197c478bd9Sstevel@tonic-gate return (SCFGA_OK);
9207c478bd9Sstevel@tonic-gate }
9217c478bd9Sstevel@tonic-gate
9227c478bd9Sstevel@tonic-gate /*
9237c478bd9Sstevel@tonic-gate * Convert bus state to receptacle state
9247c478bd9Sstevel@tonic-gate */
9257c478bd9Sstevel@tonic-gate static cfga_stat_t
bus_devinfo_to_recep_state(uint_t bus_di_state)9267c478bd9Sstevel@tonic-gate bus_devinfo_to_recep_state(uint_t bus_di_state)
9277c478bd9Sstevel@tonic-gate {
928*4c06356bSdh if (bus_di_state & (DI_BUS_QUIESCED | DI_BUS_DOWN))
929*4c06356bSdh return (CFGA_STAT_DISCONNECTED);
9307c478bd9Sstevel@tonic-gate
931*4c06356bSdh return (CFGA_STAT_CONNECTED);
9327c478bd9Sstevel@tonic-gate }
9337c478bd9Sstevel@tonic-gate
9347c478bd9Sstevel@tonic-gate /*
9357c478bd9Sstevel@tonic-gate * Convert device state to occupant state
9367c478bd9Sstevel@tonic-gate */
9377c478bd9Sstevel@tonic-gate static cfga_stat_t
dev_devinfo_to_occupant_state(uint_t dev_di_state)9387c478bd9Sstevel@tonic-gate dev_devinfo_to_occupant_state(uint_t dev_di_state)
9397c478bd9Sstevel@tonic-gate {
940*4c06356bSdh if (dev_di_state & (DI_DEVICE_OFFLINE | DI_DEVICE_DOWN))
941*4c06356bSdh return (CFGA_STAT_UNCONFIGURED);
942*4c06356bSdh
943*4c06356bSdh if (!(dev_di_state & DI_DRIVER_DETACHED))
9447c478bd9Sstevel@tonic-gate return (CFGA_STAT_CONFIGURED);
9457c478bd9Sstevel@tonic-gate
946*4c06356bSdh return (CFGA_STAT_NONE);
9477c478bd9Sstevel@tonic-gate }
948