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