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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #ifndef _SYS_IB_ADAPTERS_HERMON_H 28 #define _SYS_IB_ADAPTERS_HERMON_H 29 30 /* 31 * hermon.h 32 * Contains the #defines and typedefs necessary for the Hermon softstate 33 * structure and for proper attach() and detach() processing. Also 34 * includes all the other Hermon header files (and so is the only header 35 * file that is directly included by the Hermon source files). 36 * Lastly, this file includes everything necessary for implementing the 37 * devmap interface and for maintaining the "mapped resource database". 38 */ 39 40 #include <sys/types.h> 41 #include <sys/conf.h> 42 #include <sys/ddi.h> 43 #include <sys/sunddi.h> 44 #include <sys/tnf_probe.h> 45 #include <sys/taskq.h> 46 #include <sys/atomic.h> 47 #ifdef FMA_TEST 48 #include <sys/modhash.h> 49 #endif 50 51 #include <sys/ib/ibtl/ibci.h> 52 #include <sys/ib/ibtl/impl/ibtl_util.h> 53 #include <sys/ib/adapters/mlnx_umap.h> 54 55 /* 56 * First include all the Hermon typedefs, then include all the other Hermon 57 * specific headers (many of which depend on the typedefs having already 58 * been defined). 59 */ 60 #include <sys/ib/adapters/hermon/hermon_typedef.h> 61 #include <sys/ib/adapters/hermon/hermon_hw.h> 62 63 #include <sys/ib/adapters/hermon/hermon_agents.h> 64 #include <sys/ib/adapters/hermon/hermon_cfg.h> 65 #include <sys/ib/adapters/hermon/hermon_cmd.h> 66 #include <sys/ib/adapters/hermon/hermon_cq.h> 67 #include <sys/ib/adapters/hermon/hermon_event.h> 68 #include <sys/ib/adapters/hermon/hermon_ioctl.h> 69 #include <sys/ib/adapters/hermon/hermon_misc.h> 70 #include <sys/ib/adapters/hermon/hermon_mr.h> 71 #include <sys/ib/adapters/hermon/hermon_wr.h> 72 #include <sys/ib/adapters/hermon/hermon_qp.h> 73 #include <sys/ib/adapters/hermon/hermon_srq.h> 74 #include <sys/ib/adapters/hermon/hermon_rsrc.h> 75 #include <sys/ib/adapters/hermon/hermon_fm.h> 76 77 #ifdef __cplusplus 78 extern "C" { 79 #endif 80 81 /* 82 * Number of initial states to setup. Used in call to ddi_soft_state_init() 83 */ 84 #define HERMON_INITIAL_STATES 3 85 86 /* 87 * Macro and defines used to calculate device instance number from minor 88 * number (and vice versa). 89 */ 90 #define HERMON_MINORNUM_SHIFT 3 91 #define HERMON_DEV_INSTANCE(dev) (getminor((dev)) & \ 92 ((1 << HERMON_MINORNUM_SHIFT) - 1)) 93 94 /* 95 * Locations for the various Hermon hardware CMD,UAR & MSIx PCIe BARs 96 */ 97 #define HERMON_CMD_BAR 1 /* device config space */ 98 #define HERMON_UAR_BAR 2 /* UAR Region */ 99 #define HERMON_MSIX_BAR 3 /* MSI-X Table */ 100 101 #define HERMON_ONCLOSE_FLASH_INPROGRESS (1 << 0) 102 103 #define HERMON_MSIX_MAX 8 /* max # of interrupt vectors */ 104 105 /* 106 * VPD header size - or more rightfully, the area of interest for fwflash 107 * There's more, but we don't need it for our use so we don't read it 108 */ 109 #define HERMON_VPD_HDR_DWSIZE 0x10 /* 16 Dwords */ 110 #define HERMON_VPD_HDR_BSIZE 0x40 /* 64 Bytes */ 111 112 /* 113 * Offsets to be used w/ reset to save/restore PCI capability stuff 114 */ 115 #define HERMON_PCI_CAP_DEV_OFFS 0x08 116 #define HERMON_PCI_CAP_LNK_OFFS 0x10 117 118 119 /* 120 * Some defines for the software reset. These define the value that should 121 * be written to begin the reset (HERMON_SW_RESET_START), the delay before 122 * beginning to poll for completion (HERMON_SW_RESET_DELAY), the in-between 123 * polling delay (HERMON_SW_RESET_POLL_DELAY), and the value that indicates 124 * that the reset has not completed (HERMON_SW_RESET_NOTDONE). 125 */ 126 #define HERMON_SW_RESET_START 0x00000001 127 #define HERMON_SW_RESET_DELAY 1000000 /* 1000 ms, per 0.36 PRM */ 128 #define HERMON_SW_RESET_POLL_DELAY 100 /* 100 us */ 129 #define HERMON_SW_RESET_NOTDONE 0xFFFFFFFF 130 131 /* 132 * These defines are used in the Hermon software reset operation. They define 133 * the total number PCI registers to read/restore during the reset. And they 134 * also specify two config registers which should not be read or restored. 135 */ 136 #define HERMON_SW_RESET_NUMREGS 0x40 137 #define HERMON_SW_RESET_REG22_RSVD 0x16 /* 22 dec */ 138 #define HERMON_SW_RESET_REG23_RSVD 0x17 /* 23 dec */ 139 140 /* 141 * Macro used to output HCA warning messages. Note: HCA warning messages 142 * are only generated when an unexpected condition has been detected. This 143 * can be the result of a software bug or some other problem, but it is more 144 * often an indication that the HCA firmware (and/or hardware) has done 145 * something unexpected. This warning message means that the driver state 146 * in unpredictable and that shutdown/restart is suggested. 147 */ 148 #define HERMON_WARNING(state, string) \ 149 cmn_err(CE_WARN, "hermon%d: %s\n", (state)->hs_instance, string) 150 151 152 #define HERMON_NOTE(state, string) \ 153 cmn_err(CE_CONT, "hermon%d: %s\n", (state)->hs_instance, string) 154 155 /* 156 * Macro used to set attach failure messages. Also, the attach message buf 157 * size is set here. 158 */ 159 #define HERMON_ATTACH_MSGSIZE 80 160 #define HERMON_ATTACH_MSG(attach_buf, attach_msg) \ 161 (void) snprintf((attach_buf), HERMON_ATTACH_MSGSIZE, (attach_msg)); 162 #define HERMON_ATTACH_MSG_INIT(attach_buf) \ 163 (attach_buf)[0] = '\0'; 164 165 /* 166 * Macros used for controlling whether or not event callbacks will be forwarded 167 * to the IBTF. This is necessary because there are certain race conditions 168 * that can occur (e.g. calling IBTF with an asynch event before the IBTF 169 * registration has successfully completed or handling an event after we've 170 * detached from the IBTF.) 171 * 172 * HERMON_ENABLE_IBTF_CALLB() initializes the "hs_ibtfpriv" field in the Hermon 173 * softstate. When "hs_ibtfpriv" is non-NULL, it is OK to forward asynch 174 * and CQ events to the IBTF. 175 * 176 * HERMON_DO_IBTF_ASYNC_CALLB() and HERMON_DO_IBTF_CQ_CALLB() both set and clear 177 * the "hs_in_evcallb" flag, as necessary, to indicate that an IBTF 178 * callback is currently in progress. This is necessary so that we can 179 * block on this condition in hermon_detach(). 180 * 181 * HERMON_QUIESCE_IBTF_CALLB() is used in hermon_detach() to set the 182 * "hs_ibtfpriv" to NULL (thereby disabling any further IBTF callbacks) 183 * and to poll on the "hs_in_evcallb" flag. When this flag is zero, all 184 * IBTF callbacks have quiesced and it is safe to continue with detach 185 * (i.e. continue detaching from IBTF). 186 */ 187 #define HERMON_ENABLE_IBTF_CALLB(state, tmp_ibtfpriv) \ 188 (state)->hs_ibtfpriv = (tmp_ibtfpriv); 189 190 #define HERMON_DO_IBTF_ASYNC_CALLB(state, type, event) \ 191 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS((state)->hs_in_evcallb)) \ 192 (state)->hs_in_evcallb = 1; \ 193 ibc_async_handler((state)->hs_ibtfpriv, (type), (event)); \ 194 (state)->hs_in_evcallb = 0; 195 196 #define HERMON_DO_IBTF_CQ_CALLB(state, cq) \ 197 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS((state)->hs_in_evcallb)) \ 198 (state)->hs_in_evcallb = 1; \ 199 ibc_cq_handler((state)->hs_ibtfpriv, (cq)->cq_hdlrarg); \ 200 (state)->hs_in_evcallb = 0; 201 202 #define HERMON_QUIESCE_IBTF_CALLB(state) \ 203 { \ 204 uint_t count = 0; \ 205 \ 206 state->hs_ibtfpriv = NULL; \ 207 while (((state)->hs_in_evcallb != 0) && \ 208 (count++ < HERMON_QUIESCE_IBTF_CALLB_POLL_MAX)) { \ 209 drv_usecwait(HERMON_QUIESCE_IBTF_CALLB_POLL_DELAY); \ 210 } \ 211 } 212 213 /* 214 * Defines used by the HERMON_QUIESCE_IBTF_CALLB() macro to determine the 215 * duration and number of times (at maximum) to poll while waiting for IBTF 216 * callbacks to quiesce. 217 */ 218 #define HERMON_QUIESCE_IBTF_CALLB_POLL_DELAY 1 219 #define HERMON_QUIESCE_IBTF_CALLB_POLL_MAX 1000000 220 221 /* 222 * Macros to retrieve PCI id's of the device 223 */ 224 #define HERMON_DDI_PROP_GET(dip, property) \ 225 (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, \ 226 property, -1)) 227 228 #define HERMON_GET_VENDOR_ID(dip) HERMON_DDI_PROP_GET(dip, "vendor-id") 229 #define HERMON_GET_DEVICE_ID(dip) HERMON_DDI_PROP_GET(dip, "device-id") 230 #define HERMON_GET_REVISION_ID(dip) HERMON_DDI_PROP_GET(dip, "revision-id") 231 232 233 234 /* 235 * Define used to determine the device mode to which Hermon driver has been 236 * attached. HERMON_IS_MAINTENANCE_MODE() returns true when the device has 237 * come up in the "maintenance mode". In this mode, no InfiniBand interfaces 238 * are enabled, but the device's firmware can be updated/flashed (and 239 * test/debug interfaces should be useable). 240 * HERMON_IS_HCA_MODE() returns true when the device has come up in the 241 * normal HCA mode. In this mode, all necessary InfiniBand interfaces are 242 * enabled (and, if necessary, HERMON firmware can be updated/flashed). 243 */ 244 #define HERMON_IS_MAINTENANCE_MODE(dip) \ 245 ((ddi_prop_get_int(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ 246 "device-id", -1) == PCI_DEVID_HERMON_MAINT) && \ 247 (ddi_prop_get_int(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ 248 "vendor-id", -1) == PCI_VENID_MLX)) 249 250 #define HERMON_IS_HCA_MODE(dip) \ 251 (((ddi_prop_get_int(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ 252 "device-id", -1) == PCI_DEVID_HERMON_SDR) || \ 253 (ddi_prop_get_int(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ 254 "device-id", -1) == PCI_DEVID_HERMON_DDR) || \ 255 (ddi_prop_get_int(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ 256 "device-id", -1) == PCI_DEVID_HERMON_DDRG2) || \ 257 (ddi_prop_get_int(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ 258 "device-id", -1) == PCI_DEVID_HERMON_QDRG2)) && \ 259 (ddi_prop_get_int(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ 260 "vendor-id", -1) == PCI_VENID_MLX)) 261 262 #define HERMON_MAINTENANCE_MODE 1 263 #define HERMON_HCA_MODE 2 264 265 /* 266 * Used to determine if the device is operational, or not in maintenance mode. 267 * This means either the driver has attached successfully against an hermon 268 * device in hermon compatibility mode, or against a hermon device in full HCA 269 * mode. 270 */ 271 #define HERMON_IS_OPERATIONAL(mode) \ 272 (mode == HERMON_HCA_MODE) 273 274 /* 275 * The following define is used (in hermon_umap_db_set_onclose_cb()) to 276 * indicate that a cleanup callback is needed to undo initialization done 277 * by the firmware flash burn code. 278 */ 279 #define HERMON_ONCLOSE_FLASH_INPROGRESS (1 << 0) 280 281 /* 282 * The following enumerated type and structures are used during driver 283 * initialization. Note: The HERMON_DRV_CLEANUP_ALL type is used as a marker 284 * for end of the cleanup steps. No cleanup steps should be added after 285 * HERMON_DRV_CLEANUP_ALL. Any addition steps should be added before it. 286 */ 287 typedef enum { 288 HERMON_DRV_CLEANUP_LEVEL0, 289 HERMON_DRV_CLEANUP_LEVEL1, 290 HERMON_DRV_CLEANUP_LEVEL2, 291 HERMON_DRV_CLEANUP_LEVEL3, 292 HERMON_DRV_CLEANUP_LEVEL4, 293 HERMON_DRV_CLEANUP_LEVEL5, 294 HERMON_DRV_CLEANUP_LEVEL6, 295 HERMON_DRV_CLEANUP_LEVEL7, 296 HERMON_DRV_CLEANUP_LEVEL8, 297 HERMON_DRV_CLEANUP_LEVEL9, 298 HERMON_DRV_CLEANUP_LEVEL10, 299 HERMON_DRV_CLEANUP_LEVEL11, 300 HERMON_DRV_CLEANUP_LEVEL12, 301 HERMON_DRV_CLEANUP_LEVEL13, 302 HERMON_DRV_CLEANUP_LEVEL14, 303 HERMON_DRV_CLEANUP_LEVEL15, 304 HERMON_DRV_CLEANUP_LEVEL16, 305 HERMON_DRV_CLEANUP_LEVEL17, 306 HERMON_DRV_CLEANUP_LEVEL18, 307 HERMON_DRV_CLEANUP_LEVEL19, 308 /* No more driver cleanup steps below this point! */ 309 HERMON_DRV_CLEANUP_ALL 310 } hermon_drv_cleanup_level_t; 311 312 /* 313 * The hermon_dma_info_t structure is used to store information related to 314 * the various ICM resources' DMA allocations. The related ICM table and 315 * virtual address are stored here. The DMA and Access handles are stored 316 * here. Also, the allocation length and virtual (host) address. 317 */ 318 struct hermon_dma_info_s { 319 ddi_dma_handle_t dma_hdl; 320 ddi_acc_handle_t acc_hdl; 321 uint64_t icmaddr; /* ICM virtual address */ 322 uint64_t vaddr; /* host virtual address */ 323 uint_t length; /* length requested */ 324 uint_t icm_refcnt; /* refcnt */ 325 }; 326 _NOTE(SCHEME_PROTECTS_DATA("safe sharing", 327 hermon_dma_info_s::icm_refcnt)) 328 329 330 /* 331 * The hermon_cmd_reg_t structure is used to hold the address of the each of 332 * the most frequently accessed hardware registers. Specifically, it holds 333 * the HCA Command Registers (HCR, used to pass command and mailbox 334 * information back and forth to Hermon firmware) and the lock used to guarantee 335 * mutually exclusive access to the registers. 336 * Related to this, is the "clr_int" register which is used to clear the 337 * interrupt once all EQs have been serviced. 338 * Finally, there is the software reset register which is used to reinitialize 339 * the Hermon device and to put it into a known state at driver startup time. 340 * Below we also have the offsets (into the CMD register space) for each of 341 * the various registers. 342 */ 343 typedef struct hermon_cmd_reg_s { 344 hermon_hw_hcr_t *hcr; 345 kmutex_t hcr_lock; 346 uint64_t *clr_intr; 347 uint64_t *eq_arm; 348 uint64_t *eq_set_ci; 349 uint32_t *sw_reset; 350 uint32_t *sw_semaphore; 351 uint32_t *fw_err_buf; 352 } hermon_cmd_reg_t; 353 _NOTE(MUTEX_PROTECTS_DATA(hermon_cmd_reg_t::hcr_lock, 354 hermon_cmd_reg_t::hcr)) 355 356 /* SOME TEMPORARY PRINTING THINGS */ 357 #define HERMON_PRINT_CI (0x01 << 0) 358 #define HERMON_PRINT_MEM (0x01 << 1) 359 #define HERMON_PRINT_CQ (0x01 << 2) 360 361 362 #define HD_PRINT(state, mask) \ 363 if (state->hs_debug_lev & mask) 364 365 /* END PRINTING THINGS */ 366 367 /* 368 * The hermon_state_t structure is the HCA software state structure. It 369 * contains all the pointers and placeholder for everything that the HCA 370 * driver needs to properly operate. One of these structures exists for 371 * every instance of the HCA driver. 372 */ 373 struct hermon_state_s { 374 dev_info_t *hs_dip; 375 int hs_instance; 376 int hs_debug; /* for debug, a way of tracing */ 377 uint32_t hs_debug_lev; /* for controlling prints, a bit mask */ 378 /* see hermon.c for setting it */ 379 /* PCI device, vendor, and revision IDs */ 380 uint16_t hs_vendor_id; 381 uint16_t hs_device_id; 382 uint8_t hs_revision_id; 383 384 struct hermon_hw_qpc_s hs_debug_qpc; 385 struct hermon_hw_cqc_s hs_debug_cqc; 386 struct hermon_hw_eqc_s hs_debug_eqc; 387 388 hermon_hw_sm_perfcntr_t hs_debug_perf; 389 390 391 /* 392 * DMA information for the InfiniHost Context Memory (ICM), 393 * ICM Auxiliary allocation and the firmware. Also, record 394 * of ICM and ICMA sizes, in bytes. 395 */ 396 /* JBDB -- store here hs_icm_table, with hs_icm_dma in */ 397 398 uint64_t hs_icm_sz; 399 hermon_icm_table_t *hs_icm; 400 uint64_t hs_icma_sz; 401 hermon_dma_info_t hs_icma_dma; 402 hermon_dma_info_t hs_fw_dma; 403 404 /* Hermon interrupt/MSI information */ 405 int hs_intr_types_avail; 406 uint_t hs_intr_type_chosen; 407 int hs_intrmsi_count; 408 int hs_intrmsi_avail; 409 int hs_intrmsi_allocd; 410 ddi_intr_handle_t hs_intrmsi_hdl[HERMON_MSIX_MAX]; 411 uint_t hs_intrmsi_pri; 412 int hs_intrmsi_cap; 413 414 /* assign EQs to CQs in a round robin fashion */ 415 uint_t hs_eq_dist; /* increment when used */ 416 417 /* hermon HCA name and HCA part number */ 418 char hs_hca_name[64]; 419 char hs_hca_pn[64]; 420 int hs_hca_pn_len; 421 422 /* Hermon device operational mode */ 423 int hs_operational_mode; 424 425 /* Attach buffer saved per state to store detailed attach errors */ 426 char hs_attach_buf[HERMON_ATTACH_MSGSIZE]; 427 428 /* Hermon NodeGUID, SystemImageGUID, and NodeDescription */ 429 uint64_t hs_nodeguid; 430 uint64_t hs_sysimgguid; 431 char hs_nodedesc[64]; 432 433 /* Info passed to IBTF during registration */ 434 ibc_hca_info_t hs_ibtfinfo; 435 ibc_clnt_hdl_t hs_ibtfpriv; 436 437 /* 438 * Hermon register mapping. Holds the device access attributes, 439 * kernel mapped addresses, and DDI access handles for both 440 * Hermon's CMD and UAR BARs. 441 */ 442 ddi_device_acc_attr_t hs_reg_accattr; 443 caddr_t hs_reg_cmd_baseaddr; /* Hermon CMD BAR */ 444 ddi_acc_handle_t hs_reg_cmdhdl; 445 caddr_t hs_reg_uar_baseaddr; /* Hermon UAR BAR */ 446 ddi_acc_handle_t hs_reg_uarhdl; 447 caddr_t hs_reg_msi_baseaddr; /* Hermon MSIx BAR */ 448 ddi_acc_handle_t hs_reg_msihdl; 449 450 /* 451 * Some additional things for UAR Pages 452 */ 453 uint64_t hs_kernel_uar_index; /* kernel UAR index */ 454 uint64_t hs_bf_offset; /* offset from UAR */ 455 /* Bar to Blueflame */ 456 caddr_t hs_reg_bf_baseaddr; /* blueflame base */ 457 ddi_acc_handle_t hs_reg_bfhdl; /* blueflame handle */ 458 459 460 /* 461 * Hermon PCI config space registers. This array is used to 462 * save and restore the PCI config registers before and after a 463 * software reset. 464 */ 465 uint32_t hs_cfg_data[HERMON_SW_RESET_NUMREGS]; 466 /* for reset per Linux driver */ 467 uint32_t hs_pci_cap_offset; 468 uint32_t hs_pci_cap_devctl; 469 uint32_t hs_pci_cap_lnkctl; 470 471 /* 472 * Hermon UAR page resources. Holds the resource pointers for 473 * UAR page #0 (reserved) and for UAR page #1 (used for kernel 474 * driver doorbells). In addition, we save a pointer to the 475 * UAR page #1 doorbells which will be used throughout the driver 476 * whenever it is necessary to ring one of them. And, in case we 477 * are unable to do 64-bit writes to the page (because of system 478 * architecture), we include a lock (to ensure atomic 64-bit access). 479 */ 480 hermon_rsrc_t *hs_uarpg0_rsrc_rsrvd; 481 hermon_rsrc_t *hs_uarkpg_rsrc; 482 hermon_hw_uar_t *hs_uar; 483 kmutex_t hs_uar_lock; 484 485 /* 486 * Used during a call to open() if we are in maintenance mode, this 487 * field serves as a semi-unique rolling count index value, used only 488 * in the setup of umap_db entries. This is primarily needed to 489 * firmware device access ioctl operations can still be guaranteed to 490 * close in the event of an unplanned process exit, even in maintenance 491 * mode. 492 */ 493 uint_t hs_open_ar_indx; 494 495 /* 496 * Hermon command registers. This structure contains the addresses 497 * for each of the most frequently accessed CMD registers. Since 498 * almost all accesses to the Hermon hardware are through the Hermon 499 * command interface (i.e. the HCR), we save away the pointer to 500 * the HCR, as well as pointers to the ECR and INT registers (as 501 * well as their corresponding "clear" registers) for interrupt 502 * processing. And we also save away a pointer to the software 503 * reset register (see above). 504 */ 505 hermon_cmd_reg_t hs_cmd_regs; 506 uint32_t hs_cmd_toggle; 507 508 /* 509 * Hermon resource pointers. The following are pointers to the 510 * kmem cache (from which the Hermon resource handles are allocated), 511 * and the array of "resource pools" (which store all the pertinent 512 * information necessary to manage each of the various types of 513 * resources that are used by the driver. See hermon_rsrc.h for 514 * more detail. 515 */ 516 kmem_cache_t *hs_rsrc_cache; 517 hermon_rsrc_pool_info_t *hs_rsrc_hdl; 518 519 /* 520 * Hermon mailbox lists. These hold the information necessary to 521 * manage the pools of pre-allocated Hermon mailboxes (both "In" and 522 * "Out" type). See hermon_cmd.h for more detail. 523 */ 524 hermon_mboxlist_t hs_in_mblist; 525 hermon_mboxlist_t hs_out_mblist; 526 527 /* 528 * Hermon interrupt mailbox lists. We allocate both an "In" mailbox 529 * and an "Out" type mailbox for the interrupt context. This is in 530 * order to guarantee that a mailbox entry will always be available in 531 * the interrupt context, and we can NOSLEEP without having to worry 532 * about possible failure allocating the mbox. We create this as an 533 * mboxlist so that we have the potential for having multiple mboxes 534 * available based on the number of interrupts we can receive at once. 535 */ 536 hermon_mboxlist_t hs_in_intr_mblist; 537 hermon_mboxlist_t hs_out_intr_mblist; 538 539 /* 540 * Hermon outstanding command list. Used to hold all the information 541 * necessary to manage the Hermon "outstanding command list". See 542 * hermon_cmd.h for more detail. 543 */ 544 hermon_cmdlist_t hs_cmd_list; 545 546 /* 547 * This structure contains the Hermon driver's "configuration profile". 548 * This is the collected set of configuration information, such as 549 * number of QPs, CQs, mailboxes and other resources, sizes of 550 * individual resources, other system level configuration information, 551 * etc. See hermon_cfg.h for more detail. 552 */ 553 hermon_cfg_profile_t *hs_cfg_profile; 554 555 /* 556 * This flag contains the profile setting, selecting which profile the 557 * driver would use. This is needed in the case where we have to 558 * fallback to a smaller profile based on some DDR conditions. If we 559 * don't fallback, then it is set to the size of DDR in the system. 560 */ 561 uint32_t hs_cfg_profile_setting; 562 563 /* 564 * The following are a collection of resource handles used by the 565 * Hermon driver (internally). First is the protection domain (PD) 566 * handle that is used when mapping all kernel memory (work queues, 567 * completion queues, etc). Next is an array of EQ handles. This 568 * array is indexed by EQ number and allows the Hermon driver to quickly 569 * convert an EQ number into the software structure associated with the 570 * given EQ. Likewise, we have three arrays for CQ, QP and SRQ 571 * handles. These arrays are also indexed by CQ, QP or SRQ number and 572 * allow the driver to quickly find the corresponding CQ, QP or SRQ 573 * software structure. Note: while the EQ table is of fixed size 574 * (because there are a maximum of 64 EQs), each of the CQ, QP and SRQ 575 * handle lists must be allocated at driver startup. 576 */ 577 hermon_pdhdl_t hs_pdhdl_internal; 578 hermon_eqhdl_t hs_eqhdl[HERMON_NUM_EQ]; 579 hermon_cqhdl_t *hs_cqhdl; 580 hermon_qphdl_t *hs_qphdl; 581 hermon_srqhdl_t *hs_srqhdl; 582 kmutex_t hs_dbr_lock; /* lock for dbr mgmt */ 583 584 /* linked list of kernel dbr resources */ 585 hermon_dbr_info_t *hs_kern_dbr; 586 587 /* linked list of non-kernel dbr resources */ 588 hermon_user_dbr_t *hs_user_dbr; 589 590 /* 591 * The AVL tree is used to store information regarding QP number 592 * allocations. The lock protects access to the AVL tree. 593 */ 594 avl_tree_t hs_qpn_avl; 595 kmutex_t hs_qpn_avl_lock; 596 597 /* 598 * This field is used to indicate whether or not the Hermon driver is 599 * currently in an IBTF event callback elsewhere in the system. Note: 600 * It is "volatile" because we intend to poll on this value - in 601 * hermon_detach() - until we are assured that no further IBTF callbacks 602 * are currently being processed. 603 */ 604 volatile uint32_t hs_in_evcallb; 605 606 /* 607 * The following structures are used to store the results of several 608 * device query commands passed to the Hermon hardware at startup. 609 * Specifically, we have hung onto the results of QUERY_DDR (which 610 * gives information about how much DDR memory is present and where 611 * it is located), QUERY_FW (which gives information about firmware 612 * version numbers and the location and extent of firmware's footprint 613 * in DDR, QUERY_DEVLIM (which gives the device limitations/resource 614 * maximums) and QUERY_PORT (where some of the specs from DEVLIM moved), 615 * QUERY_ADAPTER (which gives additional miscellaneous 616 * information), and INIT/QUERY_HCA (which serves the purpose of 617 * recording what configuration information was passed to the firmware 618 * when the HCA was initialized). 619 */ 620 struct hermon_hw_queryfw_s hs_fw; 621 struct hermon_hw_querydevlim_s hs_devlim; 622 struct hermon_hw_query_port_s hs_queryport; 623 struct hermon_hw_set_port_s *hs_initport; 624 struct hermon_hw_queryadapter_s hs_adapter; 625 struct hermon_hw_initqueryhca_s hs_hcaparams; 626 627 /* 628 * The following are used for managing special QP resources. 629 * Specifically, we have a lock, a set of flags (in "hs_spec_qpflags") 630 * used to track the special QP resources, and two Hermon resource 631 * handle pointers. Each resource handle actually corresponds to two 632 * consecutive QP contexts (one per port) for each special QP type. 633 */ 634 kmutex_t hs_spec_qplock; 635 uint_t hs_spec_qpflags; 636 hermon_rsrc_t *hs_spec_qp0; 637 hermon_rsrc_t *hs_spec_qp1; 638 /* 639 * For Hermon, you have to alloc 8 qp's total, but the last 4 are 640 * unused/reserved. The following represents the handle for those 641 * last 4 qp's 642 */ 643 hermon_rsrc_t *hs_spec_qp_unused; 644 645 /* 646 * Related in some ways to the special QP handling above are these 647 * resources which are used specifically for implementing the Hermon 648 * agents (SMA, PMA, and BMA). Although, each of these agents does 649 * little more that intercept the appropriate incoming MAD and forward 650 * it along to the firmware (see hermon_agents.c for more details), we 651 * do still use a task queue to queue them up. We can also configure 652 * the driver to force firmware handling for certain classes of MAD, 653 * and, therefore, we require the agent list and number of agents 654 * in order to know what needs to be torn down at detach() time. 655 */ 656 hermon_agent_list_t *hs_agents; 657 ddi_taskq_t *hs_taskq_agents; 658 uint_t hs_num_agents; 659 660 /* 661 * Multicast group lists. These are used to track the "shadow" MCG 662 * lists that speed up the processing of attach and detach multicast 663 * group operations. See hermon_misc.h for more details. Note: we 664 * need the pointer to the "temporary" MCG entry here primarily 665 * because the size of a given MCG entry is configurable. Therefore, 666 * it is impossible to put this variable on the stack. And rather 667 * than allocate and deallocate the entry multiple times, we choose 668 * instead to preallocate it once and reuse it over and over again. 669 */ 670 kmutex_t hs_mcglock; 671 hermon_mcghdl_t hs_mcghdl; 672 hermon_hw_mcg_t *hs_mcgtmp; 673 674 /* 675 * Cache of the pkey table, sgid (guid-only) tables, and 676 * sgid (subnet) prefix. These arrays are set 677 * during port_query, and mainly used for generating MLX GSI wqes. 678 */ 679 ib_pkey_t *hs_pkey[HERMON_MAX_PORTS]; 680 ib_sn_prefix_t hs_sn_prefix[HERMON_MAX_PORTS]; 681 ib_guid_t *hs_guid[HERMON_MAX_PORTS]; 682 683 /* 684 * Used for tracking Hermon kstat information 685 */ 686 hermon_ks_info_t *hs_ks_info; 687 688 /* 689 * Used for Hermon info ioctl used by VTS 690 */ 691 kmutex_t hs_info_lock; 692 693 /* 694 * Used for Hermon FW flash burning. They are used exclusively 695 * within the ioctl calls for use when accessing the hermon 696 * flash device. 697 */ 698 kmutex_t hs_fw_flashlock; 699 int hs_fw_flashstarted; 700 dev_t hs_fw_flashdev; 701 uint32_t hs_fw_log_sector_sz; 702 uint32_t hs_fw_device_sz; 703 uint32_t hs_fw_flashbank; 704 uint32_t *hs_fw_sector; 705 uint32_t hs_fw_gpio[4]; 706 int hs_fw_cmdset; 707 708 /* 709 * Used for Hermon FM. They are basically used to manage 710 * the toggle switch to enable/disable Hermon FM. 711 * Please see the comment in hermon_fm.c. 712 */ 713 int hs_fm_capabilities; /* FM capabilities */ 714 int hs_fm_disable; /* Hermon FM disable flag */ 715 int hs_fm_state; /* Hermon FM state */ 716 boolean_t hs_fm_async_fatal; /* async internal error */ 717 uint32_t hs_fm_async_errcnt; /* async error count */ 718 boolean_t hs_fm_poll_suspend; /* poll thread suspend */ 719 kmutex_t hs_fm_lock; /* mutex for state */ 720 hermon_hca_fm_t *hs_fm_hca_fm; /* HCA FM pointer */ 721 ddi_acc_handle_t hs_fm_cmdhdl; /* fm-protected CMD hdl */ 722 ddi_acc_handle_t hs_fm_uarhdl; /* fm-protected UAR hdl */ 723 ddi_device_acc_attr_t hs_fm_accattr; /* fm-protected acc attr */ 724 ddi_periodic_t hs_fm_poll_thread; /* fma poll thread */ 725 int32_t hs_fm_degraded_reason; /* degradation cause */ 726 #ifdef FMA_TEST 727 mod_hash_t *hs_fm_test_hash; /* testset */ 728 mod_hash_t *hs_fm_id_hash; /* testid */ 729 #endif 730 /* 731 * Hermon fastreboot support. To sw-reset Hermon HCA, the driver 732 * needs to save/restore MSI-X tables and PBA. Those members are 733 * used for the purpose. 734 */ 735 /* Access handle for PCI config space */ 736 ddi_acc_handle_t hs_reg_pcihdl; /* PCI cfg handle */ 737 ddi_acc_handle_t hs_fm_pcihdl; /* fm handle */ 738 ushort_t hs_caps_ptr; /* MSI-X caps */ 739 ushort_t hs_msix_ctrl; /* MSI-X ctrl */ 740 741 /* members to handle MSI-X tables */ 742 ddi_acc_handle_t hs_reg_msix_tblhdl; /* MSI-X table handle */ 743 ddi_acc_handle_t hs_fm_msix_tblhdl; /* fm handle */ 744 char *hs_msix_tbl_addr; /* MSI-X table addr */ 745 char *hs_msix_tbl_entries; /* MSI-X table entry */ 746 size_t hs_msix_tbl_size; /* MSI-X table size */ 747 uint32_t hs_msix_tbl_offset; /* MSI-X table offset */ 748 uint32_t hs_msix_tbl_rnumber; /* MSI-X table reg# */ 749 750 /* members to handle MSI-X PBA */ 751 ddi_acc_handle_t hs_reg_msix_pbahdl; /* MSI-X PBA handle */ 752 ddi_acc_handle_t hs_fm_msix_pbahdl; /* fm handle */ 753 char *hs_msix_pba_addr; /* MSI-X PBA addr */ 754 char *hs_msix_pba_entries; /* MSI-X PBA entry */ 755 size_t hs_msix_pba_size; /* MSI-X PBA size */ 756 uint32_t hs_msix_pba_offset; /* MSI-X PBA offset */ 757 uint32_t hs_msix_pba_rnumber; /* MSI-X PBA reg# */ 758 759 boolean_t hs_quiescing; /* in fastreboot */ 760 }; 761 _NOTE(MUTEX_PROTECTS_DATA(hermon_state_s::hs_fw_flashlock, 762 hermon_state_s::hs_fw_flashstarted 763 hermon_state_s::hs_fw_flashdev 764 hermon_state_s::hs_fw_log_sector_sz 765 hermon_state_s::hs_fw_device_sz)) 766 _NOTE(MUTEX_PROTECTS_DATA(hermon_state_s::hs_spec_qplock, 767 hermon_state_s::hs_spec_qpflags 768 hermon_state_s::hs_spec_qp0 769 hermon_state_s::hs_spec_qp1)) 770 _NOTE(MUTEX_PROTECTS_DATA(hermon_state_s::hs_mcglock, 771 hermon_state_s::hs_mcghdl 772 hermon_state_s::hs_mcgtmp)) 773 _NOTE(DATA_READABLE_WITHOUT_LOCK(hermon_state_s::hs_in_evcallb 774 hermon_state_s::hs_fw_log_sector_sz 775 hermon_state_s::hs_fw_device_sz 776 hermon_state_s::hs_spec_qpflags 777 hermon_state_s::hs_spec_qp0 778 hermon_state_s::hs_spec_qp1)) 779 _NOTE(MUTEX_PROTECTS_DATA(hermon_state_s::hs_qpn_avl_lock, 780 hermon_state_s::hs_qpn_avl)) 781 _NOTE(SCHEME_PROTECTS_DATA("safe sharing", 782 hermon_state_s::hs_fm_async_fatal 783 hermon_state_s::hs_fw_sector)) 784 785 /* 786 * HERMON_IN_FASTREBOOT() shows if Hermon driver is at fastreboot. 787 * This macro should be used to check if the mutex lock can be used 788 * since the lock cannot be used if the driver is in the quiesce mode. 789 */ 790 #define HERMON_IN_FASTREBOOT(state) (state->hs_quiescing == B_TRUE) 791 792 /* 793 * Bit positions in the "hs_spec_qpflags" field above. The flags are (from 794 * least significant to most): (QP0,Port1), (QP0,Port2), (QP1,Port1), and 795 * (QP1,Port2). The masks are there to help with some specific allocation 796 * and freeing operations 797 */ 798 #define HERMON_SPECIAL_QP0_RSRC 0 799 #define HERMON_SPECIAL_QP0_RSRC_MASK 0x3 800 #define HERMON_SPECIAL_QP1_RSRC 2 801 #define HERMON_SPECIAL_QP1_RSRC_MASK 0xC 802 803 804 /* 805 * These flags specifies additional behaviors on database access. 806 * HERMON_UMAP_DB_REMOVE, for example, specifies that (if found) the database 807 * entry should be removed from the database. HERMON_UMAP_DB_IGNORE_INSTANCE 808 * specifies that a particular database query should ignore value in the 809 * "tdb_instance" field as a criterion for the search. 810 */ 811 #define HERMON_UMAP_DB_REMOVE (1 << 0) 812 #define HERMON_UMAP_DB_IGNORE_INSTANCE (1 << 1) 813 814 /* 815 * The hermon_umap_db_t structure contains what is referred to throughout the 816 * driver code as the "userland resources database". This structure contains 817 * all the necessary information to track resources that have been prepared 818 * for direct-from-userland access. There is an AVL tree ("hdl_umapdb_avl") 819 * which consists of the "hermon_umap_db_entry_t" (below) and a lock to ensure 820 * atomic access when adding or removing entries from the database. 821 */ 822 typedef struct hermon_umap_db_s { 823 kmutex_t hdl_umapdb_lock; 824 avl_tree_t hdl_umapdb_avl; 825 } hermon_umap_db_t; 826 827 /* 828 * The hermon_umap_db_priv_t structure currently contains information necessary 829 * to provide the "on close" callback to the firmware flash interfaces. It 830 * is intended that this structure could be extended to enable other "on 831 * close" callbacks as well. 832 */ 833 typedef struct hermon_umap_db_priv_s { 834 int (*hdp_cb)(void *); 835 void *hdp_arg; 836 } hermon_umap_db_priv_t; 837 838 /* 839 * The hermon_umap_db_common_t structure contains fields which are common 840 * between the database entries ("hermon_umap_db_entry_t") and the structure 841 * used to contain the search criteria ("hermon_umap_db_query_t"). This 842 * structure contains a key, a resource type (described above), an instance 843 * (corresponding to the driver instance which inserted the database entry), 844 * and a "value" field. Typically, "hdb_value" is a pointer to a Hermon 845 * resource object. Although for memory regions, the value field corresponds 846 * to the ddi_umem_cookie_t for the pinned userland memory. 847 * The structure also includes a placeholder for private data ("hdb_priv"). 848 * Currently this data is being used for holding "on close" callback 849 * information to allow certain kinds of cleanup even if a userland process 850 * prematurely exits. 851 */ 852 typedef struct hermon_umap_db_common_s { 853 uint64_t hdb_key; 854 uint64_t hdb_value; 855 uint_t hdb_type; 856 uint_t hdb_instance; 857 void *hdb_priv; 858 } hermon_umap_db_common_t; 859 860 /* 861 * The hermon_umap_db_entry_t structure is the entry in "userland resources 862 * database". As required by the AVL framework, each entry contains an 863 * "avl_node_t". Then, as required to implement the database, each entry 864 * contains a "hermon_umap_db_common_t" structure used to contain all of the 865 * relevant entries. 866 */ 867 typedef struct hermon_umap_db_entry_s { 868 avl_node_t hdbe_avlnode; 869 hermon_umap_db_common_t hdbe_common; 870 } hermon_umap_db_entry_t; 871 872 /* 873 * The hermon_umap_db_query_t structure is used in queries to the "userland 874 * resources database". In addition to the "hermon_umap_db_common_t" structure 875 * used to contain the various search criteria, this structure also contains 876 * a flags field "hqdb_flags" which can be used to specify additional behaviors 877 * (as described above). Specifically, the flags field can be used to specify 878 * that an entry should be removed from the database, if found, and to 879 * specify whether the database lookup should consider "tdb_instance" in the 880 * search. 881 */ 882 typedef struct hermon_umap_db_query_s { 883 uint_t hqdb_flags; 884 hermon_umap_db_common_t hqdb_common; 885 } hermon_umap_db_query_t; 886 _NOTE(MUTEX_PROTECTS_DATA(hermon_umap_db_s::hdl_umapdb_lock, 887 hermon_umap_db_entry_s::hdbe_avlnode 888 hermon_umap_db_entry_s::hdbe_common.hdb_key 889 hermon_umap_db_entry_s::hdbe_common.hdb_value 890 hermon_umap_db_entry_s::hdbe_common.hdb_type 891 hermon_umap_db_entry_s::hdbe_common.hdb_instance)) 892 893 /* 894 * The hermon_devmap_track_t structure contains all the necessary information 895 * to track resources that have been mapped through devmap. There is a 896 * back-pointer to the Hermon softstate, the logical offset corresponding with 897 * the mapped resource, the size of the mapped resource (zero indicates an 898 * "invalid mapping"), and a reference count and lock used to determine when 899 * to free the structure (specifically, this is necessary to handle partial 900 * unmappings). 901 */ 902 typedef struct hermon_devmap_track_s { 903 hermon_state_t *hdt_state; 904 uint64_t hdt_offset; 905 uint_t hdt_size; 906 int hdt_refcnt; 907 kmutex_t hdt_lock; 908 } hermon_devmap_track_t; 909 910 #define HERMON_ICM_SPLIT 64 911 #define HERMON_ICM_SPAN 4096 912 913 #define hermon_bitmap(bitmap, dma_info, icm_table, split_index) \ 914 bitmap = (icm_table)->icm_bitmap[split_index]; \ 915 if (bitmap == NULL) { \ 916 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*(icm_table))) \ 917 int num_spans = (icm_table)->num_spans; \ 918 bitmap = \ 919 (icm_table)->icm_bitmap[split_index] = \ 920 kmem_zalloc((num_spans + 7) / 8, KM_SLEEP); \ 921 ASSERT((icm_table)->icm_dma[split_index] == NULL); \ 922 (icm_table)->icm_dma[split_index] = \ 923 kmem_zalloc(num_spans * sizeof (hermon_dma_info_t), \ 924 KM_SLEEP); \ 925 } \ 926 dma_info = (icm_table)->icm_dma[split_index] 927 928 /* 929 * The hermon_icm_table_t encodes data pertaining to a given ICM table, and 930 * holds an array of hermon_dma_info_t's related to its backing memory. Each 931 * ICM table is sized during initialization, but real memory is allocated 932 * and mapped into and out of ICM in the device throughout the life of the 933 * instance. We use a bitmap to determine whether or not a given ICM object 934 * has memory backing it or not, and an array of hermon_dma_info_t's to house 935 * the actual allocations. Memory is allocated in chunks of span_size, stored 936 * in the icm_dma array, and can later be looked up by using the bitmap index. 937 * The total number of ICM spans is equal to table_size / span_size. We also 938 * keep track of the ICM characteristics, such as ICM object size and the 939 * number of entries in the ICM area. 940 */ 941 struct hermon_icm_table_s { 942 kmutex_t icm_table_lock; 943 kcondvar_t icm_table_cv; 944 uint8_t icm_busy; 945 hermon_rsrc_type_t icm_type; 946 uint64_t icm_baseaddr; 947 uint64_t table_size; 948 uint64_t num_entries; /* maximum #entries */ 949 uint32_t object_size; 950 uint32_t span; /* #rsrc's per span */ 951 uint32_t num_spans; /* #dmainfos in icm_dma */ 952 uint32_t split_shift; 953 uint32_t span_mask; 954 uint32_t span_shift; 955 uint32_t rsrc_mask; 956 uint16_t log_num_entries; 957 uint16_t log_object_size; 958 /* two arrays of pointers, each pointer points to arrays */ 959 uint8_t *icm_bitmap[HERMON_ICM_SPLIT]; 960 hermon_dma_info_t *icm_dma[HERMON_ICM_SPLIT]; 961 }; 962 /* 963 * Split the rsrc index into three pieces: 964 * 965 * index1 - icm_bitmap[HERMON_ICM_SPLIT], icm_dma[HERMON_ICM_SPLIT] 966 * index2 - bitmap[], dma[] 967 * offset - rsrc within the icm mapping 968 */ 969 #define hermon_index(index1, index2, rindx, table, offset) \ 970 index1 = (rindx) >> table->split_shift; \ 971 index2 = ((rindx) & table->span_mask) >> table->span_shift; \ 972 offset = (rindx) & table->rsrc_mask 973 974 /* Defined in hermon.c */ 975 int hermon_dma_alloc(hermon_state_t *state, hermon_dma_info_t *dma_info, 976 uint16_t opcode); 977 void hermon_dma_attr_init(hermon_state_t *state, ddi_dma_attr_t *dma_attr); 978 void hermon_dma_free(hermon_dma_info_t *info); 979 int hermon_icm_alloc(hermon_state_t *state, hermon_rsrc_type_t type, 980 uint32_t icm_index1, uint32_t icm_index2); 981 void hermon_icm_free(hermon_state_t *state, hermon_rsrc_type_t type, 982 uint32_t icm_index1, uint32_t icm_index2); 983 984 /* Defined in hermon_umap.c */ 985 int hermon_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len, 986 size_t *maplen, uint_t model); 987 ibt_status_t hermon_umap_ci_data_in(hermon_state_t *state, 988 ibt_ci_data_flags_t flags, ibt_object_type_t object, void *hdl, 989 void *data_p, size_t data_sz); 990 ibt_status_t hermon_umap_ci_data_out(hermon_state_t *state, 991 ibt_ci_data_flags_t flags, ibt_object_type_t object, void *hdl, 992 void *data_p, size_t data_sz); 993 void hermon_umap_db_init(void); 994 void hermon_umap_db_fini(void); 995 hermon_umap_db_entry_t *hermon_umap_db_alloc(uint_t instance, uint64_t key, 996 uint_t type, uint64_t value); 997 void hermon_umap_db_free(hermon_umap_db_entry_t *umapdb); 998 void hermon_umap_db_add(hermon_umap_db_entry_t *umapdb); 999 void hermon_umap_db_add_nolock(hermon_umap_db_entry_t *umapdb); 1000 int hermon_umap_db_find(uint_t instance, uint64_t key, uint_t type, 1001 uint64_t *value, uint_t flags, hermon_umap_db_entry_t **umapdb); 1002 int hermon_umap_db_find_nolock(uint_t instance, uint64_t key, uint_t type, 1003 uint64_t *value, uint_t flags, hermon_umap_db_entry_t **umapdb); 1004 void hermon_umap_umemlock_cb(ddi_umem_cookie_t *umem_cookie); 1005 int hermon_umap_db_set_onclose_cb(dev_t dev, uint64_t flag, 1006 int (*callback)(void *), void *arg); 1007 int hermon_umap_db_clear_onclose_cb(dev_t dev, uint64_t flag); 1008 int hermon_umap_db_handle_onclose_cb(hermon_umap_db_priv_t *priv); 1009 int hermon_rsrc_hw_entries_init(hermon_state_t *state, 1010 hermon_rsrc_hw_entry_info_t *info); 1011 void hermon_rsrc_hw_entries_fini(hermon_state_t *state, 1012 hermon_rsrc_hw_entry_info_t *info); 1013 1014 #ifdef __cplusplus 1015 } 1016 #endif 1017 1018 #endif /* _SYS_IB_ADAPTERS_HERMON_H */ 1019