1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Emulex.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Source file containing the implementation of the driver entry points
29  * and related helper functions
30  */
31 
32 #include <oce_impl.h>
33 #include <oce_ioctl.h>
34 
35 /* array of properties supported by this driver */
36 mac_priv_prop_t oce_priv_props[] = {
37 	{"_tx_ring_size", MAC_PROP_PERM_READ},
38 	{"_tx_bcopy_limit", MAC_PROP_PERM_RW},
39 	{"_rx_bcopy_limit", MAC_PROP_PERM_RW},
40 	{"_rx_ring_size", MAC_PROP_PERM_READ},
41 };
42 uint32_t oce_num_props = sizeof (oce_priv_props) / sizeof (mac_priv_prop_t);
43 
44 
45 /* ---[ static function declarations ]----------------------------------- */
46 static int oce_power10(int power);
47 static int oce_set_priv_prop(struct oce_dev *dev, const char *name,
48     uint_t size, const void *val);
49 
50 static int oce_get_priv_prop(struct oce_dev *dev, const char *name,
51     uint_t flags, uint_t size, void *val);
52 
53 /* ---[ GLD entry points ]----------------------------------------------- */
54 int
55 oce_m_start(void *arg)
56 {
57 	struct oce_dev *dev = arg;
58 	int ret;
59 
60 	mutex_enter(&dev->dev_lock);
61 
62 	if (dev->state & STATE_MAC_STARTED) {
63 		mutex_exit(&dev->dev_lock);
64 		return (0);
65 	}
66 
67 	if (dev->suspended) {
68 		mutex_exit(&dev->dev_lock);
69 		return (EIO);
70 	}
71 
72 	if (oce_fm_check_acc_handle(dev, dev->db_handle)) {
73 		ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
74 		mutex_exit(&dev->dev_lock);
75 		return (EIO);
76 	}
77 
78 	if (oce_fm_check_acc_handle(dev, dev->csr_handle)) {
79 		ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
80 		mutex_exit(&dev->dev_lock);
81 		return (EIO);
82 	}
83 
84 	if (oce_fm_check_acc_handle(dev, dev->cfg_handle)) {
85 		ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
86 		mutex_exit(&dev->dev_lock);
87 		return (EIO);
88 	}
89 
90 	ret = oce_start(dev);
91 	if (ret != DDI_SUCCESS) {
92 		mutex_exit(&dev->dev_lock);
93 		return (EIO);
94 	}
95 
96 	dev->state |= STATE_MAC_STARTED;
97 	mutex_exit(&dev->dev_lock);
98 
99 
100 	return (DDI_SUCCESS);
101 }
102 
103 int
104 oce_start(struct oce_dev *dev)
105 {
106 	int qidx = 0;
107 	int ret;
108 
109 	ret = oce_alloc_intr(dev);
110 	if (ret != DDI_SUCCESS)
111 		goto  start_fail;
112 	ret = oce_setup_handlers(dev);
113 	if (ret != DDI_SUCCESS) {
114 		oce_log(dev, CE_WARN, MOD_CONFIG,
115 		    "Interrupt handler setup failed with %d", ret);
116 		(void) oce_teardown_intr(dev);
117 		goto  start_fail;
118 	}
119 	/* get link status */
120 	(void) oce_get_link_status(dev, &dev->link);
121 
122 	if (dev->link.mac_speed == PHY_LINK_SPEED_ZERO) {
123 		oce_log(dev, CE_NOTE, MOD_CONFIG,
124 		    "LINK_DOWN: 0x%x", dev->link.mac_speed);
125 		mac_link_update(dev->mac_handle, LINK_STATE_DOWN);
126 	} else {
127 		oce_log(dev, CE_NOTE, MOD_CONFIG,
128 		    "(f,s,d,pp)=(0x%x, 0x%x, 0x%x, 0x%x)",
129 		    dev->link.mac_fault, dev->link.mac_speed,
130 		    dev->link.mac_duplex, dev->link.physical_port);
131 		mac_link_update(dev->mac_handle, LINK_STATE_UP);
132 	}
133 
134 	(void) oce_start_wq(dev->wq[0]);
135 	(void) oce_start_rq(dev->rq[0]);
136 	(void) oce_start_mq(dev->mq);
137 	/* enable interrupts */
138 	oce_ei(dev);
139 	/* arm the eqs */
140 	for (qidx = 0; qidx < dev->neqs; qidx++) {
141 		oce_arm_eq(dev, dev->eq[qidx]->eq_id, 0, B_TRUE, B_FALSE);
142 	}
143 
144 	/* update state */
145 	return (DDI_SUCCESS);
146 start_fail:
147 	return (DDI_FAILURE);
148 } /* oce_start */
149 
150 
151 void
152 oce_m_stop(void *arg)
153 {
154 	struct oce_dev *dev = arg;
155 
156 	/* disable interrupts */
157 
158 	mutex_enter(&dev->dev_lock);
159 	if (dev->suspended) {
160 		mutex_exit(&dev->dev_lock);
161 		return;
162 	}
163 	dev->state |= STATE_MAC_STOPPING;
164 	oce_stop(dev);
165 	dev->state &= ~(STATE_MAC_STOPPING | STATE_MAC_STARTED);
166 	mutex_exit(&dev->dev_lock);
167 }
168 /* called with Tx/Rx comp locks held */
169 void
170 oce_stop(struct oce_dev *dev)
171 {
172 	/* disable interrupts */
173 	oce_di(dev);
174 	oce_remove_handler(dev);
175 	(void) oce_teardown_intr(dev);
176 	mutex_enter(&dev->wq[0]->tx_lock);
177 	mutex_enter(&dev->rq[0]->rx_lock);
178 	mutex_enter(&dev->mq->lock);
179 	/* complete the pending Tx */
180 	oce_clean_wq(dev->wq[0]);
181 	/* Release all the locks */
182 	mutex_exit(&dev->mq->lock);
183 	mutex_exit(&dev->rq[0]->rx_lock);
184 	mutex_exit(&dev->wq[0]->tx_lock);
185 
186 } /* oce_stop */
187 
188 int
189 oce_m_multicast(void *arg, boolean_t add, const uint8_t *mca)
190 {
191 
192 	struct oce_dev *dev = (struct oce_dev *)arg;
193 	struct ether_addr  *mca_drv_list;
194 	struct ether_addr  mca_hw_list[OCE_MAX_MCA];
195 	uint16_t new_mcnt = 0;
196 	int ret;
197 	int i;
198 
199 	/* check the address */
200 	if ((mca[0] & 0x1) == 0) {
201 		return (EINVAL);
202 	}
203 	/* Allocate the local array for holding the addresses temporarily */
204 	bzero(&mca_hw_list, sizeof (&mca_hw_list));
205 	mca_drv_list = &dev->multi_cast[0];
206 
207 	DEV_LOCK(dev);
208 	if (add) {
209 		/* check if we exceeded hw max  supported */
210 		if (dev->num_mca <= OCE_MAX_MCA) {
211 			/* copy entire dev mca to the mbx */
212 			bcopy((void*)mca_drv_list,
213 			    (void*)mca_hw_list,
214 			    (dev->num_mca * sizeof (struct ether_addr)));
215 			/* Append the new one to local list */
216 			bcopy(mca, &mca_hw_list[dev->num_mca],
217 			    sizeof (struct ether_addr));
218 		}
219 		new_mcnt = dev->num_mca + 1;
220 	} else {
221 		struct ether_addr *hwlistp = &mca_hw_list[0];
222 		for (i = 0; i < dev->num_mca; i++) {
223 			/* copy only if it does not match */
224 			if (bcmp((mca_drv_list + i), mca, ETHERADDRL)) {
225 				bcopy(mca_drv_list + i, hwlistp,
226 				    ETHERADDRL);
227 				hwlistp++;
228 			}
229 		}
230 		new_mcnt = dev->num_mca - 1;
231 	}
232 
233 	if (dev->suspended) {
234 		goto finish;
235 	}
236 	if (new_mcnt == 0 || new_mcnt > OCE_MAX_MCA) {
237 		ret = oce_set_multicast_table(dev, dev->if_id, NULL, 0, B_TRUE);
238 	} else {
239 		ret = oce_set_multicast_table(dev, dev->if_id,
240 		    &mca_hw_list[0], new_mcnt, B_FALSE);
241 	}
242 	if (ret != 0) {
243 		DEV_UNLOCK(dev);
244 		return (EIO);
245 	}
246 	/*
247 	 *  Copy the local structure to dev structure
248 	 */
249 finish:
250 	if (new_mcnt && new_mcnt <= OCE_MAX_MCA) {
251 		bcopy(mca_hw_list, mca_drv_list,
252 		    new_mcnt * sizeof (struct ether_addr));
253 	}
254 	dev->num_mca = (uint16_t)new_mcnt;
255 	DEV_UNLOCK(dev);
256 	return (0);
257 } /* oce_m_multicast */
258 
259 int
260 oce_m_unicast(void *arg, const uint8_t *uca)
261 {
262 	struct oce_dev *dev = arg;
263 	int ret;
264 
265 	DEV_LOCK(dev);
266 	if (dev->suspended) {
267 		bcopy(uca, dev->unicast_addr, ETHERADDRL);
268 		DEV_UNLOCK(dev);
269 		return (DDI_SUCCESS);
270 	}
271 
272 	/* Delete previous one and add new one */
273 	ret = oce_del_mac(dev, dev->if_id, &dev->pmac_id);
274 	if (ret != DDI_SUCCESS) {
275 		DEV_UNLOCK(dev);
276 		return (EIO);
277 	}
278 
279 	/* Set the New MAC addr earlier is no longer valid */
280 	ret = oce_add_mac(dev, dev->if_id, uca, &dev->pmac_id);
281 	if (ret != DDI_SUCCESS) {
282 		DEV_UNLOCK(dev);
283 		return (EIO);
284 	}
285 	DEV_UNLOCK(dev);
286 	return (ret);
287 } /* oce_m_unicast */
288 
289 mblk_t *
290 oce_m_send(void *arg, mblk_t *mp)
291 {
292 	struct oce_dev *dev = arg;
293 	mblk_t *nxt_pkt;
294 	mblk_t *rmp = NULL;
295 	struct oce_wq *wq;
296 
297 	DEV_LOCK(dev);
298 	if (dev->suspended || !(dev->state & STATE_MAC_STARTED)) {
299 		DEV_UNLOCK(dev);
300 		freemsg(mp);
301 		return (NULL);
302 	}
303 	DEV_UNLOCK(dev);
304 	wq = dev->wq[0];
305 
306 	while (mp != NULL) {
307 		/* Save the Pointer since mp will be freed in case of copy */
308 		nxt_pkt = mp->b_next;
309 		mp->b_next = NULL;
310 		/* Hardcode wq since we have only one */
311 		rmp = oce_send_packet(wq, mp);
312 		if (rmp != NULL) {
313 			/* reschedule Tx */
314 			wq->resched = B_TRUE;
315 			oce_arm_cq(dev, wq->cq->cq_id, 0, B_TRUE);
316 			/* restore the chain */
317 			rmp->b_next = nxt_pkt;
318 			break;
319 		}
320 		mp  = nxt_pkt;
321 	}
322 	return (rmp);
323 } /* oce_send */
324 
325 boolean_t
326 oce_m_getcap(void *arg, mac_capab_t cap, void *data)
327 {
328 	struct oce_dev *dev = arg;
329 	boolean_t ret = B_TRUE;
330 	switch (cap) {
331 
332 	case MAC_CAPAB_HCKSUM: {
333 		uint32_t *csum_flags = u32ptr(data);
334 		*csum_flags = HCKSUM_ENABLE |
335 		    HCKSUM_INET_FULL_V4 |
336 		    HCKSUM_IPHDRCKSUM;
337 		break;
338 	}
339 	case MAC_CAPAB_LSO: {
340 		mac_capab_lso_t *mcap_lso = (mac_capab_lso_t *)data;
341 		if (dev->lso_capable) {
342 			mcap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
343 			mcap_lso->lso_basic_tcp_ipv4.lso_max = OCE_LSO_MAX_SIZE;
344 		} else {
345 			ret = B_FALSE;
346 		}
347 		break;
348 	}
349 	default:
350 		ret = B_FALSE;
351 		break;
352 	}
353 	return (ret);
354 } /* oce_m_getcap */
355 
356 int
357 oce_m_setprop(void *arg, const char *name, mac_prop_id_t id,
358     uint_t size, const void *val)
359 {
360 	struct oce_dev *dev = arg;
361 	int ret = 0;
362 
363 	DEV_LOCK(dev);
364 	switch (id) {
365 	case MAC_PROP_MTU: {
366 		uint32_t mtu;
367 
368 		bcopy(val, &mtu, sizeof (uint32_t));
369 
370 		if (dev->mtu == mtu) {
371 			ret = 0;
372 			break;
373 		}
374 
375 		if (mtu != OCE_MIN_MTU && mtu != OCE_MAX_MTU) {
376 			ret = EINVAL;
377 			break;
378 		}
379 
380 		ret = mac_maxsdu_update(dev->mac_handle, mtu);
381 		if (0 == ret) {
382 			dev->mtu = mtu;
383 			break;
384 		}
385 		break;
386 	}
387 
388 	case MAC_PROP_FLOWCTRL: {
389 		link_flowctrl_t flowctrl;
390 		uint32_t fc = 0;
391 
392 		bcopy(val, &flowctrl, sizeof (link_flowctrl_t));
393 
394 		switch (flowctrl) {
395 		case LINK_FLOWCTRL_NONE:
396 			fc = 0;
397 			break;
398 
399 		case LINK_FLOWCTRL_RX:
400 			fc = OCE_FC_RX;
401 			break;
402 
403 		case LINK_FLOWCTRL_TX:
404 			fc = OCE_FC_TX;
405 			break;
406 
407 		case LINK_FLOWCTRL_BI:
408 			fc = OCE_FC_RX | OCE_FC_TX;
409 			break;
410 		default:
411 			ret = EINVAL;
412 			break;
413 		} /* switch flowctrl */
414 
415 		if (ret)
416 			break;
417 
418 		if (fc == dev->flow_control)
419 			break;
420 
421 		if (dev->suspended) {
422 			dev->flow_control = fc;
423 			break;
424 		}
425 		/* call to set flow control */
426 		ret = oce_set_flow_control(dev, fc);
427 		/* store the new fc setting on success */
428 		if (ret == 0) {
429 		dev->flow_control = fc;
430 		}
431 		break;
432 	}
433 
434 	case MAC_PROP_PRIVATE:
435 		ret = oce_set_priv_prop(dev, name, size, val);
436 		break;
437 
438 	default:
439 		ret = ENOTSUP;
440 		break;
441 	} /* switch id */
442 
443 	DEV_UNLOCK(dev);
444 	return (ret);
445 } /* oce_m_setprop */
446 
447 int
448 oce_m_getprop(void *arg, const char *name, mac_prop_id_t id,
449     uint_t flags, uint_t size, void *val, uint_t *perm)
450 {
451 	struct oce_dev *dev = arg;
452 	uint32_t ret = 0;
453 
454 	*perm = MAC_PROP_PERM_READ;
455 
456 	switch (id) {
457 	case MAC_PROP_AUTONEG:
458 	case MAC_PROP_EN_AUTONEG:
459 	case MAC_PROP_ADV_1000FDX_CAP:
460 	case MAC_PROP_EN_1000FDX_CAP:
461 	case MAC_PROP_ADV_1000HDX_CAP:
462 	case MAC_PROP_EN_1000HDX_CAP:
463 	case MAC_PROP_ADV_100FDX_CAP:
464 	case MAC_PROP_EN_100FDX_CAP:
465 	case MAC_PROP_ADV_100HDX_CAP:
466 	case MAC_PROP_EN_100HDX_CAP:
467 	case MAC_PROP_ADV_10FDX_CAP:
468 	case MAC_PROP_EN_10FDX_CAP:
469 	case MAC_PROP_ADV_10HDX_CAP:
470 	case MAC_PROP_EN_10HDX_CAP:
471 	case MAC_PROP_ADV_100T4_CAP:
472 	case MAC_PROP_EN_100T4_CAP: {
473 		*(uint8_t *)val = 0x0;
474 		break;
475 	}
476 
477 	case MAC_PROP_ADV_10GFDX_CAP: {
478 		*(uint8_t *)val = 0x01;
479 		break;
480 	}
481 
482 	case MAC_PROP_EN_10GFDX_CAP: {
483 		*(uint8_t *)val = 0x01;
484 		break;
485 	}
486 
487 	case MAC_PROP_DUPLEX: {
488 		if (size >= sizeof (link_duplex_t)) {
489 			uint32_t *mode = (uint32_t *)val;
490 
491 			*perm = MAC_PROP_PERM_READ;
492 			if (dev->state & STATE_MAC_STARTED)
493 				*mode = LINK_DUPLEX_FULL;
494 			else
495 				*mode = LINK_DUPLEX_UNKNOWN;
496 
497 		} else
498 			ret = EINVAL;
499 		break;
500 	}
501 
502 	case MAC_PROP_SPEED: {
503 		if (size >= sizeof (uint64_t)) {
504 			uint64_t *speed = (uint64_t *)val;
505 
506 			*perm = MAC_PROP_PERM_READ;
507 			*speed = 0;
508 			if ((dev->state & STATE_MAC_STARTED) &&
509 			    (dev->link.mac_speed != 0)) {
510 				*speed = 1000000ull *
511 				    oce_power10(dev->link.mac_speed);
512 			}
513 		} else
514 			ret = EINVAL;
515 		break;
516 	}
517 
518 	case MAC_PROP_MTU: {
519 		mac_propval_range_t range;
520 
521 		*perm = MAC_PROP_PERM_RW;
522 		if (!(flags & MAC_PROP_POSSIBLE)) {
523 			ret = ENOTSUP;
524 			break;
525 		}
526 		range.mpr_count = 1;
527 		range.mpr_type = MAC_PROPVAL_UINT32;
528 		range.range_uint32[0].mpur_min = OCE_MIN_MTU;
529 		range.range_uint32[0].mpur_max = OCE_MAX_MTU;
530 		bcopy(&range, val, sizeof (mac_propval_range_t));
531 		break;
532 	}
533 
534 	case MAC_PROP_FLOWCTRL: {
535 		link_flowctrl_t *fc = (link_flowctrl_t *)val;
536 
537 		if (size < sizeof (link_flowctrl_t)) {
538 			ret = EINVAL;
539 			break;
540 		}
541 
542 		if (size >= sizeof (link_flowctrl_t)) {
543 			if (dev->flow_control & OCE_FC_TX &&
544 			    dev->flow_control & OCE_FC_RX)
545 				*fc = LINK_FLOWCTRL_BI;
546 			else if (dev->flow_control == OCE_FC_TX)
547 				*fc = LINK_FLOWCTRL_TX;
548 			else if (dev->flow_control == OCE_FC_RX)
549 				*fc = LINK_FLOWCTRL_RX;
550 			else if (dev->flow_control == 0)
551 				*fc = LINK_FLOWCTRL_NONE;
552 			else
553 				ret = EINVAL;
554 		}
555 		break;
556 	}
557 
558 	case MAC_PROP_PRIVATE: {
559 		ret = oce_get_priv_prop(dev, name, flags, size, val);
560 		break;
561 	}
562 	default:
563 		ret = ENOTSUP;
564 		break;
565 	} /* switch id */
566 	return (ret);
567 } /* oce_m_getprop */
568 
569 /*
570  * function to handle dlpi streams message from GLDv3 mac layer
571  */
572 void
573 oce_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
574 {
575 	struct oce_dev *dev = arg;
576 	struct  iocblk *iocp;
577 	int cmd;
578 	uint32_t payload_length;
579 	int ret;
580 
581 	iocp = (struct iocblk *)voidptr(mp->b_rptr);
582 	iocp->ioc_error = 0;
583 	cmd = iocp->ioc_cmd;
584 
585 	DEV_LOCK(dev);
586 	if (dev->suspended) {
587 		miocnak(wq, mp, 0, EINVAL);
588 		DEV_UNLOCK(dev);
589 		return;
590 	}
591 	DEV_UNLOCK(dev);
592 
593 	switch (cmd) {
594 
595 	case OCE_ISSUE_MBOX: {
596 		ret = oce_issue_mbox(dev, wq, mp, &payload_length);
597 		if (ret != 0) {
598 			miocnak(wq, mp, payload_length, ret);
599 		} else {
600 			miocack(wq, mp, payload_length, 0);
601 		}
602 		break;
603 	}
604 
605 	default:
606 		miocnak(wq, mp, 0, ENOTSUP);
607 		break;
608 	}
609 } /* oce_m_ioctl */
610 
611 int
612 oce_m_promiscuous(void *arg, boolean_t enable)
613 {
614 	struct oce_dev *dev = arg;
615 	int ret = 0;
616 
617 	DEV_LOCK(dev);
618 
619 	if (dev->promisc == enable) {
620 		DEV_UNLOCK(dev);
621 		return (ret);
622 	}
623 
624 	if (dev->suspended) {
625 		/* remember the setting */
626 		dev->promisc = enable;
627 		DEV_UNLOCK(dev);
628 		return (ret);
629 	}
630 
631 	ret = oce_set_promiscuous(dev, enable);
632 	if (ret == DDI_SUCCESS)
633 		dev->promisc = enable;
634 	DEV_UNLOCK(dev);
635 	return (ret);
636 } /* oce_m_promiscuous */
637 
638 static int
639 oce_power10(int power)
640 {
641 	int ret = 1;
642 
643 	while (power) {
644 		ret *= 10;
645 		power--;
646 	}
647 	return (ret);
648 }
649 
650 /*
651  * function to set a private property.
652  * Called from the set_prop GLD entry point
653  *
654  * dev - sofware handle to the device
655  * name - string containing the property name
656  * size - length of the string in name
657  * val - pointer to a location where the value to set is stored
658  *
659  * return EINVAL => invalid value in val 0 => success
660  */
661 static int
662 oce_set_priv_prop(struct oce_dev *dev, const char *name,
663     uint_t size, const void *val)
664 {
665 	int ret = ENOTSUP;
666 	long result;
667 
668 	_NOTE(ARGUNUSED(size));
669 
670 	if (NULL == val) {
671 		ret = EINVAL;
672 		return (ret);
673 	}
674 
675 	if (strcmp(name, "_tx_bcopy_limit") == 0) {
676 		(void) ddi_strtol(val, (char **)NULL, 0, &result);
677 		if (result <= OCE_WQ_BUF_SIZE) {
678 			if (result != dev->tx_bcopy_limit)
679 				dev->tx_bcopy_limit = (uint32_t)result;
680 			ret = 0;
681 		} else {
682 			ret = EINVAL;
683 		}
684 	}
685 	if (strcmp(name, "_rx_bcopy_limit") == 0) {
686 		(void) ddi_strtol(val, (char **)NULL, 0, &result);
687 		if (result <= OCE_RQ_BUF_SIZE) {
688 			if (result != dev->rx_bcopy_limit)
689 				dev->rx_bcopy_limit = (uint32_t)result;
690 			ret = 0;
691 		} else {
692 			ret = EINVAL;
693 		}
694 	}
695 
696 	return (ret);
697 } /* oce_set_priv_prop */
698 
699 /*
700  * function to get the value of a private property. Called from get_prop
701  *
702  * dev - software handle to the device
703  * name - string containing the property name
704  * flags - flags sent by the OS to get_prop
705  * size - length of the string contained name
706  * val - [OUT] pointer to the location where the result is returned
707  *
708  * return EINVAL => invalid request 0 => success
709  */
710 static int
711 oce_get_priv_prop(struct oce_dev *dev, const char *name,
712     uint_t flags, uint_t size, void *val)
713 {
714 	int ret = ENOTSUP;
715 	int value;
716 	boolean_t is_default = (flags & MAC_PROP_DEFAULT);
717 
718 	if (NULL == val) {
719 		ret = EINVAL;
720 		return (ret);
721 	}
722 
723 	if (strcmp(name, "_tx_ring_size") == 0) {
724 		value = is_default ? OCE_DEFAULT_TX_RING_SIZE :
725 		    dev->tx_ring_size;
726 		ret = 0;
727 		goto done;
728 	}
729 
730 	if (strcmp(name, "_tx_bcopy_limit") == 0) {
731 		value = dev->tx_bcopy_limit;
732 		ret = 0;
733 		goto done;
734 	}
735 
736 	if (strcmp(name, "_rx_bcopy_limit") == 0) {
737 		value = dev->rx_bcopy_limit;
738 		ret = 0;
739 		goto done;
740 	}
741 
742 	if (strcmp(name, "_rx_ring_size") == 0) {
743 		value = is_default ? OCE_DEFAULT_RX_RING_SIZE :
744 		    dev->rx_ring_size;
745 		ret = 0;
746 		goto done;
747 	}
748 
749 done:
750 	if (ret == 0) {
751 		(void) snprintf(val, size, "%d", value);
752 	}
753 	return (ret);
754 } /* oce_get_priv_prop */
755