1 /* 2 * CDDL HEADER START 3 * 4 * Copyright(c) 2007-2008 Intel Corporation. All rights reserved. 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at: 10 * http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When using or redistributing this file, you may do so under the 15 * License only. No other modification of this header is permitted. 16 * 17 * If applicable, add the following below this CDDL HEADER, with the 18 * fields enclosed by brackets "[]" replaced with your own identifying 19 * information: Portions Copyright [yyyy] [name of copyright owner] 20 * 21 * CDDL HEADER END 22 */ 23 24 /* 25 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms of the CDDL. 27 */ 28 29 #pragma ident "%Z%%M% %I% %E% SMI" 30 31 #include "ixgbe_sw.h" 32 33 /* 34 * Retrieve a value for one of the statistics. 35 */ 36 int 37 ixgbe_m_stat(void *arg, uint_t stat, uint64_t *val) 38 { 39 ixgbe_t *ixgbe = (ixgbe_t *)arg; 40 struct ixgbe_hw *hw = &ixgbe->hw; 41 ixgbe_stat_t *ixgbe_ks; 42 int i; 43 44 ixgbe_ks = (ixgbe_stat_t *)ixgbe->ixgbe_ks->ks_data; 45 46 mutex_enter(&ixgbe->gen_lock); 47 48 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 49 mutex_exit(&ixgbe->gen_lock); 50 return (ECANCELED); 51 } 52 53 switch (stat) { 54 case MAC_STAT_IFSPEED: 55 *val = ixgbe->link_speed * 1000000ull; 56 break; 57 58 case MAC_STAT_MULTIRCV: 59 ixgbe_ks->mprc.value.ui64 += 60 IXGBE_READ_REG(hw, IXGBE_MPRC); 61 *val = ixgbe_ks->mprc.value.ui64; 62 break; 63 64 case MAC_STAT_BRDCSTRCV: 65 ixgbe_ks->bprc.value.ui64 += 66 IXGBE_READ_REG(hw, IXGBE_BPRC); 67 *val = ixgbe_ks->bprc.value.ui64; 68 break; 69 70 case MAC_STAT_MULTIXMT: 71 ixgbe_ks->mptc.value.ui64 += 72 IXGBE_READ_REG(hw, IXGBE_MPTC); 73 *val = ixgbe_ks->mptc.value.ui64; 74 break; 75 76 case MAC_STAT_BRDCSTXMT: 77 ixgbe_ks->bptc.value.ui64 += 78 IXGBE_READ_REG(hw, IXGBE_BPTC); 79 *val = ixgbe_ks->bptc.value.ui64; 80 break; 81 82 case MAC_STAT_NORCVBUF: 83 for (i = 0; i < 8; i++) { 84 ixgbe_ks->rnbc.value.ui64 += 85 IXGBE_READ_REG(hw, IXGBE_RNBC(i)); 86 } 87 *val = ixgbe_ks->rnbc.value.ui64; 88 break; 89 90 case MAC_STAT_IERRORS: 91 ixgbe_ks->crcerrs.value.ui64 += 92 IXGBE_READ_REG(hw, IXGBE_CRCERRS); 93 ixgbe_ks->illerrc.value.ui64 += 94 IXGBE_READ_REG(hw, IXGBE_ILLERRC); 95 ixgbe_ks->errbc.value.ui64 += 96 IXGBE_READ_REG(hw, IXGBE_ERRBC); 97 ixgbe_ks->rlec.value.ui64 += 98 IXGBE_READ_REG(hw, IXGBE_RLEC); 99 *val = ixgbe_ks->crcerrs.value.ui64 + 100 ixgbe_ks->illerrc.value.ui64 + 101 ixgbe_ks->errbc.value.ui64 + 102 ixgbe_ks->rlec.value.ui64; 103 break; 104 105 case MAC_STAT_RBYTES: 106 for (i = 0; i < 16; i++) 107 ixgbe_ks->tor.value.ui64 += 108 IXGBE_READ_REG(hw, IXGBE_QBRC(i)); 109 *val = ixgbe_ks->tor.value.ui64; 110 break; 111 112 case MAC_STAT_IPACKETS: 113 ixgbe_ks->tpr.value.ui64 += 114 IXGBE_READ_REG(hw, IXGBE_TPR); 115 *val = ixgbe_ks->tpr.value.ui64; 116 break; 117 118 case MAC_STAT_OPACKETS: 119 ixgbe_ks->tpt.value.ui64 += 120 IXGBE_READ_REG(hw, IXGBE_TPT); 121 *val = ixgbe_ks->tpt.value.ui64; 122 break; 123 124 /* RFC 1643 stats */ 125 case ETHER_STAT_FCS_ERRORS: 126 ixgbe_ks->crcerrs.value.ui64 += 127 IXGBE_READ_REG(hw, IXGBE_CRCERRS); 128 *val = ixgbe_ks->crcerrs.value.ui64; 129 break; 130 131 case ETHER_STAT_TOOLONG_ERRORS: 132 ixgbe_ks->roc.value.ui64 += 133 IXGBE_READ_REG(hw, IXGBE_ROC); 134 *val = ixgbe_ks->roc.value.ui64; 135 break; 136 137 case ETHER_STAT_MACRCV_ERRORS: 138 ixgbe_ks->crcerrs.value.ui64 += 139 IXGBE_READ_REG(hw, IXGBE_CRCERRS); 140 ixgbe_ks->illerrc.value.ui64 += 141 IXGBE_READ_REG(hw, IXGBE_ILLERRC); 142 ixgbe_ks->errbc.value.ui64 += 143 IXGBE_READ_REG(hw, IXGBE_ERRBC); 144 ixgbe_ks->rlec.value.ui64 += 145 IXGBE_READ_REG(hw, IXGBE_RLEC); 146 *val = ixgbe_ks->crcerrs.value.ui64 + 147 ixgbe_ks->illerrc.value.ui64 + 148 ixgbe_ks->errbc.value.ui64 + 149 ixgbe_ks->rlec.value.ui64; 150 break; 151 152 /* MII/GMII stats */ 153 case ETHER_STAT_XCVR_ADDR: 154 /* The Internal PHY's MDI address for each MAC is 1 */ 155 *val = 1; 156 break; 157 158 case ETHER_STAT_XCVR_ID: 159 *val = hw->phy.id; 160 break; 161 162 case ETHER_STAT_XCVR_INUSE: 163 switch (ixgbe->link_speed) { 164 case IXGBE_LINK_SPEED_1GB_FULL: 165 *val = 166 (hw->phy.media_type == ixgbe_media_type_copper) ? 167 XCVR_1000T : XCVR_1000X; 168 break; 169 case IXGBE_LINK_SPEED_100_FULL: 170 *val = (hw->phy.media_type == ixgbe_media_type_copper) ? 171 XCVR_100T2 : XCVR_100X; 172 break; 173 default: 174 *val = XCVR_NONE; 175 break; 176 } 177 break; 178 179 case ETHER_STAT_CAP_1000FDX: 180 *val = ixgbe->param_1000fdx_cap; 181 break; 182 183 case ETHER_STAT_CAP_100FDX: 184 *val = ixgbe->param_100fdx_cap; 185 break; 186 187 case ETHER_STAT_CAP_ASMPAUSE: 188 *val = ixgbe->param_asym_pause_cap; 189 break; 190 191 case ETHER_STAT_CAP_PAUSE: 192 *val = ixgbe->param_pause_cap; 193 break; 194 195 case ETHER_STAT_CAP_AUTONEG: 196 *val = ixgbe->param_autoneg_cap; 197 break; 198 199 case ETHER_STAT_ADV_CAP_1000FDX: 200 *val = ixgbe->param_adv_1000fdx_cap; 201 break; 202 203 case ETHER_STAT_ADV_CAP_100FDX: 204 *val = ixgbe->param_adv_100fdx_cap; 205 break; 206 207 case ETHER_STAT_ADV_CAP_ASMPAUSE: 208 *val = ixgbe->param_adv_asym_pause_cap; 209 break; 210 211 case ETHER_STAT_ADV_CAP_PAUSE: 212 *val = ixgbe->param_adv_pause_cap; 213 break; 214 215 case ETHER_STAT_ADV_CAP_AUTONEG: 216 *val = hw->mac.autoneg; 217 break; 218 219 case ETHER_STAT_LP_CAP_1000FDX: 220 *val = ixgbe->param_lp_1000fdx_cap; 221 break; 222 223 case ETHER_STAT_LP_CAP_100FDX: 224 *val = ixgbe->param_lp_100fdx_cap; 225 break; 226 227 case ETHER_STAT_LP_CAP_ASMPAUSE: 228 *val = ixgbe->param_lp_asym_pause_cap; 229 break; 230 231 case ETHER_STAT_LP_CAP_PAUSE: 232 *val = ixgbe->param_lp_pause_cap; 233 break; 234 235 case ETHER_STAT_LP_CAP_AUTONEG: 236 *val = ixgbe->param_lp_autoneg_cap; 237 break; 238 239 case ETHER_STAT_LINK_ASMPAUSE: 240 *val = ixgbe->param_asym_pause_cap; 241 break; 242 243 case ETHER_STAT_LINK_PAUSE: 244 *val = ixgbe->param_pause_cap; 245 break; 246 247 case ETHER_STAT_LINK_AUTONEG: 248 *val = hw->mac.autoneg; 249 break; 250 case ETHER_STAT_LINK_DUPLEX: 251 *val = LINK_DUPLEX_FULL; 252 break; 253 254 case ETHER_STAT_TOOSHORT_ERRORS: 255 ixgbe_ks->ruc.value.ui64 += 256 IXGBE_READ_REG(hw, IXGBE_RUC); 257 *val = ixgbe_ks->ruc.value.ui64; 258 break; 259 260 case ETHER_STAT_CAP_REMFAULT: 261 *val = ixgbe->param_rem_fault; 262 break; 263 264 case ETHER_STAT_ADV_REMFAULT: 265 *val = ixgbe->param_adv_rem_fault; 266 break; 267 268 case ETHER_STAT_LP_REMFAULT: 269 *val = ixgbe->param_lp_rem_fault; 270 break; 271 272 case ETHER_STAT_JABBER_ERRORS: 273 ixgbe_ks->rjc.value.ui64 += 274 IXGBE_READ_REG(hw, IXGBE_RJC); 275 *val = ixgbe_ks->rjc.value.ui64; 276 break; 277 278 default: 279 mutex_exit(&ixgbe->gen_lock); 280 return (ENOTSUP); 281 } 282 283 mutex_exit(&ixgbe->gen_lock); 284 285 if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) 286 ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_UNAFFECTED); 287 288 return (0); 289 } 290 291 /* 292 * Bring the device out of the reset/quiesced state that it 293 * was in when the interface was registered. 294 */ 295 int 296 ixgbe_m_start(void *arg) 297 { 298 ixgbe_t *ixgbe = (ixgbe_t *)arg; 299 300 mutex_enter(&ixgbe->gen_lock); 301 302 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 303 mutex_exit(&ixgbe->gen_lock); 304 return (ECANCELED); 305 } 306 307 if (ixgbe_start(ixgbe) != IXGBE_SUCCESS) { 308 mutex_exit(&ixgbe->gen_lock); 309 return (EIO); 310 } 311 312 ixgbe->ixgbe_state |= IXGBE_STARTED; 313 314 mutex_exit(&ixgbe->gen_lock); 315 316 /* 317 * Enable and start the watchdog timer 318 */ 319 ixgbe_enable_watchdog_timer(ixgbe); 320 321 return (0); 322 } 323 324 /* 325 * Stop the device and put it in a reset/quiesced state such 326 * that the interface can be unregistered. 327 */ 328 void 329 ixgbe_m_stop(void *arg) 330 { 331 ixgbe_t *ixgbe = (ixgbe_t *)arg; 332 333 mutex_enter(&ixgbe->gen_lock); 334 335 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 336 mutex_exit(&ixgbe->gen_lock); 337 return; 338 } 339 340 ixgbe->ixgbe_state &= ~IXGBE_STARTED; 341 342 ixgbe_stop(ixgbe); 343 344 mutex_exit(&ixgbe->gen_lock); 345 346 /* 347 * Disable and stop the watchdog timer 348 */ 349 ixgbe_disable_watchdog_timer(ixgbe); 350 } 351 352 /* 353 * Set the promiscuity of the device. 354 */ 355 int 356 ixgbe_m_promisc(void *arg, boolean_t on) 357 { 358 ixgbe_t *ixgbe = (ixgbe_t *)arg; 359 uint32_t reg_val; 360 struct ixgbe_hw *hw = &ixgbe->hw; 361 362 mutex_enter(&ixgbe->gen_lock); 363 364 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 365 mutex_exit(&ixgbe->gen_lock); 366 return (ECANCELED); 367 } 368 reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL); 369 370 if (on) 371 reg_val |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); 372 else 373 reg_val &= (~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE)); 374 375 IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_FCTRL, reg_val); 376 377 mutex_exit(&ixgbe->gen_lock); 378 379 return (0); 380 } 381 382 /* 383 * Add/remove the addresses to/from the set of multicast 384 * addresses for which the device will receive packets. 385 */ 386 int 387 ixgbe_m_multicst(void *arg, boolean_t add, const uint8_t *mcst_addr) 388 { 389 ixgbe_t *ixgbe = (ixgbe_t *)arg; 390 int result; 391 392 mutex_enter(&ixgbe->gen_lock); 393 394 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 395 mutex_exit(&ixgbe->gen_lock); 396 return (ECANCELED); 397 } 398 399 result = (add) ? ixgbe_multicst_add(ixgbe, mcst_addr) 400 : ixgbe_multicst_remove(ixgbe, mcst_addr); 401 402 mutex_exit(&ixgbe->gen_lock); 403 404 return (result); 405 } 406 407 /* 408 * Set a new device unicast address. 409 */ 410 int 411 ixgbe_m_unicst(void *arg, const uint8_t *mac_addr) 412 { 413 ixgbe_t *ixgbe = (ixgbe_t *)arg; 414 int result; 415 416 mutex_enter(&ixgbe->gen_lock); 417 418 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 419 mutex_exit(&ixgbe->gen_lock); 420 return (ECANCELED); 421 } 422 423 /* 424 * Store the new MAC address. 425 */ 426 bcopy(mac_addr, ixgbe->hw.mac.addr, ETHERADDRL); 427 428 /* 429 * Set MAC address in address slot 0, which is the default address. 430 */ 431 result = ixgbe_unicst_set(ixgbe, mac_addr, 0); 432 433 mutex_exit(&ixgbe->gen_lock); 434 435 return (result); 436 } 437 438 /* 439 * Pass on M_IOCTL messages passed to the DLD, and support 440 * private IOCTLs for debugging and ndd. 441 */ 442 void 443 ixgbe_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 444 { 445 ixgbe_t *ixgbe = (ixgbe_t *)arg; 446 struct iocblk *iocp; 447 enum ioc_reply status; 448 449 iocp = (struct iocblk *)(uintptr_t)mp->b_rptr; 450 iocp->ioc_error = 0; 451 452 switch (iocp->ioc_cmd) { 453 case LB_GET_INFO_SIZE: 454 case LB_GET_INFO: 455 case LB_GET_MODE: 456 case LB_SET_MODE: 457 status = ixgbe_loopback_ioctl(ixgbe, iocp, mp); 458 break; 459 460 case ND_GET: 461 case ND_SET: 462 status = ixgbe_nd_ioctl(ixgbe, q, mp, iocp); 463 break; 464 465 default: 466 status = IOC_INVAL; 467 break; 468 } 469 470 /* 471 * Decide how to reply 472 */ 473 switch (status) { 474 default: 475 case IOC_INVAL: 476 /* 477 * Error, reply with a NAK and EINVAL or the specified error 478 */ 479 miocnak(q, mp, 0, iocp->ioc_error == 0 ? 480 EINVAL : iocp->ioc_error); 481 break; 482 483 case IOC_DONE: 484 /* 485 * OK, reply already sent 486 */ 487 break; 488 489 case IOC_ACK: 490 /* 491 * OK, reply with an ACK 492 */ 493 miocack(q, mp, 0, 0); 494 break; 495 496 case IOC_REPLY: 497 /* 498 * OK, send prepared reply as ACK or NAK 499 */ 500 mp->b_datap->db_type = iocp->ioc_error == 0 ? 501 M_IOCACK : M_IOCNAK; 502 qreply(q, mp); 503 break; 504 } 505 } 506 507 508 /* 509 * Find an unused address slot, set the address to it, reserve 510 * this slot and enable the device to start filtering on the 511 * new address. 512 */ 513 int 514 ixgbe_m_unicst_add(void *arg, mac_multi_addr_t *maddr) 515 { 516 ixgbe_t *ixgbe = (ixgbe_t *)arg; 517 mac_addr_slot_t slot; 518 int err; 519 520 mutex_enter(&ixgbe->gen_lock); 521 522 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 523 mutex_exit(&ixgbe->gen_lock); 524 return (ECANCELED); 525 } 526 527 if (mac_unicst_verify(ixgbe->mac_hdl, 528 maddr->mma_addr, maddr->mma_addrlen) == B_FALSE) { 529 mutex_exit(&ixgbe->gen_lock); 530 return (EINVAL); 531 } 532 533 if (ixgbe->unicst_avail == 0) { 534 /* no slots available */ 535 mutex_exit(&ixgbe->gen_lock); 536 return (ENOSPC); 537 } 538 539 /* 540 * Primary/default address is in slot 0. The next addresses 541 * are the multiple MAC addresses. So multiple MAC address 0 542 * is in slot 1, 1 in slot 2, and so on. So the first multiple 543 * MAC address resides in slot 1. 544 */ 545 for (slot = 1; slot < ixgbe->unicst_total; slot++) { 546 if (ixgbe->unicst_addr[slot].mac.set == 0) 547 break; 548 } 549 550 ASSERT((slot > 0) && (slot < ixgbe->unicst_total)); 551 552 maddr->mma_slot = slot; 553 554 if ((err = ixgbe_unicst_set(ixgbe, maddr->mma_addr, slot)) == 0) { 555 ixgbe->unicst_addr[slot].mac.set = 1; 556 ixgbe->unicst_avail--; 557 } 558 559 mutex_exit(&ixgbe->gen_lock); 560 561 return (err); 562 } 563 564 /* 565 * Removes a MAC address that was added before. 566 */ 567 int 568 ixgbe_m_unicst_remove(void *arg, mac_addr_slot_t slot) 569 { 570 ixgbe_t *ixgbe = (ixgbe_t *)arg; 571 int err; 572 573 mutex_enter(&ixgbe->gen_lock); 574 575 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 576 mutex_exit(&ixgbe->gen_lock); 577 return (ECANCELED); 578 } 579 580 if ((slot <= 0) || (slot >= ixgbe->unicst_total)) { 581 mutex_exit(&ixgbe->gen_lock); 582 return (EINVAL); 583 } 584 585 if (ixgbe->unicst_addr[slot].mac.set == 1) { 586 /* 587 * Copy the default address to the passed slot 588 */ 589 if ((err = ixgbe_unicst_set(ixgbe, 590 ixgbe->unicst_addr[0].mac.addr, slot)) == 0) { 591 ixgbe->unicst_addr[slot].mac.set = 0; 592 ixgbe->unicst_avail++; 593 } 594 595 mutex_exit(&ixgbe->gen_lock); 596 597 return (err); 598 } 599 600 mutex_exit(&ixgbe->gen_lock); 601 602 return (EINVAL); 603 } 604 605 /* 606 * Modifies the value of an address that has been added before. 607 * The new address length and the slot number that was returned 608 * in the call to add should be passed in. mma_flags should be 609 * set to 0. 610 * Returns 0 on success. 611 */ 612 int 613 ixgbe_m_unicst_modify(void *arg, mac_multi_addr_t *maddr) 614 { 615 ixgbe_t *ixgbe = (ixgbe_t *)arg; 616 mac_addr_slot_t slot; 617 int err; 618 619 mutex_enter(&ixgbe->gen_lock); 620 621 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 622 mutex_exit(&ixgbe->gen_lock); 623 return (ECANCELED); 624 } 625 626 if (mac_unicst_verify(ixgbe->mac_hdl, 627 maddr->mma_addr, maddr->mma_addrlen) == B_FALSE) { 628 mutex_exit(&ixgbe->gen_lock); 629 return (EINVAL); 630 } 631 632 slot = maddr->mma_slot; 633 634 if ((slot <= 0) || (slot >= ixgbe->unicst_total)) { 635 mutex_exit(&ixgbe->gen_lock); 636 return (EINVAL); 637 } 638 639 if (ixgbe->unicst_addr[slot].mac.set == 1) { 640 err = ixgbe_unicst_set(ixgbe, maddr->mma_addr, slot); 641 mutex_exit(&ixgbe->gen_lock); 642 return (err); 643 } 644 645 mutex_exit(&ixgbe->gen_lock); 646 647 return (EINVAL); 648 } 649 650 /* 651 * Get the MAC address and all other information related to 652 * the address slot passed in mac_multi_addr_t. 653 * mma_flags should be set to 0 in the call. 654 * On return, mma_flags can take the following values: 655 * 1) MMAC_SLOT_UNUSED 656 * 2) MMAC_SLOT_USED | MMAC_VENDOR_ADDR 657 * 3) MMAC_SLOT_UNUSED | MMAC_VENDOR_ADDR 658 * 4) MMAC_SLOT_USED 659 */ 660 int 661 ixgbe_m_unicst_get(void *arg, mac_multi_addr_t *maddr) 662 { 663 ixgbe_t *ixgbe = (ixgbe_t *)arg; 664 mac_addr_slot_t slot; 665 666 mutex_enter(&ixgbe->gen_lock); 667 668 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) { 669 mutex_exit(&ixgbe->gen_lock); 670 return (ECANCELED); 671 } 672 673 slot = maddr->mma_slot; 674 675 if ((slot <= 0) || (slot >= ixgbe->unicst_total)) { 676 mutex_exit(&ixgbe->gen_lock); 677 return (EINVAL); 678 } 679 if (ixgbe->unicst_addr[slot].mac.set == 1) { 680 bcopy(ixgbe->unicst_addr[slot].mac.addr, 681 maddr->mma_addr, ETHERADDRL); 682 maddr->mma_flags = MMAC_SLOT_USED; 683 } else { 684 maddr->mma_flags = MMAC_SLOT_UNUSED; 685 } 686 687 mutex_exit(&ixgbe->gen_lock); 688 689 return (0); 690 } 691 692 /* 693 * Obtain the MAC's capabilities and associated data from 694 * the driver. 695 */ 696 boolean_t 697 ixgbe_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 698 { 699 ixgbe_t *ixgbe = (ixgbe_t *)arg; 700 701 switch (cap) { 702 case MAC_CAPAB_HCKSUM: { 703 uint32_t *tx_hcksum_flags = cap_data; 704 705 /* 706 * We advertise our capabilities only if tx hcksum offload is 707 * enabled. On receive, the stack will accept checksummed 708 * packets anyway, even if we haven't said we can deliver 709 * them. 710 */ 711 if (!ixgbe->tx_hcksum_enable) 712 return (B_FALSE); 713 714 *tx_hcksum_flags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM; 715 break; 716 } 717 case MAC_CAPAB_MULTIADDRESS: { 718 multiaddress_capab_t *mmacp = cap_data; 719 720 /* 721 * The number of MAC addresses made available by 722 * this capability is one less than the total as 723 * the primary address in slot 0 is counted in 724 * the total. 725 */ 726 mmacp->maddr_naddr = ixgbe->unicst_total - 1; 727 mmacp->maddr_naddrfree = ixgbe->unicst_avail; 728 /* No multiple factory addresses, set mma_flag to 0 */ 729 mmacp->maddr_flag = 0; 730 mmacp->maddr_handle = ixgbe; 731 mmacp->maddr_add = ixgbe_m_unicst_add; 732 mmacp->maddr_remove = ixgbe_m_unicst_remove; 733 mmacp->maddr_modify = ixgbe_m_unicst_modify; 734 mmacp->maddr_get = ixgbe_m_unicst_get; 735 mmacp->maddr_reserve = NULL; 736 break; 737 } 738 default: 739 return (B_FALSE); 740 } 741 return (B_TRUE); 742 } 743