1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * USB Ethernet Control Model
  29  *
  30  * USB-IF defines three ethernet network related specifications: EEM,
  31  * ECM and NCM. This driver focuses specifically on ECM compatible
  32  * devices. This kind of devices generally have one pair of bulk
  33  * endpoints for in/out packet data and one interrupt endpoint for
  34  * device notification.
  35  *
  36  * Devices which don't report ECM compatibility through descriptors but
  37  * implement the ECM functions may also bind to this driver. This driver
  38  * will try to find at least a bulk in endpoint and a bulk out endpoint
  39  * in this case. If the non-compatible devices use vendor specific data
  40  * format, this driver will not function.
  41  *
  42  * This driver is a normal USBA client driver. It's also a GLDv3 driver,
  43  * which provides the necessary interfaces the GLDv3 framework requires.
  44  *
  45  */
  46 
  47 #include <sys/types.h>
  48 #include <sys/strsun.h>
  49 #include <sys/ddi.h>
  50 #include <sys/sunddi.h>
  51 #include <sys/byteorder.h>
  52 #include <sys/usb/usba/usbai_version.h>
  53 #include <sys/usb/usba.h>
  54 #include <sys/usb/usba/usba_types.h>
  55 #include <sys/usb/clients/usbcdc/usb_cdc.h>
  56 #include <sys/usb/clients/usbecm/usbecm.h>
  57 #include <sys/mac_provider.h>
  58 #include <sys/strsubr.h>
  59 #include <sys/ethernet.h>
  60 #include <sys/mac_ether.h> /* MAC_PLUGIN_IDENT_ETHER */
  61 #include <sys/random.h> /* random_get_bytes */
  62 #include <sys/sdt.h>      /* sdt */
  63 #include <inet/nd.h>
  64 
  65 /* MAC callbacks */
  66 static int      usbecm_m_stat(void *arg, uint_t stat, uint64_t *val);
  67 static int      usbecm_m_start(void *arg);
  68 static void     usbecm_m_stop(void *arg);
  69 static int      usbecm_m_unicst(void *arg, const uint8_t *macaddr);
  70 static int      usbecm_m_multicst(void *arg, boolean_t add, const uint8_t *m);
  71 static int      usbecm_m_promisc(void *arg, boolean_t on);
  72 static void     usbecm_m_ioctl(void *arg, queue_t *wq, mblk_t *mp);
  73 static mblk_t   *usbecm_m_tx(void *arg, mblk_t *mp);
  74 static int      usbecm_m_getprop(void *arg, const char *pr_name,
  75     mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf);
  76 static int      usbecm_m_setprop(void *arg, const char *pr_name,
  77     mac_prop_id_t wldp_pr_num, uint_t wldp_length, const void *wldp_buf);
  78 
  79 static int      usbecm_usb_init(usbecm_state_t *ecmp);
  80 static int      usbecm_mac_init(usbecm_state_t *ecmp);
  81 static int      usbecm_mac_fini(usbecm_state_t *ecmp);
  82 
  83 
  84 /* utils */
  85 static void     generate_ether_addr(uint8_t *mac_addr);
  86 static int      usbecm_rx_start(usbecm_state_t *ecmp);
  87 
  88 static void     usbecm_pipe_start_polling(usbecm_state_t *ecmp);
  89 static void     usbecm_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req);
  90 static void     usbecm_intr_ex_cb(usb_pipe_handle_t ph, usb_intr_req_t *req);
  91 static void     usbecm_parse_intr_data(usbecm_state_t *ecmp, mblk_t *data);
  92 
  93 static int      usbecm_reconnect_event_cb(dev_info_t *dip);
  94 static int      usbecm_disconnect_event_cb(dev_info_t *dip);
  95 
  96 static int      usbecm_open_pipes(usbecm_state_t *ecmp);
  97 static void     usbecm_close_pipes(usbecm_state_t *ecmp);
  98 
  99 static int      usbecm_ctrl_read(usbecm_state_t *ecmp, uchar_t request,
 100     uint16_t value, mblk_t **data, int len);
 101 static int      usbecm_ctrl_write(usbecm_state_t *ecmp, uchar_t request,
 102     uint16_t value, mblk_t **data);
 103 static int      usbecm_send_data(usbecm_state_t *ecmp, mblk_t *data);
 104 static int      usbecm_send_zero_data(usbecm_state_t *ecmp);
 105 static int      usbecm_get_statistics(usbecm_state_t *ecmp, uint32_t fs,
 106     uint32_t *stat_data);
 107 
 108 static int      usbecm_create_pm_components(usbecm_state_t *ecmp);
 109 static void     usbecm_destroy_pm_components(usbecm_state_t *ecmp);
 110 static int      usbecm_power(dev_info_t *dip, int comp, int level);
 111 static void     usbecm_pm_set_busy(usbecm_state_t *ecmp);
 112 static void     usbecm_pm_set_idle(usbecm_state_t *ecmp);
 113 
 114 static int      usbecm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
 115 static int      usbecm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
 116 
 117 static int      usbecm_suspend(usbecm_state_t *ecmp);
 118 static int      usbecm_resume(usbecm_state_t *ecmp);
 119 static int      usbecm_restore_device_state(usbecm_state_t *ecmp);
 120 static void     usbecm_cleanup(usbecm_state_t *ecmp);
 121 
 122 /* Driver identification */
 123 static char usbecm_ident[] = "usbecm 1.0";
 124 
 125 /* Global state pointer for managing per-device soft states */
 126 void *usbecm_statep;
 127 
 128 /* print levels */
 129 static uint_t   usbecm_errlevel = USB_LOG_L3;
 130 static uint_t   usbecm_errmask = 0xffffffff;
 131 static uint_t   usbecm_instance_debug = (uint_t)-1;
 132 
 133 /*
 134  * to prevent upper layers packet flood from exhausting system
 135  * resources(USBA does not set limitation of requests on a pipe),
 136  * we set a upper limit for the transfer queue length.
 137  */
 138 static  int     usbecm_tx_max = 32;
 139 
 140 #define SUN_SP_VENDOR_ID        0x0430
 141 #define SUN_SP_PRODUCT_ID       0xa4a2
 142 
 143 static uint8_t  usbecm_broadcast[ETHERADDRL] = {
 144         0xff, 0xff, 0xff, 0xff, 0xff, 0xff
 145 };
 146 
 147 static usb_event_t usbecm_events = {
 148         usbecm_disconnect_event_cb,
 149         usbecm_reconnect_event_cb,
 150         NULL, NULL
 151 };
 152 
 153 #define ECM_DS_OP_VALID(op) ((ecmp->ecm_ds_ops) && (ecmp->ecm_ds_ops->op))
 154 
 155 /*
 156  * MAC Call Back entries
 157  */
 158 static mac_callbacks_t usbecm_m_callbacks = {
 159         MC_IOCTL | MC_SETPROP | MC_GETPROP,
 160         usbecm_m_stat,          /* Get the value of a statistic */
 161         usbecm_m_start,         /* Start the device */
 162         usbecm_m_stop,          /* Stop the device */
 163         usbecm_m_promisc,       /* Enable or disable promiscuous mode */
 164         usbecm_m_multicst,      /* Enable or disable a multicast addr */
 165         usbecm_m_unicst,        /* Set the unicast MAC address */
 166         usbecm_m_tx,            /* Transmit a packet */
 167         NULL,
 168         usbecm_m_ioctl,         /* Process an unknown ioctl */
 169         NULL,                   /* mc_getcapab */
 170         NULL,                   /* mc_open */
 171         NULL,                   /* mc_close */
 172         usbecm_m_setprop,       /* mc_setprop */
 173         usbecm_m_getprop,       /* mc_getprop */
 174         NULL
 175 };
 176 
 177 
 178 /*
 179  *  Module Loading Data & Entry Points
 180  *     Can't use DDI_DEFINE_STREAM_OPS, since it does
 181  *     not provide devo_power entry.
 182  */
 183 static struct cb_ops cb_usbecm = {
 184         nulldev,                /* cb_open */
 185         nulldev,                /* cb_close */
 186         nodev,                  /* cb_strategy */
 187         nodev,                  /* cb_print */
 188         nodev,                  /* cb_dump */
 189         nodev,                  /* cb_read */
 190         nodev,                  /* cb_write */
 191         nodev,                  /* cb_ioctl */
 192         nodev,                  /* cb_devmap */
 193         nodev,                  /* cb_mmap */
 194         nodev,                  /* cb_segmap */
 195         nochpoll,               /* cb_chpoll */
 196         ddi_prop_op,            /* cb_prop_op */
 197         NULL,                   /* cb_stream */
 198         D_MP,                   /* cb_flag */
 199         CB_REV,                 /* cb_rev */
 200         nodev,                  /* cb_aread */
 201         nodev,                  /* cb_awrite */
 202 };
 203 
 204 static struct dev_ops usbecm_devops = {
 205         DEVO_REV,               /* devo_rev */
 206         0,                      /* devo_refcnt */
 207         NULL,                   /* devo_getinfo */
 208         nulldev,                /* devo_identify */
 209         nulldev,                /* devo_probe */
 210         usbecm_attach,          /* devo_attach */
 211         usbecm_detach,          /* devo_detach */
 212         nodev,                  /* devo_reset */
 213         &(cb_usbecm),               /* devo_cb_ops */
 214         (struct bus_ops *)NULL, /* devo_bus_ops */
 215         usbecm_power,           /* devo_power */
 216         ddi_quiesce_not_needed  /* devo_quiesce */
 217 };
 218 
 219 static struct modldrv usbecm_modldrv = {
 220         &mod_driverops,             /* drv_modops */
 221         usbecm_ident,           /* drv_linkinfo */
 222         &usbecm_devops              /* drv_dev_ops */
 223 };
 224 
 225 static struct modlinkage usbecm_ml = {
 226         MODREV_1,               /* ml_rev */
 227         &usbecm_modldrv, NULL       /* ml_linkage */
 228 };
 229 
 230 
 231 /*
 232  * Device operations
 233  */
 234 /*
 235  * Binding the driver to a device.
 236  *
 237  * Concurrency: Until usbecm_attach() returns with success,
 238  * the only other entry point that can be executed is getinfo().
 239  * Thus no locking here yet.
 240  */
 241 static int
 242 usbecm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 243 {
 244         char strbuf[32];
 245         int instance;
 246         int err;
 247         usbecm_state_t *ecmp = NULL;
 248 
 249         switch (cmd) {
 250         case DDI_ATTACH:
 251                 break;
 252 
 253         case DDI_RESUME:
 254                 ecmp = (usbecm_state_t *)ddi_get_soft_state(usbecm_statep,
 255                     ddi_get_instance(dip));
 256 
 257                 (void) usbecm_resume(ecmp);
 258 
 259                 return (DDI_SUCCESS);
 260 
 261         default:
 262                 return (DDI_FAILURE);
 263         }
 264 
 265         instance = ddi_get_instance(dip);
 266 
 267         if (ddi_soft_state_zalloc(usbecm_statep, instance) == DDI_SUCCESS) {
 268                 ecmp = ddi_get_soft_state(usbecm_statep, instance);
 269         }
 270         if (ecmp == NULL) {
 271                 cmn_err(CE_WARN, "usbecm_attach: fail to get soft state");
 272 
 273                 return (DDI_FAILURE);
 274         }
 275 
 276         ecmp->ecm_dip = dip;
 277 
 278         ecmp->ecm_lh = usb_alloc_log_hdl(ecmp->ecm_dip, "usbecm",
 279             &usbecm_errlevel, &usbecm_errmask, &usbecm_instance_debug, 0);
 280 
 281         if (usbecm_usb_init(ecmp) != USB_SUCCESS) {
 282                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
 283                     "usbecm_attach: failed to init usb");
 284 
 285                 goto fail;
 286         }
 287 
 288         if (ECM_DS_OP_VALID(ecm_ds_init)) {
 289                 if (ecmp->ecm_ds_ops->ecm_ds_init(ecmp) != USB_SUCCESS) {
 290                         USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
 291                             "usbecm_attach: failed to init DS");
 292 
 293                         goto fail;
 294                 }
 295         }
 296 
 297         if (usbecm_mac_init(ecmp) != DDI_SUCCESS) {
 298                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
 299                     "usbecm_attach: failed to init mac");
 300 
 301                 goto fail;
 302         }
 303         ecmp->ecm_init_flags |= USBECM_INIT_MAC;
 304 
 305         /*
 306          * Create minor node of type usb_net. Not necessary to create
 307          * DDI_NT_NET since it's created in mac_register(). Otherwise,
 308          * system will panic.
 309          */
 310         (void) snprintf(strbuf, sizeof (strbuf), "usbecm%d", instance);
 311         err = ddi_create_minor_node(dip, strbuf, S_IFCHR,
 312             instance + 1, "usb_net", 0);
 313         if (err != DDI_SUCCESS) {
 314                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
 315                     "failed to create minor node");
 316 
 317                 goto fail;
 318         }
 319 
 320         /* always busy. May change to a more precise PM in future */
 321         usbecm_pm_set_busy(ecmp);
 322 
 323         ddi_report_dev(dip);
 324 
 325         USB_DPRINTF_L4(PRINT_MASK_ATTA, ecmp->ecm_lh,
 326             "usbecm_attach: succeed!");
 327 
 328         return (DDI_SUCCESS);
 329 
 330 fail:
 331         USB_DPRINTF_L1(PRINT_MASK_ATTA, ecmp->ecm_lh,
 332             "usbecm_attach: Attach fail");
 333 
 334         usbecm_cleanup(ecmp);
 335         ddi_prop_remove_all(dip);
 336         ddi_soft_state_free(usbecm_statep, instance);
 337 
 338         return (DDI_FAILURE);
 339 
 340 }
 341 
 342 
 343 /*
 344  * Detach the driver from a device.
 345  *
 346  * Concurrency: Will be called only after a successful attach
 347  * (and not concurrently).
 348  */
 349 static int
 350 usbecm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 351 {
 352         usbecm_state_t *ecmp = NULL;
 353         int instance;
 354 
 355         instance = ddi_get_instance(dip);
 356         ecmp = ddi_get_soft_state(usbecm_statep, instance);
 357         ASSERT(ecmp != NULL);
 358 
 359         USB_DPRINTF_L4(PRINT_MASK_ATTA, ecmp->ecm_lh,
 360             "usbecm_detach: entry ");
 361 
 362         switch (cmd) {
 363         case DDI_DETACH:
 364                 break;
 365 
 366         case DDI_SUSPEND:
 367 
 368                 return (usbecm_suspend(ecmp));
 369 
 370         default:
 371                 return (DDI_FAILURE);
 372         }
 373 
 374         usbecm_pm_set_idle(ecmp);
 375 
 376         if (ECM_DS_OP_VALID(ecm_ds_fini)) {
 377                 if (ecmp->ecm_ds_ops->ecm_ds_fini(ecmp) != USB_SUCCESS) {
 378                         USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
 379                             "usbecm_detach: deinitialize DS fail!");
 380 
 381                         return (DDI_FAILURE);
 382                 }
 383         }
 384 
 385         if (usbecm_mac_fini(ecmp) != 0) {
 386 
 387                 return (DDI_FAILURE);
 388         }
 389 
 390         USB_DPRINTF_L4(PRINT_MASK_ATTA, ecmp->ecm_lh,
 391             "usbecm_detach: exit");
 392 
 393         usbecm_cleanup(ecmp);
 394         ddi_soft_state_free(usbecm_statep, instance);
 395 
 396         return (DDI_SUCCESS);
 397 }
 398 
 399 
 400 /*
 401  * Mac Call Back functions
 402  */
 403 
 404 /*
 405  * Read device statistic information.
 406  */
 407 static int
 408 usbecm_m_stat(void *arg, uint_t stat, uint64_t *val)
 409 {
 410         usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 411         uint32_t        stats;
 412         int             rval;
 413         uint32_t        fs;
 414 
 415         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 416             "usbecm_m_stat: entry, stat=%d", stat);
 417 
 418         /*
 419          * Some of the stats are MII specific. We try to
 420          * resolve all the statistics we understand. If
 421          * the usb device can't provide it, return ENOTSUP.
 422          */
 423         switch (stat) {
 424         case MAC_STAT_IFSPEED:
 425                 /* return link speed */
 426                 mutex_enter(&ecmp->ecm_mutex);
 427                 if (ecmp->ecm_stat.es_downspeed) {
 428                         *val = ecmp->ecm_stat.es_downspeed;
 429                 } else {
 430                         *val = 10 * 1000000ull; /* set a default value */
 431                 }
 432                 mutex_exit(&ecmp->ecm_mutex);
 433 
 434                 return (0);
 435         case ETHER_STAT_LINK_DUPLEX:
 436                 *val = LINK_DUPLEX_FULL;
 437 
 438                 return (0);
 439 
 440         case ETHER_STAT_SQE_ERRORS:
 441                 *val = 0;
 442 
 443                 return (0);
 444 
 445         /* Map MAC/Ether stats to ECM statistics */
 446         case MAC_STAT_NORCVBUF:
 447                 fs = ECM_RCV_NO_BUFFER;
 448 
 449                 break;
 450         case MAC_STAT_NOXMTBUF:
 451                 fs = ECM_XMIT_ERROR;
 452 
 453                 break;
 454         case MAC_STAT_IERRORS:
 455                 fs = ECM_RCV_ERROR;
 456 
 457                 break;
 458         case MAC_STAT_OERRORS:
 459                 fs = ECM_XMIT_ERROR;
 460 
 461                 break;
 462         case MAC_STAT_RBYTES:
 463                 fs = ECM_DIRECTED_BYTES_RCV;
 464 
 465                 break;
 466         case MAC_STAT_IPACKETS:
 467                 fs = ECM_RCV_OK; /* frames */
 468 
 469                 break;
 470         case MAC_STAT_OBYTES:
 471                 fs = ECM_DIRECTED_BYTES_XMIT;
 472 
 473                 break;
 474         case MAC_STAT_OPACKETS:
 475                 fs = ECM_XMIT_OK; /* frames */
 476 
 477                 break;
 478         case MAC_STAT_MULTIRCV:
 479                 fs = ECM_MULTICAST_FRAMES_RCV;
 480 
 481                 break;
 482         case MAC_STAT_BRDCSTRCV:
 483                 fs = ECM_BROADCAST_FRAMES_RCV;
 484 
 485                 break;
 486         case MAC_STAT_MULTIXMT:
 487                 fs = ECM_MULTICAST_FRAMES_XMIT;
 488 
 489                 break;
 490         case MAC_STAT_BRDCSTXMT:
 491                 fs = ECM_BROADCAST_FRAMES_XMIT;
 492 
 493                 break;
 494         case MAC_STAT_COLLISIONS:
 495                 fs = ECM_XMIT_MAX_COLLISIONS;
 496 
 497                 break;
 498         case MAC_STAT_OVERFLOWS:
 499                 fs = ECM_RCV_OVERRUN;
 500 
 501                 break;
 502         case MAC_STAT_UNDERFLOWS:
 503                 fs = ECM_XMIT_UNDERRUN;
 504 
 505                 break;
 506         case ETHER_STAT_FCS_ERRORS:
 507                 fs = ECM_RCV_CRC_ERROR;
 508 
 509                 break;
 510         case ETHER_STAT_ALIGN_ERRORS:
 511                 fs = ECM_RCV_ERROR_ALIGNMENT;
 512 
 513                 break;
 514         case ETHER_STAT_DEFER_XMTS:
 515                 fs = ECM_XMIT_DEFERRED;
 516 
 517                 break;
 518         case ETHER_STAT_FIRST_COLLISIONS:
 519                 fs = ECM_XMIT_ONE_COLLISION;
 520 
 521                 break;
 522         case ETHER_STAT_MULTI_COLLISIONS:
 523                 fs = ECM_XMIT_MORE_COLLISIONS;
 524 
 525                 break;
 526         case ETHER_STAT_TX_LATE_COLLISIONS:
 527                 fs = ECM_XMIT_LATE_COLLISIONS;
 528 
 529                 break;
 530 
 531         default:
 532                 return (ENOTSUP);
 533         }
 534 
 535         /*
 536          * we need to access device to get required stats,
 537          * so check device state first
 538          */
 539         mutex_enter(&ecmp->ecm_mutex);
 540         if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
 541                 USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
 542                     "usbecm_m_stat: device not ONLINE");
 543 
 544                 mutex_exit(&ecmp->ecm_mutex);
 545 
 546                 return (EIO);
 547         }
 548         mutex_exit(&ecmp->ecm_mutex);
 549 
 550         rval = usbecm_get_statistics(ecmp,
 551             ECM_STAT_SELECTOR(fs), &stats);
 552         if (rval != USB_SUCCESS) {
 553                 mutex_enter(&ecmp->ecm_mutex);
 554                 switch (stat) {
 555                 case MAC_STAT_IERRORS:
 556                         *val = ecmp->ecm_stat.es_ierrors;
 557 
 558                         break;
 559                 case MAC_STAT_OERRORS:
 560                         *val = ecmp->ecm_stat.es_oerrors;
 561 
 562                         break;
 563                 case MAC_STAT_RBYTES:
 564                         *val = ecmp->ecm_stat.es_ibytes;
 565 
 566                         break;
 567                 case MAC_STAT_IPACKETS:
 568                         *val = ecmp->ecm_stat.es_ipackets;
 569 
 570                         break;
 571                 case MAC_STAT_OBYTES:
 572                         *val = ecmp->ecm_stat.es_obytes;
 573 
 574                         break;
 575                 case MAC_STAT_OPACKETS:
 576                         *val = ecmp->ecm_stat.es_opackets;
 577 
 578                         break;
 579                 case MAC_STAT_MULTIRCV:
 580                         *val = ecmp->ecm_stat.es_multircv;
 581 
 582                         break;
 583                 case MAC_STAT_MULTIXMT:
 584                         *val = ecmp->ecm_stat.es_multixmt;
 585 
 586                         break;
 587                 case MAC_STAT_BRDCSTRCV:
 588                         *val = ecmp->ecm_stat.es_brdcstrcv;
 589 
 590                         break;
 591                 case MAC_STAT_BRDCSTXMT:
 592                         *val = ecmp->ecm_stat.es_brdcstxmt;
 593 
 594                         break;
 595                 case ETHER_STAT_MACXMT_ERRORS:
 596                         *val = ecmp->ecm_stat.es_macxmt_err;
 597                         break;
 598                 default:
 599                         *val = 0;
 600 
 601                         break;
 602                 }
 603                 mutex_exit(&ecmp->ecm_mutex);
 604         } else {
 605                 *val = stats;
 606         }
 607 
 608         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 609             "usbecm_m_stat: end");
 610 
 611         return (0);
 612 }
 613 
 614 
 615 /*
 616  * Start the device:
 617  *      - Set proper altsettings of the data interface
 618  *      - Open status and data endpoints
 619  *      - Start status polling
 620  *      - Get bulk-in ep ready to receive data from ethernet
 621  *
 622  * Concurrency: Presumably fully concurrent, must lock.
 623  */
 624 static int
 625 usbecm_m_start(void *arg)
 626 {
 627         usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 628         int rval;
 629 
 630         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 631             "usbecm_m_start: entry");
 632 
 633         (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
 634         mutex_enter(&ecmp->ecm_mutex);
 635         if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
 636                 USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
 637                     "usbecm_m_start: device not online");
 638                 rval = ENODEV;
 639                 mutex_exit(&ecmp->ecm_mutex);
 640 
 641                 goto fail;
 642         }
 643         mutex_exit(&ecmp->ecm_mutex);
 644 
 645         if (usbecm_open_pipes(ecmp) != USB_SUCCESS) {
 646                 USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
 647                     "usbecm_m_start: open pipes fail");
 648                 rval = EIO;
 649 
 650                 goto fail;
 651         }
 652 
 653         mutex_enter(&ecmp->ecm_mutex);
 654         if (usbecm_rx_start(ecmp) != USB_SUCCESS) {
 655                 USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
 656                     "usbecm_m_start: fail to start_rx");
 657                 mutex_exit(&ecmp->ecm_mutex);
 658                 rval = EIO;
 659 
 660                 goto fail;
 661         }
 662         ecmp->ecm_mac_state = USBECM_MAC_STARTED;
 663         mutex_exit(&ecmp->ecm_mutex);
 664 
 665         /* set the device to receive all multicast/broadcast pkts */
 666         rval = usbecm_ctrl_write(ecmp, CDC_ECM_SET_ETH_PKT_FLT,
 667             CDC_ECM_PKT_TYPE_DIRECTED | CDC_ECM_PKT_TYPE_ALL_MCAST |
 668             CDC_ECM_PKT_TYPE_BCAST, NULL);
 669         if (rval != USB_SUCCESS) {
 670                 USB_DPRINTF_L3(PRINT_MASK_OPS, ecmp->ecm_lh,
 671                     "usbecm_m_start: set packet filters fail,"
 672                     " rval=%d, continue", rval);
 673         }
 674 
 675         if (ECM_DS_OP_VALID(ecm_ds_start)) {
 676                 if (ecmp->ecm_ds_ops->ecm_ds_start(ecmp) != USB_SUCCESS) {
 677                         USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
 678                             "usbecm_m_start: Can't start hardware");
 679 
 680                         goto fail;
 681                 }
 682         }
 683 
 684         usb_release_access(ecmp->ecm_ser_acc);
 685 
 686         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 687             "usbecm_m_start: end");
 688 
 689         /*
 690          * To mark the link as RUNNING.
 691          *
 692          * ECM spec doesn't provide a way for host to get the status
 693          * of the physical link initiatively. Only the device can
 694          * report the link state through interrupt endpoints.
 695          */
 696         mac_link_update(ecmp->ecm_mh, LINK_STATE_UP);
 697         mutex_enter(&ecmp->ecm_mutex);
 698         ecmp->ecm_stat.es_linkstate = LINK_STATE_UP;
 699         mutex_exit(&ecmp->ecm_mutex);
 700 
 701         return (DDI_SUCCESS);
 702 fail:
 703         usb_release_access(ecmp->ecm_ser_acc);
 704 
 705         return (rval);
 706 }
 707 
 708 /*
 709  * Stop the device.
 710  */
 711 static void
 712 usbecm_m_stop(void *arg)
 713 {
 714         usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 715 
 716         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 717             "usbecm_m_stop: entry");
 718 
 719         (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
 720         if (ECM_DS_OP_VALID(ecm_ds_stop)) {
 721                 if (ecmp->ecm_ds_ops->ecm_ds_stop(ecmp) != USB_SUCCESS) {
 722                         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 723                             "usbecm_m_stop: fail to stop hardware");
 724                 }
 725         }
 726 
 727         usbecm_close_pipes(ecmp);
 728         usb_release_access(ecmp->ecm_ser_acc);
 729 
 730         mutex_enter(&ecmp->ecm_mutex);
 731         ecmp->ecm_mac_state = USBECM_MAC_STOPPED;
 732         mutex_exit(&ecmp->ecm_mutex);
 733 
 734         mac_link_update(ecmp->ecm_mh, LINK_STATE_DOWN);
 735         mutex_enter(&ecmp->ecm_mutex);
 736         ecmp->ecm_stat.es_linkstate = LINK_STATE_DOWN;
 737         mutex_exit(&ecmp->ecm_mutex);
 738 
 739         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 740             "usbecm_m_stop: end");
 741 }
 742 
 743 /*
 744  * Change the MAC address of the device.
 745  */
 746 /*ARGSUSED*/
 747 static int
 748 usbecm_m_unicst(void *arg, const uint8_t *macaddr)
 749 {
 750         usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 751         uint16_t        filter;
 752         int             rval;
 753 
 754         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 755             "usbecm_m_unicst: entry");
 756 
 757         /*
 758          * The device doesn't support to set a different MAC addr.
 759          * Hence, it's not necessary to stop the device first if
 760          * the mac addresses are identical. And we just set unicast
 761          * filter only.
 762          */
 763         if (bcmp(macaddr, ecmp->ecm_srcaddr, ETHERADDRL) != 0) {
 764                 USB_DPRINTF_L3(PRINT_MASK_OPS, ecmp->ecm_lh,
 765                     "usbecm_m_unicst: not supported to set a"
 766                     " different MAC addr");
 767 
 768                 return (DDI_FAILURE);
 769         }
 770         mutex_enter(&ecmp->ecm_mutex);
 771         filter = ecmp->ecm_pkt_flt |= CDC_ECM_PKT_TYPE_DIRECTED;
 772         mutex_exit(&ecmp->ecm_mutex);
 773 
 774         (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
 775         rval = usbecm_ctrl_write(ecmp, CDC_ECM_SET_ETH_PKT_FLT,
 776             filter, NULL);
 777         usb_release_access(ecmp->ecm_ser_acc);
 778 
 779         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 780             "usbecm_m_unicst: rval = %d", rval);
 781 
 782         /* some devices may not support this request, we just return success */
 783         return (DDI_SUCCESS);
 784 }
 785 
 786 /*
 787  * Enable/disable multicast.
 788  */
 789 /*ARGSUSED*/
 790 static int
 791 usbecm_m_multicst(void *arg, boolean_t add, const uint8_t *m)
 792 {
 793         usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 794         uint16_t        filter;
 795         int     rval = 0;
 796 
 797         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 798             "usbecm_m_multicst: entry");
 799         mutex_enter(&ecmp->ecm_mutex);
 800 
 801         /*
 802          * To simplify the implementation, we support switching
 803          * all multicast on/off feature only
 804          */
 805         if (add == B_TRUE) {
 806                 ecmp->ecm_pkt_flt |= CDC_ECM_PKT_TYPE_ALL_MCAST;
 807         } else {
 808                 ecmp->ecm_pkt_flt &= ~CDC_ECM_PKT_TYPE_ALL_MCAST;
 809         }
 810         filter = ecmp->ecm_pkt_flt;
 811         mutex_exit(&ecmp->ecm_mutex);
 812 
 813         (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
 814         if (ecmp->ecm_compatibility &&
 815             (ecmp->ecm_desc.wNumberMCFilters & 0x7F)) {
 816         /* Device supports SetEthernetMulticastFilters request */
 817                 rval = usbecm_ctrl_write(ecmp, CDC_ECM_SET_ETH_PKT_FLT,
 818                     filter, NULL);
 819                 USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 820                     "usbecm_m_multicst: rval = %d", rval);
 821         }
 822         usb_release_access(ecmp->ecm_ser_acc);
 823 
 824         /* some devices may not support this request, we just return success */
 825         return (DDI_SUCCESS);
 826 }
 827 
 828 /*
 829  * Enable/disable promiscuous mode.
 830  */
 831 static int
 832 usbecm_m_promisc(void *arg, boolean_t on)
 833 {
 834         usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 835         uint16_t        filter;
 836         int             rval;
 837 
 838         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 839             "usbecm_m_promisc: entry");
 840 
 841         mutex_enter(&ecmp->ecm_mutex);
 842         if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
 843                 USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
 844                     "usbecm_m_promisc: device not ONLINE");
 845                 mutex_exit(&ecmp->ecm_mutex);
 846 
 847                 return (DDI_FAILURE);
 848         }
 849 
 850 
 851         if (on == B_TRUE) {
 852                 ecmp->ecm_pkt_flt |= CDC_ECM_PKT_TYPE_PROMISC;
 853         } else {
 854                 ecmp->ecm_pkt_flt &= ~CDC_ECM_PKT_TYPE_PROMISC;
 855         }
 856         filter = ecmp->ecm_pkt_flt;
 857         mutex_exit(&ecmp->ecm_mutex);
 858 
 859         (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
 860         rval = usbecm_ctrl_write(ecmp, CDC_ECM_SET_ETH_PKT_FLT,
 861             filter, NULL);
 862         usb_release_access(ecmp->ecm_ser_acc);
 863 
 864         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 865             "usbecm_m_promisc: rval=%d", rval);
 866 
 867         /*
 868          * devices may not support this request, we just
 869          * return success to let upper layer to do further
 870          * operation.
 871          */
 872         return (DDI_SUCCESS);
 873 }
 874 
 875 /*
 876  * IOCTL request: Does not do anything. Will be enhanced
 877  *      in future.
 878  */
 879 static void
 880 usbecm_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
 881 {
 882         usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 883         struct iocblk   *iocp;
 884         int cmd;
 885 
 886         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 887             "usbecm_m_ioctl: entry");
 888 
 889         mutex_enter(&ecmp->ecm_mutex);
 890         if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
 891                 USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
 892                     "usbecm_m_ioctl: device not ONLINE");
 893                 mutex_exit(&ecmp->ecm_mutex);
 894 
 895                 miocnak(wq, mp, 0, EIO);
 896 
 897                 return;
 898         }
 899         mutex_exit(&ecmp->ecm_mutex);
 900 
 901         iocp = (void *)mp->b_rptr;
 902         iocp->ioc_error = 0;
 903         cmd = iocp->ioc_cmd;
 904 
 905         (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
 906 
 907         switch (cmd) {
 908         default:
 909                 USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 910                     "unknown cmd 0x%x", cmd);
 911                 usb_release_access(ecmp->ecm_ser_acc);
 912                 miocnak(wq, mp, 0, EINVAL);
 913 
 914                 return;
 915         }
 916 }
 917 
 918 /*
 919  * callback functions for get/set properties
 920  *      Does not do anything. Will be enhanced to
 921  *      support set/get properties in future.
 922  */
 923 /*ARGSUSED*/
 924 static int
 925 usbecm_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
 926     uint_t wldp_length, const void *wldp_buf)
 927 {
 928         usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 929         int err = ENOTSUP;
 930 
 931         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 932             "usbecm_m_setprop: entry");
 933 
 934         return (err);
 935 }
 936 
 937 /*ARGSUSED*/
 938 static int usbecm_m_getprop(void *arg, const char *pr_name,
 939     mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf)
 940 {
 941         usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 942         int err = ENOTSUP;
 943 
 944         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 945             "usbecm_m_getprop: entry");
 946 
 947         mutex_enter(&ecmp->ecm_mutex);
 948         if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
 949                 mutex_exit(&ecmp->ecm_mutex);
 950 
 951                 return (EIO);
 952         }
 953         mutex_exit(&ecmp->ecm_mutex);
 954 
 955         return (err);
 956 }
 957 
 958 /*
 959  * Transmit a data frame.
 960  */
 961 static mblk_t *
 962 usbecm_m_tx(void *arg, mblk_t *mp)
 963 {
 964         usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 965         mblk_t *next;
 966         int count = 0;
 967 
 968         ASSERT(mp != NULL);
 969 
 970         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 971             "usbecm_m_tx: entry");
 972 
 973         mutex_enter(&ecmp->ecm_mutex);
 974         if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
 975                 USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
 976                     "usbecm_m_tx: device not ONLINE");
 977                 mutex_exit(&ecmp->ecm_mutex);
 978 
 979                 return (mp);
 980         }
 981         mutex_exit(&ecmp->ecm_mutex);
 982 
 983         (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
 984 
 985         /*
 986          * To make use of the device maximum capability,
 987          * concatenate msg blocks in a msg to ETHERMAX length.
 988          */
 989         while (mp != NULL) {
 990                 next = mp->b_next;
 991                 mp->b_next = NULL;
 992 
 993                 if (usbecm_send_data(ecmp, mp) != DDI_SUCCESS) {
 994                         USB_DPRINTF_L3(PRINT_MASK_OPS, ecmp->ecm_lh,
 995                             "usbecm_m_tx: send data fail");
 996 
 997                         /* failure statistics */
 998                         mutex_enter(&ecmp->ecm_mutex);
 999                         ecmp->ecm_stat.es_oerrors++;
1000                         mutex_exit(&ecmp->ecm_mutex);
1001 
1002                         mp->b_next = next;
1003 
1004                         break;
1005                 }
1006 
1007                 /*
1008                  * To make it simple, we count all packets, no matter
1009                  * the device supports ethernet statistics or not.
1010                  */
1011                 mutex_enter(&ecmp->ecm_mutex);
1012                 ecmp->ecm_stat.es_opackets++;
1013                 ecmp->ecm_stat.es_obytes += MBLKL(mp);
1014                 mutex_exit(&ecmp->ecm_mutex);
1015 
1016                 freemsg(mp); /* free this msg upon success */
1017 
1018                 mp = next;
1019                 USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1020                     "usbecm_m_tx: %d msgs processed", ++count);
1021         }
1022 
1023         usb_release_access(ecmp->ecm_ser_acc);
1024 
1025         return (mp);
1026 }
1027 
1028 /*
1029  * usbecm_bulkin_cb:
1030  *      Bulk In regular and exeception callback;
1031  *      USBA framework will call this callback
1032  *      after deal with bulkin request.
1033  */
1034 /*ARGSUSED*/
1035 static void
1036 usbecm_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1037 {
1038         usbecm_state_t  *ecmp = (usbecm_state_t *)req->bulk_client_private;
1039         mblk_t          *data, *mp;
1040         int             data_len;
1041         int             max_pkt_size = ecmp->ecm_bulkin_sz;
1042 
1043         data = req->bulk_data;
1044         data_len = (data) ? MBLKL(data) : 0;
1045 
1046         ASSERT(data->b_cont == NULL);
1047 
1048         mutex_enter(&ecmp->ecm_mutex);
1049 
1050         USB_DPRINTF_L4(PRINT_MASK_CB, ecmp->ecm_lh,
1051             "usbecm_bulkin_cb: state=%d, len=%d", ecmp->ecm_bulkin_state,
1052             data_len);
1053 
1054         /*
1055          * may receive a zero length packet according
1056          * to USB short packet semantics
1057          */
1058         if ((ecmp->ecm_dev_state == USB_DEV_ONLINE) &&
1059             (req->bulk_completion_reason == USB_CR_OK)) {
1060                 if (data_len) {
1061                         if (ecmp->ecm_rcv_queue == NULL) {
1062                                 ecmp->ecm_rcv_queue = data;
1063                         } else {
1064                                 if ((msgsize(ecmp->ecm_rcv_queue) + data_len)
1065                                     > ETHERMAX) {
1066                                 /*
1067                                  * Exceed the ethernet maximum length, we think
1068                                  * something is wrong with this frame and hence
1069                                  * free older data. Accept new data instead.
1070                                  */
1071                                         freemsg(ecmp->ecm_rcv_queue);
1072                                         ecmp->ecm_rcv_queue = data;
1073                                 } else {
1074                                         linkb(ecmp->ecm_rcv_queue, data);
1075                                 }
1076                         }
1077                 } else {
1078                 /*
1079                  * Do not put zero length packet to receive queue.
1080                  * Otherwise, msgpullup will dupmsg() a zero length
1081                  * mblk, which will cause memleaks.
1082                  */
1083                         freemsg(data);
1084                 }
1085 
1086                 /*
1087                  * ECM V1.2, section 3.3.1, a short(including zero length)
1088                  * packet signifies end of frame. We can submit this frame
1089                  * to upper layer now.
1090                  */
1091                 if ((data_len < max_pkt_size) &&
1092                     (msgsize(ecmp->ecm_rcv_queue) > 0)) {
1093                         mp = msgpullup(ecmp->ecm_rcv_queue, -1);
1094                         freemsg(ecmp->ecm_rcv_queue);
1095                         ecmp->ecm_rcv_queue = NULL;
1096 
1097                         ecmp->ecm_stat.es_ipackets++;
1098                         ecmp->ecm_stat.es_ibytes += msgsize(mp);
1099                         if (mp && (mp->b_rptr[0] & 0x01)) {
1100                                 if (bcmp(mp->b_rptr, usbecm_broadcast,
1101                                     ETHERADDRL) != 0) {
1102                                         ecmp->ecm_stat.es_multircv++;
1103                                 } else {
1104                                         ecmp->ecm_stat.es_brdcstrcv++;
1105                                 }
1106                         }
1107 
1108                         if (mp) {
1109                                 mutex_exit(&ecmp->ecm_mutex);
1110                                 mac_rx(ecmp->ecm_mh, NULL, mp);
1111                                 mutex_enter(&ecmp->ecm_mutex);
1112                         }
1113                 }
1114 
1115                 /* prevent USBA from freeing data along with the request */
1116                 req->bulk_data = NULL;
1117         } else if (req->bulk_completion_reason != USB_CR_OK) {
1118                 ecmp->ecm_stat.es_ierrors++;
1119         }
1120         mutex_exit(&ecmp->ecm_mutex);
1121 
1122         usb_free_bulk_req(req);
1123 
1124         /* receive more */
1125         mutex_enter(&ecmp->ecm_mutex);
1126         if (((ecmp->ecm_bulkin_state == USBECM_PIPE_BUSY) ||
1127             (ecmp->ecm_bulkin_state == USBECM_PIPE_IDLE)) &&
1128             (ecmp->ecm_dev_state == USB_DEV_ONLINE)) {
1129                 if (usbecm_rx_start(ecmp) != USB_SUCCESS) {
1130                         USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1131                             "usbecm_bulkin_cb: restart rx fail "
1132                             "ecmp_state = %d", ecmp->ecm_bulkin_state);
1133                 }
1134         } else if (ecmp->ecm_bulkin_state == USBECM_PIPE_BUSY) {
1135                 ecmp->ecm_bulkin_state = USBECM_PIPE_IDLE;
1136         }
1137         mutex_exit(&ecmp->ecm_mutex);
1138 }
1139 
1140 /*
1141  * usbsecm_rx_start:
1142  *      start data receipt
1143  */
1144 static int
1145 usbecm_rx_start(usbecm_state_t *ecmp)
1146 {
1147         usb_bulk_req_t  *br;
1148         int             rval = USB_FAILURE;
1149         int             data_len;
1150 
1151         ASSERT(mutex_owned(&ecmp->ecm_mutex));
1152 
1153         DTRACE_PROBE2(usbecm_rx__start, int, ecmp->ecm_xfer_sz,
1154             int, ecmp->ecm_bulkin_sz);
1155 
1156         ecmp->ecm_bulkin_state = USBECM_PIPE_BUSY;
1157         data_len = ecmp->ecm_bulkin_sz;
1158 
1159         mutex_exit(&ecmp->ecm_mutex);
1160         br = usb_alloc_bulk_req(ecmp->ecm_dip, data_len, USB_FLAGS_SLEEP);
1161         if (br == NULL) {
1162                 USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1163                     "usbsecm_rx_start: allocate bulk request failed");
1164 
1165                 mutex_enter(&ecmp->ecm_mutex);
1166 
1167                 return (USB_FAILURE);
1168         }
1169         /* initialize bulk in request. */
1170         br->bulk_len = data_len;
1171         br->bulk_timeout = 0;
1172         br->bulk_cb = usbecm_bulkin_cb;
1173         br->bulk_exc_cb = usbecm_bulkin_cb;
1174         br->bulk_client_private = (usb_opaque_t)ecmp;
1175         br->bulk_attributes = USB_ATTRS_AUTOCLEARING
1176             | USB_ATTRS_SHORT_XFER_OK;
1177 
1178         rval = usb_pipe_bulk_xfer(ecmp->ecm_bulkin_ph, br, 0);
1179         mutex_enter(&ecmp->ecm_mutex);
1180         if (rval != USB_SUCCESS) {
1181                 USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1182                     "usbsecm_rx_start: bulk transfer failed %d", rval);
1183                 usb_free_bulk_req(br);
1184                 ecmp->ecm_bulkin_state = USBECM_PIPE_IDLE;
1185         }
1186 
1187         return (rval);
1188 }
1189 
1190 /*
1191  * usbecm_bulkout_cb:
1192  *      Bulk Out regular and exeception callback;
1193  *      USBA framework will call this callback function
1194  *      after deal with bulkout request.
1195  */
1196 /*ARGSUSED*/
1197 static void
1198 usbecm_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1199 {
1200         usbecm_state_t *ecmp = (usbecm_state_t *)req->bulk_client_private;
1201         int             data_len;
1202         boolean_t       need_update = B_FALSE;
1203 
1204         data_len = (req->bulk_data) ? MBLKL(req->bulk_data) : 0;
1205 
1206         USB_DPRINTF_L4(PRINT_MASK_CB, ecmp->ecm_lh,
1207             "usbecm_bulkout_cb: data_len = %d, cr=%d", data_len,
1208             req->bulk_completion_reason);
1209 
1210         mutex_enter(&ecmp->ecm_mutex);
1211         if ((data_len > 0) && (ecmp->ecm_tx_cnt > 0)) {
1212                 if (ecmp->ecm_tx_cnt == usbecm_tx_max) {
1213                         need_update = B_TRUE;
1214                 }
1215                 ecmp->ecm_tx_cnt--;
1216         }
1217         mutex_exit(&ecmp->ecm_mutex);
1218 
1219         if (req->bulk_completion_reason && (data_len > 0)) {
1220                 mutex_enter(&ecmp->ecm_mutex);
1221                 ecmp->ecm_stat.es_oerrors++;
1222                 mutex_exit(&ecmp->ecm_mutex);
1223 
1224                 need_update = B_TRUE;
1225         }
1226 
1227         /*
1228          * notify MAC layer to retransfer the failed packet
1229          * Or notity MAC that we have more buffer now.
1230          */
1231         if (need_update) {
1232                 mac_tx_update(ecmp->ecm_mh);
1233         }
1234 
1235         usb_free_bulk_req(req);
1236 }
1237 
1238 static int
1239 usbecm_send_data(usbecm_state_t *ecmp, mblk_t *data)
1240 {
1241         usb_bulk_req_t  *br;
1242         int             rval = USB_FAILURE;
1243         int             data_len = MBLKL(data);
1244         int             max_pkt_size;
1245         mblk_t          *new_data = NULL;
1246         int             new_data_len = 0;
1247 
1248         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1249             "usbecm_send_data: length = %d, total len=%d",
1250             data_len, (int)msgdsize(data));
1251 
1252         mutex_enter(&ecmp->ecm_mutex);
1253         if (ecmp->ecm_tx_cnt >= usbecm_tx_max) {
1254                 USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1255                     "usbecm_send_data: (%d) exceeds TX max queue length",
1256                     ecmp->ecm_tx_cnt);
1257                 mutex_exit(&ecmp->ecm_mutex);
1258 
1259                 return (USB_FAILURE);
1260         }
1261         mutex_exit(&ecmp->ecm_mutex);
1262 
1263         data_len = msgsize(data);
1264         if (data_len > ETHERMAX) {
1265                 mutex_enter(&ecmp->ecm_mutex);
1266                 ecmp->ecm_stat.es_macxmt_err++;
1267                 mutex_exit(&ecmp->ecm_mutex);
1268 
1269                 USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1270                     "usbecm_send_data: packet too long, %d", data_len);
1271 
1272                 return (USB_FAILURE);
1273         }
1274 
1275         if (data_len < ETHERMIN) {
1276                 mblk_t *tmp;
1277 
1278                 USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1279                     "usbecm_send_data: short packet, padding to ETHERMIN");
1280 
1281                 new_data_len = ETHERMIN;
1282                 if ((new_data = allocb(new_data_len, 0)) == NULL) {
1283                         USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1284                             "usbecm_send_data: fail to allocb");
1285 
1286                         return (USB_FAILURE);
1287                 }
1288                 bzero(new_data->b_wptr, new_data_len);
1289                 for (tmp = data; tmp != NULL; tmp = tmp->b_cont) {
1290                         bcopy(tmp->b_rptr, new_data->b_wptr, MBLKL(tmp));
1291                         new_data->b_wptr += MBLKL(tmp);
1292                 }
1293 
1294                 new_data->b_wptr = new_data->b_rptr + new_data_len;
1295         }
1296 
1297         br = usb_alloc_bulk_req(ecmp->ecm_dip, 0, USB_FLAGS_SLEEP);
1298         if (br == NULL) {
1299                 USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1300                     "usbecm_send_data: alloc req failed.");
1301 
1302                 return (USB_FAILURE);
1303         }
1304 
1305         /* initialize the bulk out request */
1306         if (new_data) {
1307                 br->bulk_data = msgpullup(new_data, -1); /* msg allocated! */
1308                 br->bulk_len = new_data_len;
1309         } else {
1310                 br->bulk_data = msgpullup(data, -1); /* msg allocated! */
1311                 br->bulk_len = data_len;
1312         }
1313 
1314         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1315             "usbecm_send_data: bulk_len = %d", br->bulk_len);
1316 
1317         br->bulk_timeout = USBECM_BULKOUT_TIMEOUT;
1318         br->bulk_cb = usbecm_bulkout_cb;
1319         br->bulk_exc_cb = usbecm_bulkout_cb;
1320         br->bulk_client_private = (usb_opaque_t)ecmp;
1321         br->bulk_attributes = USB_ATTRS_AUTOCLEARING;
1322 
1323         if (br->bulk_data != NULL) {
1324                 if (br->bulk_data->b_rptr[0] & 0x01) {
1325                         mutex_enter(&ecmp->ecm_mutex);
1326                         if (bcmp(br->bulk_data->b_rptr, usbecm_broadcast,
1327                             ETHERADDRL) != 0) {
1328                                 ecmp->ecm_stat.es_multixmt++;
1329                         } else {
1330                                 ecmp->ecm_stat.es_brdcstxmt++;
1331                         }
1332                         mutex_exit(&ecmp->ecm_mutex);
1333                 }
1334                 rval = usb_pipe_bulk_xfer(ecmp->ecm_bulkout_ph, br, 0);
1335         }
1336 
1337         if (rval != USB_SUCCESS) {
1338                 USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1339                     "usbecm_send_data: Send Data failed.");
1340 
1341                 /*
1342                  * br->bulk_data should be freed because we allocated
1343                  * it in this function.
1344                  */
1345                 usb_free_bulk_req(br);
1346 
1347         } else {
1348                 mutex_enter(&ecmp->ecm_mutex);
1349                 ecmp->ecm_tx_cnt++;
1350                 mutex_exit(&ecmp->ecm_mutex);
1351 
1352                 /*
1353                  * ECM V1.2, section 3.3.1, a short(including zero length)
1354                  * packet signifies end of frame. We should send a zero length
1355                  * packet to device if the total data lenght is multiple of
1356                  * bulkout endpoint's max packet size.
1357                  */
1358                 max_pkt_size = ecmp->ecm_bulk_out_ep->ep_descr.wMaxPacketSize;
1359                 if ((data_len % max_pkt_size) == 0) {
1360                         if ((rval = usbecm_send_zero_data(ecmp))
1361                             != USB_SUCCESS) {
1362                                 USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1363                                     "usbecm_send_data: fail to send padding");
1364                         }
1365                 }
1366         }
1367 
1368         if (new_data) {
1369                 freemsg(new_data);
1370         }
1371 
1372         USB_DPRINTF_L4(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1373             "usbecm_send_data: len(%d) data sent, rval=%d",
1374             new_data_len ? new_data_len : data_len, rval);
1375 
1376         return (rval);
1377 }
1378 
1379 static int
1380 usbecm_send_zero_data(usbecm_state_t *ecmp)
1381 {
1382         usb_bulk_req_t  *br;
1383         int             rval = USB_FAILURE;
1384 
1385         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1386             "usbecm_send_zero_data: entry");
1387 
1388         br = usb_alloc_bulk_req(ecmp->ecm_dip, 0, USB_FLAGS_SLEEP);
1389         if (br == NULL) {
1390                 USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1391                     "usbecm_send_data: alloc req failed.");
1392 
1393                 return (USB_FAILURE);
1394         }
1395 
1396         /* initialize the bulk out request */
1397         br->bulk_len = 0;
1398         br->bulk_timeout = USBECM_BULKOUT_TIMEOUT;
1399         br->bulk_cb = usbecm_bulkout_cb;
1400         br->bulk_exc_cb = usbecm_bulkout_cb;
1401         br->bulk_client_private = (usb_opaque_t)ecmp;
1402         br->bulk_attributes = USB_ATTRS_AUTOCLEARING;
1403 
1404         rval = usb_pipe_bulk_xfer(ecmp->ecm_bulkout_ph, br, 0);
1405 
1406         if (rval != USB_SUCCESS) {
1407                 USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1408                     "usbecm_send_zero_data: Send data failed, rval=%d",
1409                     rval);
1410 
1411                 /*
1412                  * br->bulk_data should be freed because we allocated
1413                  * it in this function.
1414                  */
1415                 usb_free_bulk_req(br);
1416 
1417         }
1418 
1419         USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1420             "usbecm_send_zero_data: end");
1421 
1422         return (rval);
1423 }
1424 
1425 /*
1426  * Loadable module configuration entry points
1427  */
1428 
1429 /*
1430  * _init module entry point.
1431  *
1432  * Called when the module is being loaded into memory.
1433  */
1434 int
1435 _init(void)
1436 {
1437         int err;
1438 
1439         err = ddi_soft_state_init(&usbecm_statep, sizeof (usbecm_state_t), 1);
1440 
1441         if (err != DDI_SUCCESS)
1442                 return (err);
1443 
1444         mac_init_ops(&usbecm_devops, "usbecm");
1445         err = mod_install(&usbecm_ml);
1446 
1447         if (err != DDI_SUCCESS) {
1448                 mac_fini_ops(&usbecm_devops);
1449                 ddi_soft_state_fini(&usbecm_statep);
1450         }
1451 
1452         return (err);
1453 }
1454 
1455 /*
1456  * _info module entry point.
1457  *
1458  * Called to obtain information about the module.
1459  */
1460 int
1461 _info(struct modinfo *modinfop)
1462 {
1463         return (mod_info(&usbecm_ml, modinfop));
1464 }
1465 
1466 /*
1467  * _fini module entry point.
1468  *
1469  * Called when the module is being unloaded.
1470  */
1471 int
1472 _fini(void)
1473 {
1474         int err;
1475 
1476         err = mod_remove(&usbecm_ml);
1477         if (err == DDI_SUCCESS) {
1478                 mac_fini_ops(&usbecm_devops);
1479                 ddi_soft_state_fini(&usbecm_statep);
1480         }
1481 
1482         return (err);
1483 }
1484 
1485 /*
1486  * usbecm_pipe_start_polling:
1487  *      start polling on the interrupt pipe
1488  */
1489 static void
1490 usbecm_pipe_start_polling(usbecm_state_t *ecmp)
1491 {
1492         usb_intr_req_t  *intr;
1493         int             rval;
1494 
1495         USB_DPRINTF_L4(PRINT_MASK_OPEN, ecmp->ecm_lh,
1496             "usbecm_pipe_start_polling: ");
1497 
1498         if (ecmp->ecm_intr_ph == NULL) {
1499 
1500                 return;
1501         }
1502 
1503         intr = usb_alloc_intr_req(ecmp->ecm_dip, 0, USB_FLAGS_SLEEP);
1504 
1505         /*
1506          * If it is in interrupt context, usb_alloc_intr_req will return NULL if
1507          * called with SLEEP flag.
1508          */
1509         if (!intr) {
1510                 USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
1511                     "usbecm_pipe_start_polling: alloc req failed.");
1512 
1513                 return;
1514         }
1515 
1516         /* initialize the interrupt request. */
1517         intr->intr_attributes = USB_ATTRS_SHORT_XFER_OK |
1518             USB_ATTRS_AUTOCLEARING;
1519         intr->intr_len = ecmp->ecm_intr_ep->ep_descr.wMaxPacketSize;
1520         intr->intr_client_private = (usb_opaque_t)ecmp;
1521         intr->intr_cb = usbecm_intr_cb;
1522         intr->intr_exc_cb = usbecm_intr_ex_cb;
1523 
1524         rval = usb_pipe_intr_xfer(ecmp->ecm_intr_ph, intr, USB_FLAGS_SLEEP);
1525 
1526         mutex_enter(&ecmp->ecm_mutex);
1527         if (rval == USB_SUCCESS) {
1528                 ecmp->ecm_intr_state = USBECM_PIPE_BUSY;
1529         } else {
1530                 usb_free_intr_req(intr);
1531                 ecmp->ecm_intr_state = USBECM_PIPE_IDLE;
1532                 USB_DPRINTF_L3(PRINT_MASK_OPEN, ecmp->ecm_lh,
1533                     "usbecm_pipe_start_polling: failed (%d)", rval);
1534         }
1535         mutex_exit(&ecmp->ecm_mutex);
1536 
1537         USB_DPRINTF_L3(PRINT_MASK_OPEN, ecmp->ecm_lh,
1538             "usbecm_pipe_start_polling: end, rval=%d", rval);
1539 }
1540 
1541 
1542 /*
1543  * usbsecm_intr_cb:
1544  *      interrupt pipe normal callback
1545  */
1546 /*ARGSUSED*/
1547 static void
1548 usbecm_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
1549 {
1550         usbecm_state_t *ecmp = (usbecm_state_t *)req->intr_client_private;
1551         mblk_t          *data = req->intr_data;
1552         int             data_len;
1553 
1554         data_len = (data) ? MBLKL(data) : 0;
1555 
1556         DTRACE_PROBE2(usbecm_intr__cb, (usb_intr_req_t *), req, int, data_len);
1557 
1558         /* check data length */
1559         if (data_len < 8) {
1560                 USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1561                     "usbsecm_intr_cb: %d packet too short", data_len);
1562                 usb_free_intr_req(req);
1563 
1564                 return;
1565         }
1566         req->intr_data = NULL;
1567         usb_free_intr_req(req);
1568 
1569         mutex_enter(&ecmp->ecm_mutex);
1570         /* parse interrupt data -- notifications */
1571         usbecm_parse_intr_data(ecmp, data);
1572         mutex_exit(&ecmp->ecm_mutex);
1573 }
1574 
1575 
1576 /*
1577  * usbsecm_intr_ex_cb:
1578  *      interrupt pipe exception callback
1579  */
1580 /*ARGSUSED*/
1581 static void
1582 usbecm_intr_ex_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
1583 {
1584         usbecm_state_t *ecmp = (usbecm_state_t *)req->intr_client_private;
1585         usb_cr_t        cr = req->intr_completion_reason;
1586 
1587         DTRACE_PROBE2(usbecm_intr_ex__cb, int, ecmp->ecm_dev_state,
1588             (usb_cr_t), cr);
1589 
1590         usb_free_intr_req(req);
1591 
1592         /*
1593          * If completion reason isn't USB_CR_PIPE_CLOSING and
1594          * USB_CR_STOPPED_POLLING, restart polling.
1595          */
1596         if ((cr != USB_CR_PIPE_CLOSING) && (cr != USB_CR_STOPPED_POLLING)) {
1597                 mutex_enter(&ecmp->ecm_mutex);
1598 
1599                 if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
1600 
1601                         USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1602                             "usbsecm_intr_ex_cb: state = %d",
1603                             ecmp->ecm_dev_state);
1604 
1605                         mutex_exit(&ecmp->ecm_mutex);
1606 
1607                         return;
1608                 }
1609                 mutex_exit(&ecmp->ecm_mutex);
1610 
1611                 usbecm_pipe_start_polling(ecmp);
1612         }
1613 }
1614 
1615 
1616 /*
1617  * usbsecm_parse_intr_data:
1618  *      Parse data received from interrupt callback
1619  */
1620 static void
1621 usbecm_parse_intr_data(usbecm_state_t *ecmp, mblk_t *data)
1622 {
1623         uint8_t         bmRequestType;
1624         uint8_t         bNotification;
1625         uint16_t        wValue;
1626         uint16_t        wLength;
1627         int             linkstate;
1628 
1629         bmRequestType = data->b_rptr[0];
1630         bNotification = data->b_rptr[1];
1631         /*
1632          * If Notification type is NETWORK_CONNECTION, wValue is 0 or 1,
1633          * mLength is 0. If Notification type is SERIAL_TYPE, mValue is 0,
1634          * mLength is 2. So we directly get the value from the byte.
1635          */
1636         wValue = data->b_rptr[2];
1637         wLength = data->b_rptr[6];
1638 
1639         if (ecmp->ecm_compatibility) {
1640                 if (bmRequestType != USB_CDC_NOTIFICATION_REQUEST_TYPE) {
1641                         USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1642                             "usbsecm_parse_intr_data: unknown request "
1643                             "type - 0x%x", bmRequestType);
1644 
1645                         freemsg(data);
1646 
1647                         return;
1648                 }
1649         } else {
1650                 /* non-compatible device specific parsing */
1651                 if (ECM_DS_OP_VALID(ecm_ds_intr_cb)) {
1652                         if (ecmp->ecm_ds_ops->ecm_ds_intr_cb(ecmp, data)
1653                             != USB_SUCCESS) {
1654                                 USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1655                                     "usbsecm_parse_intr_data: unknown request"
1656                                     "type - 0x%x", bmRequestType);
1657                         }
1658                 }
1659                 freemsg(data);
1660 
1661                 return;
1662         }
1663 
1664         /*
1665          * Check the return value of compatible devices
1666          */
1667         switch (bNotification) {
1668         case USB_CDC_NOTIFICATION_NETWORK_CONNECTION:
1669                 USB_DPRINTF_L3(PRINT_MASK_CB, ecmp->ecm_lh,
1670                     "usbsecm_parse_intr_data: %s network!",
1671                     wValue ? "connected to" :"disconnected from");
1672 
1673                 linkstate = wValue ? LINK_STATE_UP:LINK_STATE_DOWN;
1674                 if (ecmp->ecm_stat.es_linkstate == linkstate) {
1675                 /* no changes to previous state */
1676                         break;
1677                 }
1678 
1679                 ecmp->ecm_stat.es_linkstate = linkstate;
1680                 mutex_exit(&ecmp->ecm_mutex);
1681                 mac_link_update(ecmp->ecm_mh, linkstate);
1682                 mutex_enter(&ecmp->ecm_mutex);
1683 
1684                 break;
1685         case USB_CDC_NOTIFICATION_RESPONSE_AVAILABLE:
1686                 USB_DPRINTF_L3(PRINT_MASK_CB, ecmp->ecm_lh,
1687                     "usbsecm_parse_intr_data: A response is a available.");
1688 
1689                 break;
1690         case USB_CDC_NOTIFICATION_SPEED_CHANGE:
1691                 USB_DPRINTF_L3(PRINT_MASK_CB, ecmp->ecm_lh,
1692                     "usbsecm_parse_intr_data: speed change");
1693 
1694                 /* check the parameter's length. */
1695                 if (wLength != 8) {
1696                         USB_DPRINTF_L3(PRINT_MASK_CB, ecmp->ecm_lh,
1697                             "usbsecm_parse_intr_data: error data length.");
1698                 } else {
1699                         uint32_t        us_rate, ds_rate;
1700                         uint8_t         *sp;
1701 
1702                         sp = &data->b_rptr[8];
1703                         LE_TO_UINT32(sp, us_rate);
1704                         sp = &data->b_rptr[12];
1705                         LE_TO_UINT32(sp, ds_rate);
1706                         ecmp->ecm_stat.es_upspeed = us_rate;
1707                         ecmp->ecm_stat.es_downspeed = ds_rate;
1708                 }
1709 
1710                 break;
1711         default:
1712                 USB_DPRINTF_L3(PRINT_MASK_CB, ecmp->ecm_lh,
1713                     "usbsecm_parse_intr_data: unknown notification - 0x%x!",
1714                     bNotification);
1715 
1716                 break;
1717         }
1718 
1719         freemsg(data);
1720 }
1721 
1722 /*
1723  * usbecm_restore_device_state:
1724  *      restore device state after CPR resume or reconnect
1725  */
1726 static int
1727 usbecm_restore_device_state(usbecm_state_t *ecmp)
1728 {
1729         int     state;
1730 
1731         USB_DPRINTF_L4(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1732             "usbecm_restore_device_state: ");
1733 
1734         mutex_enter(&ecmp->ecm_mutex);
1735         state = ecmp->ecm_dev_state;
1736         mutex_exit(&ecmp->ecm_mutex);
1737 
1738         /* Check device status */
1739         if ((state != USB_DEV_DISCONNECTED) && (state != USB_DEV_SUSPENDED)) {
1740 
1741                 return (state);
1742         }
1743 
1744         /* Check if we are talking to the same device */
1745         if (usb_check_same_device(ecmp->ecm_dip, ecmp->ecm_lh, USB_LOG_L0,
1746             -1, USB_CHK_ALL, NULL) != USB_SUCCESS) {
1747                 mutex_enter(&ecmp->ecm_mutex);
1748                 state = ecmp->ecm_dev_state = USB_DEV_DISCONNECTED;
1749                 mutex_exit(&ecmp->ecm_mutex);
1750 
1751                 return (state);
1752         }
1753 
1754         if (state == USB_DEV_DISCONNECTED) {
1755                 USB_DPRINTF_L1(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1756                     "usbecm_restore_device_state: Device has been reconnected "
1757                     "but data may have been lost");
1758         }
1759 
1760         /* if MAC was started, restarted it */
1761         mutex_enter(&ecmp->ecm_mutex);
1762         if (ecmp->ecm_mac_state == USBECM_MAC_STARTED) {
1763                 USB_DPRINTF_L3(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1764                     "usbecm_restore_device_state: MAC was started");
1765 
1766                 mutex_exit(&ecmp->ecm_mutex);
1767                 /* Do the same operation as usbecm_m_start() does */
1768                 if (usbecm_open_pipes(ecmp) != USB_SUCCESS) {
1769 
1770                         return (state);
1771                 }
1772 
1773                 mutex_enter(&ecmp->ecm_mutex);
1774                 if (usbecm_rx_start(ecmp) != USB_SUCCESS) {
1775                         mutex_exit(&ecmp->ecm_mutex);
1776 
1777                         return (state);
1778                 }
1779         }
1780         mutex_exit(&ecmp->ecm_mutex);
1781 
1782         /*
1783          * init device state
1784          */
1785         mutex_enter(&ecmp->ecm_mutex);
1786         state = ecmp->ecm_dev_state = USB_DEV_ONLINE;
1787         mutex_exit(&ecmp->ecm_mutex);
1788 
1789         return (state);
1790 }
1791 
1792 /*
1793  * usbecm_reconnect_event_cb:
1794  *     called upon when the device is hotplugged back
1795  */
1796 /*ARGSUSED*/
1797 static int
1798 usbecm_reconnect_event_cb(dev_info_t *dip)
1799 {
1800         usbecm_state_t  *ecmp =
1801             (usbecm_state_t *)ddi_get_soft_state(usbecm_statep,
1802             ddi_get_instance(dip));
1803 
1804         ASSERT(ecmp != NULL);
1805 
1806         USB_DPRINTF_L4(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1807             "usbecm_reconnect_event_cb: entry");
1808 
1809         (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
1810 
1811         mutex_enter(&ecmp->ecm_mutex);
1812         ASSERT(ecmp->ecm_dev_state == USB_DEV_DISCONNECTED);
1813 
1814         mutex_exit(&ecmp->ecm_mutex);
1815 
1816         if (usbecm_restore_device_state(ecmp) != USB_DEV_ONLINE) {
1817                 usb_release_access(ecmp->ecm_ser_acc);
1818 
1819                 return (USB_FAILURE);
1820         }
1821 
1822         usb_release_access(ecmp->ecm_ser_acc);
1823 
1824         return (USB_SUCCESS);
1825 }
1826 
1827 
1828 /*
1829  * usbecm_disconnect_event_cb:
1830  *      callback for disconnect events
1831  */
1832 /*ARGSUSED*/
1833 static int
1834 usbecm_disconnect_event_cb(dev_info_t *dip)
1835 {
1836         usbecm_state_t  *ecmp = (usbecm_state_t *)ddi_get_soft_state(
1837             usbecm_statep, ddi_get_instance(dip));
1838 
1839         USB_DPRINTF_L4(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1840             "usbecm_disconnect_event_cb: entry");
1841 
1842         (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
1843 
1844         mutex_enter(&ecmp->ecm_mutex);
1845         ecmp->ecm_dev_state = USB_DEV_DISCONNECTED;
1846         mutex_exit(&ecmp->ecm_mutex);
1847 
1848         usbecm_close_pipes(ecmp);
1849 
1850         usb_release_access(ecmp->ecm_ser_acc);
1851 
1852         USB_DPRINTF_L4(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1853             "usbecm_disconnect_event_cb: End");
1854 
1855         return (USB_SUCCESS);
1856 }
1857 
1858 /*
1859  * power management
1860  * ----------------
1861  *
1862  * usbecm_create_pm_components:
1863  *      create PM components
1864  */
1865 static int
1866 usbecm_create_pm_components(usbecm_state_t *ecmp)
1867 {
1868         dev_info_t      *dip = ecmp->ecm_dip;
1869         usbecm_pm_t     *pm;
1870         uint_t          pwr_states;
1871 
1872         USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
1873             "usbecm_create_pm_components: entry");
1874 
1875         if (usb_create_pm_components(dip, &pwr_states) != USB_SUCCESS) {
1876                 USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
1877                     "usbecm_create_pm_components: failed");
1878 
1879                 /* don't fail the attach process */
1880                 return (USB_SUCCESS);
1881         }
1882 
1883         pm = ecmp->ecm_pm =
1884             (usbecm_pm_t *)kmem_zalloc(sizeof (usbecm_pm_t), KM_SLEEP);
1885 
1886         pm->pm_pwr_states = (uint8_t)pwr_states;
1887         pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
1888         pm->pm_wakeup_enabled = (usb_handle_remote_wakeup(dip,
1889             USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS);
1890 
1891         (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1892 
1893         return (USB_SUCCESS);
1894 }
1895 
1896 /*
1897  * usbecm_cleanup:
1898  *      Release resources of current device during detach.
1899  */
1900 static void
1901 usbecm_cleanup(usbecm_state_t *ecmp)
1902 {
1903         USB_DPRINTF_L4(PRINT_MASK_CLOSE, ecmp->ecm_lh,
1904             "usbecm_cleanup: ");
1905 
1906         if (ecmp == NULL) {
1907 
1908                 return;
1909         }
1910 
1911         usbecm_close_pipes(ecmp);
1912 
1913         /* unregister callback function */
1914         if (ecmp->ecm_init_flags & USBECM_INIT_EVENTS) {
1915                 USB_DPRINTF_L4(PRINT_MASK_CLOSE, ecmp->ecm_lh,
1916                     "usbecm_cleanup: unregister events");
1917 
1918                 usb_unregister_event_cbs(ecmp->ecm_dip, &usbecm_events);
1919         }
1920 
1921         /* destroy power management components */
1922         if (ecmp->ecm_pm != NULL) {
1923                 USB_DPRINTF_L4(PRINT_MASK_CLOSE, ecmp->ecm_lh,
1924                     "usbecm_cleanup: destroy pm");
1925                 usbecm_destroy_pm_components(ecmp);
1926         }
1927 
1928         /* free description of device tree. */
1929         if (ecmp->ecm_def_ph != NULL) {
1930                 mutex_destroy(&ecmp->ecm_mutex);
1931 
1932                 usb_free_descr_tree(ecmp->ecm_dip, ecmp->ecm_dev_data);
1933                 ecmp->ecm_def_ph = NULL;
1934         }
1935 
1936         if (ecmp->ecm_lh != NULL) {
1937                 usb_free_log_hdl(ecmp->ecm_lh);
1938                 ecmp->ecm_lh = NULL;
1939         }
1940 
1941         /* detach client device */
1942         if (ecmp->ecm_dev_data != NULL) {
1943                 usb_client_detach(ecmp->ecm_dip, ecmp->ecm_dev_data);
1944         }
1945 
1946         if (ecmp->ecm_init_flags & USBECM_INIT_MAC) {
1947                 (void) usbecm_mac_fini(ecmp);
1948         }
1949 
1950         if (ecmp->ecm_init_flags & USBECM_INIT_SER) {
1951                 usb_fini_serialization(ecmp->ecm_ser_acc);
1952         }
1953 
1954         ddi_prop_remove_all(ecmp->ecm_dip);
1955         ddi_remove_minor_node(ecmp->ecm_dip, NULL);
1956 }
1957 
1958 /*
1959  * usbecm_destroy_pm_components:
1960  *      destroy PM components
1961  */
1962 static void
1963 usbecm_destroy_pm_components(usbecm_state_t *ecmp)
1964 {
1965         usbecm_pm_t     *pm = ecmp->ecm_pm;
1966         dev_info_t      *dip = ecmp->ecm_dip;
1967         int             rval;
1968 
1969         USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
1970             "usbecm_destroy_pm_components: ");
1971 
1972         if (ecmp->ecm_dev_state != USB_DEV_DISCONNECTED) {
1973                 if (pm->pm_wakeup_enabled) {
1974                         rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1975                         if (rval != DDI_SUCCESS) {
1976                                 USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
1977                                     "usbecm_destroy_pm_components: "
1978                                     "raising power failed (%d)", rval);
1979                         }
1980 
1981                         rval = usb_handle_remote_wakeup(dip,
1982                             USB_REMOTE_WAKEUP_DISABLE);
1983                         if (rval != USB_SUCCESS) {
1984                                 USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
1985                                     "usbecm_destroy_pm_components: "
1986                                     "disable remote wakeup failed (%d)", rval);
1987                         }
1988                 }
1989 
1990                 (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
1991         }
1992         kmem_free((caddr_t)pm, sizeof (usbecm_pm_t));
1993         ecmp->ecm_pm = NULL;
1994 }
1995 
1996 /*
1997  * usbecm_pm_set_busy:
1998  *      mark device busy and raise power
1999  */
2000 static void
2001 usbecm_pm_set_busy(usbecm_state_t *ecmp)
2002 {
2003         usbecm_pm_t     *pm = ecmp->ecm_pm;
2004         dev_info_t      *dip = ecmp->ecm_dip;
2005         int             rval;
2006 
2007         USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2008             "usbecm_pm_set_busy: pm = 0x%p", (void *)pm);
2009 
2010         if (pm == NULL) {
2011 
2012                 return;
2013         }
2014 
2015         mutex_enter(&ecmp->ecm_mutex);
2016         /* if already marked busy, just increment the counter */
2017         if (pm->pm_busy_cnt++ > 0) {
2018                 mutex_exit(&ecmp->ecm_mutex);
2019 
2020                 return;
2021         }
2022 
2023         (void) pm_busy_component(dip, 0);
2024 
2025         if (pm->pm_cur_power == USB_DEV_OS_FULL_PWR) {
2026                 mutex_exit(&ecmp->ecm_mutex);
2027 
2028                 return;
2029         }
2030 
2031         /* need to raise power  */
2032         pm->pm_raise_power = B_TRUE;
2033         mutex_exit(&ecmp->ecm_mutex);
2034 
2035         rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
2036         if (rval != DDI_SUCCESS) {
2037                 USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2038                     "usbecm_pm_set_busy: raising power failed");
2039         }
2040 
2041         mutex_enter(&ecmp->ecm_mutex);
2042         pm->pm_raise_power = B_FALSE;
2043         mutex_exit(&ecmp->ecm_mutex);
2044 }
2045 
2046 
2047 /*
2048  * usbecm_pm_set_idle:
2049  *      mark device idle
2050  */
2051 static void
2052 usbecm_pm_set_idle(usbecm_state_t *ecmp)
2053 {
2054         usbecm_pm_t     *pm = ecmp->ecm_pm;
2055         dev_info_t      *dip = ecmp->ecm_dip;
2056 
2057         USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2058             "usbecm_pm_set_idle: ");
2059 
2060         if (pm == NULL) {
2061 
2062                 return;
2063         }
2064 
2065         mutex_enter(&ecmp->ecm_mutex);
2066         if (--pm->pm_busy_cnt > 0) {
2067                 mutex_exit(&ecmp->ecm_mutex);
2068 
2069                 return;
2070         }
2071 
2072         if (pm) {
2073                 (void) pm_idle_component(dip, 0);
2074         }
2075         mutex_exit(&ecmp->ecm_mutex);
2076 }
2077 
2078 
2079 /*
2080  * usbecm_pwrlvl0:
2081  *      Functions to handle power transition for OS levels 0 -> 3
2082  *      The same level as OS state, different from USB state
2083  */
2084 static int
2085 usbecm_pwrlvl0(usbecm_state_t *ecmp)
2086 {
2087         int             rval;
2088 
2089         ASSERT(mutex_owned(&ecmp->ecm_mutex));
2090 
2091         USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2092             "usbecm_pwrlvl0: ");
2093 
2094         switch (ecmp->ecm_dev_state) {
2095         case USB_DEV_ONLINE:
2096                 /* issue USB D3 command to the device */
2097                 rval = usb_set_device_pwrlvl3(ecmp->ecm_dip);
2098                 ASSERT(rval == USB_SUCCESS);
2099                 if ((ecmp->ecm_intr_ph != NULL) &&
2100                     (ecmp->ecm_intr_state == USBECM_PIPE_BUSY)) {
2101                         mutex_exit(&ecmp->ecm_mutex);
2102                         usb_pipe_stop_intr_polling(ecmp->ecm_intr_ph,
2103                             USB_FLAGS_SLEEP);
2104                         mutex_enter(&ecmp->ecm_mutex);
2105 
2106                         ecmp->ecm_intr_state = USBECM_PIPE_IDLE;
2107                 }
2108                 ecmp->ecm_dev_state = USB_DEV_PWRED_DOWN;
2109                 ecmp->ecm_pm->pm_cur_power = USB_DEV_OS_PWR_OFF;
2110 
2111                 /* FALLTHRU */
2112         case USB_DEV_DISCONNECTED:
2113         case USB_DEV_SUSPENDED:
2114                 /* allow a disconnect/cpr'ed device to go to lower power */
2115 
2116                 return (USB_SUCCESS);
2117         case USB_DEV_PWRED_DOWN:
2118         default:
2119                 USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2120                     "usbecm_pwrlvl0: illegal device state");
2121 
2122                 return (USB_FAILURE);
2123         }
2124 }
2125 
2126 
2127 /*
2128  * usbecm_pwrlvl1:
2129  *      Functions to handle power transition for OS levels 1 -> 2
2130  */
2131 static int
2132 usbecm_pwrlvl1(usbecm_state_t *ecmp)
2133 {
2134         /* issue USB D2 command to the device */
2135         (void) usb_set_device_pwrlvl2(ecmp->ecm_dip);
2136 
2137         return (USB_FAILURE);
2138 }
2139 
2140 
2141 /*
2142  * usbecm_pwrlvl2:
2143  *      Functions to handle power transition for OS levels 2 -> 1
2144  */
2145 static int
2146 usbecm_pwrlvl2(usbecm_state_t *ecmp)
2147 {
2148         /* issue USB D1 command to the device */
2149         (void) usb_set_device_pwrlvl1(ecmp->ecm_dip);
2150 
2151         return (USB_FAILURE);
2152 }
2153 
2154 
2155 /*
2156  * usbecm_pwrlvl3:
2157  *      Functions to handle power transition for OS levels 3 -> 0
2158  *      The same level as OS state, different from USB state
2159  */
2160 static int
2161 usbecm_pwrlvl3(usbecm_state_t *ecmp)
2162 {
2163         int             rval;
2164 
2165         USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2166             "usbecm_pwrlvl3: ");
2167 
2168         ASSERT(mutex_owned(&ecmp->ecm_mutex));
2169 
2170         switch (ecmp->ecm_dev_state) {
2171         case USB_DEV_PWRED_DOWN:
2172                 /* Issue USB D0 command to the device here */
2173                 rval = usb_set_device_pwrlvl0(ecmp->ecm_dip);
2174                 ASSERT(rval == USB_SUCCESS);
2175 
2176                 if (ecmp->ecm_intr_ph != NULL &&
2177                     ecmp->ecm_intr_state == USBECM_PIPE_IDLE) {
2178                         mutex_exit(&ecmp->ecm_mutex);
2179                         usbecm_pipe_start_polling(ecmp);
2180                         mutex_enter(&ecmp->ecm_mutex);
2181                 }
2182 
2183                 ecmp->ecm_dev_state = USB_DEV_ONLINE;
2184                 ecmp->ecm_pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
2185 
2186                 /* FALLTHRU */
2187         case USB_DEV_ONLINE:
2188                 /* we are already in full power */
2189 
2190                 /* FALLTHRU */
2191         case USB_DEV_DISCONNECTED:
2192         case USB_DEV_SUSPENDED:
2193 
2194                 return (USB_SUCCESS);
2195         default:
2196                 USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2197                     "usbecm_pwrlvl3: illegal device state");
2198 
2199                 return (USB_FAILURE);
2200         }
2201 }
2202 
2203 /*ARGSUSED*/
2204 static int
2205 usbecm_power(dev_info_t *dip, int comp, int level)
2206 {
2207         usbecm_state_t  *ecmp;
2208         usbecm_pm_t     *pm;
2209         int             rval = USB_SUCCESS;
2210 
2211         ecmp = ddi_get_soft_state(usbecm_statep, ddi_get_instance(dip));
2212         pm = ecmp->ecm_pm;
2213 
2214         USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2215             "usbecm_power: entry");
2216 
2217         /* check if pm is NULL */
2218         if (pm == NULL) {
2219                 USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2220                     "usbecm_power: pm is NULL.");
2221 
2222                 return (USB_FAILURE);
2223         }
2224 
2225         mutex_enter(&ecmp->ecm_mutex);
2226         /*
2227          * check if we are transitioning to a legal power level
2228          */
2229         if (USB_DEV_PWRSTATE_OK(pm->pm_pwr_states, level)) {
2230                 USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2231                     "usbecm_power: "
2232                     "illegal power level %d, pwr_states=%x",
2233                     level, pm->pm_pwr_states);
2234                 mutex_exit(&ecmp->ecm_mutex);
2235 
2236                 return (USB_FAILURE);
2237         }
2238 
2239         /*
2240          * if we are about to raise power and asked to lower power, fail
2241          */
2242         if (pm->pm_raise_power && (level < (int)pm->pm_cur_power)) {
2243                 USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2244                     "usbecm_power: wrong condition.");
2245                 mutex_exit(&ecmp->ecm_mutex);
2246 
2247                 return (USB_FAILURE);
2248         }
2249 
2250         /*
2251          * Set the power status of device by request level.
2252          */
2253         switch (level) {
2254         case USB_DEV_OS_PWR_OFF:
2255                 rval = usbecm_pwrlvl0(ecmp);
2256 
2257                 break;
2258         case USB_DEV_OS_PWR_1:
2259                 rval = usbecm_pwrlvl1(ecmp);
2260 
2261                 break;
2262         case USB_DEV_OS_PWR_2:
2263                 rval = usbecm_pwrlvl2(ecmp);
2264 
2265                 break;
2266         case USB_DEV_OS_FULL_PWR:
2267                 rval = usbecm_pwrlvl3(ecmp);
2268 
2269                 break;
2270         }
2271 
2272         mutex_exit(&ecmp->ecm_mutex);
2273 
2274         return (rval);
2275 }
2276 
2277 /*
2278  * Register with the MAC layer.
2279  */
2280 static int
2281 usbecm_mac_init(usbecm_state_t *ecmp)
2282 {
2283         mac_register_t *macp;
2284         int err;
2285 
2286         /*
2287          * Initialize mac structure
2288          */
2289         macp = mac_alloc(MAC_VERSION);
2290         if (macp == NULL) {
2291                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2292                     "failed to allocate MAC structure");
2293 
2294                 return (USB_FAILURE);
2295         }
2296 
2297         /*
2298          * Initialize pointer to device specific functions
2299          */
2300         macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
2301         macp->m_driver = ecmp;
2302         macp->m_dip = ecmp->ecm_dip;
2303 
2304         macp->m_src_addr = ecmp->ecm_srcaddr;
2305         macp->m_callbacks = &usbecm_m_callbacks;
2306         macp->m_min_sdu = 0;
2307         macp->m_max_sdu = ETHERMTU;
2308 
2309         /*
2310          * Register the macp to mac
2311          */
2312         err = mac_register(macp, &ecmp->ecm_mh);
2313         mac_free(macp);
2314 
2315         if (err != DDI_SUCCESS) {
2316                 USB_DPRINTF_L1(PRINT_MASK_ATTA, ecmp->ecm_lh,
2317                     "failed to register MAC structure");
2318 
2319                 return (USB_FAILURE);
2320         }
2321 
2322         mac_link_update(ecmp->ecm_mh, LINK_STATE_DOWN);
2323         ecmp->ecm_stat.es_linkstate = LINK_STATE_DOWN;
2324         ecmp->ecm_tx_cnt = 0;
2325 
2326         return (USB_SUCCESS);
2327 }
2328 
2329 static int
2330 usbecm_mac_fini(usbecm_state_t *ecmp)
2331 {
2332         int rval = DDI_SUCCESS;
2333 
2334         if ((ecmp->ecm_init_flags & USBECM_INIT_MAC) == 0) {
2335                 return (DDI_SUCCESS);
2336         }
2337 
2338         ecmp->ecm_init_flags &= ~USBECM_INIT_MAC;
2339         if ((rval = mac_disable(ecmp->ecm_mh)) != 0) {
2340                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2341                     "failed to disable MAC");
2342 
2343                 return (rval);
2344         }
2345 
2346         (void) mac_unregister(ecmp->ecm_mh);
2347 
2348         return (rval);
2349 }
2350 
2351 static int
2352 usbecm_resume(usbecm_state_t *ecmp)
2353 {
2354         int             current_state;
2355         int             ret;
2356 
2357         USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2358             "usbecm_resume: ");
2359 
2360         mutex_enter(&ecmp->ecm_mutex);
2361         current_state = ecmp->ecm_dev_state;
2362         mutex_exit(&ecmp->ecm_mutex);
2363 
2364         /* restore the status of device */
2365         if (current_state != USB_DEV_ONLINE) {
2366                 ret = usbecm_restore_device_state(ecmp);
2367         } else {
2368                 ret = USB_DEV_ONLINE;
2369         }
2370 
2371         return (ret);
2372 }
2373 
2374 static int
2375 usbecm_suspend(usbecm_state_t *ecmp)
2376 {
2377         (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
2378 
2379         mutex_enter(&ecmp->ecm_mutex);
2380         ecmp->ecm_dev_state = USB_DEV_SUSPENDED;
2381         mutex_exit(&ecmp->ecm_mutex);
2382 
2383         usbecm_close_pipes(ecmp);
2384 
2385         usb_release_access(ecmp->ecm_ser_acc);
2386 
2387         return (0);
2388 }
2389 
2390 /*
2391  * Translate MAC address from string to 6 bytes array int value
2392  * Can't use ether_aton() since it requires format of x:x:x:x:x:x
2393  */
2394 void
2395 label_to_mac(char *hex, unsigned char *mac)
2396 {
2397         int i;
2398         char c;
2399 
2400         /* can only count 6 bytes! */
2401         for (i = 0; i < 6; i++) {
2402                 /* upper 4 bits */
2403                 if (!isdigit(hex[2*i])) {
2404                         c = (toupper(hex[2 * i]) - 'A' + 10);
2405                 } else {
2406                         c = (hex[2 * i] - '0');
2407                 }
2408                 mac[i] = c * 16;
2409 
2410                 /* lower 4 bits */
2411                 if (!isdigit(hex[2*i + 1])) {
2412                         c = (toupper(hex[2 * i + 1]) - 'A' + 10);
2413                 } else {
2414                         c = hex[2 * i + 1] - '0';
2415                 }
2416                 mac[i] += c;
2417         }
2418 }
2419 
2420 /*
2421  * usbecm_get_descriptors:
2422  *      parse functional descriptors of ecm compatible device
2423  */
2424 static int
2425 usbecm_get_descriptors(usbecm_state_t *ecmp)
2426 {
2427         int                     i;
2428         usb_cfg_data_t          *cfg;
2429         usb_alt_if_data_t       *altif;
2430         usb_cvs_data_t          *cvs;
2431         int16_t                 master_if = -1, slave_if = -1;
2432         usb_cdc_ecm_descr_t     ecm_desc;
2433         usb_ep_data_t           *ep_data;
2434         usb_dev_descr_t         *usb_dev_desc;
2435 
2436         USB_DPRINTF_L4(PRINT_MASK_ATTA, ecmp->ecm_lh,
2437             "usbecm_get_descriptors: ");
2438 
2439         usb_dev_desc = ecmp->ecm_dev_data->dev_descr;
2440 
2441         /*
2442          * Special treatment of Sun's SP Ethernet device.
2443          */
2444         if ((usb_dev_desc->idVendor == SUN_SP_VENDOR_ID) &&
2445             (usb_dev_desc->idProduct == SUN_SP_PRODUCT_ID)) {
2446                 if (usb_set_cfg(ecmp->ecm_dip, ecmp->ecm_cfg_index,
2447                     USB_FLAGS_SLEEP, NULL, NULL) != USB_SUCCESS) {
2448                         USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2449                             "usbecm_get_descriptors: fail to set cfg ");
2450                 } else {
2451                         usb_free_dev_data(ecmp->ecm_dip, ecmp->ecm_dev_data);
2452                         if (usb_get_dev_data(ecmp->ecm_dip, &ecmp->ecm_dev_data,
2453                             USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) {
2454                                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2455                                     "usbecm_get_descriptors: fail to get"
2456                                     " dev_data");
2457 
2458                                 return (USB_FAILURE);
2459                         }
2460                 }
2461         }
2462 
2463         cfg = ecmp->ecm_dev_data->dev_curr_cfg;
2464 
2465         /* set default control and data interface */
2466         ecmp->ecm_ctrl_if_no = ecmp->ecm_data_if_no = 0;
2467 
2468         /* get current interfaces */
2469         ecmp->ecm_ctrl_if_no = ecmp->ecm_dev_data->dev_curr_if;
2470         if (cfg->cfg_if[ecmp->ecm_ctrl_if_no].if_n_alt == 0) {
2471                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2472                     "usbecm_get_descriptors: elements in if_alt is %d",
2473                     cfg->cfg_if[ecmp->ecm_ctrl_if_no].if_n_alt);
2474 
2475                 return (USB_FAILURE);
2476         }
2477 
2478         altif = &cfg->cfg_if[ecmp->ecm_ctrl_if_no].if_alt[0];
2479 
2480         /*
2481          * Based on CDC specification, ECM devices usually include the
2482          * following function descriptors: Header, Union and ECM
2483          * Contry Selection function descriptors. This loop search tree data
2484          * structure for each ecm class descriptor.
2485          */
2486         for (i = 0; i < altif->altif_n_cvs; i++) {
2487                 cvs = &altif->altif_cvs[i];
2488 
2489                 if ((cvs->cvs_buf == NULL) ||
2490                     (cvs->cvs_buf[1] != USB_CDC_CS_INTERFACE)) {
2491                         continue;
2492                 }
2493 
2494                 switch (cvs->cvs_buf[2]) {
2495                 case USB_CDC_DESCR_TYPE_HEADER:
2496                         /*
2497                          * parse header functional descriptor
2498                          * Just to check integrity.
2499                          */
2500                         if (cvs->cvs_buf_len != 5) {
2501                                 return (USB_FAILURE);
2502                         }
2503                         break;
2504                 case USB_CDC_DESCR_TYPE_ETHERNET:
2505                         /* parse ECM functional descriptor */
2506                         if (cvs->cvs_buf_len >= USB_CDC_ECM_LEN) {
2507                                 char buf[USB_MAXSTRINGLEN];
2508 
2509                                 if (usb_parse_data("4cl2sc", cvs->cvs_buf,
2510                                     cvs->cvs_buf_len, (void *)&ecm_desc,
2511                                     (size_t)USB_CDC_ECM_LEN) <
2512                                     USB_CDC_ECM_LEN) {
2513 
2514                                         return (USB_FAILURE);
2515                                 }
2516 
2517                                 /* get the MAC address */
2518                                 if (usb_get_string_descr(ecmp->ecm_dip,
2519                                     USB_LANG_ID, ecm_desc.iMACAddress, buf,
2520                                     USB_MAXSTRINGLEN) != USB_SUCCESS) {
2521 
2522                                         return (USB_FAILURE);
2523                                 }
2524 
2525                                 USB_DPRINTF_L3(PRINT_MASK_ATTA, ecmp->ecm_lh,
2526                                     "usbecm_get_descriptors: macaddr=%s ",
2527                                     buf);
2528 
2529                                 /* expects 12 characters */
2530                                 if (strlen(buf) < 12) {
2531                                         return (USB_FAILURE);
2532                                 }
2533                                 label_to_mac(buf, ecmp->ecm_srcaddr);
2534 
2535                                 bcopy(&ecm_desc, &ecmp->ecm_desc,
2536                                     USB_CDC_ECM_LEN);
2537                         }
2538                         break;
2539                 case USB_CDC_DESCR_TYPE_UNION:
2540                         /* parse Union functional descriptor. */
2541                         if (cvs->cvs_buf_len >= 5) {
2542                                 master_if = cvs->cvs_buf[3];
2543                                 slave_if = cvs->cvs_buf[4];
2544                         }
2545                         break;
2546                 default:
2547                         break;
2548                 }
2549         }
2550 
2551         /* For usb ecm devices, it must satisfy the following options. */
2552         if (cfg->cfg_n_if < 2) {
2553                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2554                     "usbecm_get_descriptors: # of interfaces %d < 2",
2555                     cfg->cfg_n_if);
2556 
2557                 return (USB_FAILURE);
2558         }
2559 
2560         if (ecmp->ecm_data_if_no == 0 &&
2561             slave_if != ecmp->ecm_data_if_no) {
2562                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2563                     "usbecm_get_descriptors: Device has no call management "
2564                     "descriptor and use Union Descriptor.");
2565 
2566                 ecmp->ecm_data_if_no = slave_if;
2567         }
2568 
2569         if ((master_if != ecmp->ecm_ctrl_if_no) ||
2570             (slave_if != ecmp->ecm_data_if_no)) {
2571                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2572                     "usbecm_get_descriptors: control interface or "
2573                     "data interface don't match.");
2574 
2575                 return (USB_FAILURE);
2576         }
2577 
2578         if ((ecmp->ecm_ctrl_if_no >= cfg->cfg_n_if) ||
2579             (ecmp->ecm_data_if_no >= cfg->cfg_n_if)) {
2580                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2581                     "usbecm_get_descriptors: control interface %d or "
2582                     "data interface %d out of range.",
2583                     ecmp->ecm_ctrl_if_no, ecmp->ecm_data_if_no);
2584 
2585                 return (USB_FAILURE);
2586         }
2587 
2588         /* ECM data interface has a minimal of two altsettings */
2589         if (cfg->cfg_if[ecmp->ecm_data_if_no].if_n_alt < 2) {
2590                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2591                     "usbecm_get_descriptors: elements in if_alt is %d,"
2592                     " MUST >= 2", cfg->cfg_if[ecmp->ecm_ctrl_if_no].if_n_alt);
2593 
2594                 return (USB_FAILURE);
2595         }
2596 
2597         /* control interface must have interrupt endpoint */
2598         if ((ep_data = usb_lookup_ep_data(ecmp->ecm_dip, ecmp->ecm_dev_data,
2599             ecmp->ecm_ctrl_if_no, 0, 0, USB_EP_ATTR_INTR,
2600             USB_EP_DIR_IN)) == NULL) {
2601                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2602                     "usbecm_get_descriptors: "
2603                     "ctrl interface %d has no interrupt endpoint",
2604                     ecmp->ecm_data_if_no);
2605 
2606                 return (USB_FAILURE);
2607         }
2608         ecmp->ecm_intr_ep = ep_data;
2609 
2610         /* data interface alt 1 must have bulk in and out(ECM v1.2,p5) */
2611         if ((ep_data = usb_lookup_ep_data(ecmp->ecm_dip, ecmp->ecm_dev_data,
2612             ecmp->ecm_data_if_no, 1, 0, USB_EP_ATTR_BULK,
2613             USB_EP_DIR_IN)) == NULL) {
2614                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2615                     "usbecm_get_descriptors: "
2616                     "data interface %d has no bulk in endpoint",
2617                     ecmp->ecm_data_if_no);
2618 
2619                 return (USB_FAILURE);
2620         }
2621         ecmp->ecm_bulk_in_ep = ep_data;
2622 
2623         if ((ep_data = usb_lookup_ep_data(ecmp->ecm_dip, ecmp->ecm_dev_data,
2624             ecmp->ecm_data_if_no, 1, 0, USB_EP_ATTR_BULK,
2625             USB_EP_DIR_OUT)) == NULL) {
2626                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2627                     "usbecm_get_descriptors: "
2628                     "data interface %d has no bulk out endpoint",
2629                     ecmp->ecm_data_if_no);
2630 
2631                 return (USB_FAILURE);
2632         }
2633         ecmp->ecm_bulk_out_ep = ep_data;
2634 
2635         /* set default value for ethernet packet filter */
2636         ecmp->ecm_pkt_flt = CDC_ECM_PKT_TYPE_DIRECTED;
2637 
2638         return (USB_SUCCESS);
2639 }
2640 
2641 /* Generate IEEE802 style MAC address */
2642 static void
2643 generate_ether_addr(uint8_t *mac_addr)
2644 {
2645         (void) random_get_bytes(mac_addr, 6);
2646         mac_addr [0] &= 0xfe;       /* unicast only */
2647         mac_addr [0] |= 0x02;   /* set locally administered bit */
2648 }
2649 
2650 /*
2651  * Find a pair of bulk In/Out endpoints
2652  */
2653 int usbecm_find_bulk_in_out_eps(usbecm_state_t *ecmp,
2654     uint16_t ifc, usb_if_data_t *intf)
2655 {
2656         uint16_t alt, alt_num;
2657         usb_ep_data_t *intr_ep = NULL;
2658         usb_ep_data_t *bulk_in, *bulk_out, *ep;
2659 
2660         alt_num = intf->if_n_alt;
2661 
2662         /*
2663          * for the non-compatible devices, to make it simple, we
2664          * suppose the devices have this kind of configuration:
2665          *      INTR In EP(if exists) + BULK In + Bulk Out in the
2666          *      same altsetting of the same interface
2667          */
2668         for (alt = 0; alt < alt_num; alt++) {
2669                 /* search pair of bulk in/out EPs */
2670                 if (((bulk_in = usb_lookup_ep_data(ecmp->ecm_dip,
2671                     ecmp->ecm_dev_data, ifc, alt, 0,
2672                     USB_EP_ATTR_BULK,
2673                     USB_EP_DIR_IN)) == NULL) ||
2674                     (bulk_out = usb_lookup_ep_data(ecmp->ecm_dip,
2675                     ecmp->ecm_dev_data, ifc, alt, 0,
2676                     USB_EP_ATTR_BULK,
2677                     USB_EP_DIR_OUT)) == NULL) {
2678 
2679                         continue;
2680                 }
2681 
2682                 /*
2683                  * search interrupt pipe.
2684                  */
2685                 if ((ep = usb_lookup_ep_data(ecmp->ecm_dip,
2686                     ecmp->ecm_dev_data, ifc, alt, 0,
2687                     USB_EP_ATTR_INTR, USB_EP_DIR_IN)) != NULL) {
2688                         intr_ep = ep;
2689                 }
2690 
2691 
2692                 ecmp->ecm_data_if_no = ifc;
2693                 ecmp->ecm_data_if_alt = alt;
2694                 ecmp->ecm_intr_ep = intr_ep;
2695                 ecmp->ecm_ctrl_if_no = ifc;
2696                 ecmp->ecm_bulk_in_ep = bulk_in;
2697                 ecmp->ecm_bulk_out_ep = bulk_out;
2698 
2699                 return (USB_SUCCESS);
2700         }
2701 
2702         return (USB_FAILURE);
2703 }
2704 
2705 static int
2706 usbecm_init_non_compatible_device(usbecm_state_t *ecmp)
2707 {
2708         usb_if_data_t *cur_if;
2709         uint16_t if_num, i;
2710 
2711         /*
2712          * If device don't conform to spec, search pairs of bulk in/out
2713          * endpoints and fill related structure. We suppose this driver
2714          * is bound to a interface.
2715          */
2716         cur_if = ecmp->ecm_dev_data->dev_curr_cfg->cfg_if;
2717         if_num = ecmp->ecm_dev_data->dev_curr_cfg->cfg_n_if;
2718 
2719         /* search each interface which have bulk in and out */
2720         for (i = 0; i < if_num; i++) {
2721                 if (usbecm_find_bulk_in_out_eps(ecmp, i,
2722                     cur_if) == USB_SUCCESS) {
2723 
2724                         break;
2725                 }
2726                 cur_if++;
2727         }
2728 
2729         USB_DPRINTF_L4(PRINT_MASK_ATTA, ecmp->ecm_lh,
2730             "usbecm_init_non_compatible_device: ctrl_if=%d,"
2731             " data_if=%d, alt=%d", ecmp->ecm_ctrl_if_no,
2732             ecmp->ecm_data_if_no, ecmp->ecm_data_if_alt);
2733 
2734         return (USB_SUCCESS);
2735 }
2736 
2737 static boolean_t
2738 usbecm_is_compatible(usbecm_state_t *ecmp)
2739 {
2740         usb_cfg_data_t *cfg_data;
2741         usb_if_data_t *intf;
2742         usb_alt_if_data_t *alt;
2743         int alt_num, if_num, cfg_num;
2744         int i, j, cfg_index;
2745 
2746         cfg_num = ecmp->ecm_dev_data->dev_n_cfg;
2747         USB_DPRINTF_L3(PRINT_MASK_ATTA, ecmp->ecm_lh,
2748             "usbecm_is_compatible: entry, cfg_num=%d", cfg_num);
2749 
2750         for (cfg_index = 0; cfg_index < cfg_num; cfg_index++) {
2751                 cfg_data = &(ecmp->ecm_dev_data->dev_cfg[cfg_index]);
2752 
2753                 USB_DPRINTF_L3(PRINT_MASK_ATTA, ecmp->ecm_lh,
2754                     "usbecm_is_compatible: cfg_index=%d, value=%d",
2755                     cfg_index, cfg_data->cfg_descr.bConfigurationValue);
2756 
2757                 intf = cfg_data->cfg_if;
2758                 if_num = cfg_data->cfg_n_if;
2759 
2760                 for (i = 0; i < if_num; i++) {
2761                         alt_num = intf->if_n_alt;
2762                         for (j = 0; j < alt_num; j++) {
2763                         alt = &intf->if_alt[j];
2764                         if ((alt->altif_descr.bInterfaceClass == 0x02) &&
2765                             (alt->altif_descr.bInterfaceSubClass == 0x06)) {
2766                                 ecmp->ecm_cfg_index = cfg_index;
2767 
2768                                 USB_DPRINTF_L3(PRINT_MASK_ATTA, ecmp->ecm_lh,
2769                                     "usbecm_is_compatible: cfg_index=%d",
2770                                     cfg_index);
2771 
2772                                 return (B_TRUE);
2773                         }
2774                         }
2775                         intf++;
2776                 }
2777         }
2778 
2779         return (B_FALSE);
2780 }
2781 
2782 
2783 static int
2784 usbecm_usb_init(usbecm_state_t *ecmp)
2785 {
2786 
2787         if (usb_client_attach(ecmp->ecm_dip, USBDRV_VERSION, 0) !=
2788             USB_SUCCESS) {
2789                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2790                 "usbecm_usb_init: fail to attach");
2791 
2792                 return (USB_FAILURE);
2793         }
2794 
2795         /* Get the configuration information of device */
2796         if (usb_get_dev_data(ecmp->ecm_dip, &ecmp->ecm_dev_data,
2797             USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) {
2798                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2799                 "usbecm_usb_init: fail to get_dev_data");
2800 
2801                 return (USB_FAILURE);
2802         }
2803         ecmp->ecm_def_ph = ecmp->ecm_dev_data->dev_default_ph;
2804         ecmp->ecm_dev_state = USB_DEV_ONLINE;
2805 
2806         mutex_init(&ecmp->ecm_mutex, NULL, MUTEX_DRIVER,
2807             ecmp->ecm_dev_data->dev_iblock_cookie);
2808 
2809         if ((strcmp(ddi_binding_name(ecmp->ecm_dip),
2810             "usbif,class2.6") == 0) ||
2811             ((strcmp(ddi_binding_name(ecmp->ecm_dip),
2812             "usb,class2.6.0") == 0))) {
2813                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2814                     "usbecm_usb_init: A CDC ECM device is attached");
2815                 ecmp->ecm_compatibility = B_TRUE;
2816         } else if (usb_owns_device(ecmp->ecm_dip) &&
2817             usbecm_is_compatible(ecmp)) {
2818                 /*
2819                  * Current Sun SP ECM device has two configurations. Hence
2820                  * USBA doesn't create interface level compatible names
2821                  * for it, see usba_ready_device_node(). We have to check
2822                  * manually to see if compatible interfaces exist, when
2823                  * the driver owns the entire device.
2824                  */
2825                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2826                     "usbecm_usb_init: A CDC ECM device is attached");
2827                 ecmp->ecm_compatibility = B_TRUE;
2828         } else {
2829                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2830                     "usbecm_usb_init: A nonstandard device is attached to "
2831                     "usbecm(7D) driver. This device doesn't conform to "
2832                     "usb cdc spec.");
2833                 ecmp->ecm_compatibility = B_FALSE;
2834 
2835                 /* generate a random MAC addr */
2836                 generate_ether_addr(ecmp->ecm_srcaddr);
2837         }
2838 
2839         if ((ecmp->ecm_compatibility == B_TRUE) &&
2840             (usbecm_get_descriptors(ecmp) != USB_SUCCESS)) {
2841                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2842                     "usbecm_usb_init: A compatible device is attached, but "
2843                     "fail to get standard descriptors");
2844 
2845                 return (USB_FAILURE);
2846         }
2847 
2848         if (ecmp->ecm_compatibility == B_FALSE) {
2849                 (void) usbecm_init_non_compatible_device(ecmp);
2850         }
2851 
2852         /* Create power management components */
2853         if (usbecm_create_pm_components(ecmp) != USB_SUCCESS) {
2854                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2855                     "usbecm_usb_init: create pm components failed.");
2856 
2857                 return (USB_FAILURE);
2858         }
2859 
2860         /* Register to get callbacks for USB events */
2861         if (usb_register_event_cbs(ecmp->ecm_dip, &usbecm_events, 0)
2862             != USB_SUCCESS) {
2863                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2864                     "usbsecm_attach: register event callback failed.");
2865 
2866                 return (USB_FAILURE);
2867         }
2868         ecmp->ecm_init_flags |= USBECM_INIT_EVENTS;
2869 
2870 
2871         /* Get max data size of bulk transfer */
2872         if (usb_pipe_get_max_bulk_transfer_size(ecmp->ecm_dip,
2873             &ecmp->ecm_xfer_sz) != USB_SUCCESS) {
2874                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2875                     "usbsecm_ds_attach: get max size of transfer failed.");
2876 
2877                 return (USB_FAILURE);
2878         }
2879 
2880 
2881         ecmp->ecm_ser_acc = usb_init_serialization(ecmp->ecm_dip,
2882             USB_INIT_SER_CHECK_SAME_THREAD);
2883         ecmp->ecm_init_flags |= USBECM_INIT_SER;
2884 
2885         return (USB_SUCCESS);
2886 }
2887 
2888 
2889 /*
2890  * Open operation pipes. Each ECM device should have Bulk In, Bulk Out
2891  * and Interrupt In endpoints
2892  */
2893 static int
2894 usbecm_open_pipes(usbecm_state_t *ecmp)
2895 {
2896         int             rval = USB_SUCCESS;
2897         usb_ep_data_t   *in_data, *out_data, *intr_pipe;
2898         usb_pipe_policy_t policy;
2899         int             altif;
2900 
2901         ASSERT(!mutex_owned(&ecmp->ecm_mutex));
2902 
2903         USB_DPRINTF_L4(PRINT_MASK_OPEN, ecmp->ecm_lh,
2904             "usbsecm_open_pipes: ecmp = 0x%p", (void *)ecmp);
2905 
2906         if (ecmp->ecm_compatibility == B_TRUE) {
2907         /* compatible device has minimum of 2 altsetting, select alt 1 */
2908                 altif = 1;
2909         } else {
2910                 altif = ecmp->ecm_data_if_alt;
2911         }
2912         intr_pipe = ecmp->ecm_intr_ep;
2913         in_data = ecmp->ecm_bulk_in_ep;
2914         out_data = ecmp->ecm_bulk_out_ep;
2915 
2916         /* Bulk in and out must exist simultaneously. */
2917         if ((in_data == NULL) || (out_data == NULL)) {
2918                 USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
2919                     "usbsecm_open_pipes: look up bulk pipe failed in "
2920                     "interface %d ",
2921                     ecmp->ecm_data_if_no);
2922 
2923                 return (USB_FAILURE);
2924         }
2925         /*
2926          * If device conform to ecm spec, it must have an interrupt pipe
2927          * for this device.
2928          */
2929         if (ecmp->ecm_compatibility == B_TRUE && intr_pipe == NULL) {
2930                 USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
2931                     "usbecm_open_pipes: look up interrupt pipe failed in "
2932                     "interface %d", ecmp->ecm_ctrl_if_no);
2933 
2934                 return (USB_FAILURE);
2935         }
2936 
2937         USB_DPRINTF_L3(PRINT_MASK_OPEN, ecmp->ecm_lh,
2938             "usbsecm_open_pipes: open intr %02x, bulkin %02x bulkout %02x",
2939             intr_pipe?intr_pipe->ep_descr.bEndpointAddress:0,
2940             in_data->ep_descr.bEndpointAddress,
2941             out_data->ep_descr.bEndpointAddress);
2942 
2943         USB_DPRINTF_L3(PRINT_MASK_OPEN, ecmp->ecm_lh,
2944             "usbsecm_open_pipes: set data if(%d) alt(%d) ",
2945             ecmp->ecm_data_if_no, altif);
2946 
2947         if ((rval = usb_set_alt_if(ecmp->ecm_dip, ecmp->ecm_data_if_no,
2948             altif, USB_FLAGS_SLEEP, NULL, NULL)) != USB_SUCCESS) {
2949                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2950                     "usbecm_open_pipes: set alternate failed (%d)",
2951                     rval);
2952 
2953                 return (rval);
2954         }
2955 
2956         policy.pp_max_async_reqs = 2;
2957 
2958         /* Open bulk in endpoint */
2959         if (usb_pipe_open(ecmp->ecm_dip, &in_data->ep_descr, &policy,
2960             USB_FLAGS_SLEEP, &ecmp->ecm_bulkin_ph) != USB_SUCCESS) {
2961                 USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
2962                     "usbecm_open_pipes: open bulkin pipe failed!");
2963 
2964                 return (USB_FAILURE);
2965         }
2966 
2967         /* Open bulk out endpoint */
2968         if (usb_pipe_open(ecmp->ecm_dip, &out_data->ep_descr, &policy,
2969             USB_FLAGS_SLEEP, &ecmp->ecm_bulkout_ph) != USB_SUCCESS) {
2970                 USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
2971                     "usbecm_open_pipes: open bulkout pipe failed!");
2972 
2973                 usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_bulkin_ph,
2974                     USB_FLAGS_SLEEP, NULL, NULL);
2975 
2976                 return (USB_FAILURE);
2977         }
2978 
2979         /* Open interrupt endpoint if found. */
2980         if (intr_pipe != NULL) {
2981                 if (usb_pipe_open(ecmp->ecm_dip, &intr_pipe->ep_descr, &policy,
2982                     USB_FLAGS_SLEEP, &ecmp->ecm_intr_ph) != USB_SUCCESS) {
2983                         USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
2984                             "usbecm_open_pipes: "
2985                             "open intr pipe failed");
2986 
2987                         usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_bulkin_ph,
2988                             USB_FLAGS_SLEEP, NULL, NULL);
2989                         usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_bulkout_ph,
2990                             USB_FLAGS_SLEEP, NULL, NULL);
2991 
2992                         return (USB_FAILURE);
2993                 }
2994         }
2995 
2996         /* initialize the pipe related data */
2997         mutex_enter(&ecmp->ecm_mutex);
2998         ecmp->ecm_bulkin_sz = in_data->ep_descr.wMaxPacketSize;
2999         ecmp->ecm_bulkin_state = USBECM_PIPE_IDLE;
3000         ecmp->ecm_bulkout_state = USBECM_PIPE_IDLE;
3001         if (ecmp->ecm_intr_ph != NULL) {
3002                 ecmp->ecm_intr_state = USBECM_PIPE_IDLE;
3003         }
3004         mutex_exit(&ecmp->ecm_mutex);
3005 
3006         if (ecmp->ecm_intr_ph != NULL) {
3007 
3008                 usbecm_pipe_start_polling(ecmp);
3009         }
3010 
3011         USB_DPRINTF_L4(PRINT_MASK_OPEN, ecmp->ecm_lh,
3012             "usbsecm_open_pipes: end");
3013 
3014         return (rval);
3015 }
3016 
3017 
3018 /*
3019  * usbsecm_close_pipes:
3020  *      Close pipes
3021  *      Each device could include three pipes: bulk in, bulk out and interrupt.
3022  */
3023 static void
3024 usbecm_close_pipes(usbecm_state_t *ecmp)
3025 {
3026 
3027         mutex_enter(&ecmp->ecm_mutex);
3028 
3029         USB_DPRINTF_L4(PRINT_MASK_CLOSE, ecmp->ecm_lh,
3030             "usbsecm_close_pipes: ecm_bulkin_state = %d",
3031             ecmp->ecm_bulkin_state);
3032 
3033         /*
3034          * Check the status of the pipes. If pipe is closing or closed,
3035          * return directly.
3036          */
3037         if ((ecmp->ecm_bulkin_state == USBECM_PIPE_CLOSED) ||
3038             (ecmp->ecm_bulkin_state == USBECM_PIPE_CLOSING)) {
3039                 USB_DPRINTF_L2(PRINT_MASK_CLOSE, ecmp->ecm_lh,
3040                     "usbsecm_close_pipes: pipe is closing or has closed");
3041                 mutex_exit(&ecmp->ecm_mutex);
3042 
3043                 return;
3044         }
3045 
3046         ecmp->ecm_bulkin_state = USBECM_PIPE_CLOSING;
3047         mutex_exit(&ecmp->ecm_mutex);
3048 
3049         /* reset the data interface's altsetting to 0 */
3050         if ((ecmp->ecm_dev_state == USB_DEV_ONLINE) &&
3051             (usb_set_alt_if(ecmp->ecm_dip, ecmp->ecm_data_if_no,
3052             0, USB_FLAGS_SLEEP, NULL, NULL) != USB_SUCCESS)) {
3053                 USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
3054                     "usbecm_close_pipes: reset alternate failed ");
3055         }
3056 
3057         /* Close pipes */
3058         usb_pipe_reset(ecmp->ecm_dip, ecmp->ecm_bulkin_ph,
3059             USB_FLAGS_SLEEP, NULL, 0);
3060         usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_bulkin_ph,
3061             USB_FLAGS_SLEEP, NULL, 0);
3062         usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_bulkout_ph,
3063             USB_FLAGS_SLEEP, NULL, 0);
3064 
3065         if (ecmp->ecm_intr_ph != NULL) {
3066                 usb_pipe_stop_intr_polling(ecmp->ecm_intr_ph,
3067                     USB_FLAGS_SLEEP);
3068                 usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_intr_ph,
3069                     USB_FLAGS_SLEEP, NULL, 0);
3070         }
3071 
3072         mutex_enter(&ecmp->ecm_mutex);
3073         /* Reset the status of pipes to closed */
3074         ecmp->ecm_bulkin_state = USBECM_PIPE_CLOSED;
3075         ecmp->ecm_bulkin_ph = NULL;
3076         ecmp->ecm_bulkout_state = USBECM_PIPE_CLOSED;
3077         ecmp->ecm_bulkout_ph = NULL;
3078         if (ecmp->ecm_intr_ph != NULL) {
3079                 ecmp->ecm_intr_state = USBECM_PIPE_CLOSED;
3080                 ecmp->ecm_intr_ph = NULL;
3081         }
3082 
3083         mutex_exit(&ecmp->ecm_mutex);
3084 
3085         USB_DPRINTF_L4(PRINT_MASK_CLOSE, ecmp->ecm_lh,
3086             "usbsecm_close_pipes: pipes have been closed.");
3087 }
3088 
3089 
3090 static int
3091 usbecm_ctrl_write(usbecm_state_t *ecmp, uchar_t request,
3092     uint16_t value, mblk_t **data)
3093 {
3094         usb_ctrl_setup_t setup;
3095         usb_cb_flags_t  cb_flags;
3096         usb_cr_t        cr;
3097         int             rval;
3098 
3099         USB_DPRINTF_L4(PRINT_MASK_ALL, ecmp->ecm_lh,
3100             "usbecm_ctrl_write: ");
3101 
3102         /* initialize the control request. */
3103         setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV |
3104             USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
3105         setup.bRequest = request;
3106         setup.wValue = value;
3107         setup.wIndex = ecmp->ecm_ctrl_if_no;
3108         setup.wLength = ((data != NULL) && (*data != NULL)) ? MBLKL(*data) : 0;
3109         setup.attrs = 0;
3110 
3111         rval = usb_pipe_ctrl_xfer_wait(ecmp->ecm_def_ph, &setup, data,
3112             &cr, &cb_flags, 0);
3113 
3114         USB_DPRINTF_L4(PRINT_MASK_ALL, ecmp->ecm_lh,
3115             "usbecm_ctrl_write: rval = %d", rval);
3116 
3117         return (rval);
3118 }
3119 
3120 static int
3121 usbecm_ctrl_read(usbecm_state_t *ecmp, uchar_t request,
3122     uint16_t value, mblk_t **data, int len)
3123 {
3124         usb_ctrl_setup_t setup;
3125         usb_cb_flags_t  cb_flags;
3126         usb_cr_t        cr;
3127 
3128         USB_DPRINTF_L4(PRINT_MASK_ALL, ecmp->ecm_lh,
3129             "usbecm_ctrl_read: ");
3130 
3131         /* initialize the control request. */
3132         setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST |
3133             USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
3134         setup.bRequest = request;
3135         setup.wValue = value;
3136         setup.wIndex = ecmp->ecm_ctrl_if_no;
3137         setup.wLength = (uint16_t)len;
3138         setup.attrs = 0;
3139 
3140         return (usb_pipe_ctrl_xfer_wait(ecmp->ecm_def_ph, &setup, data,
3141             &cr, &cb_flags, 0));
3142 }
3143 
3144 /* Get specific statistic data from device */
3145 static int
3146 usbecm_get_statistics(usbecm_state_t *ecmp, uint32_t fs, uint32_t *stat_data)
3147 {
3148         mblk_t *data = NULL;
3149         uint32_t stat;
3150 
3151         /* first check to see if this stat is collected by device */
3152         if ((ecmp->ecm_compatibility == B_TRUE) &&
3153             (ecmp->ecm_desc.bmEthernetStatistics & ECM_STAT_CAP_MASK(fs))) {
3154                 if (usbecm_ctrl_read(ecmp, CDC_ECM_GET_ETH_STAT,
3155                     ecmp->ecm_ctrl_if_no, &data, 4) != USB_SUCCESS) {
3156 
3157                         return (USB_FAILURE);
3158                 }
3159                 stat = (data->b_rptr[3] << 24) | (data->b_rptr[2] << 16) |
3160                     (data->b_rptr[1] << 8) | (data->b_rptr[0]);
3161                 *stat_data = stat;
3162 
3163                 freemsg(data);
3164 
3165                 return (USB_SUCCESS);
3166         }
3167 
3168         return (USB_FAILURE);
3169 }