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 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. 27 */ 28 29 /* 30 * The following notice accompanied the original version of this file: 31 * 32 * BSD LICENSE 33 * 34 * Copyright(c) 2007 Intel Corporation. All rights reserved. 35 * All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 41 * * Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * * Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in 45 * the documentation and/or other materials provided with the 46 * distribution. 47 * * Neither the name of Intel Corporation nor the names of its 48 * contributors may be used to endorse or promote products derived 49 * from this software without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 52 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 53 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 54 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 55 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 56 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 57 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 58 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 59 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 60 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 61 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 */ 63 64 /* 65 * Common FCoE interface interacts with MAC and FCoE clients, managing 66 * FCoE ports, doing MAC address discovery/managment, and FC frame 67 * encapsulation/decapsulation 68 */ 69 70 #include <sys/stat.h> 71 #include <sys/conf.h> 72 #include <sys/file.h> 73 #include <sys/cred.h> 74 75 #include <sys/ddi.h> 76 #include <sys/sunddi.h> 77 #include <sys/sunndi.h> 78 #include <sys/byteorder.h> 79 #include <sys/atomic.h> 80 #include <sys/sysmacros.h> 81 #include <sys/cmn_err.h> 82 #include <sys/crc32.h> 83 #include <sys/strsubr.h> 84 85 #include <sys/mac_client.h> 86 87 /* 88 * FCoE header files 89 */ 90 #include <sys/fcoe/fcoeio.h> 91 #include <sys/fcoe/fcoe_common.h> 92 93 /* 94 * Driver's own header files 95 */ 96 #include <fcoe.h> 97 #include <fcoe_fc.h> 98 #include <fcoe_eth.h> 99 100 /* 101 * Function forward declaration 102 */ 103 static int fcoe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 104 static int fcoe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 105 static int fcoe_bus_ctl(dev_info_t *fca_dip, dev_info_t *rip, 106 ddi_ctl_enum_t op, void *arg, void *result); 107 static int fcoe_open(dev_t *devp, int flag, int otype, cred_t *credp); 108 static int fcoe_close(dev_t dev, int flag, int otype, cred_t *credp); 109 static int fcoe_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 110 cred_t *credp, int *rval); 111 static int fcoe_copyin_iocdata(intptr_t data, int mode, fcoeio_t **fcoeio, 112 void **ibuf, void **abuf, void **obuf); 113 static int fcoe_copyout_iocdata(intptr_t data, int mode, fcoeio_t *fcoeio, 114 void *obuf); 115 static int fcoe_iocmd(fcoe_soft_state_t *ss, intptr_t data, int mode); 116 static int fcoe_attach_init(fcoe_soft_state_t *this_ss); 117 static int fcoe_detach_uninit(fcoe_soft_state_t *this_ss); 118 static int fcoe_initchild(dev_info_t *fcoe_dip, dev_info_t *client_dip); 119 static int fcoe_uninitchild(dev_info_t *fcoe_dip, dev_info_t *client_dip); 120 static void fcoe_init_wwn_from_mac(uint8_t *wwn, uint8_t *mac, 121 int is_pwwn, uint8_t idx); 122 static fcoe_mac_t *fcoe_create_mac_by_id(datalink_id_t linkid); 123 static int fcoe_cmp_wwn(fcoe_mac_t *checkedmac); 124 static void fcoe_watchdog(void *arg); 125 static void fcoe_worker_init(); 126 static int fcoe_worker_fini(); 127 static void fcoe_worker_frame(); 128 static int fcoe_get_port_list(fcoe_port_instance_t *ports, int count); 129 static boolean_t fcoe_mac_existed(fcoe_mac_t *pmac); 130 131 /* 132 * Driver identificaton stuff 133 */ 134 static struct cb_ops fcoe_cb_ops = { 135 fcoe_open, 136 fcoe_close, 137 nodev, 138 nodev, 139 nodev, 140 nodev, 141 nodev, 142 fcoe_ioctl, 143 nodev, 144 nodev, 145 nodev, 146 nochpoll, 147 ddi_prop_op, 148 0, 149 D_MP | D_NEW | D_HOTPLUG, 150 CB_REV, 151 nodev, 152 nodev 153 }; 154 155 static struct bus_ops fcoe_busops = { 156 BUSO_REV, 157 nullbusmap, /* bus_map */ 158 NULL, /* bus_get_intrspec */ 159 NULL, /* bus_add_intrspec */ 160 NULL, /* bus_remove_intrspec */ 161 i_ddi_map_fault, /* bus_map_fault */ 162 NULL, /* bus_dma_map */ 163 ddi_dma_allochdl, /* bus_dma_allochdl */ 164 ddi_dma_freehdl, /* bus_dma_freehdl */ 165 ddi_dma_bindhdl, /* bus_dma_bindhdl */ 166 ddi_dma_unbindhdl, /* bus_unbindhdl */ 167 ddi_dma_flush, /* bus_dma_flush */ 168 ddi_dma_win, /* bus_dma_win */ 169 ddi_dma_mctl, /* bus_dma_ctl */ 170 fcoe_bus_ctl, /* bus_ctl */ 171 ddi_bus_prop_op, /* bus_prop_op */ 172 NULL, /* bus_get_eventcookie */ 173 NULL, /* bus_add_eventcall */ 174 NULL, /* bus_remove_event */ 175 NULL, /* bus_post_event */ 176 NULL, /* bus_intr_ctl */ 177 NULL, /* bus_config */ 178 NULL, /* bus_unconfig */ 179 NULL, /* bus_fm_init */ 180 NULL, /* bus_fm_fini */ 181 NULL, /* bus_fm_access_enter */ 182 NULL, /* bus_fm_access_exit */ 183 NULL, /* bus_power */ 184 NULL 185 }; 186 187 static struct dev_ops fcoe_ops = { 188 DEVO_REV, 189 0, 190 nodev, 191 nulldev, 192 nulldev, 193 fcoe_attach, 194 fcoe_detach, 195 nodev, 196 &fcoe_cb_ops, 197 &fcoe_busops, 198 ddi_power, 199 ddi_quiesce_not_needed 200 }; 201 202 #define FCOE_VERSION "20091123-1.02" 203 #define FCOE_NAME "FCoE Transport v" FCOE_VERSION 204 #define TASKQ_NAME_LEN 32 205 206 static struct modldrv modldrv = { 207 &mod_driverops, 208 FCOE_NAME, 209 &fcoe_ops, 210 }; 211 212 static struct modlinkage modlinkage = { 213 MODREV_1, { &modldrv, NULL } 214 }; 215 216 /* 217 * TRACE for all FCoE related modules 218 */ 219 static kmutex_t fcoe_trace_buf_lock; 220 static int fcoe_trace_buf_curndx = 0; 221 static int fcoe_trace_on = 1; 222 static caddr_t fcoe_trace_buf = NULL; 223 static clock_t fcoe_trace_start = 0; 224 static caddr_t ftb = NULL; 225 static int fcoe_trace_buf_size = (1 * 1024 * 1024); 226 227 /* 228 * Driver's global variables 229 */ 230 const fcoe_ver_e fcoe_ver_now = FCOE_VER_NOW; 231 static void *fcoe_state = NULL; 232 fcoe_soft_state_t *fcoe_global_ss = NULL; 233 int fcoe_use_ext_log = 1; 234 235 static ddi_taskq_t *fcoe_worker_taskq; 236 static fcoe_worker_t *fcoe_workers; 237 static uint32_t fcoe_nworkers_running; 238 239 const char *fcoe_workers_num = "workers-number"; 240 volatile int fcoe_nworkers; 241 242 /* 243 * Common loadable module entry points _init, _fini, _info 244 */ 245 246 int 247 _init(void) 248 { 249 int ret; 250 251 ret = ddi_soft_state_init(&fcoe_state, sizeof (fcoe_soft_state_t), 0); 252 if (ret == 0) { 253 ret = mod_install(&modlinkage); 254 if (ret != 0) { 255 ddi_soft_state_fini(&fcoe_state); 256 } else { 257 fcoe_trace_start = ddi_get_lbolt(); 258 ftb = kmem_zalloc(fcoe_trace_buf_size, 259 KM_SLEEP); 260 fcoe_trace_buf = ftb; 261 mutex_init(&fcoe_trace_buf_lock, NULL, MUTEX_DRIVER, 0); 262 } 263 } 264 265 FCOE_LOG("fcoe", "exit _init with %x", ret); 266 267 return (ret); 268 } 269 270 int 271 _fini(void) 272 { 273 int ret; 274 275 ret = mod_remove(&modlinkage); 276 if (ret == 0) { 277 ddi_soft_state_fini(&fcoe_state); 278 } 279 280 FCOE_LOG("fcoe", "exit _fini with %x", ret); 281 if (ret == 0) { 282 kmem_free(fcoe_trace_buf, fcoe_trace_buf_size); 283 mutex_destroy(&fcoe_trace_buf_lock); 284 } 285 286 return (ret); 287 } 288 289 int 290 _info(struct modinfo *modinfop) 291 { 292 return (mod_info(&modlinkage, modinfop)); 293 } 294 295 /* 296 * Autoconfiguration entry points: attach, detach, getinfo 297 */ 298 299 static int 300 fcoe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 301 { 302 int ret = DDI_FAILURE; 303 int fcoe_ret; 304 int instance; 305 fcoe_soft_state_t *ss; 306 307 instance = ddi_get_instance(dip); 308 switch (cmd) { 309 case DDI_ATTACH: 310 ret = ddi_soft_state_zalloc(fcoe_state, instance); 311 if (ret == DDI_FAILURE) { 312 FCOE_LOG(0, "soft_state_zalloc-%x/%x", ret, instance); 313 return (ret); 314 } 315 316 ss = ddi_get_soft_state(fcoe_state, instance); 317 ss->ss_dip = dip; 318 319 ASSERT(fcoe_global_ss == NULL); 320 fcoe_global_ss = ss; 321 fcoe_ret = fcoe_attach_init(ss); 322 if (fcoe_ret == FCOE_SUCCESS) { 323 ret = DDI_SUCCESS; 324 } 325 326 FCOE_LOG("fcoe", "fcoe_attach_init end with-%x", fcoe_ret); 327 break; 328 329 case DDI_RESUME: 330 ret = DDI_SUCCESS; 331 break; 332 333 default: 334 FCOE_LOG("fcoe", "unsupported attach cmd-%x", cmd); 335 break; 336 } 337 338 return (ret); 339 } 340 341 static int 342 fcoe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 343 { 344 int ret = DDI_FAILURE; 345 int fcoe_ret; 346 int instance; 347 fcoe_soft_state_t *ss; 348 349 instance = ddi_get_instance(dip); 350 ss = ddi_get_soft_state(fcoe_state, instance); 351 if (ss == NULL) { 352 return (ret); 353 } 354 355 ASSERT(fcoe_global_ss != NULL); 356 ASSERT(dip == fcoe_global_ss->ss_dip); 357 switch (cmd) { 358 case DDI_DETACH: 359 fcoe_ret = fcoe_detach_uninit(ss); 360 if (fcoe_ret == FCOE_SUCCESS) { 361 ret = DDI_SUCCESS; 362 fcoe_global_ss = NULL; 363 } 364 365 break; 366 367 case DDI_SUSPEND: 368 ret = DDI_SUCCESS; 369 break; 370 371 default: 372 FCOE_LOG(0, "unsupported detach cmd-%x", cmd); 373 break; 374 } 375 376 return (ret); 377 } 378 379 /* 380 * FCA driver's intercepted bus control operations. 381 */ 382 static int 383 fcoe_bus_ctl(dev_info_t *fcoe_dip, dev_info_t *rip, 384 ddi_ctl_enum_t op, void *clientarg, void *result) 385 { 386 int ret; 387 switch (op) { 388 case DDI_CTLOPS_REPORTDEV: 389 case DDI_CTLOPS_IOMIN: 390 ret = DDI_SUCCESS; 391 break; 392 393 case DDI_CTLOPS_INITCHILD: 394 ret = fcoe_initchild(fcoe_dip, (dev_info_t *)clientarg); 395 break; 396 397 case DDI_CTLOPS_UNINITCHILD: 398 ret = fcoe_uninitchild(fcoe_dip, (dev_info_t *)clientarg); 399 break; 400 401 default: 402 ret = ddi_ctlops(fcoe_dip, rip, op, clientarg, result); 403 break; 404 } 405 406 return (ret); 407 } 408 409 /* 410 * We need specify the dev address for client driver's instance, or we 411 * can't online client driver's instance. 412 */ 413 /* ARGSUSED */ 414 static int 415 fcoe_initchild(dev_info_t *fcoe_dip, dev_info_t *client_dip) 416 { 417 char client_addr[FCOE_STR_LEN]; 418 int rval; 419 420 rval = ddi_prop_get_int(DDI_DEV_T_ANY, client_dip, 421 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_id", -1); 422 if (rval == -1) { 423 FCOE_LOG(__FUNCTION__, "no mac_id property: %p", client_dip); 424 return (DDI_FAILURE); 425 } 426 427 bzero(client_addr, FCOE_STR_LEN); 428 (void) sprintf((char *)client_addr, "%x,0", rval); 429 ddi_set_name_addr(client_dip, client_addr); 430 return (DDI_SUCCESS); 431 } 432 433 /* ARGSUSED */ 434 static int 435 fcoe_uninitchild(dev_info_t *fcoe_dip, dev_info_t *client_dip) 436 { 437 ddi_set_name_addr(client_dip, NULL); 438 return (DDI_SUCCESS); 439 } 440 441 /* 442 * Device access entry points 443 */ 444 static int 445 fcoe_open(dev_t *devp, int flag, int otype, cred_t *credp) 446 { 447 int instance; 448 fcoe_soft_state_t *ss; 449 450 if (otype != OTYP_CHR) { 451 return (EINVAL); 452 } 453 454 /* 455 * Since this is for debugging only, only allow root to issue ioctl now 456 */ 457 if (drv_priv(credp) != 0) { 458 return (EPERM); 459 } 460 461 instance = (int)getminor(*devp); 462 ss = ddi_get_soft_state(fcoe_state, instance); 463 if (ss == NULL) { 464 return (ENXIO); 465 } 466 467 mutex_enter(&ss->ss_ioctl_mutex); 468 if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL) { 469 /* 470 * It is already open for exclusive access. 471 * So shut the door on this caller. 472 */ 473 mutex_exit(&ss->ss_ioctl_mutex); 474 return (EBUSY); 475 } 476 477 if (flag & FEXCL) { 478 if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) { 479 /* 480 * Exclusive operation not possible 481 * as it is already opened 482 */ 483 mutex_exit(&ss->ss_ioctl_mutex); 484 return (EBUSY); 485 } 486 ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_EXCL; 487 } 488 489 ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_OPEN; 490 mutex_exit(&ss->ss_ioctl_mutex); 491 492 return (0); 493 } 494 495 /* ARGSUSED */ 496 static int 497 fcoe_close(dev_t dev, int flag, int otype, cred_t *credp) 498 { 499 int instance; 500 fcoe_soft_state_t *ss; 501 502 if (otype != OTYP_CHR) { 503 return (EINVAL); 504 } 505 506 instance = (int)getminor(dev); 507 ss = ddi_get_soft_state(fcoe_state, instance); 508 if (ss == NULL) { 509 return (ENXIO); 510 } 511 512 mutex_enter(&ss->ss_ioctl_mutex); 513 if ((ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) == 0) { 514 mutex_exit(&ss->ss_ioctl_mutex); 515 return (ENODEV); 516 } 517 518 ss->ss_ioctl_flags &= ~FCOE_IOCTL_FLAG_MASK; 519 mutex_exit(&ss->ss_ioctl_mutex); 520 521 return (0); 522 } 523 524 /* ARGSUSED */ 525 static int 526 fcoe_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 527 cred_t *credp, int *rval) 528 { 529 fcoe_soft_state_t *ss; 530 int ret = 0; 531 532 if (drv_priv(credp) != 0) { 533 return (EPERM); 534 } 535 536 ss = ddi_get_soft_state(fcoe_state, (int32_t)getminor(dev)); 537 if (ss == NULL) { 538 return (ENXIO); 539 } 540 541 mutex_enter(&ss->ss_ioctl_mutex); 542 if ((ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) == 0) { 543 mutex_exit(&ss->ss_ioctl_mutex); 544 return (ENXIO); 545 } 546 mutex_exit(&ss->ss_ioctl_mutex); 547 548 switch (cmd) { 549 case FCOEIO_CMD: 550 ret = fcoe_iocmd(ss, data, mode); 551 break; 552 default: 553 FCOE_LOG(0, "fcoe_ioctl: ioctl-0x%02X", cmd); 554 ret = ENOTTY; 555 break; 556 } 557 558 return (ret); 559 } 560 561 static int 562 fcoe_copyin_iocdata(intptr_t data, int mode, fcoeio_t **fcoeio, 563 void **ibuf, void **abuf, void **obuf) 564 { 565 int ret = 0; 566 567 *ibuf = NULL; 568 *abuf = NULL; 569 *obuf = NULL; 570 *fcoeio = kmem_zalloc(sizeof (fcoeio_t), KM_SLEEP); 571 if (ddi_copyin((void *)data, *fcoeio, sizeof (fcoeio_t), mode) != 0) { 572 ret = EFAULT; 573 goto copyin_iocdata_fail; 574 } 575 576 if ((*fcoeio)->fcoeio_ilen > FCOEIO_MAX_BUF_LEN || 577 (*fcoeio)->fcoeio_alen > FCOEIO_MAX_BUF_LEN || 578 (*fcoeio)->fcoeio_olen > FCOEIO_MAX_BUF_LEN) { 579 ret = EFAULT; 580 goto copyin_iocdata_fail; 581 } 582 583 if ((*fcoeio)->fcoeio_ilen) { 584 *ibuf = kmem_zalloc((*fcoeio)->fcoeio_ilen, KM_SLEEP); 585 if (ddi_copyin((void *)(unsigned long)(*fcoeio)->fcoeio_ibuf, 586 *ibuf, (*fcoeio)->fcoeio_ilen, mode) != 0) { 587 ret = EFAULT; 588 goto copyin_iocdata_fail; 589 } 590 } 591 592 if ((*fcoeio)->fcoeio_alen) { 593 *abuf = kmem_zalloc((*fcoeio)->fcoeio_alen, KM_SLEEP); 594 if (ddi_copyin((void *)(unsigned long)(*fcoeio)->fcoeio_abuf, 595 *abuf, (*fcoeio)->fcoeio_alen, mode) != 0) { 596 ret = EFAULT; 597 goto copyin_iocdata_fail; 598 } 599 } 600 601 if ((*fcoeio)->fcoeio_olen) { 602 *obuf = kmem_zalloc((*fcoeio)->fcoeio_olen, KM_SLEEP); 603 } 604 return (ret); 605 606 copyin_iocdata_fail: 607 if (*abuf) { 608 kmem_free(*abuf, (*fcoeio)->fcoeio_alen); 609 *abuf = NULL; 610 } 611 612 if (*ibuf) { 613 kmem_free(*ibuf, (*fcoeio)->fcoeio_ilen); 614 *ibuf = NULL; 615 } 616 617 kmem_free(*fcoeio, sizeof (fcoeio_t)); 618 return (ret); 619 } 620 621 static int 622 fcoe_copyout_iocdata(intptr_t data, int mode, fcoeio_t *fcoeio, void *obuf) 623 { 624 if (fcoeio->fcoeio_olen) { 625 if (ddi_copyout(obuf, 626 (void *)(unsigned long)fcoeio->fcoeio_obuf, 627 fcoeio->fcoeio_olen, mode) != 0) { 628 return (EFAULT); 629 } 630 } 631 632 if (ddi_copyout(fcoeio, (void *)data, sizeof (fcoeio_t), mode) != 0) { 633 return (EFAULT); 634 } 635 return (0); 636 } 637 638 static int 639 fcoe_iocmd(fcoe_soft_state_t *ss, intptr_t data, int mode) 640 { 641 int ret; 642 fcoe_mac_t *fcoe_mac; 643 void *ibuf = NULL; 644 void *obuf = NULL; 645 void *abuf = NULL; 646 fcoeio_t *fcoeio; 647 648 ret = fcoe_copyin_iocdata(data, mode, &fcoeio, &ibuf, &abuf, &obuf); 649 if (ret != 0) { 650 goto fcoeiocmd_release_buf; 651 } 652 653 /* 654 * If an exclusive open was demanded during open, ensure that 655 * only one thread can execute an ioctl at a time 656 */ 657 mutex_enter(&ss->ss_ioctl_mutex); 658 if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL) { 659 if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL_BUSY) { 660 mutex_exit(&ss->ss_ioctl_mutex); 661 fcoeio->fcoeio_status = FCOEIOE_BUSY; 662 ret = EBUSY; 663 goto fcoeiocmd_release_buf; 664 } 665 ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_EXCL_BUSY; 666 } 667 mutex_exit(&ss->ss_ioctl_mutex); 668 669 fcoeio->fcoeio_status = 0; 670 671 switch (fcoeio->fcoeio_cmd) { 672 case FCOEIO_CREATE_FCOE_PORT: { 673 fcoeio_create_port_param_t *param = 674 (fcoeio_create_port_param_t *)ibuf; 675 int cmpwwn = 0; 676 fcoe_port_t *eport; 677 678 if (fcoeio->fcoeio_ilen != 679 sizeof (fcoeio_create_port_param_t) || 680 fcoeio->fcoeio_xfer != FCOEIO_XFER_WRITE) { 681 fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG; 682 ret = EINVAL; 683 break; 684 } 685 686 mutex_enter(&ss->ss_ioctl_mutex); 687 fcoe_mac = fcoe_create_mac_by_id(param->fcp_mac_linkid); 688 if (fcoe_mac == NULL) { 689 mutex_exit(&ss->ss_ioctl_mutex); 690 fcoeio->fcoeio_status = FCOEIOE_CREATE_MAC; 691 ret = EIO; 692 break; 693 } 694 695 if (fcoe_mac->fm_flags & FCOE_MAC_FLAG_ENABLED) { 696 mutex_exit(&ss->ss_ioctl_mutex); 697 fcoeio->fcoeio_status = FCOEIOE_ALREADY; 698 ret = EALREADY; 699 break; 700 } else { 701 ret = fcoe_open_mac(fcoe_mac, param->fcp_force_promisc, 702 &fcoeio->fcoeio_status); 703 if (ret != 0) { 704 fcoe_destroy_mac(fcoe_mac); 705 mutex_exit(&ss->ss_ioctl_mutex); 706 if (fcoeio->fcoeio_status == 0) { 707 fcoeio->fcoeio_status = 708 FCOEIOE_OPEN_MAC; 709 } 710 ret = EIO; 711 break; 712 } else { 713 fcoe_mac->fm_flags |= FCOE_MAC_FLAG_ENABLED; 714 } 715 } 716 717 /* 718 * Provide PWWN and NWWN based on mac address 719 */ 720 eport = &fcoe_mac->fm_eport; 721 if (!param->fcp_pwwn_provided) { 722 fcoe_init_wwn_from_mac(eport->eport_portwwn, 723 fcoe_mac->fm_current_addr, 1, 0); 724 } else { 725 (void) memcpy(eport->eport_portwwn, param->fcp_pwwn, 8); 726 } 727 728 if (!param->fcp_nwwn_provided) { 729 fcoe_init_wwn_from_mac(eport->eport_nodewwn, 730 fcoe_mac->fm_current_addr, 0, 0); 731 } else { 732 (void) memcpy(eport->eport_nodewwn, param->fcp_nwwn, 8); 733 } 734 735 cmpwwn = fcoe_cmp_wwn(fcoe_mac); 736 737 if (cmpwwn != 0) { 738 if (cmpwwn == 1) { 739 fcoeio->fcoeio_status = FCOEIOE_PWWN_CONFLICTED; 740 } else if (cmpwwn == -1) { 741 fcoeio->fcoeio_status = FCOEIOE_NWWN_CONFLICTED; 742 } 743 (void) fcoe_close_mac(fcoe_mac); 744 fcoe_destroy_mac(fcoe_mac); 745 mutex_exit(&ss->ss_ioctl_mutex); 746 ret = ENOTUNIQ; 747 break; 748 } 749 750 if (ret == 0) { 751 ret = fcoe_create_port(ss->ss_dip, 752 fcoe_mac, 753 (param->fcp_port_type == FCOE_CLIENT_TARGET)); 754 if (ret != 0) { 755 if (fcoe_mac_existed(fcoe_mac) == B_TRUE) { 756 (void) fcoe_close_mac(fcoe_mac); 757 fcoe_destroy_mac(fcoe_mac); 758 } 759 fcoeio->fcoeio_status = FCOEIOE_CREATE_PORT; 760 ret = EIO; 761 } 762 } 763 mutex_exit(&ss->ss_ioctl_mutex); 764 765 break; 766 } 767 768 case FCOEIO_DELETE_FCOE_PORT: { 769 fcoeio_delete_port_param_t *del_port_param = 770 (fcoeio_delete_port_param_t *)ibuf; 771 uint64_t *is_target = (uint64_t *)obuf; 772 773 if (fcoeio->fcoeio_ilen < sizeof (fcoeio_delete_port_param_t) || 774 fcoeio->fcoeio_olen != sizeof (uint64_t) || 775 fcoeio->fcoeio_xfer != FCOEIO_XFER_RW) { 776 fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG; 777 ret = EINVAL; 778 break; 779 } 780 781 mutex_enter(&ss->ss_ioctl_mutex); 782 ret = fcoe_delete_port(ss->ss_dip, fcoeio, 783 del_port_param->fdp_mac_linkid, is_target); 784 mutex_exit(&ss->ss_ioctl_mutex); 785 FCOE_LOG("fcoe", "fcoe_delete_port %x return: %d", 786 del_port_param->fdp_mac_linkid, ret); 787 break; 788 } 789 790 case FCOEIO_GET_FCOE_PORT_LIST: { 791 fcoe_port_list_t *list = (fcoe_port_list_t *)obuf; 792 int count; 793 794 if (fcoeio->fcoeio_xfer != FCOEIO_XFER_READ || 795 fcoeio->fcoeio_olen < sizeof (fcoe_port_list_t)) { 796 fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG; 797 ret = EINVAL; 798 break; 799 } 800 mutex_enter(&ss->ss_ioctl_mutex); 801 802 list->numPorts = 1 + (fcoeio->fcoeio_olen - 803 sizeof (fcoe_port_list_t))/sizeof (fcoe_port_instance_t); 804 805 count = fcoe_get_port_list(list->ports, list->numPorts); 806 807 if (count > list->numPorts) { 808 fcoeio->fcoeio_status = FCOEIOE_MORE_DATA; 809 ret = ENOSPC; 810 } 811 list->numPorts = count; 812 mutex_exit(&ss->ss_ioctl_mutex); 813 814 break; 815 816 } 817 818 default: 819 return (ENOTTY); 820 } 821 822 FCOE_LOG("fcoe", "fcoe_ioctl %x returned %d, fcoeio_status = %d", 823 fcoeio->fcoeio_cmd, ret, fcoeio->fcoeio_status); 824 825 fcoeiocmd_release_buf: 826 if (ret == 0) { 827 ret = fcoe_copyout_iocdata(data, mode, fcoeio, obuf); 828 } else if (fcoeio->fcoeio_status) { 829 (void) fcoe_copyout_iocdata(data, mode, fcoeio, obuf); 830 } 831 832 if (obuf != NULL) { 833 kmem_free(obuf, fcoeio->fcoeio_olen); 834 obuf = NULL; 835 } 836 if (abuf != NULL) { 837 kmem_free(abuf, fcoeio->fcoeio_alen); 838 abuf = NULL; 839 } 840 841 if (ibuf != NULL) { 842 kmem_free(ibuf, fcoeio->fcoeio_ilen); 843 ibuf = NULL; 844 } 845 kmem_free(fcoeio, sizeof (fcoeio_t)); 846 847 return (ret); 848 } 849 850 /* 851 * Finish final initialization 852 */ 853 static int 854 fcoe_attach_init(fcoe_soft_state_t *ss) 855 { 856 char taskq_name[TASKQ_NAME_LEN]; 857 858 if (ddi_create_minor_node(ss->ss_dip, "admin", S_IFCHR, 859 ddi_get_instance(ss->ss_dip), DDI_PSEUDO, 0) != DDI_SUCCESS) { 860 FCOE_LOG("FCOE", "ddi_create_minor_node failed"); 861 return (FCOE_FAILURE); 862 } 863 864 /* 865 * watchdog responsible for release frame and dispatch events 866 */ 867 (void) snprintf(taskq_name, sizeof (taskq_name), "fcoe_mac"); 868 taskq_name[TASKQ_NAME_LEN - 1] = 0; 869 if ((ss->ss_watchdog_taskq = ddi_taskq_create(NULL, 870 taskq_name, 2, TASKQ_DEFAULTPRI, 0)) == NULL) { 871 return (FCOE_FAILURE); 872 } 873 874 ss->ss_ioctl_flags = 0; 875 mutex_init(&ss->ss_ioctl_mutex, NULL, MUTEX_DRIVER, NULL); 876 list_create(&ss->ss_mac_list, sizeof (fcoe_mac_t), 877 offsetof(fcoe_mac_t, fm_ss_node)); 878 list_create(&ss->ss_pfrm_list, sizeof (fcoe_i_frame_t), 879 offsetof(fcoe_i_frame_t, fmi_pending_node)); 880 881 mutex_init(&ss->ss_watch_mutex, 0, MUTEX_DRIVER, 0); 882 cv_init(&ss->ss_watch_cv, NULL, CV_DRIVER, NULL); 883 ss->ss_flags &= ~SS_FLAG_TERMINATE_WATCHDOG; 884 (void) ddi_taskq_dispatch(ss->ss_watchdog_taskq, 885 fcoe_watchdog, ss, DDI_SLEEP); 886 while ((ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) == 0) { 887 delay(10); 888 } 889 fcoe_nworkers = ddi_prop_get_int(DDI_DEV_T_ANY, ss->ss_dip, 890 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, (char *)fcoe_workers_num, 4); 891 if (fcoe_nworkers < 1) { 892 fcoe_nworkers = 4; 893 } 894 fcoe_worker_init(); 895 896 ddi_report_dev(ss->ss_dip); 897 return (FCOE_SUCCESS); 898 } 899 900 /* 901 * Finish final uninitialization 902 */ 903 static int 904 fcoe_detach_uninit(fcoe_soft_state_t *ss) 905 { 906 int ret; 907 if (!list_is_empty(&ss->ss_mac_list)) { 908 FCOE_LOG("fcoe", "ss_mac_list is not empty when detach"); 909 return (FCOE_FAILURE); 910 } 911 912 if ((ret = fcoe_worker_fini()) != FCOE_SUCCESS) { 913 return (ret); 914 } 915 916 /* 917 * Stop watchdog 918 */ 919 if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 920 mutex_enter(&ss->ss_watch_mutex); 921 ss->ss_flags |= SS_FLAG_TERMINATE_WATCHDOG; 922 cv_broadcast(&ss->ss_watch_cv); 923 mutex_exit(&ss->ss_watch_mutex); 924 while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) { 925 delay(10); 926 } 927 } 928 929 ddi_taskq_destroy(ss->ss_watchdog_taskq); 930 mutex_destroy(&ss->ss_watch_mutex); 931 cv_destroy(&ss->ss_watch_cv); 932 933 ddi_remove_minor_node(ss->ss_dip, NULL); 934 mutex_destroy(&ss->ss_ioctl_mutex); 935 list_destroy(&ss->ss_mac_list); 936 937 return (FCOE_SUCCESS); 938 } 939 940 /* 941 * Return mac instance if it exist, or else return NULL. 942 */ 943 fcoe_mac_t * 944 fcoe_lookup_mac_by_id(datalink_id_t linkid) 945 { 946 fcoe_mac_t *mac = NULL; 947 948 ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex)); 949 for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac; 950 mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) { 951 if (linkid != mac->fm_linkid) { 952 continue; 953 } 954 return (mac); 955 } 956 return (NULL); 957 } 958 959 /* 960 * Return B_TRUE if mac exists, or else return B_FALSE 961 */ 962 static boolean_t 963 fcoe_mac_existed(fcoe_mac_t *pmac) 964 { 965 fcoe_mac_t *mac = NULL; 966 967 ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex)); 968 for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac; 969 mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) { 970 if (mac == pmac) { 971 return (B_TRUE); 972 } 973 } 974 return (B_FALSE); 975 } 976 977 /* 978 * port wwn will start with 20:..., node wwn will start with 10:... 979 */ 980 static void 981 fcoe_init_wwn_from_mac(uint8_t *wwn, uint8_t *mac, int is_pwwn, uint8_t idx) 982 { 983 ASSERT(wwn != NULL); 984 ASSERT(mac != NULL); 985 wwn[0] = (is_pwwn + 1) << 4; 986 wwn[1] = idx; 987 bcopy(mac, wwn + 2, ETHERADDRL); 988 } 989 990 /* 991 * Return fcoe_mac if it exists, otherwise create a new one 992 */ 993 static fcoe_mac_t * 994 fcoe_create_mac_by_id(datalink_id_t linkid) 995 { 996 fcoe_mac_t *mac = NULL; 997 ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex)); 998 999 mac = fcoe_lookup_mac_by_id(linkid); 1000 if (mac != NULL) { 1001 FCOE_LOG("fcoe", "fcoe_create_mac_by_id found one mac %d", 1002 linkid); 1003 return (mac); 1004 } 1005 1006 mac = kmem_zalloc(sizeof (fcoe_mac_t), KM_SLEEP); 1007 mac->fm_linkid = linkid; 1008 mac->fm_flags = 0; 1009 mac->fm_ss = fcoe_global_ss; 1010 list_insert_tail(&mac->fm_ss->ss_mac_list, mac); 1011 FCOE_LOG("fcoe", "fcoe_create_mac_by_id created one mac %d", linkid); 1012 return (mac); 1013 } 1014 1015 void 1016 fcoe_destroy_mac(fcoe_mac_t *mac) 1017 { 1018 ASSERT(mac != NULL); 1019 list_remove(&mac->fm_ss->ss_mac_list, mac); 1020 kmem_free(mac, sizeof (fcoe_mac_t)); 1021 } 1022 1023 /* 1024 * raw frame layout: 1025 * ethernet header + vlan header (optional) + FCoE header + 1026 * FC frame + FCoE tailer 1027 */ 1028 /* ARGSUSED */ 1029 mblk_t * 1030 fcoe_get_mblk(fcoe_mac_t *mac, uint32_t raw_frame_size) 1031 { 1032 mblk_t *mp; 1033 int err; 1034 1035 /* 1036 * FCFH_SIZE + PADDING_SIZE 1037 */ 1038 ASSERT(raw_frame_size >= 60); 1039 while ((mp = allocb((size_t)raw_frame_size, 0)) == NULL) { 1040 if ((err = strwaitbuf((size_t)raw_frame_size, BPRI_LO)) != 0) { 1041 FCOE_LOG("fcoe_get_mblk", "strwaitbuf return %d", err); 1042 return (NULL); 1043 } 1044 } 1045 mp->b_wptr = mp->b_rptr + raw_frame_size; 1046 1047 /* 1048 * We should always zero FC frame header 1049 */ 1050 bzero(mp->b_rptr + PADDING_HEADER_SIZE, 1051 sizeof (fcoe_fc_frame_header_t)); 1052 return (mp); 1053 } 1054 1055 static void 1056 fcoe_watchdog(void *arg) 1057 { 1058 fcoe_soft_state_t *ss = (fcoe_soft_state_t *)arg; 1059 fcoe_i_frame_t *fmi; 1060 fcoe_mac_t *mac = NULL; 1061 1062 FCOE_LOG("fcoe", "fcoe_soft_state is %p", ss); 1063 1064 mutex_enter(&ss->ss_watch_mutex); 1065 ss->ss_flags |= SS_FLAG_WATCHDOG_RUNNING; 1066 while ((ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG) == 0) { 1067 while (fmi = (fcoe_i_frame_t *)list_head(&ss->ss_pfrm_list)) { 1068 list_remove(&ss->ss_pfrm_list, fmi); 1069 mutex_exit(&ss->ss_watch_mutex); 1070 1071 mac = EPORT2MAC(fmi->fmi_frame->frm_eport); 1072 mac->fm_client.ect_release_sol_frame(fmi->fmi_frame); 1073 1074 mutex_enter(&ss->ss_watch_mutex); 1075 mac->fm_frm_cnt--; 1076 } 1077 1078 ss->ss_flags |= SS_FLAG_DOG_WAITING; 1079 (void) cv_wait(&ss->ss_watch_cv, &ss->ss_watch_mutex); 1080 ss->ss_flags &= ~SS_FLAG_DOG_WAITING; 1081 } 1082 1083 ss->ss_flags &= ~SS_FLAG_WATCHDOG_RUNNING; 1084 mutex_exit(&ss->ss_watch_mutex); 1085 } 1086 1087 static void 1088 fcoe_worker_init() 1089 { 1090 uint32_t i; 1091 1092 fcoe_nworkers_running = 0; 1093 fcoe_worker_taskq = ddi_taskq_create(0, "FCOE_WORKER_TASKQ", 1094 fcoe_nworkers, TASKQ_DEFAULTPRI, 0); 1095 fcoe_workers = (fcoe_worker_t *)kmem_zalloc(sizeof (fcoe_worker_t) * 1096 fcoe_nworkers, KM_SLEEP); 1097 for (i = 0; i < fcoe_nworkers; i++) { 1098 fcoe_worker_t *w = &fcoe_workers[i]; 1099 mutex_init(&w->worker_lock, NULL, MUTEX_DRIVER, NULL); 1100 cv_init(&w->worker_cv, NULL, CV_DRIVER, NULL); 1101 w->worker_flags &= ~FCOE_WORKER_TERMINATE; 1102 list_create(&w->worker_frm_list, sizeof (fcoe_i_frame_t), 1103 offsetof(fcoe_i_frame_t, fmi_pending_node)); 1104 (void) ddi_taskq_dispatch(fcoe_worker_taskq, fcoe_worker_frame, 1105 w, DDI_SLEEP); 1106 } 1107 while (fcoe_nworkers_running != fcoe_nworkers) { 1108 delay(10); 1109 } 1110 } 1111 1112 static int 1113 fcoe_worker_fini() 1114 { 1115 uint32_t i; 1116 1117 for (i = 0; i < fcoe_nworkers; i++) { 1118 fcoe_worker_t *w = &fcoe_workers[i]; 1119 mutex_enter(&w->worker_lock); 1120 if (w->worker_flags & FCOE_WORKER_STARTED) { 1121 w->worker_flags |= FCOE_WORKER_TERMINATE; 1122 cv_signal(&w->worker_cv); 1123 } 1124 mutex_exit(&w->worker_lock); 1125 } 1126 1127 while (fcoe_nworkers_running != 0) { 1128 delay(drv_usectohz(10000)); 1129 } 1130 1131 ddi_taskq_destroy(fcoe_worker_taskq); 1132 kmem_free(fcoe_workers, sizeof (fcoe_worker_t) * fcoe_nworkers); 1133 fcoe_workers = NULL; 1134 return (FCOE_SUCCESS); 1135 } 1136 1137 static int 1138 fcoe_crc_verify(fcoe_frame_t *frm) 1139 { 1140 uint32_t crc; 1141 uint8_t *crc_array = FRM2FMI(frm)->fmi_fft->fft_crc; 1142 uint32_t crc_from_frame = ~(crc_array[0] | (crc_array[1] << 8) | 1143 (crc_array[2] << 16) | (crc_array[3] << 24)); 1144 CRC32(crc, frm->frm_fc_frame, frm->frm_fc_frame_size, -1U, crc32_table); 1145 return (crc == crc_from_frame ? FCOE_SUCCESS : FCOE_FAILURE); 1146 } 1147 1148 static void 1149 fcoe_worker_frame(void *arg) 1150 { 1151 fcoe_worker_t *w = (fcoe_worker_t *)arg; 1152 fcoe_i_frame_t *fmi; 1153 int ret; 1154 1155 atomic_inc_32(&fcoe_nworkers_running); 1156 mutex_enter(&w->worker_lock); 1157 w->worker_flags |= FCOE_WORKER_STARTED | FCOE_WORKER_ACTIVE; 1158 while ((w->worker_flags & FCOE_WORKER_TERMINATE) == 0) { 1159 /* 1160 * loop through the frames 1161 */ 1162 while (fmi = list_head(&w->worker_frm_list)) { 1163 list_remove(&w->worker_frm_list, fmi); 1164 mutex_exit(&w->worker_lock); 1165 /* 1166 * do the checksum 1167 */ 1168 ret = fcoe_crc_verify(fmi->fmi_frame); 1169 if (ret == FCOE_SUCCESS) { 1170 fmi->fmi_mac->fm_client.ect_rx_frame( 1171 fmi->fmi_frame); 1172 } else { 1173 fcoe_release_frame(fmi->fmi_frame); 1174 } 1175 mutex_enter(&w->worker_lock); 1176 w->worker_ntasks--; 1177 } 1178 w->worker_flags &= ~FCOE_WORKER_ACTIVE; 1179 cv_wait(&w->worker_cv, &w->worker_lock); 1180 w->worker_flags |= FCOE_WORKER_ACTIVE; 1181 } 1182 w->worker_flags &= ~(FCOE_WORKER_STARTED | FCOE_WORKER_ACTIVE); 1183 mutex_exit(&w->worker_lock); 1184 atomic_dec_32(&fcoe_nworkers_running); 1185 list_destroy(&w->worker_frm_list); 1186 } 1187 1188 void 1189 fcoe_post_frame(fcoe_frame_t *frm) 1190 { 1191 fcoe_worker_t *w; 1192 uint16_t oxid = FRM_OXID(frm); 1193 1194 w = &fcoe_workers[oxid % fcoe_nworkers_running]; 1195 mutex_enter(&w->worker_lock); 1196 list_insert_tail(&w->worker_frm_list, frm->frm_fcoe_private); 1197 w->worker_ntasks++; 1198 if ((w->worker_flags & FCOE_WORKER_ACTIVE) == 0) { 1199 cv_signal(&w->worker_cv); 1200 } 1201 mutex_exit(&w->worker_lock); 1202 } 1203 1204 /* 1205 * The max length of every LOG is 158 1206 */ 1207 void 1208 fcoe_trace(caddr_t ident, const char *fmt, ...) 1209 { 1210 va_list args; 1211 char tbuf[160]; 1212 int len; 1213 clock_t curclock; 1214 clock_t usec; 1215 1216 if (fcoe_trace_on == 0) { 1217 return; 1218 } 1219 1220 curclock = ddi_get_lbolt(); 1221 usec = (curclock - fcoe_trace_start) * usec_per_tick; 1222 len = snprintf(tbuf, 158, "%lu.%03lus 0t%lu %s ", (usec / 1223 (1000 * 1000)), ((usec % (1000 * 1000)) / 1000), 1224 curclock, (ident ? ident : "unknown")); 1225 va_start(args, fmt); 1226 len += vsnprintf(tbuf + len, 158 - len, fmt, args); 1227 va_end(args); 1228 1229 if (len > 158) { 1230 len = 158; 1231 } 1232 tbuf[len++] = '\n'; 1233 tbuf[len] = 0; 1234 1235 mutex_enter(&fcoe_trace_buf_lock); 1236 bcopy(tbuf, &fcoe_trace_buf[fcoe_trace_buf_curndx], len+1); 1237 fcoe_trace_buf_curndx += len; 1238 if (fcoe_trace_buf_curndx > (fcoe_trace_buf_size - 320)) { 1239 fcoe_trace_buf_curndx = 0; 1240 } 1241 mutex_exit(&fcoe_trace_buf_lock); 1242 } 1243 1244 /* 1245 * Check whether the pwwn or nwwn already exist or not 1246 * Return value: 1247 * 1: PWWN conflicted 1248 * -1: NWWN conflicted 1249 * 0: No conflict 1250 */ 1251 static int 1252 fcoe_cmp_wwn(fcoe_mac_t *checkedmac) 1253 { 1254 fcoe_mac_t *mac; 1255 uint8_t *nwwn, *pwwn, *cnwwn, *cpwwn; 1256 1257 cnwwn = checkedmac->fm_eport.eport_nodewwn; 1258 cpwwn = checkedmac->fm_eport.eport_portwwn; 1259 ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex)); 1260 1261 for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac; 1262 mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) { 1263 if (mac == checkedmac) { 1264 continue; 1265 } 1266 nwwn = mac->fm_eport.eport_nodewwn; 1267 pwwn = mac->fm_eport.eport_portwwn; 1268 1269 if (memcmp(nwwn, cnwwn, 8) == 0) { 1270 return (-1); 1271 } 1272 1273 if (memcmp(pwwn, cpwwn, 8) == 0) { 1274 return (1); 1275 } 1276 } 1277 return (0); 1278 } 1279 1280 static int 1281 fcoe_get_port_list(fcoe_port_instance_t *ports, int count) 1282 { 1283 fcoe_mac_t *mac = NULL; 1284 int i = 0; 1285 1286 ASSERT(ports != NULL); 1287 ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex)); 1288 1289 for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac; 1290 mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) { 1291 if (i < count) { 1292 bcopy(mac->fm_eport.eport_portwwn, 1293 ports[i].fpi_pwwn, 8); 1294 ports[i].fpi_mac_linkid = mac->fm_linkid; 1295 bcopy(mac->fm_current_addr, 1296 ports[i].fpi_mac_current_addr, ETHERADDRL); 1297 bcopy(mac->fm_primary_addr, 1298 ports[i].fpi_mac_factory_addr, ETHERADDRL); 1299 ports[i].fpi_port_type = 1300 EPORT_CLT_TYPE(&mac->fm_eport); 1301 ports[i].fpi_mtu_size = 1302 mac->fm_eport.eport_mtu; 1303 ports[i].fpi_mac_promisc = 1304 mac->fm_promisc_handle != NULL ? 1 : 0; 1305 } 1306 i++; 1307 } 1308 return (i); 1309 }