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 /*
  23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 #include <sys/conf.h>
  27 #include <sys/ddi.h>
  28 #include <sys/stat.h>
  29 #include <sys/pci.h>
  30 #include <sys/sunddi.h>
  31 #include <sys/modctl.h>
  32 #include <sys/file.h>
  33 #include <sys/cred.h>
  34 #include <sys/byteorder.h>
  35 #include <sys/atomic.h>
  36 #include <sys/scsi/scsi.h>
  37 #include <sys/mac_client.h>
  38 #include <sys/modhash.h>
  39 
  40 /*
  41  * leadville header files
  42  */
  43 #include <sys/fibre-channel/fc.h>
  44 #include <sys/fibre-channel/impl/fc_fcaif.h>
  45 
  46 /*
  47  * fcoe header files
  48  */
  49 #include <sys/fcoe/fcoe_common.h>
  50 
  51 /*
  52  * fcoei header files
  53  */
  54 #include <fcoei.h>
  55 
  56 /*
  57  * forward declaration of stack functions
  58  */
  59 static uint32_t fcoei_xch_check(
  60         mod_hash_key_t key, mod_hash_val_t *val, void *arg);
  61 static int fcoei_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
  62 static int fcoei_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
  63 static int fcoei_open(dev_t *devp, int flag, int otype, cred_t *credp);
  64 static int fcoei_close(dev_t dev, int flag, int otype, cred_t *credp);
  65 static int fcoei_ioctl(
  66         dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval);
  67 static int fcoei_attach_init(fcoei_soft_state_t *ss);
  68 static int fcoei_detach_uninit(fcoei_soft_state_t *ss);
  69 static void fcoei_watchdog(void *arg);
  70 static void fcoei_process_events(fcoei_soft_state_t *ss);
  71 static void fcoei_trigger_fp_attach(void *arg);
  72 static void fcoei_abts_exchange(fcoei_exchange_t *xch);
  73 static void fcoei_clear_watchdog_jobs(fcoei_soft_state_t *ss);
  74 
  75 /*
  76  * Driver identificaton stuff
  77  */
  78 static struct cb_ops fcoei_cb_ops = {
  79         fcoei_open,
  80         fcoei_close,
  81         nodev,
  82         nodev,
  83         nodev,
  84         nodev,
  85         nodev,
  86         fcoei_ioctl,
  87         nodev,
  88         nodev,
  89         nodev,
  90         nochpoll,
  91         ddi_prop_op,
  92         0,
  93         D_MP | D_NEW | D_HOTPLUG,
  94         CB_REV,
  95         nodev,
  96         nodev
  97 };
  98 
  99 static struct dev_ops fcoei_ops = {
 100         DEVO_REV,
 101         0,
 102         nodev,
 103         nulldev,
 104         nulldev,
 105         fcoei_attach,
 106         fcoei_detach,
 107         nodev,
 108         &fcoei_cb_ops,
 109         NULL,
 110         ddi_power,
 111         ddi_quiesce_not_needed
 112 };
 113 
 114 static struct modldrv modldrv = {
 115         &mod_driverops,
 116         FCOEI_NAME_VERSION,
 117         &fcoei_ops,
 118 };
 119 
 120 static struct modlinkage modlinkage = {
 121         MODREV_1,
 122         &modldrv,
 123         NULL
 124 };
 125 
 126 /*
 127  * Driver's global variables
 128  */
 129 void    *fcoei_state       = NULL;
 130 int      fcoei_use_ext_log = 0;
 131 
 132 /*
 133  * Common loadable module entry points _init, _fini, _info
 134  */
 135 int
 136 _init(void)
 137 {
 138         int ret;
 139 
 140         ret = ddi_soft_state_init(&fcoei_state, sizeof (fcoei_soft_state_t), 0);
 141         if (ret != DDI_SUCCESS) {
 142                 FCOEI_LOG(__FUNCTION__, "soft state init failed: %x", ret);
 143                 return (ret);
 144         }
 145 
 146         ret = mod_install(&modlinkage);
 147         if (ret != 0) {
 148                 ddi_soft_state_fini(&fcoei_state);
 149                 FCOEI_LOG(__FUNCTION__, "fcoei mod_install failed: %x", ret);
 150                 return (ret);
 151         }
 152 
 153         /*
 154          * Let FCTL initialize devo_bus_ops
 155          */
 156         fc_fca_init(&fcoei_ops);
 157 
 158         FCOEI_LOG(__FUNCTION__, "fcoei _init succeeded");
 159         return (ret);
 160 }
 161 
 162 int
 163 _fini(void)
 164 {
 165         int ret;
 166 
 167         ret = mod_remove(&modlinkage);
 168         if (ret != 0) {
 169                 FCOEI_EXT_LOG(__FUNCTION__, "fcoei mod_remove failed: %x", ret);
 170                 return (ret);
 171         }
 172 
 173         ddi_soft_state_fini(&fcoei_state);
 174         FCOEI_LOG(__FUNCTION__, "fcoei _fini succeeded");
 175         return (ret);
 176 }
 177 
 178 int
 179 _info(struct modinfo *modinfop)
 180 {
 181         return (mod_info(&modlinkage, modinfop));
 182 }
 183 
 184 /*
 185  * Autoconfiguration entry points: attach, detach, getinfo
 186  */
 187 
 188 static int
 189 fcoei_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 190 {
 191         int                      ret;
 192         int                      fcoe_ret;
 193         int                      instance;
 194         fcoei_soft_state_t      *ss;
 195 
 196         instance = ddi_get_instance(dip);
 197         FCOEI_LOG(__FUNCTION__, "instance is %d", instance);
 198         switch (cmd) {
 199         case DDI_ATTACH:
 200                 ret = ddi_soft_state_zalloc(fcoei_state, instance);
 201                 if (ret != DDI_SUCCESS) {
 202                         FCOEI_LOG(__FUNCTION__, "ss zalloc failed: %x", ret);
 203                         return (ret);
 204                 }
 205 
 206                 /*
 207                  * Get the soft state, and do basic initialization with dip
 208                  */
 209                 ss = ddi_get_soft_state(fcoei_state, instance);
 210                 ss->ss_dip = dip;
 211 
 212                 fcoe_ret = fcoei_attach_init(ss);
 213                 if (fcoe_ret != FCOE_SUCCESS) {
 214                         ddi_soft_state_free(fcoei_state, instance);
 215                         FCOEI_LOG(__FUNCTION__, "fcoei_attach_init failed: "
 216                             "%x", fcoe_ret);
 217                         return (DDI_FAILURE);
 218                 }
 219 
 220                 ss->ss_flags |= SS_FLAG_TRIGGER_FP_ATTACH;
 221                 (void) timeout(fcoei_trigger_fp_attach, ss, FCOE_SEC2TICK(1));
 222                 FCOEI_LOG(__FUNCTION__, "fcoei_attach succeeded: dip-%p, "
 223                     "cmd-%x", dip, cmd);
 224                 return (DDI_SUCCESS);
 225 
 226         case DDI_RESUME:
 227                 return (DDI_SUCCESS);
 228 
 229         default:
 230                 FCOEI_LOG(__FUNCTION__, "unsupported attach cmd-%X", cmd);
 231                 return (DDI_FAILURE);
 232         }
 233 }
 234 
 235 static int
 236 fcoei_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 237 {
 238         int                      fcoe_ret;
 239         int                      instance;
 240         fcoei_soft_state_t      *ss;
 241 
 242         instance = ddi_get_instance(dip);
 243         ss = ddi_get_soft_state(fcoei_state, instance);
 244         if (ss == NULL) {
 245                 FCOEI_LOG(__FUNCTION__, "get ss failed: dip-%p", dip);
 246                 return (DDI_FAILURE);
 247         }
 248 
 249         switch (cmd) {
 250         case DDI_DETACH:
 251                 if (ss->ss_flags & SS_FLAG_TRIGGER_FP_ATTACH) {
 252                         FCOEI_LOG(__FUNCTION__, "still await fp attach");
 253                         return (DDI_FAILURE);
 254                 }
 255 
 256                 if (ss->ss_flags & SS_FLAG_LV_BOUND) {
 257                         FCOEI_LOG(__FUNCTION__, "fp is not detached yet");
 258                         return (DDI_FAILURE);
 259                 }
 260 
 261                 fcoe_ret = fcoei_detach_uninit(ss);
 262                 if (fcoe_ret != FCOE_SUCCESS) {
 263                         FCOEI_LOG(__FUNCTION__, "fcoei_detach_uninit failed:"
 264                             " dip-%p, fcoe_ret-%d", dip, fcoe_ret);
 265                         return (DDI_FAILURE);
 266                 }
 267 
 268                 FCOEI_LOG(__FUNCTION__, "succeeded: dip-%p, cmd-%x", dip, cmd);
 269                 return (DDI_SUCCESS);
 270 
 271         case DDI_SUSPEND:
 272                 return (DDI_SUCCESS);
 273 
 274         default:
 275                 FCOEI_LOG(__FUNCTION__, "unspported detach cmd-%X", cmd);
 276                 return (DDI_FAILURE);
 277         }
 278 }
 279 
 280 /*
 281  * Device access entry points: open, close, ioctl
 282  */
 283 
 284 static int
 285 fcoei_open(dev_t *devp, int flag, int otype, cred_t *credp)
 286 {
 287         fcoei_soft_state_t      *ss;
 288 
 289         if (otype != OTYP_CHR) {
 290                 FCOEI_LOG(__FUNCTION__, "flag: %x", flag);
 291                 return (EINVAL);
 292         }
 293 
 294         if (drv_priv(credp)) {
 295                 return (EPERM);
 296         }
 297 
 298         /*
 299          * First of all, get related soft state
 300          */
 301         ss = ddi_get_soft_state(fcoei_state, (int)getminor(*devp));
 302         if (ss == NULL) {
 303                 return (ENXIO);
 304         }
 305 
 306         mutex_enter(&ss->ss_ioctl_mutex);
 307         if (ss->ss_ioctl_flags & FCOEI_IOCTL_FLAG_OPEN) {
 308                 /*
 309                  * We don't support concurrent open
 310                  */
 311                 mutex_exit(&ss->ss_ioctl_mutex);
 312                 return (EBUSY);
 313         }
 314 
 315         ss->ss_ioctl_flags |= FCOEI_IOCTL_FLAG_OPEN;
 316         mutex_exit(&ss->ss_ioctl_mutex);
 317 
 318         return (0);
 319 }
 320 
 321 static int
 322 fcoei_close(dev_t dev, int flag, int otype, cred_t *credp)
 323 {
 324         fcoei_soft_state_t      *ss;
 325 
 326         if (otype != OTYP_CHR) {
 327                 FCOEI_LOG(__FUNCTION__, "flag: %x, %p", flag, credp);
 328                 return (EINVAL);
 329         }
 330 
 331         /*
 332          * First of all, get related soft state
 333          */
 334         ss = ddi_get_soft_state(fcoei_state, (int)getminor(dev));
 335         if (ss == NULL) {
 336                 return (ENXIO);
 337         }
 338 
 339         mutex_enter(&ss->ss_ioctl_mutex);
 340         if (!(ss->ss_ioctl_flags & FCOEI_IOCTL_FLAG_OPEN)) {
 341                 /*
 342                  * If it's not open, we can exit
 343                  */
 344 
 345                 mutex_exit(&ss->ss_ioctl_mutex);
 346                 return (ENODEV);
 347         }
 348 
 349         ss->ss_ioctl_flags &= ~FCOEI_IOCTL_FLAG_OPEN;
 350         mutex_exit(&ss->ss_ioctl_mutex);
 351 
 352         return (0);
 353 }
 354 
 355 static int
 356 fcoei_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
 357     cred_t *credp, int *rval)
 358 {
 359         fcoei_soft_state_t      *ss;
 360         int                      ret = 0;
 361 
 362         if (drv_priv(credp) != 0) {
 363                 FCOEI_LOG(__FUNCTION__, "data: %p, %x", data, mode);
 364                 return (EPERM);
 365         }
 366 
 367         /*
 368          * Get related soft state
 369          */
 370         ss = ddi_get_soft_state(fcoei_state, (int32_t)getminor(dev));
 371         if (!ss) {
 372                 return (ENXIO);
 373         }
 374 
 375         /*
 376          * Process ioctl
 377          */
 378         switch (cmd) {
 379 
 380         default:
 381                 FCOEI_LOG(__FUNCTION__, "ioctl-0x%02X", cmd);
 382                 ret = ENOTTY;
 383         }
 384 
 385         /*
 386          * Set return value
 387          */
 388         *rval = ret;
 389         return (ret);
 390 }
 391 
 392 /*
 393  * fcoei_attach_init
 394  *      init related stuff of the soft state
 395  *
 396  * Input:
 397  *      ss = the soft state that will be processed
 398  *
 399  * Return:
 400  *      if it succeeded or not
 401  *
 402  * Comment:
 403  *      N/A
 404  */
 405 static int
 406 fcoei_attach_init(fcoei_soft_state_t *ss)
 407 {
 408         fcoe_port_t             *eport;
 409         fcoe_client_t            client_fcoei;
 410         char                     taskq_name[32];
 411         int                      ret;
 412         la_els_logi_t           *els = &ss->ss_els_logi;
 413         svc_param_t             *class3_param;
 414 
 415         /*
 416          * Register fcoei to FCOE as its client
 417          */
 418         client_fcoei.ect_eport_flags = EPORT_FLAG_INI_MODE |
 419             EPORT_FLAG_IS_DIRECT_P2P;
 420         client_fcoei.ect_max_fc_frame_size = FCOE_MAX_FC_FRAME_SIZE;
 421         client_fcoei.ect_private_frame_struct_size = sizeof (fcoei_frame_t);
 422         fcoei_init_ect_vectors(&client_fcoei);
 423         client_fcoei.ect_client_port_struct = ss;
 424         client_fcoei.ect_fcoe_ver = FCOE_VER_NOW;
 425         FCOEI_LOG(__FUNCTION__, "version: %x %x", FCOE_VER_NOW, fcoe_ver_now);
 426         ret = ddi_prop_get_int(DDI_DEV_T_ANY, ss->ss_dip,
 427             DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_id", -1);
 428         if (ret == -1) {
 429                 FCOEI_LOG(__FUNCTION__, "get mac_id failed");
 430                 return (DDI_FAILURE);
 431         } else {
 432                 client_fcoei.ect_channelid = ret;
 433         }
 434 
 435         /*
 436          * It's fcoe's responsiblity to initialize eport's all elements,
 437          * so we needn't do eport initialization
 438          */
 439         eport = fcoe_register_client(&client_fcoei);
 440         if (eport == NULL) {
 441                 goto fail_register_client;
 442         } else {
 443                 ss->ss_eport = eport;
 444                 FCOE_SET_DEFAULT_FPORT_ADDR(eport->eport_efh_dst);
 445         }
 446 
 447         /*
 448          * Now it's time to register fca_tran to FCTL
 449          * Remember fc_local_port is transparent to FCA (fcoei)
 450          */
 451         ss->ss_fca_tran.fca_version  = FCTL_FCA_MODREV_5;
 452         ss->ss_fca_tran.fca_numports = 1;
 453         ss->ss_fca_tran.fca_pkt_size = sizeof (fcoei_exchange_t);
 454         ss->ss_fca_tran.fca_cmd_max  = 2048;
 455 
 456         /*
 457          * scsi_tran_hba_setup could need these stuff
 458          */
 459         ss->ss_fca_tran.fca_dma_lim  = NULL;
 460         ss->ss_fca_tran.fca_iblock   = NULL;
 461         ss->ss_fca_tran.fca_dma_attr = NULL;
 462         ss->ss_fca_tran.fca_acc_attr = NULL;
 463 
 464         /*
 465          * Initialize vectors
 466          */
 467         fcoei_init_fcatran_vectors(&ss->ss_fca_tran);
 468 
 469         /*
 470          * fc_fca_attach only sets driver's private, it has nothing to with
 471          * common port object between fcoei and leadville.
 472          * After this attach, fp_attach will be triggered, and it will call
 473          * fca_bind_port to let fcoei to know about common port object.
 474          */
 475         if (fc_fca_attach(ss->ss_dip, &ss->ss_fca_tran) != DDI_SUCCESS) {
 476                 goto fail_fca_attach;
 477         }
 478 
 479         /*
 480          * It's time to do ss initialization
 481          */
 482         ret = ddi_create_minor_node(ss->ss_dip, "admin",
 483             S_IFCHR, ddi_get_instance(ss->ss_dip), DDI_NT_NEXUS, 0);
 484         if (ret != DDI_SUCCESS) {
 485                 goto fail_minor_node;
 486         }
 487 
 488         ss->ss_flags    = 0;
 489         ss->ss_port     = NULL;
 490         /*
 491          * ss->ss_eport has been initialized
 492          */
 493 
 494         ss->ss_sol_oxid_hash = mod_hash_create_idhash(
 495             "fcoei_sol_oxid_hash", FCOEI_SOL_HASH_SIZE,
 496             mod_hash_null_valdtor);
 497         ss->ss_unsol_rxid_hash = mod_hash_create_idhash(
 498             "fcoei_unsol_rxid_hash", FCOEI_UNSOL_HASH_SIZE,
 499             mod_hash_null_valdtor);
 500         list_create(&ss->ss_comp_xch_list, sizeof (fcoei_exchange_t),
 501             offsetof(fcoei_exchange_t, xch_comp_node));
 502         ss->ss_next_sol_oxid   = 0xFFFF;
 503         ss->ss_next_unsol_rxid = 0xFFFF;
 504 
 505         mutex_init(&ss->ss_watchdog_mutex, 0, MUTEX_DRIVER, 0);
 506         cv_init(&ss->ss_watchdog_cv, NULL, CV_DRIVER, NULL);
 507         (void) snprintf(taskq_name, 32, "leadville_fcoei_%d_taskq",
 508             ddi_get_instance(ss->ss_dip));
 509         taskq_name[31] = 0;
 510         ss->ss_taskq = ddi_taskq_create(ss->ss_dip,
 511             taskq_name, 64, TASKQ_DEFAULTPRI, DDI_SLEEP);
 512 
 513         ss->ss_link_state      = FC_STATE_OFFLINE;
 514         ss->ss_link_speed      = 0;
 515         ss->ss_port_event_counter = 0;
 516 
 517         list_create(&ss->ss_event_list, sizeof (fcoei_event_t),
 518             offsetof(fcoei_event_t, ae_node));
 519 
 520         ss->ss_sol_cnt1   = 0;
 521         ss->ss_sol_cnt2   = 0;
 522         ss->ss_sol_cnt          = &ss->ss_sol_cnt1;
 523         ss->ss_unsol_cnt1 = 0;
 524         ss->ss_unsol_cnt2 = 0;
 525         ss->ss_unsol_cnt  = &ss->ss_unsol_cnt1;
 526         ss->ss_ioctl_flags = 0;
 527 
 528         mutex_init(&ss->ss_ioctl_mutex, 0, MUTEX_DRIVER, 0);
 529 
 530         bcopy(eport->eport_portwwn, els->nport_ww_name.raw_wwn, 8);
 531         bcopy(eport->eport_nodewwn, els->node_ww_name.raw_wwn, 8);
 532         els->common_service.fcph_version = 0x2008;
 533         els->common_service.btob_credit = 3;
 534         els->common_service.cmn_features = 0x8800;
 535         els->common_service.conc_sequences = 0xff;
 536         els->common_service.relative_offset = 3;
 537         els->common_service.e_d_tov = 0x07d0;
 538         class3_param = (svc_param_t *)&els->class_3;
 539         class3_param->class_opt = 0x8800;
 540         class3_param->rcv_size = els->common_service.rx_bufsize = 2048;
 541         class3_param->conc_sequences = 0xff;
 542         class3_param->open_seq_per_xchng = 1;
 543 
 544         /*
 545          * Fill out RNID Management Information
 546          */
 547         bcopy(ss->ss_eport->eport_portwwn, ss->ss_rnid.global_id, 8);
 548         ss->ss_rnid.unit_type  = FCOEI_RNID_HBA;
 549         ss->ss_rnid.ip_version = FCOEI_RNID_IPV4;
 550 
 551         /*
 552          * Start our watchdog
 553          */
 554         (void) ddi_taskq_dispatch(ss->ss_taskq,
 555             fcoei_watchdog, ss, DDI_SLEEP);
 556         while (!(ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING)) {
 557                 delay(50);
 558         }
 559 
 560         /*
 561          * Report the device to the system
 562          */
 563         ddi_report_dev(ss->ss_dip);
 564         return (DDI_SUCCESS);
 565 
 566 
 567 fail_minor_node:
 568         FCOEI_LOG(__FUNCTION__, "fail_minor_node");
 569         (void) fc_fca_detach(ss->ss_dip);
 570 
 571 fail_fca_attach:
 572         eport->eport_deregister_client(eport);
 573         FCOEI_LOG(__FUNCTION__, "fail_fca_attach");
 574 
 575 fail_register_client:
 576         FCOEI_LOG(__FUNCTION__, "fail_register_client");
 577         return (DDI_FAILURE);
 578 }
 579 
 580 /*
 581  * fcoei_detach_uninit
 582  *      uninit related stuff of the soft state
 583  *
 584  * Input:
 585  *      ss = the soft state that will be processed
 586  *
 587  * Return:
 588  *      if it succeeded or not
 589  *
 590  * Comment:
 591  *      N/A
 592  */
 593 int
 594 fcoei_detach_uninit(fcoei_soft_state_t *ss)
 595 {
 596         /*
 597          * Stop watchdog first
 598          */
 599         if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
 600                 ss->ss_flags |= SS_FLAG_TERMINATE_WATCHDOG;
 601                 cv_broadcast(&ss->ss_watchdog_cv);
 602         }
 603 
 604         /*
 605          * Destroy the taskq
 606          */
 607         ddi_taskq_wait(ss->ss_taskq);
 608         ddi_taskq_destroy(ss->ss_taskq);
 609 
 610         /*
 611          * Release all allocated resources
 612          */
 613         mutex_destroy(&ss->ss_ioctl_mutex);
 614         mutex_destroy(&ss->ss_watchdog_mutex);
 615         cv_destroy(&ss->ss_watchdog_cv);
 616         mod_hash_destroy_idhash(ss->ss_sol_oxid_hash);
 617         mod_hash_destroy_idhash(ss->ss_unsol_rxid_hash);
 618         list_destroy(&ss->ss_event_list);
 619         ss->ss_eport->eport_deregister_client(ss->ss_eport);
 620         ddi_remove_minor_node(ss->ss_dip, NULL);
 621 
 622         /*
 623          * Release itself
 624          */
 625         ddi_soft_state_free(fcoei_state, ddi_get_instance(ss->ss_dip));
 626         return (FCOE_SUCCESS);
 627 }
 628 
 629 /*
 630  * fcoei_watchdog
 631  *      Perform periodic checking and routine tasks
 632  *
 633  * Input:
 634  *      arg = the soft state that will be processed
 635  *
 636  * Return:
 637  *      N/A
 638  *
 639  * Comment:
 640  *      N/A
 641  */
 642 static void
 643 fcoei_watchdog(void *arg)
 644 {
 645         fcoei_soft_state_t      *ss;
 646         clock_t                  tmp_delay;
 647         clock_t                  start_clock;
 648         clock_t                  last_clock;
 649 
 650         /*
 651          * For debugging
 652          */
 653         ss = (fcoei_soft_state_t *)arg;
 654         FCOEI_LOG(__FUNCTION__, "ss %p", ss);
 655         FCOEI_LOG(__FUNCTION__, "sol_hash %p", ss->ss_sol_oxid_hash);
 656         FCOEI_LOG(__FUNCTION__, "unsol_hash %p", ss->ss_unsol_rxid_hash);
 657         ss->ss_flags |= SS_FLAG_WATCHDOG_RUNNING;
 658         tmp_delay = FCOE_SEC2TICK(1) / 2;
 659         last_clock = CURRENT_CLOCK;
 660 
 661         /*
 662          * If nobody reqeusts to terminate the watchdog, we will work forever
 663          */
 664         while (!(ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG)) {
 665                 /*
 666                  * We handle all asynchronous events serially
 667                  */
 668                 fcoei_process_events(ss);
 669 
 670                 /*
 671                  * To avoid to check timing too freqently, we check
 672                  * if we need skip timing stuff.
 673                  */
 674                 start_clock = CURRENT_CLOCK;
 675                 if ((start_clock - last_clock) < tmp_delay) {
 676                         goto end_timing;
 677                 } else {
 678                         last_clock = start_clock;
 679                 }
 680 
 681                 /*
 682                  * It's time to do timeout checking of solicited exchanges
 683                  */
 684                 if (ss->ss_sol_cnt == (&ss->ss_sol_cnt1)) {
 685                         if (ss->ss_sol_cnt2 == 0) {
 686                                 ss->ss_sol_cnt = &ss->ss_sol_cnt2;
 687                         } else {
 688                                 mod_hash_walk(ss->ss_sol_oxid_hash,
 689                                     fcoei_xch_check, ss);
 690                         }
 691                 } else {
 692                         if (ss->ss_sol_cnt1 == 0) {
 693                                 ss->ss_sol_cnt = &ss->ss_sol_cnt1;
 694                         } else {
 695                                 mod_hash_walk(ss->ss_sol_oxid_hash,
 696                                     fcoei_xch_check, ss);
 697                         }
 698                 }
 699 
 700                 /*
 701                  * It's time to do timeout checking of unsolicited exchange
 702                  */
 703                 if (ss->ss_unsol_cnt == (&ss->ss_unsol_cnt1)) {
 704                         if (ss->ss_unsol_cnt2 == 0) {
 705                                 ss->ss_unsol_cnt = &ss->ss_unsol_cnt2;
 706                         } else {
 707                                 mod_hash_walk(ss->ss_unsol_rxid_hash,
 708                                     fcoei_xch_check, ss);
 709                         }
 710                 } else {
 711                         if (ss->ss_unsol_cnt1 == 0) {
 712                                 ss->ss_unsol_cnt = &ss->ss_unsol_cnt1;
 713                         } else {
 714                                 mod_hash_walk(ss->ss_unsol_rxid_hash,
 715                                     fcoei_xch_check, ss);
 716                         }
 717                 }
 718 
 719                 /*
 720                  * Check if there are exchanges which are ready to complete
 721                  */
 722                 fcoei_handle_comp_xch_list(ss);
 723 
 724         end_timing:
 725                 /*
 726                  * Wait for next cycle
 727                  */
 728                 mutex_enter(&ss->ss_watchdog_mutex);
 729                 ss->ss_flags |= SS_FLAG_WATCHDOG_IDLE;
 730                 if (!list_is_empty(&ss->ss_event_list)) {
 731                         goto skip_wait;
 732                 }
 733 
 734                 (void) cv_timedwait(&ss->ss_watchdog_cv,
 735                     &ss->ss_watchdog_mutex, CURRENT_CLOCK +
 736                     (clock_t)tmp_delay);
 737         skip_wait:
 738                 ss->ss_flags &= ~SS_FLAG_WATCHDOG_IDLE;
 739                 mutex_exit(&ss->ss_watchdog_mutex);
 740         }
 741 
 742         /*
 743          * Do clear work before exit
 744          */
 745         fcoei_clear_watchdog_jobs(ss);
 746 
 747         /*
 748          * Watchdog has stopped
 749          */
 750         ss->ss_flags &= ~SS_FLAG_WATCHDOG_RUNNING;
 751 }
 752 
 753 static void
 754 fcoei_clear_watchdog_jobs(fcoei_soft_state_t *ss)
 755 {
 756         fcoei_event_t           *ae;
 757         fcoe_frame_t            *frm;
 758 
 759         mutex_enter(&ss->ss_watchdog_mutex);
 760         while (!list_is_empty(&ss->ss_event_list)) {
 761                 ae = (fcoei_event_t *)list_head(&ss->ss_event_list);
 762                 list_remove(&ss->ss_event_list, ae);
 763                 switch (ae->ae_type) {
 764                 case AE_EVENT_SOL_FRAME:
 765                         frm = (fcoe_frame_t *)ae->ae_obj;
 766                         frm->frm_eport->eport_release_frame(frm);
 767                         break;
 768 
 769                 case AE_EVENT_UNSOL_FRAME:
 770                         frm = (fcoe_frame_t *)ae->ae_obj;
 771                         frm->frm_eport->eport_free_netb(frm->frm_netb);
 772                         frm->frm_eport->eport_release_frame(frm);
 773                         break;
 774 
 775                 case AE_EVENT_PORT:
 776                         atomic_dec_32(&ss->ss_port_event_counter);
 777                         /* FALLTHROUGH */
 778 
 779                 case AE_EVENT_RESET:
 780                         kmem_free(ae, sizeof (fcoei_event_t));
 781                         break;
 782 
 783                 case AE_EVENT_EXCHANGE:
 784                         /* FALLTHROUGH */
 785 
 786                 default:
 787                         break;
 788                 }
 789         }
 790 
 791         mod_hash_clear(ss->ss_unsol_rxid_hash);
 792         mod_hash_clear(ss->ss_sol_oxid_hash);
 793 
 794         while (!list_is_empty(&ss->ss_comp_xch_list)) {
 795                 (void) list_remove_head(&ss->ss_comp_xch_list);
 796         }
 797         mutex_exit(&ss->ss_watchdog_mutex);
 798 }
 799 
 800 /*
 801  * fcoei_process_events
 802  *      Process the events one by one
 803  *
 804  * Input:
 805  *      ss = the soft state that will be processed
 806  *
 807  * Return:
 808  *      N/A
 809  *
 810  * Comment:
 811  *      N/A
 812  */
 813 static void
 814 fcoei_process_events(fcoei_soft_state_t *ss)
 815 {
 816         fcoei_event_t   *ae = NULL;
 817 
 818         /*
 819          * It's the only place to delete node from ss_event_list, so we needn't
 820          * hold mutex to check if the list is empty.
 821          */
 822         ASSERT(!MUTEX_HELD(&ss->ss_watchdog_mutex));
 823         while (list_is_empty(&ss->ss_event_list) == B_FALSE) {
 824                 mutex_enter(&ss->ss_watchdog_mutex);
 825                 ae = (fcoei_event_t *)list_remove_head(&ss->ss_event_list);
 826                 mutex_exit(&ss->ss_watchdog_mutex);
 827 
 828                 switch (ae->ae_type) {
 829                 case AE_EVENT_SOL_FRAME:
 830                         fcoei_handle_sol_frame_done((fcoe_frame_t *)ae->ae_obj);
 831                         break;
 832 
 833                 case AE_EVENT_UNSOL_FRAME:
 834                         fcoei_process_unsol_frame((fcoe_frame_t *)ae->ae_obj);
 835                         break;
 836 
 837                 case AE_EVENT_EXCHANGE:
 838                         fcoei_process_event_exchange(ae);
 839                         break;
 840 
 841                 case AE_EVENT_PORT:
 842                         fcoei_process_event_port(ae);
 843                         break;
 844 
 845                 case AE_EVENT_RESET:
 846                         fcoei_process_event_reset(ae);
 847                         break;
 848 
 849                 default:
 850                         FCOEI_LOG(__FUNCTION__, "unsupported events");
 851                 }
 852 
 853         }
 854 }
 855 
 856 /*
 857  * fcoei_handle_tmout_xch_list
 858  *      Complete every exchange in the timed-out xch list of the soft state
 859  *
 860  * Input:
 861  *      ss = the soft state that need be handled
 862  *
 863  * Return:
 864  *      N/A
 865  *
 866  * Comment:
 867  *      When mod_hash_walk is in progress, we can't change the hashtable.
 868  *      This is post-walk handling of exchange timing
 869  */
 870 void
 871 fcoei_handle_comp_xch_list(fcoei_soft_state_t *ss)
 872 {
 873         fcoei_exchange_t        *xch      = NULL;
 874 
 875         while ((xch = list_remove_head(&ss->ss_comp_xch_list)) != NULL) {
 876                 fcoei_complete_xch(xch, NULL, xch->xch_fpkt->pkt_state,
 877                     xch->xch_fpkt->pkt_reason);
 878         }
 879 }
 880 
 881 /*
 882  * fcoei_xch_check
 883  *      Check if the exchange timed out or link is down
 884  *
 885  * Input:
 886  *      key = rxid of the unsolicited exchange
 887  *      val = the unsolicited exchange
 888  *      arg = the soft state
 889  *
 890  * Return:
 891  *      MH_WALK_CONTINUE = continue to walk
 892  *
 893  * Comment:
 894  *      We need send ABTS for timed-out for solicited exchange
 895  *      If it's solicited FLOGI, we need set SS_FLAG_FLOGI_FAILED
 896  *      If the link is down, we think it has timed out too.
 897  */
 898 /* ARGSUSED */
 899 static uint32_t
 900 fcoei_xch_check(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
 901 {
 902         fcoei_exchange_t        *xch = (fcoei_exchange_t *)val;
 903 
 904         ASSERT(xch->xch_ss == arg);
 905         if ((xch->xch_end_tick < CURRENT_CLOCK) &&
 906             (xch->xch_ss->ss_link_state != FC_STATE_OFFLINE)) {
 907                 if (xch->xch_flags & XCH_FLAG_IN_SOL_HASH) {
 908                         ASSERT(xch->xch_oxid == CMHK(key));
 909                         /*
 910                          * It's solicited exchange
 911                          */
 912                         fcoei_abts_exchange(xch);
 913                         if (LA_ELS_FLOGI == ((ls_code_t *)(void *)
 914                             xch->xch_fpkt->pkt_cmd)->ls_code) {
 915                                 /*
 916                                  * It's solicited FLOGI
 917                                  */
 918                                 xch->xch_ss->ss_flags |= SS_FLAG_FLOGI_FAILED;
 919                         }
 920                 }
 921 
 922                 FCOEI_LOG(__FUNCTION__, "oxid-%x/rxid-%x  timed out",
 923                     xch->xch_oxid, xch->xch_rxid);
 924                 xch->xch_flags |= XCH_FLAG_TMOUT;
 925                 xch->xch_fpkt->pkt_state = FC_PKT_TIMEOUT;
 926                 xch->xch_fpkt->pkt_reason = FC_REASON_ABORTED;
 927                 list_insert_tail(&xch->xch_ss->ss_comp_xch_list, xch);
 928         } else if (xch->xch_ss->ss_link_state == FC_STATE_OFFLINE) {
 929                 FCOEI_LOG(__FUNCTION__, "oxid-%x/rxid-%x  offline complete",
 930                     xch->xch_oxid, xch->xch_rxid);
 931                 xch->xch_flags |= XCH_FLAG_TMOUT;
 932                 xch->xch_fpkt->pkt_state = FC_PKT_PORT_OFFLINE;
 933                 xch->xch_fpkt->pkt_reason = FC_REASON_OFFLINE;
 934                 list_insert_tail(&xch->xch_ss->ss_comp_xch_list, xch);
 935         }
 936 
 937         return (MH_WALK_CONTINUE);
 938 }
 939 
 940 /*
 941  * fcoei_init_ifm
 942  *      initialize fcoei_frame
 943  *
 944  * Input:
 945  *      frm = the frame that ifm need link to
 946  *      xch = the exchange that ifm need link to
 947  *
 948  * Return:
 949  *      N/A
 950  *
 951  * Comment:
 952  *      For solicited frames, it's called after FC frame header initialization
 953  *      For unsolicited frames, it's called just after the frame enters fcoei
 954  */
 955 void
 956 fcoei_init_ifm(fcoe_frame_t *frm, fcoei_exchange_t *xch)
 957 {
 958         FRM2IFM(frm)->ifm_frm = frm;
 959         FRM2IFM(frm)->ifm_xch = xch;
 960         FRM2IFM(frm)->ifm_rctl = FRM_R_CTL(frm);
 961 }
 962 
 963 /*
 964  * fcoei_trigger_fp_attach
 965  *      Trigger fp_attach for this fcoei port
 966  *
 967  * Input:
 968  *      arg = the soft state that fp will attach
 969  *
 970  * Return:
 971  *      N/A
 972  *
 973  * Comment:
 974  *      N/A
 975  */
 976 static void
 977 fcoei_trigger_fp_attach(void * arg)
 978 {
 979         fcoei_soft_state_t      *ss    = (fcoei_soft_state_t *)arg;
 980         dev_info_t              *child = NULL;
 981         int                      rval  = NDI_FAILURE;
 982 
 983         ndi_devi_alloc_sleep(ss->ss_dip, "fp", DEVI_PSEUDO_NODEID, &child);
 984         if (child == NULL) {
 985                 FCOEI_LOG(__FUNCTION__, "can't alloc dev_info");
 986                 return;
 987         }
 988 
 989         /*
 990          * fp/fctl need this property
 991          */
 992         if (ddi_prop_update_string(DDI_DEV_T_NONE, child,
 993             "bus-addr", "0,0") != DDI_PROP_SUCCESS) {
 994                 FCOEI_LOG(__FUNCTION__, "update bus-addr failed");
 995                 (void) ndi_devi_free(child);
 996                 return;
 997         }
 998 
 999         /*
1000          * If it's physical HBA, fp.conf will register the property.
1001          * fcoei is one software HBA, so we need register it manually
1002          */
1003         if (ddi_prop_update_int(DDI_DEV_T_NONE, child,
1004             "port", 0) != DDI_PROP_SUCCESS) {
1005                 FCOEI_LOG(__FUNCTION__, "update port failed");
1006                 (void) ndi_devi_free(child);
1007                 return;
1008         }
1009 
1010         /*
1011          * It will call fp_attach eventually
1012          */
1013         rval = ndi_devi_online(child, NDI_ONLINE_ATTACH);
1014         ss->ss_flags &= ~SS_FLAG_TRIGGER_FP_ATTACH;
1015         if (rval != NDI_SUCCESS) {
1016                 FCOEI_LOG(__FUNCTION__, "devi_online: %d", rval);
1017         } else {
1018                 FCOEI_LOG(__FUNCTION__, "triggered successfully");
1019         }
1020 }
1021 
1022 /*
1023  * fcoei_abts_exchange
1024  *      Send ABTS to abort solicited exchange
1025  *
1026  * Input:
1027  *      xch = the exchange that will be aborted
1028  *
1029  * Return:
1030  *      N/A
1031  *
1032  * Comment:
1033  *      ABTS frame uses the same oxid as the exchange
1034  */
1035 static void
1036 fcoei_abts_exchange(fcoei_exchange_t *xch)
1037 {
1038         fc_packet_t     *fpkt = xch->xch_fpkt;
1039         fcoe_frame_t    *frm  = NULL;
1040 
1041         /*
1042          * BLS_ABTS doesn't contain any other payload except FCFH
1043          */
1044         frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
1045             FCFH_SIZE, NULL);
1046         if (frm == NULL) {
1047                 FCOEI_LOG(__FUNCTION__, "can't alloc frame: %p", xch);
1048                 return;
1049         }
1050 
1051         FFM_R_CTL(0x81, frm);
1052         FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
1053         FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
1054         FFM_F_CTL(0x090000, frm);
1055         FFM_SEQ_ID(0x01, frm);
1056         FFM_OXID(xch->xch_oxid, frm);
1057         FFM_RXID(xch->xch_rxid, frm);
1058         fcoei_init_ifm(frm, xch);
1059         xch->xch_ss->ss_eport->eport_tx_frame(frm);
1060 }
1061 
1062 /*
1063  * fcoei_complete_xch
1064  *      Complete the exchange
1065  *
1066  * Input:
1067  *      xch = the exchange that will be completed
1068  *      frm = newly-allocated frame that has not been submitted
1069  *      pkt_state = LV fpkt state
1070  *      pkt_reason = LV fpkt reason
1071  *
1072  * Return:
1073  *      N/A
1074  *
1075  * Comment:
1076  *      N/A
1077  */
1078 void
1079 fcoei_complete_xch(fcoei_exchange_t *xch, fcoe_frame_t *frm,
1080     uint8_t pkt_state, uint8_t pkt_reason)
1081 {
1082         mod_hash_val_t val;
1083 
1084         if (pkt_state != FC_PKT_SUCCESS) {
1085                 FCOEI_LOG(__FUNCTION__, "FHDR: %x/%x/%x, %x/%x/%x",
1086                     xch->xch_fpkt->pkt_cmd_fhdr.r_ctl,
1087                     xch->xch_fpkt->pkt_cmd_fhdr.f_ctl,
1088                     xch->xch_fpkt->pkt_cmd_fhdr.type,
1089                     xch->xch_fpkt->pkt_resp_fhdr.r_ctl,
1090                     xch->xch_fpkt->pkt_resp_fhdr.f_ctl,
1091                     xch->xch_fpkt->pkt_resp_fhdr.type);
1092                 FCOEI_LOG(__FUNCTION__, "%p/%p/%x/%x",
1093                     xch, frm, pkt_state, pkt_reason);
1094         }
1095 
1096         if (frm != NULL) {
1097                 /*
1098                  * It's newly-allocated frame , which we haven't sent out
1099                  */
1100                 xch->xch_ss->ss_eport->eport_free_netb(frm->frm_netb);
1101                 xch->xch_ss->ss_eport->eport_release_frame(frm);
1102                 FCOEI_LOG(__FUNCTION__, "xch: %p, not submitted", xch);
1103         }
1104 
1105         /*
1106          * If xch is in hash table, we need remove it
1107          */
1108         if (xch->xch_flags & XCH_FLAG_IN_SOL_HASH) {
1109                 (void) mod_hash_remove(xch->xch_ss->ss_sol_oxid_hash,
1110                     FMHK(xch->xch_oxid), &val);
1111                 ASSERT((fcoei_exchange_t *)val == xch);
1112                 xch->xch_flags &= ~XCH_FLAG_IN_SOL_HASH;
1113         } else if (xch->xch_flags & XCH_FLAG_IN_UNSOL_HASH) {
1114                 (void) mod_hash_remove(xch->xch_ss->ss_unsol_rxid_hash,
1115                     FMHK(xch->xch_rxid), &val);
1116                 ASSERT((fcoei_exchange_t *)val == xch);
1117                 xch->xch_flags &= ~XCH_FLAG_IN_UNSOL_HASH;
1118         } else {
1119                 FCOEI_LOG(__FUNCTION__, "xch not in any hash: %p", xch);
1120         }
1121 
1122         xch->xch_fpkt->pkt_state = pkt_state;
1123         xch->xch_fpkt->pkt_reason = pkt_reason;
1124         if (xch->xch_fpkt->pkt_tran_flags & FC_TRAN_NO_INTR) {
1125                 FCOEI_LOG(__FUNCTION__, "polled xch is done: %p", xch);
1126                 sema_v(&xch->xch_sema);
1127         } else {
1128                 xch->xch_fpkt->pkt_comp(xch->xch_fpkt);
1129         }
1130 }