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