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