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