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