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