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