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 2014 QLogic Corporation 24 * The contents of this file are subject to the terms of the 25 * QLogic End User License (the "License"). 26 * You may not use this file except in compliance with the License. 27 * 28 * You can obtain a copy of the License at 29 * http://www.qlogic.com/Resources/Documents/DriverDownloadHelp/ 30 * QLogic_End_User_Software_License.txt 31 * See the License for the specific language governing permissions 32 * and limitations under the License. 33 */ 34 35 /* 36 * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. 37 */ 38 39 #include "bnxe.h" 40 41 #ifndef STRINGIFY 42 #define XSTRINGIFY(x) #x 43 #define STRINGIFY(x) XSTRINGIFY(x) 44 #endif 45 46 #define BNXE_PRODUCT_BANNER "QLogic NetXtreme II 10 Gigabit Ethernet Driver v" STRINGIFY(MAJVERSION) "." STRINGIFY(MINVERSION) "." STRINGIFY(REVVERSION) 47 #define BNXE_PRODUCT_INFO "QLogic NXII 10 GbE v" STRINGIFY(MAJVERSION) "." STRINGIFY(MINVERSION) "." STRINGIFY(REVVERSION) 48 49 #define BNXE_REGISTER_BAR_NUM 1 50 #define BNXE_REGS_MAP_OFFSET 0 51 #define BNXE_L2_MEMORY_WINDOW_SIZE 0x40000 /* 256K for PCI Config Registers */ 52 53 u32_t dbg_code_path = CP_ALL; 54 u8_t dbg_trace_level = LV_VERBOSE; 55 u32_t g_dbg_flags = 0; 56 57 kmutex_t bnxeLoaderMutex; 58 u32_t bnxeNumPlumbed; 59 60 extern ddi_dma_attr_t bnxeDmaPageAttrib; 61 extern ddi_dma_attr_t bnxeRxDmaAttrib; 62 extern ddi_dma_attr_t bnxeTxDmaAttrib; 63 extern ddi_dma_attr_t bnxeTxCbDmaAttrib; 64 65 66 u8_t BnxeInstance(void * pDev) 67 { 68 um_device_t * pUM = (um_device_t *)pDev; 69 return (pUM == NULL) ? 0xf : pUM->instance; 70 } 71 72 73 /* pass in pointer to either lm_device_t or um_device_t */ 74 char * BnxeDevName(void * pDev) 75 { 76 um_device_t * pUM = (um_device_t *)pDev; 77 return ((pUM == NULL) || (*pUM->devName == 0)) ? "(bnxe)" : pUM->devName; 78 } 79 80 81 char * BnxeChipName(um_device_t * pUM) 82 { 83 switch (CHIP_NUM(&pUM->lm_dev) >> 16) 84 { 85 case 0x164e: return "BCM57710"; 86 case 0x164f: return "BCM57711"; 87 case 0x1650: return "BCM57711E"; 88 case 0x1662: return "BCM57712"; 89 case 0x1663: return "BCM57712NP"; 90 case 0x16a1: return "BCM57840"; 91 case 0x168d: return "BCM57840"; 92 case 0x16a4: return "BCM57840NP"; 93 case 0x16ab: return "BCM57840NP"; 94 case 0x168e: return "BCM57810"; 95 case 0x16ae: return "BCM57810NP"; 96 case 0x168a: return "BCM57800"; 97 case 0x16a5: return "BCM57800NP"; 98 default: return "UNKNOWN"; 99 } 100 } 101 102 103 boolean_t BnxeProtoSupport(um_device_t * pUM, int proto) 104 { 105 boolean_t do_eth; 106 boolean_t do_fcoe; 107 uint32_t port_feature_config_sf; 108 109 if (IS_MULTI_VNIC(&pUM->lm_dev)) 110 { 111 do_eth = B_FALSE; 112 do_fcoe = B_FALSE; 113 114 if (pUM->lm_dev.hw_info.mcp_detected == 1) 115 { 116 if (pUM->lm_dev.params.mf_proto_support_flags & 117 LM_PROTO_SUPPORT_ETHERNET) 118 { 119 do_eth = B_TRUE; 120 } 121 122 if (pUM->lm_dev.params.mf_proto_support_flags & 123 LM_PROTO_SUPPORT_FCOE) 124 { 125 do_fcoe = B_TRUE; 126 } 127 } 128 else 129 { 130 /* mcp is not present so allow enumeration */ 131 do_eth = B_TRUE; 132 do_fcoe = B_TRUE; 133 } 134 } 135 else /* SF */ 136 { 137 do_eth = B_TRUE; 138 do_fcoe = B_FALSE; 139 140 /* check per port storage personality config from NVRAM */ 141 port_feature_config_sf = (pUM->lm_dev.hw_info.port_feature_config & 142 PORT_FEAT_CFG_STORAGE_PERSONALITY_MASK); 143 144 switch (port_feature_config_sf) 145 { 146 case PORT_FEAT_CFG_STORAGE_PERSONALITY_ISCSI: 147 break; 148 149 case PORT_FEAT_CFG_STORAGE_PERSONALITY_FCOE: 150 case PORT_FEAT_CFG_STORAGE_PERSONALITY_BOTH: 151 case PORT_FEAT_CFG_STORAGE_PERSONALITY_DEFAULT: 152 default: 153 do_fcoe = B_TRUE; 154 break; 155 } 156 } 157 158 if (pUM->lm_dev.params.max_func_fcoe_cons == 0) 159 { 160 do_fcoe = B_FALSE; 161 } 162 163 return (((proto == LM_PROTO_SUPPORT_ETHERNET) && do_eth) || 164 ((proto == LM_PROTO_SUPPORT_FCOE) && do_fcoe)); 165 } 166 167 168 boolean_t BnxeProtoFcoeAfex(um_device_t * pUM) 169 { 170 return ((pUM->lm_dev.params.mf_mode == MULTI_FUNCTION_AFEX) && 171 BnxeProtoSupport(pUM, LM_PROTO_SUPPORT_FCOE)) ? B_TRUE : B_FALSE; 172 } 173 174 175 static boolean_t BnxePciInit(um_device_t * pUM) 176 { 177 /* setup resources needed for accessing the PCI configuration space */ 178 if (pci_config_setup(pUM->pDev, &pUM->pPciCfg) != DDI_SUCCESS) 179 { 180 BnxeLogWarn(pUM, "Failed to setup PCI config"); 181 return B_FALSE; 182 } 183 184 return B_TRUE; 185 } 186 187 188 static void BnxePciDestroy(um_device_t * pUM) 189 { 190 if (pUM->pPciCfg) 191 { 192 pci_config_teardown(&pUM->pPciCfg); 193 pUM->pPciCfg = NULL; 194 } 195 } 196 197 198 static void BnxeBarMemDestroy(um_device_t * pUM) 199 { 200 BnxeMemRegion * pMemRegion; 201 202 /* free the BAR mappings */ 203 while (!d_list_is_empty(&pUM->memRegionList)) 204 { 205 pMemRegion = (BnxeMemRegion *)d_list_peek_head(&pUM->memRegionList); 206 mm_unmap_io_space(&pUM->lm_dev, 207 pMemRegion->pRegAddr, 208 pMemRegion->size); 209 } 210 } 211 212 213 static void BnxeMutexInit(um_device_t * pUM) 214 { 215 lm_device_t * pLM = &pUM->lm_dev; 216 int idx; 217 218 for (idx = 0; idx < (MAX_RSS_CHAINS + 1); idx++) 219 { 220 mutex_init(&pUM->intrMutex[idx], NULL, 221 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 222 mutex_init(&pUM->intrFlipMutex[idx], NULL, 223 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 224 mutex_init(&pUM->sbMutex[idx], NULL, 225 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 226 } 227 228 for (idx = 0; idx < MAX_ETH_CONS; idx++) 229 { 230 mutex_init(&pUM->txq[idx].txMutex, NULL, 231 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 232 mutex_init(&pUM->txq[idx].freeTxDescMutex, NULL, 233 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 234 pUM->txq[idx].pUM = pUM; 235 pUM->txq[idx].idx = idx; 236 } 237 238 for (idx = 0; idx < MAX_ETH_CONS; idx++) 239 { 240 mutex_init(&pUM->rxq[idx].rxMutex, NULL, 241 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 242 mutex_init(&pUM->rxq[idx].doneRxMutex, NULL, 243 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 244 pUM->rxq[idx].pUM = pUM; 245 pUM->rxq[idx].idx = idx; 246 } 247 248 for (idx = 0; idx < USER_OPTION_RX_RING_GROUPS_MAX; idx++) 249 { 250 pUM->rxqGroup[idx].pUM = pUM; 251 pUM->rxqGroup[idx].idx = idx; 252 } 253 254 mutex_init(&pUM->ethConMutex, NULL, 255 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 256 mutex_init(&pUM->mcpMutex, NULL, 257 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 258 mutex_init(&pUM->phyMutex, NULL, 259 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 260 mutex_init(&pUM->indMutex, NULL, 261 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 262 mutex_init(&pUM->cidMutex, NULL, 263 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 264 mutex_init(&pUM->spqMutex, NULL, 265 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 266 mutex_init(&pUM->spReqMutex, NULL, 267 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 268 mutex_init(&pUM->rrReqMutex, NULL, 269 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 270 mutex_init(&pUM->islesCtrlMutex, NULL, 271 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 272 mutex_init(&pUM->toeMutex, NULL, 273 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 274 mutex_init(&pUM->memMutex, NULL, 275 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 276 mutex_init(&pUM->offloadMutex, NULL, 277 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 278 mutex_init(&pUM->hwInitMutex, NULL, 279 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 280 mutex_init(&pUM->gldMutex, NULL, 281 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 282 rw_init(&pUM->gldTxMutex, NULL, RW_DRIVER, NULL); 283 mutex_init(&pUM->timerMutex, NULL, 284 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 285 mutex_init(&pUM->kstatMutex, NULL, 286 MUTEX_DRIVER, DDI_INTR_PRI(pUM->intrPriority)); 287 } 288 289 290 static void BnxeMutexDestroy(um_device_t * pUM) 291 { 292 lm_device_t * pLM = &pUM->lm_dev; 293 int idx; 294 295 for (idx = 0; idx < (MAX_RSS_CHAINS + 1); idx++) 296 { 297 mutex_destroy(&pUM->intrMutex[idx]); 298 mutex_destroy(&pUM->intrFlipMutex[idx]); 299 mutex_destroy(&pUM->sbMutex[idx]); 300 } 301 302 for (idx = 0; idx < MAX_ETH_CONS; idx++) 303 { 304 mutex_destroy(&pUM->txq[idx].txMutex); 305 mutex_destroy(&pUM->txq[idx].freeTxDescMutex); 306 } 307 308 for (idx = 0; idx < MAX_ETH_CONS; idx++) 309 { 310 mutex_destroy(&pUM->rxq[idx].rxMutex); 311 mutex_destroy(&pUM->rxq[idx].doneRxMutex); 312 } 313 314 mutex_destroy(&pUM->ethConMutex); 315 mutex_destroy(&pUM->mcpMutex); 316 mutex_destroy(&pUM->phyMutex); 317 mutex_destroy(&pUM->indMutex); 318 mutex_destroy(&pUM->cidMutex); 319 mutex_destroy(&pUM->spqMutex); 320 mutex_destroy(&pUM->spReqMutex); 321 mutex_destroy(&pUM->rrReqMutex); 322 mutex_destroy(&pUM->islesCtrlMutex); 323 mutex_destroy(&pUM->toeMutex); 324 mutex_destroy(&pUM->memMutex); /* not until all mem deleted */ 325 mutex_destroy(&pUM->offloadMutex); 326 mutex_destroy(&pUM->hwInitMutex); 327 mutex_destroy(&pUM->gldMutex); 328 rw_destroy(&pUM->gldTxMutex); 329 mutex_destroy(&pUM->timerMutex); 330 mutex_destroy(&pUM->kstatMutex); 331 } 332 333 334 /* FMA support */ 335 336 int BnxeCheckAccHandle(ddi_acc_handle_t handle) 337 { 338 ddi_fm_error_t de; 339 340 ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION); 341 ddi_fm_acc_err_clear(handle, DDI_FME_VERSION); 342 343 return (de.fme_status); 344 } 345 346 347 int BnxeCheckDmaHandle(ddi_dma_handle_t handle) 348 { 349 ddi_fm_error_t de; 350 351 ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION); 352 353 return (de.fme_status); 354 } 355 356 357 /* The IO fault service error handling callback function */ 358 static int BnxeFmErrorCb(dev_info_t * pDev, 359 ddi_fm_error_t * err, 360 const void * impl_data) 361 { 362 /* 363 * As the driver can always deal with an error in any dma or 364 * access handle, we can just return the fme_status value. 365 */ 366 pci_ereport_post(pDev, err, NULL); 367 368 return (err->fme_status); 369 } 370 371 372 static void BnxeFmInit(um_device_t * pUM) 373 { 374 ddi_iblock_cookie_t iblk; 375 int fma_acc_flag; 376 int fma_dma_flag; 377 378 /* Only register with IO Fault Services if we have some capability */ 379 if (pUM->fmCapabilities & DDI_FM_ACCCHK_CAPABLE) 380 { 381 bnxeAccessAttribBAR.devacc_attr_version = DDI_DEVICE_ATTR_V1; 382 bnxeAccessAttribBAR.devacc_attr_access = DDI_FLAGERR_ACC; 383 } 384 385 if (pUM->fmCapabilities & DDI_FM_DMACHK_CAPABLE) 386 { 387 bnxeDmaPageAttrib.dma_attr_flags = DDI_DMA_FLAGERR; 388 bnxeRxDmaAttrib.dma_attr_flags = DDI_DMA_FLAGERR; 389 bnxeTxDmaAttrib.dma_attr_flags = DDI_DMA_FLAGERR; 390 bnxeTxCbDmaAttrib.dma_attr_flags = DDI_DMA_FLAGERR; 391 } 392 393 if (pUM->fmCapabilities) 394 { 395 /* Register capabilities with IO Fault Services */ 396 ddi_fm_init(pUM->pDev, &pUM->fmCapabilities, &iblk); 397 398 /* Initialize pci ereport capabilities if ereport capable */ 399 if (DDI_FM_EREPORT_CAP(pUM->fmCapabilities) || 400 DDI_FM_ERRCB_CAP(pUM->fmCapabilities)) 401 { 402 pci_ereport_setup(pUM->pDev); 403 } 404 405 /* Register error callback if error callback capable */ 406 if (DDI_FM_ERRCB_CAP(pUM->fmCapabilities)) 407 { 408 ddi_fm_handler_register(pUM->pDev, BnxeFmErrorCb, (void *)pUM); 409 } 410 } 411 } 412 413 414 static void BnxeFmFini(um_device_t * pUM) 415 { 416 /* Only unregister FMA capabilities if we registered some */ 417 if (pUM->fmCapabilities) 418 { 419 /* Release any resources allocated by pci_ereport_setup() */ 420 if (DDI_FM_EREPORT_CAP(pUM->fmCapabilities) || 421 DDI_FM_ERRCB_CAP(pUM->fmCapabilities)) 422 { 423 pci_ereport_teardown(pUM->pDev); 424 } 425 426 /* Un-register error callback if error callback capable */ 427 if (DDI_FM_ERRCB_CAP(pUM->fmCapabilities)) 428 { 429 ddi_fm_handler_unregister(pUM->pDev); 430 } 431 432 /* Unregister from IO Fault Services */ 433 ddi_fm_fini(pUM->pDev); 434 } 435 } 436 437 438 void BnxeFmErrorReport(um_device_t * pUM, 439 char * detail) 440 { 441 uint64_t ena; 442 char buf[FM_MAX_CLASS]; 443 444 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail); 445 446 ena = fm_ena_generate(0, FM_ENA_FMT1); 447 448 if (DDI_FM_EREPORT_CAP(pUM->fmCapabilities)) 449 { 450 ddi_fm_ereport_post(pUM->pDev, buf, ena, DDI_NOSLEEP, 451 FM_VERSION, DATA_TYPE_UINT8, 452 FM_EREPORT_VERS0, NULL); 453 } 454 } 455 456 457 static boolean_t BnxeAttachDevice(um_device_t * pUM) 458 { 459 int rc; 460 int * props = NULL; 461 uint_t numProps; 462 u32_t vendor_id; 463 u32_t device_id; 464 465 /* fm-capable in bnxe.conf can be used to set fmCapabilities. */ 466 pUM->fmCapabilities = ddi_prop_get_int(DDI_DEV_T_ANY, 467 pUM->pDev, 468 DDI_PROP_DONTPASS, 469 "fm-capable", 470 (DDI_FM_EREPORT_CAPABLE | 471 DDI_FM_ACCCHK_CAPABLE | 472 DDI_FM_DMACHK_CAPABLE | 473 DDI_FM_ERRCB_CAPABLE)); 474 475 /* Register capabilities with IO Fault Services. */ 476 BnxeFmInit(pUM); 477 478 if (!BnxePciInit(pUM)) 479 { 480 BnxeFmFini(pUM); 481 482 return B_FALSE; 483 } 484 485 BnxeMutexInit(pUM); 486 487 if (!BnxeWorkQueueInit(pUM)) 488 { 489 return B_FALSE; 490 } 491 492 rc = lm_get_dev_info(&pUM->lm_dev); 493 494 if (pUM->fmCapabilities && 495 BnxeCheckAccHandle(pUM->pPciCfg) != DDI_FM_OK) 496 { 497 ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_LOST); 498 BnxeWorkQueueWaitAndDestroy(pUM); 499 BnxeMutexDestroy(pUM); 500 BnxePciDestroy(pUM); 501 BnxeFmFini(pUM); 502 503 return B_FALSE; 504 } 505 506 if (pUM->fmCapabilities && 507 BnxeCheckAccHandle(pUM->lm_dev.vars.reg_handle[BAR_0]) != DDI_FM_OK) 508 { 509 ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_LOST); 510 BnxeWorkQueueWaitAndDestroy(pUM); 511 BnxeMutexDestroy(pUM); 512 BnxePciDestroy(pUM); 513 BnxeFmFini(pUM); 514 515 return B_FALSE; 516 } 517 518 if (rc != LM_STATUS_SUCCESS) 519 { 520 BnxeFmErrorReport(pUM, DDI_FM_DEVICE_INVAL_STATE); 521 ddi_fm_service_impact(pUM->pDev, DDI_SERVICE_LOST); 522 BnxeWorkQueueWaitAndDestroy(pUM); 523 BnxeMutexDestroy(pUM); 524 BnxePciDestroy(pUM); 525 BnxeFmFini(pUM); 526 527 BnxeLogWarn(pUM, "Failed to get device information"); 528 return B_FALSE; 529 } 530 531 #if 0 532 if (IS_PFDEV(&pUM->lm_dev) && lm_check_if_pf_assigned_to_vm(&pUM->lm_dev)) 533 { 534 lm_set_virt_mode(&pUM->lm_dev, DEVICE_TYPE_PF, VT_ASSIGNED_TO_VM_PF); 535 } 536 #endif 537 538 /* check if FCoE is enabled on this function */ 539 #if 0 540 pUM->do_fcoe = 541 ((CHIP_IS_E2(&pUM->lm_dev) || CHIP_IS_E3(&pUM->lm_dev)) && 542 BnxeProtoSupport(pUM, LM_PROTO_SUPPORT_FCOE)) ? B_TRUE : 543 B_FALSE; 544 #else 545 pUM->do_fcoe = B_FALSE; 546 #endif 547 548 lm_get_iscsi_boot_info_block(&pUM->lm_dev, &pUM->iscsiInfo); 549 if (pUM->iscsiInfo.signature != 0) 550 { 551 BnxeLogInfo(pUM, "MBA FCoE boot occurred on this interface."); 552 } 553 554 if (!BnxeIntrInit(pUM)) 555 { 556 BnxeBarMemDestroy(pUM); 557 BnxeWorkQueueWaitAndDestroy(pUM); 558 BnxeMutexDestroy(pUM); 559 BnxePciDestroy(pUM); 560 BnxeFmFini(pUM); 561 562 return B_FALSE; 563 } 564 565 if (!BnxeKstatInit(pUM)) 566 { 567 BnxeIntrFini(pUM); 568 BnxeBarMemDestroy(pUM); 569 BnxeWorkQueueWaitAndDestroy(pUM); 570 BnxeMutexDestroy(pUM); 571 BnxePciDestroy(pUM); 572 BnxeFmFini(pUM); 573 574 return B_FALSE; 575 } 576 577 if (BnxeProtoFcoeAfex(pUM)) 578 { 579 /* No support for L2 on FCoE enabled AFEX function! */ 580 BnxeLogInfo(pUM, "FCoE AFEX function, not registering with GLD."); 581 #if 0 582 /* 583 * The following is wonky. Doing a CLONE_DEV makes it visible to 584 * various L2 networking commands even though the instance was 585 * not registered with GLDv3 via mac_register(). 586 */ 587 588 /* Create a style-2 DLPI device */ 589 if (ddi_create_minor_node(pUM->pDev, 590 (char *)ddi_driver_name(pUM->pDev), 591 S_IFCHR, 592 0, 593 DDI_PSEUDO, //DDI_NT_NET, 594 CLONE_DEV) != DDI_SUCCESS) 595 { 596 BnxeLogWarn(pUM, "Failed to create device minor node."); 597 BnxeKstatFini(pUM); 598 BnxeIntrFini(pUM); 599 BnxeBarMemDestroy(pUM); 600 BnxeWorkQueueWaitAndDestroy(pUM); 601 BnxeMutexDestroy(pUM); 602 BnxePciDestroy(pUM); 603 BnxeFmFini(pUM); 604 605 return B_FALSE; 606 } 607 608 /* Create a style-1 DLPI device */ 609 if (ddi_create_minor_node(pUM->pDev, 610 pUM->devName, 611 S_IFCHR, 612 pUM->instance, 613 DDI_PSEUDO, //DDI_NT_NET, 614 0) != DDI_SUCCESS) 615 { 616 BnxeLogWarn(pUM, "Failed to create device instance minor node."); 617 ddi_remove_minor_node(pUM->pDev, (char *)ddi_driver_name(pUM->pDev)); 618 BnxeKstatFini(pUM); 619 BnxeIntrFini(pUM); 620 BnxeBarMemDestroy(pUM); 621 BnxeWorkQueueWaitAndDestroy(pUM); 622 BnxeMutexDestroy(pUM); 623 BnxePciDestroy(pUM); 624 BnxeFmFini(pUM); 625 626 return B_FALSE; 627 } 628 #endif 629 } 630 else 631 { 632 /* register with the GLDv3 MAC layer */ 633 if (!BnxeGldInit(pUM)) 634 { 635 BnxeKstatFini(pUM); 636 BnxeIntrFini(pUM); 637 BnxeBarMemDestroy(pUM); 638 BnxeWorkQueueWaitAndDestroy(pUM); 639 BnxeMutexDestroy(pUM); 640 BnxePciDestroy(pUM); 641 BnxeFmFini(pUM); 642 643 return B_FALSE; 644 } 645 } 646 647 snprintf(pUM->version, 648 sizeof(pUM->version), 649 "%d.%d.%d", 650 MAJVERSION, 651 MINVERSION, 652 REVVERSION); 653 654 snprintf(pUM->versionLM, 655 sizeof(pUM->versionLM), 656 "%d.%d.%d", 657 LM_DRIVER_MAJOR_VER, 658 LM_DRIVER_MINOR_VER, 659 LM_DRIVER_FIX_NUM); 660 661 snprintf(pUM->versionFW, 662 sizeof(pUM->versionFW), 663 "%d.%d.%d.%d", 664 BCM_5710_FW_MAJOR_VERSION, 665 BCM_5710_FW_MINOR_VERSION, 666 BCM_5710_FW_REVISION_VERSION, 667 BCM_5710_FW_ENGINEERING_VERSION); 668 669 snprintf(pUM->versionBC, 670 sizeof(pUM->versionBC), 671 "%d.%d.%d", 672 ((pUM->lm_dev.hw_info.bc_rev >> 24) & 0xff), 673 ((pUM->lm_dev.hw_info.bc_rev >> 16) & 0xff), 674 ((pUM->lm_dev.hw_info.bc_rev >> 8) & 0xff)); 675 676 snprintf(pUM->chipName, 677 sizeof(pUM->chipName), 678 "%s", 679 BnxeChipName(pUM)); 680 681 snprintf(pUM->chipID, 682 sizeof(pUM->chipID), 683 "0x%x", 684 pUM->lm_dev.hw_info.chip_id); 685 686 *pUM->bus_dev_func = 0; 687 rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, pUM->pDev, 688 0, "reg", &props, &numProps); 689 if ((rc == DDI_PROP_SUCCESS) && (numProps > 0)) 690 { 691 snprintf(pUM->bus_dev_func, 692 sizeof(pUM->bus_dev_func), 693 "%04x:%02x:%02x", 694 PCI_REG_BUS_G(props[0]), 695 PCI_REG_DEV_G(props[0]), 696 PCI_REG_FUNC_G(props[0])); 697 ddi_prop_free(props); 698 } 699 700 vendor_id = 0; 701 rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, pUM->pDev, 702 0, "vendor-id", &props, &numProps); 703 if ((rc == DDI_PROP_SUCCESS) && (numProps > 0)) 704 { 705 vendor_id = props[0]; 706 ddi_prop_free(props); 707 } 708 709 device_id = 0; 710 rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, pUM->pDev, 711 0, "device-id", &props, &numProps); 712 if ((rc == DDI_PROP_SUCCESS) && (numProps > 0)) 713 { 714 device_id = props[0]; 715 ddi_prop_free(props); 716 } 717 718 snprintf(pUM->vendor_device, 719 sizeof(pUM->vendor_device), 720 "%04x:%04x", 721 vendor_id, 722 device_id); 723 724 snprintf(pUM->intrAlloc, 725 sizeof(pUM->intrAlloc), 726 "%d %s", 727 (pUM->intrType == DDI_INTR_TYPE_FIXED) ? 1 : (pUM->defIntr.intrCount + 728 pUM->fcoeIntr.intrCount + 729 pUM->rssIntr.intrCount), 730 (pUM->intrType == DDI_INTR_TYPE_MSIX) ? "MSIX" : 731 (pUM->intrType == DDI_INTR_TYPE_MSI) ? "MSI" : 732 "Fixed"); 733 734 BnxeLogInfo(pUM, 735 "(0x%p) %s %s - v%s - FW v%s - BC v%s - %s (%s)", 736 pUM, 737 pUM->chipName, 738 pUM->chipID, 739 pUM->version, 740 pUM->versionFW, 741 pUM->versionBC, 742 IS_MULTI_VNIC(&pUM->lm_dev) ? "MF" : "SF", 743 pUM->intrAlloc); 744 745 return B_TRUE; 746 } 747 748 749 static boolean_t BnxeDetachDevice(um_device_t * pUM) 750 { 751 int rc; 752 753 rc = BnxeFcoeFini(pUM); 754 755 if ((rc != 0) && (rc != ENOTSUP) && (rc != ENODEV)) 756 { 757 return B_FALSE; 758 } 759 760 if (BnxeProtoFcoeAfex(pUM)) 761 { 762 /* No support for L2 on FCoE enabled AFEX function! */ 763 ; 764 #if 0 765 ddi_remove_minor_node(pUM->pDev, pUM->devName); 766 ddi_remove_minor_node(pUM->pDev, (char *)ddi_driver_name(pUM->pDev)); 767 #endif 768 } 769 else 770 { 771 if (!BnxeGldFini(pUM)) 772 { 773 return B_FALSE; 774 } 775 } 776 777 BnxeKstatFini(pUM); 778 BnxeIntrFini(pUM); 779 BnxeBarMemDestroy(pUM); 780 BnxeWorkQueueWaitAndDestroy(pUM); 781 BnxeMutexDestroy(pUM); 782 BnxePciDestroy(pUM); 783 BnxeFmFini(pUM); 784 785 return B_TRUE; 786 } 787 788 789 static int BnxeAttach(dev_info_t * pDev, ddi_attach_cmd_t cmd) 790 { 791 um_device_t * pUM; 792 793 switch (cmd) 794 { 795 case DDI_ATTACH: 796 797 if ((pUM = kmem_zalloc(sizeof(um_device_t), KM_SLEEP)) == NULL) 798 { 799 BnxeLogWarn(NULL, "failed to allocate device structure"); 800 return DDI_FAILURE; 801 } 802 803 ddi_set_driver_private(pDev, pUM); 804 805 /* set magic number for identification */ 806 pUM->magic = BNXE_MAGIC; 807 808 /* default for debug logging is dump everything */ 809 pUM->devParams.debug_level = (CP_ALL | LV_MASK); 810 811 /* save dev_info_t in the driver structure */ 812 pUM->pDev = pDev; 813 814 d_list_clear(&pUM->memBlockList); 815 d_list_clear(&pUM->memDmaList); 816 d_list_clear(&pUM->memRegionList); 817 #ifdef BNXE_DEBUG_DMA_LIST 818 d_list_clear(&pUM->memDmaListSaved); 819 #endif 820 821 /* obtain a human-readable device name log messages with */ 822 pUM->instance = ddi_get_instance(pDev); 823 snprintf(pUM->devName, sizeof(pUM->devName), 824 "bnxe%d", pUM->instance); 825 826 if (!BnxeAttachDevice(pUM)) 827 { 828 kmem_free(pUM, sizeof(um_device_t)); 829 return DDI_FAILURE; 830 } 831 832 if (BNXE_FCOE(pUM) && pUM->devParams.fcoeEnable) 833 { 834 BnxeFcoeStartStop(pUM); 835 } 836 837 return DDI_SUCCESS; 838 839 case DDI_RESUME: 840 #if !(defined(__S11) || defined(__S12)) 841 case DDI_PM_RESUME: 842 #endif 843 844 pUM = (um_device_t *)ddi_get_driver_private(pDev); 845 846 /* sanity check */ 847 if (pUM == NULL || pUM->pDev != pDev) 848 { 849 BnxeLogWarn(NULL, "%s: dev_info_t match failed", __func__); 850 return DDI_FAILURE; 851 } 852 853 if (BnxeHwResume(pUM) != 0) 854 { 855 BnxeLogWarn(pUM, "Fail to resume this device!"); 856 return DDI_FAILURE; 857 } 858 859 return DDI_SUCCESS; 860 861 default: 862 863 return DDI_FAILURE; 864 } 865 } 866 867 868 static int BnxeDetach(dev_info_t * pDev, ddi_detach_cmd_t cmd) 869 { 870 um_device_t * pUM; 871 872 switch (cmd) 873 { 874 case DDI_DETACH: 875 876 pUM = (um_device_t *)ddi_get_driver_private(pDev); 877 878 /* sanity check */ 879 if (pUM == NULL || pUM->pDev != pDev) 880 { 881 BnxeLogWarn(NULL, "%s: dev_info_t match failed", __func__); 882 return DDI_FAILURE; 883 } 884 885 if (pUM->intrEnabled != B_FALSE) 886 { 887 BnxeLogWarn(pUM, "Detaching a device that is currently running!"); 888 return DDI_FAILURE; 889 } 890 891 if (!BnxeDetachDevice(pUM)) 892 { 893 BnxeLogWarn(pUM, "Can't detach it now, please try again later!"); 894 return DDI_FAILURE; 895 } 896 897 kmem_free(pUM, sizeof(um_device_t)); 898 899 return DDI_SUCCESS; 900 901 case DDI_SUSPEND: 902 #if !(defined(__S11) || defined(__S12)) 903 case DDI_PM_SUSPEND: 904 #endif 905 906 pUM = (um_device_t *)ddi_get_driver_private(pDev); 907 908 /* sanity check */ 909 if (pUM == NULL || pUM->pDev != pDev) 910 { 911 BnxeLogWarn(NULL, "%s: dev_info_t match failed", __func__); 912 return DDI_FAILURE; 913 } 914 915 if (BnxeHwSuspend(pUM) != 0) 916 { 917 BnxeLogWarn(pUM, "Fail to suspend this device!"); 918 return DDI_FAILURE; 919 } 920 921 return DDI_SUCCESS; 922 923 default: 924 925 return DDI_FAILURE; 926 } 927 } 928 929 930 #if (DEVO_REV > 3) 931 932 static int BnxeQuiesce(dev_info_t * pDev) 933 { 934 um_device_t * pUM; 935 936 pUM = (um_device_t *)ddi_get_driver_private(pDev); 937 938 /* sanity check */ 939 if (pUM == NULL || pUM->pDev != pDev) 940 { 941 BnxeLogWarn(NULL, "%s: dev_info_t match failed", __func__); 942 return DDI_FAILURE; 943 } 944 945 if (!pUM->plumbed) 946 { 947 return DDI_SUCCESS; 948 } 949 950 if (BnxeHwQuiesce(pUM) != 0) 951 { 952 BnxeLogWarn(pUM, "Failed to quiesce the device!"); 953 return DDI_FAILURE; 954 } 955 956 return DDI_SUCCESS; 957 } 958 959 #endif 960 961 962 void BnxeFcoeInitChild(dev_info_t * pDev, 963 dev_info_t * cDip) 964 { 965 um_device_t *pUM = (um_device_t *) ddi_get_driver_private(pDev); 966 967 if ((pUM == NULL) || (pUM->pDev != pDev)) 968 { 969 BnxeLogWarn(NULL, "%s: dev_info_t match failed ", __func__); 970 return; 971 } 972 973 ddi_set_name_addr(cDip, ddi_get_name_addr(pUM->pDev)); 974 } 975 976 977 void BnxeFcoeUninitChild(dev_info_t * pDev, 978 dev_info_t * cDip) 979 { 980 ddi_set_name_addr(cDip, NULL); 981 } 982 983 984 static int BnxeBusCtl(dev_info_t * pDev, 985 dev_info_t * pRDev, 986 ddi_ctl_enum_t op, 987 void * pArg, 988 void * pResult) 989 { 990 um_device_t * pUM = (um_device_t *)ddi_get_driver_private(pDev); 991 992 /* sanity check */ 993 if (pUM == NULL || pUM->pDev != pDev) 994 { 995 BnxeLogWarn(NULL, "%s: dev_info_t match failed", __func__); 996 return DDI_FAILURE; 997 } 998 999 BnxeLogDbg(pUM, "BnxeBusCtl (%d)", op); 1000 1001 switch (op) 1002 { 1003 case DDI_CTLOPS_REPORTDEV: 1004 case DDI_CTLOPS_IOMIN: 1005 break; 1006 case DDI_CTLOPS_INITCHILD: 1007 BnxeFcoeInitChild(pDev, (dev_info_t *) pArg); 1008 break; 1009 case DDI_CTLOPS_UNINITCHILD: 1010 BnxeFcoeUninitChild(pDev, (dev_info_t *) pArg); 1011 break; 1012 1013 default: 1014 1015 return (ddi_ctlops(pDev, pRDev, op, pArg, pResult)); 1016 } 1017 1018 return DDI_SUCCESS; 1019 } 1020 1021 1022 static int BnxeCbIoctl(dev_t dev, 1023 int cmd, 1024 intptr_t arg, 1025 int mode, 1026 cred_t * credp, 1027 int * rvalp) 1028 { 1029 BnxeBinding * pBinding = (BnxeBinding *)arg; 1030 um_device_t * pUM; 1031 1032 (void)dev; 1033 (void)mode; 1034 (void)credp; 1035 (void)rvalp; 1036 1037 if ((pBinding == NULL) || 1038 (pBinding->pCliDev == NULL) || 1039 (pBinding->pPrvDev == NULL)) 1040 { 1041 BnxeLogWarn(NULL, "Invalid binding arg to ioctl %d", cmd); 1042 return DDI_FAILURE; 1043 } 1044 1045 pUM = (um_device_t *)ddi_get_driver_private(pBinding->pPrvDev); 1046 1047 /* sanity checks */ 1048 1049 if (pBinding->version != BNXE_BINDING_VERSION) 1050 { 1051 BnxeLogWarn(NULL, "%s: Invalid binding version (0x%08x)", 1052 __func__, pBinding->version); 1053 return DDI_FAILURE; 1054 } 1055 1056 if ((pUM == NULL) || 1057 (pUM->fcoe.pDev != pBinding->pCliDev) || 1058 (pUM->pDev != pBinding->pPrvDev)) 1059 { 1060 BnxeLogWarn(NULL, "%s: dev_info_t match failed", __func__); 1061 return DDI_FAILURE; 1062 } 1063 1064 switch (cmd) 1065 { 1066 case BNXE_BIND_FCOE: 1067 1068 /* copy the binding struct and fill in the provider callback */ 1069 1070 BnxeLogInfo(pUM, "FCoE BIND start"); 1071 1072 if (!CLIENT_DEVI(pUM, LM_CLI_IDX_FCOE)) 1073 { 1074 BnxeLogWarn(pUM, "FCoE BIND when DEVI is offline!"); 1075 return DDI_FAILURE; 1076 } 1077 1078 if (CLIENT_BOUND(pUM, LM_CLI_IDX_FCOE)) 1079 { 1080 BnxeLogWarn(pUM, "FCoE BIND when alread bound!"); 1081 return DDI_FAILURE; 1082 } 1083 1084 pUM->fcoe.bind = *pBinding; 1085 1086 pUM->fcoe.bind.prvCtl = pBinding->prvCtl = BnxeFcoePrvCtl; 1087 pUM->fcoe.bind.prvTx = pBinding->prvTx = BnxeFcoePrvTx; 1088 pUM->fcoe.bind.prvPoll = pBinding->prvPoll = BnxeFcoePrvPoll; 1089 pUM->fcoe.bind.prvSendWqes = pBinding->prvSendWqes = BnxeFcoePrvSendWqes; 1090 pUM->fcoe.bind.prvMapMailboxq = pBinding->prvMapMailboxq = BnxeFcoePrvMapMailboxq; 1091 pUM->fcoe.bind.prvUnmapMailboxq = pBinding->prvUnmapMailboxq = BnxeFcoePrvUnmapMailboxq; 1092 1093 pUM->devParams.numRxDesc[LM_CLI_IDX_FCOE] = pBinding->numRxDescs; 1094 pUM->devParams.numTxDesc[LM_CLI_IDX_FCOE] = pBinding->numTxDescs; 1095 1096 pUM->lm_dev.params.l2_rx_desc_cnt[LM_CLI_IDX_FCOE] = pBinding->numRxDescs; 1097 BnxeInitBdCnts(pUM, LM_CLI_IDX_FCOE); 1098 1099 if (BnxeHwStartFCOE(pUM)) 1100 { 1101 return DDI_FAILURE; 1102 } 1103 1104 CLIENT_BIND_SET(pUM, LM_CLI_IDX_FCOE); 1105 lm_mcp_indicate_client_bind(&pUM->lm_dev, LM_CLI_IDX_FCOE); 1106 1107 BnxeLogInfo(pUM, "FCoE BIND done"); 1108 return DDI_SUCCESS; 1109 1110 case BNXE_UNBIND_FCOE: 1111 1112 /* clear the binding struct and stats */ 1113 1114 BnxeLogInfo(pUM, "FCoE UNBIND start"); 1115 1116 if (CLIENT_DEVI(pUM, LM_CLI_IDX_FCOE)) 1117 { 1118 BnxeLogWarn(pUM, "FCoE UNBIND when DEVI is online!"); 1119 return DDI_FAILURE; 1120 } 1121 1122 if (!CLIENT_BOUND(pUM, LM_CLI_IDX_FCOE)) 1123 { 1124 BnxeLogWarn(pUM, "FCoE UNBIND when not bound!"); 1125 return DDI_FAILURE; 1126 } 1127 1128 /* We must not detach until all packets held by fcoe are retrieved. */ 1129 if (!BnxeWaitForPacketsFromClient(pUM, LM_CLI_IDX_FCOE)) 1130 { 1131 return DDI_FAILURE; 1132 } 1133 1134 lm_mcp_indicate_client_unbind(&pUM->lm_dev, LM_CLI_IDX_FCOE); 1135 CLIENT_BIND_RESET(pUM, LM_CLI_IDX_FCOE); 1136 1137 BnxeHwStopFCOE(pUM); 1138 1139 memset(&pUM->fcoe.bind, 0, sizeof(pUM->fcoe.bind)); 1140 memset(&pUM->fcoe.stats, 0, sizeof(pUM->fcoe.stats)); 1141 1142 pBinding->prvCtl = NULL; 1143 pBinding->prvTx = NULL; 1144 pBinding->prvPoll = NULL; 1145 pBinding->prvSendWqes = NULL; 1146 pBinding->prvMapMailboxq = NULL; 1147 pBinding->prvUnmapMailboxq = NULL; 1148 1149 pUM->fcoe.pDev = NULL; /* sketchy? */ 1150 1151 BnxeLogInfo(pUM, "FCoE UNBIND done"); 1152 return DDI_SUCCESS; 1153 1154 default: 1155 1156 BnxeLogWarn(pUM, "Unknown ioctl %d", cmd); 1157 return DDI_FAILURE; 1158 } 1159 } 1160 1161 #ifndef ILLUMOS 1162 static struct bus_ops bnxe_bus_ops = 1163 { 1164 BUSO_REV, 1165 nullbusmap, /* bus_map */ 1166 NULL, /* bus_get_intrspec */ 1167 NULL, /* bus_add_intrspec */ 1168 NULL, /* bus_remove_intrspec */ 1169 i_ddi_map_fault, /* bus_map_fault */ 1170 ddi_dma_map, /* bus_dma_map */ 1171 ddi_dma_allochdl, /* bus_dma_allochdl */ 1172 ddi_dma_freehdl, /* bus_dma_freehdl */ 1173 ddi_dma_bindhdl, /* bus_dma_bindhdl */ 1174 ddi_dma_unbindhdl, /* bus_unbindhdl */ 1175 ddi_dma_flush, /* bus_dma_flush */ 1176 ddi_dma_win, /* bus_dma_win */ 1177 ddi_dma_mctl, /* bus_dma_ctl */ 1178 BnxeBusCtl, /* bus_ctl */ 1179 ddi_bus_prop_op, /* bus_prop_op */ 1180 NULL, /* bus_get_eventcookie */ 1181 NULL, /* bus_add_eventcall */ 1182 NULL, /* bus_remove_event */ 1183 NULL, /* bus_post_event */ 1184 NULL, /* bus_intr_ctl */ 1185 NULL, /* bus_config */ 1186 NULL, /* bus_unconfig */ 1187 NULL, /* bus_fm_init */ 1188 NULL, /* bus_fm_fini */ 1189 NULL, /* bus_fm_access_enter */ 1190 NULL, /* bus_fm_access_exit */ 1191 NULL, /* bus_power */ 1192 NULL 1193 }; 1194 #endif /* ILLUMOS */ 1195 1196 1197 static struct cb_ops bnxe_cb_ops = 1198 { 1199 nulldev, /* cb_open */ 1200 nulldev, /* cb_close */ 1201 nodev, /* cb_strategy */ 1202 nodev, /* cb_print */ 1203 nodev, /* cb_dump */ 1204 nodev, /* cb_read */ 1205 nodev, /* cb_write */ 1206 BnxeCbIoctl, /* cb_ioctl */ 1207 nodev, /* cb_devmap */ 1208 nodev, /* cb_mmap */ 1209 nodev, /* cb_segmap */ 1210 nochpoll, /* cb_chpoll */ 1211 ddi_prop_op, /* cb_prop_op */ 1212 NULL, /* cb_stream */ 1213 (int)(D_MP | D_64BIT), /* cb_flag */ 1214 CB_REV, /* cb_rev */ 1215 nodev, /* cb_aread */ 1216 nodev, /* cb_awrite */ 1217 }; 1218 1219 1220 #if (DEVO_REV > 3) 1221 1222 static struct dev_ops bnxe_dev_ops = 1223 { 1224 DEVO_REV, /* devo_rev */ 1225 0, /* devo_refcnt */ 1226 NULL, /* devo_getinfo */ 1227 nulldev, /* devo_identify */ 1228 nulldev, /* devo_probe */ 1229 BnxeAttach, /* devo_attach */ 1230 BnxeDetach, /* devo_detach */ 1231 nodev, /* devo_reset */ 1232 &bnxe_cb_ops, /* devo_cb_ops */ 1233 #ifndef ILLUMOS 1234 &bnxe_bus_ops, /* devo_bus_ops */ 1235 #else 1236 NULL, /* devo_bus_ops */ 1237 #endif 1238 NULL, /* devo_power */ 1239 BnxeQuiesce /* devo_quiesce */ 1240 }; 1241 1242 #else 1243 1244 static struct dev_ops bnxe_dev_ops = 1245 { 1246 DEVO_REV, /* devo_rev */ 1247 0, /* devo_refcnt */ 1248 NULL, /* devo_getinfo */ 1249 nulldev, /* devo_identify */ 1250 nulldev, /* devo_probe */ 1251 BnxeAttach, /* devo_attach */ 1252 BnxeDetach, /* devo_detach */ 1253 nodev, /* devo_reset */ 1254 &bnxe_cb_ops, /* devo_cb_ops */ 1255 &bnxe_bus_ops, /* devo_bus_ops */ 1256 NULL /* devo_power */ 1257 }; 1258 1259 #endif 1260 1261 1262 static struct modldrv bnxe_modldrv = 1263 { 1264 &mod_driverops, /* drv_modops (must be mod_driverops for drivers) */ 1265 BNXE_PRODUCT_INFO, /* drv_linkinfo (string displayed by modinfo) */ 1266 &bnxe_dev_ops /* drv_dev_ops */ 1267 }; 1268 1269 1270 static struct modlinkage bnxe_modlinkage = 1271 { 1272 MODREV_1, /* ml_rev */ 1273 { 1274 &bnxe_modldrv, /* ml_linkage */ 1275 NULL /* NULL termination */ 1276 } 1277 }; 1278 1279 1280 int _init(void) 1281 { 1282 int rc; 1283 1284 mac_init_ops(&bnxe_dev_ops, "bnxe"); 1285 1286 /* Install module information with O/S */ 1287 if ((rc = mod_install(&bnxe_modlinkage)) != DDI_SUCCESS) 1288 { 1289 BnxeLogWarn(NULL, "mod_install returned 0x%x", rc); 1290 mac_fini_ops(&bnxe_dev_ops); 1291 return rc; 1292 } 1293 1294 mutex_init(&bnxeLoaderMutex, NULL, MUTEX_DRIVER, NULL); 1295 bnxeNumPlumbed = 0; 1296 1297 BnxeLogInfo(NULL, "%s", BNXE_PRODUCT_BANNER); 1298 1299 return rc; 1300 } 1301 1302 1303 int _fini(void) 1304 { 1305 int rc; 1306 1307 if ((rc = mod_remove(&bnxe_modlinkage)) == DDI_SUCCESS) 1308 { 1309 mac_fini_ops(&bnxe_dev_ops); 1310 mutex_destroy(&bnxeLoaderMutex); 1311 1312 if (bnxeNumPlumbed > 0) 1313 { 1314 /* 1315 * This shouldn't be possible since modunload must only call _fini 1316 * when no instances are currently plumbed. 1317 */ 1318 BnxeLogWarn(NULL, "%d instances have not been unplumbed", bnxeNumPlumbed); 1319 } 1320 } 1321 1322 return rc; 1323 } 1324 1325 1326 int _info(struct modinfo * pModinfo) 1327 { 1328 return mod_info(&bnxe_modlinkage, pModinfo); 1329 } 1330 1331