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