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