1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include "cfga_fp.h" 27 28 /* 29 * This file contains the entry points to the plug-in as defined in the 30 * config_admin(3X) man page. 31 */ 32 33 /* 34 * Set the version number 35 */ 36 int cfga_version = CFGA_HSL_V2; 37 38 /*ARGSUSED*/ 39 cfga_err_t 40 cfga_change_state( 41 cfga_cmd_t state_change_cmd, 42 const char *ap_id, 43 const char *options, 44 struct cfga_confirm *confp, 45 struct cfga_msg *msgp, 46 char **errstring, 47 cfga_flags_t flags) 48 { 49 apid_t apidt = {NULL}; 50 fpcfga_ret_t ret; 51 la_wwn_t pwwn; 52 char *value, *hw_option, *hw_option_p; 53 char *fp_cs_hw_opts[] = {"disable_rcm", "force_update", 54 "no_update", "unusable_SCSI_LUN", "unusable_FCP_dev", NULL}; 55 HBA_HANDLE handle; 56 HBA_PORTATTRIBUTES portAttrs; 57 int portIndex; 58 59 if (errstring != NULL) { 60 *errstring = NULL; 61 } 62 63 /* Check for super user priveleges */ 64 if (geteuid() != 0) { 65 return (CFGA_PRIV); 66 } 67 68 /* Only configure and unconfigure operations are supported */ 69 if (state_change_cmd != CFGA_CMD_CONFIGURE && 70 state_change_cmd != CFGA_CMD_UNCONFIGURE) { 71 return (CFGA_OPNOTSUPP); 72 } 73 74 if ((ret = apidt_create(ap_id, &apidt, errstring)) != FPCFGA_OK) { 75 return (err_cvt(ret)); 76 } 77 78 if (options != NULL) { 79 hw_option = calloc(1, strlen(options) + 1); 80 (void) snprintf(hw_option, strlen(options) + 1, "%s", options); 81 hw_option_p = hw_option; 82 /* Use getsubopt() if more options get added */ 83 while (*hw_option_p != '\0') { 84 switch (getsubopt(&hw_option_p, fp_cs_hw_opts, 85 &value)) { 86 case OPT_DISABLE_RCM : 87 apidt.flags |= FLAG_DISABLE_RCM; 88 break; 89 case OPT_FORCE_UPDATE_REP : 90 apidt.flags |= FLAG_FORCE_UPDATE_REP; 91 break; 92 case OPT_NO_UPDATE_REP : 93 apidt.flags |= FLAG_NO_UPDATE_REP; 94 break; 95 case OPT_REMOVE_UNUSABLE_FCP_DEV : 96 case OPT_REMOVE_UNUSABLE_SCSI_LUN: 97 if (state_change_cmd != CFGA_CMD_UNCONFIGURE) { 98 cfga_err(errstring, 0, ERRARG_OPT_INVAL, 99 options, 0); 100 S_FREE(hw_option); 101 apidt_free(&apidt); 102 return (CFGA_ERROR); 103 } 104 apidt.flags |= FLAG_REMOVE_UNUSABLE_FCP_DEV; 105 break; 106 default : 107 /* process unknonw option. */ 108 cfga_err(errstring, 0, ERRARG_OPT_INVAL, 109 options, 0); 110 S_FREE(hw_option); 111 apidt_free(&apidt); 112 return (CFGA_ERROR); 113 } 114 } 115 S_FREE(hw_option); 116 } 117 118 if (options != NULL && apidt.flags == 0) { 119 /* invalid option specified. */ 120 cfga_err(errstring, 0, ERRARG_OPT_INVAL, options, 0); 121 apidt_free(&apidt); 122 return (CFGA_ERROR); 123 } 124 125 if (apidt.dyncomp != NULL) { /* Was there a port WWN passed ? */ 126 /* 127 * Yes - so change state of the particular device 128 * 129 * First Get the WWN in la_wwn_t form 130 */ 131 if (cvt_dyncomp_to_lawwn(apidt.dyncomp, &pwwn)) { 132 cfga_err(errstring, 0, ERR_APID_INVAL, 0); 133 return (err_cvt(FPCFGA_LIB_ERR)); 134 } 135 136 if ((ret = findMatchingAdapterPort(apidt.xport_phys, 137 &handle, &portIndex, &portAttrs, errstring)) == 138 FPCFGA_OK) { 139 ret = dev_change_state(state_change_cmd, &apidt, &pwwn, 140 flags, errstring, handle, portAttrs); 141 HBA_CloseAdapter(handle); 142 HBA_FreeLibrary(); 143 } 144 } else { 145 /* Change state of all devices on FCA and the FCA itself */ 146 ret = fca_change_state(state_change_cmd, &apidt, 147 flags, errstring); 148 } 149 150 apidt_free(&apidt); 151 return (err_cvt(ret)); 152 } 153 154 155 /*ARGSUSED*/ 156 cfga_err_t 157 cfga_private_func( 158 const char *func, 159 const char *ap_id, 160 const char *options, 161 struct cfga_confirm *confp, 162 struct cfga_msg *msgp, 163 char **errstring, 164 cfga_flags_t flags) 165 { 166 if (errstring != NULL) { 167 *errstring = NULL; 168 } 169 170 if (geteuid() != 0) { 171 return (CFGA_PRIV); 172 } 173 174 return (CFGA_OPNOTSUPP); 175 } 176 177 178 /*ARGSUSED*/ 179 cfga_err_t 180 cfga_test( 181 const char *ap_id, 182 const char *options, 183 struct cfga_msg *msgp, 184 char **errstring, 185 cfga_flags_t flags) 186 { 187 if (errstring != NULL) { 188 *errstring = NULL; 189 } 190 191 if (geteuid() != 0) { 192 return (CFGA_PRIV); 193 } 194 195 return (CFGA_OPNOTSUPP); 196 } 197 198 199 /*ARGSUSED*/ 200 cfga_err_t 201 cfga_list_ext( 202 const char *ap_id, 203 cfga_list_data_t **ap_id_list, 204 int *nlistp, 205 const char *options, 206 const char *listopts, 207 char **errstring, 208 cfga_flags_t flags) 209 { 210 int fca, expand, nelem; 211 ldata_list_t *ldatalistp = NULL; 212 apid_t apidt = {NULL}; 213 fpcfga_cmd_t cmd; 214 fpcfga_ret_t ret; 215 char *value, *hw_option, *hw_option_p; 216 uint_t fp_flags = 0; 217 char *fp_list_hw_opts[] = {"devinfo_force", "show_SCSI_LUN", 218 "show_FCP_dev", NULL}; 219 220 if (errstring != NULL) { 221 *errstring = NULL; 222 } 223 224 /* Check for super user privileges */ 225 if (geteuid() != 0) { 226 return (CFGA_PRIV); 227 } 228 229 if (ap_id_list == NULL || nlistp == NULL) { 230 return (CFGA_ERROR); 231 } 232 233 *ap_id_list = NULL; 234 *nlistp = 0; 235 236 if (options != NULL) { 237 hw_option = calloc(1, strlen(options) + 1); 238 (void) snprintf(hw_option, strlen(options) + 1, "%s", options); 239 hw_option_p = hw_option; 240 /* Use getsubopt() if more options get added */ 241 while (*hw_option_p != '\0') { 242 switch (getsubopt(&hw_option_p, fp_list_hw_opts, 243 &value)) { 244 case OPT_DEVINFO_FORCE : 245 fp_flags |= FLAG_DEVINFO_FORCE; 246 break; 247 case OPT_FCP_DEV : 248 case OPT_SHOW_SCSI_LUN: 249 fp_flags |= FLAG_FCP_DEV; 250 break; 251 default : 252 /* process unknonw option. */ 253 cfga_err(errstring, 0, ERRARG_OPT_INVAL, 254 options, 0); 255 S_FREE(hw_option); 256 return (CFGA_ERROR); 257 } 258 } 259 S_FREE(hw_option); 260 } 261 262 /* if force_devinfo is specified check uid = 0 or not. */ 263 if (((fp_flags & FLAG_DEVINFO_FORCE) == FLAG_DEVINFO_FORCE) && 264 (geteuid() != 0)) { 265 return (CFGA_PRIV); 266 } 267 268 fca = 0; 269 if (GET_DYN(ap_id) == NULL) { 270 fca = 1; 271 } 272 273 expand = 0; 274 if ((flags & CFGA_FLAG_LIST_ALL) == CFGA_FLAG_LIST_ALL) { 275 expand = 1; 276 } 277 278 /* 279 * We expand published attachment points but not 280 * dynamic attachment points 281 */ 282 283 if (!fca) { /* Stat a single device - no expansion for devices */ 284 cmd = FPCFGA_STAT_FC_DEV; 285 } else if (!expand) { /* Stat only the HBA */ 286 cmd = FPCFGA_STAT_FCA_PORT; 287 } else { /* Expand HBA attachment point */ 288 cmd = FPCFGA_STAT_ALL; 289 } 290 291 ldatalistp = NULL; 292 nelem = 0; 293 294 if ((fp_flags & FLAG_FCP_DEV) == FLAG_FCP_DEV) { 295 ret = do_list_FCP_dev(ap_id, fp_flags, cmd, &ldatalistp, &nelem, 296 errstring); 297 if (ret != FPCFGA_OK) { 298 list_free(&ldatalistp); 299 return (err_cvt(ret)); 300 } 301 } else { 302 if ((ret = apidt_create(ap_id, &apidt, errstring)) 303 != FPCFGA_OK) { 304 return (err_cvt(ret)); 305 } 306 307 if (options != NULL) { 308 apidt.flags |= fp_flags; 309 } 310 311 ret = do_list(&apidt, cmd, &ldatalistp, &nelem, errstring); 312 if (ret != FPCFGA_OK) { 313 list_free(&ldatalistp); 314 apidt_free(&apidt); 315 return (err_cvt(ret)); 316 } 317 apidt_free(&apidt); 318 } 319 320 assert(ldatalistp != NULL); 321 322 if (list_ext_postprocess(&ldatalistp, nelem, ap_id_list, nlistp, 323 errstring) != FPCFGA_OK) { 324 assert(*ap_id_list == NULL && *nlistp == 0); 325 ret = FPCFGA_LIB_ERR; 326 } else { 327 assert(*ap_id_list != NULL && *nlistp == nelem); 328 ret = FPCFGA_OK; 329 } 330 331 list_free(&ldatalistp); 332 return (err_cvt(ret)); 333 } 334 335 336 /*ARGSUSED*/ 337 cfga_err_t 338 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags) 339 { 340 cfga_msg(msgp, MSG_HELP_HDR, MSG_HELP_USAGE, 0); 341 342 return (CFGA_OK); 343 344 } 345 346 /*ARGSUSED*/ 347 int 348 cfga_ap_id_cmp(const char *ap_id1, const char *ap_id2) 349 { 350 int i = 0; 351 long long ret; 352 353 if (ap_id1 == ap_id2) { 354 return (0); 355 } 356 357 if (ap_id1 == NULL || ap_id2 == NULL) { 358 if (ap_id1 == NULL) { 359 /* Return a negative value */ 360 return (0 - (uchar_t)ap_id2[0]); 361 } else { 362 return ((uchar_t)ap_id1[0]); 363 } 364 } 365 366 /* 367 * Search for first different char 368 */ 369 while (ap_id1[i] == ap_id2[i] && ap_id1[i] != '\0') 370 i++; 371 372 if ((ap_id1[i] == '\0') && 373 !(strncmp(&ap_id2[i], LUN_COMP_SEP, strlen(LUN_COMP_SEP)))) { 374 return (0); 375 } else if ((ap_id2[i] == '\0') && 376 !(strncmp(&ap_id1[i], LUN_COMP_SEP, strlen(LUN_COMP_SEP)))) { 377 return (0); 378 } 379 380 /* 381 * If one of the char is a digit, back up to where the 382 * number started, compare the number. 383 */ 384 if (isxdigit(ap_id1[i]) || isxdigit(ap_id2[i])) { 385 while ((i > 0) && isxdigit(ap_id1[i - 1])) 386 i--; 387 388 if (isxdigit(ap_id1[i]) && isxdigit(ap_id2[i])) { 389 ret = (strtoll((ap_id1 + i), NULL, 16)) - 390 (strtoll((ap_id2 + i), NULL, 16)); 391 if (ret > 0) { 392 return (1); 393 } else if (ret < 0) { 394 return (-1); 395 } else { 396 return (0); 397 } 398 } 399 } 400 401 /* One of them isn't a number, compare the char */ 402 return (ap_id1[i] - ap_id2[i]); 403 } 404