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