xref: /onnv-gate/usr/src/lib/cfgadm_plugins/scsi/common/cfga_cvt.c (revision 10696:cd0f390dd9e2)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*10696SDavid.Hollister@Sun.COM  * Common Development and Distribution License (the "License").
6*10696SDavid.Hollister@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*10696SDavid.Hollister@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include "cfga_scsi.h"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate typedef struct {
290Sstevel@tonic-gate 	char *dyncomp;
300Sstevel@tonic-gate 	char *devlink;
310Sstevel@tonic-gate 	int l_errno;
320Sstevel@tonic-gate 	scfga_ret_t ret;
330Sstevel@tonic-gate } dyn_t;
340Sstevel@tonic-gate 
350Sstevel@tonic-gate typedef struct {
360Sstevel@tonic-gate 	scfga_recur_t (*devlink_to_dyncomp_p)(dyn_t *dyntp);
370Sstevel@tonic-gate 	scfga_recur_t (*dyncomp_to_devlink_p)(dyn_t *dyntp);
380Sstevel@tonic-gate } dynrules_t;
390Sstevel@tonic-gate 
400Sstevel@tonic-gate typedef struct {
410Sstevel@tonic-gate 	dyn_t *dynp;
420Sstevel@tonic-gate 	dynrules_t *rule_array;
430Sstevel@tonic-gate 	int nrules;
440Sstevel@tonic-gate } dyncvt_t;
450Sstevel@tonic-gate 
460Sstevel@tonic-gate typedef struct {
470Sstevel@tonic-gate 	const char *hba_phys;
480Sstevel@tonic-gate 	const char *dyncomp;
490Sstevel@tonic-gate 	char *path;
500Sstevel@tonic-gate 	int l_errno;
510Sstevel@tonic-gate 	scfga_ret_t ret;
520Sstevel@tonic-gate } devpath_t;
530Sstevel@tonic-gate 
540Sstevel@tonic-gate 
550Sstevel@tonic-gate 
560Sstevel@tonic-gate /* Function prototypes */
570Sstevel@tonic-gate 
580Sstevel@tonic-gate static int drv_to_hba_logid(di_node_t node, di_minor_t minor, void *arg);
590Sstevel@tonic-gate static scfga_ret_t drv_dyn_to_devpath(const char *hba_phys,
600Sstevel@tonic-gate     const char *dyncomp, char **pathpp, int *l_errnop);
610Sstevel@tonic-gate static int do_drv_dyn_to_devpath(di_node_t node, void *arg);
620Sstevel@tonic-gate static scfga_ret_t devlink_dyn_to_devpath(const char *hba_phys,
630Sstevel@tonic-gate     const char *dyncomp, char **pathpp, int *l_errnop);
640Sstevel@tonic-gate 
650Sstevel@tonic-gate static scfga_recur_t disk_dyncomp_to_devlink(dyn_t *dyntp);
660Sstevel@tonic-gate static scfga_recur_t tape_dyncomp_to_devlink(dyn_t *dyntp);
670Sstevel@tonic-gate static scfga_recur_t def_dyncomp_to_devlink(dyn_t *dyntp);
680Sstevel@tonic-gate 
690Sstevel@tonic-gate static scfga_ret_t devlink_to_dyncomp(char *devlink,
700Sstevel@tonic-gate     char **dyncompp, int *l_errnop);
710Sstevel@tonic-gate static scfga_recur_t disk_devlink_to_dyncomp(dyn_t *dyntp);
720Sstevel@tonic-gate static scfga_recur_t tape_devlink_to_dyncomp(dyn_t *dyntp);
730Sstevel@tonic-gate static scfga_recur_t def_devlink_to_dyncomp(dyn_t *dyntp);
740Sstevel@tonic-gate static scfga_ret_t drv_to_dyncomp(di_node_t node, const char *phys,
750Sstevel@tonic-gate     char **dyncompp, int *l_errnop);
760Sstevel@tonic-gate static scfga_ret_t get_hba_devlink(const char *hba_phys,
770Sstevel@tonic-gate     char **hba_logpp, int *l_errnop);
78*10696SDavid.Hollister@Sun.COM static scfga_ret_t path_apid_dyn_to_path(const char *hba_phys, const char *dyn,
79*10696SDavid.Hollister@Sun.COM     char **pathpp, int *l_errnop);
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 
820Sstevel@tonic-gate /* Globals */
830Sstevel@tonic-gate 
840Sstevel@tonic-gate /*
850Sstevel@tonic-gate  * Rules for converting between a devlink and logical ap_id and vice-versa
860Sstevel@tonic-gate  * The default rules must be the last entry.
870Sstevel@tonic-gate  */
880Sstevel@tonic-gate static dynrules_t dyncvt_rules[] = {
890Sstevel@tonic-gate 	{disk_devlink_to_dyncomp,	disk_dyncomp_to_devlink},
900Sstevel@tonic-gate 	{tape_devlink_to_dyncomp,	tape_dyncomp_to_devlink},
910Sstevel@tonic-gate 	{def_devlink_to_dyncomp,	def_dyncomp_to_devlink}
920Sstevel@tonic-gate };
930Sstevel@tonic-gate 
940Sstevel@tonic-gate #define	N_DYNRULES	(sizeof (dyncvt_rules)/sizeof (dyncvt_rules[0]))
950Sstevel@tonic-gate 
960Sstevel@tonic-gate /*
970Sstevel@tonic-gate  * Numbering of disk slices is assumed to be 0 through n - 1
980Sstevel@tonic-gate  */
990Sstevel@tonic-gate typedef struct {
1000Sstevel@tonic-gate 	char *prefix;
1010Sstevel@tonic-gate 	int nslices;
1020Sstevel@tonic-gate } slice_t;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate static slice_t disk_slices[] = {
1050Sstevel@tonic-gate 	{"s", 16},
1060Sstevel@tonic-gate 	{"p", 5},
1070Sstevel@tonic-gate };
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate #define	N_SLICE_TYPES	(sizeof (disk_slices) / sizeof (disk_slices[0]))
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate static const char *tape_modes[] = {
1120Sstevel@tonic-gate 	"",
1130Sstevel@tonic-gate 	"b", "bn",
1140Sstevel@tonic-gate 	"c", "cb", "cbn", "cn",
1150Sstevel@tonic-gate 	"h", "hb", "hbn", "hn",
1160Sstevel@tonic-gate 	"l", "lb", "lbn", "ln",
1170Sstevel@tonic-gate 	"m", "mb", "mbn", "mn",
1180Sstevel@tonic-gate 	"n",
1190Sstevel@tonic-gate 	"u", "ub", "ubn", "un"
1200Sstevel@tonic-gate };
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate #define	N_TAPE_MODES	(sizeof (tape_modes) / sizeof (tape_modes[0]))
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate /* Various conversions routines */
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate /*
1280Sstevel@tonic-gate  * Generates the HBA logical ap_id from physical ap_id.
1290Sstevel@tonic-gate  */
1300Sstevel@tonic-gate scfga_ret_t
make_hba_logid(const char * hba_phys,char ** hba_logpp,int * l_errnop)1310Sstevel@tonic-gate make_hba_logid(const char *hba_phys, char **hba_logpp, int *l_errnop)
1320Sstevel@tonic-gate {
1330Sstevel@tonic-gate 	walkarg_t u;
1340Sstevel@tonic-gate 	pathm_t pmt = {NULL};
1350Sstevel@tonic-gate 	scfga_ret_t ret;
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	if (*hba_logpp != NULL) {
1390Sstevel@tonic-gate 		return (SCFGA_ERR);
1400Sstevel@tonic-gate 	}
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	/* A devlink for the HBA may or may not exist */
1430Sstevel@tonic-gate 	if (get_hba_devlink(hba_phys, hba_logpp, l_errnop) == SCFGA_OK) {
1440Sstevel@tonic-gate 		assert(*hba_logpp != NULL);
1450Sstevel@tonic-gate 		return (SCFGA_OK);
1460Sstevel@tonic-gate 	}
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	/*
1490Sstevel@tonic-gate 	 * No devlink based logical ap_id.
1500Sstevel@tonic-gate 	 * Try driver name and instance number.
1510Sstevel@tonic-gate 	 */
1520Sstevel@tonic-gate 	u.minor_args.nodetype = DDI_NT_SCSI_ATTACHMENT_POINT;
1530Sstevel@tonic-gate 	u.minor_args.fcn = drv_to_hba_logid;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	pmt.phys = (char *)hba_phys;
1560Sstevel@tonic-gate 	pmt.ret = SCFGA_APID_NOEXIST;
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	errno = 0;
1590Sstevel@tonic-gate 	ret = walk_tree(pmt.phys, &pmt, DINFOMINOR | DINFOPROP, &u,
1600Sstevel@tonic-gate 	    SCFGA_WALK_MINOR, &pmt.l_errno);
1610Sstevel@tonic-gate 	if (ret == SCFGA_OK && (ret = pmt.ret) == SCFGA_OK) {
1620Sstevel@tonic-gate 		assert(pmt.log != NULL);
1630Sstevel@tonic-gate 		*hba_logpp = pmt.log;
1640Sstevel@tonic-gate 		return (SCFGA_OK);
1650Sstevel@tonic-gate 	}
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	/* failed to create logical ap_id */
1680Sstevel@tonic-gate 	if (pmt.log != NULL) {
1690Sstevel@tonic-gate 		S_FREE(pmt.log);
1700Sstevel@tonic-gate 	}
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	*l_errnop = pmt.l_errno;
1740Sstevel@tonic-gate 	return (ret);
1750Sstevel@tonic-gate }
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate static scfga_ret_t
get_hba_devlink(const char * hba_phys,char ** hba_logpp,int * l_errnop)1780Sstevel@tonic-gate get_hba_devlink(const char *hba_phys, char **hba_logpp, int *l_errnop)
1790Sstevel@tonic-gate {
1800Sstevel@tonic-gate 	size_t len;
1810Sstevel@tonic-gate 	scfga_ret_t ret;
1820Sstevel@tonic-gate 	int match_minor = 1;
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	ret = physpath_to_devlink((char *)hba_phys, hba_logpp,
1850Sstevel@tonic-gate 	    l_errnop, match_minor);
1860Sstevel@tonic-gate 	if (ret != SCFGA_OK) {
1870Sstevel@tonic-gate 		return (ret);
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	assert(*hba_logpp != NULL);
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	/* Remove the "/dev/cfg/"  prefix */
1930Sstevel@tonic-gate 	len = strlen(CFGA_DEV_DIR SLASH);
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	(void) memmove(*hba_logpp, *hba_logpp + len,
1960Sstevel@tonic-gate 	    strlen(*hba_logpp + len) + 1);
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	return (SCFGA_OK);
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate /* Make logical name for HBA  based on driver and instance */
2020Sstevel@tonic-gate static int
drv_to_hba_logid(di_node_t node,di_minor_t minor,void * arg)2030Sstevel@tonic-gate drv_to_hba_logid(di_node_t node, di_minor_t minor, void *arg)
2040Sstevel@tonic-gate {
2050Sstevel@tonic-gate 	int inst;
2060Sstevel@tonic-gate 	char *drv, *mn, *log;
2070Sstevel@tonic-gate 	pathm_t *ptp;
2080Sstevel@tonic-gate 	const size_t loglen = MAXPATHLEN;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	ptp = (pathm_t *)arg;
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	errno = 0;
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	mn = di_minor_name(minor);
2150Sstevel@tonic-gate 	drv = di_driver_name(node);
2160Sstevel@tonic-gate 	inst = di_instance(node);
2170Sstevel@tonic-gate 	log = calloc(1, loglen);
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	if (mn != NULL && drv != NULL && inst != -1 && log != NULL) {
2200Sstevel@tonic-gate 		/* Count does not include terminating NULL */
2210Sstevel@tonic-gate 		if (snprintf(log, loglen, "%s%d:%s", drv, inst, mn) < loglen) {
2220Sstevel@tonic-gate 			ptp->ret = SCFGA_OK;
2230Sstevel@tonic-gate 			ptp->log = log;
2240Sstevel@tonic-gate 			return (DI_WALK_TERMINATE);
2250Sstevel@tonic-gate 		}
2260Sstevel@tonic-gate 	}
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	S_FREE(log);
2290Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate /*
2330Sstevel@tonic-gate  * Given a bus or device ap_id <hba_phys, dyncomp>, returns the physical
2340Sstevel@tonic-gate  * path in pathpp.
2350Sstevel@tonic-gate  * Returns: SCFGA_APID_NOEXIST if the path does not exist.
2360Sstevel@tonic-gate  */
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate scfga_ret_t
apid_to_path(const char * hba_phys,const char * dyncomp,char ** pathpp,int * l_errnop)2390Sstevel@tonic-gate apid_to_path(
2400Sstevel@tonic-gate 	const char *hba_phys,
2410Sstevel@tonic-gate 	const char *dyncomp,
2420Sstevel@tonic-gate 	char **pathpp,
2430Sstevel@tonic-gate 	int *l_errnop)
2440Sstevel@tonic-gate {
2450Sstevel@tonic-gate 	scfga_ret_t ret;
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	if (*pathpp != NULL) {
2480Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
2490Sstevel@tonic-gate 	}
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	/* If a bus, the physical ap_id is the physical path */
2520Sstevel@tonic-gate 	if (dyncomp == NULL) {
2530Sstevel@tonic-gate 		if ((*pathpp = strdup(hba_phys)) == NULL) {
2540Sstevel@tonic-gate 			*l_errnop = errno;
2550Sstevel@tonic-gate 			return (SCFGA_LIB_ERR);
2560Sstevel@tonic-gate 		}
2570Sstevel@tonic-gate 		return (SCFGA_OK);
2580Sstevel@tonic-gate 	}
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	/* Dynamic component exists, we have a device */
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	/*
2630Sstevel@tonic-gate 	 * If the dynamic component has a '/', it was derived from a devlink
2640Sstevel@tonic-gate 	 * Else it was derived from driver name and instance number.
265*10696SDavid.Hollister@Sun.COM 	 * If it is pathinfo instance number based ap id, it will have a format
266*10696SDavid.Hollister@Sun.COM 	 * path#.???.
2670Sstevel@tonic-gate 	 */
2680Sstevel@tonic-gate 	if (strchr(dyncomp, '/') != NULL) {
2690Sstevel@tonic-gate 		ret = devlink_dyn_to_devpath(hba_phys, dyncomp, pathpp,
2700Sstevel@tonic-gate 		    l_errnop);
271*10696SDavid.Hollister@Sun.COM 	} else if (strstr(dyncomp, PATH_APID_DYN_SEP) != NULL) {
272*10696SDavid.Hollister@Sun.COM 		ret = path_apid_dyn_to_path(hba_phys, dyncomp, pathpp,
273*10696SDavid.Hollister@Sun.COM 		    l_errnop);
2740Sstevel@tonic-gate 	} else {
2750Sstevel@tonic-gate 		ret = drv_dyn_to_devpath(hba_phys, dyncomp, pathpp, l_errnop);
2760Sstevel@tonic-gate 	}
2770Sstevel@tonic-gate 	assert(ret != SCFGA_OK || *pathpp != NULL);
2780Sstevel@tonic-gate 
279*10696SDavid.Hollister@Sun.COM 
2800Sstevel@tonic-gate 	return (ret);
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate 
283*10696SDavid.Hollister@Sun.COM /*
284*10696SDavid.Hollister@Sun.COM  * Get the devfs path of pathinfo node that is associated with
285*10696SDavid.Hollister@Sun.COM  * the given dynamic component.
286*10696SDavid.Hollister@Sun.COM  *
287*10696SDavid.Hollister@Sun.COM  * input
288*10696SDavid.Hollister@Sun.COM  *   hba_phys: physical path of HBA
289*10696SDavid.Hollister@Sun.COM  *   dyn : bus address of pathinfo node
290*10696SDavid.Hollister@Sun.COM  * output:
291*10696SDavid.Hollister@Sun.COM  *   pathpp: devfs path of the pathinfo node.
292*10696SDavid.Hollister@Sun.COM  */
293*10696SDavid.Hollister@Sun.COM static scfga_ret_t
path_apid_dyn_to_path(const char * hba_phys,const char * dyn,char ** pathpp,int * l_errnop)294*10696SDavid.Hollister@Sun.COM path_apid_dyn_to_path(
295*10696SDavid.Hollister@Sun.COM 	const char *hba_phys,
296*10696SDavid.Hollister@Sun.COM 	const char *dyn,
297*10696SDavid.Hollister@Sun.COM 	char **pathpp,
298*10696SDavid.Hollister@Sun.COM 	int *l_errnop)
299*10696SDavid.Hollister@Sun.COM {
300*10696SDavid.Hollister@Sun.COM 
301*10696SDavid.Hollister@Sun.COM 	di_node_t   root, walk_root;
302*10696SDavid.Hollister@Sun.COM 	di_path_t   pi_node = DI_PATH_NIL;
303*10696SDavid.Hollister@Sun.COM 	char	    *root_path, *devpath, *cp;
304*10696SDavid.Hollister@Sun.COM 	int	    len;
305*10696SDavid.Hollister@Sun.COM 
306*10696SDavid.Hollister@Sun.COM 	*l_errnop = 0;
307*10696SDavid.Hollister@Sun.COM 
308*10696SDavid.Hollister@Sun.COM 	/* *pathpp should be NULL if pathpp is not NULL. */
309*10696SDavid.Hollister@Sun.COM 	if ((hba_phys == NULL) || (pathpp != NULL) && (*pathpp != NULL)) {
310*10696SDavid.Hollister@Sun.COM 		return (SCFGA_LIB_ERR);
311*10696SDavid.Hollister@Sun.COM 	}
312*10696SDavid.Hollister@Sun.COM 
313*10696SDavid.Hollister@Sun.COM 	if ((root_path = strdup(hba_phys)) == NULL) {
314*10696SDavid.Hollister@Sun.COM 		*l_errnop = errno;
315*10696SDavid.Hollister@Sun.COM 		return (SCFGA_LIB_ERR);
316*10696SDavid.Hollister@Sun.COM 	}
317*10696SDavid.Hollister@Sun.COM 
318*10696SDavid.Hollister@Sun.COM 	/* Fix up path for di_init() */
319*10696SDavid.Hollister@Sun.COM 	len = strlen(DEVICES_DIR);
320*10696SDavid.Hollister@Sun.COM 	if (strncmp(root_path, DEVICES_DIR SLASH,
321*10696SDavid.Hollister@Sun.COM 	    len + strlen(SLASH)) == 0) {
322*10696SDavid.Hollister@Sun.COM 		cp = root_path + len;
323*10696SDavid.Hollister@Sun.COM 		(void) memmove(root_path, cp, strlen(cp) + 1);
324*10696SDavid.Hollister@Sun.COM 	} else if (*root_path != '/') {
325*10696SDavid.Hollister@Sun.COM 		*l_errnop = 0;
326*10696SDavid.Hollister@Sun.COM 		S_FREE(root_path);
327*10696SDavid.Hollister@Sun.COM 		return (SCFGA_ERR);
328*10696SDavid.Hollister@Sun.COM 	}
329*10696SDavid.Hollister@Sun.COM 
330*10696SDavid.Hollister@Sun.COM 	/* Remove dynamic component if any */
331*10696SDavid.Hollister@Sun.COM 	if ((cp = GET_DYN(root_path)) != NULL) {
332*10696SDavid.Hollister@Sun.COM 		*cp = '\0';
333*10696SDavid.Hollister@Sun.COM 	}
334*10696SDavid.Hollister@Sun.COM 
335*10696SDavid.Hollister@Sun.COM 	/* Remove minor name if any */
336*10696SDavid.Hollister@Sun.COM 	if ((cp = strrchr(root_path, ':')) != NULL) {
337*10696SDavid.Hollister@Sun.COM 		*cp = '\0';
338*10696SDavid.Hollister@Sun.COM 	}
339*10696SDavid.Hollister@Sun.COM 
340*10696SDavid.Hollister@Sun.COM 	/*
341*10696SDavid.Hollister@Sun.COM 	 * Cached snapshots are always rooted at "/"
342*10696SDavid.Hollister@Sun.COM 	 */
343*10696SDavid.Hollister@Sun.COM 
344*10696SDavid.Hollister@Sun.COM 	/* Get a snapshot */
345*10696SDavid.Hollister@Sun.COM 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
346*10696SDavid.Hollister@Sun.COM 		*l_errnop = errno;
347*10696SDavid.Hollister@Sun.COM 		S_FREE(root_path);
348*10696SDavid.Hollister@Sun.COM 		return (SCFGA_ERR);
349*10696SDavid.Hollister@Sun.COM 	}
350*10696SDavid.Hollister@Sun.COM 
351*10696SDavid.Hollister@Sun.COM 	/*
352*10696SDavid.Hollister@Sun.COM 	 * Lookup the subtree of interest
353*10696SDavid.Hollister@Sun.COM 	 */
354*10696SDavid.Hollister@Sun.COM 	walk_root = di_lookup_node(root, root_path);
355*10696SDavid.Hollister@Sun.COM 
356*10696SDavid.Hollister@Sun.COM 	if (walk_root == DI_NODE_NIL) {
357*10696SDavid.Hollister@Sun.COM 		*l_errnop = errno;
358*10696SDavid.Hollister@Sun.COM 		di_fini(root);
359*10696SDavid.Hollister@Sun.COM 		S_FREE(root_path);
360*10696SDavid.Hollister@Sun.COM 		return (SCFGA_LIB_ERR);
361*10696SDavid.Hollister@Sun.COM 	}
362*10696SDavid.Hollister@Sun.COM 
363*10696SDavid.Hollister@Sun.COM 	S_FREE(root_path);
364*10696SDavid.Hollister@Sun.COM 
365*10696SDavid.Hollister@Sun.COM 	if ((pi_node = di_path_next_client(walk_root, pi_node)) ==
366*10696SDavid.Hollister@Sun.COM 	    DI_PATH_NIL) {
367*10696SDavid.Hollister@Sun.COM 		di_fini(root);
368*10696SDavid.Hollister@Sun.COM 		return (SCFGA_APID_NOEXIST);
369*10696SDavid.Hollister@Sun.COM 	}
370*10696SDavid.Hollister@Sun.COM 
371*10696SDavid.Hollister@Sun.COM 	/*
372*10696SDavid.Hollister@Sun.COM 	 * now parse the path info node.
373*10696SDavid.Hollister@Sun.COM 	 */
374*10696SDavid.Hollister@Sun.COM 	do {
375*10696SDavid.Hollister@Sun.COM 		/* check the length first. */
376*10696SDavid.Hollister@Sun.COM 		if (strlen(di_path_bus_addr(pi_node)) != strlen(dyn)) {
377*10696SDavid.Hollister@Sun.COM 			continue;
378*10696SDavid.Hollister@Sun.COM 		}
379*10696SDavid.Hollister@Sun.COM 
380*10696SDavid.Hollister@Sun.COM 		if (strcmp(di_path_bus_addr(pi_node), dyn) == 0) {
381*10696SDavid.Hollister@Sun.COM 			/* get the devfspath of pathinfo node. */
382*10696SDavid.Hollister@Sun.COM 			devpath = di_path_devfs_path(pi_node);
383*10696SDavid.Hollister@Sun.COM 			if (devpath == NULL) {
384*10696SDavid.Hollister@Sun.COM 				*l_errnop = errno;
385*10696SDavid.Hollister@Sun.COM 				di_fini(root);
386*10696SDavid.Hollister@Sun.COM 				return (SCFGA_ERR);
387*10696SDavid.Hollister@Sun.COM 			}
388*10696SDavid.Hollister@Sun.COM 
389*10696SDavid.Hollister@Sun.COM 			len = strlen(DEVICES_DIR) + strlen(devpath) + 1;
390*10696SDavid.Hollister@Sun.COM 			*pathpp = calloc(1, len);
391*10696SDavid.Hollister@Sun.COM 			if (*pathpp == NULL) {
392*10696SDavid.Hollister@Sun.COM 				*l_errnop = errno;
393*10696SDavid.Hollister@Sun.COM 				di_devfs_path_free(devpath);
394*10696SDavid.Hollister@Sun.COM 				di_fini(root);
395*10696SDavid.Hollister@Sun.COM 				return (SCFGA_ERR);
396*10696SDavid.Hollister@Sun.COM 			} else {
397*10696SDavid.Hollister@Sun.COM 				(void) snprintf(*pathpp, len, "%s%s",
398*10696SDavid.Hollister@Sun.COM 				    DEVICES_DIR, devpath);
399*10696SDavid.Hollister@Sun.COM 				di_devfs_path_free(devpath);
400*10696SDavid.Hollister@Sun.COM 				di_fini(root);
401*10696SDavid.Hollister@Sun.COM 				return (SCFGA_OK);
402*10696SDavid.Hollister@Sun.COM 			}
403*10696SDavid.Hollister@Sun.COM 		}
404*10696SDavid.Hollister@Sun.COM 		pi_node = di_path_next_client(walk_root, pi_node);
405*10696SDavid.Hollister@Sun.COM 	} while (pi_node != DI_PATH_NIL);
406*10696SDavid.Hollister@Sun.COM 
407*10696SDavid.Hollister@Sun.COM 	di_fini(root);
408*10696SDavid.Hollister@Sun.COM 	return (SCFGA_APID_NOEXIST);
409*10696SDavid.Hollister@Sun.COM }
410*10696SDavid.Hollister@Sun.COM 
4110Sstevel@tonic-gate static scfga_ret_t
drv_dyn_to_devpath(const char * hba_phys,const char * dyncomp,char ** pathpp,int * l_errnop)4120Sstevel@tonic-gate drv_dyn_to_devpath(
4130Sstevel@tonic-gate 	const char *hba_phys,
4140Sstevel@tonic-gate 	const char *dyncomp,
4150Sstevel@tonic-gate 	char **pathpp,
4160Sstevel@tonic-gate 	int *l_errnop)
4170Sstevel@tonic-gate {
4180Sstevel@tonic-gate 	walkarg_t u;
4190Sstevel@tonic-gate 	devpath_t dpt = {NULL};
4200Sstevel@tonic-gate 	scfga_ret_t ret;
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	/* A device MUST have a dynamic component */
4230Sstevel@tonic-gate 	if (dyncomp == NULL || *pathpp != NULL) {
4240Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
4250Sstevel@tonic-gate 	}
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	u.node_args.flags = DI_WALK_CLDFIRST;
4280Sstevel@tonic-gate 	u.node_args.fcn = do_drv_dyn_to_devpath;
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	dpt.hba_phys = hba_phys;
4310Sstevel@tonic-gate 	dpt.dyncomp = dyncomp;
4320Sstevel@tonic-gate 	dpt.ret = SCFGA_APID_NOEXIST;
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	ret = walk_tree(hba_phys, &dpt, DINFOCPYALL, &u,
4350Sstevel@tonic-gate 	    SCFGA_WALK_NODE, &dpt.l_errno);
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	if (ret == SCFGA_OK && (ret = dpt.ret) == SCFGA_OK) {
4380Sstevel@tonic-gate 		assert(dpt.path != NULL);
4390Sstevel@tonic-gate 		*pathpp = dpt.path;
4400Sstevel@tonic-gate 		return (SCFGA_OK);
4410Sstevel@tonic-gate 	}
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	if (dpt.path != NULL) {
4440Sstevel@tonic-gate 		S_FREE(dpt.path);
4450Sstevel@tonic-gate 	}
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	*l_errnop = dpt.l_errno;
4490Sstevel@tonic-gate 	return (ret);
4500Sstevel@tonic-gate }
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate /* Converts a driver and instance number based logid into a physical path */
4530Sstevel@tonic-gate static int
do_drv_dyn_to_devpath(di_node_t node,void * arg)4540Sstevel@tonic-gate do_drv_dyn_to_devpath(di_node_t node, void *arg)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate 	int inst, rv, match_minor;
4570Sstevel@tonic-gate 	devpath_t *dptp;
4580Sstevel@tonic-gate 	char *physpath, *drv;
4590Sstevel@tonic-gate 	char *drvinst, *devpath;
4600Sstevel@tonic-gate 	const size_t drvlen = MAXPATHLEN;
4610Sstevel@tonic-gate 	size_t devlen;
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	dptp = (devpath_t *)arg;
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	assert(dptp->hba_phys != NULL && dptp->dyncomp != NULL);
4660Sstevel@tonic-gate 	assert(dptp->path == NULL);
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	/*
4690Sstevel@tonic-gate 	 * Skip stub nodes
4700Sstevel@tonic-gate 	 */
4710Sstevel@tonic-gate 	if (IS_STUB_NODE(node)) {
4720Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
4730Sstevel@tonic-gate 	}
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	errno = 0;
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	drv = di_driver_name(node);
4780Sstevel@tonic-gate 	inst = di_instance(node);
4790Sstevel@tonic-gate 	physpath = di_devfs_path(node);
4800Sstevel@tonic-gate 	if (drv == NULL || inst == -1 || physpath == NULL) {
4810Sstevel@tonic-gate 		rv = DI_WALK_CONTINUE;
4820Sstevel@tonic-gate 		goto out;
4830Sstevel@tonic-gate 	}
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	devlen = strlen(DEVICES_DIR) + strlen(physpath) + 1;
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	devpath = calloc(1, devlen);
4880Sstevel@tonic-gate 	drvinst = calloc(1, drvlen);
4890Sstevel@tonic-gate 	if (devpath == NULL || drvinst == NULL) {
4900Sstevel@tonic-gate 		dptp->l_errno = errno;
4910Sstevel@tonic-gate 		dptp->ret = SCFGA_LIB_ERR;
4920Sstevel@tonic-gate 		rv = DI_WALK_TERMINATE;
4930Sstevel@tonic-gate 		goto out;
4940Sstevel@tonic-gate 	}
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	(void) snprintf(drvinst, drvlen, "%s%d", drv, inst);
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	/* Create the physical path */
4990Sstevel@tonic-gate 	(void) snprintf(devpath, devlen, "%s%s", DEVICES_DIR, physpath);
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	/* Skip node if it is the HBA */
5020Sstevel@tonic-gate 	match_minor = 0;
5030Sstevel@tonic-gate 	if (!dev_cmp(dptp->hba_phys, devpath, match_minor)) {
5040Sstevel@tonic-gate 		rv = DI_WALK_CONTINUE;
5050Sstevel@tonic-gate 		goto out;
5060Sstevel@tonic-gate 	}
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	/* Compare the base and dynamic components */
5090Sstevel@tonic-gate 	if (!hba_dev_cmp(dptp->hba_phys, devpath) &&
5100Sstevel@tonic-gate 	    strcmp(dptp->dyncomp, drvinst) == 0) {
5110Sstevel@tonic-gate 		dptp->ret = SCFGA_OK;
5120Sstevel@tonic-gate 		dptp->path = devpath;
5130Sstevel@tonic-gate 		rv = DI_WALK_TERMINATE;
5140Sstevel@tonic-gate 	} else {
5150Sstevel@tonic-gate 		rv =  DI_WALK_CONTINUE;
5160Sstevel@tonic-gate 	}
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	/*FALLTHRU*/
5190Sstevel@tonic-gate out:
5200Sstevel@tonic-gate 	S_FREE(drvinst);
5210Sstevel@tonic-gate 	if (physpath != NULL) di_devfs_path_free(physpath);
5220Sstevel@tonic-gate 	if (dptp->ret != SCFGA_OK) S_FREE(devpath);
5230Sstevel@tonic-gate 	return (rv);
5240Sstevel@tonic-gate }
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate /* readlink wrapper to ensure proper null termination of the results */
5270Sstevel@tonic-gate static int
s_readlink(char * link,char * buf,int len)5280Sstevel@tonic-gate s_readlink(char *link, char *buf, int len)
5290Sstevel@tonic-gate {
5300Sstevel@tonic-gate 	int count;
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 	count = readlink(link, buf, len - 1);
5330Sstevel@tonic-gate 	if (count != -1)
5340Sstevel@tonic-gate 		buf[count] = '\0';
5350Sstevel@tonic-gate 	return (count);
5360Sstevel@tonic-gate }
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate /* Converts a devlink based dynamic component to a path */
5390Sstevel@tonic-gate static scfga_ret_t
devlink_dyn_to_devpath(const char * hba_phys,const char * dyncomp,char ** pathpp,int * l_errnop)5400Sstevel@tonic-gate devlink_dyn_to_devpath(
5410Sstevel@tonic-gate 	const char *hba_phys,
5420Sstevel@tonic-gate 	const char *dyncomp,
5430Sstevel@tonic-gate 	char **pathpp,
5440Sstevel@tonic-gate 	int *l_errnop)
5450Sstevel@tonic-gate {
5460Sstevel@tonic-gate 	dyn_t dynt = {NULL};
5470Sstevel@tonic-gate 	int i;
5480Sstevel@tonic-gate 	scfga_ret_t ret;
5490Sstevel@tonic-gate 	char buf[PATH_MAX], *path;
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	if (*pathpp != NULL) {
5520Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
5530Sstevel@tonic-gate 	}
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	/* Convert the dynamic component to the corresponding devlink */
5560Sstevel@tonic-gate 	dynt.dyncomp = (char *)dyncomp;
5570Sstevel@tonic-gate 	dynt.ret = SCFGA_APID_NOEXIST;
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	for (i = 0; i < N_DYNRULES; i++) {
5600Sstevel@tonic-gate 		if (dyncvt_rules[i].dyncomp_to_devlink_p(&dynt)
5610Sstevel@tonic-gate 		    != SCFGA_CONTINUE) {
5620Sstevel@tonic-gate 			break;
5630Sstevel@tonic-gate 		}
5640Sstevel@tonic-gate 	}
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	if (i >= N_DYNRULES) {
5670Sstevel@tonic-gate 		dynt.ret = SCFGA_APID_NOEXIST;
5680Sstevel@tonic-gate 	}
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 	if (dynt.ret != SCFGA_OK) {
5710Sstevel@tonic-gate 		/* No symlink or error */
5720Sstevel@tonic-gate 		return (dynt.ret);
5730Sstevel@tonic-gate 	}
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	assert(dynt.devlink != NULL);
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	/*
5780Sstevel@tonic-gate 	 * Follow devlink to get the physical path
5790Sstevel@tonic-gate 	 * Note: Do not use realpath().	It will stat() device
5800Sstevel@tonic-gate 	 *	and stat() fails under devfs if device is offline.
5810Sstevel@tonic-gate 	 */
5820Sstevel@tonic-gate 	errno = 0;
5830Sstevel@tonic-gate 	if ((s_readlink(dynt.devlink, buf, PATH_MAX) == -1) ||
5840Sstevel@tonic-gate 	    ((path = strstr(buf, "/devices/")) == NULL) ||
5850Sstevel@tonic-gate 	    ((*pathpp = strdup(path)) == NULL)) {
5860Sstevel@tonic-gate 		*l_errnop = errno;
5870Sstevel@tonic-gate 		ret = SCFGA_LIB_ERR;
5880Sstevel@tonic-gate 		goto out;
5890Sstevel@tonic-gate 	}
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	/* Compare base components as well */
5920Sstevel@tonic-gate 	if (!hba_dev_cmp(hba_phys, path)) {
5930Sstevel@tonic-gate 		ret = SCFGA_OK;
5940Sstevel@tonic-gate 	} else {
5950Sstevel@tonic-gate 		/* Mismatched base and dynamic component */
5960Sstevel@tonic-gate 		*l_errnop = 0;
5970Sstevel@tonic-gate 		ret = SCFGA_APID_NOEXIST;
5980Sstevel@tonic-gate 	}
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	/*FALLTHRU*/
6010Sstevel@tonic-gate out:
6020Sstevel@tonic-gate 	S_FREE(dynt.devlink);
6030Sstevel@tonic-gate 	if (ret != SCFGA_OK) S_FREE(*pathpp);
6040Sstevel@tonic-gate 	return (ret);
6050Sstevel@tonic-gate }
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate scfga_ret_t
make_dyncomp(di_node_t node,const char * physpath,char ** dyncompp,int * l_errnop)6080Sstevel@tonic-gate make_dyncomp(
6090Sstevel@tonic-gate 	di_node_t node,
6100Sstevel@tonic-gate 	const char *physpath,
6110Sstevel@tonic-gate 	char **dyncompp,
6120Sstevel@tonic-gate 	int *l_errnop)
6130Sstevel@tonic-gate {
6140Sstevel@tonic-gate 	char *devlink = NULL;
6150Sstevel@tonic-gate 	scfga_ret_t ret;
6160Sstevel@tonic-gate 	di_minor_t minor;
6170Sstevel@tonic-gate 	char *path;
6180Sstevel@tonic-gate 	char pathbuf[MAXPATHLEN];
6190Sstevel@tonic-gate 	int match_minor;
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	if (*dyncompp != NULL) {
6220Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
6230Sstevel@tonic-gate 	}
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	/* tag on minor name */
6260Sstevel@tonic-gate 	minor = di_minor_next(node, DI_MINOR_NIL);
6270Sstevel@tonic-gate 	if (minor == DI_MINOR_NIL) {
6280Sstevel@tonic-gate 		match_minor = 0;
6290Sstevel@tonic-gate 		path = (char *)physpath;
6300Sstevel@tonic-gate 	} else {
6310Sstevel@tonic-gate 		match_minor = 1;
632*10696SDavid.Hollister@Sun.COM 		(void) snprintf(pathbuf, MAXPATHLEN, "%s:%s", physpath,
6330Sstevel@tonic-gate 		    di_minor_name(minor));
6340Sstevel@tonic-gate 		path = pathbuf;
6350Sstevel@tonic-gate 	}
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	/* Get the corresponding devlink from the physical path */
6380Sstevel@tonic-gate 	ret = physpath_to_devlink(path, &devlink, l_errnop, match_minor);
6390Sstevel@tonic-gate 	if (ret == SCFGA_OK) {
6400Sstevel@tonic-gate 		assert(devlink != NULL);
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 		/* Create dynamic component. */
6430Sstevel@tonic-gate 		ret = devlink_to_dyncomp(devlink, dyncompp, l_errnop);
6440Sstevel@tonic-gate 		S_FREE(devlink);
6450Sstevel@tonic-gate 		if (ret == SCFGA_OK) {
6460Sstevel@tonic-gate 			assert(*dyncompp != NULL);
6470Sstevel@tonic-gate 			return (SCFGA_OK);
6480Sstevel@tonic-gate 		}
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 		/*
6510Sstevel@tonic-gate 		 * Failed to get devlink based dynamic component.
6520Sstevel@tonic-gate 		 * Try driver and instance
6530Sstevel@tonic-gate 		 */
6540Sstevel@tonic-gate 	}
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	ret = drv_to_dyncomp(node, physpath, dyncompp, l_errnop);
6570Sstevel@tonic-gate 	assert(ret != SCFGA_OK || *dyncompp != NULL);
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	return (ret);
6600Sstevel@tonic-gate }
6610Sstevel@tonic-gate 
662*10696SDavid.Hollister@Sun.COM /*
663*10696SDavid.Hollister@Sun.COM  * Create a dynamic component of path ap_id for the given path info node.
664*10696SDavid.Hollister@Sun.COM  * The caller should free the buffer for the dynamic component.
665*10696SDavid.Hollister@Sun.COM  */
666*10696SDavid.Hollister@Sun.COM scfga_ret_t
make_path_dyncomp(di_path_t path,char ** dyncompp,int * l_errnop)667*10696SDavid.Hollister@Sun.COM make_path_dyncomp(
668*10696SDavid.Hollister@Sun.COM 	di_path_t path,
669*10696SDavid.Hollister@Sun.COM 	char **dyncompp,
670*10696SDavid.Hollister@Sun.COM 	int *l_errnop)
671*10696SDavid.Hollister@Sun.COM {
672*10696SDavid.Hollister@Sun.COM 	char *pi_addr;
673*10696SDavid.Hollister@Sun.COM 
674*10696SDavid.Hollister@Sun.COM 	if ((path == DI_PATH_NIL) || (*dyncompp != NULL)) {
675*10696SDavid.Hollister@Sun.COM 		return (SCFGA_LIB_ERR);
676*10696SDavid.Hollister@Sun.COM 	}
677*10696SDavid.Hollister@Sun.COM 
678*10696SDavid.Hollister@Sun.COM 	if ((pi_addr = di_path_bus_addr(path)) != NULL) {
679*10696SDavid.Hollister@Sun.COM 		*dyncompp = calloc(1, strlen(pi_addr) + 1);
680*10696SDavid.Hollister@Sun.COM 		if (*dyncompp == NULL) {
681*10696SDavid.Hollister@Sun.COM 			*l_errnop = errno;
682*10696SDavid.Hollister@Sun.COM 			return (SCFGA_LIB_ERR);
683*10696SDavid.Hollister@Sun.COM 		}
684*10696SDavid.Hollister@Sun.COM 		(void) strncpy(*dyncompp, pi_addr, strlen(pi_addr));
685*10696SDavid.Hollister@Sun.COM 	} else {
686*10696SDavid.Hollister@Sun.COM 		return (SCFGA_LIB_ERR);
687*10696SDavid.Hollister@Sun.COM 	}
688*10696SDavid.Hollister@Sun.COM 
689*10696SDavid.Hollister@Sun.COM 	return (SCFGA_OK);
690*10696SDavid.Hollister@Sun.COM }
691*10696SDavid.Hollister@Sun.COM 
6920Sstevel@tonic-gate /*ARGSUSED*/
6930Sstevel@tonic-gate static scfga_ret_t
drv_to_dyncomp(di_node_t node,const char * phys,char ** dyncompp,int * l_errnop)6940Sstevel@tonic-gate drv_to_dyncomp(di_node_t node, const char *phys, char **dyncompp, int *l_errnop)
6950Sstevel@tonic-gate {
6960Sstevel@tonic-gate 	char *drv;
6970Sstevel@tonic-gate 	int inst;
6980Sstevel@tonic-gate 	const int dynlen = MAXPATHLEN;
6990Sstevel@tonic-gate 	scfga_ret_t ret;
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	*l_errnop = 0;
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	if ((*dyncompp = calloc(1, dynlen)) == NULL) {
7040Sstevel@tonic-gate 		*l_errnop = errno;
7050Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
7060Sstevel@tonic-gate 	}
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	drv = di_driver_name(node);
7090Sstevel@tonic-gate 	inst = di_instance(node);
7100Sstevel@tonic-gate 	if (drv != NULL && inst != -1) {
7110Sstevel@tonic-gate 		if (snprintf(*dyncompp, dynlen, "%s%d", drv, inst) < dynlen) {
7120Sstevel@tonic-gate 			return (SCFGA_OK);
7130Sstevel@tonic-gate 		} else {
7140Sstevel@tonic-gate 			ret = SCFGA_LIB_ERR;
7150Sstevel@tonic-gate 		}
7160Sstevel@tonic-gate 	} else {
7170Sstevel@tonic-gate 		ret = SCFGA_APID_NOEXIST;
7180Sstevel@tonic-gate 	}
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	S_FREE(*dyncompp);
7210Sstevel@tonic-gate 	return (ret);
7220Sstevel@tonic-gate }
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate /* Get a dynamic component from a physical path if possible */
7250Sstevel@tonic-gate static scfga_ret_t
devlink_to_dyncomp(char * devlink,char ** dyncompp,int * l_errnop)7260Sstevel@tonic-gate devlink_to_dyncomp(char *devlink, char **dyncompp, int *l_errnop)
7270Sstevel@tonic-gate {
7280Sstevel@tonic-gate 	int i;
7290Sstevel@tonic-gate 	dyn_t dynt = {NULL};
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	*l_errnop = 0;
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	if (*dyncompp != NULL) {
7340Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
7350Sstevel@tonic-gate 	}
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	/* Convert devlink to dynamic component */
7380Sstevel@tonic-gate 	dynt.devlink = devlink;
7390Sstevel@tonic-gate 	dynt.ret = SCFGA_APID_NOEXIST;
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	for (i = 0; i < N_DYNRULES; i++) {
7420Sstevel@tonic-gate 		if (dyncvt_rules[i].devlink_to_dyncomp_p(&dynt)
7430Sstevel@tonic-gate 		    != SCFGA_CONTINUE) {
7440Sstevel@tonic-gate 			break;
7450Sstevel@tonic-gate 		}
7460Sstevel@tonic-gate 	}
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 	if (i >= N_DYNRULES) {
7490Sstevel@tonic-gate 		dynt.ret = SCFGA_APID_NOEXIST;
7500Sstevel@tonic-gate 	}
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	if (dynt.ret == SCFGA_OK) {
7530Sstevel@tonic-gate 		assert(dynt.dyncomp != NULL);
7540Sstevel@tonic-gate 		*dyncompp = dynt.dyncomp;
7550Sstevel@tonic-gate 	}
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	return (dynt.ret);
7580Sstevel@tonic-gate }
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate /* For disks remove partition information, (s or p) */
7610Sstevel@tonic-gate static scfga_recur_t
disk_devlink_to_dyncomp(dyn_t * dyntp)7620Sstevel@tonic-gate disk_devlink_to_dyncomp(dyn_t *dyntp)
7630Sstevel@tonic-gate {
7640Sstevel@tonic-gate 	char *cp = NULL, *cp1 = NULL;
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	assert(dyntp->devlink != NULL);
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	dyntp->l_errno = 0;
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	if (dyntp->dyncomp != NULL) {
7710Sstevel@tonic-gate 		goto lib_err;
7720Sstevel@tonic-gate 	}
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	/* Check if a disk devlink */
7750Sstevel@tonic-gate 	if (strncmp(dyntp->devlink, DEV_DSK SLASH, strlen(DEV_DSK SLASH)) &&
7760Sstevel@tonic-gate 	    strncmp(dyntp->devlink, DEV_RDSK SLASH, strlen(DEV_RDSK SLASH))) {
7770Sstevel@tonic-gate 		return (SCFGA_CONTINUE);
7780Sstevel@tonic-gate 	}
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	cp = dyntp->devlink + strlen(DEV_DIR SLASH);
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	if ((dyntp->dyncomp = strdup(cp)) == NULL) {
7830Sstevel@tonic-gate 		dyntp->l_errno = errno;
7840Sstevel@tonic-gate 		goto lib_err;
7850Sstevel@tonic-gate 	}
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	/* Get the leaf component from dsk/cXtYdZsN */
7880Sstevel@tonic-gate 	cp1 = strrchr(dyntp->dyncomp, '/');
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	/* Blank out partition information */
7910Sstevel@tonic-gate 	dyntp->ret = SCFGA_OK;
7920Sstevel@tonic-gate 	if ((cp = strchr(cp1 + 1, 's')) != NULL) {
7930Sstevel@tonic-gate 		*cp = '\0';
7940Sstevel@tonic-gate 	} else if ((cp = strchr(cp1 + 1, 'p')) != NULL) {
7950Sstevel@tonic-gate 		*cp = '\0';
7960Sstevel@tonic-gate 	} else {
7970Sstevel@tonic-gate 		S_FREE(dyntp->dyncomp);
7980Sstevel@tonic-gate 		dyntp->ret = SCFGA_ERR;
7990Sstevel@tonic-gate 	}
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate lib_err:
8040Sstevel@tonic-gate 	dyntp->ret = SCFGA_LIB_ERR;
8050Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
8060Sstevel@tonic-gate }
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate static scfga_recur_t
disk_dyncomp_to_devlink(dyn_t * dyntp)8100Sstevel@tonic-gate disk_dyncomp_to_devlink(dyn_t *dyntp)
8110Sstevel@tonic-gate {
8120Sstevel@tonic-gate 	char buf[MAXPATHLEN], *cp = NULL;
8130Sstevel@tonic-gate 	int i, j;
8140Sstevel@tonic-gate 	size_t len;
8150Sstevel@tonic-gate 	struct stat sbuf;
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	assert(dyntp->dyncomp != NULL);
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	dyntp->l_errno = 0;
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	if (dyntp->devlink != NULL) {
8220Sstevel@tonic-gate 		dyntp->ret = SCFGA_LIB_ERR;
8230Sstevel@tonic-gate 		return (SCFGA_TERMINATE);
8240Sstevel@tonic-gate 	}
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	/* A disk link can only be from DEV_DSK (ignore /dev/rdsk) */
8270Sstevel@tonic-gate 	if (strncmp(dyntp->dyncomp, DSK_DIR SLASH, strlen(DSK_DIR SLASH)) != 0)
8280Sstevel@tonic-gate 		return (SCFGA_CONTINUE);	/* not a disk link */
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%s%s", DEV_DIR SLASH,
8310Sstevel@tonic-gate 	    dyntp->dyncomp);
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 	len = strlen(buf);
8340Sstevel@tonic-gate 	cp = buf + len;
8350Sstevel@tonic-gate 	len = sizeof (buf) - len;
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	for (i = 0; i < N_SLICE_TYPES; i++) {
8380Sstevel@tonic-gate 		for (j = 0; j < disk_slices[i].nslices; j++) {
8390Sstevel@tonic-gate 			if (snprintf(cp, len, "%s%d", disk_slices[i].prefix, j)
8400Sstevel@tonic-gate 			    >= len) {
8410Sstevel@tonic-gate 				continue;
8420Sstevel@tonic-gate 			}
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 			if (lstat(buf, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) {
8450Sstevel@tonic-gate 				if ((dyntp->devlink = strdup(buf)) == NULL) {
8460Sstevel@tonic-gate 					dyntp->l_errno = errno;
8470Sstevel@tonic-gate 					dyntp->ret = SCFGA_LIB_ERR;
8480Sstevel@tonic-gate 					return (SCFGA_TERMINATE);
8490Sstevel@tonic-gate 				}
8500Sstevel@tonic-gate 				dyntp->ret = SCFGA_OK;
8510Sstevel@tonic-gate 				return (SCFGA_TERMINATE);
8520Sstevel@tonic-gate 			}
8530Sstevel@tonic-gate 		}
8540Sstevel@tonic-gate 	}
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 	dyntp->ret = SCFGA_APID_NOEXIST;
8570Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
8580Sstevel@tonic-gate }
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate /* For tapes, remove mode(minor) information from link */
8610Sstevel@tonic-gate static scfga_recur_t
tape_devlink_to_dyncomp(dyn_t * dyntp)8620Sstevel@tonic-gate tape_devlink_to_dyncomp(dyn_t *dyntp)
8630Sstevel@tonic-gate {
8640Sstevel@tonic-gate 	char *cp = NULL;
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	assert(dyntp->devlink != NULL);
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	dyntp->l_errno = 0;
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 	if (dyntp->dyncomp != NULL) {
8710Sstevel@tonic-gate 		goto lib_err;
8720Sstevel@tonic-gate 	}
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	if (strncmp(dyntp->devlink, DEV_RMT SLASH, strlen(DEV_RMT SLASH))) {
8750Sstevel@tonic-gate 		return (SCFGA_CONTINUE);	/* not a tape */
8760Sstevel@tonic-gate 	}
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	cp = dyntp->devlink + strlen(DEV_DIR SLASH);
8790Sstevel@tonic-gate 	if ((dyntp->dyncomp = strdup(cp)) == NULL) {
8800Sstevel@tonic-gate 		dyntp->l_errno = errno;
8810Sstevel@tonic-gate 		goto lib_err;
8820Sstevel@tonic-gate 	}
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 	/* Get the leaf component from rmt/xyz */
8850Sstevel@tonic-gate 	cp = strrchr(dyntp->dyncomp, '/');
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	/* Remove the mode part */
888*10696SDavid.Hollister@Sun.COM 	while (isdigit(*(++cp))) {
889*10696SDavid.Hollister@Sun.COM 	};
8900Sstevel@tonic-gate 	*cp = '\0';
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 	dyntp->ret = SCFGA_OK;
8940Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate lib_err:
8970Sstevel@tonic-gate 	dyntp->ret = SCFGA_LIB_ERR;
8980Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
8990Sstevel@tonic-gate }
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate static scfga_recur_t
tape_dyncomp_to_devlink(dyn_t * dyntp)9020Sstevel@tonic-gate tape_dyncomp_to_devlink(dyn_t *dyntp)
9030Sstevel@tonic-gate {
9040Sstevel@tonic-gate 	char buf[MAXPATHLEN], *cp = NULL;
9050Sstevel@tonic-gate 	int i;
9060Sstevel@tonic-gate 	size_t len = 0;
9070Sstevel@tonic-gate 	struct stat sbuf;
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	assert(dyntp->dyncomp != NULL);
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate 	dyntp->l_errno = 0;
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	if (dyntp->devlink != NULL) {
9140Sstevel@tonic-gate 		goto lib_err;
9150Sstevel@tonic-gate 	}
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 	if (strncmp(dyntp->dyncomp, RMT_DIR SLASH, strlen(RMT_DIR SLASH))) {
9180Sstevel@tonic-gate 		return (SCFGA_CONTINUE);	/* not a tape */
9190Sstevel@tonic-gate 	}
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 	/* A tape device */
9220Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%s%s", DEV_DIR SLASH,
9230Sstevel@tonic-gate 	    dyntp->dyncomp);
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	len = strlen(buf);
9260Sstevel@tonic-gate 	cp = buf + len;
9270Sstevel@tonic-gate 	len = sizeof (buf) - len;
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	for (i = 0; i < N_TAPE_MODES; i++) {
9300Sstevel@tonic-gate 		(void) snprintf(cp, len, "%s", tape_modes[i]);
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 		if (lstat(buf, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) {
9330Sstevel@tonic-gate 			if ((dyntp->devlink = strdup(buf)) == NULL) {
9340Sstevel@tonic-gate 				dyntp->l_errno = errno;
9350Sstevel@tonic-gate 				goto lib_err;
9360Sstevel@tonic-gate 			}
9370Sstevel@tonic-gate 			dyntp->ret = SCFGA_OK;
9380Sstevel@tonic-gate 			return (SCFGA_TERMINATE);
9390Sstevel@tonic-gate 		}
9400Sstevel@tonic-gate 	}
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 	dyntp->ret = SCFGA_APID_NOEXIST;
9430Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate lib_err:
9460Sstevel@tonic-gate 	dyntp->ret = SCFGA_LIB_ERR;
9470Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate }
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate /*
9520Sstevel@tonic-gate  * Default rules
9530Sstevel@tonic-gate  */
9540Sstevel@tonic-gate static scfga_recur_t
def_devlink_to_dyncomp(dyn_t * dyntp)9550Sstevel@tonic-gate def_devlink_to_dyncomp(dyn_t *dyntp)
9560Sstevel@tonic-gate {
9570Sstevel@tonic-gate 	size_t len = 0;
9580Sstevel@tonic-gate 	char *cp = NULL;
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 	assert(dyntp->devlink != NULL);
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	dyntp->l_errno = 0;
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 	if (dyntp->dyncomp != NULL) {
9650Sstevel@tonic-gate 		dyntp->ret = SCFGA_LIB_ERR;
9660Sstevel@tonic-gate 		return (SCFGA_TERMINATE);
9670Sstevel@tonic-gate 	}
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	/* Is it a link in DEV_DIR directory ? */
9700Sstevel@tonic-gate 	len = strlen(DEV_DIR SLASH);
9710Sstevel@tonic-gate 	if (strncmp(dyntp->devlink, DEV_DIR SLASH, len)) {
9720Sstevel@tonic-gate 		return (SCFGA_CONTINUE);
9730Sstevel@tonic-gate 	}
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	/* Check if this is a top level devlink */
9760Sstevel@tonic-gate 	if (strchr(dyntp->devlink + len, '/') != NULL) {
9770Sstevel@tonic-gate 		/* not top level - Remove DEV_DIR SLASH prefix */
9780Sstevel@tonic-gate 		cp = dyntp->devlink + len;
9790Sstevel@tonic-gate 	} else {
9800Sstevel@tonic-gate 		/* top level, leave DEV_DIR SLASH part in */
9810Sstevel@tonic-gate 		cp = dyntp->devlink;
9820Sstevel@tonic-gate 	}
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 	if ((dyntp->dyncomp = strdup(cp)) == NULL) {
9850Sstevel@tonic-gate 		dyntp->l_errno = errno;
9860Sstevel@tonic-gate 		dyntp->ret = SCFGA_LIB_ERR;
9870Sstevel@tonic-gate 	} else {
9880Sstevel@tonic-gate 		dyntp->ret = SCFGA_OK;
9890Sstevel@tonic-gate 	}
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate }
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate static scfga_recur_t
def_dyncomp_to_devlink(dyn_t * dyntp)9960Sstevel@tonic-gate def_dyncomp_to_devlink(dyn_t *dyntp)
9970Sstevel@tonic-gate {
9980Sstevel@tonic-gate 	struct stat sbuf;
9990Sstevel@tonic-gate 	int top;
10000Sstevel@tonic-gate 	size_t prelen, linklen;
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 	assert(dyntp->dyncomp != NULL);
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	dyntp->l_errno = 0;
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 	if (dyntp->devlink != NULL) {
10070Sstevel@tonic-gate 		goto lib_err;
10080Sstevel@tonic-gate 	}
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 	prelen = strlen(DEV_DIR SLASH);
10110Sstevel@tonic-gate 	linklen = strlen(dyntp->dyncomp) + 1;
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 	/*
10140Sstevel@tonic-gate 	 * Check if the dynamic component was derived from a top level entry
10150Sstevel@tonic-gate 	 * in "/dev"
10160Sstevel@tonic-gate 	 */
10170Sstevel@tonic-gate 	if (strncmp(dyntp->dyncomp, DEV_DIR SLASH, prelen) == 0) {
10180Sstevel@tonic-gate 		top = 1;
10190Sstevel@tonic-gate 	} else if (*dyntp->dyncomp != '/' && linklen > 1 &&
10200Sstevel@tonic-gate 	    strchr(dyntp->dyncomp + 1, '/') != NULL) {
10210Sstevel@tonic-gate 		top = 0;
10220Sstevel@tonic-gate 		linklen += prelen;  /* The "/dev/" needs to be prepended */
10230Sstevel@tonic-gate 	} else {
10240Sstevel@tonic-gate 		/* Not a dynamic component we handle */
10250Sstevel@tonic-gate 		return (SCFGA_CONTINUE);
10260Sstevel@tonic-gate 	}
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	if ((dyntp->devlink = calloc(1, linklen)) == NULL) {
10290Sstevel@tonic-gate 		dyntp->l_errno = errno;
10300Sstevel@tonic-gate 		goto lib_err;
10310Sstevel@tonic-gate 	}
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 	*dyntp->devlink = '\0';
10340Sstevel@tonic-gate 	if (!top) {
10350Sstevel@tonic-gate 		(void) strcpy(dyntp->devlink, DEV_DIR SLASH);
10360Sstevel@tonic-gate 	}
10370Sstevel@tonic-gate 	(void) strcat(dyntp->devlink, dyntp->dyncomp);
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 	if (lstat(dyntp->devlink, &sbuf) != -1 && S_ISLNK(sbuf.st_mode)) {
10400Sstevel@tonic-gate 		dyntp->ret = SCFGA_OK;
10410Sstevel@tonic-gate 		return (SCFGA_TERMINATE);
10420Sstevel@tonic-gate 	}
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 	S_FREE(dyntp->devlink);
10460Sstevel@tonic-gate 	return (SCFGA_CONTINUE);
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate lib_err:
10490Sstevel@tonic-gate 	dyntp->ret = SCFGA_LIB_ERR;
10500Sstevel@tonic-gate 	return (SCFGA_TERMINATE);
10510Sstevel@tonic-gate }
1052