2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include "cfga_scsi.h"
2N/A
2N/A/*
2N/A * This file contains the entry points to the plug-in as defined in the
2N/A * config_admin(3X) man page.
2N/A */
2N/A
2N/A/*
2N/A * Set the version number
2N/A */
2N/Aint cfga_version = CFGA_HSL_V2;
2N/A
2N/A/*
2N/A * For debugging - higher values increase verbosity
2N/A */
2N/Aint _scfga_debug = 0;
2N/A
2N/A#pragma init(_cfgadm_scsi_init)
2N/A
2N/Astatic void
2N/A_cfgadm_scsi_init()
2N/A{
2N/A char *tstr;
2N/A
2N/A if (tstr = getenv("SCFGA_DEBUG")) {
2N/A _scfga_debug = atoi(tstr);
2N/A }
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Acfga_err_t
2N/Acfga_change_state(
2N/A cfga_cmd_t state_change_cmd,
2N/A const char *ap_id,
2N/A const char *options,
2N/A struct cfga_confirm *confp,
2N/A struct cfga_msg *msgp,
2N/A char **errstring,
2N/A cfga_flags_t flags)
2N/A{
2N/A apid_t apidt = {NULL};
2N/A scfga_ret_t ret;
2N/A
2N/A if (errstring != NULL) {
2N/A *errstring = NULL;
2N/A }
2N/A
2N/A /*
2N/A * All sub-commands which can change state of device require
2N/A * root privileges.
2N/A */
2N/A if (geteuid() != 0) {
2N/A return (CFGA_PRIV);
2N/A }
2N/A
2N/A if (options != NULL && strcmp(options, OPT_DISABLE_RCM) != 0) {
2N/A cfga_err(errstring, 0, ERRARG_OPT_INVAL, options, 0);
2N/A return (CFGA_ERROR);
2N/A }
2N/A
2N/A if ((ret = apidt_create(ap_id, &apidt, errstring)) != SCFGA_OK) {
2N/A return (err_cvt(ret));
2N/A }
2N/A
2N/A if (options != NULL)
2N/A apidt.flags |= FLAG_DISABLE_RCM;
2N/A
2N/A /* A dynamic component indicates a device, else it is the bus */
2N/A if (apidt.dyncomp != NULL) {
2N/A ret = dev_change_state(state_change_cmd, &apidt, flags,
2N/A errstring);
2N/A } else {
2N/A ret = bus_change_state(state_change_cmd, &apidt, confp, flags,
2N/A errstring);
2N/A }
2N/A
2N/A apidt_free(&apidt);
2N/A return (err_cvt(ret));
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Acfga_err_t
2N/Acfga_private_func(
2N/A const char *func,
2N/A const char *ap_id,
2N/A const char *options,
2N/A struct cfga_confirm *confp,
2N/A struct cfga_msg *msgp,
2N/A char **errstring,
2N/A cfga_flags_t flags)
2N/A{
2N/A apid_t apidt = {NULL};
2N/A prompt_t args = {NULL};
2N/A scfga_ret_t ret;
2N/A
2N/A if (errstring != NULL)
2N/A *errstring = NULL;
2N/A
2N/A if (geteuid() != 0) {
2N/A return (CFGA_PRIV);
2N/A }
2N/A
2N/A if (func == NULL) {
2N/A return (CFGA_ERROR);
2N/A }
2N/A
2N/A if (options != NULL && strcmp(options, OPT_DISABLE_RCM) != 0) {
2N/A cfga_err(errstring, 0, ERRARG_OPT_INVAL, options, 0);
2N/A return (CFGA_ERROR);
2N/A }
2N/A
2N/A if ((ret = apidt_create(ap_id, &apidt, errstring)) != SCFGA_OK) {
2N/A return (err_cvt(ret));
2N/A }
2N/A
2N/A if (apidt.dyntype == PATH_APID) {
2N/A const char *led = GET_MSG_STR(CMD_LED_DEV);
2N/A const char *locator = GET_MSG_STR(CMD_LOCATOR_DEV);
2N/A
2N/A if (strncmp(func, led, strlen(led)) &&
2N/A strncmp(func, locator, strlen(locator)))
2N/A return (CFGA_OPNOTSUPP);
2N/A }
2N/A
2N/A if (options != NULL)
2N/A apidt.flags |= FLAG_DISABLE_RCM;
2N/A
2N/A args.confp = confp;
2N/A args.msgp = msgp;
2N/A
2N/A /*
2N/A * Process command
2N/A */
2N/A ret = invoke_cmd(func, &apidt, &args, flags, errstring);
2N/A
2N/A apidt_free(&apidt);
2N/A return (err_cvt(ret));
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Acfga_err_t
2N/Acfga_test(
2N/A const char *ap_id,
2N/A const char *options,
2N/A struct cfga_msg *msgp,
2N/A char **errstring,
2N/A cfga_flags_t flags)
2N/A{
2N/A if (errstring != NULL) {
2N/A *errstring = NULL;
2N/A }
2N/A
2N/A if (geteuid() != 0) {
2N/A return (CFGA_PRIV);
2N/A }
2N/A
2N/A return (CFGA_OPNOTSUPP);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Acfga_err_t
2N/Acfga_list_ext(
2N/A const char *ap_id,
2N/A cfga_list_data_t **ap_id_list,
2N/A int *nlistp,
2N/A const char *options,
2N/A const char *listopts,
2N/A char **errstring,
2N/A cfga_flags_t flags)
2N/A{
2N/A int hba, expand, nelem;
2N/A ldata_list_t *llp = NULL;
2N/A apid_t apidt = {NULL};
2N/A scfga_cmd_t cmd;
2N/A scfga_ret_t ret;
2N/A
2N/A if (errstring != NULL) {
2N/A *errstring = NULL;
2N/A }
2N/A
2N/A if (ap_id_list == NULL || nlistp == NULL) {
2N/A return (CFGA_ERROR);
2N/A }
2N/A
2N/A *ap_id_list = NULL;
2N/A *nlistp = 0;
2N/A
2N/A /*
2N/A * There is no RCM involvement in "list" operations.
2N/A * The only supported option is OPT_USE_DIFORCE.
2N/A */
2N/A if (options != NULL && strcmp(options, OPT_USE_DIFORCE) != 0) {
2N/A cfga_err(errstring, 0, ERRARG_OPT_INVAL, options, 0);
2N/A return (CFGA_ERROR);
2N/A }
2N/A
2N/A hba = 0;
2N/A if (GET_DYN(ap_id) == NULL) {
2N/A hba = 1;
2N/A }
2N/A
2N/A expand = 0;
2N/A if ((flags & CFGA_FLAG_LIST_ALL) == CFGA_FLAG_LIST_ALL) {
2N/A expand = 1;
2N/A }
2N/A
2N/A /*
2N/A * We expand published attachment points but not
2N/A * dynamic attachment points
2N/A */
2N/A
2N/A if (!hba) { /* Stat a single device - no expansion for devices */
2N/A cmd = SCFGA_STAT_DEV;
2N/A } else if (!expand) { /* Stat only the HBA */
2N/A cmd = SCFGA_STAT_BUS;
2N/A } else { /* Expand HBA attachment point */
2N/A cmd = SCFGA_STAT_ALL;
2N/A }
2N/A
2N/A if ((ret = apidt_create(ap_id, &apidt, errstring)) != SCFGA_OK) {
2N/A return (err_cvt(ret));
2N/A }
2N/A
2N/A /*
2N/A * Currently only 1 option supported
2N/A */
2N/A if (options)
2N/A apidt.flags |= FLAG_USE_DIFORCE;
2N/A
2N/A llp = NULL;
2N/A nelem = 0;
2N/A
2N/A ret = do_list(&apidt, cmd, &llp, &nelem, errstring);
2N/A if (ret != SCFGA_OK) {
2N/A goto out;
2N/A }
2N/A
2N/A assert(llp != NULL);
2N/A
2N/A if (list_ext_postprocess(&llp, nelem, ap_id_list, nlistp,
2N/A errstring) != SCFGA_OK) {
2N/A assert(*ap_id_list == NULL && *nlistp == 0);
2N/A ret = SCFGA_LIB_ERR;
2N/A } else {
2N/A assert(*ap_id_list != NULL && *nlistp == nelem);
2N/A ret = SCFGA_OK;
2N/A }
2N/A
2N/A /* FALLTHROUGH */
2N/Aout:
2N/A list_free(&llp);
2N/A apidt_free(&apidt);
2N/A return (err_cvt(ret));
2N/A}
2N/A
2N/A
2N/A/*ARGSUSED*/
2N/Acfga_err_t
2N/Acfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
2N/A{
2N/A cfga_msg(msgp, MSG_HELP_HDR, MSG_HELP_USAGE, 0);
2N/A
2N/A return (CFGA_OK);
2N/A}
2N/A
2N/A/*
2N/A * cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm
2N/A */