xref: /onnv-gate/usr/src/lib/cfgadm_plugins/scsi/common/cfga_utils.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
51957Sdnielsen  * Common Development and Distribution License (the "License").
61957Sdnielsen  * 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  */
211957Sdnielsen 
220Sstevel@tonic-gate /*
23*10696SDavid.Hollister@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include "cfga_scsi.h"
281957Sdnielsen #include <libgen.h>
291957Sdnielsen #include <limits.h>
300Sstevel@tonic-gate 
310Sstevel@tonic-gate /*
320Sstevel@tonic-gate  * This file contains helper routines for the SCSI plugin
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
360Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
370Sstevel@tonic-gate #endif
380Sstevel@tonic-gate 
390Sstevel@tonic-gate typedef struct strlist {
400Sstevel@tonic-gate 	const char *str;
410Sstevel@tonic-gate 	struct strlist *next;
420Sstevel@tonic-gate } strlist_t;
430Sstevel@tonic-gate 
440Sstevel@tonic-gate typedef	struct {
450Sstevel@tonic-gate 	scfga_ret_t scsi_err;
460Sstevel@tonic-gate 	cfga_err_t  cfga_err;
470Sstevel@tonic-gate } errcvt_t;
480Sstevel@tonic-gate 
490Sstevel@tonic-gate typedef struct {
500Sstevel@tonic-gate 	scfga_cmd_t cmd;
510Sstevel@tonic-gate 	int type;
520Sstevel@tonic-gate 	int (*fcn)(const devctl_hdl_t);
530Sstevel@tonic-gate } set_state_cmd_t;
540Sstevel@tonic-gate 
550Sstevel@tonic-gate typedef struct {
560Sstevel@tonic-gate 	scfga_cmd_t cmd;
570Sstevel@tonic-gate 	int type;
580Sstevel@tonic-gate 	int (*state_fcn)(const devctl_hdl_t, uint_t *);
590Sstevel@tonic-gate } get_state_cmd_t;
600Sstevel@tonic-gate 
610Sstevel@tonic-gate /* Function prototypes */
620Sstevel@tonic-gate static char *pathdup(const char *path, int *l_errnop);
630Sstevel@tonic-gate static void msg_common(char **err_msgpp, int append_newline, int l_errno,
640Sstevel@tonic-gate     va_list ap);
650Sstevel@tonic-gate 
660Sstevel@tonic-gate /*
670Sstevel@tonic-gate  * The string table contains most of the strings used by the scsi cfgadm plugin.
680Sstevel@tonic-gate  * All strings which are to be internationalized must be in this table.
690Sstevel@tonic-gate  * Some strings which are not internationalized are also included here.
700Sstevel@tonic-gate  * Arguments to messages are NOT internationalized.
710Sstevel@tonic-gate  */
720Sstevel@tonic-gate msgcvt_t str_tbl[] = {
730Sstevel@tonic-gate 
740Sstevel@tonic-gate /*
750Sstevel@tonic-gate  * The first element (ERR_UNKNOWN) MUST always be present in the array.
760Sstevel@tonic-gate  */
770Sstevel@tonic-gate #define	UNKNOWN_ERR_IDX		0	/* Keep the index in sync */
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /* msg_code	num_args, I18N	msg_string				*/
810Sstevel@tonic-gate 
820Sstevel@tonic-gate /* ERRORS */
830Sstevel@tonic-gate {ERR_UNKNOWN,		0, 1,	"unknown error"},
840Sstevel@tonic-gate {ERR_OP_FAILED,		0, 1,	"operation failed"},
850Sstevel@tonic-gate {ERR_CMD_INVAL,		0, 1,	"invalid command"},
860Sstevel@tonic-gate {ERR_NOT_BUSAPID,	0, 1,	"not a SCSI bus apid"},
870Sstevel@tonic-gate {ERR_APID_INVAL,	0, 1,	"invalid SCSI ap_id"},
880Sstevel@tonic-gate {ERR_NOT_BUSOP,		0, 1,	"operation not supported for SCSI bus"},
890Sstevel@tonic-gate {ERR_NOT_DEVOP,		0, 1,	"operation not supported for SCSI device"},
900Sstevel@tonic-gate {ERR_UNAVAILABLE,	0, 1,	"unavailable"},
910Sstevel@tonic-gate {ERR_CTRLR_CRIT,	0, 1,	"critical partition controlled by SCSI HBA"},
920Sstevel@tonic-gate {ERR_BUS_GETSTATE,	0, 1,	"failed to get state for SCSI bus"},
930Sstevel@tonic-gate {ERR_BUS_NOTCONNECTED,	0, 1,	"SCSI bus not connected"},
940Sstevel@tonic-gate {ERR_BUS_CONNECTED,	0, 1,	"SCSI bus not disconnected"},
950Sstevel@tonic-gate {ERR_BUS_QUIESCE,	0, 1,	"SCSI bus quiesce failed"},
960Sstevel@tonic-gate {ERR_BUS_UNQUIESCE,	0, 1,	"SCSI bus unquiesce failed"},
970Sstevel@tonic-gate {ERR_BUS_CONFIGURE,	0, 1,	"failed to configure devices on SCSI bus"},
980Sstevel@tonic-gate {ERR_BUS_UNCONFIGURE,	0, 1,	"failed to unconfigure SCSI bus"},
990Sstevel@tonic-gate {ERR_DEV_CONFIGURE,	0, 1,	"failed to configure SCSI device"},
1000Sstevel@tonic-gate {ERR_DEV_RECONFIGURE,	1, 1,	"failed to reconfigure device: "},
1010Sstevel@tonic-gate {ERR_DEV_UNCONFIGURE,	0, 1,	"failed to unconfigure SCSI device"},
1020Sstevel@tonic-gate {ERR_DEV_REMOVE,	0, 1,	"remove operation failed"},
1030Sstevel@tonic-gate {ERR_DEV_REPLACE,	0, 1,	"replace operation failed"},
1040Sstevel@tonic-gate {ERR_DEV_INSERT,	0, 1,	"insert operation failed"},
1050Sstevel@tonic-gate {ERR_DEV_GETSTATE,	0, 1,	"failed to get state for SCSI device"},
1060Sstevel@tonic-gate {ERR_RESET,		0, 1,	"reset failed"},
1070Sstevel@tonic-gate {ERR_LIST,		0, 1,	"list operation failed"},
1080Sstevel@tonic-gate {ERR_MAYBE_BUSY,	0, 1,	"device may be busy"},
1090Sstevel@tonic-gate {ERR_BUS_DEV_MISMATCH,	0, 1,	"mismatched SCSI bus and device"},
1100Sstevel@tonic-gate {ERR_VAR_RUN,		0, 1,	"/var/run is not mounted"},
1110Sstevel@tonic-gate {ERR_FORK,		0, 1,	"failed to fork cleanup handler"},
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate /* Errors with arguments */
1140Sstevel@tonic-gate {ERRARG_OPT_INVAL,	1, 1,	"invalid option: "},
1150Sstevel@tonic-gate {ERRARG_HWCMD_INVAL,	1, 1,	"invalid command: "},
1160Sstevel@tonic-gate {ERRARG_DEVINFO,	1, 1,	"libdevinfo failed on path: "},
1170Sstevel@tonic-gate {ERRARG_OPEN,		1, 1,	"open failed: "},
1180Sstevel@tonic-gate {ERRARG_LOCK,		1, 1,	"lock failed: "},
1190Sstevel@tonic-gate {ERRARG_QUIESCE_LOCK,	1, 1,	"cannot acquire quiesce lock: "},
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate /* RCM Errors */
1220Sstevel@tonic-gate {ERR_RCM_HANDLE,	0, 1,	"cannot get RCM handle"},
1230Sstevel@tonic-gate {ERRARG_RCM_SUSPEND,	0, 1,	"failed to suspend: "},
1240Sstevel@tonic-gate {ERRARG_RCM_RESUME,	0, 1,	"failed to resume: "},
1250Sstevel@tonic-gate {ERRARG_RCM_OFFLINE,	0, 1,	"failed to offline: "},
126*10696SDavid.Hollister@Sun.COM {ERRARG_RCM_CLIENT_OFFLINE,	0, 1,	"failed to offline a client device: "},
1270Sstevel@tonic-gate {ERRARG_RCM_ONLINE,	0, 1,	"failed to online: "},
1280Sstevel@tonic-gate {ERRARG_RCM_REMOVE,	0, 1,	"failed to remove: "},
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate /* Commands */
1310Sstevel@tonic-gate {CMD_INSERT_DEV,	0, 0,	"insert_device"},
1320Sstevel@tonic-gate {CMD_REMOVE_DEV,	0, 0,	"remove_device"},
1331957Sdnielsen {CMD_LED_DEV,		0, 0,	"led"},
1341957Sdnielsen {CMD_LOCATOR_DEV,	0, 0,	"locator"},
1350Sstevel@tonic-gate {CMD_REPLACE_DEV,	0, 0,	"replace_device"},
1360Sstevel@tonic-gate {CMD_RESET_DEV,		0, 0,	"reset_device"},
1370Sstevel@tonic-gate {CMD_RESET_BUS,		0, 0,	"reset_bus"},
1380Sstevel@tonic-gate {CMD_RESET_ALL,		0, 0,	"reset_all"},
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate /* help messages */
1410Sstevel@tonic-gate {MSG_HELP_HDR,		0, 1,	"\nSCSI specific commands and options:\n"},
1420Sstevel@tonic-gate {MSG_HELP_USAGE,	0, 0,	"\t-x insert_device ap_id [ap_id... ]\n"
1430Sstevel@tonic-gate 				"\t-x remove_device ap_id [ap_id... ]\n"
1440Sstevel@tonic-gate 				"\t-x replace_device ap_id [ap_id... ]\n"
1451957Sdnielsen 				"\t-x locator[=on|off] ap_id [ap_id... ]\n"
1461957Sdnielsen 				"\t-x led[=LED,mode=on|off|blink] "
1471957Sdnielsen 				    "ap_id [ap_id... ]\n"
1480Sstevel@tonic-gate 				"\t-x reset_device ap_id [ap_id... ]\n"
1490Sstevel@tonic-gate 				"\t-x reset_bus ap_id [ap_id... ]\n"
1500Sstevel@tonic-gate 				"\t-x reset_all ap_id [ap_id... ]\n"},
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate /* hotplug messages */
1530Sstevel@tonic-gate {MSG_INSDEV,		1, 1,	"Adding device to SCSI HBA: "},
1540Sstevel@tonic-gate {MSG_RMDEV,		1, 1,	"Removing SCSI device: "},
1550Sstevel@tonic-gate {MSG_REPLDEV,		1, 1,	"Replacing SCSI device: "},
1560Sstevel@tonic-gate {MSG_WAIT_LOCK,		0, 1,	"Waiting for quiesce lock... "},
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate /* Hotplugging confirmation prompts */
1590Sstevel@tonic-gate {CONF_QUIESCE_1,	1, 1,
1600Sstevel@tonic-gate 	"This operation will suspend activity on SCSI bus: "},
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate {CONF_QUIESCE_2,	0, 1,	"\nContinue"},
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate {CONF_UNQUIESCE,	0, 1,
1650Sstevel@tonic-gate 	"SCSI bus quiesced successfully.\n"
1660Sstevel@tonic-gate 	"It is now safe to proceed with hotplug operation."
1670Sstevel@tonic-gate 	"\nEnter y if operation is complete or n to abort"},
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate {CONF_NO_QUIESCE,	0, 1,
1700Sstevel@tonic-gate 	"Proceed with hotplug operation."
1710Sstevel@tonic-gate 	"\nEnter y if operation is complete or n to abort"},
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate /* Misc. */
1740Sstevel@tonic-gate {WARN_DISCONNECT,	0, 1,
1750Sstevel@tonic-gate 	"WARNING: Disconnecting critical partitions may cause system hang."
1761957Sdnielsen 	"\nContinue"},
1771957Sdnielsen 
1781957Sdnielsen /* LED messages */
1791957Sdnielsen {MSG_LED_HDR,		0, 1,	"Disk                    Led"},
1801957Sdnielsen {MSG_MISSING_LED_NAME,	0, 1,	"Missing LED name"},
1811957Sdnielsen {MSG_MISSING_LED_MODE,	0, 1,	"Missing LED mode"}
1820Sstevel@tonic-gate };
1830Sstevel@tonic-gate 
1841957Sdnielsen char *
1851957Sdnielsen led_strs[] = {
1861957Sdnielsen 	"fault",
1871957Sdnielsen 	"power",
1881957Sdnielsen 	"attn",
1891957Sdnielsen 	"active",
1901957Sdnielsen 	"locator",
1911957Sdnielsen 	NULL
1921957Sdnielsen };
1931957Sdnielsen 
1941957Sdnielsen char *
1951957Sdnielsen led_mode_strs[] = {
1961957Sdnielsen 	"off",
1971957Sdnielsen 	"on",
1981957Sdnielsen 	"blink",
1991957Sdnielsen 	"faulted",
2001957Sdnielsen 	"unknown",
2011957Sdnielsen 	NULL
2021957Sdnielsen };
2031957Sdnielsen 
2041957Sdnielsen 
2051957Sdnielsen 
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate #define	N_STRS	(sizeof (str_tbl) / sizeof (str_tbl[0]))
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate #define	GET_MSG_NARGS(i)	(str_tbl[msg_idx(i)].nargs)
2100Sstevel@tonic-gate #define	GET_MSG_INTL(i)		(str_tbl[msg_idx(i)].intl)
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate static errcvt_t err_cvt_tbl[] = {
2130Sstevel@tonic-gate 	{ SCFGA_OK,		CFGA_OK			},
2140Sstevel@tonic-gate 	{ SCFGA_LIB_ERR,	CFGA_LIB_ERROR		},
2150Sstevel@tonic-gate 	{ SCFGA_APID_NOEXIST,	CFGA_APID_NOEXIST	},
2160Sstevel@tonic-gate 	{ SCFGA_NACK,		CFGA_NACK		},
2170Sstevel@tonic-gate 	{ SCFGA_BUSY,		CFGA_BUSY		},
2180Sstevel@tonic-gate 	{ SCFGA_SYSTEM_BUSY,	CFGA_SYSTEM_BUSY	},
2190Sstevel@tonic-gate 	{ SCFGA_OPNOTSUPP,	CFGA_OPNOTSUPP		},
2200Sstevel@tonic-gate 	{ SCFGA_PRIV,		CFGA_PRIV		},
2210Sstevel@tonic-gate 	{ SCFGA_UNKNOWN_ERR,	CFGA_ERROR		},
2220Sstevel@tonic-gate 	{ SCFGA_ERR,		CFGA_ERROR		}
2230Sstevel@tonic-gate };
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate #define	N_ERR_CVT_TBL	(sizeof (err_cvt_tbl)/sizeof (err_cvt_tbl[0]))
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate #define	DEV_OP	0
2280Sstevel@tonic-gate #define	BUS_OP	1
2290Sstevel@tonic-gate static set_state_cmd_t set_state_cmds[] = {
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate { SCFGA_BUS_QUIESCE,		BUS_OP,		devctl_bus_quiesce	},
2320Sstevel@tonic-gate { SCFGA_BUS_UNQUIESCE,		BUS_OP,		devctl_bus_unquiesce	},
2330Sstevel@tonic-gate { SCFGA_BUS_CONFIGURE,		BUS_OP,		devctl_bus_configure	},
2340Sstevel@tonic-gate { SCFGA_BUS_UNCONFIGURE, 	BUS_OP,		devctl_bus_unconfigure	},
2350Sstevel@tonic-gate { SCFGA_RESET_BUS,		BUS_OP,		devctl_bus_reset	},
2360Sstevel@tonic-gate { SCFGA_RESET_ALL, 		BUS_OP,		devctl_bus_resetall	},
2370Sstevel@tonic-gate { SCFGA_DEV_CONFIGURE,		DEV_OP,		devctl_device_online	},
2380Sstevel@tonic-gate { SCFGA_DEV_UNCONFIGURE,	DEV_OP,		devctl_device_offline	},
2390Sstevel@tonic-gate { SCFGA_DEV_REMOVE,		DEV_OP,		devctl_device_remove	},
2400Sstevel@tonic-gate { SCFGA_RESET_DEV,		DEV_OP,		devctl_device_reset	}
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate };
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate #define	N_SET_STATE_CMDS (sizeof (set_state_cmds)/sizeof (set_state_cmds[0]))
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate static get_state_cmd_t get_state_cmds[] = {
2470Sstevel@tonic-gate { SCFGA_BUS_GETSTATE,		BUS_OP,		devctl_bus_getstate	},
2480Sstevel@tonic-gate { SCFGA_DEV_GETSTATE,		DEV_OP,		devctl_device_getstate	}
2490Sstevel@tonic-gate };
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate #define	N_GET_STATE_CMDS (sizeof (get_state_cmds)/sizeof (get_state_cmds[0]))
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate /*
2540Sstevel@tonic-gate  * SCSI hardware specific commands
2550Sstevel@tonic-gate  */
2560Sstevel@tonic-gate static hw_cmd_t hw_cmds[] = {
2570Sstevel@tonic-gate 	/* Command string	Command ID		Function	*/
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	{ CMD_INSERT_DEV,	SCFGA_INSERT_DEV,	dev_insert	},
2600Sstevel@tonic-gate 	{ CMD_REMOVE_DEV,	SCFGA_REMOVE_DEV,	dev_remove	},
2610Sstevel@tonic-gate 	{ CMD_REPLACE_DEV,	SCFGA_REPLACE_DEV,	dev_replace	},
2621957Sdnielsen 	{ CMD_LED_DEV,		SCFGA_LED_DEV,		dev_led		},
2631957Sdnielsen 	{ CMD_LOCATOR_DEV,	SCFGA_LOCATOR_DEV,	dev_led		},
2640Sstevel@tonic-gate 	{ CMD_RESET_DEV,	SCFGA_RESET_DEV,	reset_common	},
2650Sstevel@tonic-gate 	{ CMD_RESET_BUS,	SCFGA_RESET_BUS,	reset_common	},
2660Sstevel@tonic-gate 	{ CMD_RESET_ALL,	SCFGA_RESET_ALL,	reset_common	},
2670Sstevel@tonic-gate };
2680Sstevel@tonic-gate #define	N_HW_CMDS (sizeof (hw_cmds) / sizeof (hw_cmds[0]))
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate cfga_err_t
err_cvt(scfga_ret_t s_err)2720Sstevel@tonic-gate err_cvt(scfga_ret_t s_err)
2730Sstevel@tonic-gate {
2740Sstevel@tonic-gate 	int i;
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	for (i = 0; i < N_ERR_CVT_TBL; i++) {
2770Sstevel@tonic-gate 		if (err_cvt_tbl[i].scsi_err == s_err) {
2780Sstevel@tonic-gate 			return (err_cvt_tbl[i].cfga_err);
2790Sstevel@tonic-gate 		}
2800Sstevel@tonic-gate 	}
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	return (CFGA_ERROR);
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate /*
2860Sstevel@tonic-gate  * Removes duplicate slashes from a pathname and any trailing slashes.
2870Sstevel@tonic-gate  * Returns "/" if input is "/"
2880Sstevel@tonic-gate  */
2890Sstevel@tonic-gate static char *
pathdup(const char * path,int * l_errnop)2900Sstevel@tonic-gate pathdup(const char *path, int *l_errnop)
2910Sstevel@tonic-gate {
2920Sstevel@tonic-gate 	int prev_was_slash = 0;
2930Sstevel@tonic-gate 	char c, *dp = NULL, *dup = NULL;
2940Sstevel@tonic-gate 	const char *sp = NULL;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	*l_errnop = 0;
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	if (path == NULL) {
2990Sstevel@tonic-gate 		return (NULL);
3000Sstevel@tonic-gate 	}
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	if ((dup = calloc(1, strlen(path) + 1)) == NULL) {
3030Sstevel@tonic-gate 		*l_errnop = errno;
3040Sstevel@tonic-gate 		return (NULL);
3050Sstevel@tonic-gate 	}
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	prev_was_slash = 0;
3080Sstevel@tonic-gate 	for (sp = path, dp = dup; (c = *sp) != '\0'; sp++) {
3090Sstevel@tonic-gate 		if (!prev_was_slash || c != '/') {
3100Sstevel@tonic-gate 			*dp++ = c;
3110Sstevel@tonic-gate 		}
3120Sstevel@tonic-gate 		if (c == '/') {
3130Sstevel@tonic-gate 			prev_was_slash = 1;
3140Sstevel@tonic-gate 		} else {
3150Sstevel@tonic-gate 			prev_was_slash = 0;
3160Sstevel@tonic-gate 		}
3170Sstevel@tonic-gate 	}
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	/* Remove trailing slash except if it is the first char */
3200Sstevel@tonic-gate 	if (prev_was_slash && dp != dup && dp - 1 != dup) {
3210Sstevel@tonic-gate 		*(--dp) = '\0';
3220Sstevel@tonic-gate 	} else {
3230Sstevel@tonic-gate 		*dp = '\0';
3240Sstevel@tonic-gate 	}
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	return (dup);
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate 
329*10696SDavid.Hollister@Sun.COM 
3300Sstevel@tonic-gate scfga_ret_t
apidt_create(const char * ap_id,apid_t * apidp,char ** errstring)3310Sstevel@tonic-gate apidt_create(const char *ap_id, apid_t *apidp, char **errstring)
3320Sstevel@tonic-gate {
3330Sstevel@tonic-gate 	char *hba_phys = NULL, *dyn = NULL;
3340Sstevel@tonic-gate 	char *dyncomp = NULL, *path = NULL;
3350Sstevel@tonic-gate 	int l_errno = 0;
3360Sstevel@tonic-gate 	size_t len = 0;
3370Sstevel@tonic-gate 	scfga_ret_t ret;
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	if ((hba_phys = pathdup(ap_id, &l_errno)) == NULL) {
3400Sstevel@tonic-gate 		cfga_err(errstring, l_errno, ERR_OP_FAILED, 0);
3410Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
3420Sstevel@tonic-gate 	}
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	/* Extract the base(hba) and dynamic(device) component if any */
3450Sstevel@tonic-gate 	dyncomp = NULL;
3460Sstevel@tonic-gate 	if ((dyn = GET_DYN(hba_phys)) != NULL) {
3470Sstevel@tonic-gate 		len = strlen(DYN_TO_DYNCOMP(dyn)) + 1;
3480Sstevel@tonic-gate 		dyncomp = calloc(1, len);
3490Sstevel@tonic-gate 		if (dyncomp == NULL) {
3500Sstevel@tonic-gate 			cfga_err(errstring, errno, ERR_OP_FAILED, 0);
3510Sstevel@tonic-gate 			ret = SCFGA_LIB_ERR;
3520Sstevel@tonic-gate 			goto err;
3530Sstevel@tonic-gate 		}
3540Sstevel@tonic-gate 		(void) strcpy(dyncomp, DYN_TO_DYNCOMP(dyn));
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 		/* Remove the dynamic component from the base */
3570Sstevel@tonic-gate 		*dyn = '\0';
358*10696SDavid.Hollister@Sun.COM 	} else {
359*10696SDavid.Hollister@Sun.COM 		apidp->dyntype = NODYNCOMP;
360*10696SDavid.Hollister@Sun.COM 	}
361*10696SDavid.Hollister@Sun.COM 
362*10696SDavid.Hollister@Sun.COM 	/* get dyn comp type */
363*10696SDavid.Hollister@Sun.COM 	if (dyncomp != NULL) {
364*10696SDavid.Hollister@Sun.COM 		if (strstr(dyncomp, PATH_APID_DYN_SEP) != NULL) {
365*10696SDavid.Hollister@Sun.COM 			apidp->dyntype = PATH_APID;
366*10696SDavid.Hollister@Sun.COM 		} else {
367*10696SDavid.Hollister@Sun.COM 			apidp->dyntype = DEV_APID;
368*10696SDavid.Hollister@Sun.COM 		}
3690Sstevel@tonic-gate 	}
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	/* Create the path */
372*10696SDavid.Hollister@Sun.COM 	if ((ret = apid_to_path(hba_phys, dyncomp, &path,
373*10696SDavid.Hollister@Sun.COM 	    &l_errno)) != SCFGA_OK) {
3740Sstevel@tonic-gate 		cfga_err(errstring, l_errno, ERR_OP_FAILED, 0);
3750Sstevel@tonic-gate 		goto err;
3760Sstevel@tonic-gate 	}
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	assert(path != NULL);
3790Sstevel@tonic-gate 	assert(hba_phys != NULL);
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	apidp->hba_phys = hba_phys;
3820Sstevel@tonic-gate 	apidp->dyncomp = dyncomp;
3830Sstevel@tonic-gate 	apidp->path = path;
3840Sstevel@tonic-gate 	apidp->flags = 0;
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 	return (SCFGA_OK);
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate err:
3890Sstevel@tonic-gate 	S_FREE(hba_phys);
3900Sstevel@tonic-gate 	S_FREE(dyncomp);
3910Sstevel@tonic-gate 	S_FREE(path);
3920Sstevel@tonic-gate 	return (ret);
3930Sstevel@tonic-gate }
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate void
apidt_free(apid_t * apidp)3960Sstevel@tonic-gate apidt_free(apid_t *apidp)
3970Sstevel@tonic-gate {
3980Sstevel@tonic-gate 	if (apidp == NULL)
3990Sstevel@tonic-gate 		return;
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	S_FREE(apidp->hba_phys);
4020Sstevel@tonic-gate 	S_FREE(apidp->dyncomp);
4030Sstevel@tonic-gate 	S_FREE(apidp->path);
4040Sstevel@tonic-gate }
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate scfga_ret_t
walk_tree(const char * physpath,void * arg,uint_t init_flags,walkarg_t * up,scfga_cmd_t cmd,int * l_errnop)4070Sstevel@tonic-gate walk_tree(
4080Sstevel@tonic-gate 	const char	*physpath,
4090Sstevel@tonic-gate 	void		*arg,
4100Sstevel@tonic-gate 	uint_t		init_flags,
4110Sstevel@tonic-gate 	walkarg_t	*up,
4120Sstevel@tonic-gate 	scfga_cmd_t	cmd,
4130Sstevel@tonic-gate 	int		*l_errnop)
4140Sstevel@tonic-gate {
4150Sstevel@tonic-gate 	int rv;
4160Sstevel@tonic-gate 	di_node_t root, walk_root;
4170Sstevel@tonic-gate 	char *root_path, *cp = NULL, *init_path;
4180Sstevel@tonic-gate 	size_t len;
4190Sstevel@tonic-gate 	scfga_ret_t ret;
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	*l_errnop = 0;
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	if ((root_path = strdup(physpath)) == NULL) {
4240Sstevel@tonic-gate 		*l_errnop = errno;
4250Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
4260Sstevel@tonic-gate 	}
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	/* Fix up path for di_init() */
4290Sstevel@tonic-gate 	len = strlen(DEVICES_DIR);
4300Sstevel@tonic-gate 	if (strncmp(root_path, DEVICES_DIR SLASH,
4310Sstevel@tonic-gate 	    len + strlen(SLASH)) == 0) {
4320Sstevel@tonic-gate 		cp = root_path + len;
4330Sstevel@tonic-gate 		(void) memmove(root_path, cp, strlen(cp) + 1);
4340Sstevel@tonic-gate 	} else if (*root_path != '/') {
4350Sstevel@tonic-gate 		*l_errnop = 0;
4360Sstevel@tonic-gate 		ret = SCFGA_ERR;
4370Sstevel@tonic-gate 		goto out;
4380Sstevel@tonic-gate 	}
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	/* Remove dynamic component if any */
4410Sstevel@tonic-gate 	if ((cp = GET_DYN(root_path)) != NULL) {
4420Sstevel@tonic-gate 		*cp = '\0';
4430Sstevel@tonic-gate 	}
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	/* Remove minor name if any */
4460Sstevel@tonic-gate 	if ((cp = strrchr(root_path, ':')) != NULL) {
4470Sstevel@tonic-gate 		*cp = '\0';
4480Sstevel@tonic-gate 	}
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	/*
4510Sstevel@tonic-gate 	 * Cached snapshots are always rooted at "/"
4520Sstevel@tonic-gate 	 */
4530Sstevel@tonic-gate 	init_path = root_path;
4540Sstevel@tonic-gate 	if ((init_flags & DINFOCACHE) == DINFOCACHE) {
4550Sstevel@tonic-gate 		init_path = "/";
4560Sstevel@tonic-gate 	}
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	/* Get a snapshot */
4590Sstevel@tonic-gate 	if ((root = di_init(init_path, init_flags)) == DI_NODE_NIL) {
4600Sstevel@tonic-gate 		*l_errnop = errno;
4610Sstevel@tonic-gate 		ret = SCFGA_LIB_ERR;
4620Sstevel@tonic-gate 		goto out;
4630Sstevel@tonic-gate 	}
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	/*
4660Sstevel@tonic-gate 	 * Lookup the subtree of interest
4670Sstevel@tonic-gate 	 */
4680Sstevel@tonic-gate 	walk_root = root;
4690Sstevel@tonic-gate 	if ((init_flags & DINFOCACHE) == DINFOCACHE) {
4700Sstevel@tonic-gate 		walk_root = di_lookup_node(root, root_path);
4710Sstevel@tonic-gate 	}
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	if (walk_root == DI_NODE_NIL) {
4740Sstevel@tonic-gate 		*l_errnop = errno;
4750Sstevel@tonic-gate 		di_fini(root);
4760Sstevel@tonic-gate 		ret = SCFGA_LIB_ERR;
4770Sstevel@tonic-gate 		goto out;
4780Sstevel@tonic-gate 	}
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	/* Walk the tree */
4810Sstevel@tonic-gate 	errno = 0;
4820Sstevel@tonic-gate 	if (cmd == SCFGA_WALK_NODE) {
4830Sstevel@tonic-gate 		rv = di_walk_node(walk_root, up->node_args.flags, arg,
4840Sstevel@tonic-gate 		    up->node_args.fcn);
485*10696SDavid.Hollister@Sun.COM 	} else if (cmd == SCFGA_WALK_PATH) {
486*10696SDavid.Hollister@Sun.COM 		rv = stat_path_info(walk_root, arg, l_errnop);
4870Sstevel@tonic-gate 	} else {
4880Sstevel@tonic-gate 		assert(cmd == SCFGA_WALK_MINOR);
4890Sstevel@tonic-gate 		rv = di_walk_minor(walk_root, up->minor_args.nodetype, 0, arg,
4900Sstevel@tonic-gate 		    up->minor_args.fcn);
4910Sstevel@tonic-gate 	}
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	if (rv != 0) {
4940Sstevel@tonic-gate 		*l_errnop = errno;
4950Sstevel@tonic-gate 		ret = SCFGA_LIB_ERR;
4960Sstevel@tonic-gate 	} else {
4970Sstevel@tonic-gate 		*l_errnop = 0;
4980Sstevel@tonic-gate 		ret = SCFGA_OK;
4990Sstevel@tonic-gate 	}
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	di_fini(root);
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	/*FALLTHRU*/
5040Sstevel@tonic-gate out:
5050Sstevel@tonic-gate 	S_FREE(root_path);
5060Sstevel@tonic-gate 	return (ret);
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate scfga_ret_t
invoke_cmd(const char * func,apid_t * apidtp,prompt_t * prp,cfga_flags_t flags,char ** errstring)5100Sstevel@tonic-gate invoke_cmd(
5110Sstevel@tonic-gate 	const char *func,
5120Sstevel@tonic-gate 	apid_t *apidtp,
5130Sstevel@tonic-gate 	prompt_t *prp,
5140Sstevel@tonic-gate 	cfga_flags_t flags,
5150Sstevel@tonic-gate 	char **errstring)
5160Sstevel@tonic-gate {
5170Sstevel@tonic-gate 	int i;
5181957Sdnielsen 	int len;
5191957Sdnielsen 
5201957Sdnielsen 
5211957Sdnielsen 	/*
5221957Sdnielsen 	 * Determine if the func has an equal sign; only compare up to
5231957Sdnielsen 	 * the equals
5241957Sdnielsen 	 */
525*10696SDavid.Hollister@Sun.COM 	for (len = 0; func[len] != 0 && func[len] != '='; len++) {
526*10696SDavid.Hollister@Sun.COM 	};
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	for (i = 0; i < N_HW_CMDS; i++) {
5291957Sdnielsen 		const char *s = GET_MSG_STR(hw_cmds[i].str_id);
5301957Sdnielsen 		if (strncmp(func, s, len) == 0 && s[len] == 0) {
5311957Sdnielsen 			return (hw_cmds[i].fcn(func, hw_cmds[i].cmd, apidtp,
5320Sstevel@tonic-gate 			    prp, flags, errstring));
5330Sstevel@tonic-gate 		}
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	cfga_err(errstring, 0, ERRARG_HWCMD_INVAL, func, 0);
5370Sstevel@tonic-gate 	return (SCFGA_ERR);
5380Sstevel@tonic-gate }
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate int
msg_idx(msgid_t msgid)5410Sstevel@tonic-gate msg_idx(msgid_t msgid)
5420Sstevel@tonic-gate {
5430Sstevel@tonic-gate 	int idx = 0;
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	/* The string table index and the error id may or may not be same */
5460Sstevel@tonic-gate 	if (msgid >= 0 && msgid <= N_STRS - 1 &&
5470Sstevel@tonic-gate 	    str_tbl[msgid].msgid == msgid) {
5480Sstevel@tonic-gate 		idx = msgid;
5490Sstevel@tonic-gate 	} else {
5500Sstevel@tonic-gate 		for (idx = 0; idx < N_STRS; idx++) {
5510Sstevel@tonic-gate 			if (str_tbl[idx].msgid == msgid)
5520Sstevel@tonic-gate 				break;
5530Sstevel@tonic-gate 		}
5540Sstevel@tonic-gate 		if (idx >= N_STRS) {
5550Sstevel@tonic-gate 			idx =  UNKNOWN_ERR_IDX;
5560Sstevel@tonic-gate 		}
5570Sstevel@tonic-gate 	}
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	return (idx);
5600Sstevel@tonic-gate }
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate /*
5630Sstevel@tonic-gate  * cfga_err() accepts a variable number of message IDs and constructs
5640Sstevel@tonic-gate  * a corresponding error string which is returned via the errstring argument.
5650Sstevel@tonic-gate  * cfga_err() calls dgettext() to internationalize proper messages.
5660Sstevel@tonic-gate  * May be called with a NULL argument.
5670Sstevel@tonic-gate  */
5680Sstevel@tonic-gate void
cfga_err(char ** errstring,int l_errno,...)5690Sstevel@tonic-gate cfga_err(char **errstring, int l_errno, ...)
5700Sstevel@tonic-gate {
5710Sstevel@tonic-gate 	va_list ap;
5720Sstevel@tonic-gate 	int append_newline = 0;
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	if (errstring == NULL || *errstring != NULL) {
5750Sstevel@tonic-gate 		return;
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	/*
5790Sstevel@tonic-gate 	 * Don't append a newline, the application (for example cfgadm)
5800Sstevel@tonic-gate 	 * should do that.
5810Sstevel@tonic-gate 	 */
5820Sstevel@tonic-gate 	append_newline = 0;
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	va_start(ap, l_errno);
5850Sstevel@tonic-gate 	msg_common(errstring, append_newline, l_errno, ap);
5860Sstevel@tonic-gate 	va_end(ap);
5870Sstevel@tonic-gate }
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate /*
5900Sstevel@tonic-gate  * This routine accepts a variable number of message IDs and constructs
5910Sstevel@tonic-gate  * a corresponding message string which is printed via the message print
5920Sstevel@tonic-gate  * routine argument.
5930Sstevel@tonic-gate  */
5940Sstevel@tonic-gate void
cfga_msg(struct cfga_msg * msgp,...)5950Sstevel@tonic-gate cfga_msg(struct cfga_msg *msgp, ...)
5960Sstevel@tonic-gate {
5970Sstevel@tonic-gate 	char *p = NULL;
5980Sstevel@tonic-gate 	int append_newline = 0, l_errno = 0;
5990Sstevel@tonic-gate 	va_list ap;
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	if (msgp == NULL || msgp->message_routine == NULL) {
6020Sstevel@tonic-gate 		return;
6030Sstevel@tonic-gate 	}
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	/* Append a newline after message */
6060Sstevel@tonic-gate 	append_newline = 1;
6070Sstevel@tonic-gate 	l_errno = 0;
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	va_start(ap, msgp);
6100Sstevel@tonic-gate 	msg_common(&p, append_newline, l_errno, ap);
6110Sstevel@tonic-gate 	va_end(ap);
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	(void) (*msgp->message_routine)(msgp->appdata_ptr, p);
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	S_FREE(p);
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate 
6181957Sdnielsen 
6191957Sdnielsen /*
6201957Sdnielsen  * This routine prints the value of an led for a disk.
6211957Sdnielsen  */
6221957Sdnielsen void
cfga_led_msg(struct cfga_msg * msgp,apid_t * apidp,led_strid_t led,led_modeid_t mode)6231957Sdnielsen cfga_led_msg(struct cfga_msg *msgp, apid_t *apidp, led_strid_t led,
6241957Sdnielsen     led_modeid_t mode)
6251957Sdnielsen {
6261957Sdnielsen 	char led_msg[MAX_INPUT];	/* 512 bytes */
6271957Sdnielsen 
6281957Sdnielsen 	if ((msgp == NULL) || (msgp->message_routine == NULL)) {
6291957Sdnielsen 		return;
6301957Sdnielsen 	}
6311957Sdnielsen 	if ((apidp == NULL) || (apidp->dyncomp == NULL)) {
6321957Sdnielsen 		return;
6331957Sdnielsen 	}
634*10696SDavid.Hollister@Sun.COM 	(void) snprintf(led_msg, sizeof (led_msg), "%-23s\t%s=%s\n",
635*10696SDavid.Hollister@Sun.COM 	    basename(apidp->dyncomp),
636*10696SDavid.Hollister@Sun.COM 	    dgettext(TEXT_DOMAIN, led_strs[led]),
637*10696SDavid.Hollister@Sun.COM 	    dgettext(TEXT_DOMAIN, led_mode_strs[mode]));
6381957Sdnielsen 	(void) (*msgp->message_routine)(msgp->appdata_ptr, led_msg);
6391957Sdnielsen }
6401957Sdnielsen 
6410Sstevel@tonic-gate /*
6420Sstevel@tonic-gate  * Get internationalized string corresponding to message id
6430Sstevel@tonic-gate  * Caller must free the memory allocated.
6440Sstevel@tonic-gate  */
6450Sstevel@tonic-gate char *
cfga_str(int append_newline,...)6460Sstevel@tonic-gate cfga_str(int append_newline, ...)
6470Sstevel@tonic-gate {
6480Sstevel@tonic-gate 	char *p = NULL;
6490Sstevel@tonic-gate 	int l_errno = 0;
6500Sstevel@tonic-gate 	va_list ap;
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 	va_start(ap, append_newline);
6530Sstevel@tonic-gate 	msg_common(&p, append_newline, l_errno, ap);
6540Sstevel@tonic-gate 	va_end(ap);
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	return (p);
6570Sstevel@tonic-gate }
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate static void
msg_common(char ** msgpp,int append_newline,int l_errno,va_list ap)6600Sstevel@tonic-gate msg_common(char **msgpp, int append_newline, int l_errno, va_list ap)
6610Sstevel@tonic-gate {
6620Sstevel@tonic-gate 	int a = 0;
6630Sstevel@tonic-gate 	size_t len = 0;
6640Sstevel@tonic-gate 	int i = 0, n = 0;
6650Sstevel@tonic-gate 	char *s = NULL, *t = NULL;
6660Sstevel@tonic-gate 	strlist_t dummy;
6670Sstevel@tonic-gate 	strlist_t *savep = NULL, *sp = NULL, *tailp = NULL;
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	if (*msgpp != NULL) {
6700Sstevel@tonic-gate 		return;
6710Sstevel@tonic-gate 	}
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	dummy.next = NULL;
6740Sstevel@tonic-gate 	tailp = &dummy;
6750Sstevel@tonic-gate 	for (len = 0; (a = va_arg(ap, int)) != 0; ) {
6760Sstevel@tonic-gate 		n = GET_MSG_NARGS(a); /* 0 implies no additional args */
6770Sstevel@tonic-gate 		for (i = 0; i <= n; i++) {
6780Sstevel@tonic-gate 			sp = calloc(1, sizeof (*sp));
6790Sstevel@tonic-gate 			if (sp == NULL) {
6800Sstevel@tonic-gate 				goto out;
6810Sstevel@tonic-gate 			}
6820Sstevel@tonic-gate 			if (i == 0 && GET_MSG_INTL(a)) {
6830Sstevel@tonic-gate 				sp->str = dgettext(TEXT_DOMAIN, GET_MSG_STR(a));
6840Sstevel@tonic-gate 			} else if (i == 0) {
6850Sstevel@tonic-gate 				sp->str = GET_MSG_STR(a);
6860Sstevel@tonic-gate 			} else {
6870Sstevel@tonic-gate 				sp->str = va_arg(ap, char *);
6880Sstevel@tonic-gate 			}
6890Sstevel@tonic-gate 			len += (strlen(sp->str));
6900Sstevel@tonic-gate 			sp->next = NULL;
6910Sstevel@tonic-gate 			tailp->next = sp;
6920Sstevel@tonic-gate 			tailp = sp;
6930Sstevel@tonic-gate 		}
6940Sstevel@tonic-gate 	}
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	len += 1;	/* terminating NULL */
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	s = t = NULL;
6990Sstevel@tonic-gate 	if (l_errno) {
7000Sstevel@tonic-gate 		s = dgettext(TEXT_DOMAIN, ": ");
7010Sstevel@tonic-gate 		t = S_STR(strerror(l_errno));
7020Sstevel@tonic-gate 		if (s != NULL && t != NULL) {
7030Sstevel@tonic-gate 			len += strlen(s) + strlen(t);
7040Sstevel@tonic-gate 		}
7050Sstevel@tonic-gate 	}
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 	if (append_newline) {
7080Sstevel@tonic-gate 		len++;
7090Sstevel@tonic-gate 	}
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	if ((*msgpp = calloc(1, len)) == NULL) {
7120Sstevel@tonic-gate 		goto out;
7130Sstevel@tonic-gate 	}
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	**msgpp = '\0';
7160Sstevel@tonic-gate 	for (sp = dummy.next; sp != NULL; sp = sp->next) {
7170Sstevel@tonic-gate 		(void) strcat(*msgpp, sp->str);
7180Sstevel@tonic-gate 	}
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	if (s != NULL && t != NULL) {
7210Sstevel@tonic-gate 		(void) strcat(*msgpp, s);
7220Sstevel@tonic-gate 		(void) strcat(*msgpp, t);
7230Sstevel@tonic-gate 	}
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	if (append_newline) {
7260Sstevel@tonic-gate 		(void) strcat(*msgpp, dgettext(TEXT_DOMAIN, "\n"));
7270Sstevel@tonic-gate 	}
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	/* FALLTHROUGH */
7300Sstevel@tonic-gate out:
7310Sstevel@tonic-gate 	sp = dummy.next;
7320Sstevel@tonic-gate 	while (sp != NULL) {
7330Sstevel@tonic-gate 		savep = sp->next;
7340Sstevel@tonic-gate 		S_FREE(sp);
7350Sstevel@tonic-gate 		sp = savep;
7360Sstevel@tonic-gate 	}
7370Sstevel@tonic-gate }
7380Sstevel@tonic-gate 
739*10696SDavid.Hollister@Sun.COM /*
740*10696SDavid.Hollister@Sun.COM  * Check to see if the given pi_node is the last path to the client device.
741*10696SDavid.Hollister@Sun.COM  *
742*10696SDavid.Hollister@Sun.COM  * Return:
743*10696SDavid.Hollister@Sun.COM  *	0: if there is another path avialable.
744*10696SDavid.Hollister@Sun.COM  *	-1: if no other paths available.
745*10696SDavid.Hollister@Sun.COM  */
746*10696SDavid.Hollister@Sun.COM static int
check_available_path(di_node_t client_node,di_path_t pi_node)747*10696SDavid.Hollister@Sun.COM check_available_path(
748*10696SDavid.Hollister@Sun.COM 	di_node_t client_node,
749*10696SDavid.Hollister@Sun.COM 	di_path_t pi_node)
750*10696SDavid.Hollister@Sun.COM {
751*10696SDavid.Hollister@Sun.COM 	di_path_state_t pi_state;
752*10696SDavid.Hollister@Sun.COM 	di_path_t   next_pi = DI_PATH_NIL;
753*10696SDavid.Hollister@Sun.COM 
754*10696SDavid.Hollister@Sun.COM 	if (((pi_state = di_path_state(pi_node)) != DI_PATH_STATE_ONLINE) &&
755*10696SDavid.Hollister@Sun.COM 	    (pi_state != DI_PATH_STATE_STANDBY)) {
756*10696SDavid.Hollister@Sun.COM 		/* it is not last available path */
757*10696SDavid.Hollister@Sun.COM 		return (0);
758*10696SDavid.Hollister@Sun.COM 	}
759*10696SDavid.Hollister@Sun.COM 
760*10696SDavid.Hollister@Sun.COM 	while (next_pi = di_path_client_next_path(client_node, next_pi)) {
761*10696SDavid.Hollister@Sun.COM 		/* if anohter pi node is avaialble, return 0 */
762*10696SDavid.Hollister@Sun.COM 		if ((next_pi != pi_node) &&
763*10696SDavid.Hollister@Sun.COM 		    (((pi_state = di_path_state(next_pi)) ==
764*10696SDavid.Hollister@Sun.COM 		    DI_PATH_STATE_ONLINE) ||
765*10696SDavid.Hollister@Sun.COM 		    pi_state == DI_PATH_STATE_STANDBY)) {
766*10696SDavid.Hollister@Sun.COM 			return (0);
767*10696SDavid.Hollister@Sun.COM 		}
768*10696SDavid.Hollister@Sun.COM 	}
769*10696SDavid.Hollister@Sun.COM 	return (-1);
770*10696SDavid.Hollister@Sun.COM }
771*10696SDavid.Hollister@Sun.COM 
772*10696SDavid.Hollister@Sun.COM scfga_ret_t
path_apid_state_change(apid_t * apidp,scfga_cmd_t cmd,cfga_flags_t flags,char ** errstring,int * l_errnop,msgid_t errid)773*10696SDavid.Hollister@Sun.COM path_apid_state_change(
774*10696SDavid.Hollister@Sun.COM 	apid_t		*apidp,
775*10696SDavid.Hollister@Sun.COM 	scfga_cmd_t	cmd,
776*10696SDavid.Hollister@Sun.COM 	cfga_flags_t	flags,
777*10696SDavid.Hollister@Sun.COM 	char		**errstring,
778*10696SDavid.Hollister@Sun.COM 	int		*l_errnop,
779*10696SDavid.Hollister@Sun.COM 	msgid_t		errid)
780*10696SDavid.Hollister@Sun.COM {
781*10696SDavid.Hollister@Sun.COM 	di_node_t   root, walk_root, client_node;
782*10696SDavid.Hollister@Sun.COM 	di_path_t   pi_node = DI_PATH_NIL;
783*10696SDavid.Hollister@Sun.COM 	char	    *root_path, *cp, *client_path, devpath[MAXPATHLEN];
784*10696SDavid.Hollister@Sun.COM 	int	    len, found = 0;
785*10696SDavid.Hollister@Sun.COM 	scfga_ret_t ret;
786*10696SDavid.Hollister@Sun.COM 	char *dev_list[2] = {NULL};
787*10696SDavid.Hollister@Sun.COM 
788*10696SDavid.Hollister@Sun.COM 	*l_errnop = 0;
789*10696SDavid.Hollister@Sun.COM 
790*10696SDavid.Hollister@Sun.COM 	/* Make sure apid is pathinfo associated apid. */
791*10696SDavid.Hollister@Sun.COM 	if ((apidp->dyntype != PATH_APID) || (apidp->dyncomp == NULL)) {
792*10696SDavid.Hollister@Sun.COM 		return (SCFGA_LIB_ERR);
793*10696SDavid.Hollister@Sun.COM 	}
794*10696SDavid.Hollister@Sun.COM 
795*10696SDavid.Hollister@Sun.COM 	if ((cmd != SCFGA_DEV_CONFIGURE) && (cmd != SCFGA_DEV_UNCONFIGURE)) {
796*10696SDavid.Hollister@Sun.COM 		return (SCFGA_LIB_ERR);
797*10696SDavid.Hollister@Sun.COM 	}
798*10696SDavid.Hollister@Sun.COM 
799*10696SDavid.Hollister@Sun.COM 	if ((root_path = strdup(apidp->hba_phys)) == NULL) {
800*10696SDavid.Hollister@Sun.COM 		*l_errnop = errno;
801*10696SDavid.Hollister@Sun.COM 		return (SCFGA_LIB_ERR);
802*10696SDavid.Hollister@Sun.COM 	}
803*10696SDavid.Hollister@Sun.COM 
804*10696SDavid.Hollister@Sun.COM 	/* Fix up path for di_init() */
805*10696SDavid.Hollister@Sun.COM 	len = strlen(DEVICES_DIR);
806*10696SDavid.Hollister@Sun.COM 	if (strncmp(root_path, DEVICES_DIR SLASH,
807*10696SDavid.Hollister@Sun.COM 	    len + strlen(SLASH)) == 0) {
808*10696SDavid.Hollister@Sun.COM 		cp = root_path + len;
809*10696SDavid.Hollister@Sun.COM 		(void) memmove(root_path, cp, strlen(cp) + 1);
810*10696SDavid.Hollister@Sun.COM 	} else if (*root_path != '/') {
811*10696SDavid.Hollister@Sun.COM 		*l_errnop = 0;
812*10696SDavid.Hollister@Sun.COM 		S_FREE(root_path);
813*10696SDavid.Hollister@Sun.COM 		return (SCFGA_ERR);
814*10696SDavid.Hollister@Sun.COM 	}
815*10696SDavid.Hollister@Sun.COM 
816*10696SDavid.Hollister@Sun.COM 	/* Remove dynamic component if any */
817*10696SDavid.Hollister@Sun.COM 	if ((cp = GET_DYN(root_path)) != NULL) {
818*10696SDavid.Hollister@Sun.COM 		*cp = '\0';
819*10696SDavid.Hollister@Sun.COM 	}
820*10696SDavid.Hollister@Sun.COM 
821*10696SDavid.Hollister@Sun.COM 	/* Remove minor name if any */
822*10696SDavid.Hollister@Sun.COM 	if ((cp = strrchr(root_path, ':')) != NULL) {
823*10696SDavid.Hollister@Sun.COM 		*cp = '\0';
824*10696SDavid.Hollister@Sun.COM 	}
825*10696SDavid.Hollister@Sun.COM 
826*10696SDavid.Hollister@Sun.COM 	/*
827*10696SDavid.Hollister@Sun.COM 	 * Cached snapshots are always rooted at "/"
828*10696SDavid.Hollister@Sun.COM 	 */
829*10696SDavid.Hollister@Sun.COM 
830*10696SDavid.Hollister@Sun.COM 	/* Get a snapshot */
831*10696SDavid.Hollister@Sun.COM 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
832*10696SDavid.Hollister@Sun.COM 		*l_errnop = errno;
833*10696SDavid.Hollister@Sun.COM 		S_FREE(root_path);
834*10696SDavid.Hollister@Sun.COM 		return (SCFGA_ERR);
835*10696SDavid.Hollister@Sun.COM 	}
836*10696SDavid.Hollister@Sun.COM 
837*10696SDavid.Hollister@Sun.COM 	/*
838*10696SDavid.Hollister@Sun.COM 	 * Lookup the subtree of interest
839*10696SDavid.Hollister@Sun.COM 	 */
840*10696SDavid.Hollister@Sun.COM 	walk_root = di_lookup_node(root, root_path);
841*10696SDavid.Hollister@Sun.COM 
842*10696SDavid.Hollister@Sun.COM 	if (walk_root == DI_NODE_NIL) {
843*10696SDavid.Hollister@Sun.COM 		*l_errnop = errno;
844*10696SDavid.Hollister@Sun.COM 		di_fini(root);
845*10696SDavid.Hollister@Sun.COM 		S_FREE(root_path);
846*10696SDavid.Hollister@Sun.COM 		return (SCFGA_LIB_ERR);
847*10696SDavid.Hollister@Sun.COM 	}
848*10696SDavid.Hollister@Sun.COM 
849*10696SDavid.Hollister@Sun.COM 
850*10696SDavid.Hollister@Sun.COM 	if ((pi_node = di_path_next_client(walk_root, pi_node)) ==
851*10696SDavid.Hollister@Sun.COM 	    DI_PATH_NIL) {
852*10696SDavid.Hollister@Sun.COM 		/* the path apid not found */
853*10696SDavid.Hollister@Sun.COM 		di_fini(root);
854*10696SDavid.Hollister@Sun.COM 		S_FREE(root_path);
855*10696SDavid.Hollister@Sun.COM 		return (SCFGA_APID_NOEXIST);
856*10696SDavid.Hollister@Sun.COM 	}
857*10696SDavid.Hollister@Sun.COM 
858*10696SDavid.Hollister@Sun.COM 	do {
859*10696SDavid.Hollister@Sun.COM 		/* check the length first. */
860*10696SDavid.Hollister@Sun.COM 		if (strlen(di_path_bus_addr(pi_node)) !=
861*10696SDavid.Hollister@Sun.COM 		    strlen(apidp->dyncomp)) {
862*10696SDavid.Hollister@Sun.COM 			continue;
863*10696SDavid.Hollister@Sun.COM 		}
864*10696SDavid.Hollister@Sun.COM 
865*10696SDavid.Hollister@Sun.COM 		/* compare bus addr. */
866*10696SDavid.Hollister@Sun.COM 		if (strcmp(di_path_bus_addr(pi_node), apidp->dyncomp) == 0) {
867*10696SDavid.Hollister@Sun.COM 			found = 1;
868*10696SDavid.Hollister@Sun.COM 			break;
869*10696SDavid.Hollister@Sun.COM 		}
870*10696SDavid.Hollister@Sun.COM 		pi_node = di_path_next_client(root, pi_node);
871*10696SDavid.Hollister@Sun.COM 	} while (pi_node != DI_PATH_NIL);
872*10696SDavid.Hollister@Sun.COM 
873*10696SDavid.Hollister@Sun.COM 	if (!found) {
874*10696SDavid.Hollister@Sun.COM 		di_fini(root);
875*10696SDavid.Hollister@Sun.COM 		S_FREE(root_path);
876*10696SDavid.Hollister@Sun.COM 		return (SCFGA_APID_NOEXIST);
877*10696SDavid.Hollister@Sun.COM 	}
878*10696SDavid.Hollister@Sun.COM 
879*10696SDavid.Hollister@Sun.COM 	/* Get client node path. */
880*10696SDavid.Hollister@Sun.COM 	client_node = di_path_client_node(pi_node);
881*10696SDavid.Hollister@Sun.COM 	if (client_node == DI_NODE_NIL) {
882*10696SDavid.Hollister@Sun.COM 		di_fini(root);
883*10696SDavid.Hollister@Sun.COM 		S_FREE(root_path);
884*10696SDavid.Hollister@Sun.COM 		return (SCFGA_ERR);
885*10696SDavid.Hollister@Sun.COM 	} else {
886*10696SDavid.Hollister@Sun.COM 		client_path = di_devfs_path(client_node);
887*10696SDavid.Hollister@Sun.COM 		if (client_path == NULL) {
888*10696SDavid.Hollister@Sun.COM 			di_fini(root);
889*10696SDavid.Hollister@Sun.COM 			S_FREE(root_path);
890*10696SDavid.Hollister@Sun.COM 			return (SCFGA_ERR);
891*10696SDavid.Hollister@Sun.COM 		}
892*10696SDavid.Hollister@Sun.COM 
893*10696SDavid.Hollister@Sun.COM 		if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
894*10696SDavid.Hollister@Sun.COM 			if (cmd == SCFGA_DEV_UNCONFIGURE) {
895*10696SDavid.Hollister@Sun.COM 				if (check_available_path(client_node,
896*10696SDavid.Hollister@Sun.COM 				    pi_node) != 0) {
897*10696SDavid.Hollister@Sun.COM 					/*
898*10696SDavid.Hollister@Sun.COM 					 * last path. check if unconfiguring
899*10696SDavid.Hollister@Sun.COM 					 * is okay.
900*10696SDavid.Hollister@Sun.COM 					 */
901*10696SDavid.Hollister@Sun.COM 					(void) snprintf(devpath,
902*10696SDavid.Hollister@Sun.COM 					    strlen(DEVICES_DIR) +
903*10696SDavid.Hollister@Sun.COM 					    strlen(client_path) + 1, "%s%s",
904*10696SDavid.Hollister@Sun.COM 					    DEVICES_DIR, client_path);
905*10696SDavid.Hollister@Sun.COM 					dev_list[0] = devpath;
906*10696SDavid.Hollister@Sun.COM 					flags |= FLAG_CLIENT_DEV;
907*10696SDavid.Hollister@Sun.COM 					ret = scsi_rcm_offline(dev_list,
908*10696SDavid.Hollister@Sun.COM 					    errstring, flags);
909*10696SDavid.Hollister@Sun.COM 					if (ret != SCFGA_OK) {
910*10696SDavid.Hollister@Sun.COM 						di_fini(root);
911*10696SDavid.Hollister@Sun.COM 						di_devfs_path_free(client_path);
912*10696SDavid.Hollister@Sun.COM 						S_FREE(root_path);
913*10696SDavid.Hollister@Sun.COM 						return (ret);
914*10696SDavid.Hollister@Sun.COM 					}
915*10696SDavid.Hollister@Sun.COM 				}
916*10696SDavid.Hollister@Sun.COM 			}
917*10696SDavid.Hollister@Sun.COM 		}
918*10696SDavid.Hollister@Sun.COM 	}
919*10696SDavid.Hollister@Sun.COM 
920*10696SDavid.Hollister@Sun.COM 	ret = devctl_cmd(apidp->path, cmd, NULL, l_errnop);
921*10696SDavid.Hollister@Sun.COM 	if (ret != SCFGA_OK) {
922*10696SDavid.Hollister@Sun.COM 		cfga_err(errstring, *l_errnop, errid, 0);
923*10696SDavid.Hollister@Sun.COM 
924*10696SDavid.Hollister@Sun.COM 		/*
925*10696SDavid.Hollister@Sun.COM 		 * If an unconfigure fails, cancel the RCM offline.
926*10696SDavid.Hollister@Sun.COM 		 * Discard any RCM failures so that the devctl
927*10696SDavid.Hollister@Sun.COM 		 * failure will still be reported.
928*10696SDavid.Hollister@Sun.COM 		 */
929*10696SDavid.Hollister@Sun.COM 		if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
930*10696SDavid.Hollister@Sun.COM 			if (cmd == SCFGA_DEV_UNCONFIGURE)
931*10696SDavid.Hollister@Sun.COM 				(void) scsi_rcm_online(dev_list,
932*10696SDavid.Hollister@Sun.COM 				    errstring, flags);
933*10696SDavid.Hollister@Sun.COM 		}
934*10696SDavid.Hollister@Sun.COM 	}
935*10696SDavid.Hollister@Sun.COM 
936*10696SDavid.Hollister@Sun.COM 	di_devfs_path_free(client_path);
937*10696SDavid.Hollister@Sun.COM 	di_fini(root);
938*10696SDavid.Hollister@Sun.COM 	S_FREE(root_path);
939*10696SDavid.Hollister@Sun.COM 
940*10696SDavid.Hollister@Sun.COM 	return (ret);
941*10696SDavid.Hollister@Sun.COM }
942*10696SDavid.Hollister@Sun.COM 
943*10696SDavid.Hollister@Sun.COM 
9440Sstevel@tonic-gate scfga_ret_t
devctl_cmd(const char * physpath,scfga_cmd_t cmd,uint_t * statep,int * l_errnop)9450Sstevel@tonic-gate devctl_cmd(
9460Sstevel@tonic-gate 	const char	*physpath,
9470Sstevel@tonic-gate 	scfga_cmd_t	cmd,
9480Sstevel@tonic-gate 	uint_t		*statep,
9490Sstevel@tonic-gate 	int		*l_errnop)
9500Sstevel@tonic-gate {
9510Sstevel@tonic-gate 	int rv = -1, i, type;
9520Sstevel@tonic-gate 	devctl_hdl_t hdl = NULL;
9530Sstevel@tonic-gate 	char *cp = NULL, *path = NULL;
9540Sstevel@tonic-gate 	int (*func)(const devctl_hdl_t);
9550Sstevel@tonic-gate 	int (*state_func)(const devctl_hdl_t, uint_t *);
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 	*l_errnop = 0;
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	if (statep != NULL) *statep = 0;
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 	func = NULL;
9620Sstevel@tonic-gate 	state_func = NULL;
9630Sstevel@tonic-gate 	type = 0;
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	for (i = 0; i < N_GET_STATE_CMDS; i++) {
9660Sstevel@tonic-gate 		if (get_state_cmds[i].cmd == cmd) {
9670Sstevel@tonic-gate 			state_func = get_state_cmds[i].state_fcn;
9680Sstevel@tonic-gate 			type = get_state_cmds[i].type;
9690Sstevel@tonic-gate 			assert(statep != NULL);
9700Sstevel@tonic-gate 			break;
9710Sstevel@tonic-gate 		}
9720Sstevel@tonic-gate 	}
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate 	if (state_func == NULL) {
9750Sstevel@tonic-gate 		for (i = 0; i < N_SET_STATE_CMDS; i++) {
9760Sstevel@tonic-gate 			if (set_state_cmds[i].cmd == cmd) {
9770Sstevel@tonic-gate 				func = set_state_cmds[i].fcn;
9780Sstevel@tonic-gate 				type = set_state_cmds[i].type;
9790Sstevel@tonic-gate 				assert(statep == NULL);
9800Sstevel@tonic-gate 				break;
9810Sstevel@tonic-gate 			}
9820Sstevel@tonic-gate 		}
9830Sstevel@tonic-gate 	}
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 	assert(type == BUS_OP || type == DEV_OP);
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	if (func == NULL && state_func == NULL) {
9880Sstevel@tonic-gate 		return (SCFGA_ERR);
9890Sstevel@tonic-gate 	}
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 	/*
9920Sstevel@tonic-gate 	 * Fix up path for calling devctl.
9930Sstevel@tonic-gate 	 */
9940Sstevel@tonic-gate 	if ((path = strdup(physpath)) == NULL) {
9950Sstevel@tonic-gate 		*l_errnop = errno;
9960Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
9970Sstevel@tonic-gate 	}
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	/* Remove dynamic component if any */
10000Sstevel@tonic-gate 	if ((cp = GET_DYN(path)) != NULL) {
10010Sstevel@tonic-gate 		*cp = '\0';
10020Sstevel@tonic-gate 	}
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	/* Remove minor name */
10050Sstevel@tonic-gate 	if ((cp = strrchr(path, ':')) != NULL) {
10060Sstevel@tonic-gate 		*cp = '\0';
10070Sstevel@tonic-gate 	}
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 	errno = 0;
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	if (type == BUS_OP) {
10120Sstevel@tonic-gate 		hdl = devctl_bus_acquire(path, 0);
10130Sstevel@tonic-gate 	} else {
10140Sstevel@tonic-gate 		hdl = devctl_device_acquire(path, 0);
10150Sstevel@tonic-gate 	}
10160Sstevel@tonic-gate 	*l_errnop = errno;
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	S_FREE(path);
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate 	if (hdl == NULL) {
10210Sstevel@tonic-gate 		return (SCFGA_ERR);
10220Sstevel@tonic-gate 	}
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	errno = 0;
10250Sstevel@tonic-gate 	/* Only getstate functions require a second argument */
10260Sstevel@tonic-gate 	if (func != NULL && statep == NULL) {
10270Sstevel@tonic-gate 		rv = func(hdl);
10280Sstevel@tonic-gate 		*l_errnop = errno;
10290Sstevel@tonic-gate 	} else if (state_func != NULL && statep != NULL) {
10300Sstevel@tonic-gate 		rv = state_func(hdl, statep);
10310Sstevel@tonic-gate 		*l_errnop = errno;
10320Sstevel@tonic-gate 	} else {
10330Sstevel@tonic-gate 		rv = -1;
10340Sstevel@tonic-gate 		*l_errnop = 0;
10350Sstevel@tonic-gate 	}
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	devctl_release(hdl);
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 	return ((rv == -1) ? SCFGA_ERR : SCFGA_OK);
10400Sstevel@tonic-gate }
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate /*
10430Sstevel@tonic-gate  * Is device in a known state ? (One of BUSY, ONLINE, OFFLINE)
10440Sstevel@tonic-gate  *	BUSY --> One or more device special files are open. Implies online
10450Sstevel@tonic-gate  *	ONLINE --> driver attached
10460Sstevel@tonic-gate  *	OFFLINE --> CF1 with offline flag set.
10470Sstevel@tonic-gate  *	UNKNOWN --> None of the above
10480Sstevel@tonic-gate  */
10490Sstevel@tonic-gate int
known_state(di_node_t node)10500Sstevel@tonic-gate known_state(di_node_t node)
10510Sstevel@tonic-gate {
10520Sstevel@tonic-gate 	uint_t state;
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 	state = di_state(node);
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 	/*
10570Sstevel@tonic-gate 	 * CF1 without offline flag set is considered unknown state.
10580Sstevel@tonic-gate 	 * We are in a known state if either CF2 (driver attached) or
10590Sstevel@tonic-gate 	 * offline.
10600Sstevel@tonic-gate 	 */
10610Sstevel@tonic-gate 	if ((state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE ||
1062*10696SDavid.Hollister@Sun.COM 	    (state & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) {
10630Sstevel@tonic-gate 		return (1);
10640Sstevel@tonic-gate 	}
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 	return (0);
10670Sstevel@tonic-gate }
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate void
list_free(ldata_list_t ** llpp)10700Sstevel@tonic-gate list_free(ldata_list_t **llpp)
10710Sstevel@tonic-gate {
10720Sstevel@tonic-gate 	ldata_list_t *lp, *olp;
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 	lp = *llpp;
10750Sstevel@tonic-gate 	while (lp != NULL) {
10760Sstevel@tonic-gate 		olp = lp;
10770Sstevel@tonic-gate 		lp = olp->next;
10780Sstevel@tonic-gate 		S_FREE(olp);
10790Sstevel@tonic-gate 	}
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 	*llpp = NULL;
10820Sstevel@tonic-gate }
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate /*
10850Sstevel@tonic-gate  * Obtain the devlink from a /devices path
10860Sstevel@tonic-gate  */
10870Sstevel@tonic-gate typedef struct walk_link {
10880Sstevel@tonic-gate 	char *path;
10890Sstevel@tonic-gate 	char len;
10900Sstevel@tonic-gate 	char **linkpp;
10910Sstevel@tonic-gate } walk_link_t;
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate static int
get_link(di_devlink_t devlink,void * arg)10940Sstevel@tonic-gate get_link(di_devlink_t devlink, void *arg)
10950Sstevel@tonic-gate {
10960Sstevel@tonic-gate 	walk_link_t *larg = (walk_link_t *)arg;
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	/*
10990Sstevel@tonic-gate 	 * When path is specified, it's the node path without minor
11000Sstevel@tonic-gate 	 * name. Therefore, the ../.. prefixes needs to be stripped.
11010Sstevel@tonic-gate 	 */
11020Sstevel@tonic-gate 	if (larg->path) {
11030Sstevel@tonic-gate 		char *content = (char *)di_devlink_content(devlink);
11040Sstevel@tonic-gate 		char *start = strstr(content, "/devices/");
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate 		/* line content must have minor node */
11070Sstevel@tonic-gate 		if (start == NULL ||
11080Sstevel@tonic-gate 		    strncmp(start, larg->path, larg->len) != 0 ||
11090Sstevel@tonic-gate 		    start[larg->len] != ':')
11100Sstevel@tonic-gate 			return (DI_WALK_CONTINUE);
11110Sstevel@tonic-gate 	}
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 	*(larg->linkpp) = strdup(di_devlink_path(devlink));
11140Sstevel@tonic-gate 	return (DI_WALK_TERMINATE);
11150Sstevel@tonic-gate }
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate scfga_ret_t
physpath_to_devlink(char * node_path,char ** logpp,int * l_errnop,int match_minor)11180Sstevel@tonic-gate physpath_to_devlink(
11190Sstevel@tonic-gate 	char *node_path,
11200Sstevel@tonic-gate 	char **logpp,
11210Sstevel@tonic-gate 	int *l_errnop,
11220Sstevel@tonic-gate 	int match_minor)
11230Sstevel@tonic-gate {
11240Sstevel@tonic-gate 	walk_link_t larg;
11250Sstevel@tonic-gate 	di_devlink_handle_t hdl;
11260Sstevel@tonic-gate 	char *minor_path;
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 	if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
11290Sstevel@tonic-gate 		*l_errnop = errno;
11300Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
11310Sstevel@tonic-gate 	}
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 	*logpp = NULL;
11340Sstevel@tonic-gate 	larg.linkpp = logpp;
11350Sstevel@tonic-gate 	if (match_minor) {
11360Sstevel@tonic-gate 		minor_path = node_path + strlen(DEVICES_DIR);
11370Sstevel@tonic-gate 		larg.path = NULL;
11380Sstevel@tonic-gate 	} else {
11390Sstevel@tonic-gate 		minor_path = NULL;
11400Sstevel@tonic-gate 		larg.len = strlen(node_path);
11410Sstevel@tonic-gate 		larg.path = node_path;
11420Sstevel@tonic-gate 	}
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 	(void) di_devlink_walk(hdl, NULL, minor_path, DI_PRIMARY_LINK,
11450Sstevel@tonic-gate 	    (void *)&larg, get_link);
11460Sstevel@tonic-gate 
11471957Sdnielsen 	(void) di_devlink_fini(&hdl);
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 	if (*logpp == NULL)
11500Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 	return (SCFGA_OK);
11530Sstevel@tonic-gate }
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate int
hba_dev_cmp(const char * hba,const char * devpath)11560Sstevel@tonic-gate hba_dev_cmp(const char *hba, const char *devpath)
11570Sstevel@tonic-gate {
11580Sstevel@tonic-gate 	char *cp = NULL;
11590Sstevel@tonic-gate 	int rv;
11600Sstevel@tonic-gate 	size_t hba_len, dev_len;
11610Sstevel@tonic-gate 	char l_hba[MAXPATHLEN], l_dev[MAXPATHLEN];
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 	(void) snprintf(l_hba, sizeof (l_hba), "%s", hba);
11640Sstevel@tonic-gate 	(void) snprintf(l_dev, sizeof (l_dev), "%s", devpath);
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	/* Remove dynamic component if any */
11670Sstevel@tonic-gate 	if ((cp = GET_DYN(l_hba)) != NULL) {
11680Sstevel@tonic-gate 		*cp = '\0';
11690Sstevel@tonic-gate 	}
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 	if ((cp = GET_DYN(l_dev)) != NULL) {
11720Sstevel@tonic-gate 		*cp = '\0';
11730Sstevel@tonic-gate 	}
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 	/* Remove minor names */
11770Sstevel@tonic-gate 	if ((cp = strrchr(l_hba, ':')) != NULL) {
11780Sstevel@tonic-gate 		*cp = '\0';
11790Sstevel@tonic-gate 	}
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 	if ((cp = strrchr(l_dev, ':')) != NULL) {
11820Sstevel@tonic-gate 		*cp = '\0';
11830Sstevel@tonic-gate 	}
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 	hba_len = strlen(l_hba);
11860Sstevel@tonic-gate 	dev_len = strlen(l_dev);
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 	/* Check if HBA path is component of device path */
11890Sstevel@tonic-gate 	if (rv = strncmp(l_hba, l_dev, hba_len)) {
11900Sstevel@tonic-gate 		return (rv);
11910Sstevel@tonic-gate 	}
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	/* devpath must have '/' and 1 char in addition to hba path */
11940Sstevel@tonic-gate 	if (dev_len >= hba_len + 2 && l_dev[hba_len] == '/') {
11950Sstevel@tonic-gate 		return (0);
11960Sstevel@tonic-gate 	} else {
11970Sstevel@tonic-gate 		return (-1);
11980Sstevel@tonic-gate 	}
11990Sstevel@tonic-gate }
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate int
dev_cmp(const char * dev1,const char * dev2,int match_minor)12020Sstevel@tonic-gate dev_cmp(const char *dev1, const char *dev2, int match_minor)
12030Sstevel@tonic-gate {
12040Sstevel@tonic-gate 	char l_dev1[MAXPATHLEN], l_dev2[MAXPATHLEN];
12050Sstevel@tonic-gate 	char *mn1, *mn2;
12060Sstevel@tonic-gate 	int rv;
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate 	(void) snprintf(l_dev1, sizeof (l_dev1), "%s", dev1);
12090Sstevel@tonic-gate 	(void) snprintf(l_dev2, sizeof (l_dev2), "%s", dev2);
12100Sstevel@tonic-gate 
12110Sstevel@tonic-gate 	if ((mn1 = GET_DYN(l_dev1)) != NULL) {
12120Sstevel@tonic-gate 		*mn1 = '\0';
12130Sstevel@tonic-gate 	}
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 	if ((mn2 = GET_DYN(l_dev2)) != NULL) {
12160Sstevel@tonic-gate 		*mn2 = '\0';
12170Sstevel@tonic-gate 	}
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 	/* Separate out the minor names */
12200Sstevel@tonic-gate 	if ((mn1 = strrchr(l_dev1, ':')) != NULL) {
12210Sstevel@tonic-gate 		*mn1++ = '\0';
12220Sstevel@tonic-gate 	}
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate 	if ((mn2 = strrchr(l_dev2, ':')) != NULL) {
12250Sstevel@tonic-gate 		*mn2++ = '\0';
12260Sstevel@tonic-gate 	}
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate 	if ((rv = strcmp(l_dev1, l_dev2)) != 0 || !match_minor) {
12290Sstevel@tonic-gate 		return (rv);
12300Sstevel@tonic-gate 	}
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 	/*
12330Sstevel@tonic-gate 	 * Compare minor names
12340Sstevel@tonic-gate 	 */
12350Sstevel@tonic-gate 	if (mn1 == NULL && mn2 == NULL) {
12360Sstevel@tonic-gate 		return (0);
12370Sstevel@tonic-gate 	} else if (mn1 == NULL) {
12380Sstevel@tonic-gate 		return (-1);
12390Sstevel@tonic-gate 	} else if (mn2 == NULL) {
12400Sstevel@tonic-gate 		return (1);
12410Sstevel@tonic-gate 	} else {
12420Sstevel@tonic-gate 		return (strcmp(mn1, mn2));
12430Sstevel@tonic-gate 	}
12440Sstevel@tonic-gate }
1245