1 /*
   2  * usbgem.c: General USB to Fast Ethernet mac driver framework
   3  *
   4  * Copyright (c) 2002-2012 Masayuki Murayama.  All rights reserved.
   5  *
   6  * Redistribution and use in source and binary forms, with or without
   7  * modification, are permitted provided that the following conditions are met:
   8  *
   9  * 1. Redistributions of source code must retain the above copyright notice,
  10  *    this list of conditions and the following disclaimer.
  11  *
  12  * 2. Redistributions in binary form must reproduce the above copyright notice,
  13  *    this list of conditions and the following disclaimer in the documentation
  14  *    and/or other materials provided with the distribution.
  15  *
  16  * 3. Neither the name of the author nor the names of its contributors may be
  17  *    used to endorse or promote products derived from this software without
  18  *    specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  30  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  31  * DAMAGE.
  32  */
  33 
  34 /*
  35  * Copyright 2019 Joyent, Inc.
  36  */
  37 
  38 /*
  39  * Change log
  40  */
  41 
  42 /*
  43  * TODO:
  44  *      implement DELAYED_START
  45  */
  46 
  47 /*
  48  * System Header files.
  49  */
  50 #include <sys/types.h>
  51 #include <sys/conf.h>
  52 #include <sys/debug.h>
  53 #include <sys/kmem.h>
  54 #include <sys/vtrace.h>
  55 #include <sys/ethernet.h>
  56 #include <sys/modctl.h>
  57 #include <sys/errno.h>
  58 #include <sys/ddi.h>
  59 #include <sys/sunddi.h>
  60 #ifndef USBGEM_CONFIG_GLDv3
  61 #include <sys/dlpi.h>
  62 #include <sys/strsubr.h>
  63 #endif
  64 #include <sys/stream.h>           /* required for MBLK* */
  65 #include <sys/strsun.h>           /* required for mionack() */
  66 #include <sys/byteorder.h>
  67 
  68 #include <sys/usb/usba.h>
  69 #ifdef USBGEM_CONFIG_GLDv3
  70 #include <inet/common.h>
  71 #include <inet/led.h>
  72 #include <inet/mi.h>
  73 #include <inet/nd.h>
  74 #endif
  75 
  76 /* supplement definitions */
  77 extern const char *usb_str_cr(usb_cr_t);
  78 
  79 #ifndef USBGEM_CONFIG_GLDv3
  80 #pragma weak    gld_linkstate
  81 #endif
  82 #include <sys/note.h>
  83 
  84 #include "usbgem_mii.h"
  85 #include "usbgem.h"
  86 
  87 #ifdef MODULE
  88 char    ident[] = "usb general ethernet mac driver v" VERSION;
  89 #else
  90 extern char     ident[];
  91 #endif
  92 
  93 /* Debugging support */
  94 #ifdef USBGEM_DEBUG_LEVEL
  95 static int usbgem_debug = USBGEM_DEBUG_LEVEL;
  96 #define DPRINTF(n, args)        if (usbgem_debug > (n)) cmn_err args
  97 #else
  98 #define DPRINTF(n, args)
  99 #endif
 100 
 101 /*
 102  * Useful macros and typedefs
 103  */
 104 #define ROUNDUP(x, a)           (((x) + (a) - 1) & ~((a) - 1))
 105 #define DEFAULT_PIPE(dp)        ((dp)->reg_data->dev_default_ph)
 106 #define VTAG_SIZE       4
 107 #define BOOLEAN(x)      ((x) != 0)
 108 /*
 109  * configuration parameters
 110  */
 111 #define USBDRV_MAJOR_VER        2
 112 #define USBDRV_MINOR_VER        0
 113 
 114 #define ETHERHEADERL    (sizeof (struct ether_header))
 115 #define MAXPKTLEN(dp)   ((dp)->mtu + ETHERHEADERL)
 116 #define MAXPKTBUF(dp)   ((dp)->mtu + ETHERHEADERL + ETHERFCSL)
 117 
 118 #define WATCH_INTERVAL_FAST     drv_usectohz(100*1000)
 119 
 120 #define STOP_GRACEFUL   B_TRUE
 121 
 122 /*
 123  * Private functions
 124  */
 125 static int usbgem_open_pipes(struct usbgem_dev *dp);
 126 static int usbgem_close_pipes(struct usbgem_dev *dp);
 127 static void usbgem_intr_cb(usb_pipe_handle_t, usb_intr_req_t *);
 128 static void usbgem_bulkin_cb(usb_pipe_handle_t, usb_bulk_req_t *);
 129 static void usbgem_bulkout_cb(usb_pipe_handle_t, usb_bulk_req_t *);
 130 
 131 static int usbgem_mii_start(struct usbgem_dev *);
 132 static void usbgem_mii_stop(struct usbgem_dev *);
 133 
 134 /* local buffer management */
 135 static int usbgem_init_rx_buf(struct usbgem_dev *);
 136 
 137 /* internal mac interfaces */
 138 static void usbgem_tx_timeout(struct usbgem_dev *);
 139 static void usbgem_mii_link_watcher(struct usbgem_dev *);
 140 static int usbgem_mac_init(struct usbgem_dev *);
 141 static int usbgem_mac_start(struct usbgem_dev *);
 142 static int usbgem_mac_stop(struct usbgem_dev *, int, boolean_t);
 143 static void usbgem_mac_ioctl(struct usbgem_dev *, queue_t *, mblk_t *);
 144 
 145 int usbgem_speed_value[] = {10, 100, 1000};
 146 
 147 static int usbgem_ctrl_retry = 5;
 148 
 149 /* usb event support */
 150 static int usbgem_disconnect_cb(dev_info_t *dip);
 151 static int usbgem_reconnect_cb(dev_info_t *dip);
 152 int usbgem_suspend(dev_info_t *dip);
 153 int usbgem_resume(dev_info_t *dip);
 154 
 155 static uint8_t usbgem_bcastaddr[] = {
 156         0xff, 0xff, 0xff, 0xff, 0xff, 0xff
 157 };
 158 
 159 #ifdef MODULE
 160 extern struct mod_ops mod_miscops;
 161 
 162 static struct modlmisc modlmisc = {
 163         &mod_miscops,
 164         "usbgem v" VERSION,
 165 };
 166 
 167 static struct modlinkage modlinkage = {
 168         MODREV_1, &modlmisc, NULL
 169 };
 170 
 171 /*
 172  * _init : done
 173  */
 174 int
 175 _init(void)
 176 {
 177         int     status;
 178 
 179         DPRINTF(2, (CE_CONT, "!usbgem: _init: called"));
 180         status = mod_install(&modlinkage);
 181 
 182         return (status);
 183 }
 184 
 185 /*
 186  * _fini : done
 187  */
 188 int
 189 _fini(void)
 190 {
 191         int     status;
 192 
 193         DPRINTF(2, (CE_CONT, "!usbgem: _fini: called"));
 194         status = mod_remove(&modlinkage);
 195         return (status);
 196 }
 197 
 198 int
 199 _info(struct modinfo *modinfop)
 200 {
 201         return (mod_info(&modlinkage, modinfop));
 202 }
 203 #endif /* MODULE */
 204 
 205 /* ============================================================== */
 206 /*
 207  * Ether CRC calculation utilities
 208  */
 209 /* ============================================================== */
 210 /*
 211  * Ether CRC calculation according to 21143 data sheet
 212  */
 213 #define CRC32_POLY_LE   0xedb88320
 214 uint32_t
 215 usbgem_ether_crc_le(const uint8_t *addr)
 216 {
 217         int             idx;
 218         int             bit;
 219         uint_t          data;
 220         uint32_t        crc = 0xffffffff;
 221 
 222         crc = 0xffffffff;
 223         for (idx = 0; idx < ETHERADDRL; idx++) {
 224                 for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
 225                         crc = (crc >> 1) ^
 226                             (((crc ^ data) & 1) ? CRC32_POLY_LE : 0);
 227                 }
 228         }
 229         return  (crc);
 230 }
 231 
 232 #define CRC32_POLY_BE   0x04c11db7
 233 uint32_t
 234 usbgem_ether_crc_be(const uint8_t *addr)
 235 {
 236         int             idx;
 237         int             bit;
 238         uint_t          data;
 239         uint32_t        crc;
 240 
 241         crc = 0xffffffff;
 242         for (idx = 0; idx < ETHERADDRL; idx++) {
 243                 for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
 244                         crc = (crc << 1) ^
 245                             ((((crc >> 31) ^ data) & 1) ? CRC32_POLY_BE : 0);
 246                 }
 247         }
 248         return (crc);
 249 }
 250 
 251 int
 252 usbgem_prop_get_int(struct usbgem_dev *dp, char *prop_template, int def_val)
 253 {
 254         char    propname[32];
 255 
 256         (void) sprintf(propname, prop_template, dp->name);
 257 
 258         return (ddi_prop_get_int(DDI_DEV_T_ANY, dp->dip,
 259             DDI_PROP_DONTPASS, propname, def_val));
 260 }
 261 
 262 static int
 263 usbgem_population(uint32_t x)
 264 {
 265         int     i;
 266         int     cnt;
 267 
 268         cnt = 0;
 269         for (i = 0; i < 32; i++) {
 270                 if (x & (1 << i)) {
 271                         cnt++;
 272                 }
 273         }
 274         return (cnt);
 275 }
 276 
 277 static clock_t
 278 usbgem_timestamp_nz()
 279 {
 280         clock_t now;
 281         now = ddi_get_lbolt();
 282         return (now ? now : (clock_t)1);
 283 }
 284 
 285 #ifdef USBGEM_DEBUG_LEVEL
 286 #ifdef USBGEM_DEBUG_VLAN
 287 #ifdef notdef
 288 #include <netinet/in.h>
 289 #endif
 290 static void
 291 usbgem_dump_packet(struct usbgem_dev *dp, char *title, mblk_t *mp,
 292     boolean_t check_cksum)
 293 {
 294         char    msg[180];
 295         uint8_t buf[18+20+20];
 296         uint8_t *p;
 297         size_t  offset;
 298         uint_t  ethertype;
 299         uint_t  proto;
 300         uint_t  ipproto = 0;
 301         uint_t  iplen;
 302         uint_t  iphlen;
 303         uint_t  tcplen;
 304         uint_t  udplen;
 305         uint_t  cksum;
 306         int     rest;
 307         int     len;
 308         char    *bp;
 309         mblk_t  *tp;
 310         extern uint_t   ip_cksum(mblk_t *, int, uint32_t);
 311 
 312         msg[0] = 0;
 313         bp = msg;
 314 
 315         rest = sizeof (buf);
 316         offset = 0;
 317         for (tp = mp; tp; tp = tp->b_cont) {
 318                 len = tp->b_wptr - tp->b_rptr;
 319                 len = min(rest, len);
 320                 bcopy(tp->b_rptr, &buf[offset], len);
 321                 rest -= len;
 322                 offset += len;
 323                 if (rest == 0) {
 324                         break;
 325                 }
 326         }
 327 
 328         offset = 0;
 329         p = &buf[offset];
 330 
 331         /* ethernet address */
 332         sprintf(bp,
 333             "ether: %02x:%02x:%02x:%02x:%02x:%02x"
 334             " -> %02x:%02x:%02x:%02x:%02x:%02x",
 335             p[6], p[7], p[8], p[9], p[10], p[11],
 336             p[0], p[1], p[2], p[3], p[4], p[5]);
 337         bp = &msg[strlen(msg)];
 338 
 339         /* vlag tag and etherrtype */
 340         ethertype = GET_ETHERTYPE(p);
 341         if (ethertype == VTAG_TPID) {
 342                 sprintf(bp, " vtag:0x%04x", GET_NET16(&p[14]));
 343                 bp = &msg[strlen(msg)];
 344 
 345                 offset += VTAG_SIZE;
 346                 p = &buf[offset];
 347                 ethertype = GET_ETHERTYPE(p);
 348         }
 349         sprintf(bp, " type:%04x", ethertype);
 350         bp = &msg[strlen(msg)];
 351 
 352         /* ethernet packet length */
 353         sprintf(bp, " mblklen:%d", msgdsize(mp));
 354         bp = &msg[strlen(msg)];
 355         if (mp->b_cont) {
 356                 sprintf(bp, "(");
 357                 bp = &msg[strlen(msg)];
 358                 for (tp = mp; tp; tp = tp->b_cont) {
 359                         if (tp == mp) {
 360                                 sprintf(bp, "%d", tp->b_wptr - tp->b_rptr);
 361                         } else {
 362                                 sprintf(bp, "+%d", tp->b_wptr - tp->b_rptr);
 363                         }
 364                         bp = &msg[strlen(msg)];
 365                 }
 366                 sprintf(bp, ")");
 367                 bp = &msg[strlen(msg)];
 368         }
 369 
 370         if (ethertype != ETHERTYPE_IP) {
 371                 goto x;
 372         }
 373 
 374         /* ip address */
 375         offset += sizeof (struct ether_header);
 376         p = &buf[offset];
 377         ipproto = p[9];
 378         iplen = GET_NET16(&p[2]);
 379         sprintf(bp, ", ip: %d.%d.%d.%d -> %d.%d.%d.%d proto:%d iplen:%d",
 380             p[12], p[13], p[14], p[15],
 381             p[16], p[17], p[18], p[19],
 382             ipproto, iplen);
 383         bp = (void *)&msg[strlen(msg)];
 384 
 385         iphlen = (p[0] & 0xf) * 4;
 386 
 387         /* cksum for psuedo header */
 388         cksum = *(uint16_t *)&p[12];
 389         cksum += *(uint16_t *)&p[14];
 390         cksum += *(uint16_t *)&p[16];
 391         cksum += *(uint16_t *)&p[18];
 392         cksum += BE_16(ipproto);
 393 
 394         /* tcp or udp protocol header */
 395         offset += iphlen;
 396         p = &buf[offset];
 397         if (ipproto == IPPROTO_TCP) {
 398                 tcplen = iplen - iphlen;
 399                 sprintf(bp, ", tcp: len:%d cksum:%x",
 400                     tcplen, GET_NET16(&p[16]));
 401                 bp = (void *)&msg[strlen(msg)];
 402 
 403                 if (check_cksum) {
 404                         cksum += BE_16(tcplen);
 405                         cksum = (uint16_t)ip_cksum(mp, offset, cksum);
 406                         sprintf(bp, " (%s)",
 407                             (cksum == 0 || cksum == 0xffff) ? "ok" : "ng");
 408                         bp = (void *)&msg[strlen(msg)];
 409                 }
 410         } else if (ipproto == IPPROTO_UDP) {
 411                 udplen = GET_NET16(&p[4]);
 412                 sprintf(bp, ", udp: len:%d cksum:%x",
 413                     udplen, GET_NET16(&p[6]));
 414                 bp = (void *)&msg[strlen(msg)];
 415 
 416                 if (GET_NET16(&p[6]) && check_cksum) {
 417                         cksum += *(uint16_t *)&p[4];
 418                         cksum = (uint16_t)ip_cksum(mp, offset, cksum);
 419                         sprintf(bp, " (%s)",
 420                             (cksum == 0 || cksum == 0xffff) ? "ok" : "ng");
 421                         bp = (void *)&msg[strlen(msg)];
 422                 }
 423         }
 424 x:
 425         cmn_err(CE_CONT, "!%s: %s: %s", dp->name, title, msg);
 426 }
 427 #endif /* USBGEM_DEBUG_VLAN */
 428 #endif /* USBGEM_DEBUG_LEVEL */
 429 
 430 #ifdef GEM_GCC_RUNTIME
 431 /*
 432  * gcc3 runtime routines
 433  */
 434 #pragma weak memcmp
 435 int
 436 memcmp(const void *s1, const void *s2, size_t n)
 437 {
 438         int     i;
 439         int     ret;
 440 
 441         ret = 0;
 442         for (i = 0; i < n; i++) {
 443                 ret = (int)((uint8_t *)s1)[i] - (int)((uint8_t *)s2)[i];
 444                 if (ret) {
 445                         return (ret);
 446                 }
 447         }
 448         return (0);
 449 }
 450 
 451 #pragma weak memset
 452 void *
 453 memset(void *s, int c, size_t n)
 454 {
 455         if ((c & 0xff) == 0) {
 456                 bzero(s, n);
 457         } else {
 458                 while (n--) {
 459                         ((uint8_t *)s)[n] = c;
 460                 }
 461         }
 462         return (s);
 463 }
 464 
 465 #pragma weak _memcpy = memcpy
 466 #pragma weak memcpy
 467 void *
 468 memcpy(void *s1, const void *s2, size_t n)
 469 {
 470         bcopy(s2, s1, n);
 471         return (s1);
 472 }
 473 #endif /* GEM_GCC_RUNTIME */
 474 /* ============================================================== */
 475 /*
 476  * hardware operations
 477  */
 478 /* ============================================================== */
 479 static int
 480 usbgem_hal_reset_chip(struct usbgem_dev *dp)
 481 {
 482         int     err;
 483 
 484         sema_p(&dp->hal_op_lock);
 485         err = (*dp->ugc.usbgc_reset_chip)(dp);
 486         sema_v(&dp->hal_op_lock);
 487         return (err);
 488 }
 489 
 490 static int
 491 usbgem_hal_init_chip(struct usbgem_dev *dp)
 492 {
 493         int     err;
 494 
 495         sema_p(&dp->hal_op_lock);
 496         err = (*dp->ugc.usbgc_init_chip)(dp);
 497         sema_v(&dp->hal_op_lock);
 498         return (err);
 499 }
 500 
 501 static int
 502 usbgem_hal_attach_chip(struct usbgem_dev *dp)
 503 {
 504         int     err;
 505 
 506         sema_p(&dp->hal_op_lock);
 507         err = (*dp->ugc.usbgc_attach_chip)(dp);
 508         sema_v(&dp->hal_op_lock);
 509         return (err);
 510 }
 511 
 512 static int
 513 usbgem_hal_set_rx_filter(struct usbgem_dev *dp)
 514 {
 515         int     err;
 516 
 517         sema_p(&dp->hal_op_lock);
 518         err = (*dp->ugc.usbgc_set_rx_filter)(dp);
 519         sema_v(&dp->hal_op_lock);
 520         return (err);
 521 }
 522 
 523 static int
 524 usbgem_hal_set_media(struct usbgem_dev *dp)
 525 {
 526         int     err;
 527 
 528         sema_p(&dp->hal_op_lock);
 529         err = (*dp->ugc.usbgc_set_media)(dp);
 530         sema_v(&dp->hal_op_lock);
 531         return (err);
 532 }
 533 
 534 static int
 535 usbgem_hal_start_chip(struct usbgem_dev *dp)
 536 {
 537         int     err;
 538 
 539         sema_p(&dp->hal_op_lock);
 540         err = (*dp->ugc.usbgc_start_chip)(dp);
 541         sema_v(&dp->hal_op_lock);
 542         return (err);
 543 }
 544 
 545 static int
 546 usbgem_hal_stop_chip(struct usbgem_dev *dp)
 547 {
 548         int     err;
 549 
 550         sema_p(&dp->hal_op_lock);
 551         err = (*dp->ugc.usbgc_stop_chip)(dp);
 552         sema_v(&dp->hal_op_lock);
 553         return (err);
 554 }
 555 
 556 static int
 557 usbgem_hal_get_stats(struct usbgem_dev *dp)
 558 {
 559         int     err;
 560 
 561         sema_p(&dp->hal_op_lock);
 562         err = (*dp->ugc.usbgc_get_stats)(dp);
 563         sema_v(&dp->hal_op_lock);
 564         return (err);
 565 }
 566 
 567 
 568 /* ============================================================== */
 569 /*
 570  * USB pipe management
 571  */
 572 /* ============================================================== */
 573 static boolean_t
 574 usbgem_rx_start_unit(struct usbgem_dev *dp, usb_bulk_req_t *req)
 575 {
 576         mblk_t  *mp;
 577         int     err;
 578         usb_flags_t     flags;
 579 
 580         ASSERT(req);
 581 
 582         mp = allocb(dp->rx_buf_len, BPRI_MED);
 583         if (mp == NULL) {
 584                 cmn_err(CE_WARN, "!%s: %s: failed to allocate mblk",
 585                     dp->name, __func__);
 586                 goto err;
 587         }
 588 
 589         req->bulk_len = dp->rx_buf_len;
 590         req->bulk_data = mp;
 591         req->bulk_client_private = (usb_opaque_t)dp;
 592         req->bulk_timeout = 0;
 593         req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK;
 594         req->bulk_cb = usbgem_bulkin_cb;
 595         req->bulk_exc_cb = usbgem_bulkin_cb;
 596         req->bulk_completion_reason = 0;
 597         req->bulk_cb_flags = 0;
 598 
 599         flags = 0;
 600         err = usb_pipe_bulk_xfer(dp->bulkin_pipe, req, flags);
 601 
 602         if (err != USB_SUCCESS) {
 603                 cmn_err(CE_WARN, "%s: failed to bulk_xfer for rx, err:%d",
 604                     dp->name, err);
 605 
 606                 /* free req and mp */
 607                 usb_free_bulk_req(req);
 608                 goto err;
 609         }
 610         return (B_TRUE);
 611 err:
 612         return (B_FALSE);
 613 }
 614 
 615 /* ============================================================== */
 616 /*
 617  * Rx/Tx buffer management
 618  */
 619 /* ============================================================== */
 620 static int
 621 usbgem_init_rx_buf(struct usbgem_dev *dp)
 622 {
 623         int     i;
 624         usb_bulk_req_t  *req;
 625 
 626         ASSERT(dp->mac_state == MAC_STATE_ONLINE);
 627 
 628         for (i = 0; i < dp->ugc.usbgc_rx_list_max; i++) {
 629                 req = usb_alloc_bulk_req(dp->dip, 0, USB_FLAGS_SLEEP);
 630                 if (req == NULL) {
 631                         cmn_err(CE_WARN,
 632                             "!%s: %s: failed to allocate bulkreq for rx",
 633                             dp->name, __func__);
 634                         return (USB_FAILURE);
 635                 }
 636                 if (!usbgem_rx_start_unit(dp, req)) {
 637                         return (USB_FAILURE);
 638                 }
 639                 mutex_enter(&dp->rxlock);
 640                 dp->rx_busy_cnt++;
 641                 mutex_exit(&dp->rxlock);
 642         }
 643         return (USB_SUCCESS);
 644 }
 645 
 646 /* ============================================================== */
 647 /*
 648  * memory resource management
 649  */
 650 /* ============================================================== */
 651 static int
 652 usbgem_free_memory(struct usbgem_dev *dp)
 653 {
 654         usb_bulk_req_t  *req;
 655 
 656         /* free all tx requst structure */
 657         while ((req = dp->tx_free_list) != NULL) {
 658                 dp->tx_free_list =
 659                     (usb_bulk_req_t *)req->bulk_client_private;
 660                 req->bulk_data = NULL;
 661                 usb_free_bulk_req(req);
 662         }
 663         return (USB_SUCCESS);
 664 }
 665 
 666 static int
 667 usbgem_alloc_memory(struct usbgem_dev *dp)
 668 {
 669         int     i;
 670         usb_bulk_req_t  *req;
 671 
 672         /* allocate tx requests */
 673         dp->tx_free_list = NULL;
 674         for (i = 0; i < dp->ugc.usbgc_tx_list_max; i++) {
 675                 req = usb_alloc_bulk_req(dp->dip, 0, USB_FLAGS_SLEEP);
 676                 if (req == NULL) {
 677                         cmn_err(CE_WARN,
 678                             "%s:%s failed to allocate tx requests",
 679                             dp->name, __func__);
 680 
 681                         /* free partially allocated tx requests */
 682                         (void) usbgem_free_memory(dp);
 683                         return (USB_FAILURE);
 684                 }
 685 
 686                 /* add the new one allocated into tx free list */
 687                 req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
 688                 dp->tx_free_list = req;
 689         }
 690 
 691         return (USB_SUCCESS);
 692 }
 693 
 694 /* ========================================================== */
 695 /*
 696  * Start transmission.
 697  * Return zero on success,
 698  */
 699 /* ========================================================== */
 700 
 701 #ifdef TXTIMEOUT_TEST
 702 static int usbgem_send_cnt = 0;
 703 #endif
 704 
 705 /*
 706  * usbgem_send is used only to send data packet into ethernet line.
 707  */
 708 static mblk_t *
 709 usbgem_send_common(struct usbgem_dev *dp, mblk_t *mp, uint32_t flags)
 710 {
 711         int             err;
 712         mblk_t          *new;
 713         usb_bulk_req_t  *req;
 714         int             mcast;
 715         int             bcast;
 716         int             len;
 717         boolean_t       intr;
 718         usb_flags_t     usb_flags = 0;
 719 #ifdef USBGEM_DEBUG_LEVEL
 720         usb_pipe_state_t        p_state;
 721 #endif
 722         DPRINTF(2, (CE_CONT, "!%s: %s: called", dp->name, __func__));
 723 
 724         intr = (flags & 1) != 0;
 725         len = msgdsize(mp);
 726         bcast = 0;
 727         mcast = 0;
 728         if (mp->b_rptr[0] & 1) {
 729                 if (bcmp(mp->b_rptr, &usbgem_bcastaddr, ETHERADDRL) == 0) {
 730                         bcast = 1;
 731                 } else {
 732                         mcast = 1;
 733                 }
 734         }
 735         new = (*dp->ugc.usbgc_tx_make_packet)(dp, mp);
 736         if (new == NULL) {
 737                 /*
 738                  * no memory resource. we don't stop downstream,
 739                  * we just discard the packet.
 740                  */
 741                 DPRINTF(0, (CE_CONT, "!%s: %s: no memory",
 742                     dp->name, __func__));
 743                 freemsg(mp);
 744 
 745                 mutex_enter(&dp->txlock);
 746                 dp->stats.noxmtbuf++;
 747                 dp->stats.errxmt++;
 748                 mutex_exit(&dp->txlock);
 749 
 750                 return (NULL);
 751         }
 752 
 753         ASSERT(new->b_cont == NULL);
 754 
 755         mutex_enter(&dp->txlock);
 756         if (dp->tx_free_list == NULL) {
 757                 /*
 758                  * no tx free slot
 759                  */
 760                 ASSERT(dp->tx_busy_cnt == dp->ugc.usbgc_tx_list_max);
 761                 mutex_exit(&dp->txlock);
 762 
 763                 DPRINTF(4, (CE_CONT, "!%s: %s: no free slot",
 764                     dp->name, __func__));
 765                 if (new && new != mp) {
 766                         /* free reallocated message */
 767                         freemsg(new);
 768                 }
 769                 return (mp);
 770         }
 771         req = dp->tx_free_list;
 772         dp->tx_free_list = (usb_bulk_req_t *)req->bulk_client_private;
 773         dp->tx_busy_cnt++;
 774 
 775         if (dp->tx_free_list == NULL) {
 776                 intr = B_TRUE;
 777         }
 778         if (intr) {
 779                 dp->tx_intr_pended++;
 780         }
 781         DB_TCI(new) = intr;
 782 #ifdef USBGEM_DEBUG_LEVEL
 783         new->b_datap->db_cksum32 = dp->tx_seq_num;
 784         dp->tx_seq_num++;
 785 #endif
 786         dp->stats.obytes += len;
 787         dp->stats.opackets++;
 788         if (bcast | mcast) {
 789                 dp->stats.obcast += bcast;
 790                 dp->stats.omcast += mcast;
 791         }
 792         mutex_exit(&dp->txlock);
 793 
 794         DPRINTF(2, (CE_CONT, "!%s: %s: sending", dp->name, __func__));
 795 
 796         req->bulk_len = (long)new->b_wptr - (long)new->b_rptr;
 797         req->bulk_data = new;
 798         req->bulk_client_private = (usb_opaque_t)dp;
 799         req->bulk_timeout = dp->bulkout_timeout;  /* in second */
 800         req->bulk_attributes = 0;
 801         req->bulk_cb = usbgem_bulkout_cb;
 802         req->bulk_exc_cb = usbgem_bulkout_cb;
 803         req->bulk_completion_reason = 0;
 804         req->bulk_cb_flags = 0;
 805 
 806         if (intr) {
 807                 usb_flags = USB_FLAGS_SLEEP;
 808         }
 809         if ((err = usb_pipe_bulk_xfer(dp->bulkout_pipe, req, usb_flags))
 810             != USB_SUCCESS) {
 811 
 812                 /* failed to transfer the packet, discard it. */
 813                 freemsg(new);
 814                 req->bulk_data = NULL;
 815 
 816                 /* recycle the request block */
 817                 mutex_enter(&dp->txlock);
 818                 dp->tx_busy_cnt--;
 819                 req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
 820                 dp->tx_free_list = req;
 821                 mutex_exit(&dp->txlock);
 822 
 823                 cmn_err(CE_NOTE,
 824                     "%s: %s: usb_pipe_bulk_xfer: failed: err:%d",
 825                     dp->name, __func__, err);
 826 
 827                 /* we use another flag to indicate error state. */
 828                 if (dp->fatal_error == (clock_t)0) {
 829                         dp->fatal_error = usbgem_timestamp_nz();
 830                 }
 831         } else {
 832                 /* record the start time */
 833                 dp->tx_start_time = ddi_get_lbolt();
 834         }
 835 
 836         if (err == USB_SUCCESS && (usb_flags & USB_FLAGS_SLEEP)) {
 837                 usbgem_bulkout_cb(dp->bulkout_pipe, req);
 838         }
 839 
 840         if (new != mp) {
 841                 freemsg(mp);
 842         }
 843         return (NULL);
 844 }
 845 
 846 int
 847 usbgem_restart_nic(struct usbgem_dev *dp)
 848 {
 849         int     ret;
 850         int     flags = 0;
 851 
 852         DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
 853 
 854         ASSERT(dp->mac_state != MAC_STATE_DISCONNECTED);
 855 
 856         /*
 857          * ensure to stop the nic
 858          */
 859         if (dp->mac_state == MAC_STATE_ONLINE) {
 860                 (void) usbgem_mac_stop(dp, MAC_STATE_STOPPED, STOP_GRACEFUL);
 861         }
 862 
 863         /* now the nic become quiescent, reset the chip */
 864         if (usbgem_hal_reset_chip(dp) != USB_SUCCESS) {
 865                 cmn_err(CE_WARN, "%s: %s: failed to reset chip",
 866                     dp->name, __func__);
 867                 goto err;
 868         }
 869 
 870         /*
 871          * restore the nic state step by step
 872          */
 873         if (dp->nic_state < NIC_STATE_INITIALIZED) {
 874                 goto done;
 875         }
 876 
 877         if (usbgem_mac_init(dp) != USB_SUCCESS) {
 878                 cmn_err(CE_WARN, "%s: %s: failed to initialize chip",
 879                     dp->name, __func__);
 880                 goto err;
 881         }
 882 
 883         /* setup mac address and enable rx filter */
 884         sema_p(&dp->rxfilter_lock);
 885         dp->rxmode |= RXMODE_ENABLE;
 886         ret = usbgem_hal_set_rx_filter(dp);
 887         sema_v(&dp->rxfilter_lock);
 888         if (ret != USB_SUCCESS) {
 889                 goto err;
 890         }
 891 
 892         /*
 893          * update the link state asynchronously
 894          */
 895         cv_signal(&dp->link_watcher_wait_cv);
 896 
 897         /*
 898          * XXX - a panic happened because of linkdown.
 899          * We must check mii_state here, because the link can be down just
 900          * before the restart event happen. If the link is down now,
 901          * gem_mac_start() will be called from gem_mii_link_check() when
 902          * the link become up later.
 903          */
 904         if (dp->mii_state == MII_STATE_LINKUP) {
 905                 if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
 906                         goto err;
 907                 }
 908                 if (dp->nic_state < NIC_STATE_ONLINE) {
 909                         goto done;
 910                 }
 911 
 912                 (void) usbgem_mac_start(dp);
 913 
 914         }
 915 done:
 916         return (USB_SUCCESS);
 917 err:
 918 #ifdef GEM_CONFIG_FMA
 919         ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
 920 #endif
 921         return (USB_FAILURE);
 922 }
 923 
 924 static void
 925 usbgem_tx_timeout(struct usbgem_dev *dp)
 926 {
 927         uint_t  rwlock;
 928         clock_t now;
 929 
 930         for (; ; ) {
 931                 mutex_enter(&dp->tx_watcher_lock);
 932                 (void) cv_timedwait(&dp->tx_watcher_cv, &dp->tx_watcher_lock,
 933                     dp->tx_watcher_interval + ddi_get_lbolt());
 934                 mutex_exit(&dp->tx_watcher_lock);
 935 
 936                 if (dp->tx_watcher_stop) {
 937                         break;
 938                 }
 939 
 940                 now = ddi_get_lbolt();
 941 
 942                 rwlock = RW_READER;
 943 again:
 944                 rw_enter(&dp->dev_state_lock, rwlock);
 945 
 946                 if ((dp->mac_state != MAC_STATE_DISCONNECTED &&
 947                     dp->fatal_error &&
 948                     now - dp->fatal_error >= dp->ugc.usbgc_tx_timeout) ||
 949                     (dp->mac_state == MAC_STATE_ONLINE &&
 950                     dp->mii_state == MII_STATE_LINKUP &&
 951                     dp->tx_busy_cnt != 0 &&
 952                     now - dp->tx_start_time >= dp->ugc.usbgc_tx_timeout)) {
 953                         if (rwlock == RW_READER) {
 954                                 /*
 955                                  * Upgrade dev_state_lock from shared mode
 956                                  * to exclusive mode to restart nic
 957                                  */
 958                                 rwlock = RW_WRITER;
 959                                 rw_exit(&dp->dev_state_lock);
 960                                 goto again;
 961                         }
 962                         cmn_err(CE_WARN, "%s: %s: restarting the nic:"
 963                             " fatal_error:%ld nic_state:%d"
 964                             " mac_state:%d starttime:%ld",
 965                             dp->name, __func__,
 966                             dp->fatal_error ? now - dp->fatal_error: 0,
 967                             dp->nic_state, dp->mac_state,
 968                             dp->tx_busy_cnt ? now - dp->tx_start_time : 0);
 969 
 970                         (void) usbgem_restart_nic(dp);
 971                 }
 972 
 973                 rw_exit(&dp->dev_state_lock);
 974         }
 975 }
 976 
 977 static int
 978 usbgem_tx_watcher_start(struct usbgem_dev *dp)
 979 {
 980         int     err;
 981         kthread_t       *wdth;
 982 
 983         DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
 984 
 985         /* make a first call of uwgem_lw_link_check() */
 986         dp->tx_watcher_stop = 0;
 987         dp->tx_watcher_interval = drv_usectohz(1000*1000);
 988 
 989         wdth = thread_create(NULL, 0, usbgem_tx_timeout, dp, 0, &p0,
 990             TS_RUN, minclsyspri);
 991         if (wdth == NULL) {
 992                 cmn_err(CE_WARN,
 993                     "!%s: %s: failed to create a tx_watcher thread",
 994                     dp->name, __func__);
 995                 return (USB_FAILURE);
 996         }
 997         dp->tx_watcher_did = wdth->t_did;
 998 
 999         return (USB_SUCCESS);
1000 }
1001 
1002 static void
1003 usbgem_tx_watcher_stop(struct usbgem_dev *dp)
1004 {
1005         DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
1006         if (dp->tx_watcher_did) {
1007                 /* Ensure timer routine stopped */
1008                 dp->tx_watcher_stop = 1;
1009                 cv_signal(&dp->tx_watcher_cv);
1010                 thread_join(dp->tx_watcher_did);
1011                 dp->tx_watcher_did = 0;
1012         }
1013 }
1014 
1015 /* ================================================================== */
1016 /*
1017  * Callback handlers
1018  */
1019 /* ================================================================== */
1020 static void
1021 usbgem_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1022 {
1023         mblk_t  *newmp;
1024         mblk_t  *mp;
1025         mblk_t  *tp;
1026         uint64_t        len = 0;
1027         int     pkts = 0;
1028         int     bcast = 0;
1029         int     mcast = 0;
1030         boolean_t       busy;
1031         struct usbgem_dev       *dp;
1032 
1033         dp = (struct usbgem_dev *)req->bulk_client_private;
1034         mp = req->bulk_data;
1035         req->bulk_data = NULL;
1036 
1037         DPRINTF(2, (CE_CONT, "!%s: %s: mp:%p, cr:%s(%d)",
1038             dp->name, __func__, mp,
1039             usb_str_cr(req->bulk_completion_reason),
1040             req->bulk_completion_reason));
1041 
1042         /*
1043          * we cannot acquire dev_state_lock because the routine
1044          * must be executed during usbgem_mac_stop() to avoid
1045          * dead lock.
1046          * we use a simle membar operation to get the state correctly.
1047          */
1048         membar_consumer();
1049 
1050         if (req->bulk_completion_reason == USB_CR_OK &&
1051             dp->nic_state == NIC_STATE_ONLINE) {
1052                 newmp = (*dp->ugc.usbgc_rx_make_packet)(dp, mp);
1053 
1054                 if (newmp != mp) {
1055                         /* the message has been reallocated, free old one */
1056                         freemsg(mp);
1057                 }
1058 
1059                 /* the message may includes one or more ethernet packets */
1060                 for (tp = newmp; tp; tp = tp->b_next) {
1061                         len += (uintptr_t)tp->b_wptr - (uintptr_t)tp->b_rptr;
1062                         pkts++;
1063                         if (tp->b_rptr[0] & 1) {
1064                                 if (bcmp(tp->b_rptr, &usbgem_bcastaddr,
1065                                     ETHERADDRL) == 0) {
1066                                         bcast++;
1067                                 } else {
1068                                         mcast++;
1069                                 }
1070                         }
1071                 }
1072 
1073                 /* send up if it is a valid packet */
1074 #ifdef USBGEM_CONFIG_GLDv3
1075                 mac_rx(dp->mh, NULL, newmp);
1076 #else
1077                 while (newmp) {
1078                         tp = newmp;
1079                         newmp = newmp->b_next;
1080                         tp->b_next = NULL;
1081                         gld_recv(dp->macinfo, tp);
1082                 }
1083 #endif
1084         } else {
1085                 freemsg(mp);
1086                 len = 0;
1087         }
1088 
1089         mutex_enter(&dp->rxlock);
1090         /* update rx_active */
1091         if (dp->rx_active) {
1092                 dp->rx_active = dp->mac_state == MAC_STATE_ONLINE;
1093         }
1094 
1095         dp->stats.rbytes += len;
1096         dp->stats.rpackets += pkts;
1097         if (bcast | mcast) {
1098                 dp->stats.rbcast += bcast;
1099                 dp->stats.rmcast += mcast;
1100         }
1101         mutex_exit(&dp->rxlock);
1102 
1103         if (dp->rx_active) {
1104                 /* prepare to receive the next packets */
1105                 if (usbgem_rx_start_unit(dp, req)) {
1106                         /* we successed */
1107                         goto done;
1108                 }
1109                 cmn_err(CE_WARN,
1110                     "!%s: %s: failed to fill next rx packet",
1111                     dp->name, __func__);
1112                 /*
1113                  * we use another flag to indicate error state.
1114                  * if we acquire dev_state_lock for RW_WRITER here,
1115                  * usbgem_mac_stop() may hang.
1116                  */
1117                 if (dp->fatal_error == (clock_t)0) {
1118                         dp->fatal_error = usbgem_timestamp_nz();
1119                 }
1120         } else {
1121                 /* no need to prepare the next packets */
1122                 usb_free_bulk_req(req);
1123         }
1124 
1125         mutex_enter(&dp->rxlock);
1126         dp->rx_active = B_FALSE;
1127         dp->rx_busy_cnt--;
1128         if (dp->rx_busy_cnt == 0) {
1129                 /* wake up someone waits for me */
1130                 cv_broadcast(&dp->rx_drain_cv);
1131         }
1132         mutex_exit(&dp->rxlock);
1133 done:
1134         ;
1135 }
1136 
1137 static void
1138 usbgem_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1139 {
1140         boolean_t       intr;
1141         boolean_t       tx_sched;
1142         struct usbgem_dev       *dp;
1143 
1144         dp = (struct usbgem_dev *)req->bulk_client_private;
1145         tx_sched = B_FALSE;
1146 
1147         DPRINTF(2, (CE_CONT,
1148             "!%s: %s: cr:%s(%d) cb_flags:0x%x head:%d tail:%d",
1149             dp->name, __func__,
1150             usb_str_cr(req->bulk_completion_reason),
1151             req->bulk_completion_reason,
1152             req->bulk_cb_flags,
1153             dp->tx_busy_cnt));
1154 
1155         /* we have finished to transfer the packet into tx fifo */
1156         intr = DB_TCI(req->bulk_data);
1157         freemsg(req->bulk_data);
1158 
1159         if (req->bulk_completion_reason != USB_CR_OK &&
1160             dp->fatal_error == (clock_t)0) {
1161                 dp->fatal_error = usbgem_timestamp_nz();
1162         }
1163 
1164         mutex_enter(&dp->txlock);
1165 
1166         if (intr) {
1167                 ASSERT(dp->tx_intr_pended > 0);
1168                 /* find the last interrupt we have scheduled */
1169                 if (--(dp->tx_intr_pended) == 0) {
1170                         tx_sched = B_TRUE;
1171                 }
1172         }
1173 
1174         ASSERT(dp->tx_busy_cnt > 0);
1175         req->bulk_client_private = (usb_opaque_t)dp->tx_free_list;
1176         dp->tx_free_list = req;
1177         dp->tx_busy_cnt--;
1178 
1179 #ifdef CONFIG_TX_LIMITER
1180         if (tx_sched) {
1181                 dp->tx_max_packets =
1182                     min(dp->tx_max_packets + 1, dp->ugc.usbgc_tx_list_max);
1183         }
1184 #endif
1185         if (dp->mac_state != MAC_STATE_ONLINE && dp->tx_busy_cnt == 0) {
1186                 cv_broadcast(&dp->tx_drain_cv);
1187         }
1188 
1189         mutex_exit(&dp->txlock);
1190 
1191         if (tx_sched) {
1192 #ifdef USBGEM_CONFIG_GLDv3
1193                 mac_tx_update(dp->mh);
1194 #else
1195                 gld_sched(dp->macinfo);
1196 #endif
1197         }
1198 }
1199 
1200 static void
1201 usbgem_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
1202 {
1203         struct usbgem_dev       *dp;
1204 
1205         dp = (struct usbgem_dev *)req->intr_client_private;
1206         dp->stats.intr++;
1207 
1208         if (req->intr_completion_reason == USB_CR_OK) {
1209                 (*dp->ugc.usbgc_interrupt)(dp, req->intr_data);
1210         }
1211 
1212         /* free the request and data */
1213         usb_free_intr_req(req);
1214 }
1215 
1216 /* ======================================================================== */
1217 /*
1218  * MII support routines
1219  */
1220 /* ======================================================================== */
1221 static void
1222 usbgem_choose_forcedmode(struct usbgem_dev *dp)
1223 {
1224         /* choose media mode */
1225         if (dp->anadv_1000fdx || dp->anadv_1000hdx) {
1226                 dp->speed = USBGEM_SPD_1000;
1227                 dp->full_duplex = dp->anadv_1000fdx;
1228         } else if (dp->anadv_100fdx || dp->anadv_100t4) {
1229                 dp->speed = USBGEM_SPD_100;
1230                 dp->full_duplex = B_TRUE;
1231         } else if (dp->anadv_100hdx) {
1232                 dp->speed = USBGEM_SPD_100;
1233                 dp->full_duplex = B_FALSE;
1234         } else {
1235                 dp->speed = USBGEM_SPD_10;
1236                 dp->full_duplex = dp->anadv_10fdx;
1237         }
1238 }
1239 
1240 static uint16_t
1241 usbgem_mii_read(struct usbgem_dev *dp, uint_t reg, int *errp)
1242 {
1243         uint16_t        val;
1244 
1245         sema_p(&dp->hal_op_lock);
1246         val = (*dp->ugc.usbgc_mii_read)(dp, reg, errp);
1247         sema_v(&dp->hal_op_lock);
1248 
1249         return (val);
1250 }
1251 
1252 static void
1253 usbgem_mii_write(struct usbgem_dev *dp, uint_t reg, uint16_t val, int *errp)
1254 {
1255         sema_p(&dp->hal_op_lock);
1256         (*dp->ugc.usbgc_mii_write)(dp, reg, val, errp);
1257         sema_v(&dp->hal_op_lock);
1258 }
1259 
1260 static int
1261 usbgem_mii_probe(struct usbgem_dev *dp)
1262 {
1263         int     err;
1264 
1265         err = (*dp->ugc.usbgc_mii_probe)(dp);
1266         return (err);
1267 }
1268 
1269 static int
1270 usbgem_mii_init(struct usbgem_dev *dp)
1271 {
1272         int     err;
1273 
1274         err = (*dp->ugc.usbgc_mii_init)(dp);
1275         return (err);
1276 }
1277 
1278 #define fc_cap_decode(x)        \
1279         ((((x) & MII_ABILITY_PAUSE) != 0 ? 1 : 0) | \
1280         (((x) & MII_ABILITY_ASM_DIR) != 0 ? 2 : 0))
1281 
1282 int
1283 usbgem_mii_config_default(struct usbgem_dev *dp, int *errp)
1284 {
1285         uint16_t        mii_stat;
1286         uint16_t        val;
1287 
1288         DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
1289 
1290         /*
1291          * Configure bits in advertisement register
1292          */
1293         mii_stat = dp->mii_status;
1294 
1295         DPRINTF(1, (CE_CONT, "!%s: %s: MII_STATUS reg:%b",
1296             dp->name, __func__, mii_stat, MII_STATUS_BITS));
1297 
1298         if ((mii_stat & MII_STATUS_ABILITY_TECH) == 0) {
1299                 /* it's funny */
1300                 cmn_err(CE_WARN, "!%s: wrong ability bits: mii_status:%b",
1301                     dp->name, mii_stat, MII_STATUS_BITS);
1302                 return (USB_FAILURE);
1303         }
1304 
1305         /* Do not change the rest of ability bits in advert reg */
1306         val = usbgem_mii_read(dp, MII_AN_ADVERT, errp) & ~MII_ABILITY_ALL;
1307         if (*errp != USB_SUCCESS) {
1308                 goto usberr;
1309         }
1310 
1311         DPRINTF(0, (CE_CONT,
1312             "!%s: %s: 100T4:%d 100F:%d 100H:%d 10F:%d 10H:%d",
1313             dp->name, __func__,
1314             dp->anadv_100t4, dp->anadv_100fdx, dp->anadv_100hdx,
1315             dp->anadv_10fdx, dp->anadv_10hdx));
1316 
1317         /* set technology bits */
1318         if (dp->anadv_100t4) {
1319                 val |= MII_ABILITY_100BASE_T4;
1320         }
1321         if (dp->anadv_100fdx) {
1322                 val |= MII_ABILITY_100BASE_TX_FD;
1323         }
1324         if (dp->anadv_100hdx) {
1325                 val |= MII_ABILITY_100BASE_TX;
1326         }
1327         if (dp->anadv_10fdx) {
1328                 val |= MII_ABILITY_10BASE_T_FD;
1329         }
1330         if (dp->anadv_10hdx) {
1331                 val |= MII_ABILITY_10BASE_T;
1332         }
1333 
1334         /* set flow control capabilities */
1335         if (dp->anadv_pause) {
1336                 val |= MII_ABILITY_PAUSE;
1337         }
1338         if (dp->anadv_asmpause) {
1339                 val |= MII_ABILITY_ASM_DIR;
1340         }
1341 
1342         DPRINTF(0, (CE_CONT,
1343             "!%s: %s: setting MII_AN_ADVERT reg:%b, pause:%d, asmpause:%d",
1344             dp->name, __func__, val, MII_ABILITY_BITS,
1345             dp->anadv_pause, dp->anadv_asmpause));
1346 
1347         usbgem_mii_write(dp, MII_AN_ADVERT, val, errp);
1348         if (*errp != USB_SUCCESS) {
1349                 goto usberr;
1350         }
1351 
1352         if (dp->mii_status & MII_STATUS_XSTATUS) {
1353                 /*
1354                  * 1000Base-T GMII support
1355                  */
1356                 if (!dp->anadv_autoneg) {
1357                         /* enable manual configuration */
1358                         val = MII_1000TC_CFG_EN;
1359                         if (dp->anadv_1000t_ms == 2) {
1360                                 val |= MII_1000TC_CFG_VAL;
1361                         }
1362                 } else {
1363                         val = 0;
1364                         if (dp->anadv_1000fdx) {
1365                                 val |= MII_1000TC_ADV_FULL;
1366                         }
1367                         if (dp->anadv_1000hdx) {
1368                                 val |= MII_1000TC_ADV_HALF;
1369                         }
1370                         switch (dp->anadv_1000t_ms) {
1371                         case 1:
1372                                 /* slave */
1373                                 val |= MII_1000TC_CFG_EN;
1374                                 break;
1375 
1376                         case 2:
1377                                 /* master */
1378                                 val |= MII_1000TC_CFG_EN | MII_1000TC_CFG_VAL;
1379                                 break;
1380 
1381                         default:
1382                                 /* auto: do nothing */
1383                                 break;
1384                         }
1385                 }
1386                 DPRINTF(0, (CE_CONT,
1387                     "!%s: %s: setting MII_1000TC reg:%b",
1388                     dp->name, __func__, val, MII_1000TC_BITS));
1389 
1390                 usbgem_mii_write(dp, MII_1000TC, val, errp);
1391                 if (*errp != USB_SUCCESS) {
1392                         goto usberr;
1393                 }
1394         }
1395         return (USB_SUCCESS);
1396 
1397 usberr:
1398         return (*errp);
1399 }
1400 
1401 static char *usbgem_fc_type[] = {
1402         "without",
1403         "with symmetric",
1404         "with tx",
1405         "with rx",
1406 };
1407 
1408 #ifdef USBGEM_CONFIG_GLDv3
1409 #define USBGEM_LINKUP(dp)       mac_link_update((dp)->mh, LINK_STATE_UP)
1410 #define USBGEM_LINKDOWN(dp)     mac_link_update((dp)->mh, LINK_STATE_DOWN)
1411 #else
1412 #define USBGEM_LINKUP(dp)       \
1413         if (gld_linkstate) {    \
1414                 gld_linkstate((dp)->macinfo, GLD_LINKSTATE_UP);      \
1415         }
1416 #define USBGEM_LINKDOWN(dp)     \
1417         if (gld_linkstate) {    \
1418                 gld_linkstate((dp)->macinfo, GLD_LINKSTATE_DOWN);    \
1419         }
1420 #endif
1421 
1422 static uint8_t usbgem_fc_result[4 /* my cap */][4 /* lp cap */] = {
1423 /*       none   symm    tx      rx/symm */
1424 /* none */
1425         {FLOW_CONTROL_NONE,
1426                 FLOW_CONTROL_NONE,
1427                         FLOW_CONTROL_NONE,
1428                                 FLOW_CONTROL_NONE},
1429 /* sym */
1430         {FLOW_CONTROL_NONE,
1431                 FLOW_CONTROL_SYMMETRIC,
1432                         FLOW_CONTROL_NONE,
1433                                 FLOW_CONTROL_SYMMETRIC},
1434 /* tx */
1435         {FLOW_CONTROL_NONE,
1436                 FLOW_CONTROL_NONE,
1437                         FLOW_CONTROL_NONE,
1438                                 FLOW_CONTROL_TX_PAUSE},
1439 /* rx/symm */
1440         {FLOW_CONTROL_NONE,
1441                 FLOW_CONTROL_SYMMETRIC,
1442                         FLOW_CONTROL_RX_PAUSE,
1443                                 FLOW_CONTROL_SYMMETRIC},
1444 };
1445 
1446 static boolean_t
1447 usbgem_mii_link_check(struct usbgem_dev *dp, int *oldstatep, int *newstatep)
1448 {
1449         boolean_t       tx_sched = B_FALSE;
1450         uint16_t        status;
1451         uint16_t        advert;
1452         uint16_t        lpable;
1453         uint16_t        exp;
1454         uint16_t        ctl1000;
1455         uint16_t        stat1000;
1456         uint16_t        val;
1457         clock_t         now;
1458         clock_t         diff;
1459         int             linkdown_action;
1460         boolean_t       fix_phy = B_FALSE;
1461         int             err;
1462         uint_t          rwlock;
1463 
1464         DPRINTF(4, (CE_CONT, "!%s: %s: time:%d state:%d",
1465             dp->name, __func__, ddi_get_lbolt(), dp->mii_state));
1466 
1467         if (dp->mii_state != MII_STATE_LINKUP) {
1468                 rwlock = RW_WRITER;
1469         } else {
1470                 rwlock = RW_READER;
1471         }
1472 again:
1473         rw_enter(&dp->dev_state_lock, rwlock);
1474 
1475         /* save old mii state */
1476         *oldstatep = dp->mii_state;
1477 
1478         if (dp->mac_state == MAC_STATE_DISCONNECTED) {
1479                 /* stop periodic execution of the link watcher */
1480                 dp->mii_interval = 0;
1481                 tx_sched = B_FALSE;
1482                 goto next;
1483         }
1484 
1485         now = ddi_get_lbolt();
1486         diff = now - dp->mii_last_check;
1487         dp->mii_last_check = now;
1488 
1489         /*
1490          * For NWAM, don't show linkdown state right
1491          * when the device is attached.
1492          */
1493         if (dp->linkup_delay > 0) {
1494                 if (dp->linkup_delay > diff) {
1495                         dp->linkup_delay -= diff;
1496                 } else {
1497                         /* link up timeout */
1498                         dp->linkup_delay = -1;
1499                 }
1500         }
1501 
1502 next_nowait:
1503         switch (dp->mii_state) {
1504         case MII_STATE_UNKNOWN:
1505                 goto reset_phy;
1506 
1507         case MII_STATE_RESETTING:
1508                 dp->mii_timer -= diff;
1509                 if (dp->mii_timer > 0) {
1510                         /* don't read phy registers in resetting */
1511                         dp->mii_interval = WATCH_INTERVAL_FAST;
1512                         goto next;
1513                 }
1514 
1515                 val = usbgem_mii_read(dp, MII_CONTROL, &err);
1516                 if (err != USB_SUCCESS) {
1517                         goto usberr;
1518                 }
1519                 if (val & MII_CONTROL_RESET) {
1520                         cmn_err(CE_NOTE,
1521                             "!%s: time:%ld resetting phy not complete."
1522                             " mii_control:0x%b",
1523                             dp->name, ddi_get_lbolt(),
1524                             val, MII_CONTROL_BITS);
1525                 }
1526 
1527                 /* ensure neither isolated nor pwrdown nor auto-nego mode */
1528                 usbgem_mii_write(dp, MII_CONTROL, 0, &err);
1529                 if (err != USB_SUCCESS) {
1530                         goto usberr;
1531                 }
1532 #if USBGEM_DEBUG_LEVEL > 10
1533                 val = usbgem_mii_read(dp, MII_CONTROL, &err);
1534                 cmn_err(CE_CONT, "!%s: readback control %b",
1535                     dp->name, val, MII_CONTROL_BITS);
1536 #endif
1537                 /* As resetting PHY has completed, configure PHY registers */
1538                 if ((*dp->ugc.usbgc_mii_config)(dp, &err) != USB_SUCCESS) {
1539                         /* we failed to configure PHY */
1540                         goto usberr;
1541                 }
1542 
1543                 /* prepare for forced mode */
1544                 usbgem_choose_forcedmode(dp);
1545 
1546                 dp->mii_lpable = 0;
1547                 dp->mii_advert = 0;
1548                 dp->mii_exp = 0;
1549                 dp->mii_ctl1000 = 0;
1550                 dp->mii_stat1000 = 0;
1551 
1552                 dp->flow_control = FLOW_CONTROL_NONE;
1553 
1554                 if (!dp->anadv_autoneg) {
1555                         /* skip auto-negotiation phase */
1556                         dp->mii_state = MII_STATE_MEDIA_SETUP;
1557                         dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1558                         goto next_nowait;
1559                 }
1560 
1561                 /* issue an auto-negotiation command */
1562                 goto autonego;
1563 
1564         case MII_STATE_AUTONEGOTIATING:
1565                 /*
1566                  * Autonegotiation in progress
1567                  */
1568                 dp->mii_timer -= diff;
1569                 if (dp->mii_timer -
1570                     (dp->ugc.usbgc_mii_an_timeout - dp->ugc.usbgc_mii_an_wait)
1571                     > 0) {
1572                         /* wait for minimum time (2.3 - 2.5 sec) */
1573                         dp->mii_interval = WATCH_INTERVAL_FAST;
1574                         goto next;
1575                 }
1576 
1577                 /* read PHY status */
1578                 status = usbgem_mii_read(dp, MII_STATUS, &err);
1579                 if (err != USB_SUCCESS) {
1580                         goto usberr;
1581                 }
1582                 DPRINTF(4, (CE_CONT,
1583                     "!%s: %s: called: mii_state:%d MII_STATUS reg:%b",
1584                     dp->name, __func__, dp->mii_state,
1585                     status, MII_STATUS_BITS));
1586 
1587                 if (status & MII_STATUS_REMFAULT) {
1588                         /*
1589                          * The link parnert told me something wrong happend.
1590                          * What do we do ?
1591                          */
1592                         cmn_err(CE_CONT,
1593                             "!%s: auto-negotiation failed: remote fault",
1594                             dp->name);
1595                         goto autonego;
1596                 }
1597 
1598                 if ((status & MII_STATUS_ANDONE) == 0) {
1599                         if (dp->mii_timer <= 0) {
1600                                 /*
1601                                  * Auto-negotiation has been timed out,
1602                                  * Reset PHY and try again.
1603                                  */
1604                                 if (!dp->mii_supress_msg) {
1605                                         cmn_err(CE_WARN,
1606                                             "!%s: auto-negotiation failed:"
1607                                             " timeout",
1608                                             dp->name);
1609                                         dp->mii_supress_msg = B_TRUE;
1610                                 }
1611                                 goto autonego;
1612                         }
1613                         /*
1614                          * Auto-negotiation is in progress. Wait for a while.
1615                          */
1616                         dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
1617                         goto next;
1618                 }
1619 
1620                 /*
1621                  * Auto-negotiation has been completed. Let's go to AN_DONE.
1622                  */
1623                 dp->mii_state = MII_STATE_AN_DONE;
1624                 dp->mii_supress_msg = B_FALSE;
1625                 DPRINTF(0, (CE_CONT,
1626                     "!%s: auto-negotiation completed, MII_STATUS:%b",
1627                     dp->name, status, MII_STATUS_BITS));
1628 
1629                 if (dp->ugc.usbgc_mii_an_delay > 0) {
1630                         dp->mii_timer = dp->ugc.usbgc_mii_an_delay;
1631                         dp->mii_interval = drv_usectohz(20*1000);
1632                         goto next;
1633                 }
1634 
1635                 dp->mii_timer = 0;
1636                 diff = 0;
1637                 goto next_nowait;
1638 
1639         case MII_STATE_AN_DONE:
1640                 /*
1641                  * Auto-negotiation has done. Now we can set up media.
1642                  */
1643                 dp->mii_timer -= diff;
1644                 if (dp->mii_timer > 0) {
1645                         /* wait for a while */
1646                         dp->mii_interval = WATCH_INTERVAL_FAST;
1647                         goto next;
1648                 }
1649 
1650                 /*
1651                  * Setup speed and duplex mode according with
1652                  * the result of auto negotiation.
1653                  */
1654 
1655                 /*
1656                  * Read registers required to determin current
1657                  * duplex mode and media speed.
1658                  */
1659                 if (dp->ugc.usbgc_mii_an_delay > 0) {
1660                         /* the 'status' variable is not initialized yet */
1661                         status = usbgem_mii_read(dp, MII_STATUS, &err);
1662                         if (err != USB_SUCCESS) {
1663                                 goto usberr;
1664                         }
1665                 }
1666                 advert = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
1667                 if (err != USB_SUCCESS) {
1668                         goto usberr;
1669                 }
1670                 lpable = usbgem_mii_read(dp, MII_AN_LPABLE, &err);
1671                 if (err != USB_SUCCESS) {
1672                         goto usberr;
1673                 }
1674                 exp = usbgem_mii_read(dp, MII_AN_EXPANSION, &err);
1675                 if (err != USB_SUCCESS) {
1676                         goto usberr;
1677                 }
1678                 if (exp == 0xffff) {
1679                         /* some phys don't have exp register */
1680                         exp = 0;
1681                 }
1682 
1683                 ctl1000 = 0;
1684                 stat1000 = 0;
1685                 if (dp->mii_status & MII_STATUS_XSTATUS) {
1686                         ctl1000 = usbgem_mii_read(dp, MII_1000TC, &err);
1687                         if (err != USB_SUCCESS) {
1688                                 goto usberr;
1689                         }
1690                         stat1000 = usbgem_mii_read(dp, MII_1000TS, &err);
1691                         if (err != USB_SUCCESS) {
1692                                 goto usberr;
1693                         }
1694                 }
1695                 dp->mii_lpable = lpable;
1696                 dp->mii_advert = advert;
1697                 dp->mii_exp = exp;
1698                 dp->mii_ctl1000 = ctl1000;
1699                 dp->mii_stat1000 = stat1000;
1700 
1701                 cmn_err(CE_CONT,
1702                     "!%s: auto-negotiation done: "
1703                     "status:%b, advert:%b, lpable:%b, exp:%b",
1704                     dp->name,
1705                     status, MII_STATUS_BITS,
1706                     advert, MII_ABILITY_BITS,
1707                     lpable, MII_ABILITY_BITS,
1708                     exp, MII_AN_EXP_BITS);
1709 
1710                 DPRINTF(0, (CE_CONT, "!%s: MII_STATUS:%b",
1711                     dp->name, status, MII_STATUS_BITS));
1712 
1713                 if (dp->mii_status & MII_STATUS_XSTATUS) {
1714                         cmn_err(CE_CONT,
1715                             "! MII_1000TC reg:%b, MII_1000TS reg:%b",
1716                             ctl1000, MII_1000TC_BITS,
1717                             stat1000, MII_1000TS_BITS);
1718                 }
1719 
1720                 if (usbgem_population(lpable) <= 1 &&
1721                     (exp & MII_AN_EXP_LPCANAN) == 0) {
1722                         if ((advert & MII_ABILITY_TECH) != lpable) {
1723                                 cmn_err(CE_WARN,
1724                                     "!%s: but the link partner doesn't seem"
1725                                     " to have auto-negotiation capability."
1726                                     " please check the link configuration.",
1727                                     dp->name);
1728                         }
1729                         /*
1730                          * it should be a result of pararell detection,
1731                          * which cannot detect duplex mode.
1732                          */
1733                         if ((advert & lpable) == 0 &&
1734                             lpable & MII_ABILITY_10BASE_T) {
1735                                 /* no common technology, try 10M half mode */
1736                                 lpable |= advert & MII_ABILITY_10BASE_T;
1737                                 fix_phy = B_TRUE;
1738                         }
1739                 } else if (lpable == 0) {
1740                         cmn_err(CE_WARN, "!%s: wrong lpable.", dp->name);
1741                         goto reset_phy;
1742                 }
1743                 /*
1744                  * configure current link mode according to AN priority.
1745                  */
1746                 val = advert & lpable;
1747                 if ((ctl1000 & MII_1000TC_ADV_FULL) &&
1748                     (stat1000 & MII_1000TS_LP_FULL)) {
1749                         /* 1000BaseT & full duplex */
1750                         dp->speed = USBGEM_SPD_1000;
1751                         dp->full_duplex = B_TRUE;
1752                 } else if ((ctl1000 & MII_1000TC_ADV_HALF) &&
1753                     (stat1000 & MII_1000TS_LP_HALF)) {
1754                         /* 1000BaseT & half duplex */
1755                         dp->speed = USBGEM_SPD_1000;
1756                         dp->full_duplex = B_FALSE;
1757                 } else if ((val & MII_ABILITY_100BASE_TX_FD)) {
1758                         /* 100BaseTx & fullduplex */
1759                         dp->speed = USBGEM_SPD_100;
1760                         dp->full_duplex = B_TRUE;
1761                 } else if ((val & MII_ABILITY_100BASE_T4)) {
1762                         /* 100BaseTx & fullduplex */
1763                         dp->speed = USBGEM_SPD_100;
1764                         dp->full_duplex = B_TRUE;
1765                 } else if ((val & MII_ABILITY_100BASE_TX)) {
1766                         /* 100BaseTx & half duplex */
1767                         dp->speed = USBGEM_SPD_100;
1768                         dp->full_duplex = B_FALSE;
1769                 } else if ((val & MII_ABILITY_10BASE_T_FD)) {
1770                         /* 10BaseT & full duplex */
1771                         dp->speed = USBGEM_SPD_10;
1772                         dp->full_duplex = B_TRUE;
1773                 } else if ((val & MII_ABILITY_10BASE_T)) {
1774                         /* 10BaseT & half duplex */
1775                         dp->speed = USBGEM_SPD_10;
1776                         dp->full_duplex = B_FALSE;
1777                 } else {
1778                         /*
1779                          * the link partner doesn't seem to have
1780                          * auto-negotiation capability and our PHY
1781                          * could not report current mode correctly.
1782                          * We guess current mode by mii_control register.
1783                          */
1784                         val = usbgem_mii_read(dp, MII_CONTROL, &err);
1785                         if (err != USB_SUCCESS) {
1786                                 goto usberr;
1787                         }
1788 
1789                         /* select 100m half or 10m half */
1790                         dp->speed = (val & MII_CONTROL_100MB) ?
1791                             USBGEM_SPD_100 : USBGEM_SPD_10;
1792                         dp->full_duplex = B_FALSE;
1793                         fix_phy = B_TRUE;
1794 
1795                         cmn_err(CE_NOTE,
1796                             "!%s: auto-negotiation done but "
1797                             "common ability not found.\n"
1798                             "PHY state: control:%b advert:%b lpable:%b\n"
1799                             "guessing %d Mbps %s duplex mode",
1800                             dp->name,
1801                             val, MII_CONTROL_BITS,
1802                             advert, MII_ABILITY_BITS,
1803                             lpable, MII_ABILITY_BITS,
1804                             usbgem_speed_value[dp->speed],
1805                             dp->full_duplex ? "full" : "half");
1806                 }
1807 
1808                 if (dp->full_duplex) {
1809                         dp->flow_control =
1810                             usbgem_fc_result[fc_cap_decode(advert)]
1811                             [fc_cap_decode(lpable)];
1812                 } else {
1813                         dp->flow_control = FLOW_CONTROL_NONE;
1814                 }
1815                 dp->mii_state = MII_STATE_MEDIA_SETUP;
1816                 dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1817                 goto next_nowait;
1818 
1819         case MII_STATE_MEDIA_SETUP:
1820                 DPRINTF(2, (CE_CONT, "!%s: setup midia mode", dp->name));
1821 
1822                 /* assume the link state is down */
1823                 dp->mii_state = MII_STATE_LINKDOWN;
1824                 dp->mii_supress_msg = B_FALSE;
1825 
1826                 /* use short interval */
1827                 dp->mii_interval = WATCH_INTERVAL_FAST;
1828 
1829                 if ((!dp->anadv_autoneg) ||
1830                     dp->ugc.usbgc_mii_an_oneshot || fix_phy) {
1831 
1832                         /*
1833                          * write the result of auto negotiation back.
1834                          */
1835                         val = usbgem_mii_read(dp, MII_CONTROL, &err);
1836                         if (err != USB_SUCCESS) {
1837                                 goto usberr;
1838                         }
1839                         val &= ~(MII_CONTROL_SPEED | MII_CONTROL_FDUPLEX |
1840                             MII_CONTROL_ANE   | MII_CONTROL_RSAN);
1841 
1842                         if (dp->full_duplex) {
1843                                 val |= MII_CONTROL_FDUPLEX;
1844                         }
1845 
1846                         switch (dp->speed) {
1847                         case USBGEM_SPD_1000:
1848                                 val |= MII_CONTROL_1000MB;
1849                                 break;
1850 
1851                         case USBGEM_SPD_100:
1852                                 val |= MII_CONTROL_100MB;
1853                                 break;
1854 
1855                         default:
1856                                 cmn_err(CE_WARN, "%s: unknown speed:%d",
1857                                     dp->name, dp->speed);
1858                                 /* FALLTHROUGH */
1859 
1860                         case USBGEM_SPD_10:
1861                                 /* for USBGEM_SPD_10, do nothing */
1862                                 break;
1863                         }
1864 
1865                         if (dp->mii_status & MII_STATUS_XSTATUS) {
1866                                 usbgem_mii_write(dp,
1867                                     MII_1000TC, MII_1000TC_CFG_EN, &err);
1868                                 if (err != USB_SUCCESS) {
1869                                         goto usberr;
1870                                 }
1871                         }
1872                         usbgem_mii_write(dp, MII_CONTROL, val, &err);
1873                         if (err != USB_SUCCESS) {
1874                                 goto usberr;
1875                         }
1876                 }
1877                 /*
1878                  * XXX -- nic state should be one of
1879                  * NIC_STATE_DISCONNECTED
1880                  * NIC_STATE_STOPPED
1881                  * NIC_STATE_INITIALIZED
1882                  * NIC_STATE_ONLINE
1883                  */
1884                 if (dp->nic_state >= NIC_STATE_INITIALIZED) {
1885                         /* notify the result of autonegotiation to mac */
1886                         if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
1887                                 goto usberr;
1888                         }
1889                 }
1890                 goto next_nowait;
1891 
1892         case MII_STATE_LINKDOWN:
1893                 status = usbgem_mii_read(dp, MII_STATUS, &err);
1894                 if (err != USB_SUCCESS) {
1895                         goto usberr;
1896                 }
1897                 if (status & MII_STATUS_LINKUP) {
1898                         /*
1899                          * Link is going up
1900                          */
1901                         dp->mii_state = MII_STATE_LINKUP;
1902                         dp->mii_supress_msg = B_FALSE;
1903 
1904                         DPRINTF(0, (CE_CONT,
1905                             "!%s: link up detected: status:%b",
1906                             dp->name, status, MII_STATUS_BITS));
1907 
1908                         /*
1909                          * MII_CONTROL_100MB and  MII_CONTROL_FDUPLEX are
1910                          * ignored when MII_CONTROL_ANE is set.
1911                          */
1912                         cmn_err(CE_CONT,
1913                             "!%s: Link up: %d Mbps %s duplex %s flow control",
1914                             dp->name,
1915                             usbgem_speed_value[dp->speed],
1916                             dp->full_duplex ? "full" : "half",
1917                             usbgem_fc_type[dp->flow_control]);
1918 
1919                         dp->mii_interval =
1920                             dp->ugc.usbgc_mii_link_watch_interval;
1921 
1922                         if (dp->ugc.usbgc_mii_hw_link_detection &&
1923                             dp->nic_state == NIC_STATE_ONLINE) {
1924                                 dp->mii_interval = 0;
1925                         }
1926 
1927                         if (dp->nic_state == NIC_STATE_ONLINE) {
1928                                 if (dp->mac_state == MAC_STATE_INITIALIZED) {
1929                                         (void) usbgem_mac_start(dp);
1930                                 }
1931                                 tx_sched = B_TRUE;
1932                         }
1933 
1934                         goto next;
1935                 }
1936 
1937                 dp->mii_supress_msg = B_TRUE;
1938                 if (dp->anadv_autoneg) {
1939                         dp->mii_timer -= diff;
1940                         if (dp->mii_timer <= 0) {
1941                                 /*
1942                                  * the link down timer expired.
1943                                  * need to restart auto-negotiation.
1944                                  */
1945                                 linkdown_action =
1946                                     dp->ugc.usbgc_mii_linkdown_timeout_action;
1947                                 goto restart_autonego;
1948                         }
1949                 }
1950                 /* don't change mii_state */
1951                 goto next;
1952 
1953         case MII_STATE_LINKUP:
1954                 if (rwlock == RW_READER) {
1955                         /* first pass, read mii status */
1956                         status = usbgem_mii_read(dp, MII_STATUS, &err);
1957                         if (err != USB_SUCCESS) {
1958                                 goto usberr;
1959                         }
1960                 }
1961                 if ((status & MII_STATUS_LINKUP) == 0) {
1962                         /*
1963                          * Link is going down
1964                          */
1965                         cmn_err(CE_NOTE,
1966                             "!%s: link down detected: status:%b",
1967                             dp->name, status, MII_STATUS_BITS);
1968                         /*
1969                          * Acquire exclusive lock to change mii_state
1970                          */
1971                         if (rwlock == RW_READER) {
1972                                 rwlock = RW_WRITER;
1973                                 rw_exit(&dp->dev_state_lock);
1974                                 goto again;
1975                         }
1976 
1977                         dp->mii_state = MII_STATE_LINKDOWN;
1978                         dp->mii_timer = dp->ugc.usbgc_mii_linkdown_timeout;
1979 
1980                         /*
1981                          * As we may change the state of the device,
1982                          * let us acquire exclusive lock for the state.
1983                          */
1984                         if (dp->nic_state == NIC_STATE_ONLINE &&
1985                             dp->mac_state == MAC_STATE_ONLINE &&
1986                             dp->ugc.usbgc_mii_stop_mac_on_linkdown) {
1987                                 (void) usbgem_restart_nic(dp);
1988                                 /* drain tx */
1989                                 tx_sched = B_TRUE;
1990                         }
1991 
1992                         if (dp->anadv_autoneg) {
1993                                 /* need to restart auto-negotiation */
1994                                 linkdown_action =
1995                                     dp->ugc.usbgc_mii_linkdown_action;
1996                                 goto restart_autonego;
1997                         }
1998                         /*
1999                          * don't use hw link down detection until the link
2000                          * status become stable for a while.
2001                          */
2002                         dp->mii_interval =
2003                             dp->ugc.usbgc_mii_link_watch_interval;
2004 
2005                         goto next;
2006                 }
2007 
2008                 /*
2009                  * still link up, no need to change mii_state
2010                  */
2011                 if (dp->ugc.usbgc_mii_hw_link_detection &&
2012                     dp->nic_state == NIC_STATE_ONLINE) {
2013                         /*
2014                          * no need to check link status periodicly
2015                          * if nic can generate interrupts when link go down.
2016                          */
2017                         dp->mii_interval = 0;
2018                 }
2019                 goto next;
2020         }
2021         /* NOTREACHED */
2022         cmn_err(CE_PANIC, "!%s: %s: not reached", dp->name, __func__);
2023 
2024         /*
2025          * Actions for new state.
2026          */
2027 restart_autonego:
2028         switch (linkdown_action) {
2029         case MII_ACTION_RESET:
2030                 if (!dp->mii_supress_msg) {
2031                         cmn_err(CE_CONT, "!%s: resetting PHY", dp->name);
2032                 }
2033                 dp->mii_supress_msg = B_TRUE;
2034                 goto reset_phy;
2035 
2036         case MII_ACTION_NONE:
2037                 dp->mii_supress_msg = B_TRUE;
2038                 if (dp->ugc.usbgc_mii_an_oneshot) {
2039                         goto autonego;
2040                 }
2041                 /* PHY will restart autonego automatically */
2042                 dp->mii_state = MII_STATE_AUTONEGOTIATING;
2043                 dp->mii_timer = dp->ugc.usbgc_mii_an_timeout;
2044                 dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
2045                 goto next;
2046 
2047         case MII_ACTION_RSA:
2048                 if (!dp->mii_supress_msg) {
2049                         cmn_err(CE_CONT, "!%s: restarting auto-negotiation",
2050                             dp->name);
2051                 }
2052                 dp->mii_supress_msg = B_TRUE;
2053                 goto autonego;
2054 
2055         default:
2056                 cmn_err(CE_PANIC, "!%s: unknowm linkdown action: %d",
2057                     dp->name, dp->ugc.usbgc_mii_linkdown_action);
2058         }
2059         /* NOTREACHED */
2060 
2061 reset_phy:
2062         if (!dp->mii_supress_msg) {
2063                 cmn_err(CE_CONT, "!%s: resetting PHY", dp->name);
2064         }
2065         dp->mii_state = MII_STATE_RESETTING;
2066         dp->mii_timer = dp->ugc.usbgc_mii_reset_timeout;
2067         if (!dp->ugc.usbgc_mii_dont_reset) {
2068                 usbgem_mii_write(dp, MII_CONTROL, MII_CONTROL_RESET, &err);
2069                 if (err != USB_SUCCESS) {
2070                         goto usberr;
2071                 }
2072         }
2073         dp->mii_interval = WATCH_INTERVAL_FAST;
2074         goto next;
2075 
2076 autonego:
2077         if (!dp->mii_supress_msg) {
2078                 cmn_err(CE_CONT, "!%s: auto-negotiation started", dp->name);
2079         }
2080         dp->mii_state = MII_STATE_AUTONEGOTIATING;
2081         dp->mii_timer = dp->ugc.usbgc_mii_an_timeout;
2082 
2083         /* start/restart autoneg */
2084         val = usbgem_mii_read(dp, MII_CONTROL, &err) &
2085             ~(MII_CONTROL_ISOLATE | MII_CONTROL_PWRDN | MII_CONTROL_RESET);
2086         if (err != USB_SUCCESS) {
2087                 goto usberr;
2088         }
2089         if (val & MII_CONTROL_ANE) {
2090                 val |= MII_CONTROL_RSAN;
2091         }
2092         usbgem_mii_write(dp, MII_CONTROL,
2093             val | dp->ugc.usbgc_mii_an_cmd | MII_CONTROL_ANE, &err);
2094         if (err != USB_SUCCESS) {
2095                 goto usberr;
2096         }
2097 
2098         dp->mii_interval = dp->ugc.usbgc_mii_an_watch_interval;
2099         goto next;
2100 
2101 usberr:
2102         dp->mii_state = MII_STATE_UNKNOWN;
2103         dp->mii_interval = dp->ugc.usbgc_mii_link_watch_interval;
2104         tx_sched = B_TRUE;
2105 
2106 next:
2107         *newstatep = dp->mii_state;
2108         rw_exit(&dp->dev_state_lock);
2109         return (tx_sched);
2110 }
2111 
2112 static void
2113 usbgem_mii_link_watcher(struct usbgem_dev *dp)
2114 {
2115         int             old_mii_state;
2116         int             new_mii_state;
2117         boolean_t       tx_sched;
2118 
2119         DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2120 
2121         for (; ; ) {
2122 
2123                 mutex_enter(&dp->link_watcher_lock);
2124                 if (dp->mii_interval) {
2125                         (void) cv_timedwait(&dp->link_watcher_wait_cv,
2126                             &dp->link_watcher_lock,
2127                             dp->mii_interval + ddi_get_lbolt());
2128                 } else {
2129                         cv_wait(&dp->link_watcher_wait_cv,
2130                             &dp->link_watcher_lock);
2131                 }
2132                 mutex_exit(&dp->link_watcher_lock);
2133 
2134                 if (dp->link_watcher_stop) {
2135                         break;
2136                 }
2137 
2138                 /* we block callbacks from disconnect/suspend and restart */
2139                 tx_sched = usbgem_mii_link_check(dp,
2140                     &old_mii_state, &new_mii_state);
2141 
2142                 /*
2143                  * gld v2 notifier functions are not able to
2144                  * be called with any locks in this layer.
2145                  */
2146                 if (tx_sched) {
2147                         /* kick potentially stopped downstream */
2148 #ifdef USBGEM_CONFIG_GLDv3
2149                         mac_tx_update(dp->mh);
2150 #else
2151                         gld_sched(dp->macinfo);
2152 #endif
2153                 }
2154 
2155                 if (old_mii_state != new_mii_state) {
2156                         /* notify new mii link state */
2157                         if (new_mii_state == MII_STATE_LINKUP) {
2158                                 dp->linkup_delay = 0;
2159                                 USBGEM_LINKUP(dp);
2160                         } else if (dp->linkup_delay <= 0) {
2161                                 USBGEM_LINKDOWN(dp);
2162                         }
2163                 } else if (dp->linkup_delay < 0) {
2164                         /* first linkup timeout */
2165                         dp->linkup_delay = 0;
2166                         USBGEM_LINKDOWN(dp);
2167                 }
2168         }
2169 
2170         thread_exit();
2171 }
2172 
2173 void
2174 usbgem_mii_update_link(struct usbgem_dev *dp)
2175 {
2176         cv_signal(&dp->link_watcher_wait_cv);
2177 }
2178 
2179 int
2180 usbgem_mii_probe_default(struct usbgem_dev *dp)
2181 {
2182         int             phy;
2183         uint16_t        status;
2184         uint16_t        xstatus;
2185         int             err;
2186         uint16_t        adv;
2187         uint16_t        adv_org;
2188 
2189         DPRINTF(3, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2190 
2191         /*
2192          * Scan PHY
2193          */
2194         dp->mii_status = 0;
2195 
2196         /* Try default phy first */
2197         if (dp->mii_phy_addr) {
2198                 status = usbgem_mii_read(dp, MII_STATUS, &err);
2199                 if (err != USB_SUCCESS) {
2200                         goto usberr;
2201                 }
2202                 if (status != 0xffff && status != 0x0000) {
2203                         goto PHY_found;
2204                 }
2205 
2206                 if (dp->mii_phy_addr < 0) {
2207                         cmn_err(CE_NOTE,
2208                     "!%s: failed to probe default internal and/or non-MII PHY",
2209                             dp->name);
2210                         return (USB_FAILURE);
2211                 }
2212 
2213                 cmn_err(CE_NOTE,
2214                     "!%s: failed to probe default MII PHY at %d",
2215                     dp->name, dp->mii_phy_addr);
2216         }
2217 
2218         /* Try all possible address */
2219         for (phy = dp->ugc.usbgc_mii_addr_min; phy < 32; phy++) {
2220                 dp->mii_phy_addr = phy;
2221                 status = usbgem_mii_read(dp, MII_STATUS, &err);
2222                 if (err != USB_SUCCESS) {
2223                         DPRINTF(0, (CE_CONT,
2224                             "!%s: %s: mii_read(status) failed",
2225                             dp->name, __func__));
2226                         goto usberr;
2227                 }
2228 
2229                 if (status != 0xffff && status != 0x0000) {
2230                         usbgem_mii_write(dp, MII_CONTROL, 0, &err);
2231                         if (err != USB_SUCCESS) {
2232                                 DPRINTF(0, (CE_CONT,
2233                                     "!%s: %s: mii_write(control) failed",
2234                                     dp->name, __func__));
2235                                 goto usberr;
2236                         }
2237                         goto PHY_found;
2238                 }
2239         }
2240         for (phy = dp->ugc.usbgc_mii_addr_min; phy < 32; phy++) {
2241                 dp->mii_phy_addr = phy;
2242                 usbgem_mii_write(dp, MII_CONTROL, 0, &err);
2243                 if (err != USB_SUCCESS) {
2244                         DPRINTF(0, (CE_CONT,
2245                             "!%s: %s: mii_write(control) failed",
2246                             dp->name, __func__));
2247                         goto usberr;
2248                 }
2249                 status = usbgem_mii_read(dp, MII_STATUS, &err);
2250                 if (err != USB_SUCCESS) {
2251                         DPRINTF(0, (CE_CONT,
2252                             "!%s: %s: mii_read(status) failed",
2253                             dp->name, __func__));
2254                         goto usberr;
2255                 }
2256 
2257                 if (status != 0xffff && status != 0) {
2258                         goto PHY_found;
2259                 }
2260         }
2261 
2262         cmn_err(CE_NOTE, "!%s: no MII PHY found", dp->name);
2263         return (USB_FAILURE);
2264 
2265 PHY_found:
2266         dp->mii_status = status;
2267         dp->mii_status_ro = ~status;
2268         dp->mii_phy_id = usbgem_mii_read(dp, MII_PHYIDH, &err) << 16;
2269         if (err != USB_SUCCESS) {
2270                 DPRINTF(0, (CE_CONT,
2271                     "!%s: %s: mii_read(PHYIDH) failed",
2272                     dp->name, __func__));
2273                 goto usberr;
2274         }
2275         dp->mii_phy_id |= usbgem_mii_read(dp, MII_PHYIDL, &err);
2276         if (err != USB_SUCCESS) {
2277                 DPRINTF(0, (CE_CONT,
2278                     "!%s: %s: mii_read(PHYIDL) failed",
2279                     dp->name, __func__));
2280                 goto usberr;
2281         }
2282 
2283         if (dp->mii_phy_addr < 0) {
2284                 cmn_err(CE_CONT, "!%s: using internal/non-MII PHY(0x%08x)",
2285                     dp->name, dp->mii_phy_id);
2286         } else {
2287                 cmn_err(CE_CONT, "!%s: MII PHY (0x%08x) found at %d",
2288                     dp->name, dp->mii_phy_id, dp->mii_phy_addr);
2289         }
2290 
2291         cmn_err(CE_CONT,
2292             "!%s: PHY control:%b, status:%b, advert:%b, lpar:%b, exp:%b",
2293             dp->name,
2294             usbgem_mii_read(dp, MII_CONTROL, &err), MII_CONTROL_BITS,
2295             status, MII_STATUS_BITS,
2296             usbgem_mii_read(dp, MII_AN_ADVERT, &err), MII_ABILITY_BITS,
2297             usbgem_mii_read(dp, MII_AN_LPABLE, &err), MII_ABILITY_BITS,
2298             usbgem_mii_read(dp, MII_AN_EXPANSION, &err), MII_AN_EXP_BITS);
2299 
2300         dp->mii_xstatus = 0;
2301         if (status & MII_STATUS_XSTATUS) {
2302                 dp->mii_xstatus = usbgem_mii_read(dp, MII_XSTATUS, &err);
2303 
2304                 cmn_err(CE_CONT, "!%s: xstatus:%b",
2305                     dp->name, dp->mii_xstatus, MII_XSTATUS_BITS);
2306         }
2307         dp->mii_xstatus_ro = ~dp->mii_xstatus;
2308 
2309         /* check if the phy can advertize pause abilities */
2310         adv_org = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
2311         if (err != USB_SUCCESS) {
2312                 goto usberr;
2313         }
2314 
2315         usbgem_mii_write(dp, MII_AN_ADVERT,
2316             MII_ABILITY_PAUSE | MII_ABILITY_ASM_DIR, &err);
2317         if (err != USB_SUCCESS) {
2318                 goto usberr;
2319         }
2320 
2321         adv = usbgem_mii_read(dp, MII_AN_ADVERT, &err);
2322         if (err != USB_SUCCESS) {
2323                 goto usberr;
2324         }
2325 
2326         if ((adv & MII_ABILITY_PAUSE) == 0) {
2327                 dp->ugc.usbgc_flow_control &= ~1;
2328         }
2329 
2330         if ((adv & MII_ABILITY_ASM_DIR) == 0) {
2331                 dp->ugc.usbgc_flow_control &= ~2;
2332         }
2333 
2334         usbgem_mii_write(dp, MII_AN_ADVERT, adv_org, &err);
2335         if (err != USB_SUCCESS) {
2336                 goto usberr;
2337         }
2338         return (USB_SUCCESS);
2339 
2340 usberr:
2341         return (USB_FAILURE);
2342 }
2343 
2344 int
2345 usbgem_mii_init_default(struct usbgem_dev *dp)
2346 {
2347         /* ENPTY */
2348         return (USB_SUCCESS);
2349 }
2350 
2351 static int
2352 usbgem_mii_start(struct usbgem_dev *dp)
2353 {
2354         int     err;
2355         kthread_t       *lwth;
2356 
2357         DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2358 
2359         /* make a first call of usbgem_mii_link_check() */
2360         dp->link_watcher_stop = 0;
2361         dp->mii_state = MII_STATE_UNKNOWN;
2362         dp->mii_interval = drv_usectohz(1000*1000); /* 1sec */
2363         dp->mii_last_check = ddi_get_lbolt();
2364         dp->linkup_delay = 600 * drv_usectohz(1000*1000); /* 10 minutes */
2365 
2366         lwth = thread_create(NULL, 0, usbgem_mii_link_watcher, dp, 0, &p0,
2367             TS_RUN, minclsyspri);
2368         if (lwth == NULL) {
2369                 cmn_err(CE_WARN,
2370                     "!%s: %s: failed to create a link watcher thread",
2371                     dp->name, __func__);
2372                 return (USB_FAILURE);
2373         }
2374         dp->link_watcher_did = lwth->t_did;
2375 
2376         return (USB_SUCCESS);
2377 }
2378 
2379 static void
2380 usbgem_mii_stop(struct usbgem_dev *dp)
2381 {
2382         DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2383 
2384         /* Ensure timer routine stopped */
2385         dp->link_watcher_stop = 1;
2386         cv_signal(&dp->link_watcher_wait_cv);
2387         thread_join(dp->link_watcher_did);
2388 }
2389 
2390 /* ============================================================== */
2391 /*
2392  * internal mac register operation interface
2393  */
2394 /* ============================================================== */
2395 /*
2396  * usbgem_mac_init: cold start
2397  */
2398 static int
2399 usbgem_mac_init(struct usbgem_dev *dp)
2400 {
2401         int     err;
2402 
2403         DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2404 
2405         if (dp->mac_state == MAC_STATE_DISCONNECTED) {
2406                 /* pretend we succeeded */
2407                 return (USB_SUCCESS);
2408         }
2409 
2410         ASSERT(dp->mac_state == MAC_STATE_STOPPED);
2411 
2412         /* reset fatal error timestamp */
2413         dp->fatal_error = (clock_t)0;
2414 
2415         /* reset tx side state */
2416         mutex_enter(&dp->txlock);
2417         dp->tx_busy_cnt = 0;
2418         dp->tx_max_packets = dp->ugc.usbgc_tx_list_max;
2419         mutex_exit(&dp->txlock);
2420 
2421         /* reset rx side state */
2422         mutex_enter(&dp->rxlock);
2423         dp->rx_busy_cnt = 0;
2424         mutex_exit(&dp->rxlock);
2425 
2426         err = usbgem_hal_init_chip(dp);
2427         if (err == USB_SUCCESS) {
2428                 dp->mac_state = MAC_STATE_INITIALIZED;
2429         }
2430 
2431         return (err);
2432 }
2433 
2434 /*
2435  * usbgem_mac_start: warm start
2436  */
2437 static int
2438 usbgem_mac_start(struct usbgem_dev *dp)
2439 {
2440         int     err;
2441         int     i;
2442         usb_flags_t     flags = 0;
2443         usb_intr_req_t  *req;
2444 #ifdef USBGEM_DEBUG_LEVEL
2445         usb_pipe_state_t        p_state;
2446 #endif
2447         DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2448 
2449         if (dp->mac_state == MAC_STATE_DISCONNECTED) {
2450                 /* do nothing but don't return failure */
2451                 return (USB_SUCCESS);
2452         }
2453 
2454         if (dp->mac_state != MAC_STATE_INITIALIZED) {
2455                 /* don't return failer */
2456                 DPRINTF(0, (CE_CONT,
2457                     "!%s: %s: mac_state(%d) is not MAC_STATE_INITIALIZED",
2458                     dp->name, __func__, dp->mac_state));
2459                 goto x;
2460         }
2461 
2462         dp->mac_state = MAC_STATE_ONLINE;
2463 
2464         if (usbgem_hal_start_chip(dp) != USB_SUCCESS) {
2465                 cmn_err(CE_NOTE,
2466                     "!%s: %s: usb error was detected during start_chip",
2467                     dp->name, __func__);
2468                 goto x;
2469         }
2470 
2471 #ifdef USBGEM_DEBUG_LEVEL
2472         usb_pipe_get_state(dp->intr_pipe, &p_state, 0);
2473         ASSERT(p_state == USB_PIPE_STATE_IDLE);
2474 #endif /* USBGEM_DEBUG_LEVEL */
2475 
2476         if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2477 
2478                 /* make a request for interrupt */
2479 
2480                 req = usb_alloc_intr_req(dp->dip, 0, USB_FLAGS_SLEEP);
2481                 if (req == NULL) {
2482                         cmn_err(CE_WARN, "!%s: %s: failed to allocate intreq",
2483                             dp->name, __func__);
2484                         goto x;
2485                 }
2486                 req->intr_data = NULL;
2487                 req->intr_client_private = (usb_opaque_t)dp;
2488                 req->intr_timeout = 0;
2489                 req->intr_attributes =
2490                     USB_ATTRS_SHORT_XFER_OK | USB_ATTRS_AUTOCLEARING;
2491                 req->intr_len = dp->ep_intr->wMaxPacketSize;
2492                 req->intr_cb = usbgem_intr_cb;
2493                 req->intr_exc_cb = usbgem_intr_cb;
2494                 req->intr_completion_reason = 0;
2495                 req->intr_cb_flags = 0;
2496 
2497                 err = usb_pipe_intr_xfer(dp->intr_pipe, req, flags);
2498                 if (err != USB_SUCCESS) {
2499                         cmn_err(CE_WARN,
2500                             "%s: err:%d failed to start polling of intr pipe",
2501                             dp->name, err);
2502                         goto x;
2503                 }
2504         }
2505 
2506         /* kick to receive the first packet */
2507         if (usbgem_init_rx_buf(dp) != USB_SUCCESS) {
2508                 goto err_stop_intr;
2509         }
2510         dp->rx_active = B_TRUE;
2511 
2512         return (USB_SUCCESS);
2513 
2514 err_stop_intr:
2515         /* stop the interrupt pipe */
2516         DPRINTF(0, (CE_CONT, "!%s: %s: FAULURE", dp->name, __func__));
2517         if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2518                 usb_pipe_stop_intr_polling(dp->intr_pipe, USB_FLAGS_SLEEP);
2519         }
2520 x:
2521         ASSERT(dp->mac_state == MAC_STATE_ONLINE);
2522         /* we use another flag to indicate error state. */
2523         if (dp->fatal_error == (clock_t)0) {
2524                 dp->fatal_error = usbgem_timestamp_nz();
2525         }
2526         return (USB_FAILURE);
2527 }
2528 
2529 static int
2530 usbgem_mac_stop(struct usbgem_dev *dp, int new_state, boolean_t graceful)
2531 {
2532         DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2533 
2534         /*
2535          * we must have writer lock for dev_state_lock
2536          */
2537         ASSERT(new_state == MAC_STATE_STOPPED ||
2538             new_state == MAC_STATE_DISCONNECTED);
2539 
2540         /* stop polling interrupt pipe */
2541         if (dp->ugc.usbgc_interrupt && dp->intr_pipe) {
2542                 usb_pipe_stop_intr_polling(dp->intr_pipe, USB_FLAGS_SLEEP);
2543         }
2544 
2545         if (new_state == MAC_STATE_STOPPED || graceful) {
2546                 /* stop the nic hardware completely */
2547                 if (usbgem_hal_stop_chip(dp) != USB_SUCCESS) {
2548                         (void) usbgem_hal_reset_chip(dp);
2549                 }
2550         }
2551 
2552         /* stop preparing new rx packets and sending new packets */
2553         dp->mac_state = new_state;
2554 
2555         /* other processors must get mac_state correctly after here */
2556         membar_producer();
2557 
2558         /* cancel all requests we have sent */
2559         usb_pipe_reset(dp->dip, dp->bulkin_pipe, USB_FLAGS_SLEEP, NULL, 0);
2560         usb_pipe_reset(dp->dip, dp->bulkout_pipe, USB_FLAGS_SLEEP, NULL, 0);
2561 
2562         DPRINTF(0, (CE_CONT,
2563             "!%s: %s: rx_busy_cnt:%d tx_busy_cnt:%d",
2564             dp->name, __func__, dp->rx_busy_cnt, dp->tx_busy_cnt));
2565 
2566         /*
2567          * Here all rx packets has been cancelled and their call back
2568          * function has been exeuted, because we called usb_pipe_reset
2569          * synchronously.
2570          * So actually we just ensure rx_busy_cnt == 0.
2571          */
2572         mutex_enter(&dp->rxlock);
2573         while (dp->rx_busy_cnt > 0) {
2574                 cv_wait(&dp->rx_drain_cv, &dp->rxlock);
2575         }
2576         mutex_exit(&dp->rxlock);
2577 
2578         DPRINTF(0, (CE_CONT, "!%s: %s: rx_busy_cnt is %d now",
2579             dp->name, __func__, dp->rx_busy_cnt));
2580 
2581         mutex_enter(&dp->txlock);
2582         while (dp->tx_busy_cnt > 0) {
2583                 cv_wait(&dp->tx_drain_cv, &dp->txlock);
2584         }
2585         mutex_exit(&dp->txlock);
2586 
2587         DPRINTF(0, (CE_CONT, "!%s: %s: tx_busy_cnt is %d now",
2588             dp->name, __func__, dp->tx_busy_cnt));
2589 
2590         return (USB_SUCCESS);
2591 }
2592 
2593 static int
2594 usbgem_add_multicast(struct usbgem_dev *dp, const uint8_t *ep)
2595 {
2596         int     cnt;
2597         int     err;
2598 
2599         DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2600 
2601         sema_p(&dp->rxfilter_lock);
2602         if (dp->mc_count_req++ < USBGEM_MAXMC) {
2603                 /* append the new address at the end of the mclist */
2604                 cnt = dp->mc_count;
2605                 bcopy(ep, dp->mc_list[cnt].addr.ether_addr_octet,
2606                     ETHERADDRL);
2607                 if (dp->ugc.usbgc_multicast_hash) {
2608                         dp->mc_list[cnt].hash =
2609                             (*dp->ugc.usbgc_multicast_hash)(dp, ep);
2610                 }
2611                 dp->mc_count = cnt + 1;
2612         }
2613 
2614         if (dp->mc_count_req != dp->mc_count) {
2615                 /* multicast address list overflow */
2616                 dp->rxmode |= RXMODE_MULTI_OVF;
2617         } else {
2618                 dp->rxmode &= ~RXMODE_MULTI_OVF;
2619         }
2620 
2621         if (dp->mac_state != MAC_STATE_DISCONNECTED) {
2622                 /* tell new multicast list to the hardware */
2623                 err = usbgem_hal_set_rx_filter(dp);
2624         }
2625         sema_v(&dp->rxfilter_lock);
2626 
2627         return (err);
2628 }
2629 
2630 static int
2631 usbgem_remove_multicast(struct usbgem_dev *dp, const uint8_t *ep)
2632 {
2633         size_t          len;
2634         int             i;
2635         int             cnt;
2636         int             err;
2637 
2638         DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
2639 
2640         sema_p(&dp->rxfilter_lock);
2641         dp->mc_count_req--;
2642         cnt = dp->mc_count;
2643         for (i = 0; i < cnt; i++) {
2644                 if (bcmp(ep, &dp->mc_list[i].addr, ETHERADDRL)) {
2645                         continue;
2646                 }
2647                 /* shrink the mclist by copying forward */
2648                 len = (cnt - (i + 1)) * sizeof (*dp->mc_list);
2649                 if (len > 0) {
2650                         bcopy(&dp->mc_list[i+1], &dp->mc_list[i], len);
2651                 }
2652                 dp->mc_count--;
2653                 break;
2654         }
2655 
2656         if (dp->mc_count_req != dp->mc_count) {
2657                 /* multicast address list overflow */
2658                 dp->rxmode |= RXMODE_MULTI_OVF;
2659         } else {
2660                 dp->rxmode &= ~RXMODE_MULTI_OVF;
2661         }
2662 
2663         if (dp->mac_state != MAC_STATE_DISCONNECTED) {
2664                 err = usbgem_hal_set_rx_filter(dp);
2665         }
2666         sema_v(&dp->rxfilter_lock);
2667 
2668         return (err);
2669 }
2670 
2671 
2672 /* ============================================================== */
2673 /*
2674  * ioctl
2675  */
2676 /* ============================================================== */
2677 enum ioc_reply {
2678         IOC_INVAL = -1,                         /* bad, NAK with EINVAL */
2679         IOC_DONE,                               /* OK, reply sent       */
2680         IOC_ACK,                                /* OK, just send ACK    */
2681         IOC_REPLY,                              /* OK, just send reply  */
2682         IOC_RESTART_ACK,                        /* OK, restart & ACK        */
2683         IOC_RESTART_REPLY                       /* OK, restart & reply      */
2684 };
2685 
2686 
2687 #ifdef USBGEM_CONFIG_MAC_PROP
2688 static int
2689 usbgem_get_def_val(struct usbgem_dev *dp, mac_prop_id_t pr_num,
2690     uint_t pr_valsize, void *pr_val)
2691 {
2692         link_flowctrl_t fl;
2693         int err = 0;
2694 
2695         ASSERT(pr_valsize > 0);
2696         switch (pr_num) {
2697         case MAC_PROP_AUTONEG:
2698                 *(uint8_t *)pr_val =
2699                     BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
2700                 break;
2701 
2702         case MAC_PROP_FLOWCTRL:
2703                 if (pr_valsize < sizeof (link_flowctrl_t)) {
2704                         return (EINVAL);
2705                 }
2706                 switch (dp->ugc.usbgc_flow_control) {
2707                 case FLOW_CONTROL_NONE:
2708                         fl = LINK_FLOWCTRL_NONE;
2709                         break;
2710                 case FLOW_CONTROL_SYMMETRIC:
2711                         fl = LINK_FLOWCTRL_BI;
2712                         break;
2713                 case FLOW_CONTROL_TX_PAUSE:
2714                         fl = LINK_FLOWCTRL_TX;
2715                         break;
2716                 case FLOW_CONTROL_RX_PAUSE:
2717                         fl = LINK_FLOWCTRL_RX;
2718                         break;
2719                 }
2720                 bcopy(&fl, pr_val, sizeof (fl));
2721                 break;
2722 
2723         case MAC_PROP_ADV_1000FDX_CAP:
2724         case MAC_PROP_EN_1000FDX_CAP:
2725                 *(uint8_t *)pr_val =
2726                     (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
2727                     (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
2728                 break;
2729 
2730         case MAC_PROP_ADV_1000HDX_CAP:
2731         case MAC_PROP_EN_1000HDX_CAP:
2732                 *(uint8_t *)pr_val =
2733                     (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
2734                     (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
2735                 break;
2736 
2737         case MAC_PROP_ADV_100T4_CAP:
2738         case MAC_PROP_EN_100T4_CAP:
2739                 *(uint8_t *)pr_val =
2740                     BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
2741                 break;
2742 
2743         case MAC_PROP_ADV_100FDX_CAP:
2744         case MAC_PROP_EN_100FDX_CAP:
2745                 *(uint8_t *)pr_val =
2746                     BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
2747                 break;
2748 
2749         case MAC_PROP_ADV_100HDX_CAP:
2750         case MAC_PROP_EN_100HDX_CAP:
2751                 *(uint8_t *)pr_val =
2752                     BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
2753                 break;
2754 
2755         case MAC_PROP_ADV_10FDX_CAP:
2756         case MAC_PROP_EN_10FDX_CAP:
2757                 *(uint8_t *)pr_val =
2758                     BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
2759                 break;
2760 
2761         case MAC_PROP_ADV_10HDX_CAP:
2762         case MAC_PROP_EN_10HDX_CAP:
2763                 *(uint8_t *)pr_val =
2764                     BOOLEAN(dp->mii_status & MII_STATUS_10);
2765                 break;
2766 
2767         default:
2768                 err = ENOTSUP;
2769                 break;
2770         }
2771         return (err);
2772 }
2773 
2774 #ifdef MAC_VERSION_V1
2775 static void
2776 usbgem_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
2777     mac_prop_info_handle_t prh)
2778 {
2779         struct usbgem_dev *dp = arg;
2780         link_flowctrl_t fl;
2781 
2782         /*
2783          * By default permissions are read/write unless specified
2784          * otherwise by the driver.
2785          */
2786 
2787         switch (pr_num) {
2788         case MAC_PROP_DUPLEX:
2789         case MAC_PROP_SPEED:
2790         case MAC_PROP_STATUS:
2791         case MAC_PROP_ADV_1000FDX_CAP:
2792         case MAC_PROP_ADV_1000HDX_CAP:
2793         case MAC_PROP_ADV_100FDX_CAP:
2794         case MAC_PROP_ADV_100HDX_CAP:
2795         case MAC_PROP_ADV_10FDX_CAP:
2796         case MAC_PROP_ADV_10HDX_CAP:
2797         case MAC_PROP_ADV_100T4_CAP:
2798         case MAC_PROP_EN_100T4_CAP:
2799                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2800                 break;
2801 
2802         case MAC_PROP_EN_1000FDX_CAP:
2803                 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET_FD) == 0) {
2804                         mac_prop_info_set_default_uint8(prh,
2805                             BOOLEAN(
2806                             dp->mii_xstatus & MII_XSTATUS_1000BASET_FD));
2807                 } else if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX_FD)
2808                     == 0) {
2809                         mac_prop_info_set_default_uint8(prh,
2810                             BOOLEAN(
2811                             dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD));
2812                 } else {
2813                         mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2814                 }
2815                 break;
2816 
2817         case MAC_PROP_EN_1000HDX_CAP:
2818                 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET) == 0) {
2819                         mac_prop_info_set_default_uint8(prh,
2820                             BOOLEAN(
2821                             dp->mii_xstatus & MII_XSTATUS_1000BASET));
2822                 } else if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX) == 0) {
2823                         mac_prop_info_set_default_uint8(prh,
2824                             BOOLEAN(
2825                             dp->mii_xstatus & MII_XSTATUS_1000BASEX));
2826                 } else {
2827                         mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2828                 }
2829                 break;
2830 
2831         case MAC_PROP_EN_100FDX_CAP:
2832                 if ((dp->mii_status_ro & MII_STATUS_100_BASEX_FD) == 0) {
2833                         mac_prop_info_set_default_uint8(prh,
2834                             BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD));
2835                 } else {
2836                         mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2837                 }
2838                 break;
2839 
2840         case MAC_PROP_EN_100HDX_CAP:
2841                 if ((dp->mii_status_ro & MII_STATUS_100_BASEX) == 0) {
2842                         mac_prop_info_set_default_uint8(prh,
2843                             BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX));
2844                 } else {
2845                         mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2846                 }
2847                 break;
2848 
2849         case MAC_PROP_EN_10FDX_CAP:
2850                 if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2851                         mac_prop_info_set_default_uint8(prh,
2852                             BOOLEAN(dp->mii_status & MII_STATUS_10_FD));
2853                 } else {
2854                         mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2855                 }
2856                 break;
2857 
2858         case MAC_PROP_EN_10HDX_CAP:
2859                 if ((dp->mii_status_ro & MII_STATUS_10) == 0) {
2860                         mac_prop_info_set_default_uint8(prh,
2861                             BOOLEAN(dp->mii_status & MII_STATUS_10));
2862                 } else {
2863                         mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2864                 }
2865                 break;
2866 
2867         case MAC_PROP_AUTONEG:
2868                 if ((dp->mii_status_ro & MII_STATUS_CANAUTONEG) == 0) {
2869                         mac_prop_info_set_default_uint8(prh,
2870                             BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG));
2871                 } else {
2872                         mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
2873                 }
2874                 break;
2875 
2876         case MAC_PROP_FLOWCTRL:
2877                 switch (dp->ugc.usbgc_flow_control) {
2878                 case FLOW_CONTROL_NONE:
2879                         fl = LINK_FLOWCTRL_NONE;
2880                         break;
2881                 case FLOW_CONTROL_SYMMETRIC:
2882                         fl = LINK_FLOWCTRL_BI;
2883                         break;
2884                 case FLOW_CONTROL_TX_PAUSE:
2885                         fl = LINK_FLOWCTRL_TX;
2886                         break;
2887                 case FLOW_CONTROL_RX_PAUSE:
2888                         fl = LINK_FLOWCTRL_RX;
2889                         break;
2890                 }
2891                 mac_prop_info_set_default_link_flowctrl(prh, fl);
2892                 break;
2893 
2894         case MAC_PROP_MTU:
2895                 mac_prop_info_set_range_uint32(prh,
2896                     dp->ugc.usbgc_min_mtu, dp->ugc.usbgc_max_mtu);
2897                 break;
2898 
2899         case MAC_PROP_PRIVATE:
2900                 break;
2901         }
2902 }
2903 #endif
2904 
2905 static int
2906 usbgem_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
2907     uint_t pr_valsize, const void *pr_val)
2908 {
2909         struct usbgem_dev *dp = arg;
2910         int err = 0;
2911         boolean_t       update = B_FALSE;
2912         link_flowctrl_t flowctrl;
2913         uint32_t cur_mtu, new_mtu;
2914 
2915         rw_enter(&dp->dev_state_lock, RW_WRITER);
2916         switch (pr_num) {
2917         case MAC_PROP_EN_1000FDX_CAP:
2918                 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET_FD) == 0 ||
2919                     (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX_FD) == 0) {
2920                         if (dp->anadv_1000fdx != *(uint8_t *)pr_val) {
2921                                 dp->anadv_1000fdx = *(uint8_t *)pr_val;
2922                                 update = B_TRUE;
2923                         }
2924                 } else {
2925                         err = ENOTSUP;
2926                 }
2927                 break;
2928 
2929         case MAC_PROP_EN_1000HDX_CAP:
2930                 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET) == 0 ||
2931                     (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX) == 0) {
2932                         if (dp->anadv_1000hdx != *(uint8_t *)pr_val) {
2933                                 dp->anadv_1000hdx = *(uint8_t *)pr_val;
2934                                 update = B_TRUE;
2935                         }
2936                 } else {
2937                         err = ENOTSUP;
2938                 }
2939                 break;
2940 
2941         case MAC_PROP_EN_100FDX_CAP:
2942                 if ((dp->mii_status_ro & MII_STATUS_100_BASEX_FD) == 0) {
2943                         if (dp->anadv_100fdx != *(uint8_t *)pr_val) {
2944                                 dp->anadv_100fdx = *(uint8_t *)pr_val;
2945                                 update = B_TRUE;
2946                         }
2947                 } else {
2948                         err = ENOTSUP;
2949                 }
2950                 break;
2951 
2952         case MAC_PROP_EN_100HDX_CAP:
2953                 if ((dp->mii_status_ro & MII_STATUS_100_BASEX) == 0) {
2954                         if (dp->anadv_100hdx != *(uint8_t *)pr_val) {
2955                                 dp->anadv_100hdx = *(uint8_t *)pr_val;
2956                                 update = B_TRUE;
2957                         }
2958                 } else {
2959                         err = ENOTSUP;
2960                 }
2961                 break;
2962 
2963         case MAC_PROP_EN_10FDX_CAP:
2964                 if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2965                         if (dp->anadv_10fdx != *(uint8_t *)pr_val) {
2966                                 dp->anadv_10fdx = *(uint8_t *)pr_val;
2967                                 update = B_TRUE;
2968                         }
2969                 } else {
2970                         err = ENOTSUP;
2971                 }
2972                 break;
2973 
2974         case MAC_PROP_EN_10HDX_CAP:
2975                 if ((dp->mii_status_ro & MII_STATUS_10_FD) == 0) {
2976                         if (dp->anadv_10hdx != *(uint8_t *)pr_val) {
2977                                 dp->anadv_10hdx = *(uint8_t *)pr_val;
2978                                 update = B_TRUE;
2979                         }
2980                 } else {
2981                         err = ENOTSUP;
2982                 }
2983                 break;
2984 
2985         case MAC_PROP_AUTONEG:
2986                 if ((dp->mii_status_ro & MII_STATUS_CANAUTONEG) == 0) {
2987                         if (dp->anadv_autoneg != *(uint8_t *)pr_val) {
2988                                 dp->anadv_autoneg = *(uint8_t *)pr_val;
2989                                 update = B_TRUE;
2990                         }
2991                 } else {
2992                         err = ENOTSUP;
2993                 }
2994                 break;
2995 
2996         case MAC_PROP_FLOWCTRL:
2997                 bcopy(pr_val, &flowctrl, sizeof (flowctrl));
2998 
2999                 switch (flowctrl) {
3000                 default:
3001                         err = EINVAL;
3002                         break;
3003 
3004                 case LINK_FLOWCTRL_NONE:
3005                         if (dp->flow_control != FLOW_CONTROL_NONE) {
3006                                 dp->flow_control = FLOW_CONTROL_NONE;
3007                                 update = B_TRUE;
3008                         }
3009                         break;
3010 
3011                 case LINK_FLOWCTRL_RX:
3012                         if (dp->flow_control != FLOW_CONTROL_RX_PAUSE) {
3013                                 dp->flow_control = FLOW_CONTROL_RX_PAUSE;
3014                                 update = B_TRUE;
3015                         }
3016                         break;
3017 
3018                 case LINK_FLOWCTRL_TX:
3019                         if (dp->flow_control != FLOW_CONTROL_TX_PAUSE) {
3020                                 dp->flow_control = FLOW_CONTROL_TX_PAUSE;
3021                                 update = B_TRUE;
3022                         }
3023                         break;
3024 
3025                 case LINK_FLOWCTRL_BI:
3026                         if (dp->flow_control != FLOW_CONTROL_SYMMETRIC) {
3027                                 dp->flow_control = FLOW_CONTROL_SYMMETRIC;
3028                                 update = B_TRUE;
3029                         }
3030                         break;
3031                 }
3032                 break;
3033 
3034         case MAC_PROP_ADV_1000FDX_CAP:
3035         case MAC_PROP_ADV_1000HDX_CAP:
3036         case MAC_PROP_ADV_100FDX_CAP:
3037         case MAC_PROP_ADV_100HDX_CAP:
3038         case MAC_PROP_ADV_10FDX_CAP:
3039         case MAC_PROP_ADV_10HDX_CAP:
3040         case MAC_PROP_STATUS:
3041         case MAC_PROP_SPEED:
3042         case MAC_PROP_DUPLEX:
3043                 err = ENOTSUP; /* read-only prop. Can't set this. */
3044                 break;
3045 
3046         case MAC_PROP_MTU:
3047                 bcopy(pr_val, &new_mtu, sizeof (new_mtu));
3048                 if (new_mtu != dp->mtu) {
3049                         err = EINVAL;
3050                 }
3051                 break;
3052 
3053         case MAC_PROP_PRIVATE:
3054                 err = ENOTSUP;
3055                 break;
3056 
3057         default:
3058                 err = ENOTSUP;
3059                 break;
3060         }
3061 
3062         if (update) {
3063                 /* sync with PHY */
3064                 usbgem_choose_forcedmode(dp);
3065                 dp->mii_state = MII_STATE_UNKNOWN;
3066                 cv_signal(&dp->link_watcher_wait_cv);
3067         }
3068         rw_exit(&dp->dev_state_lock);
3069         return (err);
3070 }
3071 
3072 static int
3073 #ifdef MAC_VERSION_V1
3074 usbgem_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
3075     uint_t pr_valsize, void *pr_val)
3076 #else
3077 usbgem_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
3078     uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm)
3079 #endif
3080 {
3081         struct usbgem_dev *dp = arg;
3082         int err = 0;
3083         link_flowctrl_t flowctrl;
3084         uint64_t tmp = 0;
3085 
3086         if (pr_valsize == 0) {
3087                 return (EINVAL);
3088         }
3089 #ifndef MAC_VERSION_V1
3090         *perm = MAC_PROP_PERM_RW;
3091 #endif
3092         bzero(pr_val, pr_valsize);
3093 #ifndef MAC_VERSION_V1
3094         if ((pr_flags & MAC_PROP_DEFAULT) && (pr_num != MAC_PROP_PRIVATE)) {
3095                 return (usbgem_get_def_val(dp, pr_num, pr_valsize, pr_val));
3096         }
3097 #endif
3098         rw_enter(&dp->dev_state_lock, RW_READER);
3099         switch (pr_num) {
3100         case MAC_PROP_DUPLEX:
3101 #ifndef MAC_VERSION_V1
3102                 *perm = MAC_PROP_PERM_READ;
3103 #endif
3104                 if (pr_valsize >= sizeof (link_duplex_t)) {
3105                         if (dp->mii_state != MII_STATE_LINKUP) {
3106                                 *(link_duplex_t *)pr_val = LINK_DUPLEX_UNKNOWN;
3107                         } else if (dp->full_duplex) {
3108                                 *(link_duplex_t *)pr_val = LINK_DUPLEX_FULL;
3109                         } else {
3110                                 *(link_duplex_t *)pr_val = LINK_DUPLEX_HALF;
3111                         }
3112                 } else {
3113                         err = EINVAL;
3114                 }
3115                 break;
3116         case MAC_PROP_SPEED:
3117 #ifndef MAC_VERSION_V1
3118                 *perm = MAC_PROP_PERM_READ;
3119 #endif
3120                 if (pr_valsize >= sizeof (uint64_t)) {
3121                         switch (dp->speed) {
3122                         case USBGEM_SPD_1000:
3123                                 tmp = 1000000000;
3124                                 break;
3125                         case USBGEM_SPD_100:
3126                                 tmp = 100000000;
3127                                 break;
3128                         case USBGEM_SPD_10:
3129                                 tmp = 10000000;
3130                                 break;
3131                         default:
3132                                 tmp = 0;
3133                         }
3134                         bcopy(&tmp, pr_val, sizeof (tmp));
3135                 } else {
3136                         err = EINVAL;
3137                 }
3138                 break;
3139 
3140         case MAC_PROP_AUTONEG:
3141 #ifndef MAC_VERSION_V1
3142                 if (dp->mii_status_ro & MII_STATUS_CANAUTONEG) {
3143                         *perm = MAC_PROP_PERM_READ;
3144                 }
3145 #endif
3146                 *(uint8_t *)pr_val = dp->anadv_autoneg;
3147                 break;
3148 
3149         case MAC_PROP_FLOWCTRL:
3150                 if (pr_valsize >= sizeof (link_flowctrl_t)) {
3151                         switch (dp->flow_control) {
3152                         case FLOW_CONTROL_NONE:
3153                                 flowctrl = LINK_FLOWCTRL_NONE;
3154                                 break;
3155                         case FLOW_CONTROL_RX_PAUSE:
3156                                 flowctrl = LINK_FLOWCTRL_RX;
3157                                 break;
3158                         case FLOW_CONTROL_TX_PAUSE:
3159                                 flowctrl = LINK_FLOWCTRL_TX;
3160                                 break;
3161                         case FLOW_CONTROL_SYMMETRIC:
3162                                 flowctrl = LINK_FLOWCTRL_BI;
3163                                 break;
3164                         }
3165                         bcopy(&flowctrl, pr_val, sizeof (flowctrl));
3166                 } else {
3167                         err = EINVAL;
3168                 }
3169                 break;
3170 
3171         case MAC_PROP_ADV_1000FDX_CAP:
3172         case MAC_PROP_ADV_1000HDX_CAP:
3173         case MAC_PROP_ADV_100FDX_CAP:
3174         case MAC_PROP_ADV_100HDX_CAP:
3175         case MAC_PROP_ADV_10FDX_CAP:
3176         case MAC_PROP_ADV_10HDX_CAP:
3177         case MAC_PROP_ADV_100T4_CAP:
3178                 usbgem_get_def_val(dp, pr_num, pr_valsize, pr_val);
3179                 break;
3180 
3181         case MAC_PROP_EN_1000FDX_CAP:
3182 #ifndef MAC_VERSION_V1
3183                 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET_FD) &&
3184                     (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX_FD)) {
3185                         *perm = MAC_PROP_PERM_READ;
3186                 }
3187 #endif
3188                 *(uint8_t *)pr_val = dp->anadv_1000fdx;
3189                 break;
3190 
3191         case MAC_PROP_EN_1000HDX_CAP:
3192 #ifndef MAC_VERSION_V1
3193                 if ((dp->mii_xstatus_ro & MII_XSTATUS_1000BASET) &&
3194                     (dp->mii_xstatus_ro & MII_XSTATUS_1000BASEX)) {
3195                         *perm = MAC_PROP_PERM_READ;
3196                 }
3197 #endif
3198                 *(uint8_t *)pr_val = dp->anadv_1000hdx;
3199                 break;
3200 
3201         case MAC_PROP_EN_100FDX_CAP:
3202 #ifndef MAC_VERSION_V1
3203                 if (dp->mii_status_ro & MII_STATUS_100_BASEX_FD) {
3204                         *perm = MAC_PROP_PERM_READ;
3205                 }
3206 #endif
3207                 *(uint8_t *)pr_val = dp->anadv_100fdx;
3208                 break;
3209 
3210         case MAC_PROP_EN_100HDX_CAP:
3211 #ifndef MAC_VERSION_V1
3212                 if (dp->mii_status_ro & MII_STATUS_100_BASEX) {
3213                         *perm = MAC_PROP_PERM_READ;
3214                 }
3215 #endif
3216                 *(uint8_t *)pr_val = dp->anadv_100hdx;
3217                 break;
3218 
3219         case MAC_PROP_EN_10FDX_CAP:
3220 #ifndef MAC_VERSION_V1
3221                 if (dp->mii_status_ro & MII_STATUS_10_FD) {
3222                         *perm = MAC_PROP_PERM_READ;
3223                 }
3224 #endif
3225                 *(uint8_t *)pr_val = dp->anadv_10fdx;
3226                 break;
3227 
3228         case MAC_PROP_EN_10HDX_CAP:
3229 #ifndef MAC_VERSION_V1
3230                 if (dp->mii_status_ro & MII_STATUS_10) {
3231                         *perm = MAC_PROP_PERM_READ;
3232                 }
3233 #endif
3234                 *(uint8_t *)pr_val = dp->anadv_10hdx;
3235                 break;
3236 
3237         case MAC_PROP_EN_100T4_CAP:
3238 #ifndef MAC_VERSION_V1
3239                 if (dp->mii_status_ro & MII_STATUS_100_BASE_T4) {
3240                         *perm = MAC_PROP_PERM_READ;
3241                 }
3242 #endif
3243                 *(uint8_t *)pr_val = dp->anadv_100t4;
3244                 break;
3245 
3246         case MAC_PROP_PRIVATE:
3247                 err = ENOTSUP;
3248                 break;
3249 
3250 #ifndef MAC_VERSION_V1
3251         case MAC_PROP_MTU: {
3252                 mac_propval_range_t range;
3253                 if (!(pr_flags & MAC_PROP_POSSIBLE)) {
3254                         err = ENOTSUP;
3255                         break;
3256                 }
3257                 if (pr_valsize < sizeof (mac_propval_range_t)) {
3258                         err = EINVAL;
3259                         break;
3260                 }
3261                 range.mpr_count = 1;
3262                 range.mpr_type = MAC_PROPVAL_UINT32;
3263                 range.range_uint32[0].mpur_min = ETHERMTU;
3264                 range.range_uint32[0].mpur_max = dp->mtu;
3265                 bcopy(&range, pr_val, sizeof (range));
3266                 break;
3267         }
3268 #endif
3269         default:
3270                 err = ENOTSUP;
3271                 break;
3272         }
3273 
3274         rw_exit(&dp->dev_state_lock);
3275         return (err);
3276 }
3277 #endif /* USBGEM_CONFIG_MAC_PROP */
3278 
3279 #ifdef USBGEM_CONFIG_ND
3280 /* ============================================================== */
3281 /*
3282  * ND interface
3283  */
3284 /* ============================================================== */
3285 enum {
3286         PARAM_AUTONEG_CAP,
3287         PARAM_PAUSE_CAP,
3288         PARAM_ASYM_PAUSE_CAP,
3289         PARAM_1000FDX_CAP,
3290         PARAM_1000HDX_CAP,
3291         PARAM_100T4_CAP,
3292         PARAM_100FDX_CAP,
3293         PARAM_100HDX_CAP,
3294         PARAM_10FDX_CAP,
3295         PARAM_10HDX_CAP,
3296 
3297         PARAM_ADV_AUTONEG_CAP,
3298         PARAM_ADV_PAUSE_CAP,
3299         PARAM_ADV_ASYM_PAUSE_CAP,
3300         PARAM_ADV_1000FDX_CAP,
3301         PARAM_ADV_1000HDX_CAP,
3302         PARAM_ADV_100T4_CAP,
3303         PARAM_ADV_100FDX_CAP,
3304         PARAM_ADV_100HDX_CAP,
3305         PARAM_ADV_10FDX_CAP,
3306         PARAM_ADV_10HDX_CAP,
3307         PARAM_ADV_1000T_MS,
3308 
3309         PARAM_LP_AUTONEG_CAP,
3310         PARAM_LP_PAUSE_CAP,
3311         PARAM_LP_ASYM_PAUSE_CAP,
3312         PARAM_LP_1000FDX_CAP,
3313         PARAM_LP_1000HDX_CAP,
3314         PARAM_LP_100T4_CAP,
3315         PARAM_LP_100FDX_CAP,
3316         PARAM_LP_100HDX_CAP,
3317         PARAM_LP_10FDX_CAP,
3318         PARAM_LP_10HDX_CAP,
3319 
3320         PARAM_LINK_STATUS,
3321         PARAM_LINK_SPEED,
3322         PARAM_LINK_DUPLEX,
3323 
3324         PARAM_LINK_AUTONEG,
3325         PARAM_LINK_RX_PAUSE,
3326         PARAM_LINK_TX_PAUSE,
3327 
3328         PARAM_LOOP_MODE,
3329         PARAM_MSI_CNT,
3330 #ifdef DEBUG_RESUME
3331         PARAM_RESUME_TEST,
3332 #endif
3333 
3334         PARAM_COUNT
3335 };
3336 
3337 struct usbgem_nd_arg {
3338         struct usbgem_dev       *dp;
3339         int             item;
3340 };
3341 
3342 static int
3343 usbgem_param_get(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *credp)
3344 {
3345         struct usbgem_dev       *dp = ((struct usbgem_nd_arg *)(void *)arg)->dp;
3346         int             item = ((struct usbgem_nd_arg *)(void *)arg)->item;
3347         long            val;
3348 
3349         DPRINTF(1, (CE_CONT, "!%s: %s: called, item:%d",
3350             dp->name, __func__, item));
3351 
3352         switch (item) {
3353         case PARAM_AUTONEG_CAP:
3354                 val = BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
3355                 DPRINTF(1, (CE_CONT, "autoneg_cap:%d", val));
3356                 break;
3357 
3358         case PARAM_PAUSE_CAP:
3359                 val = dp->ugc.usbgc_flow_control != FLOW_CONTROL_NONE;
3360                 break;
3361 
3362         case PARAM_ASYM_PAUSE_CAP:
3363                 val = dp->ugc.usbgc_flow_control > FLOW_CONTROL_SYMMETRIC;
3364                 break;
3365 
3366         case PARAM_1000FDX_CAP:
3367                 val = (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
3368                     (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
3369                 break;
3370 
3371         case PARAM_1000HDX_CAP:
3372                 val = (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
3373                     (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
3374                 break;
3375 
3376         case PARAM_100T4_CAP:
3377                 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
3378                 break;
3379 
3380         case PARAM_100FDX_CAP:
3381                 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
3382                 break;
3383 
3384         case PARAM_100HDX_CAP:
3385                 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
3386                 break;
3387 
3388         case PARAM_10FDX_CAP:
3389                 val = BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
3390                 break;
3391 
3392         case PARAM_10HDX_CAP:
3393                 val = BOOLEAN(dp->mii_status & MII_STATUS_10);
3394                 break;
3395 
3396         case PARAM_ADV_AUTONEG_CAP:
3397                 val = dp->anadv_autoneg;
3398                 break;
3399 
3400         case PARAM_ADV_PAUSE_CAP:
3401                 val = dp->anadv_pause;
3402                 break;
3403 
3404         case PARAM_ADV_ASYM_PAUSE_CAP:
3405                 val = dp->anadv_asmpause;
3406                 break;
3407 
3408         case PARAM_ADV_1000FDX_CAP:
3409                 val = dp->anadv_1000fdx;
3410                 break;
3411 
3412         case PARAM_ADV_1000HDX_CAP:
3413                 val = dp->anadv_1000hdx;
3414                 break;
3415 
3416         case PARAM_ADV_100T4_CAP:
3417                 val = dp->anadv_100t4;
3418                 break;
3419 
3420         case PARAM_ADV_100FDX_CAP:
3421                 val = dp->anadv_100fdx;
3422                 break;
3423 
3424         case PARAM_ADV_100HDX_CAP:
3425                 val = dp->anadv_100hdx;
3426                 break;
3427 
3428         case PARAM_ADV_10FDX_CAP:
3429                 val = dp->anadv_10fdx;
3430                 break;
3431 
3432         case PARAM_ADV_10HDX_CAP:
3433                 val = dp->anadv_10hdx;
3434                 break;
3435 
3436         case PARAM_ADV_1000T_MS:
3437                 val = dp->anadv_1000t_ms;
3438                 break;
3439 
3440         case PARAM_LP_AUTONEG_CAP:
3441                 val = BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
3442                 break;
3443 
3444         case PARAM_LP_PAUSE_CAP:
3445                 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_PAUSE);
3446                 break;
3447 
3448         case PARAM_LP_ASYM_PAUSE_CAP:
3449                 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_ASM_DIR);
3450                 break;
3451 
3452         case PARAM_LP_1000FDX_CAP:
3453                 val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_FULL);
3454                 break;
3455 
3456         case PARAM_LP_1000HDX_CAP:
3457                 val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_HALF);
3458                 break;
3459 
3460         case PARAM_LP_100T4_CAP:
3461                 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_T4);
3462                 break;
3463 
3464         case PARAM_LP_100FDX_CAP:
3465                 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX_FD);
3466                 break;
3467 
3468         case PARAM_LP_100HDX_CAP:
3469                 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX);
3470                 break;
3471 
3472         case PARAM_LP_10FDX_CAP:
3473                 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T_FD);
3474                 break;
3475 
3476         case PARAM_LP_10HDX_CAP:
3477                 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T);
3478                 break;
3479 
3480         case PARAM_LINK_STATUS:
3481                 val = (dp->mii_state == MII_STATE_LINKUP);
3482                 break;
3483 
3484         case PARAM_LINK_SPEED:
3485                 val = usbgem_speed_value[dp->speed];
3486                 break;
3487 
3488         case PARAM_LINK_DUPLEX:
3489                 val = 0;
3490                 if (dp->mii_state == MII_STATE_LINKUP) {
3491                         val = dp->full_duplex ? 2 : 1;
3492                 }
3493                 break;
3494 
3495         case PARAM_LINK_AUTONEG:
3496                 val = BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
3497                 break;
3498 
3499         case PARAM_LINK_RX_PAUSE:
3500                 val = (dp->flow_control == FLOW_CONTROL_SYMMETRIC) ||
3501                     (dp->flow_control == FLOW_CONTROL_RX_PAUSE);
3502                 break;
3503 
3504         case PARAM_LINK_TX_PAUSE:
3505                 val = (dp->flow_control == FLOW_CONTROL_SYMMETRIC) ||
3506                     (dp->flow_control == FLOW_CONTROL_TX_PAUSE);
3507                 break;
3508 
3509 #ifdef DEBUG_RESUME
3510         case PARAM_RESUME_TEST:
3511                 val = 0;
3512                 break;
3513 #endif
3514         default:
3515                 cmn_err(CE_WARN, "%s: unimplemented ndd control (%d)",
3516                     dp->name, item);
3517                 break;
3518         }
3519 
3520         (void) mi_mpprintf(mp, "%ld", val);
3521 
3522         return (0);
3523 }
3524 
3525 static int
3526 usbgem_param_set(queue_t *q,
3527     mblk_t *mp, char *value, caddr_t arg, cred_t *credp)
3528 {
3529         struct usbgem_dev       *dp = ((struct usbgem_nd_arg *)(void *)arg)->dp;
3530         int             item = ((struct usbgem_nd_arg *)(void *)arg)->item;
3531         long            val;
3532         char            *end;
3533 
3534         DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3535         if (ddi_strtol(value, &end, 10, &val)) {
3536                 return (EINVAL);
3537         }
3538         if (end == value) {
3539                 return (EINVAL);
3540         }
3541 
3542         switch (item) {
3543         case PARAM_ADV_AUTONEG_CAP:
3544                 if (val != 0 && val != 1) {
3545                         goto err;
3546                 }
3547                 if (val && (dp->mii_status & MII_STATUS_CANAUTONEG) == 0) {
3548                         goto err;
3549                 }
3550                 dp->anadv_autoneg = (int)val;
3551                 break;
3552 
3553         case PARAM_ADV_PAUSE_CAP:
3554                 if (val != 0 && val != 1) {
3555                         goto err;
3556                 }
3557                 if (val && dp->ugc.usbgc_flow_control == FLOW_CONTROL_NONE) {
3558                         goto err;
3559                 }
3560                 dp->anadv_pause = (int)val;
3561                 break;
3562 
3563         case PARAM_ADV_ASYM_PAUSE_CAP:
3564                 if (val != 0 && val != 1) {
3565                         goto err;
3566                 }
3567                 if (val &&
3568                     dp->ugc.usbgc_flow_control <= FLOW_CONTROL_SYMMETRIC) {
3569                         goto err;
3570                 }
3571                 dp->anadv_asmpause = (int)val;
3572                 break;
3573 
3574         case PARAM_ADV_1000FDX_CAP:
3575                 if (val != 0 && val != 1) {
3576                         goto err;
3577                 }
3578                 if (val && (dp->mii_xstatus &
3579                     (MII_XSTATUS_1000BASET_FD |
3580                     MII_XSTATUS_1000BASEX_FD)) == 0) {
3581                         goto err;
3582                 }
3583                 dp->anadv_1000fdx = (int)val;
3584                 break;
3585 
3586         case PARAM_ADV_1000HDX_CAP:
3587                 if (val != 0 && val != 1) {
3588                         goto err;
3589                 }
3590                 if (val && (dp->mii_xstatus &
3591                     (MII_XSTATUS_1000BASET | MII_XSTATUS_1000BASEX)) == 0) {
3592                         goto err;
3593                 }
3594                 dp->anadv_1000hdx = (int)val;
3595                 break;
3596 
3597         case PARAM_ADV_100T4_CAP:
3598                 if (val != 0 && val != 1) {
3599                         goto err;
3600                 }
3601                 if (val && (dp->mii_status & MII_STATUS_100_BASE_T4) == 0) {
3602                         goto err;
3603                 }
3604                 dp->anadv_100t4 = (int)val;
3605                 break;
3606 
3607         case PARAM_ADV_100FDX_CAP:
3608                 if (val != 0 && val != 1) {
3609                         goto err;
3610                 }
3611                 if (val && (dp->mii_status & MII_STATUS_100_BASEX_FD) == 0) {
3612                         goto err;
3613                 }
3614                 dp->anadv_100fdx = (int)val;
3615                 break;
3616 
3617         case PARAM_ADV_100HDX_CAP:
3618                 if (val != 0 && val != 1) {
3619                         goto err;
3620                 }
3621                 if (val && (dp->mii_status & MII_STATUS_100_BASEX) == 0) {
3622                         goto err;
3623                 }
3624                 dp->anadv_100hdx = (int)val;
3625                 break;
3626 
3627         case PARAM_ADV_10FDX_CAP:
3628                 if (val != 0 && val != 1) {
3629                         goto err;
3630                 }
3631                 if (val && (dp->mii_status & MII_STATUS_10_FD) == 0) {
3632                         goto err;
3633                 }
3634                 dp->anadv_10fdx = (int)val;
3635                 break;
3636 
3637         case PARAM_ADV_10HDX_CAP:
3638                 if (val != 0 && val != 1) {
3639                         goto err;
3640                 }
3641                 if (val && (dp->mii_status & MII_STATUS_10) == 0) {
3642                         goto err;
3643                 }
3644                 dp->anadv_10hdx = (int)val;
3645                 break;
3646 
3647         case PARAM_ADV_1000T_MS:
3648                 if (val != 0 && val != 1 && val != 2) {
3649                         goto err;
3650                 }
3651                 if (val && (dp->mii_xstatus &
3652                     (MII_XSTATUS_1000BASET | MII_XSTATUS_1000BASET_FD)) == 0) {
3653                         goto err;
3654                 }
3655                 dp->anadv_1000t_ms = (int)val;
3656                 break;
3657 
3658 #ifdef DEBUG_RESUME
3659         case PARAM_RESUME_TEST:
3660                 mutex_exit(&dp->xmitlock);
3661                 mutex_exit(&dp->intrlock);
3662                 gem_suspend(dp->dip);
3663                 gem_resume(dp->dip);
3664                 mutex_enter(&dp->intrlock);
3665                 mutex_enter(&dp->xmitlock);
3666                 break;
3667 #endif
3668         }
3669 
3670         /* sync with PHY */
3671         usbgem_choose_forcedmode(dp);
3672 
3673         dp->mii_state = MII_STATE_UNKNOWN;
3674         if (dp->ugc.usbgc_mii_hw_link_detection) {
3675                 /* wake up link watcher possiblely sleeps */
3676                 cv_signal(&dp->link_watcher_wait_cv);
3677         }
3678 
3679         return (0);
3680 err:
3681         return (EINVAL);
3682 }
3683 
3684 static void
3685 usbgem_nd_load(struct usbgem_dev *dp,
3686     char *name, ndgetf_t gf, ndsetf_t sf, int item)
3687 {
3688         struct usbgem_nd_arg    *arg;
3689 
3690         ASSERT(item >= 0);
3691         ASSERT(item < PARAM_COUNT);
3692 
3693         arg = &((struct usbgem_nd_arg *)(void *)dp->nd_arg_p)[item];
3694         arg->dp = dp;
3695         arg->item = item;
3696 
3697         DPRINTF(2, (CE_CONT, "!%s: %s: name:%s, item:%d",
3698             dp->name, __func__, name, item));
3699         (void) nd_load(&dp->nd_data_p, name, gf, sf, (caddr_t)arg);
3700 }
3701 
3702 static void
3703 usbgem_nd_setup(struct usbgem_dev *dp)
3704 {
3705         DPRINTF(1, (CE_CONT, "!%s: %s: called, mii_status:0x%b",
3706             dp->name, __func__, dp->mii_status, MII_STATUS_BITS));
3707 
3708         ASSERT(dp->nd_arg_p == NULL);
3709 
3710         dp->nd_arg_p =
3711             kmem_zalloc(sizeof (struct usbgem_nd_arg) * PARAM_COUNT, KM_SLEEP);
3712 
3713 #define SETFUNC(x)      ((x) ? usbgem_param_set : NULL)
3714 
3715         usbgem_nd_load(dp, "autoneg_cap",
3716             usbgem_param_get, NULL, PARAM_AUTONEG_CAP);
3717         usbgem_nd_load(dp, "pause_cap",
3718             usbgem_param_get, NULL, PARAM_PAUSE_CAP);
3719         usbgem_nd_load(dp, "asym_pause_cap",
3720             usbgem_param_get, NULL, PARAM_ASYM_PAUSE_CAP);
3721         usbgem_nd_load(dp, "1000fdx_cap",
3722             usbgem_param_get, NULL, PARAM_1000FDX_CAP);
3723         usbgem_nd_load(dp, "1000hdx_cap",
3724             usbgem_param_get, NULL, PARAM_1000HDX_CAP);
3725         usbgem_nd_load(dp, "100T4_cap",
3726             usbgem_param_get, NULL, PARAM_100T4_CAP);
3727         usbgem_nd_load(dp, "100fdx_cap",
3728             usbgem_param_get, NULL, PARAM_100FDX_CAP);
3729         usbgem_nd_load(dp, "100hdx_cap",
3730             usbgem_param_get, NULL, PARAM_100HDX_CAP);
3731         usbgem_nd_load(dp, "10fdx_cap",
3732             usbgem_param_get, NULL, PARAM_10FDX_CAP);
3733         usbgem_nd_load(dp, "10hdx_cap",
3734             usbgem_param_get, NULL, PARAM_10HDX_CAP);
3735 
3736         /* Our advertised capabilities */
3737         usbgem_nd_load(dp, "adv_autoneg_cap", usbgem_param_get,
3738             SETFUNC(dp->mii_status & MII_STATUS_CANAUTONEG),
3739             PARAM_ADV_AUTONEG_CAP);
3740         usbgem_nd_load(dp, "adv_pause_cap", usbgem_param_get,
3741             SETFUNC(dp->ugc.usbgc_flow_control & 1),
3742             PARAM_ADV_PAUSE_CAP);
3743         usbgem_nd_load(dp, "adv_asym_pause_cap", usbgem_param_get,
3744             SETFUNC(dp->ugc.usbgc_flow_control & 2),
3745             PARAM_ADV_ASYM_PAUSE_CAP);
3746         usbgem_nd_load(dp, "adv_1000fdx_cap", usbgem_param_get,
3747             SETFUNC(dp->mii_xstatus &
3748             (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASET_FD)),
3749             PARAM_ADV_1000FDX_CAP);
3750         usbgem_nd_load(dp, "adv_1000hdx_cap", usbgem_param_get,
3751             SETFUNC(dp->mii_xstatus &
3752             (MII_XSTATUS_1000BASEX | MII_XSTATUS_1000BASET)),
3753             PARAM_ADV_1000HDX_CAP);
3754         usbgem_nd_load(dp, "adv_100T4_cap", usbgem_param_get,
3755             SETFUNC((dp->mii_status & MII_STATUS_100_BASE_T4) &&
3756             !dp->mii_advert_ro),
3757             PARAM_ADV_100T4_CAP);
3758         usbgem_nd_load(dp, "adv_100fdx_cap", usbgem_param_get,
3759             SETFUNC((dp->mii_status & MII_STATUS_100_BASEX_FD) &&
3760             !dp->mii_advert_ro),
3761             PARAM_ADV_100FDX_CAP);
3762         usbgem_nd_load(dp, "adv_100hdx_cap", usbgem_param_get,
3763             SETFUNC((dp->mii_status & MII_STATUS_100_BASEX) &&
3764             !dp->mii_advert_ro),
3765             PARAM_ADV_100HDX_CAP);
3766         usbgem_nd_load(dp, "adv_10fdx_cap", usbgem_param_get,
3767             SETFUNC((dp->mii_status & MII_STATUS_10_FD) &&
3768             !dp->mii_advert_ro),
3769             PARAM_ADV_10FDX_CAP);
3770         usbgem_nd_load(dp, "adv_10hdx_cap", usbgem_param_get,
3771             SETFUNC((dp->mii_status & MII_STATUS_10) &&
3772             !dp->mii_advert_ro),
3773             PARAM_ADV_10HDX_CAP);
3774         usbgem_nd_load(dp, "adv_1000t_ms", usbgem_param_get,
3775             SETFUNC(dp->mii_xstatus &
3776             (MII_XSTATUS_1000BASET_FD | MII_XSTATUS_1000BASET)),
3777             PARAM_ADV_1000T_MS);
3778 
3779 
3780         /* Partner's advertised capabilities */
3781         usbgem_nd_load(dp, "lp_autoneg_cap",
3782             usbgem_param_get, NULL, PARAM_LP_AUTONEG_CAP);
3783         usbgem_nd_load(dp, "lp_pause_cap",
3784             usbgem_param_get, NULL, PARAM_LP_PAUSE_CAP);
3785         usbgem_nd_load(dp, "lp_asym_pause_cap",
3786             usbgem_param_get, NULL, PARAM_LP_ASYM_PAUSE_CAP);
3787         usbgem_nd_load(dp, "lp_1000fdx_cap",
3788             usbgem_param_get, NULL, PARAM_LP_1000FDX_CAP);
3789         usbgem_nd_load(dp, "lp_1000hdx_cap",
3790             usbgem_param_get, NULL, PARAM_LP_1000HDX_CAP);
3791         usbgem_nd_load(dp, "lp_100T4_cap",
3792             usbgem_param_get, NULL, PARAM_LP_100T4_CAP);
3793         usbgem_nd_load(dp, "lp_100fdx_cap",
3794             usbgem_param_get, NULL, PARAM_LP_100FDX_CAP);
3795         usbgem_nd_load(dp, "lp_100hdx_cap",
3796             usbgem_param_get, NULL, PARAM_LP_100HDX_CAP);
3797         usbgem_nd_load(dp, "lp_10fdx_cap",
3798             usbgem_param_get, NULL, PARAM_LP_10FDX_CAP);
3799         usbgem_nd_load(dp, "lp_10hdx_cap",
3800             usbgem_param_get, NULL, PARAM_LP_10HDX_CAP);
3801 
3802         /* Current operating modes */
3803         usbgem_nd_load(dp, "link_status",
3804             usbgem_param_get, NULL, PARAM_LINK_STATUS);
3805         usbgem_nd_load(dp, "link_speed",
3806             usbgem_param_get, NULL, PARAM_LINK_SPEED);
3807         usbgem_nd_load(dp, "link_duplex",
3808             usbgem_param_get, NULL, PARAM_LINK_DUPLEX);
3809         usbgem_nd_load(dp, "link_autoneg",
3810             usbgem_param_get, NULL, PARAM_LINK_AUTONEG);
3811         usbgem_nd_load(dp, "link_rx_pause",
3812             usbgem_param_get, NULL, PARAM_LINK_RX_PAUSE);
3813         usbgem_nd_load(dp, "link_tx_pause",
3814             usbgem_param_get, NULL, PARAM_LINK_TX_PAUSE);
3815 #ifdef DEBUG_RESUME
3816         usbgem_nd_load(dp, "resume_test",
3817             usbgem_param_get, usbgem_param_set, PARAM_RESUME_TEST);
3818 #endif
3819 #undef  SETFUNC
3820 }
3821 
3822 static
3823 enum ioc_reply
3824 usbgem_nd_ioctl(struct usbgem_dev *dp,
3825     queue_t *wq, mblk_t *mp, struct iocblk *iocp)
3826 {
3827         boolean_t       ok;
3828 
3829         DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3830 
3831         switch (iocp->ioc_cmd) {
3832         case ND_GET:
3833                 ok = nd_getset(wq, dp->nd_data_p, mp);
3834                 DPRINTF(1, (CE_CONT,
3835                     "%s: get %s", dp->name, ok ? "OK" : "FAIL"));
3836                 return (ok ? IOC_REPLY : IOC_INVAL);
3837 
3838         case ND_SET:
3839                 ok = nd_getset(wq, dp->nd_data_p, mp);
3840 
3841                 DPRINTF(1, (CE_CONT, "%s: set %s err %d",
3842                     dp->name, ok ? "OK" : "FAIL", iocp->ioc_error));
3843 
3844                 if (!ok) {
3845                         return (IOC_INVAL);
3846                 }
3847 
3848                 if (iocp->ioc_error) {
3849                         return (IOC_REPLY);
3850                 }
3851 
3852                 return (IOC_RESTART_REPLY);
3853         }
3854 
3855         cmn_err(CE_WARN, "%s: invalid cmd 0x%x", dp->name, iocp->ioc_cmd);
3856 
3857         return (IOC_INVAL);
3858 }
3859 
3860 static void
3861 usbgem_nd_cleanup(struct usbgem_dev *dp)
3862 {
3863         ASSERT(dp->nd_data_p != NULL);
3864         ASSERT(dp->nd_arg_p != NULL);
3865 
3866         nd_free(&dp->nd_data_p);
3867 
3868         kmem_free(dp->nd_arg_p, sizeof (struct usbgem_nd_arg) * PARAM_COUNT);
3869         dp->nd_arg_p = NULL;
3870 }
3871 #endif /* USBGEM_CONFIG_ND */
3872 
3873 static void
3874 usbgem_mac_ioctl(struct usbgem_dev *dp, queue_t *wq, mblk_t *mp)
3875 {
3876         struct iocblk   *iocp;
3877         enum ioc_reply  status;
3878 
3879         DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3880 
3881         /*
3882          * Validate the command before bothering with the mutex ...
3883          */
3884         iocp = (void *)mp->b_rptr;
3885         iocp->ioc_error = 0;
3886 
3887         DPRINTF(1, (CE_CONT, "%s: %s cmd:0x%x", dp->name, __func__,
3888             iocp->ioc_cmd));
3889 
3890 #ifdef USBGEM_CONFIG_ND
3891         switch (iocp->ioc_cmd) {
3892         default:
3893                 _NOTE(NOTREACHED)
3894                 status = IOC_INVAL;
3895                 break;
3896 
3897         case ND_GET:
3898         case ND_SET:
3899                 status = usbgem_nd_ioctl(dp, wq, mp, iocp);
3900                 break;
3901         }
3902 
3903         /*
3904          * Finally, decide how to reply
3905          */
3906         switch (status) {
3907         default:
3908         case IOC_INVAL:
3909                 /*
3910                  * Error, reply with a NAK and EINVAL or the specified error
3911                  */
3912                 miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
3913                     EINVAL : iocp->ioc_error);
3914                 break;
3915 
3916         case IOC_DONE:
3917                 /*
3918                  * OK, reply already sent
3919                  */
3920                 break;
3921 
3922         case IOC_RESTART_ACK:
3923         case IOC_ACK:
3924                 /*
3925                  * OK, reply with an ACK
3926                  */
3927                 miocack(wq, mp, 0, 0);
3928                 break;
3929 
3930         case IOC_RESTART_REPLY:
3931         case IOC_REPLY:
3932                 /*
3933                  * OK, send prepared reply as ACK or NAK
3934                  */
3935                 mp->b_datap->db_type =
3936                     iocp->ioc_error == 0 ? M_IOCACK : M_IOCNAK;
3937                 qreply(wq, mp);
3938                 break;
3939         }
3940 #else
3941         miocnak(wq, mp, 0, EINVAL);
3942         return;
3943 #endif /* USBGEM_CONFIG_GLDv3 */
3944 }
3945 
3946 #ifndef SYS_MAC_H
3947 #define XCVR_UNDEFINED  0
3948 #define XCVR_NONE       1
3949 #define XCVR_10         2
3950 #define XCVR_100T4      3
3951 #define XCVR_100X       4
3952 #define XCVR_100T2      5
3953 #define XCVR_1000X      6
3954 #define XCVR_1000T      7
3955 #endif
3956 static int
3957 usbgem_mac_xcvr_inuse(struct usbgem_dev *dp)
3958 {
3959         int     val = XCVR_UNDEFINED;
3960 
3961         if ((dp->mii_status & MII_STATUS_XSTATUS) == 0) {
3962                 if (dp->mii_status & MII_STATUS_100_BASE_T4) {
3963                         val = XCVR_100T4;
3964                 } else if (dp->mii_status &
3965                     (MII_STATUS_100_BASEX_FD |
3966                     MII_STATUS_100_BASEX)) {
3967                         val = XCVR_100X;
3968                 } else if (dp->mii_status &
3969                     (MII_STATUS_100_BASE_T2_FD |
3970                     MII_STATUS_100_BASE_T2)) {
3971                         val = XCVR_100T2;
3972                 } else if (dp->mii_status &
3973                     (MII_STATUS_10_FD | MII_STATUS_10)) {
3974                         val = XCVR_10;
3975                 }
3976         } else if (dp->mii_xstatus &
3977             (MII_XSTATUS_1000BASET_FD | MII_XSTATUS_1000BASET)) {
3978                 val = XCVR_1000T;
3979         } else if (dp->mii_xstatus &
3980             (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASEX)) {
3981                 val = XCVR_1000X;
3982         }
3983 
3984         return (val);
3985 }
3986 
3987 #ifdef USBGEM_CONFIG_GLDv3
3988 /* ============================================================== */
3989 /*
3990  * GLDv3 interface
3991  */
3992 /* ============================================================== */
3993 static int      usbgem_m_getstat(void *, uint_t, uint64_t *);
3994 static int      usbgem_m_start(void *);
3995 static void     usbgem_m_stop(void *);
3996 static int      usbgem_m_setpromisc(void *, boolean_t);
3997 static int      usbgem_m_multicst(void *, boolean_t, const uint8_t *);
3998 static int      usbgem_m_unicst(void *, const uint8_t *);
3999 static mblk_t   *usbgem_m_tx(void *, mblk_t *);
4000 static void     usbgem_m_ioctl(void *, queue_t *, mblk_t *);
4001 #ifdef GEM_CONFIG_MAC_PROP
4002 static int      usbgem_m_setprop(void *, const char *, mac_prop_id_t,
4003     uint_t, const void *);
4004 #ifdef MAC_VERSION_V1
4005 static int      usbgem_m_getprop(void *, const char *, mac_prop_id_t,
4006     uint_t, void *);
4007 #else
4008 static int      usbgem_m_getprop(void *, const char *, mac_prop_id_t,
4009     uint_t, uint_t, void *, uint_t *);
4010 #endif
4011 #endif
4012 
4013 #ifdef _SYS_MAC_PROVIDER_H
4014 #define GEM_M_CALLBACK_FLAGS    (MC_IOCTL)
4015 #else
4016 #define GEM_M_CALLBACK_FLAGS    (MC_IOCTL)
4017 #endif
4018 
4019 static mac_callbacks_t gem_m_callbacks = {
4020 #ifdef USBGEM_CONFIG_MAC_PROP
4021 #ifdef MAC_VERSION_V1
4022         GEM_M_CALLBACK_FLAGS | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
4023 #else
4024         GEM_M_CALLBACK_FLAGS | MC_SETPROP | MC_GETPROP,
4025 #endif
4026 #else
4027         GEM_M_CALLBACK_FLAGS,
4028 #endif
4029         usbgem_m_getstat,
4030         usbgem_m_start,
4031         usbgem_m_stop,
4032         usbgem_m_setpromisc,
4033         usbgem_m_multicst,
4034         usbgem_m_unicst,
4035         usbgem_m_tx,
4036 #ifdef _SYS_MAC_PROVIDER_H
4037 #ifdef MAC_VERSION_V1
4038         NULL,
4039 #endif
4040 #else
4041         NULL,   /* m_resources */
4042 #endif
4043         usbgem_m_ioctl,
4044         NULL, /* m_getcapab */
4045 #ifdef USBGEM_CONFIG_MAC_PROP
4046         NULL,
4047         NULL,
4048         usbgem_m_setprop,
4049         usbgem_m_getprop,
4050 #endif
4051 #ifdef MAC_VERSION_V1
4052         usbgem_m_propinfo,
4053 #endif
4054 };
4055 
4056 static int
4057 usbgem_m_start(void *arg)
4058 {
4059         int     ret;
4060         int     err;
4061         struct usbgem_dev *dp = arg;
4062 
4063         DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4064 
4065         err = EIO;
4066 
4067         rw_enter(&dp->dev_state_lock, RW_WRITER);
4068         dp->nic_state = NIC_STATE_ONLINE;
4069 
4070         if (dp->mac_state == MAC_STATE_DISCONNECTED) {
4071                 err = 0;
4072                 goto x;
4073         }
4074         if (usbgem_mac_init(dp) != USB_SUCCESS) {
4075                 goto x;
4076         }
4077 
4078         /* initialize rx filter state */
4079         sema_p(&dp->rxfilter_lock);
4080         dp->mc_count = 0;
4081         dp->mc_count_req = 0;
4082 
4083         bcopy(dp->dev_addr.ether_addr_octet,
4084             dp->cur_addr.ether_addr_octet, ETHERADDRL);
4085         dp->rxmode |= RXMODE_ENABLE;
4086 
4087         ret = usbgem_hal_set_rx_filter(dp);
4088         sema_v(&dp->rxfilter_lock);
4089 
4090         if (ret != USB_SUCCESS) {
4091                 goto x;
4092         }
4093 
4094         if (dp->mii_state == MII_STATE_LINKUP) {
4095                 /* setup media mode if the link have been up */
4096                 if (usbgem_hal_set_media(dp) != USB_SUCCESS) {
4097                         goto x;
4098                 }
4099                 if (usbgem_mac_start(dp) != USB_SUCCESS) {
4100                         goto x;
4101                 }
4102         }
4103 
4104         err = 0;
4105 x:
4106         rw_exit(&dp->dev_state_lock);
4107         return (err);
4108 }
4109 
4110 static void
4111 usbgem_m_stop(void *arg)
4112 {
4113         struct usbgem_dev       *dp = arg;
4114 
4115         DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4116 
4117         /* stop rx gracefully */
4118         rw_enter(&dp->dev_state_lock, RW_READER);
4119         sema_p(&dp->rxfilter_lock);
4120         dp->rxmode &= ~RXMODE_ENABLE;
4121 
4122         if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4123                 (void) usbgem_hal_set_rx_filter(dp);
4124         }
4125         sema_v(&dp->rxfilter_lock);
4126         rw_exit(&dp->dev_state_lock);
4127 
4128         /* make the nic state inactive */
4129         rw_enter(&dp->dev_state_lock, RW_WRITER);
4130         dp->nic_state = NIC_STATE_STOPPED;
4131 
4132         /* stop mac completely */
4133         if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4134                 (void) usbgem_mac_stop(dp, MAC_STATE_STOPPED, STOP_GRACEFUL);
4135         }
4136         rw_exit(&dp->dev_state_lock);
4137 }
4138 
4139 static int
4140 usbgem_m_multicst(void *arg, boolean_t add, const uint8_t *ep)
4141 {
4142         int     err;
4143         int     ret;
4144         struct usbgem_dev       *dp = arg;
4145 
4146         DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4147 
4148         rw_enter(&dp->dev_state_lock, RW_READER);
4149         if (add) {
4150                 ret = usbgem_add_multicast(dp, ep);
4151         } else {
4152                 ret = usbgem_remove_multicast(dp, ep);
4153         }
4154         rw_exit(&dp->dev_state_lock);
4155 
4156         err = 0;
4157         if (ret != USB_SUCCESS) {
4158 #ifdef GEM_CONFIG_FMA
4159                 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4160 #endif
4161                 err = EIO;
4162         }
4163 
4164         return (err);
4165 }
4166 
4167 static int
4168 usbgem_m_setpromisc(void *arg, boolean_t on)
4169 {
4170         int     err;
4171         struct usbgem_dev       *dp = arg;
4172 
4173         DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4174 
4175         rw_enter(&dp->dev_state_lock, RW_READER);
4176 
4177         sema_p(&dp->rxfilter_lock);
4178         if (on) {
4179                 dp->rxmode |= RXMODE_PROMISC;
4180         } else {
4181                 dp->rxmode &= ~RXMODE_PROMISC;
4182         }
4183 
4184         err = 0;
4185         if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4186                 if (usbgem_hal_set_rx_filter(dp) != USB_SUCCESS) {
4187                         err = EIO;
4188                 }
4189         }
4190         sema_v(&dp->rxfilter_lock);
4191 
4192         rw_exit(&dp->dev_state_lock);
4193 
4194 #ifdef GEM_CONFIG_FMA
4195         if (err != 0) {
4196                 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4197         }
4198 #endif
4199         return (err);
4200 }
4201 
4202 int
4203 usbgem_m_getstat(void *arg, uint_t stat, uint64_t *valp)
4204 {
4205         uint64_t        val;
4206         struct usbgem_dev       *dp = arg;
4207         struct usbgem_stats     *gstp = &dp->stats;
4208 
4209         DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4210 
4211         rw_enter(&dp->dev_state_lock, RW_READER);
4212         if (dp->mac_state == MAC_STATE_DISCONNECTED) {
4213                 rw_exit(&dp->dev_state_lock);
4214                 return (0);
4215         }
4216 
4217         /* LINTED */
4218         if (usbgem_hal_get_stats(dp) != USB_SUCCESS) {
4219 #ifdef GEM_CONFIG_FMA
4220                 rw_exit(&dp->dev_state_lock);
4221                 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4222                 return (EIO);
4223 #endif
4224         }
4225         rw_exit(&dp->dev_state_lock);
4226 
4227         switch (stat) {
4228         case MAC_STAT_IFSPEED:
4229                 val = usbgem_speed_value[dp->speed] *1000000ull;
4230                 break;
4231 
4232         case MAC_STAT_MULTIRCV:
4233                 val = gstp->rmcast;
4234                 break;
4235 
4236         case MAC_STAT_BRDCSTRCV:
4237                 val = gstp->rbcast;
4238                 break;
4239 
4240         case MAC_STAT_MULTIXMT:
4241                 val = gstp->omcast;
4242                 break;
4243 
4244         case MAC_STAT_BRDCSTXMT:
4245                 val = gstp->obcast;
4246                 break;
4247 
4248         case MAC_STAT_NORCVBUF:
4249                 val = gstp->norcvbuf + gstp->missed;
4250                 break;
4251 
4252         case MAC_STAT_IERRORS:
4253                 val = gstp->errrcv;
4254                 break;
4255 
4256         case MAC_STAT_NOXMTBUF:
4257                 val = gstp->noxmtbuf;
4258                 break;
4259 
4260         case MAC_STAT_OERRORS:
4261                 val = gstp->errxmt;
4262                 break;
4263 
4264         case MAC_STAT_COLLISIONS:
4265                 val = gstp->collisions;
4266                 break;
4267 
4268         case MAC_STAT_RBYTES:
4269                 val = gstp->rbytes;
4270                 break;
4271 
4272         case MAC_STAT_IPACKETS:
4273                 val = gstp->rpackets;
4274                 break;
4275 
4276         case MAC_STAT_OBYTES:
4277                 val = gstp->obytes;
4278                 break;
4279 
4280         case MAC_STAT_OPACKETS:
4281                 val = gstp->opackets;
4282                 break;
4283 
4284         case MAC_STAT_UNDERFLOWS:
4285                 val = gstp->underflow;
4286                 break;
4287 
4288         case MAC_STAT_OVERFLOWS:
4289                 val = gstp->overflow;
4290                 break;
4291 
4292         case ETHER_STAT_ALIGN_ERRORS:
4293                 val = gstp->frame;
4294                 break;
4295 
4296         case ETHER_STAT_FCS_ERRORS:
4297                 val = gstp->crc;
4298                 break;
4299 
4300         case ETHER_STAT_FIRST_COLLISIONS:
4301                 val = gstp->first_coll;
4302                 break;
4303 
4304         case ETHER_STAT_MULTI_COLLISIONS:
4305                 val = gstp->multi_coll;
4306                 break;
4307 
4308         case ETHER_STAT_SQE_ERRORS:
4309                 val = gstp->sqe;
4310                 break;
4311 
4312         case ETHER_STAT_DEFER_XMTS:
4313                 val = gstp->defer;
4314                 break;
4315 
4316         case ETHER_STAT_TX_LATE_COLLISIONS:
4317                 val = gstp->xmtlatecoll;
4318                 break;
4319 
4320         case ETHER_STAT_EX_COLLISIONS:
4321                 val = gstp->excoll;
4322                 break;
4323 
4324         case ETHER_STAT_MACXMT_ERRORS:
4325                 val = gstp->xmit_internal_err;
4326                 break;
4327 
4328         case ETHER_STAT_CARRIER_ERRORS:
4329                 val = gstp->nocarrier;
4330                 break;
4331 
4332         case ETHER_STAT_TOOLONG_ERRORS:
4333                 val = gstp->frame_too_long;
4334                 break;
4335 
4336         case ETHER_STAT_MACRCV_ERRORS:
4337                 val = gstp->rcv_internal_err;
4338                 break;
4339 
4340         case ETHER_STAT_XCVR_ADDR:
4341                 val = dp->mii_phy_addr;
4342                 break;
4343 
4344         case ETHER_STAT_XCVR_ID:
4345                 val = dp->mii_phy_id;
4346                 break;
4347 
4348         case ETHER_STAT_XCVR_INUSE:
4349                 val = usbgem_mac_xcvr_inuse(dp);
4350                 break;
4351 
4352         case ETHER_STAT_CAP_1000FDX:
4353                 val = (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
4354                     (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
4355                 break;
4356 
4357         case ETHER_STAT_CAP_1000HDX:
4358                 val = (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
4359                     (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
4360                 break;
4361 
4362         case ETHER_STAT_CAP_100FDX:
4363                 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
4364                 break;
4365 
4366         case ETHER_STAT_CAP_100HDX:
4367                 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
4368                 break;
4369 
4370         case ETHER_STAT_CAP_10FDX:
4371                 val = BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
4372                 break;
4373 
4374         case ETHER_STAT_CAP_10HDX:
4375                 val = BOOLEAN(dp->mii_status & MII_STATUS_10);
4376                 break;
4377 
4378         case ETHER_STAT_CAP_ASMPAUSE:
4379                 val = dp->ugc.usbgc_flow_control > FLOW_CONTROL_SYMMETRIC;
4380                 break;
4381 
4382         case ETHER_STAT_CAP_PAUSE:
4383                 val = dp->ugc.usbgc_flow_control != FLOW_CONTROL_NONE;
4384                 break;
4385 
4386         case ETHER_STAT_CAP_AUTONEG:
4387                 val = BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
4388                 break;
4389 
4390         case ETHER_STAT_ADV_CAP_1000FDX:
4391                 val = dp->anadv_1000fdx;
4392                 break;
4393 
4394         case ETHER_STAT_ADV_CAP_1000HDX:
4395                 val = dp->anadv_1000hdx;
4396                 break;
4397 
4398         case ETHER_STAT_ADV_CAP_100FDX:
4399                 val = dp->anadv_100fdx;
4400                 break;
4401 
4402         case ETHER_STAT_ADV_CAP_100HDX:
4403                 val = dp->anadv_100hdx;
4404                 break;
4405 
4406         case ETHER_STAT_ADV_CAP_10FDX:
4407                 val = dp->anadv_10fdx;
4408                 break;
4409 
4410         case ETHER_STAT_ADV_CAP_10HDX:
4411                 val = dp->anadv_10hdx;
4412                 break;
4413 
4414         case ETHER_STAT_ADV_CAP_ASMPAUSE:
4415                 val = dp->anadv_asmpause;
4416                 break;
4417 
4418         case ETHER_STAT_ADV_CAP_PAUSE:
4419                 val = dp->anadv_pause;
4420                 break;
4421 
4422         case ETHER_STAT_ADV_CAP_AUTONEG:
4423                 val = dp->anadv_autoneg;
4424                 break;
4425 
4426         case ETHER_STAT_LP_CAP_1000FDX:
4427                 val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_FULL);
4428                 break;
4429 
4430         case ETHER_STAT_LP_CAP_1000HDX:
4431                 val = BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_HALF);
4432                 break;
4433 
4434         case ETHER_STAT_LP_CAP_100FDX:
4435                 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX_FD);
4436                 break;
4437 
4438         case ETHER_STAT_LP_CAP_100HDX:
4439                 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX);
4440                 break;
4441 
4442         case ETHER_STAT_LP_CAP_10FDX:
4443                 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T_FD);
4444                 break;
4445 
4446         case ETHER_STAT_LP_CAP_10HDX:
4447                 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T);
4448                 break;
4449 
4450         case ETHER_STAT_LP_CAP_ASMPAUSE:
4451                 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_ASM_DIR);
4452                 break;
4453 
4454         case ETHER_STAT_LP_CAP_PAUSE:
4455                 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_PAUSE);
4456                 break;
4457 
4458         case ETHER_STAT_LP_CAP_AUTONEG:
4459                 val = BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
4460                 break;
4461 
4462         case ETHER_STAT_LINK_ASMPAUSE:
4463                 val = BOOLEAN(dp->flow_control & 2);
4464                 break;
4465 
4466         case ETHER_STAT_LINK_PAUSE:
4467                 val = BOOLEAN(dp->flow_control & 1);
4468                 break;
4469 
4470         case ETHER_STAT_LINK_AUTONEG:
4471                 val = dp->anadv_autoneg &&
4472                     BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
4473                 break;
4474 
4475         case ETHER_STAT_LINK_DUPLEX:
4476                 val = (dp->mii_state == MII_STATE_LINKUP) ?
4477                     (dp->full_duplex ? 2 : 1) : 0;
4478                 break;
4479 
4480         case ETHER_STAT_TOOSHORT_ERRORS:
4481                 val = gstp->runt;
4482                 break;
4483 #ifdef NEVER    /* it doesn't make sense */
4484         case ETHER_STAT_CAP_REMFAULT:
4485                 val = B_TRUE;
4486                 break;
4487 
4488         case ETHER_STAT_ADV_REMFAULT:
4489                 val = dp->anadv_remfault;
4490                 break;
4491 #endif
4492         case ETHER_STAT_LP_REMFAULT:
4493                 val = BOOLEAN(dp->mii_lpable & MII_AN_ADVERT_REMFAULT);
4494                 break;
4495 
4496         case ETHER_STAT_JABBER_ERRORS:
4497                 val = gstp->jabber;
4498                 break;
4499 
4500         case ETHER_STAT_CAP_100T4:
4501                 val = BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
4502                 break;
4503 
4504         case ETHER_STAT_ADV_CAP_100T4:
4505                 val = dp->anadv_100t4;
4506                 break;
4507 
4508         case ETHER_STAT_LP_CAP_100T4:
4509                 val = BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_T4);
4510                 break;
4511 
4512         default:
4513 #if GEM_DEBUG_LEVEL > 2
4514                 cmn_err(CE_WARN,
4515                     "%s: unrecognized parameter value = %d",
4516                     __func__, stat);
4517 #endif
4518                 *valp = 0;
4519                 return (ENOTSUP);
4520         }
4521 
4522         *valp = val;
4523 
4524         return (0);
4525 }
4526 
4527 static int
4528 usbgem_m_unicst(void *arg, const uint8_t *mac)
4529 {
4530         int     err;
4531         struct usbgem_dev       *dp = arg;
4532 
4533         DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4534 
4535         rw_enter(&dp->dev_state_lock, RW_READER);
4536 
4537         sema_p(&dp->rxfilter_lock);
4538         bcopy(mac, dp->cur_addr.ether_addr_octet, ETHERADDRL);
4539         dp->rxmode |= RXMODE_ENABLE;
4540 
4541         err = 0;
4542         if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4543                 if (usbgem_hal_set_rx_filter(dp) != USB_SUCCESS) {
4544                         err = EIO;
4545                 }
4546         }
4547         sema_v(&dp->rxfilter_lock);
4548         rw_exit(&dp->dev_state_lock);
4549 
4550 #ifdef GEM_CONFIG_FMA
4551         if (err != 0) {
4552                 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4553         }
4554 #endif
4555         return (err);
4556 }
4557 
4558 /*
4559  * usbgem_m_tx is used only for sending data packets into ethernet wire.
4560  */
4561 static mblk_t *
4562 usbgem_m_tx(void *arg, mblk_t *mp_head)
4563 {
4564         int     limit;
4565         mblk_t  *mp;
4566         mblk_t  *nmp;
4567         struct usbgem_dev       *dp = arg;
4568 
4569         DPRINTF(4, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4570 
4571         mp = mp_head;
4572 
4573         rw_enter(&dp->dev_state_lock, RW_READER);
4574 
4575         if (dp->mii_state != MII_STATE_LINKUP ||
4576             dp->mac_state != MAC_STATE_ONLINE) {
4577                 /* some nics hate to send packets during the link is down */
4578                 for (; mp; mp = nmp) {
4579                         nmp = mp->b_next;
4580                         mp->b_next = NULL;
4581                         freemsg(mp);
4582                 }
4583                 goto x;
4584         }
4585 
4586         ASSERT(dp->nic_state == NIC_STATE_ONLINE);
4587 
4588         limit = dp->tx_max_packets;
4589         for (; limit-- && mp; mp = nmp) {
4590                 nmp = mp->b_next;
4591                 mp->b_next = NULL;
4592                 if (usbgem_send_common(dp, mp,
4593                     (limit == 0 && nmp) ? 1 : 0)) {
4594                         mp->b_next = nmp;
4595                         break;
4596                 }
4597         }
4598 #ifdef CONFIG_TX_LIMITER
4599         if (mp == mp_head) {
4600                 /* no packets were sent, descrease allocation limit */
4601                 mutex_enter(&dp->txlock);
4602                 dp->tx_max_packets = max(dp->tx_max_packets - 1, 1);
4603                 mutex_exit(&dp->txlock);
4604         }
4605 #endif
4606 x:
4607         rw_exit(&dp->dev_state_lock);
4608 
4609         return (mp);
4610 }
4611 
4612 static void
4613 usbgem_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
4614 {
4615         struct usbgem_dev       *dp = arg;
4616 
4617         DPRINTF(1, (CE_CONT, "!%s: %s: called",
4618             ((struct usbgem_dev *)arg)->name, __func__));
4619 
4620         rw_enter(&dp->dev_state_lock, RW_READER);
4621         usbgem_mac_ioctl((struct usbgem_dev *)arg, wq, mp);
4622         rw_exit(&dp->dev_state_lock);
4623 }
4624 
4625 static void
4626 usbgem_gld3_init(struct usbgem_dev *dp, mac_register_t *macp)
4627 {
4628         macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
4629         macp->m_driver = dp;
4630         macp->m_dip = dp->dip;
4631         macp->m_src_addr = dp->dev_addr.ether_addr_octet;
4632         macp->m_callbacks = &gem_m_callbacks;
4633         macp->m_min_sdu = 0;
4634         macp->m_max_sdu = dp->mtu;
4635 
4636         if (dp->misc_flag & USBGEM_VLAN) {
4637                 macp->m_margin = VTAG_SIZE;
4638         }
4639 }
4640 #else
4641 /* ============================================================== */
4642 /*
4643  * GLDv2 interface
4644  */
4645 /* ============================================================== */
4646 static int usbgem_gld_reset(gld_mac_info_t *);
4647 static int usbgem_gld_start(gld_mac_info_t *);
4648 static int usbgem_gld_stop(gld_mac_info_t *);
4649 static int usbgem_gld_set_mac_address(gld_mac_info_t *, uint8_t *);
4650 static int usbgem_gld_set_multicast(gld_mac_info_t *, uint8_t *, int);
4651 static int usbgem_gld_set_promiscuous(gld_mac_info_t *, int);
4652 static int usbgem_gld_get_stats(gld_mac_info_t *, struct gld_stats *);
4653 static int usbgem_gld_send(gld_mac_info_t *, mblk_t *);
4654 static int usbgem_gld_send_tagged(gld_mac_info_t *, mblk_t *, uint32_t);
4655 
4656 static int
4657 usbgem_gld_reset(gld_mac_info_t *macinfo)
4658 {
4659         int     err;
4660         struct usbgem_dev       *dp;
4661 
4662         err = GLD_SUCCESS;
4663         dp = (struct usbgem_dev *)macinfo->gldm_private;
4664 
4665         DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4666 
4667         rw_enter(&dp->dev_state_lock, RW_WRITER);
4668         if (usbgem_mac_init(dp) != USB_SUCCESS) {
4669                 err = GLD_FAILURE;
4670                 goto x;
4671         }
4672 
4673         dp->nic_state = NIC_STATE_INITIALIZED;
4674 
4675         /* setup media mode if the link have been up */
4676         if (dp->mii_state == MII_STATE_LINKUP) {
4677                 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4678                         (void) usbgem_hal_set_media(dp);
4679                 }
4680         }
4681 x:
4682         rw_exit(&dp->dev_state_lock);
4683         return (err);
4684 }
4685 
4686 static int
4687 usbgem_gld_start(gld_mac_info_t *macinfo)
4688 {
4689         int     err;
4690         struct usbgem_dev *dp;
4691 
4692         dp = (struct usbgem_dev *)macinfo->gldm_private;
4693 
4694         DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4695 
4696         rw_enter(&dp->dev_state_lock, RW_WRITER);
4697 
4698         dp->nic_state = NIC_STATE_ONLINE;
4699 
4700         if (dp->mii_state == MII_STATE_LINKUP) {
4701                 if (usbgem_mac_start(dp) != USB_SUCCESS) {
4702                         /* sema_v(&dp->mii_lock); */
4703                         err = GLD_FAILURE;
4704                         goto x;
4705                 }
4706         }
4707 
4708         /*
4709          * XXX - don't call gld_linkstate() here,
4710          * otherwise it cause recursive mutex call.
4711          */
4712         err = GLD_SUCCESS;
4713 x:
4714         rw_exit(&dp->dev_state_lock);
4715 
4716         return (err);
4717 }
4718 
4719 static int
4720 usbgem_gld_stop(gld_mac_info_t *macinfo)
4721 {
4722         int     err = GLD_SUCCESS;
4723         struct usbgem_dev       *dp;
4724 
4725         dp = (struct usbgem_dev *)macinfo->gldm_private;
4726 
4727         DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4728 
4729         /* try to stop rx gracefully */
4730         rw_enter(&dp->dev_state_lock, RW_READER);
4731         sema_p(&dp->rxfilter_lock);
4732         dp->rxmode &= ~RXMODE_ENABLE;
4733 
4734         if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4735                 (void) usbgem_hal_set_rx_filter(dp);
4736         }
4737         sema_v(&dp->rxfilter_lock);
4738         rw_exit(&dp->dev_state_lock);
4739 
4740         /* make the nic state inactive */
4741         rw_enter(&dp->dev_state_lock, RW_WRITER);
4742         dp->nic_state = NIC_STATE_STOPPED;
4743 
4744         if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4745                 if (usbgem_mac_stop(dp, MAC_STATE_STOPPED, STOP_GRACEFUL)
4746                     != USB_SUCCESS) {
4747                         err = GLD_FAILURE;
4748                 }
4749         }
4750         rw_exit(&dp->dev_state_lock);
4751 
4752         return (err);
4753 }
4754 
4755 static int
4756 usbgem_gld_set_multicast(gld_mac_info_t *macinfo, uint8_t *ep, int flag)
4757 {
4758         int             err;
4759         int             ret;
4760         struct usbgem_dev       *dp;
4761 
4762         dp = (struct usbgem_dev *)macinfo->gldm_private;
4763 
4764         DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4765 
4766         rw_enter(&dp->dev_state_lock, RW_READER);
4767         if (flag == GLD_MULTI_ENABLE) {
4768                 ret = usbgem_add_multicast(dp, ep);
4769         } else {
4770                 ret = usbgem_remove_multicast(dp, ep);
4771         }
4772         rw_exit(&dp->dev_state_lock);
4773 
4774         err = GLD_SUCCESS;
4775         if (ret != USB_SUCCESS) {
4776 #ifdef GEM_CONFIG_FMA
4777                 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4778 #endif
4779                 err = GLD_FAILURE;
4780         }
4781         return (err);
4782 }
4783 
4784 static int
4785 usbgem_gld_set_promiscuous(gld_mac_info_t *macinfo, int flag)
4786 {
4787         boolean_t       need_to_change = B_TRUE;
4788         struct usbgem_dev       *dp;
4789 
4790         dp = (struct usbgem_dev *)macinfo->gldm_private;
4791 
4792         DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4793 
4794         sema_p(&dp->rxfilter_lock);
4795         if (flag == GLD_MAC_PROMISC_NONE) {
4796                 dp->rxmode &= ~(RXMODE_PROMISC | RXMODE_ALLMULTI_REQ);
4797         } else if (flag == GLD_MAC_PROMISC_MULTI) {
4798                 dp->rxmode |= RXMODE_ALLMULTI_REQ;
4799         } else if (flag == GLD_MAC_PROMISC_PHYS) {
4800                 dp->rxmode |= RXMODE_PROMISC;
4801         } else {
4802                 /* mode unchanged */
4803                 need_to_change = B_FALSE;
4804         }
4805 
4806         if (need_to_change) {
4807                 if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4808                         (void) usbgem_hal_set_rx_filter(dp);
4809                 }
4810         }
4811         sema_v(&dp->rxfilter_lock);
4812 
4813         return (GLD_SUCCESS);
4814 }
4815 
4816 static int
4817 usbgem_gld_set_mac_address(gld_mac_info_t *macinfo, uint8_t *mac)
4818 {
4819         struct usbgem_dev       *dp;
4820         dp = (struct usbgem_dev *)macinfo->gldm_private;
4821 
4822         DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4823 
4824         sema_p(&dp->rxfilter_lock);
4825         bcopy(mac, dp->cur_addr.ether_addr_octet, ETHERADDRL);
4826         dp->rxmode |= RXMODE_ENABLE;
4827 
4828         if (dp->mac_state != MAC_STATE_DISCONNECTED) {
4829                 (void) usbgem_hal_set_rx_filter(dp);
4830         }
4831         sema_v(&dp->rxfilter_lock);
4832 
4833         return (GLD_SUCCESS);
4834 }
4835 
4836 static  int
4837 usbgem_gld_get_stats(gld_mac_info_t *macinfo, struct gld_stats *gs)
4838 {
4839         struct usbgem_dev       *dp;
4840         struct usbgem_stats     *vs;
4841 
4842         dp = (struct usbgem_dev *)macinfo->gldm_private;
4843 
4844         if ((*dp->ugc.usbgc_get_stats)(dp) != USB_SUCCESS) {
4845 #ifdef GEM_CONFIG_FMA
4846                 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4847 #endif
4848                 return (USB_FAILURE);
4849         }
4850 
4851         vs = &dp->stats;
4852 
4853         gs->glds_errxmt = vs->errxmt;
4854         gs->glds_errrcv = vs->errrcv;
4855         gs->glds_collisions = vs->collisions;
4856 
4857         gs->glds_excoll = vs->excoll;
4858         gs->glds_defer = vs->defer;
4859         gs->glds_frame = vs->frame;
4860         gs->glds_crc = vs->crc;
4861 
4862         gs->glds_overflow = vs->overflow; /* fifo err,underrun,rbufovf */
4863         gs->glds_underflow = vs->underflow;
4864         gs->glds_short = vs->runt;
4865         gs->glds_missed = vs->missed; /* missed pkts while rbuf ovf */
4866         gs->glds_xmtlatecoll = vs->xmtlatecoll;
4867         gs->glds_nocarrier = vs->nocarrier;
4868         gs->glds_norcvbuf = vs->norcvbuf; /* OS resource exaust */
4869         gs->glds_intr = vs->intr;
4870 
4871         /* all before here must be kept in place for v0 compatibility */
4872         gs->glds_speed = usbgem_speed_value[dp->speed] * 1000000;
4873         gs->glds_media = GLDM_PHYMII;
4874         gs->glds_duplex = dp->full_duplex ? GLD_DUPLEX_FULL : GLD_DUPLEX_HALF;
4875 
4876         /* gs->glds_media_specific */
4877         gs->glds_dot3_first_coll = vs->first_coll;
4878         gs->glds_dot3_multi_coll = vs->multi_coll;
4879         gs->glds_dot3_sqe_error = 0;
4880         gs->glds_dot3_mac_xmt_error = 0;
4881         gs->glds_dot3_mac_rcv_error = 0;
4882         gs->glds_dot3_frame_too_long = vs->frame_too_long;
4883 
4884         return (GLD_SUCCESS);
4885 }
4886 
4887 static int
4888 usbgem_gld_ioctl(gld_mac_info_t *macinfo, queue_t *wq, mblk_t *mp)
4889 {
4890         struct usbgem_dev       *dp;
4891 
4892         dp = (struct usbgem_dev *)macinfo->gldm_private;
4893         usbgem_mac_ioctl(dp, wq, mp);
4894 
4895         return (GLD_SUCCESS);
4896 }
4897 
4898 /*
4899  * gem_gld_send is used only for sending data packets into ethernet wire.
4900  */
4901 static int
4902 usbgem_gld_send(gld_mac_info_t *macinfo, mblk_t *mp)
4903 {
4904         int             ret;
4905         uint32_t        flags = 0;
4906         struct usbgem_dev       *dp;
4907 
4908         dp = (struct usbgem_dev *)macinfo->gldm_private;
4909 
4910         /* nic state must be online of suspended */
4911         rw_enter(&dp->dev_state_lock, RW_READER);
4912 
4913         ASSERT(dp->nic_state == NIC_STATE_ONLINE);
4914         ASSERT(mp->b_next == NULL);
4915 
4916         if (dp->mii_state != MII_STATE_LINKUP) {
4917                 /* Some nics hate to send packets while the link is down. */
4918                 /* we discard the untransmitted packets silently */
4919                 rw_exit(&dp->dev_state_lock);
4920 
4921                 freemsg(mp);
4922 #ifdef GEM_CONFIG_FMA
4923                 /* FIXME - should we ignore the error? */
4924                 ddi_fm_service_impact(dp->dip, DDI_SERVICE_DEGRADED);
4925 #endif
4926                 return (GLD_SUCCESS);
4927         }
4928 
4929         ret = (usbgem_send_common(dp, mp, flags) == NULL)
4930             ? GLD_SUCCESS : GLD_NORESOURCES;
4931         rw_exit(&dp->dev_state_lock);
4932 
4933         return (ret);
4934 }
4935 
4936 /*
4937  * usbgem_gld_send is used only for sending data packets into ethernet wire.
4938  */
4939 static int
4940 usbgem_gld_send_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag)
4941 {
4942         uint32_t        flags;
4943         struct usbgem_dev       *dp;
4944 
4945         dp = (struct usbgem_dev *)macinfo->gldm_private;
4946 
4947         /*
4948          * Some nics hate to send packets while the link is down.
4949          */
4950         if (dp->mii_state != MII_STATE_LINKUP) {
4951                 /* we dicard the untransmitted packets silently */
4952                 freemsg(mp);
4953 #ifdef GEM_CONFIG_FMA
4954                 /* FIXME - should we ignore the error? */
4955                 ddi_fm_service_impact(dp->dip, DDI_SERVICE_UNAFFECTED);
4956 #endif
4957                 return (GLD_SUCCESS);
4958         }
4959 #ifdef notyet
4960         flags = GLD_VTAG_TCI(vtag) << GEM_SEND_VTAG_SHIFT;
4961 #endif
4962         return ((usbgem_send_common(dp, mp, 0) == NULL) ?
4963             GLD_SUCCESS : GLD_NORESOURCES);
4964 }
4965 
4966 static void
4967 usbgem_gld_init(struct usbgem_dev *dp, gld_mac_info_t *macinfo, char *ident)
4968 {
4969         /*
4970          * configure GLD
4971          */
4972         macinfo->gldm_devinfo = dp->dip;
4973         macinfo->gldm_private = (caddr_t)dp;
4974 
4975         macinfo->gldm_reset = usbgem_gld_reset;
4976         macinfo->gldm_start = usbgem_gld_start;
4977         macinfo->gldm_stop = usbgem_gld_stop;
4978         macinfo->gldm_set_mac_addr = usbgem_gld_set_mac_address;
4979         macinfo->gldm_send = usbgem_gld_send;
4980         macinfo->gldm_set_promiscuous = usbgem_gld_set_promiscuous;
4981         macinfo->gldm_get_stats = usbgem_gld_get_stats;
4982         macinfo->gldm_ioctl = usbgem_gld_ioctl;
4983         macinfo->gldm_set_multicast = usbgem_gld_set_multicast;
4984         macinfo->gldm_intr = NULL;
4985         macinfo->gldm_mctl = NULL;
4986 
4987         macinfo->gldm_ident = ident;
4988         macinfo->gldm_type = DL_ETHER;
4989         macinfo->gldm_minpkt = 0;
4990         macinfo->gldm_maxpkt = dp->mtu;
4991         macinfo->gldm_addrlen = ETHERADDRL;
4992         macinfo->gldm_saplen = -2;
4993         macinfo->gldm_ppa = ddi_get_instance(dp->dip);
4994 #ifdef GLD_CAP_LINKSTATE
4995         macinfo->gldm_capabilities = GLD_CAP_LINKSTATE;
4996 #endif
4997         macinfo->gldm_vendor_addr = dp->dev_addr.ether_addr_octet;
4998         macinfo->gldm_broadcast_addr = usbgem_bcastaddr;
4999 }
5000 #endif /* USBGEM_CONFIG_GLDv3 */
5001 
5002 
5003 /* ======================================================================== */
5004 /*
5005  * .conf interface
5006  */
5007 /* ======================================================================== */
5008 void
5009 usbgem_generate_macaddr(struct usbgem_dev *dp, uint8_t *mac)
5010 {
5011         extern char     hw_serial[];
5012         char            *hw_serial_p;
5013         int             i;
5014         uint64_t        val;
5015         uint64_t        key;
5016 
5017         cmn_err(CE_NOTE,
5018             "!%s: using temp ether address,"
5019             " do not use this for long time",
5020             dp->name);
5021 
5022         /* prefer a fixed address for DHCP */
5023         hw_serial_p = &hw_serial[0];
5024         val = stoi(&hw_serial_p);
5025 
5026         key = 0;
5027         for (i = 0; i < USBGEM_NAME_LEN; i++) {
5028                 if (dp->name[i] == 0) {
5029                         break;
5030                 }
5031                 key ^= dp->name[i];
5032         }
5033         key ^= ddi_get_instance(dp->dip);
5034         val ^= key << 32;
5035 
5036         /* generate a local address */
5037         mac[0] = 0x02;
5038         mac[1] = (uint8_t)(val >> 32);
5039         mac[2] = (uint8_t)(val >> 24);
5040         mac[3] = (uint8_t)(val >> 16);
5041         mac[4] = (uint8_t)(val >> 8);
5042         mac[5] = (uint8_t)val;
5043 }
5044 
5045 boolean_t
5046 usbgem_get_mac_addr_conf(struct usbgem_dev *dp)
5047 {
5048         char            propname[32];
5049         char            *valstr;
5050         uint8_t         mac[ETHERADDRL];
5051         char            *cp;
5052         int             c;
5053         int             i;
5054         int             j;
5055         uint8_t         v;
5056         uint8_t         d;
5057         uint8_t         ored;
5058 
5059         DPRINTF(3, (CE_CONT, "!%s: %s: called", dp->name, __func__));
5060         /*
5061          * Get ethernet address from .conf file
5062          */
5063         (void) sprintf(propname, "mac-addr");
5064         if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, dp->dip,
5065             DDI_PROP_DONTPASS, propname, &valstr)) != DDI_PROP_SUCCESS) {
5066                 return (B_FALSE);
5067         }
5068 
5069         if (strlen(valstr) != ETHERADDRL*3-1) {
5070                 goto syntax_err;
5071         }
5072 
5073         cp = valstr;
5074         j = 0;
5075         ored = 0;
5076         for (;;) {
5077                 v = 0;
5078                 for (i = 0; i < 2; i++) {
5079                         c = *cp++;
5080 
5081                         if (c >= 'a' && c <= 'f') {
5082                                 d = c - 'a' + 10;
5083                         } else if (c >= 'A' && c <= 'F') {
5084                                 d = c - 'A' + 10;
5085                         } else if (c >= '0' && c <= '9') {
5086                                 d = c - '0';
5087                         } else {
5088                                 goto syntax_err;
5089                         }
5090                         v = (v << 4) | d;
5091                 }
5092 
5093                 mac[j++] = v;
5094                 ored |= v;
5095                 if (j == ETHERADDRL) {
5096                         /* done */
5097                         break;
5098                 }
5099 
5100                 c = *cp++;
5101                 if (c != ':') {
5102                         goto syntax_err;
5103                 }
5104         }
5105 
5106         if (ored == 0) {
5107                 usbgem_generate_macaddr(dp, mac);
5108         }
5109         for (i = 0; i < ETHERADDRL; i++) {
5110                 dp->dev_addr.ether_addr_octet[i] = mac[i];
5111         }
5112         ddi_prop_free(valstr);
5113         return (B_TRUE);
5114 
5115 syntax_err:
5116         cmn_err(CE_CONT,
5117             "!%s: read mac addr: trying .conf: syntax err %s",
5118             dp->name, valstr);
5119         ddi_prop_free(valstr);
5120 
5121         return (B_FALSE);
5122 }
5123 
5124 static void
5125 usbgem_read_conf(struct usbgem_dev *dp)
5126 {
5127         int     val;
5128 
5129         DPRINTF(1, (CE_CONT, "!%s: %s: called", dp->name, __func__));
5130 
5131         /*
5132          * Get media mode infomation from .conf file
5133          */
5134         dp->anadv_autoneg = usbgem_prop_get_int(dp, "adv_autoneg_cap", 1) != 0;
5135         dp->anadv_1000fdx = usbgem_prop_get_int(dp, "adv_1000fdx_cap", 1) != 0;
5136         dp->anadv_1000hdx = usbgem_prop_get_int(dp, "adv_1000hdx_cap", 1) != 0;
5137         dp->anadv_100t4 = usbgem_prop_get_int(dp, "adv_100T4_cap", 1) != 0;
5138         dp->anadv_100fdx = usbgem_prop_get_int(dp, "adv_100fdx_cap", 1) != 0;
5139         dp->anadv_100hdx = usbgem_prop_get_int(dp, "adv_100hdx_cap", 1) != 0;
5140         dp->anadv_10fdx = usbgem_prop_get_int(dp, "adv_10fdx_cap", 1) != 0;
5141         dp->anadv_10hdx = usbgem_prop_get_int(dp, "adv_10hdx_cap", 1) != 0;
5142         dp->anadv_1000t_ms = usbgem_prop_get_int(dp, "adv_1000t_ms", 0);
5143 
5144         if ((ddi_prop_exists(DDI_DEV_T_ANY, dp->dip,
5145             DDI_PROP_DONTPASS, "full-duplex"))) {
5146                 dp->full_duplex =
5147                     usbgem_prop_get_int(dp, "full-duplex", 1) != 0;
5148                 dp->anadv_autoneg = B_FALSE;
5149                 if (dp->full_duplex) {
5150                         dp->anadv_1000hdx = B_FALSE;
5151                         dp->anadv_100hdx = B_FALSE;
5152                         dp->anadv_10hdx = B_FALSE;
5153                 } else {
5154                         dp->anadv_1000fdx = B_FALSE;
5155                         dp->anadv_100fdx = B_FALSE;
5156                         dp->anadv_10fdx = B_FALSE;
5157                 }
5158         }
5159 
5160         if ((val = usbgem_prop_get_int(dp, "speed", 0)) > 0) {
5161                 dp->anadv_autoneg = B_FALSE;
5162                 switch (val) {
5163                 case 1000:
5164                         dp->speed = USBGEM_SPD_1000;
5165                         dp->anadv_100t4 = B_FALSE;
5166                         dp->anadv_100fdx = B_FALSE;
5167                         dp->anadv_100hdx = B_FALSE;
5168                         dp->anadv_10fdx = B_FALSE;
5169                         dp->anadv_10hdx = B_FALSE;
5170                         break;
5171                 case 100:
5172                         dp->speed = USBGEM_SPD_100;
5173                         dp->anadv_1000fdx = B_FALSE;
5174                         dp->anadv_1000hdx = B_FALSE;
5175                         dp->anadv_10fdx = B_FALSE;
5176                         dp->anadv_10hdx = B_FALSE;
5177                         break;
5178                 case 10:
5179                         dp->speed = USBGEM_SPD_10;
5180                         dp->anadv_1000fdx = B_FALSE;
5181                         dp->anadv_1000hdx = B_FALSE;
5182                         dp->anadv_100t4 = B_FALSE;
5183                         dp->anadv_100fdx = B_FALSE;
5184                         dp->anadv_100hdx = B_FALSE;
5185                         break;
5186                 default:
5187                         cmn_err(CE_WARN,
5188                             "!%s: property %s: illegal value:%d",
5189                             dp->name, "speed", val);
5190                         dp->anadv_autoneg = B_TRUE;
5191                         break;
5192                 }
5193         }
5194         val = usbgem_prop_get_int(dp,
5195             "adv_pause", dp->ugc.usbgc_flow_control & 1);
5196         val |= usbgem_prop_get_int(dp,
5197             "adv_asmpause", BOOLEAN(dp->ugc.usbgc_flow_control & 2)) << 1;
5198         if (val > FLOW_CONTROL_RX_PAUSE || val < FLOW_CONTROL_NONE) {
5199                 cmn_err(CE_WARN,
5200                     "!%s: property %s: illegal value:%d",
5201                     dp->name, "flow-control", val);
5202         } else {
5203                 val = min(val, dp->ugc.usbgc_flow_control);
5204         }
5205         dp->anadv_pause = BOOLEAN(val & 1);
5206         dp->anadv_asmpause = BOOLEAN(val & 2);
5207 
5208         dp->mtu = usbgem_prop_get_int(dp, "mtu", dp->mtu);
5209         dp->txthr = usbgem_prop_get_int(dp, "txthr", dp->txthr);
5210         dp->rxthr = usbgem_prop_get_int(dp, "rxthr", dp->rxthr);
5211         dp->txmaxdma = usbgem_prop_get_int(dp, "txmaxdma", dp->txmaxdma);
5212         dp->rxmaxdma = usbgem_prop_get_int(dp, "rxmaxdma", dp->rxmaxdma);
5213 #ifdef GEM_CONFIG_POLLING
5214         dp->poll_pkt_delay =
5215             usbgem_prop_get_int(dp, "pkt_delay", dp->poll_pkt_delay);
5216 
5217         dp->max_poll_interval[GEM_SPD_10] =
5218             usbgem_prop_get_int(dp, "max_poll_interval_10",
5219             dp->max_poll_interval[GEM_SPD_10]);
5220         dp->max_poll_interval[GEM_SPD_100] =
5221             usbgem_prop_get_int(dp, "max_poll_interval_100",
5222             dp->max_poll_interval[GEM_SPD_100]);
5223         dp->max_poll_interval[GEM_SPD_1000] =
5224             usbgem_prop_get_int(dp, "max_poll_interval_1000",
5225             dp->max_poll_interval[GEM_SPD_1000]);
5226 
5227         dp->min_poll_interval[GEM_SPD_10] =
5228             usbgem_prop_get_int(dp, "min_poll_interval_10",
5229             dp->min_poll_interval[GEM_SPD_10]);
5230         dp->min_poll_interval[GEM_SPD_100] =
5231             usbgem_prop_get_int(dp, "min_poll_interval_100",
5232             dp->min_poll_interval[GEM_SPD_100]);
5233         dp->min_poll_interval[GEM_SPD_1000] =
5234             usbgem_prop_get_int(dp, "min_poll_interval_1000",
5235             dp->min_poll_interval[GEM_SPD_1000]);
5236 #endif
5237 }
5238 
5239 /*
5240  * usbem kstat support
5241  */
5242 #ifndef GEM_CONFIG_GLDv3
5243 /* kstat items based from dmfe driver */
5244 
5245 struct usbgem_kstat_named {
5246         struct kstat_named      ks_xcvr_addr;
5247         struct kstat_named      ks_xcvr_id;
5248         struct kstat_named      ks_xcvr_inuse;
5249         struct kstat_named      ks_link_up;
5250         struct kstat_named      ks_link_duplex; /* 0:unknwon, 1:half, 2:full */
5251         struct kstat_named      ks_cap_1000fdx;
5252         struct kstat_named      ks_cap_1000hdx;
5253         struct kstat_named      ks_cap_100fdx;
5254         struct kstat_named      ks_cap_100hdx;
5255         struct kstat_named      ks_cap_10fdx;
5256         struct kstat_named      ks_cap_10hdx;
5257 #ifdef NEVER
5258         struct kstat_named      ks_cap_remfault;
5259 #endif
5260         struct kstat_named      ks_cap_autoneg;
5261 
5262         struct kstat_named      ks_adv_cap_1000fdx;
5263         struct kstat_named      ks_adv_cap_1000hdx;
5264         struct kstat_named      ks_adv_cap_100fdx;
5265         struct kstat_named      ks_adv_cap_100hdx;
5266         struct kstat_named      ks_adv_cap_10fdx;
5267         struct kstat_named      ks_adv_cap_10hdx;
5268 #ifdef NEVER
5269         struct kstat_named      ks_adv_cap_remfault;
5270 #endif
5271         struct kstat_named      ks_adv_cap_autoneg;
5272         struct kstat_named      ks_lp_cap_1000fdx;
5273         struct kstat_named      ks_lp_cap_1000hdx;
5274         struct kstat_named      ks_lp_cap_100fdx;
5275         struct kstat_named      ks_lp_cap_100hdx;
5276         struct kstat_named      ks_lp_cap_10fdx;
5277         struct kstat_named      ks_lp_cap_10hdx;
5278         struct kstat_named      ks_lp_cap_remfault;
5279         struct kstat_named      ks_lp_cap_autoneg;
5280 };
5281 
5282 static int
5283 usbgem_kstat_update(kstat_t *ksp, int rw)
5284 {
5285         struct usbgem_kstat_named *knp;
5286         struct usbgem_dev *dp = (struct usbgem_dev *)ksp->ks_private;
5287 
5288         if (rw != KSTAT_READ) {
5289                 return (0);
5290         }
5291 
5292         knp = (struct usbgem_kstat_named *)ksp->ks_data;
5293 
5294         knp->ks_xcvr_addr.value.ul = dp->mii_phy_addr;
5295         knp->ks_xcvr_id.value.ul = dp->mii_phy_id;
5296         knp->ks_xcvr_inuse.value.ul = usbgem_mac_xcvr_inuse(dp);
5297         knp->ks_link_up.value.ul = dp->mii_state == MII_STATE_LINKUP;
5298         knp->ks_link_duplex.value.ul =
5299             (dp->mii_state == MII_STATE_LINKUP) ?
5300             (dp->full_duplex ? 2 : 1) : 0;
5301 
5302         knp->ks_cap_1000fdx.value.ul =
5303             (dp->mii_xstatus & MII_XSTATUS_1000BASET_FD) ||
5304             (dp->mii_xstatus & MII_XSTATUS_1000BASEX_FD);
5305         knp->ks_cap_1000hdx.value.ul =
5306             (dp->mii_xstatus & MII_XSTATUS_1000BASET) ||
5307             (dp->mii_xstatus & MII_XSTATUS_1000BASEX);
5308         knp->ks_cap_100fdx.value.ul =
5309             BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
5310         knp->ks_cap_100hdx.value.ul =
5311             BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
5312         knp->ks_cap_10fdx.value.ul =
5313             BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
5314         knp->ks_cap_10hdx.value.ul =
5315             BOOLEAN(dp->mii_status & MII_STATUS_10);
5316 #ifdef NEVER
5317         knp->ks_cap_remfault.value.ul = B_TRUE;
5318 #endif
5319         knp->ks_cap_autoneg.value.ul =
5320             BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
5321 
5322         knp->ks_adv_cap_1000fdx.value.ul = dp->anadv_1000fdx;
5323         knp->ks_adv_cap_1000hdx.value.ul = dp->anadv_1000hdx;
5324         knp->ks_adv_cap_100fdx.value.ul      = dp->anadv_100fdx;
5325         knp->ks_adv_cap_100hdx.value.ul      = dp->anadv_100hdx;
5326         knp->ks_adv_cap_10fdx.value.ul       = dp->anadv_10fdx;
5327         knp->ks_adv_cap_10hdx.value.ul       = dp->anadv_10hdx;
5328 #ifdef NEVER
5329         knp->ks_adv_cap_remfault.value.ul = 0;
5330 #endif
5331         knp->ks_adv_cap_autoneg.value.ul = dp->anadv_autoneg;
5332 
5333         knp->ks_lp_cap_1000fdx.value.ul =
5334             BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_FULL);
5335         knp->ks_lp_cap_1000hdx.value.ul =
5336             BOOLEAN(dp->mii_stat1000 & MII_1000TS_LP_HALF);
5337         knp->ks_lp_cap_100fdx.value.ul =
5338             BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX_FD);
5339         knp->ks_lp_cap_100hdx.value.ul =
5340             BOOLEAN(dp->mii_lpable & MII_ABILITY_100BASE_TX);
5341         knp->ks_lp_cap_10fdx.value.ul =
5342             BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T_FD);
5343         knp->ks_lp_cap_10hdx.value.ul =
5344             BOOLEAN(dp->mii_lpable & MII_ABILITY_10BASE_T);
5345         knp->ks_lp_cap_remfault.value.ul =
5346             BOOLEAN(dp->mii_exp & MII_AN_EXP_PARFAULT);
5347         knp->ks_lp_cap_autoneg.value.ul =
5348             BOOLEAN(dp->mii_exp & MII_AN_EXP_LPCANAN);
5349 
5350         return (0);
5351 }
5352 
5353 
5354 static int
5355 usbgem_kstat_init(struct usbgem_dev *dp)
5356 {
5357         int                     i;
5358         kstat_t                 *ksp;
5359         struct usbgem_kstat_named       *knp;
5360 
5361         ksp = kstat_create(
5362             (char *)ddi_driver_name(dp->dip), ddi_get_instance(dp->dip),
5363             "mii", "net", KSTAT_TYPE_NAMED,
5364             sizeof (*knp) / sizeof (knp->ks_xcvr_addr), 0);
5365 
5366         if (ksp == NULL) {
5367                 cmn_err(CE_WARN, "%s: %s() for mii failed",
5368                     dp->name, __func__);
5369                 return (USB_FAILURE);
5370         }
5371 
5372         knp = (struct usbgem_kstat_named *)ksp->ks_data;
5373 
5374         kstat_named_init(&knp->ks_xcvr_addr, "xcvr_addr",
5375             KSTAT_DATA_INT32);
5376         kstat_named_init(&knp->ks_xcvr_id, "xcvr_id",
5377             KSTAT_DATA_UINT32);
5378         kstat_named_init(&knp->ks_xcvr_inuse, "xcvr_inuse",
5379             KSTAT_DATA_UINT32);
5380         kstat_named_init(&knp->ks_link_up, "link_up",
5381             KSTAT_DATA_UINT32);
5382         kstat_named_init(&knp->ks_link_duplex, "link_duplex",
5383             KSTAT_DATA_UINT32);
5384         kstat_named_init(&knp->ks_cap_1000fdx, "cap_1000fdx",
5385             KSTAT_DATA_UINT32);
5386         kstat_named_init(&knp->ks_cap_1000hdx, "cap_1000hdx",
5387             KSTAT_DATA_UINT32);
5388         kstat_named_init(&knp->ks_cap_100fdx, "cap_100fdx",
5389             KSTAT_DATA_UINT32);
5390         kstat_named_init(&knp->ks_cap_100hdx, "cap_100hdx",
5391             KSTAT_DATA_UINT32);
5392         kstat_named_init(&knp->ks_cap_10fdx, "cap_10fdx",
5393             KSTAT_DATA_UINT32);
5394         kstat_named_init(&knp->ks_cap_10hdx, "cap_10hdx",
5395             KSTAT_DATA_UINT32);
5396 #ifdef NEVER
5397         kstat_named_init(&knp->ks_cap_remfault, "cap_rem_fault",
5398             KSTAT_DATA_UINT32);
5399 #endif
5400         kstat_named_init(&knp->ks_cap_autoneg, "cap_autoneg",
5401             KSTAT_DATA_UINT32);
5402         kstat_named_init(&knp->ks_adv_cap_1000fdx, "adv_cap_1000fdx",
5403             KSTAT_DATA_UINT32);
5404         kstat_named_init(&knp->ks_adv_cap_1000hdx, "adv_cap_1000hdx",
5405             KSTAT_DATA_UINT32);
5406         kstat_named_init(&knp->ks_adv_cap_100fdx, "adv_cap_100fdx",
5407             KSTAT_DATA_UINT32);
5408         kstat_named_init(&knp->ks_adv_cap_100hdx, "adv_cap_100hdx",
5409             KSTAT_DATA_UINT32);
5410         kstat_named_init(&knp->ks_adv_cap_10fdx, "adv_cap_10fdx",
5411             KSTAT_DATA_UINT32);
5412         kstat_named_init(&knp->ks_adv_cap_10hdx, "adv_cap_10hdx",
5413             KSTAT_DATA_UINT32);
5414 #ifdef NEVER
5415         kstat_named_init(&knp->ks_adv_cap_remfault, "adv_rem_fault",
5416             KSTAT_DATA_UINT32);
5417 #endif
5418         kstat_named_init(&knp->ks_adv_cap_autoneg, "adv_cap_autoneg",
5419             KSTAT_DATA_UINT32);
5420 
5421         kstat_named_init(&knp->ks_lp_cap_1000fdx, "lp_cap_1000fdx",
5422             KSTAT_DATA_UINT32);
5423         kstat_named_init(&knp->ks_lp_cap_1000hdx, "lp_cap_1000hdx",
5424             KSTAT_DATA_UINT32);
5425         kstat_named_init(&knp->ks_lp_cap_100fdx, "lp_cap_100fdx",
5426             KSTAT_DATA_UINT32);
5427         kstat_named_init(&knp->ks_lp_cap_100hdx, "lp_cap_100hdx",
5428             KSTAT_DATA_UINT32);
5429         kstat_named_init(&knp->ks_lp_cap_10fdx, "lp_cap_10fdx",
5430             KSTAT_DATA_UINT32);
5431         kstat_named_init(&knp->ks_lp_cap_10hdx, "lp_cap_10hdx",
5432             KSTAT_DATA_UINT32);
5433         kstat_named_init(&knp->ks_lp_cap_remfault, "lp_cap_rem_fault",
5434             KSTAT_DATA_UINT32);
5435         kstat_named_init(&knp->ks_lp_cap_autoneg, "lp_cap_autoneg",
5436             KSTAT_DATA_UINT32);
5437 
5438         ksp->ks_private = (void *) dp;
5439         ksp->ks_update = usbgem_kstat_update;
5440         dp->ksp = ksp;
5441 
5442         kstat_install(ksp);
5443 
5444         return (USB_SUCCESS);
5445 }
5446 #endif /* GEM_CONFIG_GLDv3 */
5447 /* ======================================================================== */
5448 /*
5449  * attach/detatch/usb support
5450  */
5451 /* ======================================================================== */
5452 int
5453 usbgem_ctrl_out(struct usbgem_dev *dp,
5454     uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
5455     void *bp, int size)
5456 {
5457         mblk_t                  *data;
5458         usb_ctrl_setup_t        setup;
5459         usb_cr_t                completion_reason;
5460         usb_cb_flags_t          cb_flags;
5461         usb_flags_t             flags;
5462         int                     i;
5463         int                     ret;
5464 
5465         DPRINTF(4, (CE_CONT, "!%s: %s "
5466             "reqt:0x%02x req:0x%02x val:0x%04x ix:0x%04x len:0x%02x "
5467             "bp:0x%p nic_state:%d",
5468             dp->name, __func__, reqt, req, val, ix, len, bp, dp->nic_state));
5469 
5470         if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5471                 return (USB_PIPE_ERROR);
5472         }
5473 
5474         data = NULL;
5475         if (size > 0) {
5476                 if ((data = allocb(size, 0)) == NULL) {
5477                         return (USB_FAILURE);
5478                 }
5479 
5480                 bcopy(bp, data->b_rptr, size);
5481                 data->b_wptr = data->b_rptr + size;
5482         }
5483 
5484         setup.bmRequestType = reqt;
5485         setup.bRequest = req;
5486         setup.wValue = val;
5487         setup.wIndex = ix;
5488         setup.wLength = len;
5489         setup.attrs = 0;        /* attributes */
5490 
5491         for (i = usbgem_ctrl_retry; i > 0; i--) {
5492                 completion_reason = 0;
5493                 cb_flags = 0;
5494 
5495                 ret = usb_pipe_ctrl_xfer_wait(DEFAULT_PIPE(dp),
5496                     &setup, &data, &completion_reason, &cb_flags, 0);
5497 
5498                 if (ret == USB_SUCCESS) {
5499                         break;
5500                 }
5501                 if (i == 1) {
5502                         cmn_err(CE_WARN,
5503                             "!%s: %s failed: "
5504                             "reqt:0x%x req:0x%x val:0x%x ix:0x%x len:0x%x "
5505                             "ret:%d cr:%s(%d), cb_flags:0x%x %s",
5506                             dp->name, __func__, reqt, req, val, ix, len,
5507                             ret, usb_str_cr(completion_reason),
5508                             completion_reason,
5509                             cb_flags,
5510                             (i > 1) ? "retrying..." : "fatal");
5511                 }
5512         }
5513 
5514         if (data != NULL) {
5515                 freemsg(data);
5516         }
5517 
5518         return (ret);
5519 }
5520 
5521 int
5522 usbgem_ctrl_in(struct usbgem_dev *dp,
5523     uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
5524     void *bp, int size)
5525 {
5526         mblk_t                  *data;
5527         usb_ctrl_setup_t        setup;
5528         usb_cr_t                completion_reason;
5529         usb_cb_flags_t          cb_flags;
5530         int                     i;
5531         int                     ret;
5532         int                     reclen;
5533 
5534         DPRINTF(4, (CE_CONT,
5535             "!%s: %s:"
5536             " reqt:0x%02x req:0x%02x val:0x%04x ix:0x%04x len:0x%02x"
5537             " bp:x%p mac_state:%d",
5538             dp->name, __func__, reqt, req, val, ix, len, bp, dp->mac_state));
5539 
5540         if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5541                 return (USB_PIPE_ERROR);
5542         }
5543 
5544         data = NULL;
5545 
5546         setup.bmRequestType = reqt;
5547         setup.bRequest = req;
5548         setup.wValue = val;
5549         setup.wIndex = ix;
5550         setup.wLength = len;
5551         setup.attrs = USB_ATTRS_AUTOCLEARING;   /* XXX */
5552 
5553         for (i = usbgem_ctrl_retry; i > 0; i--) {
5554                 completion_reason = 0;
5555                 cb_flags = 0;
5556                 ret = usb_pipe_ctrl_xfer_wait(DEFAULT_PIPE(dp), &setup, &data,
5557                     &completion_reason, &cb_flags, 0);
5558 
5559                 if (ret == USB_SUCCESS) {
5560                         reclen = msgdsize(data);
5561                         bcopy(data->b_rptr, bp, min(reclen, size));
5562                         break;
5563                 }
5564                 if (i == 1) {
5565                         cmn_err(CE_WARN,
5566                             "!%s: %s failed: "
5567                             "reqt:0x%x req:0x%x val:0x%x ix:0x%x len:0x%x "
5568                             "ret:%d cr:%s(%d) cb_flags:0x%x %s",
5569                             dp->name, __func__,
5570                             reqt, req, val, ix, len,
5571                             ret, usb_str_cr(completion_reason),
5572                             completion_reason,
5573                             cb_flags,
5574                             (i > 1) ? "retrying..." : "fatal");
5575                 }
5576         }
5577 
5578         if (data) {
5579                 freemsg(data);
5580         }
5581 
5582         return (ret);
5583 }
5584 
5585 int
5586 usbgem_ctrl_out_val(struct usbgem_dev *dp,
5587     uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
5588     uint32_t v)
5589 {
5590         uint8_t buf[4];
5591 
5592         /* convert to little endian from native byte order */
5593         switch (len) {
5594         case 4:
5595                 buf[3] = v >> 24;
5596                 buf[2] = v >> 16;
5597                 /* FALLTHROUGH */
5598         case 2:
5599                 buf[1] = v >> 8;
5600                 /* FALLTHROUGH */
5601         case 1:
5602                 buf[0] = v;
5603         }
5604 
5605         return (usbgem_ctrl_out(dp, reqt, req, val, ix, len, buf, len));
5606 }
5607 
5608 int
5609 usbgem_ctrl_in_val(struct usbgem_dev *dp,
5610     uint8_t reqt, uint8_t req, uint16_t val, uint16_t ix, uint16_t len,
5611     void *valp)
5612 {
5613         uint8_t         buf[4];
5614         uint_t          v;
5615         int             err;
5616 
5617 #ifdef SANITY
5618         bzero(buf, sizeof (buf));
5619 #endif
5620         err = usbgem_ctrl_in(dp, reqt, req, val, ix, len, buf, len);
5621         if (err == USB_SUCCESS) {
5622                 v = 0;
5623                 switch (len) {
5624                 case 4:
5625                         v |= buf[3] << 24;
5626                         v |= buf[2] << 16;
5627                         /* FALLTHROUGH */
5628                 case 2:
5629                         v |= buf[1] << 8;
5630                         /* FALLTHROUGH */
5631                 case 1:
5632                         v |= buf[0];
5633                 }
5634 
5635                 switch (len) {
5636                 case 4:
5637                         *(uint32_t *)valp = v;
5638                         break;
5639                 case 2:
5640                         *(uint16_t *)valp = v;
5641                         break;
5642                 case 1:
5643                         *(uint8_t *)valp = v;
5644                         break;
5645                 }
5646         }
5647         return (err);
5648 }
5649 
5650 /*
5651  * Attach / detach / disconnect / reconnect management
5652  */
5653 static int
5654 usbgem_open_pipes(struct usbgem_dev *dp)
5655 {
5656         int                     i;
5657         int                     ret;
5658         int                     ifnum;
5659         int                     alt;
5660         usb_client_dev_data_t   *reg_data;
5661         usb_ep_data_t           *ep_tree_node;
5662 
5663         DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
5664 
5665         ifnum = dp->ugc.usbgc_ifnum;
5666         alt = dp->ugc.usbgc_alt;
5667 
5668         ep_tree_node = usb_lookup_ep_data(dp->dip, dp->reg_data, ifnum, alt,
5669             0, USB_EP_ATTR_BULK, USB_EP_DIR_IN);
5670         if (ep_tree_node == NULL) {
5671                 cmn_err(CE_WARN, "!%s: %s: ep_bulkin is NULL",
5672                     dp->name, __func__);
5673                 goto err;
5674         }
5675         dp->ep_bulkin = &ep_tree_node->ep_descr;
5676 
5677         ep_tree_node = usb_lookup_ep_data(dp->dip, dp->reg_data, ifnum, alt,
5678             0, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
5679         if (ep_tree_node == NULL) {
5680                 cmn_err(CE_WARN, "!%s: %s: ep_bulkout is NULL",
5681                     dp->name, __func__);
5682                 goto err;
5683         }
5684         dp->ep_bulkout = &ep_tree_node->ep_descr;
5685 
5686         ep_tree_node = usb_lookup_ep_data(dp->dip, dp->reg_data, ifnum, alt,
5687             0, USB_EP_ATTR_INTR, USB_EP_DIR_IN);
5688         if (ep_tree_node) {
5689                 dp->ep_intr = &ep_tree_node->ep_descr;
5690         } else {
5691                 /* don't care */
5692                 DPRINTF(1, (CE_CONT, "!%s: %s: ep_intr is NULL",
5693                     dp->name, __func__));
5694                 dp->ep_intr = NULL;
5695         }
5696 
5697         /* XXX -- no need to open default pipe */
5698 
5699         /* open bulk out pipe */
5700         bzero(&dp->policy_bulkout, sizeof (usb_pipe_policy_t));
5701         dp->policy_bulkout.pp_max_async_reqs = 1;
5702 
5703         if ((ret = usb_pipe_open(dp->dip,
5704             dp->ep_bulkout, &dp->policy_bulkout, USB_FLAGS_SLEEP,
5705             &dp->bulkout_pipe)) != USB_SUCCESS) {
5706                 cmn_err(CE_WARN,
5707                     "!%s: %s: err:%x: failed to open bulk-out pipe",
5708                     dp->name, __func__, ret);
5709                 dp->bulkout_pipe = NULL;
5710                 goto err;
5711         }
5712         DPRINTF(1, (CE_CONT, "!%s: %s: bulkout_pipe opened successfully",
5713             dp->name, __func__));
5714 
5715         /* open bulk in pipe */
5716         bzero(&dp->policy_bulkin, sizeof (usb_pipe_policy_t));
5717         dp->policy_bulkin.pp_max_async_reqs = 1;
5718         if ((ret = usb_pipe_open(dp->dip,
5719             dp->ep_bulkin, &dp->policy_bulkin, USB_FLAGS_SLEEP,
5720             &dp->bulkin_pipe)) != USB_SUCCESS) {
5721                 cmn_err(CE_WARN,
5722                     "!%s: %s: ret:%x failed to open bulk-in pipe",
5723                     dp->name, __func__, ret);
5724                 dp->bulkin_pipe = NULL;
5725                 goto err;
5726         }
5727         DPRINTF(1, (CE_CONT, "!%s: %s: bulkin_pipe opened successfully",
5728             dp->name, __func__));
5729 
5730         if (dp->ep_intr) {
5731                 /* open interrupt pipe */
5732                 bzero(&dp->policy_interrupt, sizeof (usb_pipe_policy_t));
5733                 dp->policy_interrupt.pp_max_async_reqs = 1;
5734                 if ((ret = usb_pipe_open(dp->dip, dp->ep_intr,
5735                     &dp->policy_interrupt, USB_FLAGS_SLEEP,
5736                     &dp->intr_pipe)) != USB_SUCCESS) {
5737                         cmn_err(CE_WARN,
5738                             "!%s: %s: ret:%x failed to open interrupt pipe",
5739                             dp->name, __func__, ret);
5740                         dp->intr_pipe = NULL;
5741                         goto err;
5742                 }
5743         }
5744         DPRINTF(1, (CE_CONT, "!%s: %s: intr_pipe opened successfully",
5745             dp->name, __func__));
5746 
5747         return (USB_SUCCESS);
5748 
5749 err:
5750         if (dp->bulkin_pipe) {
5751                 usb_pipe_close(dp->dip,
5752                     dp->bulkin_pipe, USB_FLAGS_SLEEP, NULL, 0);
5753                 dp->bulkin_pipe = NULL;
5754         }
5755         if (dp->bulkout_pipe) {
5756                 usb_pipe_close(dp->dip,
5757                     dp->bulkout_pipe, USB_FLAGS_SLEEP, NULL, 0);
5758                 dp->bulkout_pipe = NULL;
5759         }
5760         if (dp->intr_pipe) {
5761                 usb_pipe_close(dp->dip,
5762                     dp->intr_pipe, USB_FLAGS_SLEEP, NULL, 0);
5763                 dp->intr_pipe = NULL;
5764         }
5765 
5766         return (USB_FAILURE);
5767 }
5768 
5769 static int
5770 usbgem_close_pipes(struct usbgem_dev *dp)
5771 {
5772         DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
5773 
5774         if (dp->intr_pipe) {
5775                 usb_pipe_close(dp->dip,
5776                     dp->intr_pipe, USB_FLAGS_SLEEP, NULL, 0);
5777                 dp->intr_pipe = NULL;
5778         }
5779         DPRINTF(1, (CE_CONT, "!%s: %s: 1", dp->name, __func__));
5780 
5781         ASSERT(dp->bulkin_pipe);
5782         usb_pipe_close(dp->dip, dp->bulkin_pipe, USB_FLAGS_SLEEP, NULL, 0);
5783         dp->bulkin_pipe = NULL;
5784         DPRINTF(1, (CE_CONT, "!%s: %s: 2", dp->name, __func__));
5785 
5786         ASSERT(dp->bulkout_pipe);
5787         usb_pipe_close(dp->dip, dp->bulkout_pipe, USB_FLAGS_SLEEP, NULL, 0);
5788         dp->bulkout_pipe = NULL;
5789         DPRINTF(1, (CE_CONT, "!%s: %s: 3", dp->name, __func__));
5790 
5791         return (USB_SUCCESS);
5792 }
5793 
5794 #define FREEZE_GRACEFUL         (B_TRUE)
5795 #define FREEZE_NO_GRACEFUL      (B_FALSE)
5796 static int
5797 usbgem_freeze_device(struct usbgem_dev *dp, boolean_t graceful)
5798 {
5799         DPRINTF(0, (CE_NOTE, "!%s: %s: called", dp->name, __func__));
5800 
5801         /* stop nic activity */
5802         (void) usbgem_mac_stop(dp, MAC_STATE_DISCONNECTED, graceful);
5803 
5804         /*
5805          * Here we free all memory resource allocated, because it will
5806          * cause to panic the system that we free usb_bulk_req objects
5807          * during the usb device is disconnected.
5808          */
5809         (void) usbgem_free_memory(dp);
5810 
5811         return (USB_SUCCESS);
5812 }
5813 
5814 static int
5815 usbgem_disconnect_cb(dev_info_t *dip)
5816 {
5817         int     ret;
5818         struct usbgem_dev       *dp;
5819 
5820         dp = USBGEM_GET_DEV(dip);
5821 
5822         cmn_err(CE_NOTE, "!%s: the usb device was disconnected (dp=%p)",
5823             dp->name, (void *)dp);
5824 
5825         /* start serialize */
5826         rw_enter(&dp->dev_state_lock, RW_WRITER);
5827 
5828         ret = usbgem_freeze_device(dp, 0);
5829 
5830         /* end of serialize */
5831         rw_exit(&dp->dev_state_lock);
5832 
5833         return (ret);
5834 }
5835 
5836 static int
5837 usbgem_recover_device(struct usbgem_dev *dp)
5838 {
5839         int     err;
5840 
5841         DPRINTF(0, (CE_NOTE, "!%s: %s: called", dp->name, __func__));
5842 
5843         err = USB_SUCCESS;
5844 
5845         /* reinitialize the usb connection */
5846         usbgem_close_pipes(dp);
5847         if ((err = usbgem_open_pipes(dp)) != USB_SUCCESS) {
5848                 goto x;
5849         }
5850 
5851         /* initialize nic state */
5852         dp->mac_state = MAC_STATE_STOPPED;
5853         dp->mii_state = MII_STATE_UNKNOWN;
5854 
5855         /* allocate memory resources again */
5856         if ((err = usbgem_alloc_memory(dp)) != USB_SUCCESS) {
5857                 goto x;
5858         }
5859 
5860         /* restart nic and recover state */
5861         (void) usbgem_restart_nic(dp);
5862 
5863         usbgem_mii_init(dp);
5864 
5865         /* kick potentially stopped house keeping thread */
5866         cv_signal(&dp->link_watcher_wait_cv);
5867 x:
5868         return (err);
5869 }
5870 
5871 static int
5872 usbgem_reconnect_cb(dev_info_t *dip)
5873 {
5874         int     err = USB_SUCCESS;
5875         struct usbgem_dev       *dp;
5876 
5877         dp = USBGEM_GET_DEV(dip);
5878         DPRINTF(0, (CE_CONT, "!%s: dp=%p", ddi_get_name(dip), dp));
5879 #ifdef notdef
5880         /* check device changes after disconnect */
5881         if (usb_check_same_device(dp->dip, NULL, USB_LOG_L2, -1,
5882             USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
5883                 cmn_err(CE_CONT,
5884                     "!%s: no or different device installed", dp->name);
5885                 return (DDI_SUCCESS);
5886         }
5887 #endif
5888         cmn_err(CE_NOTE, "%s: the usb device was reconnected", dp->name);
5889 
5890         /* start serialize */
5891         rw_enter(&dp->dev_state_lock, RW_WRITER);
5892 
5893         if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5894                 err = usbgem_recover_device(dp);
5895         }
5896 
5897         /* end of serialize */
5898         rw_exit(&dp->dev_state_lock);
5899 
5900         return (err == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
5901 }
5902 
5903 int
5904 usbgem_suspend(dev_info_t *dip)
5905 {
5906         int     err = USB_SUCCESS;
5907         struct usbgem_dev       *dp;
5908 
5909         dp = USBGEM_GET_DEV(dip);
5910 
5911         DPRINTF(0, (CE_CONT, "!%s: %s: callded", dp->name, __func__));
5912 
5913         /* start serialize */
5914         rw_enter(&dp->dev_state_lock, RW_WRITER);
5915 
5916         if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5917                 err = usbgem_freeze_device(dp, STOP_GRACEFUL);
5918         }
5919 
5920         /* end of serialize */
5921         rw_exit(&dp->dev_state_lock);
5922 
5923         return (err == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
5924 }
5925 
5926 int
5927 usbgem_resume(dev_info_t *dip)
5928 {
5929         int     err = USB_SUCCESS;
5930         struct usbgem_dev       *dp;
5931 
5932         dp = USBGEM_GET_DEV(dip);
5933 
5934         DPRINTF(0, (CE_CONT, "!%s: %s: callded", dp->name, __func__));
5935 #ifdef notdef
5936         /* check device changes after disconnect */
5937         if (usb_check_same_device(dp->dip, NULL, USB_LOG_L2, -1,
5938             USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
5939                 cmn_err(CE_CONT,
5940                     "!%s: no or different device installed", dp->name);
5941                 return (DDI_SUCCESS);
5942         }
5943 #endif
5944         /* start serialize */
5945         rw_enter(&dp->dev_state_lock, RW_WRITER);
5946 
5947         if (dp->mac_state == MAC_STATE_DISCONNECTED) {
5948                 err = usbgem_recover_device(dp);
5949         }
5950 
5951         /* end of serialize */
5952         rw_exit(&dp->dev_state_lock);
5953 
5954         return (err == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
5955 }
5956 
5957 #define USBGEM_LOCAL_DATA_SIZE(gc)      \
5958         (sizeof (struct usbgem_dev) + USBGEM_MCALLOC)
5959 
5960 struct usbgem_dev *
5961 usbgem_do_attach(dev_info_t *dip,
5962     struct usbgem_conf *gc, void *lp, int lmsize)
5963 {
5964         struct usbgem_dev       *dp;
5965         int                     i;
5966 #ifdef USBGEM_CONFIG_GLDv3
5967         mac_register_t          *macp = NULL;
5968 #else
5969         gld_mac_info_t          *macinfo;
5970         void                    *tmp;
5971 #endif
5972         int                     ret;
5973         int                     unit;
5974         int                     err;
5975 
5976         unit = ddi_get_instance(dip);
5977 
5978         DPRINTF(2, (CE_CONT, "!usbgem%d: %s: called", unit, __func__));
5979 
5980         /*
5981          * Allocate soft data structure
5982          */
5983         dp = kmem_zalloc(USBGEM_LOCAL_DATA_SIZE(gc), KM_SLEEP);
5984         if (dp == NULL) {
5985 #ifndef USBGEM_CONFIG_GLDv3
5986                 gld_mac_free(macinfo);
5987 #endif
5988                 return (NULL);
5989         }
5990 #ifdef USBGEM_CONFIG_GLDv3
5991         if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
5992                 cmn_err(CE_WARN, "!gem%d: %s: mac_alloc failed",
5993                     unit, __func__);
5994                 return (NULL);
5995         }
5996 #else
5997         macinfo = gld_mac_alloc(dip);
5998         dp->macinfo = macinfo;
5999 #endif
6000 
6001         /* link to private area */
6002         dp->private = lp;
6003         dp->priv_size = lmsize;
6004         dp->mc_list = (struct mcast_addr *)&dp[1];
6005 
6006         dp->dip = dip;
6007         bcopy(gc->usbgc_name, dp->name, USBGEM_NAME_LEN);
6008 
6009         /*
6010          * register with usb service
6011          */
6012         if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
6013                 cmn_err(CE_WARN,
6014                     "%s: %s: usb_client_attach failed",
6015                     dp->name, __func__);
6016                 goto err_free_private;
6017         }
6018 
6019         if (usb_get_dev_data(dip, &dp->reg_data,
6020             USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) {
6021                 dp->reg_data = NULL;
6022                 goto err_unregister_client;
6023         }
6024 #ifdef USBGEM_DEBUG_LEVEL
6025         usb_print_descr_tree(dp->dip, dp->reg_data);
6026 #endif
6027 
6028         if (usbgem_open_pipes(dp) != USB_SUCCESS) {
6029                 /* failed to open pipes */
6030                 cmn_err(CE_WARN, "!%s: %s: failed to open pipes",
6031                     dp->name, __func__);
6032                 goto err_unregister_client;
6033         }
6034 
6035         /*
6036          * Initialize mutexs and condition variables
6037          */
6038         mutex_init(&dp->rxlock, NULL, MUTEX_DRIVER, NULL);
6039         mutex_init(&dp->txlock, NULL, MUTEX_DRIVER, NULL);
6040         cv_init(&dp->rx_drain_cv, NULL, CV_DRIVER, NULL);
6041         cv_init(&dp->tx_drain_cv, NULL, CV_DRIVER, NULL);
6042         rw_init(&dp->dev_state_lock, NULL, RW_DRIVER, NULL);
6043         mutex_init(&dp->link_watcher_lock, NULL, MUTEX_DRIVER, NULL);
6044         cv_init(&dp->link_watcher_wait_cv, NULL, CV_DRIVER, NULL);
6045         sema_init(&dp->hal_op_lock, 1, NULL, SEMA_DRIVER, NULL);
6046         sema_init(&dp->rxfilter_lock, 1, NULL, SEMA_DRIVER, NULL);
6047 
6048         /*
6049          * Initialize configuration
6050          */
6051         dp->ugc = *gc;
6052 
6053         dp->mtu = ETHERMTU;
6054         dp->rxmode = 0;
6055         dp->speed = USBGEM_SPD_10;   /* default is 10Mbps */
6056         dp->full_duplex = B_FALSE;   /* default is half */
6057         dp->flow_control = FLOW_CONTROL_NONE;
6058 
6059         dp->nic_state = NIC_STATE_STOPPED;
6060         dp->mac_state = MAC_STATE_STOPPED;
6061         dp->mii_state = MII_STATE_UNKNOWN;
6062 
6063         /* performance tuning parameters */
6064         dp->txthr = ETHERMAX;                /* tx fifo threshoold */
6065         dp->txmaxdma = 16*4;         /* tx max dma burst size */
6066         dp->rxthr = 128;             /* rx fifo threshoold */
6067         dp->rxmaxdma = 16*4;         /* rx max dma burst size */
6068 
6069         /*
6070          * Get media mode infomation from .conf file
6071          */
6072         usbgem_read_conf(dp);
6073 
6074         /* rx_buf_len depend on MTU */
6075         dp->rx_buf_len = MAXPKTBUF(dp) + dp->ugc.usbgc_rx_header_len;
6076 
6077         /*
6078          * Reset the chip
6079          */
6080         if (usbgem_hal_reset_chip(dp) != USB_SUCCESS) {
6081                 cmn_err(CE_WARN,
6082                     "!%s: %s: failed to reset the usb device",
6083                     dp->name, __func__);
6084                 goto err_destroy_locks;
6085         }
6086 
6087         /*
6088          * HW dependant paremeter initialization
6089          */
6090         if (usbgem_hal_attach_chip(dp) != USB_SUCCESS) {
6091                 cmn_err(CE_WARN,
6092                     "!%s: %s: failed to attach the usb device",
6093                     dp->name, __func__);
6094                 goto err_destroy_locks;
6095         }
6096 
6097         /* allocate resources */
6098         if (usbgem_alloc_memory(dp) != USB_SUCCESS) {
6099                 goto err_destroy_locks;
6100         }
6101 
6102         DPRINTF(0, (CE_CONT,
6103             "!%s: %02x:%02x:%02x:%02x:%02x:%02x",
6104             dp->name,
6105             dp->dev_addr.ether_addr_octet[0],
6106             dp->dev_addr.ether_addr_octet[1],
6107             dp->dev_addr.ether_addr_octet[2],
6108             dp->dev_addr.ether_addr_octet[3],
6109             dp->dev_addr.ether_addr_octet[4],
6110             dp->dev_addr.ether_addr_octet[5]));
6111 
6112         /* copy mac address */
6113         dp->cur_addr = dp->dev_addr;
6114 
6115         /* pre-calculated tx timeout in second for performance */
6116         dp->bulkout_timeout =
6117             dp->ugc.usbgc_tx_timeout / drv_usectohz(1000*1000);
6118 
6119 #ifdef USBGEM_CONFIG_GLDv3
6120         usbgem_gld3_init(dp, macp);
6121 #else
6122         usbgem_gld_init(dp, macinfo, ident);
6123 #endif
6124 
6125         /* Probe MII phy (scan phy) */
6126         dp->mii_lpable = 0;
6127         dp->mii_advert = 0;
6128         dp->mii_exp = 0;
6129         dp->mii_ctl1000 = 0;
6130         dp->mii_stat1000 = 0;
6131 
6132         dp->mii_status_ro = 0;
6133         dp->mii_xstatus_ro = 0;
6134 
6135         if (usbgem_mii_probe(dp) != USB_SUCCESS) {
6136                 cmn_err(CE_WARN, "!%s: %s: mii_probe failed",
6137                     dp->name, __func__);
6138                 goto err_free_memory;
6139         }
6140 
6141         /* mask unsupported abilities */
6142         dp->anadv_autoneg &= BOOLEAN(dp->mii_status & MII_STATUS_CANAUTONEG);
6143         dp->anadv_1000fdx &=
6144             BOOLEAN(dp->mii_xstatus &
6145             (MII_XSTATUS_1000BASEX_FD | MII_XSTATUS_1000BASET_FD));
6146         dp->anadv_1000hdx &=
6147             BOOLEAN(dp->mii_xstatus &
6148             (MII_XSTATUS_1000BASEX | MII_XSTATUS_1000BASET));
6149         dp->anadv_100t4 &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASE_T4);
6150         dp->anadv_100fdx &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX_FD);
6151         dp->anadv_100hdx &= BOOLEAN(dp->mii_status & MII_STATUS_100_BASEX);
6152         dp->anadv_10fdx &= BOOLEAN(dp->mii_status & MII_STATUS_10_FD);
6153         dp->anadv_10hdx &= BOOLEAN(dp->mii_status & MII_STATUS_10);
6154 
6155         if (usbgem_mii_init(dp) != USB_SUCCESS) {
6156                 cmn_err(CE_WARN, "!%s: %s: mii_init failed",
6157                     dp->name, __func__);
6158                 goto err_free_memory;
6159         }
6160 
6161         /*
6162          * initialize kstats including mii statistics
6163          */
6164 #ifdef USBGEM_CONFIG_GLDv3
6165 #ifdef USBGEM_CONFIG_ND
6166         usbgem_nd_setup(dp);
6167 #endif
6168 #else
6169         if (usbgem_kstat_init(dp) != USB_SUCCESS) {
6170                 goto err_free_memory;
6171         }
6172 #endif
6173 
6174         /*
6175          * Add interrupt to system.
6176          */
6177 #ifdef USBGEM_CONFIG_GLDv3
6178         if (ret = mac_register(macp, &dp->mh)) {
6179                 cmn_err(CE_WARN, "!%s: mac_register failed, error:%d",
6180                     dp->name, ret);
6181                 goto err_release_stats;
6182         }
6183         mac_free(macp);
6184         macp = NULL;
6185 #else
6186         /* gld_register will corrupts driver_private */
6187         tmp = ddi_get_driver_private(dip);
6188         if (gld_register(dip,
6189             (char *)ddi_driver_name(dip), macinfo) != DDI_SUCCESS) {
6190                 cmn_err(CE_WARN, "!%s: %s: gld_register failed",
6191                     dp->name, __func__);
6192                 ddi_set_driver_private(dip, tmp);
6193                 goto err_release_stats;
6194         }
6195         /* restore driver private */
6196         ddi_set_driver_private(dip, tmp);
6197 #endif /* USBGEM_CONFIG_GLDv3 */
6198         if (usb_register_hotplug_cbs(dip,
6199             usbgem_suspend, usbgem_resume) != USB_SUCCESS) {
6200                 cmn_err(CE_WARN,
6201                     "!%s: %s: failed to register hotplug cbs",
6202                     dp->name, __func__);
6203                 goto err_unregister_gld;
6204         }
6205 
6206         /* reset mii and start mii link watcher */
6207         if (usbgem_mii_start(dp) != USB_SUCCESS) {
6208                 goto err_unregister_hotplug;
6209         }
6210 
6211         /* start tx watchdow watcher */
6212         if (usbgem_tx_watcher_start(dp)) {
6213                 goto err_usbgem_mii_stop;
6214         }
6215 
6216         ddi_set_driver_private(dip, (caddr_t)dp);
6217 
6218         DPRINTF(2, (CE_CONT, "!%s: %s: return: success", dp->name, __func__));
6219 
6220         return (dp);
6221 
6222 err_usbgem_mii_stop:
6223         usbgem_mii_stop(dp);
6224 
6225 err_unregister_hotplug:
6226         usb_unregister_hotplug_cbs(dip);
6227 
6228 err_unregister_gld:
6229 #ifdef USBGEM_CONFIG_GLDv3
6230         mac_unregister(dp->mh);
6231 #else
6232         gld_unregister(macinfo);
6233 #endif
6234 
6235 err_release_stats:
6236 #ifdef USBGEM_CONFIG_GLDv3
6237 #ifdef USBGEM_CONFIG_ND
6238         /* release NDD resources */
6239         usbgem_nd_cleanup(dp);
6240 #endif
6241 #else
6242         kstat_delete(dp->ksp);
6243 #endif
6244 
6245 err_free_memory:
6246         usbgem_free_memory(dp);
6247 
6248 err_destroy_locks:
6249         cv_destroy(&dp->tx_drain_cv);
6250         cv_destroy(&dp->rx_drain_cv);
6251         mutex_destroy(&dp->txlock);
6252         mutex_destroy(&dp->rxlock);
6253         rw_destroy(&dp->dev_state_lock);
6254         mutex_destroy(&dp->link_watcher_lock);
6255         cv_destroy(&dp->link_watcher_wait_cv);
6256         sema_destroy(&dp->hal_op_lock);
6257         sema_destroy(&dp->rxfilter_lock);
6258 
6259 err_close_pipes:
6260         (void) usbgem_close_pipes(dp);
6261 
6262 err_unregister_client:
6263         usb_client_detach(dp->dip, dp->reg_data);
6264 
6265 err_free_private:
6266 #ifdef USBGEM_CONFIG_GLDv3
6267         if (macp) {
6268                 mac_free(macp);
6269         }
6270 #else
6271         gld_mac_free(macinfo);
6272 #endif
6273         kmem_free((caddr_t)dp, USBGEM_LOCAL_DATA_SIZE(gc));
6274 
6275         return (NULL);
6276 }
6277 
6278 int
6279 usbgem_do_detach(dev_info_t *dip)
6280 {
6281         struct usbgem_dev       *dp;
6282 
6283         dp = USBGEM_GET_DEV(dip);
6284 
6285 #ifdef USBGEM_CONFIG_GLDv3
6286         /* unregister with gld v3 */
6287         if (mac_unregister(dp->mh) != DDI_SUCCESS) {
6288                 return (DDI_FAILURE);
6289         }
6290 #else
6291         /* unregister with gld v2 */
6292         if (gld_unregister(dp->macinfo) != DDI_SUCCESS) {
6293                 return (DDI_FAILURE);
6294         }
6295 #endif
6296         /* unregister with hotplug service */
6297         usb_unregister_hotplug_cbs(dip);
6298 
6299         /* stop tx watchdog watcher */
6300         usbgem_tx_watcher_stop(dp);
6301 
6302         /* stop the link manager */
6303         usbgem_mii_stop(dp);
6304 
6305         /* unregister with usb service */
6306         (void) usbgem_free_memory(dp);
6307         (void) usbgem_close_pipes(dp);
6308         usb_client_detach(dp->dip, dp->reg_data);
6309         dp->reg_data = NULL;
6310 
6311         /* unregister with kernel statistics */
6312 #ifdef USBGEM_CONFIG_GLDv3
6313 #ifdef USBGEM_CONFIG_ND
6314         /* release ndd resources */
6315         usbgem_nd_cleanup(dp);
6316 #endif
6317 #else
6318         /* destroy kstat objects */
6319         kstat_delete(dp->ksp);
6320 #endif
6321 
6322         /* release locks and condition variables */
6323         mutex_destroy(&dp->txlock);
6324         mutex_destroy(&dp->rxlock);
6325         cv_destroy(&dp->tx_drain_cv);
6326         cv_destroy(&dp->rx_drain_cv);
6327         rw_destroy(&dp->dev_state_lock);
6328         mutex_destroy(&dp->link_watcher_lock);
6329         cv_destroy(&dp->link_watcher_wait_cv);
6330         sema_destroy(&dp->hal_op_lock);
6331         sema_destroy(&dp->rxfilter_lock);
6332 
6333         /* release basic memory resources */
6334 #ifndef USBGEM_CONFIG_GLDv3
6335         gld_mac_free(dp->macinfo);
6336 #endif
6337         kmem_free((caddr_t)(dp->private), dp->priv_size);
6338         kmem_free((caddr_t)dp, USBGEM_LOCAL_DATA_SIZE(&dp->ugc));
6339 
6340         DPRINTF(2, (CE_CONT, "!%s: %s: return: success",
6341             ddi_driver_name(dip), __func__));
6342 
6343         return (DDI_SUCCESS);
6344 }
6345 
6346 int
6347 usbgem_mod_init(struct dev_ops *dop, char *name)
6348 {
6349 #ifdef USBGEM_CONFIG_GLDv3
6350         major_t major;
6351         major = ddi_name_to_major(name);
6352         if (major == DDI_MAJOR_T_NONE) {
6353                 return (DDI_FAILURE);
6354         }
6355         mac_init_ops(dop, name);
6356 #endif
6357         return (DDI_SUCCESS);
6358 }
6359 
6360 void
6361 usbgem_mod_fini(struct dev_ops *dop)
6362 {
6363 #ifdef USBGEM_CONFIG_GLDv3
6364         mac_fini_ops(dop);
6365 #endif
6366 }
6367 
6368 int
6369 usbgem_quiesce(dev_info_t *dip)
6370 {
6371         struct usbgem_dev       *dp;
6372 
6373         dp = USBGEM_GET_DEV(dip);
6374 
6375         ASSERT(dp != NULL);
6376 
6377         if (dp->mac_state != MAC_STATE_DISCONNECTED &&
6378             dp->mac_state != MAC_STATE_STOPPED) {
6379                 if (usbgem_hal_stop_chip(dp) != USB_SUCCESS) {
6380                         (void) usbgem_hal_reset_chip(dp);
6381                 }
6382         }
6383 
6384         /* devo_quiesce() must return DDI_SUCCESS always */
6385         return (DDI_SUCCESS);
6386 }