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