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