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
BnxeInstance(void * pDev)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 */
BnxeDevName(void * pDev)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
BnxeChipName(um_device_t * pUM)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
BnxeProtoSupport(um_device_t * pUM,int proto)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
BnxeProtoFcoeAfex(um_device_t * pUM)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
BnxePciInit(um_device_t * pUM)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
BnxePciDestroy(um_device_t * pUM)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
BnxeBarMemDestroy(um_device_t * pUM)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
BnxeMutexInit(um_device_t * pUM)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
BnxeMutexDestroy(um_device_t * pUM)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
BnxeCheckAccHandle(ddi_acc_handle_t handle)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
BnxeCheckDmaHandle(ddi_dma_handle_t handle)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 */
BnxeFmErrorCb(dev_info_t * pDev,ddi_fm_error_t * err,const void * impl_data)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
BnxeFmInit(um_device_t * pUM)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
BnxeFmFini(um_device_t * pUM)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
BnxeFmErrorReport(um_device_t * pUM,char * detail)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
BnxeAttachDevice(um_device_t * pUM)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
BnxeDetachDevice(um_device_t * pUM)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
BnxeAttach(dev_info_t * pDev,ddi_attach_cmd_t cmd)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
BnxeDetach(dev_info_t * pDev,ddi_detach_cmd_t cmd)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
BnxeQuiesce(dev_info_t * pDev)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
BnxeFcoeInitChild(dev_info_t * pDev,dev_info_t * cDip)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
BnxeFcoeUninitChild(dev_info_t * pDev,dev_info_t * cDip)977 void BnxeFcoeUninitChild(dev_info_t * pDev,
978 dev_info_t * cDip)
979 {
980 ddi_set_name_addr(cDip, NULL);
981 }
982
983
BnxeBusCtl(dev_info_t * pDev,dev_info_t * pRDev,ddi_ctl_enum_t op,void * pArg,void * pResult)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
BnxeCbIoctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)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
_init(void)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
_fini(void)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
_info(struct modinfo * pModinfo)1326 int _info(struct modinfo * pModinfo)
1327 {
1328 return mod_info(&bnxe_modlinkage, pModinfo);
1329 }
1330
1331