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