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