17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
509fe1b16Sdnielsen  * Common Development and Distribution License (the "License").
609fe1b16Sdnielsen  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2109fe1b16Sdnielsen 
227c478bd9Sstevel@tonic-gate /*
23*4c06356bSdh  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include "cfga_scsi.h"
2809fe1b16Sdnielsen #include <libgen.h>
2909fe1b16Sdnielsen #include <limits.h>
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * This file contains helper routines for the SCSI plugin
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
367c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
377c478bd9Sstevel@tonic-gate #endif
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate typedef struct strlist {
407c478bd9Sstevel@tonic-gate 	const char *str;
417c478bd9Sstevel@tonic-gate 	struct strlist *next;
427c478bd9Sstevel@tonic-gate } strlist_t;
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate typedef	struct {
457c478bd9Sstevel@tonic-gate 	scfga_ret_t scsi_err;
467c478bd9Sstevel@tonic-gate 	cfga_err_t  cfga_err;
477c478bd9Sstevel@tonic-gate } errcvt_t;
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate typedef struct {
507c478bd9Sstevel@tonic-gate 	scfga_cmd_t cmd;
517c478bd9Sstevel@tonic-gate 	int type;
527c478bd9Sstevel@tonic-gate 	int (*fcn)(const devctl_hdl_t);
537c478bd9Sstevel@tonic-gate } set_state_cmd_t;
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate typedef struct {
567c478bd9Sstevel@tonic-gate 	scfga_cmd_t cmd;
577c478bd9Sstevel@tonic-gate 	int type;
587c478bd9Sstevel@tonic-gate 	int (*state_fcn)(const devctl_hdl_t, uint_t *);
597c478bd9Sstevel@tonic-gate } get_state_cmd_t;
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /* Function prototypes */
627c478bd9Sstevel@tonic-gate static char *pathdup(const char *path, int *l_errnop);
637c478bd9Sstevel@tonic-gate static void msg_common(char **err_msgpp, int append_newline, int l_errno,
647c478bd9Sstevel@tonic-gate     va_list ap);
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate  * The string table contains most of the strings used by the scsi cfgadm plugin.
687c478bd9Sstevel@tonic-gate  * All strings which are to be internationalized must be in this table.
697c478bd9Sstevel@tonic-gate  * Some strings which are not internationalized are also included here.
707c478bd9Sstevel@tonic-gate  * Arguments to messages are NOT internationalized.
717c478bd9Sstevel@tonic-gate  */
727c478bd9Sstevel@tonic-gate msgcvt_t str_tbl[] = {
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate  * The first element (ERR_UNKNOWN) MUST always be present in the array.
767c478bd9Sstevel@tonic-gate  */
777c478bd9Sstevel@tonic-gate #define	UNKNOWN_ERR_IDX		0	/* Keep the index in sync */
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate /* msg_code	num_args, I18N	msg_string				*/
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate /* ERRORS */
837c478bd9Sstevel@tonic-gate {ERR_UNKNOWN,		0, 1,	"unknown error"},
847c478bd9Sstevel@tonic-gate {ERR_OP_FAILED,		0, 1,	"operation failed"},
857c478bd9Sstevel@tonic-gate {ERR_CMD_INVAL,		0, 1,	"invalid command"},
867c478bd9Sstevel@tonic-gate {ERR_NOT_BUSAPID,	0, 1,	"not a SCSI bus apid"},
877c478bd9Sstevel@tonic-gate {ERR_APID_INVAL,	0, 1,	"invalid SCSI ap_id"},
887c478bd9Sstevel@tonic-gate {ERR_NOT_BUSOP,		0, 1,	"operation not supported for SCSI bus"},
897c478bd9Sstevel@tonic-gate {ERR_NOT_DEVOP,		0, 1,	"operation not supported for SCSI device"},
907c478bd9Sstevel@tonic-gate {ERR_UNAVAILABLE,	0, 1,	"unavailable"},
917c478bd9Sstevel@tonic-gate {ERR_CTRLR_CRIT,	0, 1,	"critical partition controlled by SCSI HBA"},
927c478bd9Sstevel@tonic-gate {ERR_BUS_GETSTATE,	0, 1,	"failed to get state for SCSI bus"},
937c478bd9Sstevel@tonic-gate {ERR_BUS_NOTCONNECTED,	0, 1,	"SCSI bus not connected"},
947c478bd9Sstevel@tonic-gate {ERR_BUS_CONNECTED,	0, 1,	"SCSI bus not disconnected"},
957c478bd9Sstevel@tonic-gate {ERR_BUS_QUIESCE,	0, 1,	"SCSI bus quiesce failed"},
967c478bd9Sstevel@tonic-gate {ERR_BUS_UNQUIESCE,	0, 1,	"SCSI bus unquiesce failed"},
977c478bd9Sstevel@tonic-gate {ERR_BUS_CONFIGURE,	0, 1,	"failed to configure devices on SCSI bus"},
987c478bd9Sstevel@tonic-gate {ERR_BUS_UNCONFIGURE,	0, 1,	"failed to unconfigure SCSI bus"},
997c478bd9Sstevel@tonic-gate {ERR_DEV_CONFIGURE,	0, 1,	"failed to configure SCSI device"},
1007c478bd9Sstevel@tonic-gate {ERR_DEV_RECONFIGURE,	1, 1,	"failed to reconfigure device: "},
1017c478bd9Sstevel@tonic-gate {ERR_DEV_UNCONFIGURE,	0, 1,	"failed to unconfigure SCSI device"},
1027c478bd9Sstevel@tonic-gate {ERR_DEV_REMOVE,	0, 1,	"remove operation failed"},
1037c478bd9Sstevel@tonic-gate {ERR_DEV_REPLACE,	0, 1,	"replace operation failed"},
1047c478bd9Sstevel@tonic-gate {ERR_DEV_INSERT,	0, 1,	"insert operation failed"},
1057c478bd9Sstevel@tonic-gate {ERR_DEV_GETSTATE,	0, 1,	"failed to get state for SCSI device"},
1067c478bd9Sstevel@tonic-gate {ERR_RESET,		0, 1,	"reset failed"},
1077c478bd9Sstevel@tonic-gate {ERR_LIST,		0, 1,	"list operation failed"},
1087c478bd9Sstevel@tonic-gate {ERR_MAYBE_BUSY,	0, 1,	"device may be busy"},
1097c478bd9Sstevel@tonic-gate {ERR_BUS_DEV_MISMATCH,	0, 1,	"mismatched SCSI bus and device"},
1107c478bd9Sstevel@tonic-gate {ERR_VAR_RUN,		0, 1,	"/var/run is not mounted"},
1117c478bd9Sstevel@tonic-gate {ERR_FORK,		0, 1,	"failed to fork cleanup handler"},
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate /* Errors with arguments */
1147c478bd9Sstevel@tonic-gate {ERRARG_OPT_INVAL,	1, 1,	"invalid option: "},
1157c478bd9Sstevel@tonic-gate {ERRARG_HWCMD_INVAL,	1, 1,	"invalid command: "},
1167c478bd9Sstevel@tonic-gate {ERRARG_DEVINFO,	1, 1,	"libdevinfo failed on path: "},
1177c478bd9Sstevel@tonic-gate {ERRARG_OPEN,		1, 1,	"open failed: "},
1187c478bd9Sstevel@tonic-gate {ERRARG_LOCK,		1, 1,	"lock failed: "},
1197c478bd9Sstevel@tonic-gate {ERRARG_QUIESCE_LOCK,	1, 1,	"cannot acquire quiesce lock: "},
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /* RCM Errors */
1227c478bd9Sstevel@tonic-gate {ERR_RCM_HANDLE,	0, 1,	"cannot get RCM handle"},
1237c478bd9Sstevel@tonic-gate {ERRARG_RCM_SUSPEND,	0, 1,	"failed to suspend: "},
1247c478bd9Sstevel@tonic-gate {ERRARG_RCM_RESUME,	0, 1,	"failed to resume: "},
1257c478bd9Sstevel@tonic-gate {ERRARG_RCM_OFFLINE,	0, 1,	"failed to offline: "},
126*4c06356bSdh {ERRARG_RCM_CLIENT_OFFLINE,	0, 1,	"failed to offline a client device: "},
1277c478bd9Sstevel@tonic-gate {ERRARG_RCM_ONLINE,	0, 1,	"failed to online: "},
1287c478bd9Sstevel@tonic-gate {ERRARG_RCM_REMOVE,	0, 1,	"failed to remove: "},
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate /* Commands */
1317c478bd9Sstevel@tonic-gate {CMD_INSERT_DEV,	0, 0,	"insert_device"},
1327c478bd9Sstevel@tonic-gate {CMD_REMOVE_DEV,	0, 0,	"remove_device"},
13309fe1b16Sdnielsen {CMD_LED_DEV,		0, 0,	"led"},
13409fe1b16Sdnielsen {CMD_LOCATOR_DEV,	0, 0,	"locator"},
1357c478bd9Sstevel@tonic-gate {CMD_REPLACE_DEV,	0, 0,	"replace_device"},
1367c478bd9Sstevel@tonic-gate {CMD_RESET_DEV,		0, 0,	"reset_device"},
1377c478bd9Sstevel@tonic-gate {CMD_RESET_BUS,		0, 0,	"reset_bus"},
1387c478bd9Sstevel@tonic-gate {CMD_RESET_ALL,		0, 0,	"reset_all"},
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate /* help messages */
1417c478bd9Sstevel@tonic-gate {MSG_HELP_HDR,		0, 1,	"\nSCSI specific commands and options:\n"},
1427c478bd9Sstevel@tonic-gate {MSG_HELP_USAGE,	0, 0,	"\t-x insert_device ap_id [ap_id... ]\n"
1437c478bd9Sstevel@tonic-gate 				"\t-x remove_device ap_id [ap_id... ]\n"
1447c478bd9Sstevel@tonic-gate 				"\t-x replace_device ap_id [ap_id... ]\n"
14509fe1b16Sdnielsen 				"\t-x locator[=on|off] ap_id [ap_id... ]\n"
14609fe1b16Sdnielsen 				"\t-x led[=LED,mode=on|off|blink] "
14709fe1b16Sdnielsen 				    "ap_id [ap_id... ]\n"
1487c478bd9Sstevel@tonic-gate 				"\t-x reset_device ap_id [ap_id... ]\n"
1497c478bd9Sstevel@tonic-gate 				"\t-x reset_bus ap_id [ap_id... ]\n"
1507c478bd9Sstevel@tonic-gate 				"\t-x reset_all ap_id [ap_id... ]\n"},
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate /* hotplug messages */
1537c478bd9Sstevel@tonic-gate {MSG_INSDEV,		1, 1,	"Adding device to SCSI HBA: "},
1547c478bd9Sstevel@tonic-gate {MSG_RMDEV,		1, 1,	"Removing SCSI device: "},
1557c478bd9Sstevel@tonic-gate {MSG_REPLDEV,		1, 1,	"Replacing SCSI device: "},
1567c478bd9Sstevel@tonic-gate {MSG_WAIT_LOCK,		0, 1,	"Waiting for quiesce lock... "},
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate /* Hotplugging confirmation prompts */
1597c478bd9Sstevel@tonic-gate {CONF_QUIESCE_1,	1, 1,
1607c478bd9Sstevel@tonic-gate 	"This operation will suspend activity on SCSI bus: "},
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate {CONF_QUIESCE_2,	0, 1,	"\nContinue"},
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate {CONF_UNQUIESCE,	0, 1,
1657c478bd9Sstevel@tonic-gate 	"SCSI bus quiesced successfully.\n"
1667c478bd9Sstevel@tonic-gate 	"It is now safe to proceed with hotplug operation."
1677c478bd9Sstevel@tonic-gate 	"\nEnter y if operation is complete or n to abort"},
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate {CONF_NO_QUIESCE,	0, 1,
1707c478bd9Sstevel@tonic-gate 	"Proceed with hotplug operation."
1717c478bd9Sstevel@tonic-gate 	"\nEnter y if operation is complete or n to abort"},
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate /* Misc. */
1747c478bd9Sstevel@tonic-gate {WARN_DISCONNECT,	0, 1,
1757c478bd9Sstevel@tonic-gate 	"WARNING: Disconnecting critical partitions may cause system hang."
17609fe1b16Sdnielsen 	"\nContinue"},
17709fe1b16Sdnielsen 
17809fe1b16Sdnielsen /* LED messages */
17909fe1b16Sdnielsen {MSG_LED_HDR,		0, 1,	"Disk                    Led"},
18009fe1b16Sdnielsen {MSG_MISSING_LED_NAME,	0, 1,	"Missing LED name"},
18109fe1b16Sdnielsen {MSG_MISSING_LED_MODE,	0, 1,	"Missing LED mode"}
1827c478bd9Sstevel@tonic-gate };
1837c478bd9Sstevel@tonic-gate 
18409fe1b16Sdnielsen char *
18509fe1b16Sdnielsen led_strs[] = {
18609fe1b16Sdnielsen 	"fault",
18709fe1b16Sdnielsen 	"power",
18809fe1b16Sdnielsen 	"attn",
18909fe1b16Sdnielsen 	"active",
19009fe1b16Sdnielsen 	"locator",
19109fe1b16Sdnielsen 	NULL
19209fe1b16Sdnielsen };
19309fe1b16Sdnielsen 
19409fe1b16Sdnielsen char *
19509fe1b16Sdnielsen led_mode_strs[] = {
19609fe1b16Sdnielsen 	"off",
19709fe1b16Sdnielsen 	"on",
19809fe1b16Sdnielsen 	"blink",
19909fe1b16Sdnielsen 	"faulted",
20009fe1b16Sdnielsen 	"unknown",
20109fe1b16Sdnielsen 	NULL
20209fe1b16Sdnielsen };
20309fe1b16Sdnielsen 
20409fe1b16Sdnielsen 
20509fe1b16Sdnielsen 
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate #define	N_STRS	(sizeof (str_tbl) / sizeof (str_tbl[0]))
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate #define	GET_MSG_NARGS(i)	(str_tbl[msg_idx(i)].nargs)
2107c478bd9Sstevel@tonic-gate #define	GET_MSG_INTL(i)		(str_tbl[msg_idx(i)].intl)
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate static errcvt_t err_cvt_tbl[] = {
2137c478bd9Sstevel@tonic-gate 	{ SCFGA_OK,		CFGA_OK			},
2147c478bd9Sstevel@tonic-gate 	{ SCFGA_LIB_ERR,	CFGA_LIB_ERROR		},
2157c478bd9Sstevel@tonic-gate 	{ SCFGA_APID_NOEXIST,	CFGA_APID_NOEXIST	},
2167c478bd9Sstevel@tonic-gate 	{ SCFGA_NACK,		CFGA_NACK		},
2177c478bd9Sstevel@tonic-gate 	{ SCFGA_BUSY,		CFGA_BUSY		},
2187c478bd9Sstevel@tonic-gate 	{ SCFGA_SYSTEM_BUSY,	CFGA_SYSTEM_BUSY	},
2197c478bd9Sstevel@tonic-gate 	{ SCFGA_OPNOTSUPP,	CFGA_OPNOTSUPP		},
2207c478bd9Sstevel@tonic-gate 	{ SCFGA_PRIV,		CFGA_PRIV		},
2217c478bd9Sstevel@tonic-gate 	{ SCFGA_UNKNOWN_ERR,	CFGA_ERROR		},
2227c478bd9Sstevel@tonic-gate 	{ SCFGA_ERR,		CFGA_ERROR		}
2237c478bd9Sstevel@tonic-gate };
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate #define	N_ERR_CVT_TBL	(sizeof (err_cvt_tbl)/sizeof (err_cvt_tbl[0]))
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate #define	DEV_OP	0
2287c478bd9Sstevel@tonic-gate #define	BUS_OP	1
2297c478bd9Sstevel@tonic-gate static set_state_cmd_t set_state_cmds[] = {
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate { SCFGA_BUS_QUIESCE,		BUS_OP,		devctl_bus_quiesce	},
2327c478bd9Sstevel@tonic-gate { SCFGA_BUS_UNQUIESCE,		BUS_OP,		devctl_bus_unquiesce	},
2337c478bd9Sstevel@tonic-gate { SCFGA_BUS_CONFIGURE,		BUS_OP,		devctl_bus_configure	},
2347c478bd9Sstevel@tonic-gate { SCFGA_BUS_UNCONFIGURE, 	BUS_OP,		devctl_bus_unconfigure	},
2357c478bd9Sstevel@tonic-gate { SCFGA_RESET_BUS,		BUS_OP,		devctl_bus_reset	},
2367c478bd9Sstevel@tonic-gate { SCFGA_RESET_ALL, 		BUS_OP,		devctl_bus_resetall	},
2377c478bd9Sstevel@tonic-gate { SCFGA_DEV_CONFIGURE,		DEV_OP,		devctl_device_online	},
2387c478bd9Sstevel@tonic-gate { SCFGA_DEV_UNCONFIGURE,	DEV_OP,		devctl_device_offline	},
2397c478bd9Sstevel@tonic-gate { SCFGA_DEV_REMOVE,		DEV_OP,		devctl_device_remove	},
2407c478bd9Sstevel@tonic-gate { SCFGA_RESET_DEV,		DEV_OP,		devctl_device_reset	}
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate };
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate #define	N_SET_STATE_CMDS (sizeof (set_state_cmds)/sizeof (set_state_cmds[0]))
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate static get_state_cmd_t get_state_cmds[] = {
2477c478bd9Sstevel@tonic-gate { SCFGA_BUS_GETSTATE,		BUS_OP,		devctl_bus_getstate	},
2487c478bd9Sstevel@tonic-gate { SCFGA_DEV_GETSTATE,		DEV_OP,		devctl_device_getstate	}
2497c478bd9Sstevel@tonic-gate };
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate #define	N_GET_STATE_CMDS (sizeof (get_state_cmds)/sizeof (get_state_cmds[0]))
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate /*
2547c478bd9Sstevel@tonic-gate  * SCSI hardware specific commands
2557c478bd9Sstevel@tonic-gate  */
2567c478bd9Sstevel@tonic-gate static hw_cmd_t hw_cmds[] = {
2577c478bd9Sstevel@tonic-gate 	/* Command string	Command ID		Function	*/
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	{ CMD_INSERT_DEV,	SCFGA_INSERT_DEV,	dev_insert	},
2607c478bd9Sstevel@tonic-gate 	{ CMD_REMOVE_DEV,	SCFGA_REMOVE_DEV,	dev_remove	},
2617c478bd9Sstevel@tonic-gate 	{ CMD_REPLACE_DEV,	SCFGA_REPLACE_DEV,	dev_replace	},
26209fe1b16Sdnielsen 	{ CMD_LED_DEV,		SCFGA_LED_DEV,		dev_led		},
26309fe1b16Sdnielsen 	{ CMD_LOCATOR_DEV,	SCFGA_LOCATOR_DEV,	dev_led		},
2647c478bd9Sstevel@tonic-gate 	{ CMD_RESET_DEV,	SCFGA_RESET_DEV,	reset_common	},
2657c478bd9Sstevel@tonic-gate 	{ CMD_RESET_BUS,	SCFGA_RESET_BUS,	reset_common	},
2667c478bd9Sstevel@tonic-gate 	{ CMD_RESET_ALL,	SCFGA_RESET_ALL,	reset_common	},
2677c478bd9Sstevel@tonic-gate };
2687c478bd9Sstevel@tonic-gate #define	N_HW_CMDS (sizeof (hw_cmds) / sizeof (hw_cmds[0]))
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate cfga_err_t
err_cvt(scfga_ret_t s_err)2727c478bd9Sstevel@tonic-gate err_cvt(scfga_ret_t s_err)
2737c478bd9Sstevel@tonic-gate {
2747c478bd9Sstevel@tonic-gate 	int i;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_ERR_CVT_TBL; i++) {
2777c478bd9Sstevel@tonic-gate 		if (err_cvt_tbl[i].scsi_err == s_err) {
2787c478bd9Sstevel@tonic-gate 			return (err_cvt_tbl[i].cfga_err);
2797c478bd9Sstevel@tonic-gate 		}
2807c478bd9Sstevel@tonic-gate 	}
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	return (CFGA_ERROR);
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate /*
2867c478bd9Sstevel@tonic-gate  * Removes duplicate slashes from a pathname and any trailing slashes.
2877c478bd9Sstevel@tonic-gate  * Returns "/" if input is "/"
2887c478bd9Sstevel@tonic-gate  */
2897c478bd9Sstevel@tonic-gate static char *
pathdup(const char * path,int * l_errnop)2907c478bd9Sstevel@tonic-gate pathdup(const char *path, int *l_errnop)
2917c478bd9Sstevel@tonic-gate {
2927c478bd9Sstevel@tonic-gate 	int prev_was_slash = 0;
2937c478bd9Sstevel@tonic-gate 	char c, *dp = NULL, *dup = NULL;
2947c478bd9Sstevel@tonic-gate 	const char *sp = NULL;
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	*l_errnop = 0;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	if (path == NULL) {
2997c478bd9Sstevel@tonic-gate 		return (NULL);
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	if ((dup = calloc(1, strlen(path) + 1)) == NULL) {
3037c478bd9Sstevel@tonic-gate 		*l_errnop = errno;
3047c478bd9Sstevel@tonic-gate 		return (NULL);
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	prev_was_slash = 0;
3087c478bd9Sstevel@tonic-gate 	for (sp = path, dp = dup; (c = *sp) != '\0'; sp++) {
3097c478bd9Sstevel@tonic-gate 		if (!prev_was_slash || c != '/') {
3107c478bd9Sstevel@tonic-gate 			*dp++ = c;
3117c478bd9Sstevel@tonic-gate 		}
3127c478bd9Sstevel@tonic-gate 		if (c == '/') {
3137c478bd9Sstevel@tonic-gate 			prev_was_slash = 1;
3147c478bd9Sstevel@tonic-gate 		} else {
3157c478bd9Sstevel@tonic-gate 			prev_was_slash = 0;
3167c478bd9Sstevel@tonic-gate 		}
3177c478bd9Sstevel@tonic-gate 	}
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	/* Remove trailing slash except if it is the first char */
3207c478bd9Sstevel@tonic-gate 	if (prev_was_slash && dp != dup && dp - 1 != dup) {
3217c478bd9Sstevel@tonic-gate 		*(--dp) = '\0';
3227c478bd9Sstevel@tonic-gate 	} else {
3237c478bd9Sstevel@tonic-gate 		*dp = '\0';
3247c478bd9Sstevel@tonic-gate 	}
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	return (dup);
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate 
329*4c06356bSdh 
3307c478bd9Sstevel@tonic-gate scfga_ret_t
apidt_create(const char * ap_id,apid_t * apidp,char ** errstring)3317c478bd9Sstevel@tonic-gate apidt_create(const char *ap_id, apid_t *apidp, char **errstring)
3327c478bd9Sstevel@tonic-gate {
3337c478bd9Sstevel@tonic-gate 	char *hba_phys = NULL, *dyn = NULL;
3347c478bd9Sstevel@tonic-gate 	char *dyncomp = NULL, *path = NULL;
3357c478bd9Sstevel@tonic-gate 	int l_errno = 0;
3367c478bd9Sstevel@tonic-gate 	size_t len = 0;
3377c478bd9Sstevel@tonic-gate 	scfga_ret_t ret;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	if ((hba_phys = pathdup(ap_id, &l_errno)) == NULL) {
3407c478bd9Sstevel@tonic-gate 		cfga_err(errstring, l_errno, ERR_OP_FAILED, 0);
3417c478bd9Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	/* Extract the base(hba) and dynamic(device) component if any */
3457c478bd9Sstevel@tonic-gate 	dyncomp = NULL;
3467c478bd9Sstevel@tonic-gate 	if ((dyn = GET_DYN(hba_phys)) != NULL) {
3477c478bd9Sstevel@tonic-gate 		len = strlen(DYN_TO_DYNCOMP(dyn)) + 1;
3487c478bd9Sstevel@tonic-gate 		dyncomp = calloc(1, len);
3497c478bd9Sstevel@tonic-gate 		if (dyncomp == NULL) {
3507c478bd9Sstevel@tonic-gate 			cfga_err(errstring, errno, ERR_OP_FAILED, 0);
3517c478bd9Sstevel@tonic-gate 			ret = SCFGA_LIB_ERR;
3527c478bd9Sstevel@tonic-gate 			goto err;
3537c478bd9Sstevel@tonic-gate 		}
3547c478bd9Sstevel@tonic-gate 		(void) strcpy(dyncomp, DYN_TO_DYNCOMP(dyn));
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 		/* Remove the dynamic component from the base */
3577c478bd9Sstevel@tonic-gate 		*dyn = '\0';
358*4c06356bSdh 	} else {
359*4c06356bSdh 		apidp->dyntype = NODYNCOMP;
360*4c06356bSdh 	}
361*4c06356bSdh 
362*4c06356bSdh 	/* get dyn comp type */
363*4c06356bSdh 	if (dyncomp != NULL) {
364*4c06356bSdh 		if (strstr(dyncomp, PATH_APID_DYN_SEP) != NULL) {
365*4c06356bSdh 			apidp->dyntype = PATH_APID;
366*4c06356bSdh 		} else {
367*4c06356bSdh 			apidp->dyntype = DEV_APID;
368*4c06356bSdh 		}
3697c478bd9Sstevel@tonic-gate 	}
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	/* Create the path */
372*4c06356bSdh 	if ((ret = apid_to_path(hba_phys, dyncomp, &path,
373*4c06356bSdh 	    &l_errno)) != SCFGA_OK) {
3747c478bd9Sstevel@tonic-gate 		cfga_err(errstring, l_errno, ERR_OP_FAILED, 0);
3757c478bd9Sstevel@tonic-gate 		goto err;
3767c478bd9Sstevel@tonic-gate 	}
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	assert(path != NULL);
3797c478bd9Sstevel@tonic-gate 	assert(hba_phys != NULL);
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	apidp->hba_phys = hba_phys;
3827c478bd9Sstevel@tonic-gate 	apidp->dyncomp = dyncomp;
3837c478bd9Sstevel@tonic-gate 	apidp->path = path;
3847c478bd9Sstevel@tonic-gate 	apidp->flags = 0;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	return (SCFGA_OK);
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate err:
3897c478bd9Sstevel@tonic-gate 	S_FREE(hba_phys);
3907c478bd9Sstevel@tonic-gate 	S_FREE(dyncomp);
3917c478bd9Sstevel@tonic-gate 	S_FREE(path);
3927c478bd9Sstevel@tonic-gate 	return (ret);
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate void
apidt_free(apid_t * apidp)3967c478bd9Sstevel@tonic-gate apidt_free(apid_t *apidp)
3977c478bd9Sstevel@tonic-gate {
3987c478bd9Sstevel@tonic-gate 	if (apidp == NULL)
3997c478bd9Sstevel@tonic-gate 		return;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	S_FREE(apidp->hba_phys);
4027c478bd9Sstevel@tonic-gate 	S_FREE(apidp->dyncomp);
4037c478bd9Sstevel@tonic-gate 	S_FREE(apidp->path);
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@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)4077c478bd9Sstevel@tonic-gate walk_tree(
4087c478bd9Sstevel@tonic-gate 	const char	*physpath,
4097c478bd9Sstevel@tonic-gate 	void		*arg,
4107c478bd9Sstevel@tonic-gate 	uint_t		init_flags,
4117c478bd9Sstevel@tonic-gate 	walkarg_t	*up,
4127c478bd9Sstevel@tonic-gate 	scfga_cmd_t	cmd,
4137c478bd9Sstevel@tonic-gate 	int		*l_errnop)
4147c478bd9Sstevel@tonic-gate {
4157c478bd9Sstevel@tonic-gate 	int rv;
4167c478bd9Sstevel@tonic-gate 	di_node_t root, walk_root;
4177c478bd9Sstevel@tonic-gate 	char *root_path, *cp = NULL, *init_path;
4187c478bd9Sstevel@tonic-gate 	size_t len;
4197c478bd9Sstevel@tonic-gate 	scfga_ret_t ret;
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	*l_errnop = 0;
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	if ((root_path = strdup(physpath)) == NULL) {
4247c478bd9Sstevel@tonic-gate 		*l_errnop = errno;
4257c478bd9Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	/* Fix up path for di_init() */
4297c478bd9Sstevel@tonic-gate 	len = strlen(DEVICES_DIR);
4307c478bd9Sstevel@tonic-gate 	if (strncmp(root_path, DEVICES_DIR SLASH,
4317c478bd9Sstevel@tonic-gate 	    len + strlen(SLASH)) == 0) {
4327c478bd9Sstevel@tonic-gate 		cp = root_path + len;
4337c478bd9Sstevel@tonic-gate 		(void) memmove(root_path, cp, strlen(cp) + 1);
4347c478bd9Sstevel@tonic-gate 	} else if (*root_path != '/') {
4357c478bd9Sstevel@tonic-gate 		*l_errnop = 0;
4367c478bd9Sstevel@tonic-gate 		ret = SCFGA_ERR;
4377c478bd9Sstevel@tonic-gate 		goto out;
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	/* Remove dynamic component if any */
4417c478bd9Sstevel@tonic-gate 	if ((cp = GET_DYN(root_path)) != NULL) {
4427c478bd9Sstevel@tonic-gate 		*cp = '\0';
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	/* Remove minor name if any */
4467c478bd9Sstevel@tonic-gate 	if ((cp = strrchr(root_path, ':')) != NULL) {
4477c478bd9Sstevel@tonic-gate 		*cp = '\0';
4487c478bd9Sstevel@tonic-gate 	}
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	/*
4517c478bd9Sstevel@tonic-gate 	 * Cached snapshots are always rooted at "/"
4527c478bd9Sstevel@tonic-gate 	 */
4537c478bd9Sstevel@tonic-gate 	init_path = root_path;
4547c478bd9Sstevel@tonic-gate 	if ((init_flags & DINFOCACHE) == DINFOCACHE) {
4557c478bd9Sstevel@tonic-gate 		init_path = "/";
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	/* Get a snapshot */
4597c478bd9Sstevel@tonic-gate 	if ((root = di_init(init_path, init_flags)) == DI_NODE_NIL) {
4607c478bd9Sstevel@tonic-gate 		*l_errnop = errno;
4617c478bd9Sstevel@tonic-gate 		ret = SCFGA_LIB_ERR;
4627c478bd9Sstevel@tonic-gate 		goto out;
4637c478bd9Sstevel@tonic-gate 	}
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	/*
4667c478bd9Sstevel@tonic-gate 	 * Lookup the subtree of interest
4677c478bd9Sstevel@tonic-gate 	 */
4687c478bd9Sstevel@tonic-gate 	walk_root = root;
4697c478bd9Sstevel@tonic-gate 	if ((init_flags & DINFOCACHE) == DINFOCACHE) {
4707c478bd9Sstevel@tonic-gate 		walk_root = di_lookup_node(root, root_path);
4717c478bd9Sstevel@tonic-gate 	}
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	if (walk_root == DI_NODE_NIL) {
4747c478bd9Sstevel@tonic-gate 		*l_errnop = errno;
4757c478bd9Sstevel@tonic-gate 		di_fini(root);
4767c478bd9Sstevel@tonic-gate 		ret = SCFGA_LIB_ERR;
4777c478bd9Sstevel@tonic-gate 		goto out;
4787c478bd9Sstevel@tonic-gate 	}
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	/* Walk the tree */
4817c478bd9Sstevel@tonic-gate 	errno = 0;
4827c478bd9Sstevel@tonic-gate 	if (cmd == SCFGA_WALK_NODE) {
4837c478bd9Sstevel@tonic-gate 		rv = di_walk_node(walk_root, up->node_args.flags, arg,
4847c478bd9Sstevel@tonic-gate 		    up->node_args.fcn);
485*4c06356bSdh 	} else if (cmd == SCFGA_WALK_PATH) {
486*4c06356bSdh 		rv = stat_path_info(walk_root, arg, l_errnop);
4877c478bd9Sstevel@tonic-gate 	} else {
4887c478bd9Sstevel@tonic-gate 		assert(cmd == SCFGA_WALK_MINOR);
4897c478bd9Sstevel@tonic-gate 		rv = di_walk_minor(walk_root, up->minor_args.nodetype, 0, arg,
4907c478bd9Sstevel@tonic-gate 		    up->minor_args.fcn);
4917c478bd9Sstevel@tonic-gate 	}
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	if (rv != 0) {
4947c478bd9Sstevel@tonic-gate 		*l_errnop = errno;
4957c478bd9Sstevel@tonic-gate 		ret = SCFGA_LIB_ERR;
4967c478bd9Sstevel@tonic-gate 	} else {
4977c478bd9Sstevel@tonic-gate 		*l_errnop = 0;
4987c478bd9Sstevel@tonic-gate 		ret = SCFGA_OK;
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	di_fini(root);
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
5047c478bd9Sstevel@tonic-gate out:
5057c478bd9Sstevel@tonic-gate 	S_FREE(root_path);
5067c478bd9Sstevel@tonic-gate 	return (ret);
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate scfga_ret_t
invoke_cmd(const char * func,apid_t * apidtp,prompt_t * prp,cfga_flags_t flags,char ** errstring)5107c478bd9Sstevel@tonic-gate invoke_cmd(
5117c478bd9Sstevel@tonic-gate 	const char *func,
5127c478bd9Sstevel@tonic-gate 	apid_t *apidtp,
5137c478bd9Sstevel@tonic-gate 	prompt_t *prp,
5147c478bd9Sstevel@tonic-gate 	cfga_flags_t flags,
5157c478bd9Sstevel@tonic-gate 	char **errstring)
5167c478bd9Sstevel@tonic-gate {
5177c478bd9Sstevel@tonic-gate 	int i;
51809fe1b16Sdnielsen 	int len;
51909fe1b16Sdnielsen 
52009fe1b16Sdnielsen 
52109fe1b16Sdnielsen 	/*
52209fe1b16Sdnielsen 	 * Determine if the func has an equal sign; only compare up to
52309fe1b16Sdnielsen 	 * the equals
52409fe1b16Sdnielsen 	 */
525*4c06356bSdh 	for (len = 0; func[len] != 0 && func[len] != '='; len++) {
526*4c06356bSdh 	};
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_HW_CMDS; i++) {
52909fe1b16Sdnielsen 		const char *s = GET_MSG_STR(hw_cmds[i].str_id);
53009fe1b16Sdnielsen 		if (strncmp(func, s, len) == 0 && s[len] == 0) {
53109fe1b16Sdnielsen 			return (hw_cmds[i].fcn(func, hw_cmds[i].cmd, apidtp,
5327c478bd9Sstevel@tonic-gate 			    prp, flags, errstring));
5337c478bd9Sstevel@tonic-gate 		}
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	cfga_err(errstring, 0, ERRARG_HWCMD_INVAL, func, 0);
5377c478bd9Sstevel@tonic-gate 	return (SCFGA_ERR);
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate int
msg_idx(msgid_t msgid)5417c478bd9Sstevel@tonic-gate msg_idx(msgid_t msgid)
5427c478bd9Sstevel@tonic-gate {
5437c478bd9Sstevel@tonic-gate 	int idx = 0;
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	/* The string table index and the error id may or may not be same */
5467c478bd9Sstevel@tonic-gate 	if (msgid >= 0 && msgid <= N_STRS - 1 &&
5477c478bd9Sstevel@tonic-gate 	    str_tbl[msgid].msgid == msgid) {
5487c478bd9Sstevel@tonic-gate 		idx = msgid;
5497c478bd9Sstevel@tonic-gate 	} else {
5507c478bd9Sstevel@tonic-gate 		for (idx = 0; idx < N_STRS; idx++) {
5517c478bd9Sstevel@tonic-gate 			if (str_tbl[idx].msgid == msgid)
5527c478bd9Sstevel@tonic-gate 				break;
5537c478bd9Sstevel@tonic-gate 		}
5547c478bd9Sstevel@tonic-gate 		if (idx >= N_STRS) {
5557c478bd9Sstevel@tonic-gate 			idx =  UNKNOWN_ERR_IDX;
5567c478bd9Sstevel@tonic-gate 		}
5577c478bd9Sstevel@tonic-gate 	}
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	return (idx);
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate /*
5637c478bd9Sstevel@tonic-gate  * cfga_err() accepts a variable number of message IDs and constructs
5647c478bd9Sstevel@tonic-gate  * a corresponding error string which is returned via the errstring argument.
5657c478bd9Sstevel@tonic-gate  * cfga_err() calls dgettext() to internationalize proper messages.
5667c478bd9Sstevel@tonic-gate  * May be called with a NULL argument.
5677c478bd9Sstevel@tonic-gate  */
5687c478bd9Sstevel@tonic-gate void
cfga_err(char ** errstring,int l_errno,...)5697c478bd9Sstevel@tonic-gate cfga_err(char **errstring, int l_errno, ...)
5707c478bd9Sstevel@tonic-gate {
5717c478bd9Sstevel@tonic-gate 	va_list ap;
5727c478bd9Sstevel@tonic-gate 	int append_newline = 0;
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	if (errstring == NULL || *errstring != NULL) {
5757c478bd9Sstevel@tonic-gate 		return;
5767c478bd9Sstevel@tonic-gate 	}
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	/*
5797c478bd9Sstevel@tonic-gate 	 * Don't append a newline, the application (for example cfgadm)
5807c478bd9Sstevel@tonic-gate 	 * should do that.
5817c478bd9Sstevel@tonic-gate 	 */
5827c478bd9Sstevel@tonic-gate 	append_newline = 0;
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	va_start(ap, l_errno);
5857c478bd9Sstevel@tonic-gate 	msg_common(errstring, append_newline, l_errno, ap);
5867c478bd9Sstevel@tonic-gate 	va_end(ap);
5877c478bd9Sstevel@tonic-gate }
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate /*
5907c478bd9Sstevel@tonic-gate  * This routine accepts a variable number of message IDs and constructs
5917c478bd9Sstevel@tonic-gate  * a corresponding message string which is printed via the message print
5927c478bd9Sstevel@tonic-gate  * routine argument.
5937c478bd9Sstevel@tonic-gate  */
5947c478bd9Sstevel@tonic-gate void
cfga_msg(struct cfga_msg * msgp,...)5957c478bd9Sstevel@tonic-gate cfga_msg(struct cfga_msg *msgp, ...)
5967c478bd9Sstevel@tonic-gate {
5977c478bd9Sstevel@tonic-gate 	char *p = NULL;
5987c478bd9Sstevel@tonic-gate 	int append_newline = 0, l_errno = 0;
5997c478bd9Sstevel@tonic-gate 	va_list ap;
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	if (msgp == NULL || msgp->message_routine == NULL) {
6027c478bd9Sstevel@tonic-gate 		return;
6037c478bd9Sstevel@tonic-gate 	}
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	/* Append a newline after message */
6067c478bd9Sstevel@tonic-gate 	append_newline = 1;
6077c478bd9Sstevel@tonic-gate 	l_errno = 0;
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	va_start(ap, msgp);
6107c478bd9Sstevel@tonic-gate 	msg_common(&p, append_newline, l_errno, ap);
6117c478bd9Sstevel@tonic-gate 	va_end(ap);
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	(void) (*msgp->message_routine)(msgp->appdata_ptr, p);
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	S_FREE(p);
6167c478bd9Sstevel@tonic-gate }
6177c478bd9Sstevel@tonic-gate 
61809fe1b16Sdnielsen 
61909fe1b16Sdnielsen /*
62009fe1b16Sdnielsen  * This routine prints the value of an led for a disk.
62109fe1b16Sdnielsen  */
62209fe1b16Sdnielsen void
cfga_led_msg(struct cfga_msg * msgp,apid_t * apidp,led_strid_t led,led_modeid_t mode)62309fe1b16Sdnielsen cfga_led_msg(struct cfga_msg *msgp, apid_t *apidp, led_strid_t led,
62409fe1b16Sdnielsen     led_modeid_t mode)
62509fe1b16Sdnielsen {
62609fe1b16Sdnielsen 	char led_msg[MAX_INPUT];	/* 512 bytes */
62709fe1b16Sdnielsen 
62809fe1b16Sdnielsen 	if ((msgp == NULL) || (msgp->message_routine == NULL)) {
62909fe1b16Sdnielsen 		return;
63009fe1b16Sdnielsen 	}
63109fe1b16Sdnielsen 	if ((apidp == NULL) || (apidp->dyncomp == NULL)) {
63209fe1b16Sdnielsen 		return;
63309fe1b16Sdnielsen 	}
634*4c06356bSdh 	(void) snprintf(led_msg, sizeof (led_msg), "%-23s\t%s=%s\n",
635*4c06356bSdh 	    basename(apidp->dyncomp),
636*4c06356bSdh 	    dgettext(TEXT_DOMAIN, led_strs[led]),
637*4c06356bSdh 	    dgettext(TEXT_DOMAIN, led_mode_strs[mode]));
63809fe1b16Sdnielsen 	(void) (*msgp->message_routine)(msgp->appdata_ptr, led_msg);
63909fe1b16Sdnielsen }
64009fe1b16Sdnielsen 
6417c478bd9Sstevel@tonic-gate /*
6427c478bd9Sstevel@tonic-gate  * Get internationalized string corresponding to message id
6437c478bd9Sstevel@tonic-gate  * Caller must free the memory allocated.
6447c478bd9Sstevel@tonic-gate  */
6457c478bd9Sstevel@tonic-gate char *
cfga_str(int append_newline,...)6467c478bd9Sstevel@tonic-gate cfga_str(int append_newline, ...)
6477c478bd9Sstevel@tonic-gate {
6487c478bd9Sstevel@tonic-gate 	char *p = NULL;
6497c478bd9Sstevel@tonic-gate 	int l_errno = 0;
6507c478bd9Sstevel@tonic-gate 	va_list ap;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	va_start(ap, append_newline);
6537c478bd9Sstevel@tonic-gate 	msg_common(&p, append_newline, l_errno, ap);
6547c478bd9Sstevel@tonic-gate 	va_end(ap);
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	return (p);
6577c478bd9Sstevel@tonic-gate }
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate static void
msg_common(char ** msgpp,int append_newline,int l_errno,va_list ap)6607c478bd9Sstevel@tonic-gate msg_common(char **msgpp, int append_newline, int l_errno, va_list ap)
6617c478bd9Sstevel@tonic-gate {
6627c478bd9Sstevel@tonic-gate 	int a = 0;
6637c478bd9Sstevel@tonic-gate 	size_t len = 0;
6647c478bd9Sstevel@tonic-gate 	int i = 0, n = 0;
6657c478bd9Sstevel@tonic-gate 	char *s = NULL, *t = NULL;
6667c478bd9Sstevel@tonic-gate 	strlist_t dummy;
6677c478bd9Sstevel@tonic-gate 	strlist_t *savep = NULL, *sp = NULL, *tailp = NULL;
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	if (*msgpp != NULL) {
6707c478bd9Sstevel@tonic-gate 		return;
6717c478bd9Sstevel@tonic-gate 	}
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	dummy.next = NULL;
6747c478bd9Sstevel@tonic-gate 	tailp = &dummy;
6757c478bd9Sstevel@tonic-gate 	for (len = 0; (a = va_arg(ap, int)) != 0; ) {
6767c478bd9Sstevel@tonic-gate 		n = GET_MSG_NARGS(a); /* 0 implies no additional args */
6777c478bd9Sstevel@tonic-gate 		for (i = 0; i <= n; i++) {
6787c478bd9Sstevel@tonic-gate 			sp = calloc(1, sizeof (*sp));
6797c478bd9Sstevel@tonic-gate 			if (sp == NULL) {
6807c478bd9Sstevel@tonic-gate 				goto out;
6817c478bd9Sstevel@tonic-gate 			}
6827c478bd9Sstevel@tonic-gate 			if (i == 0 && GET_MSG_INTL(a)) {
6837c478bd9Sstevel@tonic-gate 				sp->str = dgettext(TEXT_DOMAIN, GET_MSG_STR(a));
6847c478bd9Sstevel@tonic-gate 			} else if (i == 0) {
6857c478bd9Sstevel@tonic-gate 				sp->str = GET_MSG_STR(a);
6867c478bd9Sstevel@tonic-gate 			} else {
6877c478bd9Sstevel@tonic-gate 				sp->str = va_arg(ap, char *);
6887c478bd9Sstevel@tonic-gate 			}
6897c478bd9Sstevel@tonic-gate 			len += (strlen(sp->str));
6907c478bd9Sstevel@tonic-gate 			sp->next = NULL;
6917c478bd9Sstevel@tonic-gate 			tailp->next = sp;
6927c478bd9Sstevel@tonic-gate 			tailp = sp;
6937c478bd9Sstevel@tonic-gate 		}
6947c478bd9Sstevel@tonic-gate 	}
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	len += 1;	/* terminating NULL */
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	s = t = NULL;
6997c478bd9Sstevel@tonic-gate 	if (l_errno) {
7007c478bd9Sstevel@tonic-gate 		s = dgettext(TEXT_DOMAIN, ": ");
7017c478bd9Sstevel@tonic-gate 		t = S_STR(strerror(l_errno));
7027c478bd9Sstevel@tonic-gate 		if (s != NULL && t != NULL) {
7037c478bd9Sstevel@tonic-gate 			len += strlen(s) + strlen(t);
7047c478bd9Sstevel@tonic-gate 		}
7057c478bd9Sstevel@tonic-gate 	}
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	if (append_newline) {
7087c478bd9Sstevel@tonic-gate 		len++;
7097c478bd9Sstevel@tonic-gate 	}
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	if ((*msgpp = calloc(1, len)) == NULL) {
7127c478bd9Sstevel@tonic-gate 		goto out;
7137c478bd9Sstevel@tonic-gate 	}
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	**msgpp = '\0';
7167c478bd9Sstevel@tonic-gate 	for (sp = dummy.next; sp != NULL; sp = sp->next) {
7177c478bd9Sstevel@tonic-gate 		(void) strcat(*msgpp, sp->str);
7187c478bd9Sstevel@tonic-gate 	}
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	if (s != NULL && t != NULL) {
7217c478bd9Sstevel@tonic-gate 		(void) strcat(*msgpp, s);
7227c478bd9Sstevel@tonic-gate 		(void) strcat(*msgpp, t);
7237c478bd9Sstevel@tonic-gate 	}
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	if (append_newline) {
7267c478bd9Sstevel@tonic-gate 		(void) strcat(*msgpp, dgettext(TEXT_DOMAIN, "\n"));
7277c478bd9Sstevel@tonic-gate 	}
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	/* FALLTHROUGH */
7307c478bd9Sstevel@tonic-gate out:
7317c478bd9Sstevel@tonic-gate 	sp = dummy.next;
7327c478bd9Sstevel@tonic-gate 	while (sp != NULL) {
7337c478bd9Sstevel@tonic-gate 		savep = sp->next;
7347c478bd9Sstevel@tonic-gate 		S_FREE(sp);
7357c478bd9Sstevel@tonic-gate 		sp = savep;
7367c478bd9Sstevel@tonic-gate 	}
7377c478bd9Sstevel@tonic-gate }
7387c478bd9Sstevel@tonic-gate 
739*4c06356bSdh /*
740*4c06356bSdh  * Check to see if the given pi_node is the last path to the client device.
741*4c06356bSdh  *
742*4c06356bSdh  * Return:
743*4c06356bSdh  *	0: if there is another path avialable.
744*4c06356bSdh  *	-1: if no other paths available.
745*4c06356bSdh  */
746*4c06356bSdh static int
check_available_path(di_node_t client_node,di_path_t pi_node)747*4c06356bSdh check_available_path(
748*4c06356bSdh 	di_node_t client_node,
749*4c06356bSdh 	di_path_t pi_node)
750*4c06356bSdh {
751*4c06356bSdh 	di_path_state_t pi_state;
752*4c06356bSdh 	di_path_t   next_pi = DI_PATH_NIL;
753*4c06356bSdh 
754*4c06356bSdh 	if (((pi_state = di_path_state(pi_node)) != DI_PATH_STATE_ONLINE) &&
755*4c06356bSdh 	    (pi_state != DI_PATH_STATE_STANDBY)) {
756*4c06356bSdh 		/* it is not last available path */
757*4c06356bSdh 		return (0);
758*4c06356bSdh 	}
759*4c06356bSdh 
760*4c06356bSdh 	while (next_pi = di_path_client_next_path(client_node, next_pi)) {
761*4c06356bSdh 		/* if anohter pi node is avaialble, return 0 */
762*4c06356bSdh 		if ((next_pi != pi_node) &&
763*4c06356bSdh 		    (((pi_state = di_path_state(next_pi)) ==
764*4c06356bSdh 		    DI_PATH_STATE_ONLINE) ||
765*4c06356bSdh 		    pi_state == DI_PATH_STATE_STANDBY)) {
766*4c06356bSdh 			return (0);
767*4c06356bSdh 		}
768*4c06356bSdh 	}
769*4c06356bSdh 	return (-1);
770*4c06356bSdh }
771*4c06356bSdh 
772*4c06356bSdh 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*4c06356bSdh path_apid_state_change(
774*4c06356bSdh 	apid_t		*apidp,
775*4c06356bSdh 	scfga_cmd_t	cmd,
776*4c06356bSdh 	cfga_flags_t	flags,
777*4c06356bSdh 	char		**errstring,
778*4c06356bSdh 	int		*l_errnop,
779*4c06356bSdh 	msgid_t		errid)
780*4c06356bSdh {
781*4c06356bSdh 	di_node_t   root, walk_root, client_node;
782*4c06356bSdh 	di_path_t   pi_node = DI_PATH_NIL;
783*4c06356bSdh 	char	    *root_path, *cp, *client_path, devpath[MAXPATHLEN];
784*4c06356bSdh 	int	    len, found = 0;
785*4c06356bSdh 	scfga_ret_t ret;
786*4c06356bSdh 	char *dev_list[2] = {NULL};
787*4c06356bSdh 
788*4c06356bSdh 	*l_errnop = 0;
789*4c06356bSdh 
790*4c06356bSdh 	/* Make sure apid is pathinfo associated apid. */
791*4c06356bSdh 	if ((apidp->dyntype != PATH_APID) || (apidp->dyncomp == NULL)) {
792*4c06356bSdh 		return (SCFGA_LIB_ERR);
793*4c06356bSdh 	}
794*4c06356bSdh 
795*4c06356bSdh 	if ((cmd != SCFGA_DEV_CONFIGURE) && (cmd != SCFGA_DEV_UNCONFIGURE)) {
796*4c06356bSdh 		return (SCFGA_LIB_ERR);
797*4c06356bSdh 	}
798*4c06356bSdh 
799*4c06356bSdh 	if ((root_path = strdup(apidp->hba_phys)) == NULL) {
800*4c06356bSdh 		*l_errnop = errno;
801*4c06356bSdh 		return (SCFGA_LIB_ERR);
802*4c06356bSdh 	}
803*4c06356bSdh 
804*4c06356bSdh 	/* Fix up path for di_init() */
805*4c06356bSdh 	len = strlen(DEVICES_DIR);
806*4c06356bSdh 	if (strncmp(root_path, DEVICES_DIR SLASH,
807*4c06356bSdh 	    len + strlen(SLASH)) == 0) {
808*4c06356bSdh 		cp = root_path + len;
809*4c06356bSdh 		(void) memmove(root_path, cp, strlen(cp) + 1);
810*4c06356bSdh 	} else if (*root_path != '/') {
811*4c06356bSdh 		*l_errnop = 0;
812*4c06356bSdh 		S_FREE(root_path);
813*4c06356bSdh 		return (SCFGA_ERR);
814*4c06356bSdh 	}
815*4c06356bSdh 
816*4c06356bSdh 	/* Remove dynamic component if any */
817*4c06356bSdh 	if ((cp = GET_DYN(root_path)) != NULL) {
818*4c06356bSdh 		*cp = '\0';
819*4c06356bSdh 	}
820*4c06356bSdh 
821*4c06356bSdh 	/* Remove minor name if any */
822*4c06356bSdh 	if ((cp = strrchr(root_path, ':')) != NULL) {
823*4c06356bSdh 		*cp = '\0';
824*4c06356bSdh 	}
825*4c06356bSdh 
826*4c06356bSdh 	/*
827*4c06356bSdh 	 * Cached snapshots are always rooted at "/"
828*4c06356bSdh 	 */
829*4c06356bSdh 
830*4c06356bSdh 	/* Get a snapshot */
831*4c06356bSdh 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
832*4c06356bSdh 		*l_errnop = errno;
833*4c06356bSdh 		S_FREE(root_path);
834*4c06356bSdh 		return (SCFGA_ERR);
835*4c06356bSdh 	}
836*4c06356bSdh 
837*4c06356bSdh 	/*
838*4c06356bSdh 	 * Lookup the subtree of interest
839*4c06356bSdh 	 */
840*4c06356bSdh 	walk_root = di_lookup_node(root, root_path);
841*4c06356bSdh 
842*4c06356bSdh 	if (walk_root == DI_NODE_NIL) {
843*4c06356bSdh 		*l_errnop = errno;
844*4c06356bSdh 		di_fini(root);
845*4c06356bSdh 		S_FREE(root_path);
846*4c06356bSdh 		return (SCFGA_LIB_ERR);
847*4c06356bSdh 	}
848*4c06356bSdh 
849*4c06356bSdh 
850*4c06356bSdh 	if ((pi_node = di_path_next_client(walk_root, pi_node)) ==
851*4c06356bSdh 	    DI_PATH_NIL) {
852*4c06356bSdh 		/* the path apid not found */
853*4c06356bSdh 		di_fini(root);
854*4c06356bSdh 		S_FREE(root_path);
855*4c06356bSdh 		return (SCFGA_APID_NOEXIST);
856*4c06356bSdh 	}
857*4c06356bSdh 
858*4c06356bSdh 	do {
859*4c06356bSdh 		/* check the length first. */
860*4c06356bSdh 		if (strlen(di_path_bus_addr(pi_node)) !=
861*4c06356bSdh 		    strlen(apidp->dyncomp)) {
862*4c06356bSdh 			continue;
863*4c06356bSdh 		}
864*4c06356bSdh 
865*4c06356bSdh 		/* compare bus addr. */
866*4c06356bSdh 		if (strcmp(di_path_bus_addr(pi_node), apidp->dyncomp) == 0) {
867*4c06356bSdh 			found = 1;
868*4c06356bSdh 			break;
869*4c06356bSdh 		}
870*4c06356bSdh 		pi_node = di_path_next_client(root, pi_node);
871*4c06356bSdh 	} while (pi_node != DI_PATH_NIL);
872*4c06356bSdh 
873*4c06356bSdh 	if (!found) {
874*4c06356bSdh 		di_fini(root);
875*4c06356bSdh 		S_FREE(root_path);
876*4c06356bSdh 		return (SCFGA_APID_NOEXIST);
877*4c06356bSdh 	}
878*4c06356bSdh 
879*4c06356bSdh 	/* Get client node path. */
880*4c06356bSdh 	client_node = di_path_client_node(pi_node);
881*4c06356bSdh 	if (client_node == DI_NODE_NIL) {
882*4c06356bSdh 		di_fini(root);
883*4c06356bSdh 		S_FREE(root_path);
884*4c06356bSdh 		return (SCFGA_ERR);
885*4c06356bSdh 	} else {
886*4c06356bSdh 		client_path = di_devfs_path(client_node);
887*4c06356bSdh 		if (client_path == NULL) {
888*4c06356bSdh 			di_fini(root);
889*4c06356bSdh 			S_FREE(root_path);
890*4c06356bSdh 			return (SCFGA_ERR);
891*4c06356bSdh 		}
892*4c06356bSdh 
893*4c06356bSdh 		if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
894*4c06356bSdh 			if (cmd == SCFGA_DEV_UNCONFIGURE) {
895*4c06356bSdh 				if (check_available_path(client_node,
896*4c06356bSdh 				    pi_node) != 0) {
897*4c06356bSdh 					/*
898*4c06356bSdh 					 * last path. check if unconfiguring
899*4c06356bSdh 					 * is okay.
900*4c06356bSdh 					 */
901*4c06356bSdh 					(void) snprintf(devpath,
902*4c06356bSdh 					    strlen(DEVICES_DIR) +
903*4c06356bSdh 					    strlen(client_path) + 1, "%s%s",
904*4c06356bSdh 					    DEVICES_DIR, client_path);
905*4c06356bSdh 					dev_list[0] = devpath;
906*4c06356bSdh 					flags |= FLAG_CLIENT_DEV;
907*4c06356bSdh 					ret = scsi_rcm_offline(dev_list,
908*4c06356bSdh 					    errstring, flags);
909*4c06356bSdh 					if (ret != SCFGA_OK) {
910*4c06356bSdh 						di_fini(root);
911*4c06356bSdh 						di_devfs_path_free(client_path);
912*4c06356bSdh 						S_FREE(root_path);
913*4c06356bSdh 						return (ret);
914*4c06356bSdh 					}
915*4c06356bSdh 				}
916*4c06356bSdh 			}
917*4c06356bSdh 		}
918*4c06356bSdh 	}
919*4c06356bSdh 
920*4c06356bSdh 	ret = devctl_cmd(apidp->path, cmd, NULL, l_errnop);
921*4c06356bSdh 	if (ret != SCFGA_OK) {
922*4c06356bSdh 		cfga_err(errstring, *l_errnop, errid, 0);
923*4c06356bSdh 
924*4c06356bSdh 		/*
925*4c06356bSdh 		 * If an unconfigure fails, cancel the RCM offline.
926*4c06356bSdh 		 * Discard any RCM failures so that the devctl
927*4c06356bSdh 		 * failure will still be reported.
928*4c06356bSdh 		 */
929*4c06356bSdh 		if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
930*4c06356bSdh 			if (cmd == SCFGA_DEV_UNCONFIGURE)
931*4c06356bSdh 				(void) scsi_rcm_online(dev_list,
932*4c06356bSdh 				    errstring, flags);
933*4c06356bSdh 		}
934*4c06356bSdh 	}
935*4c06356bSdh 
936*4c06356bSdh 	di_devfs_path_free(client_path);
937*4c06356bSdh 	di_fini(root);
938*4c06356bSdh 	S_FREE(root_path);
939*4c06356bSdh 
940*4c06356bSdh 	return (ret);
941*4c06356bSdh }
942*4c06356bSdh 
943*4c06356bSdh 
9447c478bd9Sstevel@tonic-gate scfga_ret_t
devctl_cmd(const char * physpath,scfga_cmd_t cmd,uint_t * statep,int * l_errnop)9457c478bd9Sstevel@tonic-gate devctl_cmd(
9467c478bd9Sstevel@tonic-gate 	const char	*physpath,
9477c478bd9Sstevel@tonic-gate 	scfga_cmd_t	cmd,
9487c478bd9Sstevel@tonic-gate 	uint_t		*statep,
9497c478bd9Sstevel@tonic-gate 	int		*l_errnop)
9507c478bd9Sstevel@tonic-gate {
9517c478bd9Sstevel@tonic-gate 	int rv = -1, i, type;
9527c478bd9Sstevel@tonic-gate 	devctl_hdl_t hdl = NULL;
9537c478bd9Sstevel@tonic-gate 	char *cp = NULL, *path = NULL;
9547c478bd9Sstevel@tonic-gate 	int (*func)(const devctl_hdl_t);
9557c478bd9Sstevel@tonic-gate 	int (*state_func)(const devctl_hdl_t, uint_t *);
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	*l_errnop = 0;
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	if (statep != NULL) *statep = 0;
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	func = NULL;
9627c478bd9Sstevel@tonic-gate 	state_func = NULL;
9637c478bd9Sstevel@tonic-gate 	type = 0;
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	for (i = 0; i < N_GET_STATE_CMDS; i++) {
9667c478bd9Sstevel@tonic-gate 		if (get_state_cmds[i].cmd == cmd) {
9677c478bd9Sstevel@tonic-gate 			state_func = get_state_cmds[i].state_fcn;
9687c478bd9Sstevel@tonic-gate 			type = get_state_cmds[i].type;
9697c478bd9Sstevel@tonic-gate 			assert(statep != NULL);
9707c478bd9Sstevel@tonic-gate 			break;
9717c478bd9Sstevel@tonic-gate 		}
9727c478bd9Sstevel@tonic-gate 	}
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 	if (state_func == NULL) {
9757c478bd9Sstevel@tonic-gate 		for (i = 0; i < N_SET_STATE_CMDS; i++) {
9767c478bd9Sstevel@tonic-gate 			if (set_state_cmds[i].cmd == cmd) {
9777c478bd9Sstevel@tonic-gate 				func = set_state_cmds[i].fcn;
9787c478bd9Sstevel@tonic-gate 				type = set_state_cmds[i].type;
9797c478bd9Sstevel@tonic-gate 				assert(statep == NULL);
9807c478bd9Sstevel@tonic-gate 				break;
9817c478bd9Sstevel@tonic-gate 			}
9827c478bd9Sstevel@tonic-gate 		}
9837c478bd9Sstevel@tonic-gate 	}
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	assert(type == BUS_OP || type == DEV_OP);
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	if (func == NULL && state_func == NULL) {
9887c478bd9Sstevel@tonic-gate 		return (SCFGA_ERR);
9897c478bd9Sstevel@tonic-gate 	}
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 	/*
9927c478bd9Sstevel@tonic-gate 	 * Fix up path for calling devctl.
9937c478bd9Sstevel@tonic-gate 	 */
9947c478bd9Sstevel@tonic-gate 	if ((path = strdup(physpath)) == NULL) {
9957c478bd9Sstevel@tonic-gate 		*l_errnop = errno;
9967c478bd9Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
9977c478bd9Sstevel@tonic-gate 	}
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	/* Remove dynamic component if any */
10007c478bd9Sstevel@tonic-gate 	if ((cp = GET_DYN(path)) != NULL) {
10017c478bd9Sstevel@tonic-gate 		*cp = '\0';
10027c478bd9Sstevel@tonic-gate 	}
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	/* Remove minor name */
10057c478bd9Sstevel@tonic-gate 	if ((cp = strrchr(path, ':')) != NULL) {
10067c478bd9Sstevel@tonic-gate 		*cp = '\0';
10077c478bd9Sstevel@tonic-gate 	}
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 	errno = 0;
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 	if (type == BUS_OP) {
10127c478bd9Sstevel@tonic-gate 		hdl = devctl_bus_acquire(path, 0);
10137c478bd9Sstevel@tonic-gate 	} else {
10147c478bd9Sstevel@tonic-gate 		hdl = devctl_device_acquire(path, 0);
10157c478bd9Sstevel@tonic-gate 	}
10167c478bd9Sstevel@tonic-gate 	*l_errnop = errno;
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 	S_FREE(path);
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 	if (hdl == NULL) {
10217c478bd9Sstevel@tonic-gate 		return (SCFGA_ERR);
10227c478bd9Sstevel@tonic-gate 	}
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	errno = 0;
10257c478bd9Sstevel@tonic-gate 	/* Only getstate functions require a second argument */
10267c478bd9Sstevel@tonic-gate 	if (func != NULL && statep == NULL) {
10277c478bd9Sstevel@tonic-gate 		rv = func(hdl);
10287c478bd9Sstevel@tonic-gate 		*l_errnop = errno;
10297c478bd9Sstevel@tonic-gate 	} else if (state_func != NULL && statep != NULL) {
10307c478bd9Sstevel@tonic-gate 		rv = state_func(hdl, statep);
10317c478bd9Sstevel@tonic-gate 		*l_errnop = errno;
10327c478bd9Sstevel@tonic-gate 	} else {
10337c478bd9Sstevel@tonic-gate 		rv = -1;
10347c478bd9Sstevel@tonic-gate 		*l_errnop = 0;
10357c478bd9Sstevel@tonic-gate 	}
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	devctl_release(hdl);
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	return ((rv == -1) ? SCFGA_ERR : SCFGA_OK);
10407c478bd9Sstevel@tonic-gate }
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate /*
10437c478bd9Sstevel@tonic-gate  * Is device in a known state ? (One of BUSY, ONLINE, OFFLINE)
10447c478bd9Sstevel@tonic-gate  *	BUSY --> One or more device special files are open. Implies online
10457c478bd9Sstevel@tonic-gate  *	ONLINE --> driver attached
10467c478bd9Sstevel@tonic-gate  *	OFFLINE --> CF1 with offline flag set.
10477c478bd9Sstevel@tonic-gate  *	UNKNOWN --> None of the above
10487c478bd9Sstevel@tonic-gate  */
10497c478bd9Sstevel@tonic-gate int
known_state(di_node_t node)10507c478bd9Sstevel@tonic-gate known_state(di_node_t node)
10517c478bd9Sstevel@tonic-gate {
10527c478bd9Sstevel@tonic-gate 	uint_t state;
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	state = di_state(node);
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	/*
10577c478bd9Sstevel@tonic-gate 	 * CF1 without offline flag set is considered unknown state.
10587c478bd9Sstevel@tonic-gate 	 * We are in a known state if either CF2 (driver attached) or
10597c478bd9Sstevel@tonic-gate 	 * offline.
10607c478bd9Sstevel@tonic-gate 	 */
10617c478bd9Sstevel@tonic-gate 	if ((state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE ||
1062*4c06356bSdh 	    (state & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) {
10637c478bd9Sstevel@tonic-gate 		return (1);
10647c478bd9Sstevel@tonic-gate 	}
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 	return (0);
10677c478bd9Sstevel@tonic-gate }
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate void
list_free(ldata_list_t ** llpp)10707c478bd9Sstevel@tonic-gate list_free(ldata_list_t **llpp)
10717c478bd9Sstevel@tonic-gate {
10727c478bd9Sstevel@tonic-gate 	ldata_list_t *lp, *olp;
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 	lp = *llpp;
10757c478bd9Sstevel@tonic-gate 	while (lp != NULL) {
10767c478bd9Sstevel@tonic-gate 		olp = lp;
10777c478bd9Sstevel@tonic-gate 		lp = olp->next;
10787c478bd9Sstevel@tonic-gate 		S_FREE(olp);
10797c478bd9Sstevel@tonic-gate 	}
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	*llpp = NULL;
10827c478bd9Sstevel@tonic-gate }
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate /*
10857c478bd9Sstevel@tonic-gate  * Obtain the devlink from a /devices path
10867c478bd9Sstevel@tonic-gate  */
10877c478bd9Sstevel@tonic-gate typedef struct walk_link {
10887c478bd9Sstevel@tonic-gate 	char *path;
10897c478bd9Sstevel@tonic-gate 	char len;
10907c478bd9Sstevel@tonic-gate 	char **linkpp;
10917c478bd9Sstevel@tonic-gate } walk_link_t;
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate static int
get_link(di_devlink_t devlink,void * arg)10947c478bd9Sstevel@tonic-gate get_link(di_devlink_t devlink, void *arg)
10957c478bd9Sstevel@tonic-gate {
10967c478bd9Sstevel@tonic-gate 	walk_link_t *larg = (walk_link_t *)arg;
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 	/*
10997c478bd9Sstevel@tonic-gate 	 * When path is specified, it's the node path without minor
11007c478bd9Sstevel@tonic-gate 	 * name. Therefore, the ../.. prefixes needs to be stripped.
11017c478bd9Sstevel@tonic-gate 	 */
11027c478bd9Sstevel@tonic-gate 	if (larg->path) {
11037c478bd9Sstevel@tonic-gate 		char *content = (char *)di_devlink_content(devlink);
11047c478bd9Sstevel@tonic-gate 		char *start = strstr(content, "/devices/");
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate 		/* line content must have minor node */
11077c478bd9Sstevel@tonic-gate 		if (start == NULL ||
11087c478bd9Sstevel@tonic-gate 		    strncmp(start, larg->path, larg->len) != 0 ||
11097c478bd9Sstevel@tonic-gate 		    start[larg->len] != ':')
11107c478bd9Sstevel@tonic-gate 			return (DI_WALK_CONTINUE);
11117c478bd9Sstevel@tonic-gate 	}
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 	*(larg->linkpp) = strdup(di_devlink_path(devlink));
11147c478bd9Sstevel@tonic-gate 	return (DI_WALK_TERMINATE);
11157c478bd9Sstevel@tonic-gate }
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate scfga_ret_t
physpath_to_devlink(char * node_path,char ** logpp,int * l_errnop,int match_minor)11187c478bd9Sstevel@tonic-gate physpath_to_devlink(
11197c478bd9Sstevel@tonic-gate 	char *node_path,
11207c478bd9Sstevel@tonic-gate 	char **logpp,
11217c478bd9Sstevel@tonic-gate 	int *l_errnop,
11227c478bd9Sstevel@tonic-gate 	int match_minor)
11237c478bd9Sstevel@tonic-gate {
11247c478bd9Sstevel@tonic-gate 	walk_link_t larg;
11257c478bd9Sstevel@tonic-gate 	di_devlink_handle_t hdl;
11267c478bd9Sstevel@tonic-gate 	char *minor_path;
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 	if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
11297c478bd9Sstevel@tonic-gate 		*l_errnop = errno;
11307c478bd9Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
11317c478bd9Sstevel@tonic-gate 	}
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate 	*logpp = NULL;
11347c478bd9Sstevel@tonic-gate 	larg.linkpp = logpp;
11357c478bd9Sstevel@tonic-gate 	if (match_minor) {
11367c478bd9Sstevel@tonic-gate 		minor_path = node_path + strlen(DEVICES_DIR);
11377c478bd9Sstevel@tonic-gate 		larg.path = NULL;
11387c478bd9Sstevel@tonic-gate 	} else {
11397c478bd9Sstevel@tonic-gate 		minor_path = NULL;
11407c478bd9Sstevel@tonic-gate 		larg.len = strlen(node_path);
11417c478bd9Sstevel@tonic-gate 		larg.path = node_path;
11427c478bd9Sstevel@tonic-gate 	}
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	(void) di_devlink_walk(hdl, NULL, minor_path, DI_PRIMARY_LINK,
11457c478bd9Sstevel@tonic-gate 	    (void *)&larg, get_link);
11467c478bd9Sstevel@tonic-gate 
114709fe1b16Sdnielsen 	(void) di_devlink_fini(&hdl);
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate 	if (*logpp == NULL)
11507c478bd9Sstevel@tonic-gate 		return (SCFGA_LIB_ERR);
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	return (SCFGA_OK);
11537c478bd9Sstevel@tonic-gate }
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate int
hba_dev_cmp(const char * hba,const char * devpath)11567c478bd9Sstevel@tonic-gate hba_dev_cmp(const char *hba, const char *devpath)
11577c478bd9Sstevel@tonic-gate {
11587c478bd9Sstevel@tonic-gate 	char *cp = NULL;
11597c478bd9Sstevel@tonic-gate 	int rv;
11607c478bd9Sstevel@tonic-gate 	size_t hba_len, dev_len;
11617c478bd9Sstevel@tonic-gate 	char l_hba[MAXPATHLEN], l_dev[MAXPATHLEN];
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate 	(void) snprintf(l_hba, sizeof (l_hba), "%s", hba);
11647c478bd9Sstevel@tonic-gate 	(void) snprintf(l_dev, sizeof (l_dev), "%s", devpath);
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	/* Remove dynamic component if any */
11677c478bd9Sstevel@tonic-gate 	if ((cp = GET_DYN(l_hba)) != NULL) {
11687c478bd9Sstevel@tonic-gate 		*cp = '\0';
11697c478bd9Sstevel@tonic-gate 	}
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 	if ((cp = GET_DYN(l_dev)) != NULL) {
11727c478bd9Sstevel@tonic-gate 		*cp = '\0';
11737c478bd9Sstevel@tonic-gate 	}
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	/* Remove minor names */
11777c478bd9Sstevel@tonic-gate 	if ((cp = strrchr(l_hba, ':')) != NULL) {
11787c478bd9Sstevel@tonic-gate 		*cp = '\0';
11797c478bd9Sstevel@tonic-gate 	}
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 	if ((cp = strrchr(l_dev, ':')) != NULL) {
11827c478bd9Sstevel@tonic-gate 		*cp = '\0';
11837c478bd9Sstevel@tonic-gate 	}
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	hba_len = strlen(l_hba);
11867c478bd9Sstevel@tonic-gate 	dev_len = strlen(l_dev);
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	/* Check if HBA path is component of device path */
11897c478bd9Sstevel@tonic-gate 	if (rv = strncmp(l_hba, l_dev, hba_len)) {
11907c478bd9Sstevel@tonic-gate 		return (rv);
11917c478bd9Sstevel@tonic-gate 	}
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 	/* devpath must have '/' and 1 char in addition to hba path */
11947c478bd9Sstevel@tonic-gate 	if (dev_len >= hba_len + 2 && l_dev[hba_len] == '/') {
11957c478bd9Sstevel@tonic-gate 		return (0);
11967c478bd9Sstevel@tonic-gate 	} else {
11977c478bd9Sstevel@tonic-gate 		return (-1);
11987c478bd9Sstevel@tonic-gate 	}
11997c478bd9Sstevel@tonic-gate }
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate int
dev_cmp(const char * dev1,const char * dev2,int match_minor)12027c478bd9Sstevel@tonic-gate dev_cmp(const char *dev1, const char *dev2, int match_minor)
12037c478bd9Sstevel@tonic-gate {
12047c478bd9Sstevel@tonic-gate 	char l_dev1[MAXPATHLEN], l_dev2[MAXPATHLEN];
12057c478bd9Sstevel@tonic-gate 	char *mn1, *mn2;
12067c478bd9Sstevel@tonic-gate 	int rv;
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 	(void) snprintf(l_dev1, sizeof (l_dev1), "%s", dev1);
12097c478bd9Sstevel@tonic-gate 	(void) snprintf(l_dev2, sizeof (l_dev2), "%s", dev2);
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 	if ((mn1 = GET_DYN(l_dev1)) != NULL) {
12127c478bd9Sstevel@tonic-gate 		*mn1 = '\0';
12137c478bd9Sstevel@tonic-gate 	}
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	if ((mn2 = GET_DYN(l_dev2)) != NULL) {
12167c478bd9Sstevel@tonic-gate 		*mn2 = '\0';
12177c478bd9Sstevel@tonic-gate 	}
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 	/* Separate out the minor names */
12207c478bd9Sstevel@tonic-gate 	if ((mn1 = strrchr(l_dev1, ':')) != NULL) {
12217c478bd9Sstevel@tonic-gate 		*mn1++ = '\0';
12227c478bd9Sstevel@tonic-gate 	}
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 	if ((mn2 = strrchr(l_dev2, ':')) != NULL) {
12257c478bd9Sstevel@tonic-gate 		*mn2++ = '\0';
12267c478bd9Sstevel@tonic-gate 	}
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate 	if ((rv = strcmp(l_dev1, l_dev2)) != 0 || !match_minor) {
12297c478bd9Sstevel@tonic-gate 		return (rv);
12307c478bd9Sstevel@tonic-gate 	}
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 	/*
12337c478bd9Sstevel@tonic-gate 	 * Compare minor names
12347c478bd9Sstevel@tonic-gate 	 */
12357c478bd9Sstevel@tonic-gate 	if (mn1 == NULL && mn2 == NULL) {
12367c478bd9Sstevel@tonic-gate 		return (0);
12377c478bd9Sstevel@tonic-gate 	} else if (mn1 == NULL) {
12387c478bd9Sstevel@tonic-gate 		return (-1);
12397c478bd9Sstevel@tonic-gate 	} else if (mn2 == NULL) {
12407c478bd9Sstevel@tonic-gate 		return (1);
12417c478bd9Sstevel@tonic-gate 	} else {
12427c478bd9Sstevel@tonic-gate 		return (strcmp(mn1, mn2));
12437c478bd9Sstevel@tonic-gate 	}
12447c478bd9Sstevel@tonic-gate }
1245