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 }