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