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 2008 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A
2N/A
2N/A
2N/A#include "cfga_fp.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/*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 fpcfga_ret_t ret;
2N/A la_wwn_t pwwn;
2N/A char *value, *hw_option, *hw_option_p;
2N/A char *fp_cs_hw_opts[] = {"disable_rcm", "force_update",
2N/A "no_update", "unusable_SCSI_LUN", "unusable_FCP_dev", NULL};
2N/A HBA_HANDLE handle;
2N/A HBA_PORTATTRIBUTES portAttrs;
2N/A int portIndex;
2N/A
2N/A if (errstring != NULL) {
2N/A *errstring = NULL;
2N/A }
2N/A
2N/A /* Check for super user priveleges */
2N/A if (geteuid() != 0) {
2N/A return (CFGA_PRIV);
2N/A }
2N/A
2N/A /* Only configure and unconfigure operations are supported */
2N/A if (state_change_cmd != CFGA_CMD_CONFIGURE &&
2N/A state_change_cmd != CFGA_CMD_UNCONFIGURE) {
2N/A return (CFGA_OPNOTSUPP);
2N/A }
2N/A
2N/A if ((ret = apidt_create(ap_id, &apidt, errstring)) != CFGA_OK) {
2N/A return (err_cvt(ret));
2N/A }
2N/A
2N/A if (options != NULL) {
2N/A hw_option = calloc(1, strlen(options) + 1);
2N/A (void) snprintf(hw_option, strlen(options) + 1, "%s", options);
2N/A hw_option_p = hw_option;
2N/A /* Use getsubopt() if more options get added */
2N/A while (*hw_option_p != '\0') {
2N/A switch (getsubopt(&hw_option_p, fp_cs_hw_opts, &value)) {
2N/A case OPT_DISABLE_RCM :
2N/A apidt.flags |= FLAG_DISABLE_RCM;
2N/A break;
2N/A case OPT_FORCE_UPDATE_REP :
2N/A apidt.flags |= FLAG_FORCE_UPDATE_REP;
2N/A break;
2N/A case OPT_NO_UPDATE_REP :
2N/A apidt.flags |= FLAG_NO_UPDATE_REP;
2N/A break;
2N/A case OPT_REMOVE_UNUSABLE_FCP_DEV :
2N/A case OPT_REMOVE_UNUSABLE_SCSI_LUN:
2N/A if (state_change_cmd != CFGA_CMD_UNCONFIGURE) {
2N/A cfga_err(errstring, 0, ERRARG_OPT_INVAL,
2N/A options, 0);
2N/A S_FREE(hw_option);
2N/A apidt_free(&apidt);
2N/A return (CFGA_ERROR);
2N/A }
2N/A apidt.flags |= FLAG_REMOVE_UNUSABLE_FCP_DEV;
2N/A break;
2N/A default :
2N/A /* process unknonw option. */
2N/A cfga_err(errstring, 0, ERRARG_OPT_INVAL,
2N/A options, 0);
2N/A S_FREE(hw_option);
2N/A apidt_free(&apidt);
2N/A return (CFGA_ERROR);
2N/A }
2N/A }
2N/A S_FREE(hw_option);
2N/A }
2N/A
2N/A if (options != NULL && apidt.flags == 0) {
2N/A /* invalid option specified. */
2N/A cfga_err(errstring, 0, ERRARG_OPT_INVAL, options, 0);
2N/A apidt_free(&apidt);
2N/A return (CFGA_ERROR);
2N/A }
2N/A
2N/A if (apidt.dyncomp != NULL) { /* Was there a port WWN passed ? */
2N/A /*
2N/A * Yes - so change state of the particular device
2N/A *
2N/A * First Get the WWN in la_wwn_t form
2N/A */
2N/A if (cvt_dyncomp_to_lawwn(apidt.dyncomp, &pwwn)) {
2N/A cfga_err(errstring, 0, ERR_APID_INVAL, 0);
2N/A return (err_cvt(FPCFGA_LIB_ERR));
2N/A }
2N/A
2N/A if ((ret = findMatchingAdapterPort(apidt.xport_phys,
2N/A &handle, &portIndex, &portAttrs, errstring)) ==
2N/A FPCFGA_OK) {
2N/A ret = dev_change_state(state_change_cmd, &apidt, &pwwn,
2N/A flags, errstring, handle, portAttrs);
2N/A HBA_CloseAdapter(handle);
2N/A HBA_FreeLibrary();
2N/A }
2N/A } else {
2N/A /* Change state of all devices on FCA and the FCA itself */
2N/A ret = fca_change_state(state_change_cmd, &apidt,
2N/A flags, errstring);
2N/A }
2N/A
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_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 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
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
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 fca, expand, nelem;
2N/A ldata_list_t *ldatalistp = NULL;
2N/A apid_t apidt = {NULL};
2N/A fpcfga_cmd_t cmd;
2N/A fpcfga_ret_t ret;
2N/A char *value, *hw_option, *hw_option_p;
2N/A uint_t fp_flags = 0;
2N/A char *fp_list_hw_opts[] = {"devinfo_force", "show_SCSI_LUN",
2N/A "show_FCP_dev", NULL};
2N/A
2N/A if (errstring != NULL) {
2N/A *errstring = NULL;
2N/A }
2N/A
2N/A /* Check for super user privileges */
2N/A if (geteuid() != 0) {
2N/A return (CFGA_PRIV);
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 if (options != NULL) {
2N/A hw_option = calloc(1, strlen(options) + 1);
2N/A (void) snprintf(hw_option, strlen(options) + 1, "%s", options);
2N/A hw_option_p = hw_option;
2N/A /* Use getsubopt() if more options get added */
2N/A while (*hw_option_p != '\0') {
2N/A switch (getsubopt(&hw_option_p, fp_list_hw_opts, &value)) {
2N/A case OPT_DEVINFO_FORCE :
2N/A fp_flags |= FLAG_DEVINFO_FORCE;
2N/A break;
2N/A case OPT_FCP_DEV :
2N/A case OPT_SHOW_SCSI_LUN:
2N/A fp_flags |= FLAG_FCP_DEV;
2N/A break;
2N/A default :
2N/A /* process unknonw option. */
2N/A cfga_err(errstring, 0, ERRARG_OPT_INVAL,
2N/A options, 0);
2N/A S_FREE(hw_option);
2N/A return (CFGA_ERROR);
2N/A }
2N/A }
2N/A S_FREE(hw_option);
2N/A }
2N/A
2N/A /* if force_devinfo is specified check uid = 0 or not. */
2N/A if (((fp_flags & FLAG_DEVINFO_FORCE) == FLAG_DEVINFO_FORCE) &&
2N/A (geteuid() != 0)) {
2N/A return (CFGA_PRIV);
2N/A }
2N/A
2N/A fca = 0;
2N/A if (GET_DYN(ap_id) == NULL) {
2N/A fca = 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 (!fca) { /* Stat a single device - no expansion for devices */
2N/A cmd = FPCFGA_STAT_FC_DEV;
2N/A } else if (!expand) { /* Stat only the HBA */
2N/A cmd = FPCFGA_STAT_FCA_PORT;
2N/A } else { /* Expand HBA attachment point */
2N/A cmd = FPCFGA_STAT_ALL;
2N/A }
2N/A
2N/A ldatalistp = NULL;
2N/A nelem = 0;
2N/A
2N/A if ((fp_flags & FLAG_FCP_DEV) == FLAG_FCP_DEV) {
2N/A ret = do_list_FCP_dev(ap_id, fp_flags, cmd, &ldatalistp, &nelem,
2N/A errstring);
2N/A if (ret != FPCFGA_OK) {
2N/A list_free(&ldatalistp);
2N/A return (err_cvt(ret));
2N/A }
2N/A } else {
2N/A if ((ret = apidt_create(ap_id, &apidt, errstring))
2N/A != FPCFGA_OK) {
2N/A return (err_cvt(ret));
2N/A }
2N/A
2N/A if (options != NULL) {
2N/A apidt.flags |= fp_flags;
2N/A }
2N/A
2N/A ret = do_list(&apidt, cmd, &ldatalistp, &nelem, errstring);
2N/A if (ret != FPCFGA_OK) {
2N/A list_free(&ldatalistp);
2N/A apidt_free(&apidt);
2N/A return (err_cvt(ret));
2N/A }
2N/A apidt_free(&apidt);
2N/A }
2N/A
2N/A assert(ldatalistp != NULL);
2N/A
2N/A if (list_ext_postprocess(&ldatalistp, nelem, ap_id_list, nlistp,
2N/A errstring) != FPCFGA_OK) {
2N/A assert(*ap_id_list == NULL && *nlistp == 0);
2N/A ret = FPCFGA_LIB_ERR;
2N/A } else {
2N/A assert(*ap_id_list != NULL && *nlistp == nelem);
2N/A ret = FPCFGA_OK;
2N/A }
2N/A
2N/A list_free(&ldatalistp);
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/*ARGSUSED*/
2N/Aint
2N/Acfga_ap_id_cmp(const char *ap_id1, const char *ap_id2)
2N/A{
2N/A int i = 0;
2N/A long long ret;
2N/A
2N/A if (ap_id1 == ap_id2) {
2N/A return (0);
2N/A }
2N/A
2N/A if (ap_id1 == NULL || ap_id2 == NULL) {
2N/A if (ap_id1 == NULL) {
2N/A /* Return a negative value */
2N/A return (0 - (uchar_t)ap_id2[0]);
2N/A } else {
2N/A return ((uchar_t)ap_id1[0]);
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Search for first different char
2N/A */
2N/A while (ap_id1[i] == ap_id2[i] && ap_id1[i] != '\0')
2N/A i++;
2N/A
2N/A if ((ap_id1[i] == '\0') &&
2N/A !(strncmp(&ap_id2[i], LUN_COMP_SEP, strlen(LUN_COMP_SEP)))) {
2N/A return (0);
2N/A } else if ((ap_id2[i] == '\0') &&
2N/A !(strncmp(&ap_id1[i], LUN_COMP_SEP, strlen(LUN_COMP_SEP)))) {
2N/A return (0);
2N/A }
2N/A
2N/A /*
2N/A * If one of the char is a digit, back up to where the
2N/A * number started, compare the number.
2N/A */
2N/A if (isxdigit(ap_id1[i]) || isxdigit(ap_id2[i])) {
2N/A while ((i > 0) && isxdigit(ap_id1[i - 1]))
2N/A i--;
2N/A
2N/A if (isxdigit(ap_id1[i]) && isxdigit(ap_id2[i])) {
2N/A ret = (strtoll((ap_id1 + i), NULL, 16)) -
2N/A (strtoll((ap_id2 + i), NULL, 16));
2N/A if (ret > 0) {
2N/A return (1);
2N/A } else if (ret < 0) {
2N/A return (-1);
2N/A } else {
2N/A return (0);
2N/A }
2N/A }
2N/A }
2N/A
2N/A /* One of them isn't a number, compare the char */
2N/A return (ap_id1[i] - ap_id2[i]);
2N/A}