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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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