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