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