xref: /illumos-gate/usr/src/uts/common/io/bnx/bnxgldv3.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
1 /*
2  * Copyright 2014-2017 Cavium, Inc.
3  * The contents of this file are subject to the terms of the Common Development
4  * and Distribution License, v.1,  (the "License").
5  *
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the License at available
9  * at http://opensource.org/licenses/CDDL-1.0
10  *
11  * See the License for the specific language governing permissions and
12  * limitations under the License.
13  */
14 
15 /*
16  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
17  * Copyright (c) 2019, Joyent, Inc.
18  */
19 
20 #include "bnxgld.h"
21 #include "bnxhwi.h"
22 #include "bnxsnd.h"
23 #include "bnxrcv.h"
24 #include "bnxcfg.h"
25 
26 #include <sys/mac_provider.h>
27 #include <sys/mac_ether.h>
28 #include <sys/dlpi.h>
29 #include <sys/policy.h>
30 
31 /*
32  * Name:    bnx_m_start
33  *
34  * Input:   ptr to driver device structure.
35  *
36  * Return:  DDI_SUCCESS or DDI_FAILURE
37  *
38  * Description:
39  *          This routine is called by GLD to enable device for
40  *          packet reception and enable interrupts.
41  */
42 static int
43 bnx_m_start(void *arg)
44 {
45 	int rc;
46 	um_device_t *umdevice;
47 
48 	umdevice = (um_device_t *)arg;
49 
50 	mutex_enter(&umdevice->os_param.gld_mutex);
51 
52 	if (umdevice->dev_start == B_TRUE) {
53 		/* We're already started.  Success! */
54 		rc = 0;
55 		goto done;
56 	}
57 
58 	/* Always report the initial link state as unknown. */
59 	bnx_gld_link(umdevice, LINK_STATE_UNKNOWN);
60 
61 	umdevice->link_updates_ok = B_TRUE;
62 
63 	if (bnx_hdwr_acquire(umdevice)) {
64 		rc = EIO;
65 		goto done;
66 	}
67 
68 	umdevice->dev_start = B_TRUE;
69 
70 	rc = 0;
71 
72 done:
73 	mutex_exit(&umdevice->os_param.gld_mutex);
74 
75 	return (rc);
76 }
77 
78 /*
79  * Name:    bnx_m_stop
80  *
81  * Input:   ptr to driver device structure.
82  *
83  * Return:  DDI_SUCCESS or DDI_FAILURE
84  *
85  * Description:
86  *          This routine stops packet reception by clearing RX MASK
87  *          register. Also interrupts are disabled for this device.
88  */
89 static void
90 bnx_m_stop(void *arg)
91 {
92 	um_device_t *umdevice;
93 
94 	umdevice = (um_device_t *)arg;
95 
96 	mutex_enter(&umdevice->os_param.gld_mutex);
97 
98 	if (umdevice->dev_start == B_TRUE) {
99 		umdevice->dev_start = B_FALSE;
100 		umdevice->link_updates_ok = B_FALSE;
101 
102 		bnx_hdwr_release(umdevice);
103 
104 		/* Report the link state back to unknown. */
105 		bnx_gld_link(umdevice, LINK_STATE_UNKNOWN);
106 
107 		umdevice->dev_var.indLink   = 0;
108 		umdevice->dev_var.indMedium = 0;
109 	}
110 
111 	mutex_exit(&umdevice->os_param.gld_mutex);
112 }
113 
114 
115 
116 /*
117  * Name:    bnx_m_unicast
118  *
119  * Input:   ptr to driver device structure,
120  *          pointer to buffer containing MAC address.
121  *
122  * Return:  DDI_SUCCESS or DDI_FAILURE
123  *
124  * Description:
125  */
126 static int
127 bnx_m_unicast(void *arg, const uint8_t *macaddr)
128 {
129 	int rc;
130 	um_device_t *umdevice;
131 	lm_device_t *lmdevice;
132 
133 	umdevice = (um_device_t *)arg;
134 	lmdevice = &(umdevice->lm_dev);
135 
136 	mutex_enter(&umdevice->os_param.gld_mutex);
137 
138 	/* Validate MAC address */
139 	if (IS_ETH_MULTICAST(macaddr)) {
140 		cmn_err(CE_WARN, "%s: Attempt to program a multicast / "
141 		    "broadcast address as a MAC address.", umdevice->dev_name);
142 		rc = EINVAL;
143 		goto done;
144 	}
145 
146 	if (umdevice->dev_start == B_TRUE) {
147 		if (lm_set_mac_addr(lmdevice, 0,
148 		    &(lmdevice->params.mac_addr[0])) != LM_STATUS_SUCCESS) {
149 			cmn_err(CE_WARN, "%s: failed to program MAC address.",
150 			    umdevice->dev_name);
151 			rc = EIO;
152 			goto done;
153 		}
154 	}
155 
156 	bcopy(macaddr, &(lmdevice->params.mac_addr[0]), ETHERADDRL);
157 
158 	rc = 0;
159 
160 done:
161 	mutex_exit(&umdevice->os_param.gld_mutex);
162 
163 	return (rc);
164 }
165 
166 static int
167 bnx_mc_add(um_device_t *umdevice, const uint8_t *const mc_addr)
168 {
169 	int rc;
170 	int index;
171 	lm_status_t   lmstatus;
172 	lm_device_t *lmdevice;
173 
174 	lmdevice = &(umdevice->lm_dev);
175 
176 	index = bnx_find_mchash_collision(&(lmdevice->mc_table), mc_addr);
177 	if (index == -1) {
178 		lmstatus = lm_add_mc(lmdevice, (u8_t *)mc_addr);
179 		if (lmstatus == LM_STATUS_SUCCESS) {
180 			umdevice->dev_var.rx_filter_mask |=
181 			    LM_RX_MASK_ACCEPT_MULTICAST;
182 			rc = 0;
183 		} else {
184 			rc = ENOMEM;
185 		}
186 	} else {
187 		lmdevice->mc_table.addr_arr[index].ref_cnt++;
188 		rc = 0;
189 	}
190 
191 	return (rc);
192 }
193 
194 static int
195 bnx_mc_del(um_device_t *umdevice, const uint8_t *const mc_addr)
196 {
197 	int rc;
198 	int index;
199 	lm_status_t lmstatus;
200 	lm_device_t *lmdevice;
201 
202 	lmdevice = &(umdevice->lm_dev);
203 
204 	index = bnx_find_mchash_collision(&(lmdevice->mc_table), mc_addr);
205 	if (index == -1) {
206 		rc = ENXIO;
207 	} else {
208 		lmstatus = lm_del_mc(lmdevice,
209 		    lmdevice->mc_table.addr_arr[index].mc_addr);
210 		if (lmstatus == LM_STATUS_SUCCESS) {
211 			if (lmdevice->mc_table.entry_cnt == 0) {
212 				umdevice->dev_var.rx_filter_mask &=
213 				    ~LM_RX_MASK_ACCEPT_MULTICAST;
214 			}
215 
216 			rc = 0;
217 		} else {
218 			rc = ENXIO;
219 		}
220 	}
221 
222 	return (rc);
223 }
224 
225 
226 
227 /*
228  * Name:    bnx_m_multicast
229  *
230  * Input:   ptr to driver device structure,
231  *          boolean describing whether to enable or disable this address,
232  *          pointer to buffer containing multicast address.
233  *
234  * Return:  DDI_SUCCESS or DDI_FAILURE
235  *
236  * Description:
237  *          This function is used to enable or disable multicast packet
238  *          reception for particular multicast addresses.
239  */
240 static int
241 bnx_m_multicast(void * arg, boolean_t multiflag, const uint8_t *multicastaddr)
242 {
243 	um_device_t *umdevice;
244 	int rc;
245 
246 	umdevice = (um_device_t *)arg;
247 
248 	mutex_enter(&umdevice->os_param.gld_mutex);
249 
250 	if (umdevice->dev_start != B_TRUE) {
251 		rc = EAGAIN;
252 		goto done;
253 	}
254 
255 	switch (multiflag) {
256 		case B_TRUE:
257 			rc = bnx_mc_add(umdevice, multicastaddr);
258 			break;
259 
260 		case B_FALSE:
261 			rc = bnx_mc_del(umdevice, multicastaddr);
262 			break;
263 
264 		default:
265 			rc = EINVAL;
266 			break;
267 	}
268 
269 done:
270 	mutex_exit(&umdevice->os_param.gld_mutex);
271 
272 	return (rc);
273 }
274 
275 
276 
277 /*
278  * Name:    bnx_m_promiscuous
279  *
280  * Input:   ptr to driver device structure,
281  *          boolean describing whether to enable or disable promiscuous mode.
282  *
283  * Return:  DDI_SUCCESS or DDI_FAILURE
284  *
285  * Description:
286  *          This function enables promiscuous mode for this device.
287  *		'flags' argument determines the type of mode being set,
288  *		"PROMISC_PHY" enables reception of all packet types including
289  *		bad/error packets. "PROMISC_MULTI" mode will enable all
290  *		multicast packets, unicasts and broadcast packets to be
291  *		received. "PROMISC_NONE" will enable only broadcast and
292  *		unicast packets.
293  */
294 static int
295 bnx_m_promiscuous(void *arg, boolean_t promiscflag)
296 {
297 	int rc;
298 	um_device_t *umdevice;
299 
300 	umdevice = (um_device_t *)arg;
301 
302 	mutex_enter(&umdevice->os_param.gld_mutex);
303 
304 	if (umdevice->dev_start != B_TRUE) {
305 		rc = EAGAIN;
306 		goto done;
307 	}
308 
309 	switch (promiscflag) {
310 		case B_TRUE:
311 			umdevice->dev_var.rx_filter_mask |=
312 			    LM_RX_MASK_PROMISCUOUS_MODE;
313 			break;
314 
315 		case B_FALSE:
316 			umdevice->dev_var.rx_filter_mask &=
317 			    ~LM_RX_MASK_PROMISCUOUS_MODE;
318 			break;
319 
320 		default:
321 			rc = EINVAL;
322 			goto done;
323 	}
324 
325 	(void) lm_set_rx_mask(&(umdevice->lm_dev), RX_FILTER_USER_IDX0,
326 	    umdevice->dev_var.rx_filter_mask);
327 
328 	rc = 0;
329 
330 done:
331 	mutex_exit(&umdevice->os_param.gld_mutex);
332 
333 	return (rc);
334 }
335 
336 
337 static mblk_t *
338 bnx_m_tx(void *arg, mblk_t *mp)
339 {
340 	int rc;
341 	mblk_t *nmp;
342 	um_device_t *umdevice;
343 
344 	umdevice = (um_device_t *)arg;
345 
346 	rw_enter(&umdevice->os_param.gld_snd_mutex, RW_READER);
347 
348 	if (umdevice->dev_start != B_TRUE ||
349 	    umdevice->nddcfg.link_speed == 0) {
350 		freemsgchain(mp);
351 		mp = NULL;
352 		goto done;
353 	}
354 
355 	nmp = NULL;
356 
357 	while (mp) {
358 		/* Save the next pointer, in case we do double copy. */
359 		nmp = mp->b_next;
360 		mp->b_next = NULL;
361 
362 		rc = bnx_xmit_ring_xmit_mblk(umdevice, 0, mp);
363 
364 		if (rc == BNX_SEND_GOODXMIT) {
365 			mp = nmp;
366 			continue;
367 		}
368 
369 		if (rc == BNX_SEND_DEFERPKT)
370 			mp = nmp;
371 		else
372 			mp->b_next = nmp;
373 
374 		break;
375 	}
376 
377 done:
378 	rw_exit(&umdevice->os_param.gld_snd_mutex);
379 
380 	return (mp);
381 }
382 
383 
384 static u64_t
385 shift_left32(u32_t val)
386 {
387 	lm_u64_t tmp;
388 
389 	/* FIXME -- Get rid of shift_left32() */
390 
391 	tmp.as_u32.low = 0;
392 	tmp.as_u32.high = val;
393 
394 	return (tmp.as_u64);
395 }
396 
397 
398 
399 /*
400  * Name:    bnx_m_stats
401  *
402  * Input:   ptr to mac info structure, ptr to gld_stats struct
403  *
404  * Return:  DDI_SUCCESS or DDI_FAILURE
405  *
406  * Description: bnx_m_stats() populates gld_stats structure elements
407  *              from latest data from statistic block.
408  */
409 static int
410 bnx_m_stats(void * arg, uint_t stat, uint64_t *val)
411 {
412 	int rc;
413 	um_device_t *umdevice;
414 	lm_device_t *lmdevice;
415 	const bnx_lnk_cfg_t *linkconf;
416 
417 	umdevice = (um_device_t *)arg;
418 
419 	if (umdevice == NULL || val == NULL) {
420 		return (EINVAL);
421 	}
422 
423 	lmdevice = &(umdevice->lm_dev);
424 
425 	/* FIXME -- Fix STATS collections */
426 
427 	if (umdevice->dev_var.isfiber) {
428 		linkconf = &bnx_serdes_config;
429 	} else {
430 		linkconf = &bnx_copper_config;
431 	}
432 
433 	mutex_enter(&umdevice->os_param.gld_mutex);
434 
435 	if (umdevice->dev_start != B_TRUE) {
436 		rc = EAGAIN;
437 		goto done;
438 	}
439 
440 	*val = 0;
441 	switch (stat) {
442 	case MAC_STAT_IFSPEED:
443 		*val = umdevice->nddcfg.link_speed * 1000000ull;
444 		break;
445 	case MAC_STAT_MULTIRCV:
446 		*val += shift_left32(
447 		    lmdevice->vars.stats_virt->stat_IfHCInMulticastPkts_hi);
448 		*val +=
449 		    lmdevice->vars.stats_virt->stat_IfHCInMulticastPkts_lo;
450 		break;
451 	case MAC_STAT_BRDCSTRCV:
452 		*val += shift_left32(
453 		    lmdevice->vars.stats_virt->stat_IfHCInBroadcastPkts_hi);
454 		*val +=
455 		    lmdevice->vars.stats_virt->stat_IfHCInBroadcastPkts_lo;
456 		break;
457 	case MAC_STAT_MULTIXMT:
458 		*val += shift_left32(
459 		    lmdevice->vars.stats_virt->stat_IfHCOutMulticastPkts_hi);
460 		*val +=
461 		    lmdevice->vars.stats_virt->stat_IfHCOutMulticastPkts_lo;
462 		break;
463 	case MAC_STAT_BRDCSTXMT:
464 		*val += shift_left32(
465 		    lmdevice->vars.stats_virt->stat_IfHCOutBroadcastPkts_hi);
466 		*val +=
467 		    lmdevice->vars.stats_virt->stat_IfHCOutBroadcastPkts_lo;
468 		break;
469 	case MAC_STAT_NORCVBUF:
470 		*val = lmdevice->vars.stats_virt->stat_IfInMBUFDiscards;
471 		break;
472 	case ETHER_STAT_MACRCV_ERRORS:
473 	case MAC_STAT_IERRORS:
474 		*val = lmdevice->vars.stats_virt->stat_Dot3StatsFCSErrors +
475 		    lmdevice->vars.stats_virt->stat_Dot3StatsAlignmentErrors +
476 		    lmdevice->vars.stats_virt->stat_EtherStatsUndersizePkts +
477 		    lmdevice->vars.stats_virt->stat_EtherStatsOverrsizePkts;
478 		break;
479 	case MAC_STAT_OERRORS:
480 		*val = lmdevice->vars.stats_virt->
481 		    stat_emac_tx_stat_dot3statsinternalmactransmiterrors;
482 		break;
483 	case MAC_STAT_COLLISIONS:
484 		*val = lmdevice->vars.stats_virt->stat_EtherStatsCollisions;
485 		break;
486 	case MAC_STAT_RBYTES:
487 		*val += shift_left32(
488 		    lmdevice->vars.stats_virt->stat_IfHCInOctets_hi);
489 		*val +=
490 		    lmdevice->vars.stats_virt->stat_IfHCInOctets_lo;
491 		break;
492 	case MAC_STAT_IPACKETS:
493 		*val += shift_left32(lmdevice->vars.stats_virt->
494 		    stat_IfHCInUcastPkts_hi);
495 		*val += lmdevice->vars.stats_virt->stat_IfHCInUcastPkts_lo;
496 
497 		*val += shift_left32(lmdevice->vars.stats_virt->
498 		    stat_IfHCInMulticastPkts_hi);
499 		*val += lmdevice->vars.stats_virt->stat_IfHCInMulticastPkts_lo;
500 
501 		*val += shift_left32(lmdevice->vars.stats_virt->
502 		    stat_IfHCInBroadcastPkts_hi);
503 		*val += lmdevice->vars.stats_virt->stat_IfHCInBroadcastPkts_lo;
504 		break;
505 	case MAC_STAT_OBYTES:
506 		*val += shift_left32(
507 		    lmdevice->vars.stats_virt->stat_IfHCOutOctets_hi);
508 		*val +=
509 		    lmdevice->vars.stats_virt->stat_IfHCOutOctets_lo;
510 		break;
511 	case MAC_STAT_OPACKETS:
512 		*val += shift_left32(lmdevice->vars.stats_virt->
513 		    stat_IfHCOutUcastPkts_hi);
514 		*val += lmdevice->vars.stats_virt->stat_IfHCOutUcastPkts_lo;
515 
516 		*val += shift_left32(lmdevice->vars.stats_virt->
517 		    stat_IfHCOutMulticastPkts_hi);
518 		*val += lmdevice->vars.stats_virt->stat_IfHCOutMulticastPkts_lo;
519 
520 		*val += shift_left32(lmdevice->vars.stats_virt->
521 		    stat_IfHCOutBroadcastPkts_hi);
522 		*val += lmdevice->vars.stats_virt->stat_IfHCOutBroadcastPkts_lo;
523 		break;
524 	case ETHER_STAT_ALIGN_ERRORS:
525 		*val = lmdevice->vars.stats_virt->stat_Dot3StatsAlignmentErrors;
526 		break;
527 	case ETHER_STAT_FCS_ERRORS:
528 		*val = lmdevice->vars.stats_virt->stat_Dot3StatsFCSErrors;
529 		break;
530 	case ETHER_STAT_FIRST_COLLISIONS:
531 		*val = lmdevice->vars.stats_virt->
532 		    stat_Dot3StatsSingleCollisionFrames;
533 		break;
534 	case ETHER_STAT_MULTI_COLLISIONS:
535 		*val = lmdevice->vars.stats_virt->
536 		    stat_Dot3StatsMultipleCollisionFrames;
537 		break;
538 	case ETHER_STAT_DEFER_XMTS:
539 		*val = lmdevice->vars.stats_virt->
540 		    stat_Dot3StatsDeferredTransmissions;
541 		break;
542 	case ETHER_STAT_TX_LATE_COLLISIONS:
543 		*val = lmdevice->vars.stats_virt->
544 		    stat_Dot3StatsLateCollisions;
545 		break;
546 	case ETHER_STAT_EX_COLLISIONS:
547 		*val = lmdevice->vars.stats_virt->
548 		    stat_Dot3StatsExcessiveCollisions;
549 		break;
550 	case ETHER_STAT_MACXMT_ERRORS:
551 		*val = lmdevice->vars.stats_virt->
552 		    stat_emac_tx_stat_dot3statsinternalmactransmiterrors;
553 		break;
554 	case ETHER_STAT_CARRIER_ERRORS:
555 		*val = lmdevice->vars.stats_virt->
556 		    stat_Dot3StatsCarrierSenseErrors;
557 		break;
558 	case ETHER_STAT_TOOLONG_ERRORS:
559 		*val = lmdevice->vars.stats_virt->
560 		    stat_EtherStatsOverrsizePkts;
561 		break;
562 #if (MAC_VERSION > 1)
563 	case ETHER_STAT_TOOSHORT_ERRORS:
564 		*val = lmdevice->vars.stats_virt->
565 		    stat_EtherStatsUndersizePkts;
566 		break;
567 #endif
568 	case ETHER_STAT_XCVR_ADDR:
569 		*val = lmdevice->params.phy_addr;
570 		break;
571 	case ETHER_STAT_XCVR_ID:
572 		*val = lmdevice->hw_info.phy_id;
573 		break;
574 	case ETHER_STAT_XCVR_INUSE:
575 		switch (umdevice->nddcfg.link_speed) {
576 		case 1000:
577 			*val = (umdevice->dev_var.isfiber) ?
578 			    XCVR_1000X : XCVR_1000T;
579 			break;
580 		case 100:
581 			*val = XCVR_100X;
582 			break;
583 		case 10:
584 			*val = XCVR_10;
585 			break;
586 		default:
587 			*val = XCVR_NONE;
588 			break;
589 		}
590 		break;
591 	case ETHER_STAT_CAP_1000FDX:
592 		*val = 1;
593 		break;
594 	case ETHER_STAT_CAP_1000HDX:
595 		*val = linkconf->param_1000hdx;
596 		break;
597 	case ETHER_STAT_CAP_100FDX:
598 		*val = linkconf->param_100fdx;
599 		break;
600 	case ETHER_STAT_CAP_100HDX:
601 		*val = linkconf->param_100hdx;
602 		break;
603 	case ETHER_STAT_CAP_10FDX:
604 		*val = linkconf->param_10fdx;
605 		break;
606 	case ETHER_STAT_CAP_10HDX:
607 		*val = linkconf->param_10hdx;
608 		break;
609 	case ETHER_STAT_CAP_ASMPAUSE:
610 		*val = 1;
611 		break;
612 	case ETHER_STAT_CAP_PAUSE:
613 		*val = 1;
614 		break;
615 	case ETHER_STAT_CAP_AUTONEG:
616 		*val = 1;
617 		break;
618 #if (MAC_VERSION > 1)
619 	case ETHER_STAT_CAP_REMFAULT:
620 		*val = 1;
621 		break;
622 #endif
623 	case ETHER_STAT_ADV_CAP_1000FDX:
624 		*val = umdevice->curcfg.lnkcfg.param_1000fdx;
625 		break;
626 	case ETHER_STAT_ADV_CAP_1000HDX:
627 		*val = umdevice->curcfg.lnkcfg.param_1000hdx;
628 		break;
629 	case ETHER_STAT_ADV_CAP_100FDX:
630 		*val = umdevice->curcfg.lnkcfg.param_100fdx;
631 		break;
632 	case ETHER_STAT_ADV_CAP_100HDX:
633 		*val = umdevice->curcfg.lnkcfg.param_100hdx;
634 		break;
635 	case ETHER_STAT_ADV_CAP_10FDX:
636 		*val = umdevice->curcfg.lnkcfg.param_10fdx;
637 		break;
638 	case ETHER_STAT_ADV_CAP_10HDX:
639 		*val = umdevice->curcfg.lnkcfg.param_10hdx;
640 		break;
641 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
642 		*val = 1;
643 		break;
644 	case ETHER_STAT_ADV_CAP_PAUSE:
645 		*val = 1;
646 		break;
647 	case ETHER_STAT_ADV_CAP_AUTONEG:
648 		*val = umdevice->curcfg.lnkcfg.link_autoneg;
649 		break;
650 #if (MAC_VERSION > 1)
651 	case ETHER_STAT_ADV_REMFAULT:
652 		*val = 1;
653 		break;
654 #endif
655 	case ETHER_STAT_LP_CAP_1000FDX:
656 		*val = umdevice->remote.param_1000fdx;
657 		break;
658 	case ETHER_STAT_LP_CAP_1000HDX:
659 		*val = umdevice->remote.param_1000hdx;
660 		break;
661 	case ETHER_STAT_LP_CAP_100FDX:
662 		*val = umdevice->remote.param_100fdx;
663 		break;
664 	case ETHER_STAT_LP_CAP_100HDX:
665 		*val = umdevice->remote.param_100hdx;
666 		break;
667 	case ETHER_STAT_LP_CAP_10FDX:
668 		*val = umdevice->remote.param_10fdx;
669 		break;
670 	case ETHER_STAT_LP_CAP_10HDX:
671 		*val = umdevice->remote.param_10hdx;
672 		break;
673 	case ETHER_STAT_LP_CAP_ASMPAUSE:
674 		/* FIXME -- Implement LP_ASYM_PAUSE stat */
675 		break;
676 	case ETHER_STAT_LP_CAP_PAUSE:
677 		/* FIXME -- Implement LP_PAUSE stat */
678 		break;
679 	case ETHER_STAT_LP_CAP_AUTONEG:
680 		*val = umdevice->remote.link_autoneg;
681 		break;
682 #if (MAC_VERSION > 1)
683 	case ETHER_STAT_LP_REMFAULT:
684 		/* FIXME -- Implement LP_REMFAULT stat */
685 		break;
686 #endif
687 	case ETHER_STAT_LINK_ASMPAUSE:
688 		/* FIXME -- Implement ASMPAUSE stat */
689 		break;
690 	case ETHER_STAT_LINK_PAUSE:
691 		/* FIXME -- Implement PAUSE stat */
692 		break;
693 	case ETHER_STAT_LINK_AUTONEG:
694 		*val = umdevice->curcfg.lnkcfg.link_autoneg;
695 		break;
696 	case ETHER_STAT_LINK_DUPLEX:
697 		*val = umdevice->nddcfg.link_duplex == B_TRUE ?
698 		    LINK_DUPLEX_FULL: LINK_DUPLEX_HALF;
699 		break;
700 	default:
701 		rc = ENOTSUP;
702 	}
703 
704 	rc = 0;
705 
706 done:
707 	mutex_exit(&umdevice->os_param.gld_mutex);
708 
709 	return (rc);
710 }
711 
712 static boolean_t
713 bnx_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
714 {
715 	um_device_t *umdevice;
716 
717 	umdevice = (um_device_t *)arg;
718 
719 	switch (cap) {
720 	case MAC_CAPAB_HCKSUM: {
721 		uint32_t *txflags = cap_data;
722 
723 		*txflags = 0;
724 
725 		if (umdevice->dev_var.enabled_oflds &
726 		    (LM_OFFLOAD_TX_IP_CKSUM | LM_OFFLOAD_RX_IP_CKSUM)) {
727 			*txflags |= HCKSUM_IPHDRCKSUM;
728 		}
729 
730 		if (umdevice->dev_var.enabled_oflds &
731 		    (LM_OFFLOAD_TX_TCP_CKSUM | LM_OFFLOAD_TX_UDP_CKSUM |
732 		    LM_OFFLOAD_RX_TCP_CKSUM | LM_OFFLOAD_RX_UDP_CKSUM)) {
733 			*txflags |= HCKSUM_INET_FULL_V4;
734 		}
735 		break;
736 	}
737 	default:
738 		return (B_FALSE);
739 	}
740 
741 	return (B_TRUE);
742 }
743 
744 static int
745 bnx_refresh_rx_tx_pkts(um_device_t *umdevice)
746 {
747 	if (umdevice->os_param.active_resc_flag & DRV_RESOURCE_HDWR_REGISTER) {
748 		bnx_hdwr_fini(umdevice);
749 		/*
750 		 * Initialize the adapter resource.  Mainly allocating memory
751 		 * needed by the driver, such as packet descriptors, shared
752 		 * memory, etc.
753 		 */
754 		if (lm_init_resc(&(umdevice->lm_dev)) != LM_STATUS_SUCCESS) {
755 			return (EIO);
756 		}
757 
758 		if (bnx_txpkts_init(umdevice)) {
759 			return (EIO);
760 		}
761 
762 		if (bnx_rxpkts_init(umdevice)) {
763 			return (EIO);
764 		}
765 	}
766 	return (0);
767 }
768 
769 static int
770 bnx_set_priv_prop(um_device_t *umdevice, const char *pr_name,
771     uint_t pr_valsize, const void *pr_val)
772 {
773 	boolean_t refresh = B_FALSE;
774 	long result;
775 	int err = 0;
776 
777 	if (strcmp(pr_name, "_adv_2500fdx_cap") == 0) {
778 		if (lm_get_medium(&umdevice->lm_dev) != LM_MEDIUM_TYPE_FIBER) {
779 			return (ENOTSUP);
780 		}
781 		if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) {
782 			return (EINVAL);
783 		}
784 		if (result != 1 && result != 0) {
785 			return (EINVAL);
786 		}
787 		if (umdevice->hwinit.lnkcfg.param_2500fdx != (uint32_t)result) {
788 			umdevice->hwinit.lnkcfg.param_2500fdx =
789 			    (uint32_t)result;
790 			umdevice->curcfg.lnkcfg.param_2500fdx =
791 			    (uint32_t)result;
792 			bnx_update_phy(umdevice);
793 		}
794 	} else if (strcmp(pr_name, "_checksum") == 0) {
795 		if (umdevice->dev_start == B_TRUE) {
796 			return (EBUSY);
797 		}
798 		if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) {
799 			return (EINVAL);
800 		}
801 		switch (result) {
802 			case USER_OPTION_CKSUM_TX_ONLY:
803 				umdevice->dev_var.enabled_oflds =
804 				    LM_OFFLOAD_TX_IP_CKSUM |
805 				    LM_OFFLOAD_TX_TCP_CKSUM |
806 				    LM_OFFLOAD_TX_UDP_CKSUM;
807 				break;
808 
809 			case USER_OPTION_CKSUM_RX_ONLY:
810 				umdevice->dev_var.enabled_oflds =
811 				    LM_OFFLOAD_RX_IP_CKSUM |
812 				    LM_OFFLOAD_RX_TCP_CKSUM |
813 				    LM_OFFLOAD_RX_UDP_CKSUM;
814 				break;
815 
816 			case USER_OPTION_CKSUM_TX_RX:
817 				umdevice->dev_var.enabled_oflds =
818 				    LM_OFFLOAD_TX_IP_CKSUM |
819 				    LM_OFFLOAD_RX_IP_CKSUM |
820 				    LM_OFFLOAD_TX_TCP_CKSUM |
821 				    LM_OFFLOAD_RX_TCP_CKSUM |
822 				    LM_OFFLOAD_TX_UDP_CKSUM |
823 				    LM_OFFLOAD_RX_UDP_CKSUM;
824 				break;
825 
826 			case USER_OPTION_CKSUM_NONE:
827 				umdevice->dev_var.enabled_oflds =
828 				    LM_OFFLOAD_NONE;
829 				break;
830 
831 			default:
832 				return (EINVAL);
833 		}
834 	} else if (strcmp(pr_name, "_tx_descriptor_count") == 0) {
835 		if (umdevice->dev_start == B_TRUE) {
836 			return (EBUSY);
837 		}
838 		if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) {
839 			return (EINVAL);
840 		}
841 		if (result < USER_OPTION_TX_DESC_CNT_MIN ||
842 		    result > USER_OPTION_TX_DESC_CNT_MAX) {
843 			return (EINVAL);
844 		}
845 		_TX_QINFO(umdevice, 0).desc_cnt = result;
846 		umdevice->lm_dev.params.l2_tx_bd_page_cnt[0] =
847 		    result / MAX_BD_PER_PAGE;
848 		if (result % MAX_BD_PER_PAGE) {
849 			umdevice->lm_dev.params.l2_tx_bd_page_cnt[0]++;
850 		}
851 		if (umdevice->lm_dev.params.l2_tx_bd_page_cnt[0] > 127) {
852 			umdevice->lm_dev.params.l2_tx_bd_page_cnt[0] = 127;
853 		}
854 		refresh = B_TRUE;
855 	} else if (strcmp(pr_name, "_rx_descriptor_count") == 0) {
856 		if (umdevice->dev_start == B_TRUE) {
857 			return (EBUSY);
858 		}
859 		if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) {
860 			return (EINVAL);
861 		}
862 		if (result < USER_OPTION_RX_DESC_CNT_MIN ||
863 		    result > USER_OPTION_RX_DESC_CNT_MAX) {
864 			return (EINVAL);
865 		}
866 		umdevice->lm_dev.params.l2_rx_desc_cnt[0] = result;
867 		result = (result * BNX_RECV_MAX_FRAGS) / MAX_BD_PER_PAGE;
868 		umdevice->lm_dev.params.l2_rx_bd_page_cnt[0] = result;
869 		if (result % MAX_BD_PER_PAGE) {
870 			umdevice->lm_dev.params.l2_rx_bd_page_cnt[0]++;
871 		}
872 		refresh = B_TRUE;
873 	}
874 #if 0
875 	/* Initialized by init_hc() */
876 	else if (strcmp(pr_name, "_tx_coalesce_ticks") == 0) {
877 		if (umdevice->dev_start == B_TRUE) {
878 			return (EBUSY);
879 		}
880 		if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) {
881 			return (EINVAL);
882 		}
883 		if (result < USER_OPTION_TICKS_MIN ||
884 		    result > USER_OPTION_TICKS_MAX) {
885 			return (EINVAL);
886 		}
887 		umdevice->lm_dev.params.tx_ticks = result;
888 	} else if (strcmp(pr_name, "_tx_coalesce_ticks_int") == 0) {
889 		if (umdevice->dev_start == B_TRUE) {
890 			return (EBUSY);
891 		}
892 		if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) {
893 			return (EINVAL);
894 		}
895 		if (result < USER_OPTION_TICKS_INT_MIN ||
896 		    result > USER_OPTION_TICKS_INT_MAX) {
897 			return (EINVAL);
898 		}
899 		umdevice->lm_dev.params.tx_ticks_int = result;
900 	} else if (strcmp(pr_name, "_rx_coalesce_ticks") == 0) {
901 		if (umdevice->dev_start == B_TRUE) {
902 			return (EBUSY);
903 		}
904 		if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) {
905 			return (EINVAL);
906 		}
907 		if (result < USER_OPTION_TICKS_MIN ||
908 		    result > USER_OPTION_TICKS_MAX) {
909 			return (EINVAL);
910 		}
911 		umdevice->lm_dev.params.rx_ticks = result;
912 	} else if (strcmp(pr_name, "_rx_coalesce_ticks_int") == 0) {
913 		if (umdevice->dev_start == B_TRUE) {
914 			return (EBUSY);
915 		}
916 		if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) {
917 			return (EINVAL);
918 		}
919 		if (result < USER_OPTION_TICKS_INT_MIN ||
920 		    result > USER_OPTION_TICKS_INT_MAX) {
921 			return (EINVAL);
922 		}
923 		umdevice->lm_dev.params.rx_ticks_int = result;
924 	} else if (strcmp(pr_name, "_tx_coalesce_frames") == 0) {
925 		if (umdevice->dev_start == B_TRUE) {
926 			return (EBUSY);
927 		}
928 		if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) {
929 			return (EINVAL);
930 		}
931 		if (result < USER_OPTION_FRAMES_MIN ||
932 		    result > USER_OPTION_FRAMES_MAX) {
933 			return (EINVAL);
934 		}
935 		umdevice->lm_dev.params.tx_quick_cons_trip = result;
936 	} else if (strcmp(pr_name, "_tx_coalesce_frames_int") == 0) {
937 		if (umdevice->dev_start == B_TRUE) {
938 			return (EBUSY);
939 		}
940 		if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) {
941 			return (EINVAL);
942 		}
943 		if (result < USER_OPTION_FRAMES_MIN ||
944 		    result > USER_OPTION_FRAMES_MAX) {
945 			return (EINVAL);
946 		}
947 		umdevice->lm_dev.params.tx_quick_cons_trip_int = result;
948 	} else if (strcmp(pr_name, "_rx_coalesce_frames") == 0) {
949 		if (umdevice->dev_start == B_TRUE) {
950 			return (EBUSY);
951 		}
952 		if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) {
953 			return (EINVAL);
954 		}
955 		if (result < USER_OPTION_FRAMES_MIN ||
956 		    result > USER_OPTION_FRAMES_MAX) {
957 			return (EINVAL);
958 		}
959 		umdevice->lm_dev.params.rx_quick_cons_trip = result;
960 	} else if (strcmp(pr_name, "_rx_coalesce_frames_int") == 0) {
961 		if (umdevice->dev_start == B_TRUE) {
962 			return (EBUSY);
963 		}
964 		if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) {
965 			return (EINVAL);
966 		}
967 		if (result < USER_OPTION_FRAMES_MIN ||
968 		    result > USER_OPTION_FRAMES_MAX) {
969 			return (EINVAL);
970 		}
971 		umdevice->lm_dev.params.rx_quick_cons_trip_int = result;
972 	} else if (strcmp(pr_name, "_statticks") == 0) {
973 		if (umdevice->dev_start == B_TRUE) {
974 			return (EBUSY);
975 		}
976 		if (ddi_strtol(pr_val, (char **)NULL, 0, &result)) {
977 			return (EINVAL);
978 		}
979 		if (result < USER_OPTION_STATSTICKS_MIN ||
980 		    result > USER_OPTION_STATSTICKS_MAX) {
981 			return (EINVAL);
982 		}
983 		umdevice->lm_dev.params.stats_ticks = result;
984 	}
985 #endif
986 	else if (strcmp(pr_name, "_disable_msix") == 0) {
987 		err = ENOTSUP;
988 	} else {
989 		err = ENOTSUP;
990 	}
991 
992 	if (!err && refresh) {
993 		err = bnx_refresh_rx_tx_pkts(umdevice);
994 	}
995 	return (err);
996 }
997 
998 
999 static int
1000 bnx_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
1001     uint_t pr_valsize, const void *pr_val)
1002 {
1003 	um_device_t *umdevice = arg;
1004 	boolean_t reprogram = B_FALSE;
1005 	boolean_t rxpause;
1006 	boolean_t txpause;
1007 	uint32_t mtu;
1008 	link_flowctrl_t fl;
1009 	int err = 0;
1010 
1011 	mutex_enter(&umdevice->os_param.gld_mutex);
1012 
1013 	if (lm_get_medium(&umdevice->lm_dev) == LM_MEDIUM_TYPE_FIBER) {
1014 		if (pr_num == MAC_PROP_EN_100FDX_CAP ||
1015 		    pr_num == MAC_PROP_EN_100HDX_CAP ||
1016 		    pr_num == MAC_PROP_EN_10FDX_CAP ||
1017 		    pr_num == MAC_PROP_EN_10HDX_CAP) {
1018 			mutex_exit(&umdevice->os_param.gld_mutex);
1019 			return (ENOTSUP);
1020 		}
1021 	}
1022 
1023 	switch (pr_num) {
1024 		/* read-only properties */
1025 		case MAC_PROP_ADV_1000FDX_CAP:
1026 		case MAC_PROP_ADV_1000HDX_CAP:
1027 		case MAC_PROP_ADV_100FDX_CAP:
1028 		case MAC_PROP_ADV_100HDX_CAP:
1029 		case MAC_PROP_ADV_10FDX_CAP:
1030 		case MAC_PROP_ADV_10HDX_CAP:
1031 		case MAC_PROP_STATUS:
1032 		case MAC_PROP_SPEED:
1033 		case MAC_PROP_DUPLEX:
1034 		default:
1035 
1036 			err = ENOTSUP;
1037 			break;
1038 
1039 
1040 /* BEGIN CSTYLED */
1041 #define	BNX_SETPROP_CASE(cap, param)							\
1042 		case cap:								\
1043 			if (umdevice->hwinit.lnkcfg.param != *(uint8_t *)pr_val) {	\
1044 				umdevice->hwinit.lnkcfg.param = *(uint8_t *)pr_val;	\
1045 				umdevice->curcfg.lnkcfg.param = *(uint8_t *)pr_val;	\
1046 				reprogram = B_TRUE;					\
1047 			}								\
1048 			break
1049 /* END CSTYLED */
1050 
1051 
1052 		BNX_SETPROP_CASE(MAC_PROP_EN_1000FDX_CAP, param_1000fdx);
1053 		BNX_SETPROP_CASE(MAC_PROP_EN_1000HDX_CAP, param_1000hdx);
1054 		BNX_SETPROP_CASE(MAC_PROP_EN_100FDX_CAP, param_100fdx);
1055 		BNX_SETPROP_CASE(MAC_PROP_EN_100HDX_CAP, param_100hdx);
1056 		BNX_SETPROP_CASE(MAC_PROP_EN_10FDX_CAP, param_10fdx);
1057 		BNX_SETPROP_CASE(MAC_PROP_EN_10HDX_CAP, param_10hdx);
1058 		BNX_SETPROP_CASE(MAC_PROP_AUTONEG, link_autoneg);
1059 
1060 		case MAC_PROP_FLOWCTRL:
1061 			bcopy(pr_val, &fl, sizeof (fl));
1062 			switch (fl) {
1063 				case LINK_FLOWCTRL_NONE:
1064 
1065 					rxpause = B_FALSE;
1066 					txpause = B_FALSE;
1067 					break;
1068 
1069 				case LINK_FLOWCTRL_RX:
1070 
1071 					rxpause = B_TRUE;
1072 					txpause = B_FALSE;
1073 					break;
1074 
1075 				case LINK_FLOWCTRL_TX:
1076 
1077 					rxpause = B_FALSE;
1078 					txpause = B_TRUE;
1079 					break;
1080 
1081 				case LINK_FLOWCTRL_BI:
1082 
1083 					rxpause = B_TRUE;
1084 					txpause = B_TRUE;
1085 					break;
1086 
1087 				default:
1088 
1089 					err = ENOTSUP;
1090 					break;
1091 			}
1092 
1093 			if (err == 0) {
1094 				if (umdevice->hwinit.lnkcfg.param_tx_pause !=
1095 				    txpause ||
1096 				    umdevice->hwinit.lnkcfg.param_rx_pause !=
1097 				    rxpause) {
1098 					umdevice->hwinit.lnkcfg.param_tx_pause =
1099 					    txpause;
1100 					umdevice->hwinit.lnkcfg.param_rx_pause =
1101 					    rxpause;
1102 					umdevice->curcfg.lnkcfg.param_tx_pause =
1103 					    txpause;
1104 					umdevice->curcfg.lnkcfg.param_rx_pause =
1105 					    rxpause;
1106 					reprogram = B_TRUE;
1107 				}
1108 			}
1109 
1110 			break;
1111 
1112 		case MAC_PROP_MTU:
1113 			if (umdevice->dev_start == B_TRUE) {
1114 				err = EBUSY;
1115 				break;
1116 			}
1117 
1118 			bcopy(pr_val, &mtu, sizeof (mtu));
1119 
1120 			if (mtu < USER_OPTION_MTU_MIN ||
1121 			    mtu > USER_OPTION_MTU_MAX) {
1122 				err = EINVAL;
1123 				break;
1124 			}
1125 
1126 			if (umdevice->dev_var.mtu == mtu) {
1127 				break;
1128 			}
1129 
1130 			umdevice->dev_var.mtu = mtu;
1131 			umdevice->lm_dev.params.mtu = umdevice->dev_var.mtu
1132 			    + sizeof (struct ether_header) + VLAN_TAGSZ;
1133 
1134 			if (bnx_refresh_rx_tx_pkts(umdevice) != 0) {
1135 				err = EIO;
1136 			} else {
1137 				reprogram = B_TRUE;
1138 			}
1139 			break;
1140 
1141 		case MAC_PROP_PRIVATE:
1142 			err = bnx_set_priv_prop(umdevice, pr_name, pr_valsize,
1143 			    pr_val);
1144 			reprogram = B_TRUE;
1145 			break;
1146 	}
1147 
1148 	if (!err && reprogram) {
1149 		bnx_update_phy(umdevice);
1150 	}
1151 
1152 	mutex_exit(&umdevice->os_param.gld_mutex);
1153 
1154 	return (err);
1155 }
1156 
1157 static int
1158 bnx_get_priv_prop(um_device_t *umdevice, const char *pr_name,
1159     uint_t pr_valsize, void *pr_val)
1160 {
1161 	int value;
1162 
1163 	if (strcmp(pr_name, "_adv_2500fdx_cap") == 0) {
1164 		if (lm_get_medium(&umdevice->lm_dev) !=
1165 		    LM_MEDIUM_TYPE_FIBER) {
1166 			return (ENOTSUP);
1167 		}
1168 		value = umdevice->curcfg.lnkcfg.param_2500fdx;
1169 	} else if (strcmp(pr_name, "_checksum") == 0) {
1170 		value = umdevice->dev_var.enabled_oflds;
1171 	} else if (strcmp(pr_name, "_tx_descriptor_count") == 0) {
1172 		value = _TX_QINFO(umdevice, 0).desc_cnt;
1173 	} else if (strcmp(pr_name, "_rx_descriptor_count") == 0) {
1174 		value = umdevice->lm_dev.params.l2_rx_desc_cnt[0];
1175 	} else if (strcmp(pr_name, "_tx_coalesce_ticks") == 0) {
1176 		value = umdevice->lm_dev.params.tx_ticks;
1177 	} else if (strcmp(pr_name, "_tx_coalesce_ticks_int") == 0) {
1178 		value = umdevice->lm_dev.params.tx_ticks_int;
1179 	} else if (strcmp(pr_name, "_rx_coalesce_ticks") == 0) {
1180 		value = umdevice->lm_dev.params.rx_ticks;
1181 	} else if (strcmp(pr_name, "_rx_coalesce_ticks_int") == 0) {
1182 		value = umdevice->lm_dev.params.rx_ticks_int;
1183 	} else if (strcmp(pr_name, "_tx_coalesce_frames") == 0) {
1184 		value = umdevice->lm_dev.params.tx_quick_cons_trip;
1185 	} else if (strcmp(pr_name, "_tx_coalesce_frames_int") == 0) {
1186 		value = umdevice->lm_dev.params.tx_quick_cons_trip_int;
1187 	} else if (strcmp(pr_name, "_rx_coalesce_frames") == 0) {
1188 		value = umdevice->lm_dev.params.rx_quick_cons_trip;
1189 	} else if (strcmp(pr_name, "_rx_coalesce_frames_int") == 0) {
1190 		value = umdevice->lm_dev.params.rx_quick_cons_trip_int;
1191 	} else if (strcmp(pr_name, "_statticks") == 0) {
1192 		value = umdevice->lm_dev.params.stats_ticks;
1193 	} else if (strcmp(pr_name, "_disable_msix") == 0) {
1194 		value = umdevice->dev_var.disableMsix;
1195 	} else {
1196 		return (ENOTSUP);
1197 	}
1198 
1199 	(void) snprintf(pr_val, pr_valsize, "%d", value);
1200 	return (0);
1201 
1202 }
1203 
1204 static int
1205 bnx_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
1206     uint_t pr_valsize, void *pr_val)
1207 {
1208 	um_device_t *umdevice = arg;
1209 	link_duplex_t link_duplex;
1210 	uint64_t link_speed;
1211 	link_state_t link_state;
1212 	link_flowctrl_t fl;
1213 
1214 	if (lm_get_medium(&umdevice->lm_dev) == LM_MEDIUM_TYPE_FIBER) {
1215 		if (pr_num == MAC_PROP_EN_100FDX_CAP ||
1216 		    pr_num == MAC_PROP_EN_100HDX_CAP ||
1217 		    pr_num == MAC_PROP_EN_10FDX_CAP ||
1218 		    pr_num == MAC_PROP_EN_10HDX_CAP) {
1219 			return (ENOTSUP);
1220 		}
1221 	}
1222 
1223 	switch (pr_num) {
1224 		case MAC_PROP_DUPLEX:
1225 			link_duplex = umdevice->nddcfg.link_duplex == B_TRUE ?
1226 			    LINK_DUPLEX_FULL: LINK_DUPLEX_HALF;
1227 
1228 			ASSERT(pr_valsize >= sizeof (link_duplex_t));
1229 
1230 			bcopy(&link_duplex, pr_val, sizeof (link_duplex_t));
1231 			break;
1232 
1233 		case MAC_PROP_SPEED:
1234 			link_speed = umdevice->nddcfg.link_speed * 1000000ull;
1235 
1236 			ASSERT(pr_valsize >= sizeof (link_speed));
1237 
1238 			bcopy(&link_speed, pr_val, sizeof (link_speed));
1239 			break;
1240 
1241 		case MAC_PROP_STATUS:
1242 			link_state = umdevice->nddcfg.link_speed ?
1243 			    LINK_STATE_UP : LINK_STATE_DOWN;
1244 
1245 			ASSERT(pr_valsize >= sizeof (link_state_t));
1246 
1247 			bcopy(&link_state, pr_val, sizeof (link_state));
1248 			break;
1249 
1250 		case MAC_PROP_AUTONEG:
1251 			*(uint8_t *)pr_val =
1252 			    umdevice->curcfg.lnkcfg.link_autoneg;
1253 			break;
1254 
1255 		case MAC_PROP_FLOWCTRL:
1256 			ASSERT(pr_valsize >= sizeof (fl));
1257 
1258 			boolean_t txpause =
1259 			    umdevice->curcfg.lnkcfg.param_tx_pause;
1260 			boolean_t rxpause =
1261 			    umdevice->curcfg.lnkcfg.param_rx_pause;
1262 			if (txpause) {
1263 				if (rxpause) {
1264 					fl = LINK_FLOWCTRL_BI;
1265 				} else {
1266 					fl = LINK_FLOWCTRL_TX;
1267 				}
1268 			} else {
1269 				if (rxpause) {
1270 					fl = LINK_FLOWCTRL_RX;
1271 				} else {
1272 					fl = LINK_FLOWCTRL_NONE;
1273 				}
1274 			}
1275 			bcopy(&fl, pr_val, sizeof (fl));
1276 			break;
1277 
1278 		case MAC_PROP_ADV_1000FDX_CAP:
1279 			*(uint8_t *)pr_val =
1280 			    umdevice->curcfg.lnkcfg.param_1000fdx;
1281 			break;
1282 
1283 		case MAC_PROP_EN_1000FDX_CAP:
1284 			*(uint8_t *)pr_val =
1285 			    umdevice->curcfg.lnkcfg.param_1000fdx;
1286 			break;
1287 
1288 		case MAC_PROP_ADV_1000HDX_CAP:
1289 			*(uint8_t *)pr_val =
1290 			    umdevice->curcfg.lnkcfg.param_1000hdx;
1291 			break;
1292 
1293 		case MAC_PROP_EN_1000HDX_CAP:
1294 			*(uint8_t *)pr_val =
1295 			    umdevice->curcfg.lnkcfg.param_1000hdx;
1296 			break;
1297 
1298 		case MAC_PROP_ADV_100FDX_CAP:
1299 			*(uint8_t *)pr_val =
1300 			    umdevice->curcfg.lnkcfg.param_100fdx;
1301 			break;
1302 
1303 		case MAC_PROP_EN_100FDX_CAP:
1304 			*(uint8_t *)pr_val =
1305 			    umdevice->curcfg.lnkcfg.param_100fdx;
1306 			break;
1307 
1308 		case MAC_PROP_ADV_100HDX_CAP:
1309 			*(uint8_t *)pr_val =
1310 			    umdevice->curcfg.lnkcfg.param_100hdx;
1311 			break;
1312 
1313 		case MAC_PROP_EN_100HDX_CAP:
1314 			*(uint8_t *)pr_val =
1315 			    umdevice->curcfg.lnkcfg.param_100hdx;
1316 			break;
1317 
1318 		case MAC_PROP_ADV_10FDX_CAP:
1319 			*(uint8_t *)pr_val =
1320 			    umdevice->curcfg.lnkcfg.param_10fdx;
1321 			break;
1322 
1323 		case MAC_PROP_EN_10FDX_CAP:
1324 			*(uint8_t *)pr_val =
1325 			    umdevice->curcfg.lnkcfg.param_10fdx;
1326 			break;
1327 
1328 		case MAC_PROP_ADV_10HDX_CAP:
1329 			*(uint8_t *)pr_val =
1330 			    umdevice->curcfg.lnkcfg.param_10hdx;
1331 			break;
1332 
1333 		case MAC_PROP_EN_10HDX_CAP:
1334 			*(uint8_t *)pr_val =
1335 			    umdevice->curcfg.lnkcfg.param_10hdx;
1336 			break;
1337 
1338 		case MAC_PROP_PRIVATE:
1339 			return (bnx_get_priv_prop(umdevice, pr_name, pr_valsize,
1340 			    pr_val));
1341 
1342 		default:
1343 
1344 			return (ENOTSUP);
1345 
1346 	}
1347 
1348 	return (0);
1349 
1350 }
1351 
1352 static void
1353 bnx_priv_propinfo(um_device_t *umdevice, const char *pr_name,
1354     mac_prop_info_handle_t prh)
1355 {
1356 	char valstr[64];
1357 	int value;
1358 
1359 	if (strcmp(pr_name, "_adv_2500fdx_cap") == 0) {
1360 		if (lm_get_medium(&umdevice->lm_dev) != LM_MEDIUM_TYPE_FIBER) {
1361 			return;
1362 		}
1363 		value = umdevice->curcfg.lnkcfg.param_2500fdx;
1364 	} else if (strcmp(pr_name, "_checksum") == 0) {
1365 		value = umdevice->dev_var.enabled_oflds;
1366 	} else if (strcmp(pr_name, "_tx_descriptor_count") == 0) {
1367 		value = _TX_QINFO(umdevice, 0).desc_cnt;
1368 	} else if (strcmp(pr_name, "_rx_descriptor_count") == 0) {
1369 		value = umdevice->lm_dev.params.l2_rx_desc_cnt[0];
1370 	} else if (strcmp(pr_name, "_tx_coalesce_ticks") == 0) {
1371 		value = umdevice->lm_dev.params.tx_ticks;
1372 	} else if (strcmp(pr_name, "_tx_coalesce_ticks_int") == 0) {
1373 		value = umdevice->lm_dev.params.tx_ticks_int;
1374 	} else if (strcmp(pr_name, "_rx_coalesce_ticks") == 0) {
1375 		value = umdevice->lm_dev.params.rx_ticks;
1376 	} else if (strcmp(pr_name, "_rx_coalesce_ticks_int") == 0) {
1377 		value = umdevice->lm_dev.params.rx_ticks_int;
1378 	} else if (strcmp(pr_name, "_tx_coalesce_frames") == 0) {
1379 		value = umdevice->lm_dev.params.tx_quick_cons_trip;
1380 	} else if (strcmp(pr_name, "_tx_coalesce_frames_int") == 0) {
1381 		value = umdevice->lm_dev.params.tx_quick_cons_trip_int;
1382 	} else if (strcmp(pr_name, "_rx_coalesce_frames") == 0) {
1383 		value = umdevice->lm_dev.params.rx_quick_cons_trip;
1384 	} else if (strcmp(pr_name, "_rx_coalesce_frames_int") == 0) {
1385 		value = umdevice->lm_dev.params.rx_quick_cons_trip_int;
1386 	} else if (strcmp(pr_name, "_statticks") == 0) {
1387 		value = umdevice->lm_dev.params.stats_ticks;
1388 	} else if (strcmp(pr_name, "_disable_msix") == 0) {
1389 		value = umdevice->dev_var.disableMsix;
1390 	} else {
1391 		return;
1392 	}
1393 
1394 	(void) snprintf(valstr, sizeof (valstr), "%d", value);
1395 	mac_prop_info_set_default_str(prh, valstr);
1396 
1397 }
1398 
1399 static void
1400 bnx_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
1401     mac_prop_info_handle_t prh)
1402 {
1403 	um_device_t *umdevice = arg;
1404 
1405 	if (lm_get_medium(&umdevice->lm_dev) == LM_MEDIUM_TYPE_FIBER) {
1406 		if (pr_num == MAC_PROP_EN_100FDX_CAP ||
1407 		    pr_num == MAC_PROP_ADV_100FDX_CAP ||
1408 		    pr_num == MAC_PROP_EN_100HDX_CAP ||
1409 		    pr_num == MAC_PROP_ADV_100HDX_CAP ||
1410 		    pr_num == MAC_PROP_EN_10FDX_CAP ||
1411 		    pr_num == MAC_PROP_ADV_10FDX_CAP ||
1412 		    pr_num == MAC_PROP_EN_10HDX_CAP ||
1413 		    pr_num == MAC_PROP_ADV_10HDX_CAP) {
1414 			mac_prop_info_set_default_uint8(prh, 0);
1415 			return;
1416 		}
1417 	}
1418 	switch (pr_num) {
1419 		case MAC_PROP_ADV_1000FDX_CAP:
1420 		case MAC_PROP_ADV_1000HDX_CAP:
1421 		case MAC_PROP_ADV_100FDX_CAP:
1422 		case MAC_PROP_ADV_100HDX_CAP:
1423 		case MAC_PROP_ADV_10FDX_CAP:
1424 		case MAC_PROP_ADV_10HDX_CAP:
1425 		case MAC_PROP_STATUS:
1426 		case MAC_PROP_SPEED:
1427 		case MAC_PROP_DUPLEX:
1428 
1429 			mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1430 			break;
1431 
1432 		case MAC_PROP_EN_1000FDX_CAP:
1433 
1434 			mac_prop_info_set_default_uint8(prh, 1);
1435 			break;
1436 
1437 		case MAC_PROP_EN_1000HDX_CAP:
1438 		case MAC_PROP_EN_100FDX_CAP:
1439 		case MAC_PROP_EN_100HDX_CAP:
1440 		case MAC_PROP_EN_10FDX_CAP:
1441 		case MAC_PROP_EN_10HDX_CAP:
1442 
1443 			if (lm_get_medium(&umdevice->lm_dev) ==
1444 			    LM_MEDIUM_TYPE_FIBER) {
1445 				mac_prop_info_set_default_uint8(prh, 0);
1446 			} else {
1447 				mac_prop_info_set_default_uint8(prh, 1);
1448 			}
1449 			break;
1450 
1451 		case MAC_PROP_AUTONEG:
1452 
1453 			mac_prop_info_set_default_uint8(prh, 1);
1454 			break;
1455 
1456 		case MAC_PROP_FLOWCTRL:
1457 
1458 			mac_prop_info_set_default_link_flowctrl(prh,
1459 			    LINK_FLOWCTRL_BI);
1460 			break;
1461 
1462 		case MAC_PROP_MTU:
1463 
1464 			mac_prop_info_set_range_uint32(prh,
1465 			    USER_OPTION_MTU_MIN, USER_OPTION_MTU_MAX);
1466 			break;
1467 
1468 		case MAC_PROP_PRIVATE:
1469 
1470 			bnx_priv_propinfo(umdevice, pr_name, prh);
1471 			break;
1472 		default:
1473 			break;
1474 	}
1475 }
1476 
1477 static mac_callbacks_t bnx_callbacks = {
1478 	(MC_GETCAPAB | MC_SETPROP | MC_GETPROP| MC_PROPINFO),
1479 	bnx_m_stats,
1480 	bnx_m_start,
1481 	bnx_m_stop,
1482 	bnx_m_promiscuous,
1483 	bnx_m_multicast,
1484 	bnx_m_unicast,
1485 	bnx_m_tx,
1486 	NULL,
1487 	NULL,
1488 	bnx_m_getcapab,
1489 	NULL,
1490 	NULL,
1491 	bnx_m_setprop,
1492 	bnx_m_getprop,
1493 	bnx_m_propinfo
1494 };
1495 
1496 
1497 
1498 /*
1499  * Name:    bnx_gld_init
1500  *
1501  * Input:   ptr to device structure.
1502  *
1503  * Return:  DDI_SUCCESS or DDI_FAILURE
1504  *
1505  * Description:
1506  *          This routine populates mac info structure for this device
1507  *          instance and registers device with GLD.
1508  */
1509 int
1510 bnx_gld_init(um_device_t *const umdevice)
1511 {
1512 	mac_register_t *macp;
1513 	int rc;
1514 
1515 	umdevice->dev_start = B_FALSE;
1516 
1517 	mutex_init(&umdevice->os_param.gld_mutex, NULL,
1518 	    MUTEX_DRIVER, DDI_INTR_PRI(umdevice->intrPriority));
1519 
1520 	rw_init(&umdevice->os_param.gld_snd_mutex, NULL, RW_DRIVER, NULL);
1521 
1522 	macp = mac_alloc(MAC_VERSION);
1523 	if (macp == NULL) {
1524 		cmn_err(CE_WARN,
1525 		    "%s: Failed to allocate GLD MAC memory.\n",
1526 		    umdevice->dev_name);
1527 		goto error;
1528 	}
1529 
1530 	macp->m_driver = umdevice;
1531 	macp->m_dip = umdevice->os_param.dip;
1532 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
1533 	macp->m_callbacks = &bnx_callbacks;
1534 	macp->m_min_sdu = 0;
1535 	macp->m_max_sdu = umdevice->dev_var.mtu;
1536 	macp->m_src_addr  = &(umdevice->lm_dev.params.mac_addr[0]);
1537 
1538 	macp->m_margin = VLAN_TAG_SIZE;
1539 
1540 	/*
1541 	 * Call mac_register() after initializing all
1542 	 * the required elements of mac_t struct.
1543 	 */
1544 	rc = mac_register(macp, &umdevice->os_param.macp);
1545 
1546 	mac_free(macp);
1547 
1548 	if (rc != 0) {
1549 		cmn_err(CE_WARN,
1550 		    "%s: Failed to register with GLD.\n",
1551 		    umdevice->dev_name);
1552 		goto error;
1553 	}
1554 
1555 	/* Always report the initial link state as unknown. */
1556 	bnx_gld_link(umdevice, LINK_STATE_UNKNOWN);
1557 
1558 	return (0);
1559 
1560 error:
1561 	rw_destroy(&umdevice->os_param.gld_snd_mutex);
1562 	mutex_destroy(&umdevice->os_param.gld_mutex);
1563 
1564 	return (-1);
1565 }
1566 
1567 void
1568 bnx_gld_link(um_device_t * const umdevice, const link_state_t linkup)
1569 {
1570 	mac_link_update(umdevice->os_param.macp, linkup);
1571 }
1572 
1573 int
1574 bnx_gld_fini(um_device_t * const umdevice)
1575 {
1576 	if (umdevice->dev_start != B_FALSE) {
1577 		cmn_err(CE_WARN,
1578 		    "%s: Detaching device from GLD that is still started!!!\n",
1579 		    umdevice->dev_name);
1580 		return (-1);
1581 	}
1582 
1583 	if (mac_unregister(umdevice->os_param.macp)) {
1584 		cmn_err(CE_WARN,
1585 		    "%s: Failed to unregister with the GLD.\n",
1586 		    umdevice->dev_name);
1587 		return (-1);
1588 	}
1589 
1590 	rw_destroy(&umdevice->os_param.gld_snd_mutex);
1591 	mutex_destroy(&umdevice->os_param.gld_mutex);
1592 
1593 	return (0);
1594 }
1595