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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdlib.h> 27 #include <stdio.h> 28 #include <wchar.h> 29 #include <strings.h> 30 #include <sys/types.h> 31 #include <sys/stat.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 #include <libintl.h> 35 #include <errno.h> 36 #include <string.h> 37 #include <assert.h> 38 #include <syslog.h> 39 #include <libfcoe.h> 40 #include <libdllink.h> 41 #include <fcoeio.h> 42 #include <libscf.h> 43 #include <inttypes.h> 44 45 #define FCOE_DEV_PATH "/devices/fcoe:admin" 46 47 #define OPEN_FCOE 0 48 #define OPEN_EXCL_FCOE O_EXCL 49 50 /* 51 * Open for fcoe module 52 * 53 * flag - open flag (OPEN_FCOE, OPEN_EXCL_FCOE) 54 * fd - pointer to integer. On success, contains the fcoe file descriptor 55 */ 56 static int 57 openFcoe(int flag, int *fd) 58 { 59 int ret = FCOE_STATUS_ERROR; 60 61 if ((*fd = open(FCOE_DEV_PATH, O_NDELAY | O_RDONLY | flag)) != -1) { 62 ret = FCOE_STATUS_OK; 63 } else { 64 if (errno == EPERM || errno == EACCES) { 65 ret = FCOE_STATUS_ERROR_PERM; 66 } else { 67 ret = FCOE_STATUS_ERROR_OPEN_DEV; 68 } 69 syslog(LOG_DEBUG, "openFcoe:open failure:%s:errno(%d)", 70 FCOE_DEV_PATH, errno); 71 } 72 73 return (ret); 74 } 75 76 static void 77 WWN2str(char *buf, FCOE_PORT_WWN *wwn) { 78 int j; 79 unsigned char *pc = (unsigned char *)&(wwn->wwn[0]); 80 buf[0] = '\0'; 81 for (j = 0; j < 16; j += 2) { 82 (void) sprintf(&buf[j], "%02X", (int)*pc++); 83 } 84 } 85 86 static int 87 isWWNZero(FCOE_PORT_WWN portwwn) 88 { 89 int i; 90 int size = sizeof (FCOE_PORT_WWN); 91 92 for (i = 0; i < size; i++) { 93 if (portwwn.wwn[i] != 0) { 94 return (0); 95 } 96 } 97 return (1); 98 } 99 100 /* 101 * Initialize scf fcoe service access 102 * handle - returned handle 103 * service - returned service handle 104 */ 105 static int 106 fcoe_cfg_scf_init(scf_handle_t **handle, scf_service_t **service, int is_target) 107 { 108 scf_scope_t *scope = NULL; 109 int ret; 110 111 if ((*handle = scf_handle_create(SCF_VERSION)) == NULL) { 112 syslog(LOG_ERR, "scf_handle_create failed - %s", 113 scf_strerror(scf_error())); 114 ret = FCOE_ERROR; 115 goto err; 116 } 117 118 if (scf_handle_bind(*handle) == -1) { 119 syslog(LOG_ERR, "scf_handle_bind failed - %s", 120 scf_strerror(scf_error())); 121 ret = FCOE_ERROR; 122 goto err; 123 } 124 125 if ((*service = scf_service_create(*handle)) == NULL) { 126 syslog(LOG_ERR, "scf_service_create failed - %s", 127 scf_strerror(scf_error())); 128 ret = FCOE_ERROR; 129 goto err; 130 } 131 132 if ((scope = scf_scope_create(*handle)) == NULL) { 133 syslog(LOG_ERR, "scf_scope_create failed - %s", 134 scf_strerror(scf_error())); 135 ret = FCOE_ERROR; 136 goto err; 137 } 138 139 if (scf_handle_get_scope(*handle, SCF_SCOPE_LOCAL, scope) == -1) { 140 syslog(LOG_ERR, "scf_handle_get_scope failed - %s", 141 scf_strerror(scf_error())); 142 ret = FCOE_ERROR; 143 goto err; 144 } 145 146 if (scf_scope_get_service(scope, 147 is_target ? FCOE_TARGET_SERVICE: FCOE_INITIATOR_SERVICE, 148 *service) == -1) { 149 syslog(LOG_ERR, "scf_scope_get_service failed - %s", 150 scf_strerror(scf_error())); 151 ret = FCOE_ERROR_SERVICE_NOT_FOUND; 152 goto err; 153 } 154 155 scf_scope_destroy(scope); 156 157 return (FCOE_SUCCESS); 158 159 err: 160 if (*handle != NULL) { 161 scf_handle_destroy(*handle); 162 } 163 if (*service != NULL) { 164 scf_service_destroy(*service); 165 *service = NULL; 166 } 167 if (scope != NULL) { 168 scf_scope_destroy(scope); 169 } 170 return (ret); 171 } 172 173 static int 174 fcoe_add_remove_scf_entry(char *mac_name, 175 char *pwwn, char *nwwn, 176 int is_target, int is_promiscuous, int addRemoveFlag) 177 { 178 scf_handle_t *handle = NULL; 179 scf_service_t *svc = NULL; 180 scf_propertygroup_t *pg = NULL; 181 scf_transaction_t *tran = NULL; 182 scf_transaction_entry_t *entry = NULL; 183 scf_property_t *prop = NULL; 184 scf_value_t *valueLookup = NULL; 185 scf_iter_t *valueIter = NULL; 186 scf_value_t **valueSet = NULL; 187 int ret = FCOE_SUCCESS; 188 boolean_t createProp = B_FALSE; 189 int lastAlloc = 0; 190 char buf[FCOE_PORT_LIST_LENGTH] = {0}; 191 char memberName[FCOE_PORT_LIST_LENGTH] = {0}; 192 boolean_t found = B_FALSE; 193 int i = 0; 194 int valueArraySize = 0; 195 int commitRet; 196 int portListAlloc = 100; 197 198 (void) snprintf(memberName, FCOE_PORT_LIST_LENGTH, 199 "%s:%s:%s:%d:%d", mac_name, pwwn, nwwn, 200 is_target, is_promiscuous); 201 202 ret = fcoe_cfg_scf_init(&handle, &svc, is_target); 203 if (ret != FCOE_SUCCESS) { 204 goto out; 205 } 206 207 if (((pg = scf_pg_create(handle)) == NULL) || 208 ((tran = scf_transaction_create(handle)) == NULL) || 209 ((entry = scf_entry_create(handle)) == NULL) || 210 ((prop = scf_property_create(handle)) == NULL) || 211 ((valueIter = scf_iter_create(handle)) == NULL)) { 212 ret = FCOE_ERROR; 213 goto out; 214 } 215 216 /* get property group or create it */ 217 if (scf_service_get_pg(svc, FCOE_PG_NAME, pg) == -1) { 218 if ((scf_error() == SCF_ERROR_NOT_FOUND)) { 219 if (scf_service_add_pg(svc, FCOE_PG_NAME, 220 SCF_GROUP_APPLICATION, 0, pg) == -1) { 221 syslog(LOG_ERR, "add pg failed - %s", 222 scf_strerror(scf_error())); 223 ret = FCOE_ERROR; 224 } else { 225 createProp = B_TRUE; 226 } 227 } else { 228 syslog(LOG_ERR, "get pg failed - %s", 229 scf_strerror(scf_error())); 230 ret = FCOE_ERROR; 231 } 232 if (ret != FCOE_SUCCESS) { 233 goto out; 234 } 235 } 236 237 /* to make sure property exists */ 238 if (createProp == B_FALSE) { 239 if (scf_pg_get_property(pg, FCOE_PORT_LIST, prop) == -1) { 240 if ((scf_error() == SCF_ERROR_NOT_FOUND)) { 241 createProp = B_TRUE; 242 } else { 243 syslog(LOG_ERR, "get property failed - %s", 244 scf_strerror(scf_error())); 245 ret = FCOE_ERROR; 246 goto out; 247 } 248 } 249 } 250 251 /* Begin the transaction */ 252 if (scf_transaction_start(tran, pg) == -1) { 253 syslog(LOG_ERR, "start transaction failed - %s", 254 scf_strerror(scf_error())); 255 ret = FCOE_ERROR; 256 goto out; 257 } 258 259 valueSet = (scf_value_t **)calloc(1, sizeof (*valueSet) 260 * (lastAlloc = portListAlloc)); 261 if (valueSet == NULL) { 262 ret = FCOE_ERROR_NOMEM; 263 goto out; 264 } 265 266 if (createProp) { 267 if (scf_transaction_property_new(tran, entry, FCOE_PORT_LIST, 268 SCF_TYPE_USTRING) == -1) { 269 if (scf_error() == SCF_ERROR_EXISTS) { 270 ret = FCOE_ERROR_EXISTS; 271 } else { 272 syslog(LOG_ERR, 273 "transaction property new failed - %s", 274 scf_strerror(scf_error())); 275 ret = FCOE_ERROR; 276 } 277 goto out; 278 } 279 } else { 280 if (scf_transaction_property_change(tran, entry, 281 FCOE_PORT_LIST, SCF_TYPE_USTRING) == -1) { 282 syslog(LOG_ERR, 283 "transaction property change failed - %s", 284 scf_strerror(scf_error())); 285 ret = FCOE_ERROR; 286 goto out; 287 } 288 289 if (scf_pg_get_property(pg, FCOE_PORT_LIST, prop) == -1) { 290 syslog(LOG_ERR, "get property failed - %s", 291 scf_strerror(scf_error())); 292 ret = FCOE_ERROR; 293 goto out; 294 } 295 296 valueLookup = scf_value_create(handle); 297 if (valueLookup == NULL) { 298 syslog(LOG_ERR, "scf value alloc failed - %s", 299 scf_strerror(scf_error())); 300 ret = FCOE_ERROR; 301 goto out; 302 } 303 304 if (scf_iter_property_values(valueIter, prop) == -1) { 305 syslog(LOG_ERR, "iter value failed - %s", 306 scf_strerror(scf_error())); 307 ret = FCOE_ERROR; 308 goto out; 309 } 310 311 while (scf_iter_next_value(valueIter, valueLookup) == 1) { 312 char *macnameIter = NULL; 313 char buftmp[FCOE_PORT_LIST_LENGTH] = {0}; 314 315 bzero(buf, sizeof (buf)); 316 if (scf_value_get_ustring(valueLookup, 317 buf, MAXNAMELEN) == -1) { 318 syslog(LOG_ERR, "iter value failed- %s", 319 scf_strerror(scf_error())); 320 ret = FCOE_ERROR; 321 break; 322 } 323 (void) strcpy(buftmp, buf); 324 macnameIter = strtok(buftmp, ":"); 325 if (strcmp(macnameIter, mac_name) == 0) { 326 if (addRemoveFlag == FCOE_SCF_ADD) { 327 ret = FCOE_ERROR_EXISTS; 328 break; 329 } else { 330 found = B_TRUE; 331 continue; 332 } 333 } 334 335 valueSet[i] = scf_value_create(handle); 336 if (valueSet[i] == NULL) { 337 syslog(LOG_ERR, "scf value alloc failed - %s", 338 scf_strerror(scf_error())); 339 ret = FCOE_ERROR; 340 break; 341 } 342 343 if (scf_value_set_ustring(valueSet[i], buf) == -1) { 344 syslog(LOG_ERR, "set value failed 1- %s", 345 scf_strerror(scf_error())); 346 ret = FCOE_ERROR; 347 break; 348 } 349 350 if (scf_entry_add_value(entry, valueSet[i]) == -1) { 351 syslog(LOG_ERR, "add value failed - %s", 352 scf_strerror(scf_error())); 353 ret = FCOE_ERROR; 354 break; 355 } 356 357 i++; 358 359 if (i >= lastAlloc) { 360 lastAlloc += portListAlloc; 361 valueSet = realloc(valueSet, 362 sizeof (*valueSet) * lastAlloc); 363 if (valueSet == NULL) { 364 ret = FCOE_ERROR; 365 break; 366 } 367 } 368 } 369 } 370 371 valueArraySize = i; 372 if (!found && (addRemoveFlag == FCOE_SCF_REMOVE)) { 373 ret = FCOE_ERROR_MEMBER_NOT_FOUND; 374 } 375 if (ret != FCOE_SUCCESS) { 376 goto out; 377 } 378 379 if (addRemoveFlag == FCOE_SCF_ADD) { 380 /* 381 * Now create the new entry 382 */ 383 valueSet[i] = scf_value_create(handle); 384 if (valueSet[i] == NULL) { 385 syslog(LOG_ERR, "scf value alloc failed - %s", 386 scf_strerror(scf_error())); 387 ret = FCOE_ERROR; 388 goto out; 389 } else { 390 valueArraySize++; 391 } 392 393 /* 394 * Set the new member name 395 */ 396 if (scf_value_set_ustring(valueSet[i], memberName) == -1) { 397 syslog(LOG_ERR, "set value failed 2- %s", 398 scf_strerror(scf_error())); 399 ret = FCOE_ERROR; 400 goto out; 401 } 402 403 /* 404 * Add the new member 405 */ 406 if (scf_entry_add_value(entry, valueSet[i]) == -1) { 407 syslog(LOG_ERR, "add value failed - %s", 408 scf_strerror(scf_error())); 409 ret = FCOE_ERROR; 410 goto out; 411 } 412 } 413 414 if ((commitRet = scf_transaction_commit(tran)) != 1) { 415 syslog(LOG_ERR, "transaction commit failed - %s", 416 scf_strerror(scf_error())); 417 if (commitRet == 0) { 418 ret = FCOE_ERROR_BUSY; 419 } else { 420 ret = FCOE_ERROR; 421 } 422 goto out; 423 } 424 425 out: 426 /* 427 * Free resources 428 */ 429 if (handle != NULL) { 430 scf_handle_destroy(handle); 431 } 432 if (svc != NULL) { 433 scf_service_destroy(svc); 434 } 435 if (pg != NULL) { 436 scf_pg_destroy(pg); 437 } 438 if (tran != NULL) { 439 scf_transaction_destroy(tran); 440 } 441 if (entry != NULL) { 442 scf_entry_destroy(entry); 443 } 444 if (prop != NULL) { 445 scf_property_destroy(prop); 446 } 447 if (valueIter != NULL) { 448 scf_iter_destroy(valueIter); 449 } 450 if (valueLookup != NULL) { 451 scf_value_destroy(valueLookup); 452 } 453 454 /* 455 * Free valueSet scf resources 456 */ 457 if (valueArraySize > 0) { 458 for (i = 0; i < valueArraySize; i++) { 459 scf_value_destroy(valueSet[i]); 460 } 461 } 462 /* 463 * Now free the pointer array to the resources 464 */ 465 if (valueSet != NULL) { 466 free(valueSet); 467 } 468 469 return (ret); 470 } 471 472 FCOE_STATUS 473 FCOE_CreatePort( 474 const FCOE_UINT8 *macLinkName, 475 FCOE_UINT8 portType, 476 FCOE_PORT_WWN pwwn, 477 FCOE_PORT_WWN nwwn, 478 FCOE_UINT8 promiscuous) 479 { 480 FCOE_STATUS status; 481 int fcoe_fd; 482 fcoeio_t fcoeio; 483 fcoeio_create_port_param_t param; 484 dladm_handle_t handle; 485 datalink_id_t linkid; 486 datalink_class_t class; 487 488 bzero(¶m, sizeof (fcoeio_create_port_param_t)); 489 490 if (macLinkName == NULL) { 491 return (FCOE_STATUS_ERROR_INVAL_ARG); 492 } 493 494 if (strlen((char *)macLinkName) > MAXLINKNAMELEN-1) { 495 return (FCOE_STATUS_ERROR_MAC_LEN); 496 } 497 498 if (dladm_open(&handle) != DLADM_STATUS_OK) { 499 return (FCOE_STATUS_ERROR); 500 } 501 502 if (dladm_name2info(handle, (const char *)macLinkName, 503 &linkid, NULL, &class, NULL) != DLADM_STATUS_OK) { 504 dladm_close(handle); 505 (void) fcoe_add_remove_scf_entry((char *)macLinkName, 506 "", 507 "", 508 portType, 509 0, 510 FCOE_SCF_REMOVE); 511 return (FCOE_STATUS_ERROR_GET_LINKINFO); 512 } 513 dladm_close(handle); 514 515 if (class != DATALINK_CLASS_PHYS) { 516 return (FCOE_STATUS_ERROR_CLASS_UNSUPPORT); 517 } 518 519 if (portType != FCOE_PORTTYPE_INITIATOR && 520 portType != FCOE_PORTTYPE_TARGET) { 521 return (FCOE_STATUS_ERROR_INVAL_ARG); 522 } 523 524 if (!isWWNZero(pwwn)) { 525 param.fcp_pwwn_provided = 1; 526 bcopy(pwwn.wwn, param.fcp_pwwn, 8); 527 } 528 529 if (!isWWNZero(nwwn)) { 530 param.fcp_nwwn_provided = 1; 531 bcopy(nwwn.wwn, param.fcp_nwwn, 8); 532 } 533 534 if (param.fcp_pwwn_provided == 1 && 535 param.fcp_nwwn_provided == 1 && 536 bcmp(&pwwn, &nwwn, 8) == 0) { 537 return (FCOE_STATUS_ERROR_WWN_SAME); 538 } 539 540 param.fcp_force_promisc = promiscuous; 541 param.fcp_mac_linkid = linkid; 542 param.fcp_port_type = (fcoe_cli_type_t)portType; 543 544 if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) { 545 return (status); 546 } 547 548 (void) memset(&fcoeio, 0, sizeof (fcoeio)); 549 fcoeio.fcoeio_cmd = FCOEIO_CREATE_FCOE_PORT; 550 551 fcoeio.fcoeio_ilen = sizeof (param); 552 fcoeio.fcoeio_xfer = FCOEIO_XFER_WRITE; 553 fcoeio.fcoeio_ibuf = (uintptr_t)¶m; 554 555 if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) { 556 switch (fcoeio.fcoeio_status) { 557 case FCOEIOE_INVAL_ARG: 558 status = FCOE_STATUS_ERROR_INVAL_ARG; 559 break; 560 561 case FCOEIOE_BUSY: 562 status = FCOE_STATUS_ERROR_BUSY; 563 break; 564 565 case FCOEIOE_ALREADY: 566 status = FCOE_STATUS_ERROR_ALREADY; 567 break; 568 569 case FCOEIOE_PWWN_CONFLICTED: 570 status = FCOE_STATUS_ERROR_PWWN_CONFLICTED; 571 break; 572 573 case FCOEIOE_NWWN_CONFLICTED: 574 status = FCOE_STATUS_ERROR_NWWN_CONFLICTED; 575 break; 576 577 case FCOEIOE_CREATE_MAC: 578 status = FCOE_STATUS_ERROR_CREATE_MAC; 579 break; 580 581 case FCOEIOE_OPEN_MAC: 582 status = FCOE_STATUS_ERROR_OPEN_MAC; 583 break; 584 585 case FCOEIOE_CREATE_PORT: 586 status = FCOE_STATUS_ERROR_CREATE_PORT; 587 break; 588 589 case FCOEIOE_NEED_JUMBO_FRAME: 590 status = FCOE_STATUS_ERROR_NEED_JUMBO_FRAME; 591 break; 592 593 default: 594 status = FCOE_STATUS_ERROR; 595 } 596 } else { 597 char cpwwn[17], cnwwn[17]; 598 599 WWN2str(cpwwn, &pwwn); 600 WWN2str(cnwwn, &nwwn); 601 602 (void) fcoe_add_remove_scf_entry((char *)macLinkName, 603 cpwwn, 604 cnwwn, 605 portType, 606 promiscuous, 607 FCOE_SCF_ADD); 608 status = FCOE_STATUS_OK; 609 } 610 (void) close(fcoe_fd); 611 return (status); 612 } 613 614 FCOE_STATUS 615 FCOE_DeletePort(const FCOE_UINT8 *macLinkName) 616 { 617 FCOE_STATUS status = FCOE_STATUS_OK; 618 int fcoe_fd; 619 fcoeio_t fcoeio; 620 dladm_handle_t handle; 621 datalink_id_t linkid; 622 fcoeio_delete_port_param_t fc_del_port; 623 uint64_t is_target = 0; 624 int io_ret = 0; 625 626 if (macLinkName == NULL) { 627 return (FCOE_STATUS_ERROR_INVAL_ARG); 628 } 629 630 if (strlen((char *)macLinkName) > MAXLINKNAMELEN-1) { 631 return (FCOE_STATUS_ERROR_MAC_LEN); 632 } 633 if (dladm_open(&handle) != DLADM_STATUS_OK) { 634 return (FCOE_STATUS_ERROR); 635 } 636 637 if (dladm_name2info(handle, (const char *)macLinkName, 638 &linkid, NULL, NULL, NULL) != DLADM_STATUS_OK) { 639 dladm_close(handle); 640 return (FCOE_STATUS_ERROR_GET_LINKINFO); 641 } 642 dladm_close(handle); 643 644 if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) { 645 return (status); 646 } 647 648 fc_del_port.fdp_mac_linkid = linkid; 649 650 (void) memset(&fcoeio, 0, sizeof (fcoeio)); 651 fcoeio.fcoeio_cmd = FCOEIO_DELETE_FCOE_PORT; 652 653 /* only 4 bytes here, need to change */ 654 fcoeio.fcoeio_ilen = sizeof (fcoeio_delete_port_param_t); 655 fcoeio.fcoeio_olen = sizeof (uint64_t); 656 fcoeio.fcoeio_xfer = FCOEIO_XFER_RW; 657 fcoeio.fcoeio_ibuf = (uintptr_t)&fc_del_port; 658 fcoeio.fcoeio_obuf = (uintptr_t)&is_target; 659 660 io_ret = ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio); 661 if (io_ret != 0) { 662 switch (fcoeio.fcoeio_status) { 663 case FCOEIOE_INVAL_ARG: 664 status = FCOE_STATUS_ERROR_INVAL_ARG; 665 break; 666 667 case FCOEIOE_BUSY: 668 status = FCOE_STATUS_ERROR_BUSY; 669 break; 670 671 case FCOEIOE_ALREADY: 672 status = FCOE_STATUS_ERROR_ALREADY; 673 break; 674 675 case FCOEIOE_MAC_NOT_FOUND: 676 status = FCOE_STATUS_ERROR_MAC_NOT_FOUND; 677 break; 678 679 case FCOEIOE_OFFLINE_FAILURE: 680 status = FCOE_STATUS_ERROR_OFFLINE_DEV; 681 break; 682 683 default: 684 status = FCOE_STATUS_ERROR; 685 } 686 } else { 687 (void) fcoe_add_remove_scf_entry((char *)macLinkName, 688 "", 689 "", 690 is_target, 691 0, 692 FCOE_SCF_REMOVE); 693 status = FCOE_STATUS_OK; 694 } 695 696 if (io_ret == FCOEIOE_MAC_NOT_FOUND) { 697 (void) fcoe_add_remove_scf_entry((char *)macLinkName, 698 "", 699 "", 700 0, 701 0, 702 FCOE_SCF_REMOVE); 703 (void) fcoe_add_remove_scf_entry((char *)macLinkName, 704 "", 705 "", 706 1, 707 0, 708 FCOE_SCF_REMOVE); 709 } 710 (void) close(fcoe_fd); 711 return (status); 712 } 713 714 FCOE_STATUS 715 FCOE_GetPortList( 716 FCOE_UINT32 *port_num, 717 FCOE_PORT_ATTRIBUTE **portlist) 718 { 719 FCOE_STATUS status = FCOE_STATUS_OK; 720 int fcoe_fd; 721 fcoeio_t fcoeio; 722 fcoe_port_list_t *inportlist = NULL; 723 FCOE_PORT_ATTRIBUTE *outportlist = NULL; 724 int i; 725 int size = 64; /* default first attempt */ 726 int retry = 0; 727 int bufsize; 728 dladm_handle_t handle; 729 char mac_name[MAXLINKNAMELEN]; 730 731 if (port_num == NULL || portlist == NULL) { 732 return (FCOE_STATUS_ERROR_INVAL_ARG); 733 } 734 *port_num = 0; 735 736 if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) { 737 return (status); 738 } 739 740 /* Get fcoe port list */ 741 (void) memset(&fcoeio, 0, sizeof (fcoeio)); 742 retry = 0; 743 744 do { 745 bufsize = sizeof (fcoe_port_instance_t) * (size - 1) + 746 sizeof (fcoe_port_list_t); 747 inportlist = (fcoe_port_list_t *)malloc(bufsize); 748 fcoeio.fcoeio_cmd = FCOEIO_GET_FCOE_PORT_LIST; 749 fcoeio.fcoeio_olen = bufsize; 750 fcoeio.fcoeio_xfer = FCOEIO_XFER_READ; 751 fcoeio.fcoeio_obuf = (uintptr_t)inportlist; 752 753 if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) { 754 if (fcoeio.fcoeio_status == FCOEIOE_MORE_DATA) { 755 size = inportlist->numPorts; 756 } 757 free(inportlist); 758 switch (fcoeio.fcoeio_status) { 759 case FCOEIOE_INVAL_ARG: 760 status = FCOE_STATUS_ERROR_INVAL_ARG; 761 (void) close(fcoe_fd); 762 return (status); 763 764 case FCOEIOE_BUSY: 765 status = FCOE_STATUS_ERROR_BUSY; 766 retry++; 767 break; 768 769 case FCOEIOE_MORE_DATA: 770 status = FCOE_STATUS_ERROR_MORE_DATA; 771 retry++; 772 default: 773 status = FCOE_STATUS_ERROR; 774 (void) close(fcoe_fd); 775 return (status); 776 } 777 } else { 778 status = FCOE_STATUS_OK; 779 break; 780 } 781 } while (retry <= 3 && status != FCOE_STATUS_OK); 782 783 if (status == FCOE_STATUS_OK && inportlist->numPorts > 0) { 784 if (dladm_open(&handle) != DLADM_STATUS_OK) { 785 handle = NULL; 786 } 787 788 outportlist = (PFCOE_PORT_ATTRIBUTE) 789 malloc(sizeof (FCOE_PORT_ATTRIBUTE) * inportlist->numPorts); 790 791 for (i = 0; i < inportlist->numPorts; i++) { 792 fcoe_port_instance_t *pi = &inportlist->ports[i]; 793 FCOE_PORT_ATTRIBUTE *po = &outportlist[i]; 794 bcopy(pi->fpi_pwwn, &po->port_wwn, 8); 795 796 if (handle == NULL || 797 dladm_datalink_id2info(handle, pi->fpi_mac_linkid, 798 NULL, NULL, NULL, mac_name, sizeof (mac_name)) 799 != DLADM_STATUS_OK) { 800 (void) strcpy((char *)po->mac_link_name, 801 "<unknown>"); 802 } else { 803 (void) strcpy((char *)po->mac_link_name, 804 mac_name); 805 } 806 bcopy(pi->fpi_mac_factory_addr, 807 po->mac_factory_addr, 6); 808 bcopy(pi->fpi_mac_current_addr, 809 po->mac_current_addr, 6); 810 po->port_type = (FCOE_UINT8)pi->fpi_port_type; 811 po->mtu_size = pi->fpi_mtu_size; 812 po->mac_promisc = pi->fpi_mac_promisc; 813 } 814 815 if (handle != NULL) { 816 dladm_close(handle); 817 } 818 *port_num = inportlist->numPorts; 819 *portlist = outportlist; 820 free(inportlist); 821 } else { 822 *port_num = 0; 823 *portlist = NULL; 824 } 825 (void) close(fcoe_fd); 826 return (status); 827 } 828 829 FCOE_STATUS FCOE_LoadConfig( 830 FCOE_UINT8 portType, 831 FCOE_SMF_PORT_LIST **portlist) 832 { 833 scf_handle_t *handle = NULL; 834 scf_service_t *svc = NULL; 835 scf_propertygroup_t *pg = NULL; 836 scf_transaction_t *tran = NULL; 837 scf_transaction_entry_t *entry = NULL; 838 scf_property_t *prop = NULL; 839 scf_value_t *valueLookup = NULL; 840 scf_iter_t *valueIter = NULL; 841 char buf[FCOE_PORT_LIST_LENGTH] = {0}; 842 int commitRet; 843 FCOE_UINT32 portIndex; 844 int bufsize, retry; 845 int size = 10; /* default first attempt */ 846 int pg_or_prop_not_found = 0; 847 848 commitRet = fcoe_cfg_scf_init(&handle, &svc, portType); 849 if (commitRet != FCOE_SUCCESS) { 850 goto out; 851 } 852 853 if (((pg = scf_pg_create(handle)) == NULL) || 854 ((tran = scf_transaction_create(handle)) == NULL) || 855 ((entry = scf_entry_create(handle)) == NULL) || 856 ((prop = scf_property_create(handle)) == NULL) || 857 ((valueIter = scf_iter_create(handle)) == NULL)) { 858 goto out; 859 } 860 861 if (scf_service_get_pg(svc, FCOE_PG_NAME, pg) == -1) { 862 pg_or_prop_not_found = 1; 863 goto out; 864 } 865 866 if (scf_pg_get_property(pg, FCOE_PORT_LIST, prop) == -1) { 867 pg_or_prop_not_found = 1; 868 goto out; 869 } 870 871 valueLookup = scf_value_create(handle); 872 if (valueLookup == NULL) { 873 syslog(LOG_ERR, "scf value alloc failed - %s", 874 scf_strerror(scf_error())); 875 goto out; 876 } 877 878 portIndex = 0; 879 880 do { 881 if (scf_iter_property_values(valueIter, prop) == -1) { 882 syslog(LOG_ERR, "iter value failed - %s", 883 scf_strerror(scf_error())); 884 goto out; 885 } 886 887 retry = 0; 888 bufsize = sizeof (FCOE_SMF_PORT_INSTANCE) * (size - 1) + 889 sizeof (FCOE_SMF_PORT_LIST); 890 *portlist = (PFCOE_SMF_PORT_LIST)malloc(bufsize); 891 892 while (scf_iter_next_value(valueIter, valueLookup) == 1) { 893 uint8_t *macLinkName = NULL; 894 char *remainder = NULL; 895 uint64_t nodeWWN, portWWN; 896 int is_target, is_promiscuous; 897 898 bzero(buf, sizeof (buf)); 899 if (scf_value_get_ustring(valueLookup, buf, 900 MAXNAMELEN) == -1) { 901 syslog(LOG_ERR, "iter value failed - %s", 902 scf_strerror(scf_error())); 903 break; 904 } 905 macLinkName = (uint8_t *)strtok(buf, ":"); 906 remainder = strtok(NULL, "#"); 907 (void) sscanf(remainder, 908 "%016" PRIx64 ":%016" PRIx64 ":%d:%d", 909 &portWWN, &nodeWWN, &is_target, &is_promiscuous); 910 911 if (portIndex >= size) { 912 free(*portlist); 913 retry = 1; 914 size *= 2; 915 break; 916 } else { 917 PFCOE_SMF_PORT_INSTANCE pi = 918 &(*portlist)->ports[portIndex++]; 919 (void) strcpy((char *)pi->mac_link_name, 920 (char *)macLinkName); 921 pi->port_type = is_target ? 922 FCOE_PORTTYPE_TARGET: 923 FCOE_PORTTYPE_INITIATOR; 924 portWWN = htonll(portWWN); 925 nodeWWN = htonll(nodeWWN); 926 (void) memcpy(&pi->port_pwwn, &portWWN, 927 sizeof (FCOE_PORT_WWN)); 928 (void) memcpy(&pi->port_nwwn, &nodeWWN, 929 sizeof (FCOE_PORT_WWN)); 930 pi->mac_promisc = is_promiscuous; 931 } 932 } 933 934 (*portlist)->port_num = portIndex; 935 } while (retry == 1); 936 937 return (FCOE_STATUS_OK); 938 out: 939 /* 940 * Free resources 941 */ 942 if (handle != NULL) { 943 scf_handle_destroy(handle); 944 } 945 if (svc != NULL) { 946 scf_service_destroy(svc); 947 } 948 if (pg != NULL) { 949 scf_pg_destroy(pg); 950 } 951 if (tran != NULL) { 952 scf_transaction_destroy(tran); 953 } 954 if (entry != NULL) { 955 scf_entry_destroy(entry); 956 } 957 if (prop != NULL) { 958 scf_property_destroy(prop); 959 } 960 if (valueIter != NULL) { 961 scf_iter_destroy(valueIter); 962 } 963 if (valueLookup != NULL) { 964 scf_value_destroy(valueLookup); 965 } 966 967 if (pg_or_prop_not_found == 1) { 968 return (FCOE_STATUS_OK); 969 } else { 970 return (FCOE_STATUS_ERROR); 971 } 972 } 973