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