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 2010 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 char *oce_priv_props[] = {
37 	"_tx_ring_size",
38 	"_tx_bcopy_limit",
39 	"_rx_ring_size",
40 	"_rx_bcopy_limit",
41 	NULL
42 };
43 
44 extern int pow10[];
45 
46 /* ---[ static function declarations ]----------------------------------- */
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 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) != DDI_FM_OK) {
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) != DDI_FM_OK) {
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) != DDI_FM_OK) {
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 	struct link_status link = {0};
108 
109 	/* get link status */
110 	(void) oce_get_link_status(dev, &link);
111 
112 	dev->link_status  = (link.logical_link_status == NTWK_LOGICAL_LINK_UP) ?
113 	    LINK_STATE_UP : LINK_STATE_DOWN;
114 
115 	dev->link_speed = link.qos_link_speed ? link.qos_link_speed * 10 :
116 	    pow10[link.mac_speed];
117 
118 	mac_link_update(dev->mac_handle, dev->link_status);
119 
120 	for (qidx = 0; qidx < dev->nwqs; qidx++) {
121 		(void) oce_start_wq(dev->wq[qidx]);
122 	}
123 	for (qidx = 0; qidx < dev->nrqs; qidx++) {
124 		(void) oce_start_rq(dev->rq[qidx]);
125 	}
126 	(void) oce_start_mq(dev->mq);
127 	/* enable interrupts */
128 	oce_ei(dev);
129 	/* arm the eqs */
130 	for (qidx = 0; qidx < dev->neqs; qidx++) {
131 		oce_arm_eq(dev, dev->eq[qidx]->eq_id, 0, B_TRUE, B_FALSE);
132 	}
133 	/* TODO update state */
134 	return (DDI_SUCCESS);
135 } /* oce_start */
136 
137 
138 void
139 oce_m_stop(void *arg)
140 {
141 	struct oce_dev *dev = arg;
142 
143 	/* disable interrupts */
144 
145 	mutex_enter(&dev->dev_lock);
146 	if (dev->suspended) {
147 		mutex_exit(&dev->dev_lock);
148 		return;
149 	}
150 	dev->state |= STATE_MAC_STOPPING;
151 	oce_stop(dev);
152 	dev->state &= ~(STATE_MAC_STOPPING | STATE_MAC_STARTED);
153 	mutex_exit(&dev->dev_lock);
154 }
155 /* called with Tx/Rx comp locks held */
156 void
157 oce_stop(struct oce_dev *dev)
158 {
159 	int qidx;
160 	/* disable interrupts */
161 	oce_di(dev);
162 	for (qidx = 0; qidx < dev->nwqs; qidx++) {
163 		mutex_enter(&dev->wq[qidx]->tx_lock);
164 	}
165 	mutex_enter(&dev->mq->lock);
166 	/* complete the pending Tx */
167 	for (qidx = 0; qidx < dev->nwqs; qidx++)
168 		oce_clean_wq(dev->wq[qidx]);
169 	/* Release all the locks */
170 	mutex_exit(&dev->mq->lock);
171 	for (qidx = 0; qidx < dev->nwqs; qidx++)
172 		mutex_exit(&dev->wq[qidx]->tx_lock);
173 	if (dev->link_status == LINK_STATE_UP) {
174 		dev->link_status = LINK_STATE_UNKNOWN;
175 		mac_link_update(dev->mac_handle, dev->link_status);
176 	}
177 
178 } /* oce_stop */
179 
180 int
181 oce_m_multicast(void *arg, boolean_t add, const uint8_t *mca)
182 {
183 
184 	struct oce_dev *dev = (struct oce_dev *)arg;
185 	struct ether_addr  *mca_drv_list;
186 	struct ether_addr  mca_hw_list[OCE_MAX_MCA];
187 	uint16_t new_mcnt = dev->num_mca;
188 	int ret;
189 	int i;
190 
191 	/* check the address */
192 	if ((mca[0] & 0x1) == 0) {
193 		return (EINVAL);
194 	}
195 	/* Allocate the local array for holding the addresses temporarily */
196 	bzero(&mca_hw_list, sizeof (&mca_hw_list));
197 	mca_drv_list = &dev->multi_cast[0];
198 
199 	DEV_LOCK(dev);
200 	if (add) {
201 		/* check if we exceeded hw max  supported */
202 		if (new_mcnt < OCE_MAX_MCA) {
203 			/* copy entire dev mca to the mbx */
204 			bcopy((void*)mca_drv_list,
205 			    (void*)mca_hw_list,
206 			    (dev->num_mca * sizeof (struct ether_addr)));
207 			/* Append the new one to local list */
208 			bcopy(mca, &mca_hw_list[dev->num_mca],
209 			    sizeof (struct ether_addr));
210 		}
211 		new_mcnt++;
212 	} else {
213 		struct ether_addr *hwlistp = &mca_hw_list[0];
214 		for (i = 0; i < dev->num_mca; i++) {
215 			/* copy only if it does not match */
216 			if (bcmp((mca_drv_list + i), mca, ETHERADDRL)) {
217 				bcopy(mca_drv_list + i, hwlistp,
218 				    ETHERADDRL);
219 				hwlistp++;
220 			} else {
221 				new_mcnt--;
222 			}
223 		}
224 	}
225 
226 	if (dev->suspended) {
227 		goto finish;
228 	}
229 	if (new_mcnt > OCE_MAX_MCA) {
230 		ret = oce_set_multicast_table(dev, dev->if_id, &mca_hw_list[0],
231 		    OCE_MAX_MCA, B_TRUE);
232 	} else {
233 		ret = oce_set_multicast_table(dev, dev->if_id,
234 		    &mca_hw_list[0], new_mcnt, B_FALSE);
235 	}
236 	if (ret != 0) {
237 		DEV_UNLOCK(dev);
238 		return (EIO);
239 	}
240 	/*
241 	 *  Copy the local structure to dev structure
242 	 */
243 finish:
244 	if (new_mcnt && new_mcnt <= OCE_MAX_MCA) {
245 		bcopy(mca_hw_list, mca_drv_list,
246 		    new_mcnt * sizeof (struct ether_addr));
247 
248 		dev->num_mca = (uint16_t)new_mcnt;
249 	}
250 	DEV_UNLOCK(dev);
251 	return (0);
252 } /* oce_m_multicast */
253 
254 int
255 oce_m_unicast(void *arg, const uint8_t *uca)
256 {
257 	struct oce_dev *dev = arg;
258 	int ret;
259 
260 	DEV_LOCK(dev);
261 	if (dev->suspended) {
262 		bcopy(uca, dev->unicast_addr, ETHERADDRL);
263 		DEV_UNLOCK(dev);
264 		return (DDI_SUCCESS);
265 	}
266 
267 	/* Delete previous one and add new one */
268 	ret = oce_del_mac(dev, dev->if_id, &dev->pmac_id);
269 	if (ret != DDI_SUCCESS) {
270 		DEV_UNLOCK(dev);
271 		return (EIO);
272 	}
273 	bzero(dev->unicast_addr, ETHERADDRL);
274 
275 	/* Set the New MAC addr earlier is no longer valid */
276 	ret = oce_add_mac(dev, dev->if_id, uca, &dev->pmac_id);
277 	if (ret != DDI_SUCCESS) {
278 		DEV_UNLOCK(dev);
279 		return (EIO);
280 	}
281 	bcopy(uca, dev->unicast_addr, ETHERADDRL);
282 	DEV_UNLOCK(dev);
283 	return (ret);
284 } /* oce_m_unicast */
285 
286 /*
287  * Hashing policy for load balancing over the set of TX rings
288  * available to the driver.
289  */
290 mblk_t *
291 oce_m_send(void *arg, mblk_t *mp)
292 {
293 	struct oce_dev *dev = arg;
294 	mblk_t *nxt_pkt;
295 	mblk_t *rmp = NULL;
296 	struct oce_wq *wq;
297 
298 	DEV_LOCK(dev);
299 	if (dev->suspended || !(dev->state & STATE_MAC_STARTED)) {
300 		DEV_UNLOCK(dev);
301 		freemsg(mp);
302 		return (NULL);
303 	}
304 	DEV_UNLOCK(dev);
305 	/*
306 	 * Hash to pick a wq
307 	 */
308 	wq = oce_get_wq(dev, mp);
309 
310 	while (mp != NULL) {
311 		/* Save the Pointer since mp will be freed in case of copy */
312 		nxt_pkt = mp->b_next;
313 		mp->b_next = NULL;
314 		/* Hardcode wq since we have only one */
315 		rmp = oce_send_packet(wq, mp);
316 		if (rmp != NULL) {
317 			/* reschedule Tx */
318 			wq->resched = B_TRUE;
319 			oce_arm_cq(dev, wq->cq->cq_id, 0, B_TRUE);
320 			/* restore the chain */
321 			rmp->b_next = nxt_pkt;
322 			break;
323 		}
324 		mp  = nxt_pkt;
325 	}
326 	return (rmp);
327 } /* oce_send */
328 
329 boolean_t
330 oce_m_getcap(void *arg, mac_capab_t cap, void *data)
331 {
332 	struct oce_dev *dev = arg;
333 	boolean_t ret = B_TRUE;
334 	switch (cap) {
335 
336 	case MAC_CAPAB_HCKSUM: {
337 		uint32_t *csum_flags = u32ptr(data);
338 		*csum_flags = HCKSUM_ENABLE |
339 		    HCKSUM_INET_FULL_V4 |
340 		    HCKSUM_IPHDRCKSUM;
341 		break;
342 	}
343 	case MAC_CAPAB_LSO: {
344 		mac_capab_lso_t *mcap_lso = (mac_capab_lso_t *)data;
345 		if (dev->lso_capable) {
346 			mcap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
347 			mcap_lso->lso_basic_tcp_ipv4.lso_max = OCE_LSO_MAX_SIZE;
348 		} else {
349 			ret = B_FALSE;
350 		}
351 		break;
352 	}
353 	default:
354 		ret = B_FALSE;
355 		break;
356 	}
357 	return (ret);
358 } /* oce_m_getcap */
359 
360 int
361 oce_m_setprop(void *arg, const char *name, mac_prop_id_t id,
362     uint_t size, const void *val)
363 {
364 	struct oce_dev *dev = arg;
365 	int ret = 0;
366 
367 	DEV_LOCK(dev);
368 	switch (id) {
369 	case MAC_PROP_MTU: {
370 		uint32_t mtu;
371 
372 		bcopy(val, &mtu, sizeof (uint32_t));
373 
374 		if (dev->mtu == mtu) {
375 			ret = 0;
376 			break;
377 		}
378 
379 		if (mtu != OCE_MIN_MTU && mtu != OCE_MAX_MTU) {
380 			ret = EINVAL;
381 			break;
382 		}
383 
384 		ret = mac_maxsdu_update(dev->mac_handle, mtu);
385 		if (0 == ret) {
386 			dev->mtu = mtu;
387 			break;
388 		}
389 		break;
390 	}
391 
392 	case MAC_PROP_FLOWCTRL: {
393 		link_flowctrl_t flowctrl;
394 		uint32_t fc = 0;
395 
396 		bcopy(val, &flowctrl, sizeof (link_flowctrl_t));
397 
398 		switch (flowctrl) {
399 		case LINK_FLOWCTRL_NONE:
400 			fc = 0;
401 			break;
402 
403 		case LINK_FLOWCTRL_RX:
404 			fc = OCE_FC_RX;
405 			break;
406 
407 		case LINK_FLOWCTRL_TX:
408 			fc = OCE_FC_TX;
409 			break;
410 
411 		case LINK_FLOWCTRL_BI:
412 			fc = OCE_FC_RX | OCE_FC_TX;
413 			break;
414 		default:
415 			ret = EINVAL;
416 			break;
417 		} /* switch flowctrl */
418 
419 		if (ret)
420 			break;
421 
422 		if (fc == dev->flow_control)
423 			break;
424 
425 		if (dev->suspended) {
426 			dev->flow_control = fc;
427 			break;
428 		}
429 		/* call to set flow control */
430 		ret = oce_set_flow_control(dev, fc);
431 		/* store the new fc setting on success */
432 		if (ret == 0) {
433 		dev->flow_control = fc;
434 		}
435 		break;
436 	}
437 
438 	case MAC_PROP_PRIVATE:
439 		ret = oce_set_priv_prop(dev, name, size, val);
440 		break;
441 
442 	default:
443 		ret = ENOTSUP;
444 		break;
445 	} /* switch id */
446 
447 	DEV_UNLOCK(dev);
448 	return (ret);
449 } /* oce_m_setprop */
450 
451 int
452 oce_m_getprop(void *arg, const char *name, mac_prop_id_t id,
453     uint_t size, void *val)
454 {
455 	struct oce_dev *dev = arg;
456 	uint32_t ret = 0;
457 
458 	switch (id) {
459 	case MAC_PROP_ADV_10GFDX_CAP:
460 	case MAC_PROP_EN_10GFDX_CAP:
461 		*(uint8_t *)val = 0x01;
462 		break;
463 
464 	case MAC_PROP_DUPLEX: {
465 		uint32_t *mode = (uint32_t *)val;
466 
467 		ASSERT(size >= sizeof (link_duplex_t));
468 		if (dev->state & STATE_MAC_STARTED)
469 			*mode = LINK_DUPLEX_FULL;
470 		else
471 			*mode = LINK_DUPLEX_UNKNOWN;
472 		break;
473 	}
474 
475 	case MAC_PROP_SPEED: {
476 		uint64_t *speed = (uint64_t *)val;
477 		struct link_status link = {0};
478 
479 		ASSERT(size >= sizeof (uint64_t));
480 		*speed = 0;
481 
482 		if (dev->state & STATE_MAC_STARTED) {
483 			if (dev->link_speed < 0) {
484 				(void) oce_get_link_status(dev, &link);
485 				dev->link_speed = link.qos_link_speed ?
486 				    link.qos_link_speed * 10 :
487 				    pow10[link.mac_speed];
488 			}
489 
490 			*speed = dev->link_speed * 1000000ull;
491 		}
492 		break;
493 	}
494 
495 	case MAC_PROP_FLOWCTRL: {
496 		link_flowctrl_t *fc = (link_flowctrl_t *)val;
497 
498 		ASSERT(size >= sizeof (link_flowctrl_t));
499 		if (dev->flow_control & OCE_FC_TX &&
500 		    dev->flow_control & OCE_FC_RX)
501 			*fc = LINK_FLOWCTRL_BI;
502 		else if (dev->flow_control == OCE_FC_TX)
503 			*fc = LINK_FLOWCTRL_TX;
504 		else if (dev->flow_control == OCE_FC_RX)
505 			*fc = LINK_FLOWCTRL_RX;
506 		else if (dev->flow_control == 0)
507 			*fc = LINK_FLOWCTRL_NONE;
508 		else
509 			ret = EINVAL;
510 		break;
511 	}
512 
513 	case MAC_PROP_PRIVATE:
514 		ret = oce_get_priv_prop(dev, name, size, val);
515 		break;
516 
517 	default:
518 		ret = ENOTSUP;
519 		break;
520 	} /* switch id */
521 	return (ret);
522 } /* oce_m_getprop */
523 
524 void
525 oce_m_propinfo(void *arg, const char *name, mac_prop_id_t pr_num,
526     mac_prop_info_handle_t prh)
527 {
528 	_NOTE(ARGUNUSED(arg));
529 
530 	switch (pr_num) {
531 	case MAC_PROP_AUTONEG:
532 	case MAC_PROP_EN_AUTONEG:
533 	case MAC_PROP_ADV_1000FDX_CAP:
534 	case MAC_PROP_EN_1000FDX_CAP:
535 	case MAC_PROP_ADV_1000HDX_CAP:
536 	case MAC_PROP_EN_1000HDX_CAP:
537 	case MAC_PROP_ADV_100FDX_CAP:
538 	case MAC_PROP_EN_100FDX_CAP:
539 	case MAC_PROP_ADV_100HDX_CAP:
540 	case MAC_PROP_EN_100HDX_CAP:
541 	case MAC_PROP_ADV_10FDX_CAP:
542 	case MAC_PROP_EN_10FDX_CAP:
543 	case MAC_PROP_ADV_10HDX_CAP:
544 	case MAC_PROP_EN_10HDX_CAP:
545 	case MAC_PROP_ADV_100T4_CAP:
546 	case MAC_PROP_EN_100T4_CAP:
547 	case MAC_PROP_ADV_10GFDX_CAP:
548 	case MAC_PROP_EN_10GFDX_CAP:
549 	case MAC_PROP_SPEED:
550 	case MAC_PROP_DUPLEX:
551 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
552 		break;
553 
554 	case MAC_PROP_MTU:
555 		mac_prop_info_set_range_uint32(prh, OCE_MIN_MTU, OCE_MAX_MTU);
556 		break;
557 
558 	case MAC_PROP_PRIVATE: {
559 		char valstr[64];
560 		int value;
561 
562 		if (strcmp(name, "_tx_ring_size") == 0) {
563 			value = OCE_DEFAULT_TX_RING_SIZE;
564 		} else if (strcmp(name, "_rx_ring_size") == 0) {
565 			value = OCE_DEFAULT_RX_RING_SIZE;
566 		} else {
567 			return;
568 		}
569 
570 		(void) snprintf(valstr, sizeof (valstr), "%d", value);
571 		mac_prop_info_set_default_str(prh, valstr);
572 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
573 		break;
574 	}
575 	}
576 } /* oce_m_propinfo */
577 
578 /*
579  * function to handle dlpi streams message from GLDv3 mac layer
580  */
581 void
582 oce_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
583 {
584 	struct oce_dev *dev = arg;
585 	struct  iocblk *iocp;
586 	int cmd;
587 	uint32_t payload_length;
588 	int ret;
589 
590 	iocp = (struct iocblk *)voidptr(mp->b_rptr);
591 	iocp->ioc_error = 0;
592 	cmd = iocp->ioc_cmd;
593 
594 	DEV_LOCK(dev);
595 	if (dev->suspended) {
596 		miocnak(wq, mp, 0, EINVAL);
597 		DEV_UNLOCK(dev);
598 		return;
599 	}
600 	DEV_UNLOCK(dev);
601 
602 	switch (cmd) {
603 
604 	case OCE_ISSUE_MBOX: {
605 		ret = oce_issue_mbox(dev, wq, mp, &payload_length);
606 		if (ret != 0) {
607 			miocnak(wq, mp, payload_length, ret);
608 		} else {
609 			miocack(wq, mp, payload_length, 0);
610 		}
611 		break;
612 	}
613 
614 	default:
615 		miocnak(wq, mp, 0, ENOTSUP);
616 		break;
617 	}
618 } /* oce_m_ioctl */
619 
620 int
621 oce_m_promiscuous(void *arg, boolean_t enable)
622 {
623 	struct oce_dev *dev = arg;
624 	int ret = 0;
625 
626 	DEV_LOCK(dev);
627 
628 	if (dev->promisc == enable) {
629 		DEV_UNLOCK(dev);
630 		return (ret);
631 	}
632 
633 	if (dev->suspended) {
634 		/* remember the setting */
635 		dev->promisc = enable;
636 		DEV_UNLOCK(dev);
637 		return (ret);
638 	}
639 
640 	ret = oce_set_promiscuous(dev, enable);
641 	if (ret == DDI_SUCCESS)
642 		dev->promisc = enable;
643 	DEV_UNLOCK(dev);
644 	return (ret);
645 } /* oce_m_promiscuous */
646 
647 /*
648  * function to set a private property.
649  * Called from the set_prop GLD entry point
650  *
651  * dev - sofware handle to the device
652  * name - string containing the property name
653  * size - length of the string in name
654  * val - pointer to a location where the value to set is stored
655  *
656  * return EINVAL => invalid value in val 0 => success
657  */
658 static int
659 oce_set_priv_prop(struct oce_dev *dev, const char *name,
660     uint_t size, const void *val)
661 {
662 	int ret = ENOTSUP;
663 	long result;
664 
665 	_NOTE(ARGUNUSED(size));
666 
667 	if (NULL == val) {
668 		ret = EINVAL;
669 		return (ret);
670 	}
671 
672 	if (strcmp(name, "_tx_bcopy_limit") == 0) {
673 		(void) ddi_strtol(val, (char **)NULL, 0, &result);
674 		if (result <= OCE_WQ_BUF_SIZE) {
675 			if (result != dev->tx_bcopy_limit)
676 				dev->tx_bcopy_limit = (uint32_t)result;
677 			ret = 0;
678 		} else {
679 			ret = EINVAL;
680 		}
681 	}
682 	if (strcmp(name, "_rx_bcopy_limit") == 0) {
683 		(void) ddi_strtol(val, (char **)NULL, 0, &result);
684 		if (result <= OCE_RQ_BUF_SIZE) {
685 			if (result != dev->rx_bcopy_limit)
686 				dev->rx_bcopy_limit = (uint32_t)result;
687 			ret = 0;
688 		} else {
689 			ret = EINVAL;
690 		}
691 	}
692 
693 	return (ret);
694 } /* oce_set_priv_prop */
695 
696 /*
697  * function to get the value of a private property. Called from get_prop
698  *
699  * dev - software handle to the device
700  * name - string containing the property name
701  * size - length of the string contained name
702  * val - [OUT] pointer to the location where the result is returned
703  *
704  * return EINVAL => invalid request 0 => success
705  */
706 static int
707 oce_get_priv_prop(struct oce_dev *dev, const char *name,
708     uint_t size, void *val)
709 {
710 	int value;
711 
712 	if (strcmp(name, "_tx_ring_size") == 0) {
713 		value = dev->tx_ring_size;
714 	} else if (strcmp(name, "_tx_bcopy_limit") == 0) {
715 		value = dev->tx_bcopy_limit;
716 	} else if (strcmp(name, "_rx_ring_size") == 0) {
717 		value = dev->rx_ring_size;
718 	} else if (strcmp(name, "_rx_bcopy_limit") == 0) {
719 		value = dev->rx_bcopy_limit;
720 	} else {
721 		return (ENOTSUP);
722 	}
723 
724 	(void) snprintf(val, size, "%d", value);
725 	return (0);
726 } /* oce_get_priv_prop */
727