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  * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
  24  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * USBA: Solaris USB Architecture support for the hub
  29  * including root hub
  30  * Most of the code for hubd resides in this file and
  31  * is shared between the HCD root hub support and hubd
  32  */
  33 #define USBA_FRAMEWORK
  34 #include <sys/usb/usba.h>
  35 #include <sys/usb/usba/usba_devdb.h>
  36 #include <sys/sunndi.h>
  37 #include <sys/usb/usba/usba_impl.h>
  38 #include <sys/usb/usba/usba_types.h>
  39 #include <sys/usb/usba/hubdi.h>
  40 #include <sys/usb/usba/hcdi_impl.h>
  41 #include <sys/usb/hubd/hub.h>
  42 #include <sys/usb/hubd/hubdvar.h>
  43 #include <sys/usb/hubd/hubd_impl.h>
  44 #include <sys/kobj.h>
  45 #include <sys/kobj_lex.h>
  46 #include <sys/fs/dv_node.h>
  47 #include <sys/strsun.h>
  48 
  49 /*
  50  * External functions
  51  */
  52 extern boolean_t consconfig_console_is_ready(void);
  53 
  54 /*
  55  * Prototypes for static functions
  56  */
  57 static  int     usba_hubdi_bus_ctl(
  58                         dev_info_t              *dip,
  59                         dev_info_t              *rdip,
  60                         ddi_ctl_enum_t          op,
  61                         void                    *arg,
  62                         void                    *result);
  63 
  64 static int      usba_hubdi_map_fault(
  65                         dev_info_t              *dip,
  66                         dev_info_t              *rdip,
  67                         struct hat              *hat,
  68                         struct seg              *seg,
  69                         caddr_t                 addr,
  70                         struct devpage          *dp,
  71                         pfn_t                   pfn,
  72                         uint_t                  prot,
  73                         uint_t                  lock);
  74 
  75 static int hubd_busop_get_eventcookie(dev_info_t *dip,
  76                         dev_info_t *rdip,
  77                         char *eventname,
  78                         ddi_eventcookie_t *cookie);
  79 static int hubd_busop_add_eventcall(dev_info_t *dip,
  80                         dev_info_t *rdip,
  81                         ddi_eventcookie_t cookie,
  82                         void (*callback)(dev_info_t *dip,
  83                                 ddi_eventcookie_t cookie, void *arg,
  84                                 void *bus_impldata),
  85                         void *arg, ddi_callback_id_t *cb_id);
  86 static int hubd_busop_remove_eventcall(dev_info_t *dip,
  87                         ddi_callback_id_t cb_id);
  88 static int hubd_bus_config(dev_info_t *dip,
  89                         uint_t flag,
  90                         ddi_bus_config_op_t op,
  91                         void *arg,
  92                         dev_info_t **child);
  93 static int hubd_bus_unconfig(dev_info_t *dip,
  94                         uint_t flag,
  95                         ddi_bus_config_op_t op,
  96                         void *arg);
  97 static int hubd_bus_power(dev_info_t *dip, void *impl_arg,
  98                         pm_bus_power_op_t op, void *arg, void *result);
  99 
 100 static usb_port_t  hubd_get_port_num(hubd_t *, struct devctl_iocdata *);
 101 static dev_info_t *hubd_get_child_dip(hubd_t *, usb_port_t);
 102 static uint_t hubd_cfgadm_state(hubd_t *, usb_port_t);
 103 static int hubd_toggle_port(hubd_t *, usb_port_t);
 104 static void hubd_register_cpr_callback(hubd_t *);
 105 static void hubd_unregister_cpr_callback(hubd_t *);
 106 
 107 /*
 108  * Busops vector for USB HUB's
 109  */
 110 struct bus_ops usba_hubdi_busops =      {
 111         BUSO_REV,
 112         nullbusmap,                     /* bus_map */
 113         NULL,                           /* bus_get_intrspec */
 114         NULL,                           /* bus_add_intrspec */
 115         NULL,                           /* bus_remove_intrspec */
 116         usba_hubdi_map_fault,           /* bus_map_fault */
 117         NULL,                           /* bus_dma_map */
 118         ddi_dma_allochdl,
 119         ddi_dma_freehdl,
 120         ddi_dma_bindhdl,
 121         ddi_dma_unbindhdl,
 122         ddi_dma_flush,
 123         ddi_dma_win,
 124         ddi_dma_mctl,                   /* bus_dma_ctl */
 125         usba_hubdi_bus_ctl,             /* bus_ctl */
 126         ddi_bus_prop_op,                /* bus_prop_op */
 127         hubd_busop_get_eventcookie,
 128         hubd_busop_add_eventcall,
 129         hubd_busop_remove_eventcall,
 130         NULL,                           /* bus_post_event */
 131         NULL,                           /* bus_intr_ctl */
 132         hubd_bus_config,                /* bus_config */
 133         hubd_bus_unconfig,              /* bus_unconfig */
 134         NULL,                           /* bus_fm_init */
 135         NULL,                           /* bus_fm_fini */
 136         NULL,                           /* bus_fm_access_enter */
 137         NULL,                           /* bus_fm_access_exit */
 138         hubd_bus_power                  /* bus_power */
 139 };
 140 
 141 #define USB_HUB_INTEL_VID       0x8087
 142 #define USB_HUB_INTEL_PID       0x0020
 143 
 144 /*
 145  * local variables
 146  */
 147 static kmutex_t usba_hubdi_mutex;       /* protects USBA HUB data structures */
 148 
 149 static usba_list_entry_t        usba_hubdi_list;
 150 
 151 usb_log_handle_t        hubdi_log_handle;
 152 uint_t                  hubdi_errlevel = USB_LOG_L4;
 153 uint_t                  hubdi_errmask = (uint_t)-1;
 154 uint8_t                 hubdi_min_pm_threshold = 5; /* seconds */
 155 uint8_t                 hubdi_reset_delay = 20; /* seconds */
 156 extern int modrootloaded;
 157 
 158 /*
 159  * initialize private data
 160  */
 161 void
 162 usba_hubdi_initialization()
 163 {
 164         hubdi_log_handle = usb_alloc_log_hdl(NULL, "hubdi", &hubdi_errlevel,
 165             &hubdi_errmask, NULL, 0);
 166 
 167         USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle,
 168             "usba_hubdi_initialization");
 169 
 170         mutex_init(&usba_hubdi_mutex, NULL, MUTEX_DRIVER, NULL);
 171 
 172         usba_init_list(&usba_hubdi_list, NULL, NULL);
 173 }
 174 
 175 
 176 void
 177 usba_hubdi_destroy()
 178 {
 179         USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle,
 180             "usba_hubdi_destroy");
 181 
 182         mutex_destroy(&usba_hubdi_mutex);
 183         usba_destroy_list(&usba_hubdi_list);
 184 
 185         usb_free_log_hdl(hubdi_log_handle);
 186 }
 187 
 188 
 189 /*
 190  * Called by an HUB to attach an instance of the driver
 191  *      make this instance known to USBA
 192  *      the HUB should initialize usba_hubdi structure prior
 193  *      to calling this interface
 194  */
 195 int
 196 usba_hubdi_register(dev_info_t  *dip,
 197                 uint_t          flags)
 198 {
 199         usba_hubdi_t *hubdi = kmem_zalloc(sizeof (usba_hubdi_t), KM_SLEEP);
 200         usba_device_t *usba_device = usba_get_usba_device(dip);
 201 
 202         USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle,
 203             "usba_hubdi_register: %s", ddi_node_name(dip));
 204 
 205         hubdi->hubdi_dip = dip;
 206         hubdi->hubdi_flags = flags;
 207 
 208         usba_device->usb_hubdi = hubdi;
 209 
 210         /*
 211          * add this hubdi instance to the list of known hubdi's
 212          */
 213         usba_init_list(&hubdi->hubdi_list, (usb_opaque_t)hubdi,
 214             usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)->
 215             hcdi_iblock_cookie);
 216         mutex_enter(&usba_hubdi_mutex);
 217         usba_add_to_list(&usba_hubdi_list, &hubdi->hubdi_list);
 218         mutex_exit(&usba_hubdi_mutex);
 219 
 220         return (DDI_SUCCESS);
 221 }
 222 
 223 
 224 /*
 225  * Called by an HUB to detach an instance of the driver
 226  */
 227 int
 228 usba_hubdi_unregister(dev_info_t *dip)
 229 {
 230         usba_device_t *usba_device = usba_get_usba_device(dip);
 231         usba_hubdi_t *hubdi = usba_device->usb_hubdi;
 232 
 233         USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle,
 234             "usba_hubdi_unregister: %s", ddi_node_name(dip));
 235 
 236         mutex_enter(&usba_hubdi_mutex);
 237         (void) usba_rm_from_list(&usba_hubdi_list, &hubdi->hubdi_list);
 238         mutex_exit(&usba_hubdi_mutex);
 239 
 240         usba_destroy_list(&hubdi->hubdi_list);
 241 
 242         kmem_free(hubdi, sizeof (usba_hubdi_t));
 243 
 244         return (DDI_SUCCESS);
 245 }
 246 
 247 
 248 /*
 249  * misc bus routines currently not used
 250  */
 251 /*ARGSUSED*/
 252 static int
 253 usba_hubdi_map_fault(dev_info_t *dip,
 254         dev_info_t      *rdip,
 255         struct hat      *hat,
 256         struct seg      *seg,
 257         caddr_t         addr,
 258         struct devpage  *dp,
 259         pfn_t           pfn,
 260         uint_t          prot,
 261         uint_t          lock)
 262 {
 263         return (DDI_FAILURE);
 264 }
 265 
 266 
 267 /*
 268  * root hub support. the root hub uses the same devi as the HCD
 269  */
 270 int
 271 usba_hubdi_bind_root_hub(dev_info_t *dip,
 272         uchar_t *root_hub_config_descriptor,
 273         size_t config_length,
 274         usb_dev_descr_t *root_hub_device_descriptor)
 275 {
 276         usba_device_t *usba_device;
 277         usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
 278         hubd_t  *root_hubd;
 279         usb_pipe_handle_t ph = NULL;
 280         dev_info_t *child = ddi_get_child(dip);
 281 
 282         if (ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
 283             "root-hub") != NDI_SUCCESS) {
 284 
 285                 return (USB_FAILURE);
 286         }
 287 
 288         usba_add_root_hub(dip);
 289 
 290         root_hubd = kmem_zalloc(sizeof (hubd_t), KM_SLEEP);
 291 
 292         /*
 293          * create and initialize a usba_device structure
 294          */
 295         usba_device = usba_alloc_usba_device(dip);
 296 
 297         mutex_enter(&usba_device->usb_mutex);
 298         usba_device->usb_hcdi_ops = hcdi->hcdi_ops;
 299         usba_device->usb_cfg = root_hub_config_descriptor;
 300         usba_device->usb_cfg_length = config_length;
 301         usba_device->usb_dev_descr = root_hub_device_descriptor;
 302         usba_device->usb_port = 1;
 303         usba_device->usb_addr = ROOT_HUB_ADDR;
 304         usba_device->usb_root_hubd = root_hubd;
 305         usba_device->usb_cfg_array = kmem_zalloc(sizeof (uchar_t *),
 306             KM_SLEEP);
 307         usba_device->usb_cfg_array_length = sizeof (uchar_t *);
 308 
 309         usba_device->usb_cfg_array_len = kmem_zalloc(sizeof (uint16_t),
 310             KM_SLEEP);
 311         usba_device->usb_cfg_array_len_length = sizeof (uint16_t);
 312 
 313         usba_device->usb_cfg_array[0] = root_hub_config_descriptor;
 314         usba_device->usb_cfg_array_len[0] =
 315             sizeof (root_hub_config_descriptor);
 316 
 317         usba_device->usb_cfg_str_descr = kmem_zalloc(sizeof (uchar_t *),
 318             KM_SLEEP);
 319         usba_device->usb_n_cfgs = 1;
 320         usba_device->usb_n_ifs = 1;
 321         usba_device->usb_dip = dip;
 322 
 323         usba_device->usb_client_flags = kmem_zalloc(
 324             usba_device->usb_n_ifs * USBA_CLIENT_FLAG_SIZE, KM_SLEEP);
 325 
 326         usba_device->usb_client_attach_list = kmem_zalloc(
 327             usba_device->usb_n_ifs *
 328             sizeof (*usba_device->usb_client_attach_list), KM_SLEEP);
 329 
 330         usba_device->usb_client_ev_cb_list = kmem_zalloc(
 331             usba_device->usb_n_ifs *
 332             sizeof (*usba_device->usb_client_ev_cb_list), KM_SLEEP);
 333 
 334         /*
 335          * The bDeviceProtocol field of root hub device specifies,
 336          * whether root hub is a High or Full speed usb device.
 337          */
 338         if (root_hub_device_descriptor->bDeviceProtocol) {
 339                 usba_device->usb_port_status = USBA_HIGH_SPEED_DEV;
 340         } else {
 341                 usba_device->usb_port_status = USBA_FULL_SPEED_DEV;
 342         }
 343 
 344         mutex_exit(&usba_device->usb_mutex);
 345 
 346         usba_set_usba_device(dip, usba_device);
 347 
 348         /*
 349          * For the root hub the default pipe is not yet open
 350          */
 351         if (usb_pipe_open(dip, NULL, NULL,
 352             USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph) != USB_SUCCESS) {
 353                 goto fail;
 354         }
 355 
 356         /*
 357          * kill off all OBP children, they may not be fully
 358          * enumerated
 359          */
 360         while (child) {
 361                 dev_info_t *next = ddi_get_next_sibling(child);
 362                 (void) ddi_remove_child(child, 0);
 363                 child = next;
 364         }
 365 
 366         /*
 367          * "attach" the root hub driver
 368          */
 369         if (usba_hubdi_attach(dip, DDI_ATTACH) != DDI_SUCCESS) {
 370                 goto fail;
 371         }
 372 
 373         return (USB_SUCCESS);
 374 
 375 fail:
 376         (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "root-hub");
 377 
 378         usba_rem_root_hub(dip);
 379 
 380         if (ph) {
 381                 usb_pipe_close(dip, ph,
 382                     USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
 383         }
 384 
 385         kmem_free(usba_device->usb_cfg_array,
 386             usba_device->usb_cfg_array_length);
 387         kmem_free(usba_device->usb_cfg_array_len,
 388             usba_device->usb_cfg_array_len_length);
 389 
 390         kmem_free(usba_device->usb_cfg_str_descr, sizeof (uchar_t *));
 391 
 392         usba_free_usba_device(usba_device);
 393 
 394         usba_set_usba_device(dip, NULL);
 395         if (root_hubd) {
 396                 kmem_free(root_hubd, sizeof (hubd_t));
 397         }
 398 
 399         return (USB_FAILURE);
 400 }
 401 
 402 
 403 int
 404 usba_hubdi_unbind_root_hub(dev_info_t *dip)
 405 {
 406         usba_device_t *usba_device;
 407 
 408         /* was root hub attached? */
 409         if (!(usba_is_root_hub(dip))) {
 410 
 411                 /* return success anyway */
 412                 return (USB_SUCCESS);
 413         }
 414 
 415         /*
 416          * usba_hubdi_detach also closes the default pipe
 417          * and removes properties so there is no need to
 418          * do it here
 419          */
 420         if (usba_hubdi_detach(dip, DDI_DETACH) != DDI_SUCCESS) {
 421 
 422                 if (DEVI_IS_ATTACHING(dip)) {
 423                         USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle,
 424                             "failure to unbind root hub after attach failure");
 425                 }
 426 
 427                 return (USB_FAILURE);
 428         }
 429 
 430         usba_device = usba_get_usba_device(dip);
 431 
 432         kmem_free(usba_device->usb_root_hubd, sizeof (hubd_t));
 433 
 434         kmem_free(usba_device->usb_cfg_array,
 435             usba_device->usb_cfg_array_length);
 436         kmem_free(usba_device->usb_cfg_array_len,
 437             usba_device->usb_cfg_array_len_length);
 438 
 439         kmem_free(usba_device->usb_cfg_str_descr, sizeof (uchar_t *));
 440 
 441         usba_free_usba_device(usba_device);
 442 
 443         usba_rem_root_hub(dip);
 444 
 445         (void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "root-hub");
 446 
 447         return (USB_SUCCESS);
 448 }
 449 
 450 
 451 /*
 452  * Actual Hub Driver support code:
 453  *      shared by root hub and non-root hubs
 454  */
 455 #include <sys/usb/usba/usbai_version.h>
 456 
 457 /* Debugging support */
 458 uint_t hubd_errlevel    = USB_LOG_L4;
 459 uint_t hubd_errmask     = (uint_t)DPRINT_MASK_ALL;
 460 uint_t hubd_instance_debug = (uint_t)-1;
 461 static uint_t hubdi_bus_config_debug = 0;
 462 
 463 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_errlevel))
 464 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_errmask))
 465 _NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_instance_debug))
 466 
 467 _NOTE(SCHEME_PROTECTS_DATA("unique", msgb))
 468 _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info))
 469 
 470 
 471 /*
 472  * local variables:
 473  *
 474  * Amount of time to wait between resetting the port and accessing
 475  * the device.  The value is in microseconds.
 476  */
 477 static uint_t hubd_device_delay = 1000000;
 478 
 479 /*
 480  * enumeration retry
 481  */
 482 #define HUBD_PORT_RETRY 5
 483 static uint_t hubd_retry_enumerate = HUBD_PORT_RETRY;
 484 
 485 /*
 486  * Stale hotremoved device cleanup delay
 487  */
 488 #define HUBD_STALE_DIP_CLEANUP_DELAY    5000000
 489 static uint_t hubd_dip_cleanup_delay = HUBD_STALE_DIP_CLEANUP_DELAY;
 490 
 491 /*
 492  * retries for USB suspend and resume
 493  */
 494 #define HUBD_SUS_RES_RETRY      2
 495 
 496 void    *hubd_statep;
 497 
 498 /*
 499  * prototypes
 500  */
 501 static int hubd_cleanup(dev_info_t *dip, hubd_t  *hubd);
 502 static int hubd_check_ports(hubd_t  *hubd);
 503 
 504 static int  hubd_open_intr_pipe(hubd_t *hubd);
 505 static void hubd_start_polling(hubd_t *hubd, int always);
 506 static void hubd_stop_polling(hubd_t *hubd);
 507 static void hubd_close_intr_pipe(hubd_t *hubd);
 508 
 509 static void hubd_read_cb(usb_pipe_handle_t pipe, usb_intr_req_t *req);
 510 static void hubd_exception_cb(usb_pipe_handle_t pipe,
 511                                                 usb_intr_req_t *req);
 512 static void hubd_hotplug_thread(void *arg);
 513 static void hubd_reset_thread(void *arg);
 514 static int hubd_create_child(dev_info_t *dip,
 515                 hubd_t          *hubd,
 516                 usba_device_t   *usba_device,
 517                 usb_port_status_t port_status,
 518                 usb_port_t      port,
 519                 int             iteration);
 520 
 521 static int hubd_delete_child(hubd_t *hubd, usb_port_t port, uint_t flag,
 522         boolean_t retry);
 523 
 524 static int hubd_get_hub_descriptor(hubd_t *hubd);
 525 
 526 static int hubd_get_hub_status_words(hubd_t *hubd, uint16_t *status);
 527 
 528 static int hubd_reset_port(hubd_t *hubd, usb_port_t port);
 529 
 530 static int hubd_get_hub_status(hubd_t *hubd);
 531 
 532 static int hubd_handle_port_connect(hubd_t *hubd, usb_port_t port);
 533 
 534 static int hubd_disable_port(hubd_t *hubd, usb_port_t port);
 535 
 536 static int hubd_enable_port(hubd_t *hubd, usb_port_t port);
 537 static int hubd_recover_disabled_port(hubd_t *hubd, usb_port_t port);
 538 
 539 static int hubd_determine_port_status(hubd_t *hubd, usb_port_t port,
 540         uint16_t *status, uint16_t *change, uint_t ack_flag);
 541 
 542 static int hubd_enable_all_port_power(hubd_t *hubd);
 543 static int hubd_disable_all_port_power(hubd_t *hubd);
 544 static int hubd_disable_port_power(hubd_t *hubd, usb_port_t port);
 545 static int hubd_enable_port_power(hubd_t *hubd, usb_port_t port);
 546 
 547 static void hubd_free_usba_device(hubd_t *hubd, usba_device_t *usba_device);
 548 
 549 static int hubd_can_suspend(hubd_t *hubd);
 550 static void hubd_restore_device_state(dev_info_t *dip, hubd_t *hubd);
 551 static int hubd_setdevaddr(hubd_t *hubd, usb_port_t port);
 552 static void hubd_setdevconfig(hubd_t *hubd, usb_port_t port);
 553 
 554 static int hubd_register_events(hubd_t *hubd);
 555 static void hubd_do_callback(hubd_t *hubd, dev_info_t *dip,
 556         ddi_eventcookie_t cookie);
 557 static void hubd_run_callbacks(hubd_t *hubd, usba_event_t type);
 558 static void hubd_post_event(hubd_t *hubd, usb_port_t port, usba_event_t type);
 559 static void hubd_create_pm_components(dev_info_t *dip, hubd_t *hubd);
 560 
 561 static int hubd_disconnect_event_cb(dev_info_t *dip);
 562 static int hubd_reconnect_event_cb(dev_info_t *dip);
 563 static int hubd_pre_suspend_event_cb(dev_info_t *dip);
 564 static int hubd_post_resume_event_cb(dev_info_t *dip);
 565 static int hubd_cpr_suspend(hubd_t *hubd);
 566 static void hubd_cpr_resume(dev_info_t *dip);
 567 static int hubd_restore_state_cb(dev_info_t *dip);
 568 static int hubd_check_same_device(hubd_t *hubd, usb_port_t port);
 569 
 570 static int hubd_init_power_budget(hubd_t *hubd);
 571 
 572 static ndi_event_definition_t hubd_ndi_event_defs[] = {
 573         {USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL,
 574                                                 NDI_EVENT_POST_TO_ALL},
 575         {USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL,
 576                                                 NDI_EVENT_POST_TO_ALL},
 577         {USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL,
 578                                                 NDI_EVENT_POST_TO_ALL},
 579         {USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL,
 580                                                 NDI_EVENT_POST_TO_ALL}
 581 };
 582 
 583 #define HUBD_N_NDI_EVENTS \
 584         (sizeof (hubd_ndi_event_defs) / sizeof (ndi_event_definition_t))
 585 
 586 static ndi_event_set_t hubd_ndi_events = {
 587         NDI_EVENTS_REV1, HUBD_N_NDI_EVENTS, hubd_ndi_event_defs};
 588 
 589 /* events received from parent */
 590 static usb_event_t hubd_events = {
 591         hubd_disconnect_event_cb,
 592         hubd_reconnect_event_cb,
 593         hubd_pre_suspend_event_cb,
 594         hubd_post_resume_event_cb
 595 };
 596 
 597 
 598 /*
 599  * hubd_get_soft_state() returns the hubd soft state
 600  */
 601 hubd_t *
 602 hubd_get_soft_state(dev_info_t *dip)
 603 {
 604         if (dip == NULL) {
 605 
 606                 return (NULL);
 607         }
 608 
 609         if (usba_is_root_hub(dip)) {
 610                 usba_device_t *usba_device = usba_get_usba_device(dip);
 611 
 612                 return (usba_device->usb_root_hubd);
 613         } else {
 614                 int instance = ddi_get_instance(dip);
 615 
 616                 return (ddi_get_soft_state(hubd_statep, instance));
 617         }
 618 }
 619 
 620 
 621 /*
 622  * PM support functions:
 623  */
 624 /*ARGSUSED*/
 625 static void
 626 hubd_pm_busy_component(hubd_t *hubd, dev_info_t *dip, int component)
 627 {
 628         if (hubd->h_hubpm != NULL) {
 629                 hubd->h_hubpm->hubp_busy_pm++;
 630                 mutex_exit(HUBD_MUTEX(hubd));
 631                 if (pm_busy_component(dip, 0) != DDI_SUCCESS) {
 632                         mutex_enter(HUBD_MUTEX(hubd));
 633                         hubd->h_hubpm->hubp_busy_pm--;
 634                         mutex_exit(HUBD_MUTEX(hubd));
 635                 }
 636                 mutex_enter(HUBD_MUTEX(hubd));
 637                 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
 638                     "hubd_pm_busy_component: %d", hubd->h_hubpm->hubp_busy_pm);
 639         }
 640 }
 641 
 642 
 643 /*ARGSUSED*/
 644 static void
 645 hubd_pm_idle_component(hubd_t *hubd, dev_info_t *dip, int component)
 646 {
 647         if (hubd->h_hubpm != NULL) {
 648                 mutex_exit(HUBD_MUTEX(hubd));
 649                 if (pm_idle_component(dip, 0) == DDI_SUCCESS) {
 650                         mutex_enter(HUBD_MUTEX(hubd));
 651                         ASSERT(hubd->h_hubpm->hubp_busy_pm > 0);
 652                         hubd->h_hubpm->hubp_busy_pm--;
 653                         mutex_exit(HUBD_MUTEX(hubd));
 654                 }
 655                 mutex_enter(HUBD_MUTEX(hubd));
 656                 USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
 657                     "hubd_pm_idle_component: %d", hubd->h_hubpm->hubp_busy_pm);
 658         }
 659 }
 660 
 661 
 662 /*
 663  * track power level changes for children of this instance
 664  */
 665 static void
 666 hubd_set_child_pwrlvl(hubd_t *hubd, usb_port_t port, uint8_t power)
 667 {
 668         int     old_power, new_power, pwr;
 669         usb_port_t      portno;
 670         hub_power_t     *hubpm;
 671 
 672         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
 673             "hubd_set_child_pwrlvl: port=%d power=%d",
 674             port, power);
 675 
 676         mutex_enter(HUBD_MUTEX(hubd));
 677         hubpm = hubd->h_hubpm;
 678 
 679         old_power = 0;
 680         for (portno = 1; portno <= hubd->h_hub_descr.bNbrPorts; portno++) {
 681                 old_power += hubpm->hubp_child_pwrstate[portno];
 682         }
 683 
 684         /* assign the port power */
 685         pwr = hubd->h_hubpm->hubp_child_pwrstate[port];
 686         hubd->h_hubpm->hubp_child_pwrstate[port] = power;
 687         new_power = old_power - pwr + power;
 688 
 689         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
 690             "hubd_set_child_pwrlvl: new_power=%d old_power=%d",
 691             new_power, old_power);
 692 
 693         if ((new_power > 0) && (old_power == 0)) {
 694                 /* we have the first child coming out of low power */
 695                 (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0);
 696         } else if ((new_power == 0) && (old_power > 0)) {
 697                 /* we have the last child going to low power */
 698                 (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0);
 699         }
 700         mutex_exit(HUBD_MUTEX(hubd));
 701 }
 702 
 703 
 704 /*
 705  * given a child dip, locate its port number
 706  */
 707 static usb_port_t
 708 hubd_child_dip2port(hubd_t *hubd, dev_info_t *dip)
 709 {
 710         usb_port_t      port;
 711 
 712         mutex_enter(HUBD_MUTEX(hubd));
 713         for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) {
 714                 if (hubd->h_children_dips[port] == dip) {
 715 
 716                         break;
 717                 }
 718         }
 719         ASSERT(port <= hubd->h_hub_descr.bNbrPorts);
 720         mutex_exit(HUBD_MUTEX(hubd));
 721 
 722         return (port);
 723 }
 724 
 725 
 726 /*
 727  * if the hub can be put into low power mode, return success
 728  * NOTE: suspend here means going to lower power, not CPR suspend.
 729  */
 730 static int
 731 hubd_can_suspend(hubd_t *hubd)
 732 {
 733         hub_power_t     *hubpm;
 734         int             total_power = 0;
 735         usb_port_t      port;
 736 
 737         hubpm = hubd->h_hubpm;
 738 
 739         if (DEVI_IS_DETACHING(hubd->h_dip)) {
 740 
 741                 return (USB_SUCCESS);
 742         }
 743 
 744         /*
 745          * Don't go to lower power if haven't been at full power for enough
 746          * time to let hotplug thread kickoff.
 747          */
 748         if (gethrtime() < (hubpm->hubp_time_at_full_power +
 749             hubpm->hubp_min_pm_threshold)) {
 750 
 751                 return (USB_FAILURE);
 752         }
 753 
 754         for (port = 1; (total_power == 0) &&
 755             (port <= hubd->h_hub_descr.bNbrPorts); port++) {
 756                 total_power += hubpm->hubp_child_pwrstate[port];
 757         }
 758 
 759         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
 760             "hubd_can_suspend: %d", total_power);
 761 
 762         return (total_power ? USB_FAILURE : USB_SUCCESS);
 763 }
 764 
 765 
 766 /*
 767  * resume port depending on current device state
 768  */
 769 static int
 770 hubd_resume_port(hubd_t *hubd, usb_port_t port)
 771 {
 772         int             rval, retry;
 773         usb_cr_t        completion_reason;
 774         usb_cb_flags_t  cb_flags;
 775         uint16_t        status;
 776         uint16_t        change;
 777         int             retval = USB_FAILURE;
 778 
 779         mutex_enter(HUBD_MUTEX(hubd));
 780 
 781         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
 782             "hubd_resume_port: port=%d state=0x%x (%s)", port,
 783             hubd->h_dev_state, usb_str_dev_state(hubd->h_dev_state));
 784 
 785         switch (hubd->h_dev_state) {
 786         case USB_DEV_HUB_CHILD_PWRLVL:
 787                 /*
 788                  * This could be a bus ctl for a port other than the one
 789                  * that has a remote wakeup condition. So check.
 790                  */
 791                 if ((hubd->h_port_state[port] & PORT_STATUS_PSS) == 0) {
 792                         /* the port isn't suspended, so don't resume */
 793                         retval = USB_SUCCESS;
 794 
 795                         USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
 796                             "hubd_resume_port: port=%d not suspended", port);
 797 
 798                         break;
 799                 }
 800                 /*
 801                  * Device has initiated a wakeup.
 802                  * Issue a ClearFeature(PortSuspend)
 803                  */
 804                 mutex_exit(HUBD_MUTEX(hubd));
 805                 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
 806                     hubd->h_default_pipe,
 807                     HUB_HANDLE_PORT_FEATURE_TYPE,
 808                     USB_REQ_CLEAR_FEATURE,
 809                     CFS_PORT_SUSPEND,
 810                     port,
 811                     0, NULL, 0,
 812                     &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
 813                         USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
 814                             "ClearFeature(PortSuspend) fails "
 815                             "rval=%d cr=%d cb=0x%x", rval,
 816                             completion_reason, cb_flags);
 817                 }
 818                 mutex_enter(HUBD_MUTEX(hubd));
 819 
 820                 /* either way ack changes on the port */
 821                 (void) hubd_determine_port_status(hubd, port,
 822                     &status, &change, PORT_CHANGE_PSSC);
 823                 retval = USB_SUCCESS;
 824 
 825                 break;
 826         case USB_DEV_HUB_STATE_RECOVER:
 827                 /*
 828                  * When hubd's connect event callback posts a connect
 829                  * event to its child, it results in this busctl call
 830                  * which is valid
 831                  */
 832                 /* FALLTHRU */
 833         case USB_DEV_ONLINE:
 834                 if (((hubd->h_port_state[port] & PORT_STATUS_CCS) == 0) ||
 835                     ((hubd->h_port_state[port] & PORT_STATUS_PSS) == 0)) {
 836                         /*
 837                          * the port isn't suspended, or connected
 838                          * so don't resume
 839                          */
 840                         retval = USB_SUCCESS;
 841 
 842                         USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
 843                             "hubd_resume_port: port=%d not suspended", port);
 844 
 845                         break;
 846                 }
 847                 /*
 848                  * prevent kicking off the hotplug thread
 849                  */
 850                 hubd->h_hotplug_thread++;
 851                 hubd_stop_polling(hubd);
 852 
 853                 /* Now ClearFeature(PortSuspend) */
 854                 for (retry = 0; retry < HUBD_SUS_RES_RETRY; retry++) {
 855                         mutex_exit(HUBD_MUTEX(hubd));
 856                         rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
 857                             hubd->h_default_pipe,
 858                             HUB_HANDLE_PORT_FEATURE_TYPE,
 859                             USB_REQ_CLEAR_FEATURE,
 860                             CFS_PORT_SUSPEND,
 861                             port,
 862                             0, NULL, 0,
 863                             &completion_reason, &cb_flags, 0);
 864                         mutex_enter(HUBD_MUTEX(hubd));
 865                         if (rval != USB_SUCCESS) {
 866                                 USB_DPRINTF_L2(DPRINT_MASK_PM,
 867                                     hubd->h_log_handle,
 868                                     "ClearFeature(PortSuspend) fails"
 869                                     "rval=%d cr=%d cb=0x%x", rval,
 870                                     completion_reason, cb_flags);
 871                         } else {
 872                                 /*
 873                                  * As per spec section 11.9 and 7.1.7.7
 874                                  * hub need to provide at least 20ms of
 875                                  * resume signalling, and s/w provide 10ms of
 876                                  * recovery time before accessing the port.
 877                                  */
 878                                 mutex_exit(HUBD_MUTEX(hubd));
 879                                 delay(drv_usectohz(40000));
 880                                 mutex_enter(HUBD_MUTEX(hubd));
 881                                 (void) hubd_determine_port_status(hubd, port,
 882                                     &status, &change, PORT_CHANGE_PSSC);
 883 
 884                                 if ((status & PORT_STATUS_PSS) == 0) {
 885                                         /* the port did finally resume */
 886                                         retval = USB_SUCCESS;
 887 
 888                                         break;
 889                                 }
 890                         }
 891                 }
 892 
 893                 /* allow hotplug thread again */
 894                 hubd->h_hotplug_thread--;
 895                 hubd_start_polling(hubd, 0);
 896 
 897                 break;
 898         case USB_DEV_DISCONNECTED:
 899                 /* Ignore - NO Operation */
 900                 retval = USB_SUCCESS;
 901 
 902                 break;
 903         case USB_DEV_SUSPENDED:
 904         case USB_DEV_PWRED_DOWN:
 905         default:
 906                 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
 907                     "Improper state for port Resume");
 908 
 909                 break;
 910         }
 911         mutex_exit(HUBD_MUTEX(hubd));
 912 
 913         return (retval);
 914 }
 915 
 916 
 917 /*
 918  * suspend port depending on device state
 919  */
 920 static int
 921 hubd_suspend_port(hubd_t *hubd, usb_port_t port)
 922 {
 923         int             rval, retry;
 924         int             retval = USB_FAILURE;
 925         usb_cr_t        completion_reason;
 926         usb_cb_flags_t  cb_flags;
 927         uint16_t        status;
 928         uint16_t        change;
 929 
 930         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
 931             "hubd_suspend_port: port=%d", port);
 932 
 933         mutex_enter(HUBD_MUTEX(hubd));
 934 
 935         switch (hubd->h_dev_state) {
 936         case USB_DEV_HUB_STATE_RECOVER:
 937                 /*
 938                  * When hubd's connect event callback posts a connect
 939                  * event to its child, it results in this busctl call
 940                  * which is valid
 941                  */
 942                 /* FALLTHRU */
 943         case USB_DEV_HUB_CHILD_PWRLVL:
 944                 /*
 945                  * When one child is resuming, the other could timeout
 946                  * and go to low power mode, which is valid
 947                  */
 948                 /* FALLTHRU */
 949         case USB_DEV_ONLINE:
 950                 hubd->h_hotplug_thread++;
 951                 hubd_stop_polling(hubd);
 952 
 953                 /*
 954                  * Some devices start an unprovoked resume.  According to spec,
 955                  * normal resume time for port is 10ms.  Wait for double that
 956                  * time, then check to be sure port is really suspended.
 957                  */
 958                 for (retry = 0; retry < HUBD_SUS_RES_RETRY; retry++) {
 959                         /* Now SetFeature(PortSuspend) */
 960                         mutex_exit(HUBD_MUTEX(hubd));
 961                         if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
 962                             hubd->h_default_pipe,
 963                             HUB_HANDLE_PORT_FEATURE_TYPE,
 964                             USB_REQ_SET_FEATURE,
 965                             CFS_PORT_SUSPEND,
 966                             port,
 967                             0, NULL, 0,
 968                             &completion_reason, &cb_flags, 0)) !=
 969                             USB_SUCCESS) {
 970                                 USB_DPRINTF_L2(DPRINT_MASK_PM,
 971                                     hubd->h_log_handle,
 972                                     "SetFeature(PortSuspend) fails"
 973                                     "rval=%d cr=%d cb=0x%x",
 974                                     rval, completion_reason, cb_flags);
 975                         }
 976 
 977                         /*
 978                          * some devices start an unprovoked resume
 979                          * wait and check port status after some time
 980                          */
 981                         delay(drv_usectohz(20000));
 982 
 983                         /* either ways ack changes on the port */
 984                         mutex_enter(HUBD_MUTEX(hubd));
 985                         (void) hubd_determine_port_status(hubd, port,
 986                             &status, &change, PORT_CHANGE_PSSC);
 987                         if (status & PORT_STATUS_PSS) {
 988                                 /* the port is indeed suspended */
 989                                 retval = USB_SUCCESS;
 990 
 991                                 break;
 992                         } else {
 993                                 USB_DPRINTF_L0(DPRINT_MASK_PM,
 994                                     hubd->h_log_handle,
 995                                     "hubdi: port%d failed to be suspended!",
 996                                     port);
 997                         }
 998                 }
 999 
1000                 hubd->h_hotplug_thread--;
1001                 hubd_start_polling(hubd, 0);
1002 
1003                 break;
1004 
1005         case USB_DEV_DISCONNECTED:
1006                 /* Ignore - No Operation */
1007                 retval = USB_SUCCESS;
1008 
1009                 break;
1010 
1011         case USB_DEV_SUSPENDED:
1012         case USB_DEV_PWRED_DOWN:
1013         default:
1014                 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
1015                     "Improper state for port Suspend");
1016 
1017                 break;
1018         }
1019         mutex_exit(HUBD_MUTEX(hubd));
1020 
1021         return (retval);
1022 }
1023 
1024 
1025 /*
1026  * child post attach/detach notifications
1027  */
1028 static void
1029 hubd_post_attach(hubd_t *hubd, usb_port_t port, struct attachspec *as)
1030 {
1031         dev_info_t      *dip;
1032 
1033         USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
1034             "hubd_post_attach: port=%d result=%d",
1035             port, as->result);
1036 
1037         if (as->result == DDI_SUCCESS) {
1038                 /*
1039                  * Check if the child created wants to be power managed.
1040                  * If yes, the childs power level gets automatically tracked
1041                  * by DDI_CTLOPS_POWER busctl.
1042                  * If no, we set power of the new child by default
1043                  * to USB_DEV_OS_FULL_PWR. Because we should never suspend.
1044                  */
1045                 mutex_enter(HUBD_MUTEX(hubd));
1046                 dip = hubd->h_children_dips[port];
1047                 mutex_exit(HUBD_MUTEX(hubd));
1048                 if (DEVI(dip)->devi_pm_info == NULL) {
1049                         hubd_set_child_pwrlvl(hubd, port, USB_DEV_OS_FULL_PWR);
1050                 }
1051         }
1052 }
1053 
1054 
1055 static void
1056 hubd_post_detach(hubd_t *hubd, usb_port_t port, struct detachspec *ds)
1057 {
1058         USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
1059             "hubd_post_detach: port=%d result=%d", port, ds->result);
1060 
1061         /*
1062          * if the device is successfully detached and is the
1063          * last device to detach, mark component as idle
1064          */
1065         mutex_enter(HUBD_MUTEX(hubd));
1066         if (ds->result == DDI_SUCCESS) {
1067                 usba_device_t   *usba_device = hubd->h_usba_devices[port];
1068                 dev_info_t      *pdip = hubd->h_dip;
1069                 mutex_exit(HUBD_MUTEX(hubd));
1070 
1071                 usba_hubdi_incr_power_budget(pdip, usba_device);
1072 
1073                 /*
1074                  * We set power of the detached child
1075                  * to 0, so that we can suspend if all
1076                  * our children are gone
1077                  */
1078                 hubd_set_child_pwrlvl(hubd, port, USB_DEV_OS_PWR_OFF);
1079 
1080                 /* check for leaks on detaching */
1081                 if ((usba_device) && (ds->cmd == DDI_DETACH)) {
1082                         usba_check_for_leaks(usba_device);
1083                 }
1084         } else {
1085                 mutex_exit(HUBD_MUTEX(hubd));
1086         }
1087 }
1088 
1089 
1090 /*
1091  * hubd_post_power
1092  *      After the child's power entry point has been called
1093  *      we record its power level in our local struct.
1094  *      If the device has powered off, we suspend port
1095  */
1096 static int
1097 hubd_post_power(hubd_t *hubd, usb_port_t port, pm_bp_child_pwrchg_t *bpc,
1098     int result)
1099 {
1100         int     retval = USB_SUCCESS;
1101 
1102         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1103             "hubd_post_power: port=%d", port);
1104 
1105         if (result == DDI_SUCCESS) {
1106 
1107                 /* record this power in our local struct */
1108                 hubd_set_child_pwrlvl(hubd, port, bpc->bpc_nlevel);
1109 
1110                 if (bpc->bpc_nlevel == USB_DEV_OS_PWR_OFF) {
1111 
1112                         /* now suspend the port */
1113                         retval = hubd_suspend_port(hubd, port);
1114                 } else if (bpc->bpc_nlevel == USB_DEV_OS_FULL_PWR) {
1115 
1116                         /* make sure the port is resumed */
1117                         retval = hubd_resume_port(hubd, port);
1118                 }
1119         } else {
1120 
1121                 /* record old power in our local struct */
1122                 hubd_set_child_pwrlvl(hubd, port, bpc->bpc_olevel);
1123 
1124                 if (bpc->bpc_olevel == USB_DEV_OS_PWR_OFF) {
1125 
1126                         /*
1127                          * As this device failed to transition from
1128                          * power off state, suspend the port again
1129                          */
1130                         retval = hubd_suspend_port(hubd, port);
1131                 }
1132         }
1133 
1134         return (retval);
1135 }
1136 
1137 
1138 /*
1139  * bus ctl notifications are handled here, the rest goes up to root hub/hcd
1140  */
1141 static int
1142 usba_hubdi_bus_ctl(dev_info_t *dip,
1143         dev_info_t      *rdip,
1144         ddi_ctl_enum_t  op,
1145         void            *arg,
1146         void            *result)
1147 {
1148         usba_device_t *hub_usba_device = usba_get_usba_device(rdip);
1149         dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip;
1150         struct attachspec *as;
1151         struct detachspec *ds;
1152         hubd_t          *hubd;
1153         usb_port_t      port;
1154         int             circ, rval;
1155         int             retval = DDI_FAILURE;
1156 
1157         hubd = hubd_get_soft_state(dip);
1158 
1159         mutex_enter(HUBD_MUTEX(hubd));
1160 
1161         /* flag that we are currently running bus_ctl */
1162         hubd->h_bus_ctls++;
1163         mutex_exit(HUBD_MUTEX(hubd));
1164 
1165         USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1166             "usba_hubdi_bus_ctl:\n\t"
1167             "dip=0x%p, rdip=0x%p, op=0x%x, arg=0x%p",
1168             (void *)dip, (void *)rdip, op, arg);
1169 
1170         switch (op) {
1171         case DDI_CTLOPS_ATTACH:
1172                 as = (struct attachspec *)arg;
1173                 port = hubd_child_dip2port(hubd, rdip);
1174 
1175                 /* there is nothing to do at resume time */
1176                 if (as->cmd == DDI_RESUME) {
1177                         break;
1178                 }
1179 
1180                 /* serialize access */
1181                 ndi_devi_enter(hubd->h_dip, &circ);
1182 
1183                 switch (as->when) {
1184                 case DDI_PRE:
1185                         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1186                             "DDI_PRE DDI_CTLOPS_ATTACH: dip=%p, port=%d",
1187                             (void *)rdip, port);
1188 
1189                         mutex_enter(HUBD_MUTEX(hubd));
1190                         hubd->h_port_state[port] |= HUBD_CHILD_ATTACHING;
1191 
1192                         /* Go busy here.  Matching idle is DDI_POST case. */
1193                         (void) hubd_pm_busy_component(hubd, dip, 0);
1194                         mutex_exit(HUBD_MUTEX(hubd));
1195 
1196                         /*
1197                          * if we suspended the port previously
1198                          * because child went to low power state, and
1199                          * someone unloaded the driver, the port would
1200                          * still be suspended and needs to be resumed
1201                          */
1202                         rval = hubd_resume_port(hubd, port);
1203                         if (rval == USB_SUCCESS) {
1204                                 retval = DDI_SUCCESS;
1205                         }
1206 
1207                         break;
1208                 case DDI_POST:
1209                         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1210                             "DDI_POST DDI_CTLOPS_ATTACH: dip=%p, port=%d",
1211                             (void *)rdip, port);
1212 
1213                         mutex_enter(HUBD_MUTEX(hubd));
1214                         hubd->h_port_state[port] &= ~HUBD_CHILD_ATTACHING;
1215                         mutex_exit(HUBD_MUTEX(hubd));
1216 
1217                         hubd_post_attach(hubd, port, (struct attachspec *)arg);
1218                         retval = DDI_SUCCESS;
1219                         mutex_enter(HUBD_MUTEX(hubd));
1220 
1221                         /* Matching idle call for DDI_PRE busy call. */
1222                         (void) hubd_pm_idle_component(hubd, dip, 0);
1223                         mutex_exit(HUBD_MUTEX(hubd));
1224                 }
1225                 ndi_devi_exit(hubd->h_dip, circ);
1226 
1227                 break;
1228         case DDI_CTLOPS_DETACH:
1229                 ds = (struct detachspec *)arg;
1230                 port = hubd_child_dip2port(hubd, rdip);
1231 
1232                 /* there is nothing to do at suspend time */
1233                 if (ds->cmd == DDI_SUSPEND) {
1234                         break;
1235                 }
1236 
1237                 /* serialize access */
1238                 ndi_devi_enter(hubd->h_dip, &circ);
1239 
1240                 switch (ds->when) {
1241                 case DDI_PRE:
1242                         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1243                             "DDI_PRE DDI_CTLOPS_DETACH: dip=%p port=%d",
1244                             (void *)rdip, port);
1245 
1246                         mutex_enter(HUBD_MUTEX(hubd));
1247                         hubd->h_port_state[port] |= HUBD_CHILD_DETACHING;
1248 
1249                         /* Go busy here.  Matching idle is DDI_POST case. */
1250                         (void) hubd_pm_busy_component(hubd, dip, 0);
1251 
1252                         mutex_exit(HUBD_MUTEX(hubd));
1253                         retval = DDI_SUCCESS;
1254 
1255                         break;
1256                 case DDI_POST:
1257                         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1258                             "DDI_POST DDI_CTLOPS_DETACH: dip=%p port=%d",
1259                             (void *)rdip, port);
1260 
1261                         mutex_enter(HUBD_MUTEX(hubd));
1262                         hubd->h_port_state[port] &= ~HUBD_CHILD_DETACHING;
1263                         mutex_exit(HUBD_MUTEX(hubd));
1264 
1265                         /* Matching idle call for DDI_PRE busy call. */
1266                         hubd_post_detach(hubd, port, (struct detachspec *)arg);
1267                         retval = DDI_SUCCESS;
1268                         mutex_enter(HUBD_MUTEX(hubd));
1269                         (void) hubd_pm_idle_component(hubd, dip, 0);
1270                         mutex_exit(HUBD_MUTEX(hubd));
1271 
1272                         break;
1273                 }
1274                 ndi_devi_exit(hubd->h_dip, circ);
1275 
1276                 break;
1277         default:
1278                 retval = usba_bus_ctl(root_hub_dip, rdip, op, arg, result);
1279         }
1280 
1281         /* decrement bus_ctls count */
1282         mutex_enter(HUBD_MUTEX(hubd));
1283         hubd->h_bus_ctls--;
1284         ASSERT(hubd->h_bus_ctls >= 0);
1285         mutex_exit(HUBD_MUTEX(hubd));
1286 
1287         return (retval);
1288 }
1289 
1290 /*
1291  * hubd_config_one:
1292  *      enumerate one child according to 'port'
1293  */
1294 
1295 static boolean_t
1296 hubd_config_one(hubd_t *hubd, int port)
1297 {
1298         uint16_t        status, change;
1299         dev_info_t      *hdip = hubd->h_dip;
1300         dev_info_t      *rh_dip = hubd->h_usba_device->usb_root_hub_dip;
1301         boolean_t       online_child = B_FALSE, found = B_FALSE;
1302         int             prh_circ, rh_circ, circ;
1303 
1304         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
1305             "hubd_config_one:  started, hubd_reset_port = 0x%x", port);
1306 
1307         ndi_hold_devi(hdip); /* so we don't race with detach */
1308 
1309         /*
1310          * this ensures one config activity per system at a time.
1311          * we enter the parent PCI node to have this serialization.
1312          * this also excludes ioctls and deathrow thread
1313          */
1314         ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ);
1315         ndi_devi_enter(rh_dip, &rh_circ);
1316 
1317         /* exclude other threads */
1318         ndi_devi_enter(hdip, &circ);
1319         mutex_enter(HUBD_MUTEX(hubd));
1320 
1321         hubd_pm_busy_component(hubd, hubd->h_dip, 0);
1322 
1323         if (!hubd->h_children_dips[port]) {
1324 
1325                 (void) hubd_determine_port_status(hubd, port,
1326                     &status, &change, HUBD_ACK_ALL_CHANGES);
1327 
1328                 if (status & PORT_STATUS_CCS) {
1329                         online_child |= (hubd_handle_port_connect(hubd,
1330                             port) == USB_SUCCESS);
1331                         found = online_child;
1332                 }
1333         } else {
1334                 found = B_TRUE;
1335         }
1336 
1337         mutex_exit(HUBD_MUTEX(hubd));
1338 
1339         ndi_devi_exit(hdip, circ);
1340         ndi_devi_exit(rh_dip, rh_circ);
1341         ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ);
1342 
1343         if (online_child) {
1344                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
1345                     "hubd_config_one: onlining child");
1346 
1347                 (void) ndi_devi_online(hubd->h_dip, 0);
1348         }
1349 
1350         mutex_enter(HUBD_MUTEX(hubd));
1351 
1352         (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0);
1353 
1354         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
1355             "hubd_config_one: exit");
1356 
1357         mutex_exit(HUBD_MUTEX(hubd));
1358 
1359         ndi_rele_devi(hdip);
1360 
1361         return (found);
1362 }
1363 
1364 /*
1365  * bus enumeration entry points
1366  */
1367 static int
1368 hubd_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
1369     void *arg, dev_info_t **child)
1370 {
1371         hubd_t  *hubd = hubd_get_soft_state(dip);
1372         int     rval, circ;
1373         long port;
1374 
1375         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1376             "hubd_bus_config: op=%d", op);
1377 
1378         if (hubdi_bus_config_debug) {
1379                 flag |= NDI_DEVI_DEBUG;
1380         }
1381 
1382         if (op == BUS_CONFIG_ONE) {
1383                 boolean_t found;
1384                 char cname[80];
1385                 char *name, *addr;
1386 
1387                 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
1388                     "hubd_bus_config: op=%d (BUS_CONFIG_ONE)", op);
1389 
1390                 (void) snprintf(cname, 80, "%s", (char *)arg);
1391                 /* split name into "name@addr" parts */
1392                 i_ddi_parse_name(cname, &name, &addr, NULL);
1393                 if (addr && *addr) {
1394                         (void) ddi_strtol(addr, NULL, 16, &port);
1395                 } else {
1396                         return (NDI_FAILURE);
1397                 }
1398 
1399                 found = hubd_config_one(hubd, port);
1400 
1401                 if (found == 0) {
1402                         return (NDI_FAILURE);
1403                 }
1404 
1405         }
1406         ndi_devi_enter(hubd->h_dip, &circ);
1407         rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0);
1408         ndi_devi_exit(hubd->h_dip, circ);
1409 
1410         return (rval);
1411 }
1412 
1413 
1414 static int
1415 hubd_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
1416     void *arg)
1417 {
1418         hubd_t          *hubd = hubd_get_soft_state(dip);
1419         dev_info_t      *cdip;
1420         usb_port_t      port;
1421         int             circ;
1422         int             rval;
1423 
1424         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1425             "hubd_bus_unconfig: op=%d", op);
1426 
1427         if (hubdi_bus_config_debug) {
1428                 flag |= NDI_DEVI_DEBUG;
1429         }
1430 
1431         if ((op == BUS_UNCONFIG_ALL) && (flag & NDI_AUTODETACH) == 0) {
1432                 flag |= NDI_DEVI_REMOVE;
1433         }
1434 
1435         /* serialize access */
1436         ndi_devi_enter(dip, &circ);
1437 
1438         rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
1439 
1440         /* logically zap children's list */
1441         mutex_enter(HUBD_MUTEX(hubd));
1442         for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) {
1443                 hubd->h_port_state[port] |= HUBD_CHILD_ZAP;
1444         }
1445         mutex_exit(HUBD_MUTEX(hubd));
1446 
1447         /* fill in what's left */
1448         for (cdip = ddi_get_child(dip); cdip;
1449             cdip = ddi_get_next_sibling(cdip)) {
1450                 usba_device_t *usba_device = usba_get_usba_device(cdip);
1451 
1452                 if (usba_device == NULL) {
1453 
1454                         continue;
1455                 }
1456                 mutex_enter(HUBD_MUTEX(hubd));
1457                 port = usba_device->usb_port;
1458                 hubd->h_children_dips[port] = cdip;
1459                 hubd->h_port_state[port] &= ~HUBD_CHILD_ZAP;
1460                 mutex_exit(HUBD_MUTEX(hubd));
1461         }
1462 
1463         /* physically zap the children we didn't find */
1464         mutex_enter(HUBD_MUTEX(hubd));
1465         for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) {
1466                 if (hubd->h_port_state[port] &   HUBD_CHILD_ZAP) {
1467                         /* zap the dip and usba_device structure as well */
1468                         hubd_free_usba_device(hubd, hubd->h_usba_devices[port]);
1469                         hubd->h_children_dips[port] = NULL;
1470                         hubd->h_port_state[port] &= ~HUBD_CHILD_ZAP;
1471                 }
1472         }
1473         mutex_exit(HUBD_MUTEX(hubd));
1474 
1475         ndi_devi_exit(dip, circ);
1476 
1477         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1478             "hubd_bus_unconfig: rval=%d", rval);
1479 
1480         return (rval);
1481 }
1482 
1483 
1484 /* bus_power entry point */
1485 static int
1486 hubd_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op,
1487     void *arg, void *result)
1488 {
1489         hubd_t          *hubd;
1490         int             rval, pwrup_res;
1491         usb_port_t      port;
1492         int             retval = DDI_FAILURE;
1493         pm_bp_child_pwrchg_t    *bpc;
1494         pm_bp_nexus_pwrup_t     bpn;
1495 
1496         hubd = hubd_get_soft_state(dip);
1497 
1498         USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1499             "hubd_bus_power: dip=%p, impl_arg=%p, power_op=%d, arg=%p, "
1500             "result=%d\n", (void *)dip, impl_arg, op, arg, *(int *)result);
1501 
1502         bpc = (pm_bp_child_pwrchg_t *)arg;
1503 
1504         mutex_enter(HUBD_MUTEX(hubd));
1505         hubd->h_bus_pwr++;
1506         mutex_exit(HUBD_MUTEX(hubd));
1507 
1508         switch (op) {
1509         case BUS_POWER_PRE_NOTIFICATION:
1510                 port = hubd_child_dip2port(hubd, bpc->bpc_dip);
1511                 USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1512                     "hubd_bus_power: BUS_POWER_PRE_NOTIFICATION, port=%d",
1513                     port);
1514 
1515                 /* go to full power if we are powered down */
1516                 mutex_enter(HUBD_MUTEX(hubd));
1517 
1518                 /*
1519                  * If this case completes normally, idle will be in
1520                  * hubd_bus_power / BUS_POWER_POST_NOTIFICATION
1521                  */
1522                 hubd_pm_busy_component(hubd, dip, 0);
1523 
1524                 /*
1525                  * raise power only if we have created the components
1526                  * and are currently in low power
1527                  */
1528                 if ((hubd->h_dev_state == USB_DEV_PWRED_DOWN) &&
1529                     hubd->h_hubpm->hubp_wakeup_enabled) {
1530                         mutex_exit(HUBD_MUTEX(hubd));
1531 
1532                         bpn.bpn_comp = 0;
1533                         bpn.bpn_dip = dip;
1534                         bpn.bpn_level = USB_DEV_OS_FULL_PWR;
1535                         bpn.bpn_private = bpc->bpc_private;
1536 
1537                         rval = pm_busop_bus_power(dip, impl_arg,
1538                             BUS_POWER_NEXUS_PWRUP, (void *)&bpn,
1539                             (void *)&pwrup_res);
1540 
1541                         if (rval != DDI_SUCCESS || pwrup_res != DDI_SUCCESS) {
1542                                 mutex_enter(HUBD_MUTEX(hubd));
1543                                 hubd_pm_idle_component(hubd, dip, 0);
1544                                 mutex_exit(HUBD_MUTEX(hubd));
1545 
1546                                 break;
1547                         }
1548                         mutex_enter(HUBD_MUTEX(hubd));
1549                 }
1550 
1551                 /* indicate that child is changing power level */
1552                 hubd->h_port_state[port] |= HUBD_CHILD_PWRLVL_CHNG;
1553                 mutex_exit(HUBD_MUTEX(hubd));
1554 
1555                 if ((bpc->bpc_olevel == 0) &&
1556                     (bpc->bpc_nlevel > bpc->bpc_olevel)) {
1557                         /*
1558                          * this child is transitioning from power off
1559                          * to power on state - resume port
1560                          */
1561                         rval = hubd_resume_port(hubd, port);
1562                         if (rval == USB_SUCCESS) {
1563                                 retval = DDI_SUCCESS;
1564                         } else {
1565                                 /* reset this flag on failure */
1566                                 mutex_enter(HUBD_MUTEX(hubd));
1567                                 hubd->h_port_state[port] &=
1568                                     ~HUBD_CHILD_PWRLVL_CHNG;
1569                                 hubd_pm_idle_component(hubd, dip, 0);
1570                                 mutex_exit(HUBD_MUTEX(hubd));
1571                         }
1572                 } else {
1573                         retval = DDI_SUCCESS;
1574                 }
1575 
1576                 break;
1577         case BUS_POWER_POST_NOTIFICATION:
1578                 port = hubd_child_dip2port(hubd, bpc->bpc_dip);
1579                 USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1580                     "hubd_bus_power: BUS_POWER_POST_NOTIFICATION, port=%d",
1581                     port);
1582 
1583                 mutex_enter(HUBD_MUTEX(hubd));
1584                 hubd->h_port_state[port] &= ~HUBD_CHILD_PWRLVL_CHNG;
1585                 mutex_exit(HUBD_MUTEX(hubd));
1586 
1587                 /* record child's pwr and suspend port if required */
1588                 rval = hubd_post_power(hubd, port, bpc, *(int *)result);
1589                 if (rval == USB_SUCCESS) {
1590 
1591                         retval = DDI_SUCCESS;
1592                 }
1593 
1594                 mutex_enter(HUBD_MUTEX(hubd));
1595 
1596                 /*
1597                  * Matching idle for the busy in
1598                  * hubd_bus_power / BUS_POWER_PRE_NOTIFICATION
1599                  */
1600                 hubd_pm_idle_component(hubd, dip, 0);
1601 
1602                 mutex_exit(HUBD_MUTEX(hubd));
1603 
1604                 break;
1605         default:
1606                 retval = pm_busop_bus_power(dip, impl_arg, op, arg, result);
1607 
1608                 break;
1609         }
1610 
1611         mutex_enter(HUBD_MUTEX(hubd));
1612         hubd->h_bus_pwr--;
1613         mutex_exit(HUBD_MUTEX(hubd));
1614 
1615         return (retval);
1616 }
1617 
1618 
1619 /*
1620  * functions to handle power transition for OS levels 0 -> 3
1621  */
1622 static int
1623 hubd_pwrlvl0(hubd_t *hubd)
1624 {
1625         hub_power_t     *hubpm;
1626 
1627         /* We can't power down if hotplug thread is running */
1628         if (hubd->h_hotplug_thread || hubd->h_hubpm->hubp_busy_pm ||
1629             (hubd_can_suspend(hubd) == USB_FAILURE)) {
1630 
1631                 return (USB_FAILURE);
1632         }
1633 
1634         switch (hubd->h_dev_state) {
1635         case USB_DEV_ONLINE:
1636                 hubpm = hubd->h_hubpm;
1637 
1638                 /*
1639                  * To avoid race with bus_power pre_notify on check over
1640                  * dev_state, we need to correctly set the dev state
1641                  * before the mutex is dropped in stop polling.
1642                  */
1643                 hubd->h_dev_state = USB_DEV_PWRED_DOWN;
1644                 hubpm->hubp_current_power = USB_DEV_OS_PWR_OFF;
1645 
1646                 /*
1647                  * if we are the root hub, do not stop polling
1648                  * otherwise, we will never see a resume
1649                  */
1650                 if (usba_is_root_hub(hubd->h_dip)) {
1651                         /* place holder to implement Global Suspend */
1652                         USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
1653                             "Global Suspend: Not Yet Implemented");
1654                 } else {
1655                         hubd_stop_polling(hubd);
1656                 }
1657 
1658                 /* Issue USB D3 command to the device here */
1659                 (void) usb_set_device_pwrlvl3(hubd->h_dip);
1660 
1661                 break;
1662         case USB_DEV_DISCONNECTED:
1663         case USB_DEV_SUSPENDED:
1664         case USB_DEV_PWRED_DOWN:
1665         default:
1666 
1667                 break;
1668         }
1669 
1670         return (USB_SUCCESS);
1671 }
1672 
1673 
1674 /* ARGSUSED */
1675 static int
1676 hubd_pwrlvl1(hubd_t *hubd)
1677 {
1678         /* Issue USB D2 command to the device here */
1679         (void) usb_set_device_pwrlvl2(hubd->h_dip);
1680 
1681         return (USB_FAILURE);
1682 }
1683 
1684 
1685 /* ARGSUSED */
1686 static int
1687 hubd_pwrlvl2(hubd_t *hubd)
1688 {
1689         /* Issue USB D1 command to the device here */
1690         (void) usb_set_device_pwrlvl1(hubd->h_dip);
1691 
1692         return (USB_FAILURE);
1693 }
1694 
1695 
1696 static int
1697 hubd_pwrlvl3(hubd_t *hubd)
1698 {
1699         hub_power_t     *hubpm;
1700         int             rval;
1701 
1702         USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, "hubd_pwrlvl3");
1703 
1704         hubpm = hubd->h_hubpm;
1705         switch (hubd->h_dev_state) {
1706         case USB_DEV_PWRED_DOWN:
1707                 ASSERT(hubpm->hubp_current_power == USB_DEV_OS_PWR_OFF);
1708                 if (usba_is_root_hub(hubd->h_dip)) {
1709                         /* implement global resume here */
1710                         USB_DPRINTF_L2(DPRINT_MASK_PM,
1711                             hubd->h_log_handle,
1712                             "Global Resume: Not Yet Implemented");
1713                 }
1714                 /* Issue USB D0 command to the device here */
1715                 rval = usb_set_device_pwrlvl0(hubd->h_dip);
1716                 ASSERT(rval == USB_SUCCESS);
1717                 hubd->h_dev_state = USB_DEV_ONLINE;
1718                 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR;
1719                 hubpm->hubp_time_at_full_power = gethrtime();
1720                 hubd_start_polling(hubd, 0);
1721 
1722                 /* FALLTHRU */
1723         case USB_DEV_ONLINE:
1724                 /* we are already in full power */
1725 
1726                 /* FALLTHRU */
1727         case USB_DEV_DISCONNECTED:
1728         case USB_DEV_SUSPENDED:
1729                 /*
1730                  * PM framework tries to put you in full power
1731                  * during system shutdown. If we are disconnected
1732                  * return success. Also, we should not change state
1733                  * when we are disconnected or suspended or about to
1734                  * transition to that state
1735                  */
1736 
1737                 return (USB_SUCCESS);
1738         default:
1739                 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
1740                     "hubd_pwrlvl3: Illegal dev_state=%d", hubd->h_dev_state);
1741 
1742                 return (USB_FAILURE);
1743         }
1744 }
1745 
1746 
1747 /* power entry point */
1748 /* ARGSUSED */
1749 int
1750 usba_hubdi_power(dev_info_t *dip, int comp, int level)
1751 {
1752         hubd_t          *hubd;
1753         hub_power_t     *hubpm;
1754         int             retval;
1755         int             circ;
1756 
1757         hubd = hubd_get_soft_state(dip);
1758         USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1759             "usba_hubdi_power: level=%d", level);
1760 
1761         ndi_devi_enter(dip, &circ);
1762 
1763         mutex_enter(HUBD_MUTEX(hubd));
1764         hubpm = hubd->h_hubpm;
1765 
1766         /* check if we are transitioning to a legal power level */
1767         if (USB_DEV_PWRSTATE_OK(hubpm->hubp_pwr_states, level)) {
1768                 USB_DPRINTF_L2(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1769                     "usba_hubdi_power: illegal power level=%d "
1770                     "hubp_pwr_states=0x%x", level, hubpm->hubp_pwr_states);
1771                 mutex_exit(HUBD_MUTEX(hubd));
1772 
1773                 ndi_devi_exit(dip, circ);
1774 
1775                 return (DDI_FAILURE);
1776         }
1777 
1778         switch (level) {
1779         case USB_DEV_OS_PWR_OFF:
1780                 retval = hubd_pwrlvl0(hubd);
1781 
1782                 break;
1783         case USB_DEV_OS_PWR_1:
1784                 retval = hubd_pwrlvl1(hubd);
1785 
1786                 break;
1787         case USB_DEV_OS_PWR_2:
1788                 retval = hubd_pwrlvl2(hubd);
1789 
1790                 break;
1791         case USB_DEV_OS_FULL_PWR:
1792                 retval = hubd_pwrlvl3(hubd);
1793 
1794                 break;
1795         }
1796         mutex_exit(HUBD_MUTEX(hubd));
1797 
1798         ndi_devi_exit(dip, circ);
1799 
1800         return ((retval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
1801 }
1802 
1803 
1804 /* power entry point for the root hub */
1805 int
1806 usba_hubdi_root_hub_power(dev_info_t *dip, int comp, int level)
1807 {
1808         return (usba_hubdi_power(dip, comp, level));
1809 }
1810 
1811 
1812 /*
1813  * standard driver entry points support code
1814  */
1815 int
1816 usba_hubdi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1817 {
1818         int                     instance = ddi_get_instance(dip);
1819         hubd_t                  *hubd = NULL;
1820         int                     i, rval;
1821         int                     minor;
1822         uint8_t                 ports_count;
1823         char                    *log_name = NULL;
1824         const char              *root_hub_drvname;
1825         usb_ep_data_t           *ep_data;
1826         usba_device_t           *child_ud = NULL;
1827         usb_dev_descr_t         *usb_dev_descr;
1828         usb_port_status_t       parent_port_status, child_port_status;
1829 
1830         USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubdi_log_handle,
1831             "hubd_attach instance %d, cmd=0x%x", instance, cmd);
1832 
1833         switch (cmd) {
1834         case DDI_ATTACH:
1835 
1836                 break;
1837         case DDI_RESUME:
1838                 hubd_cpr_resume(dip);
1839 
1840                 return (DDI_SUCCESS);
1841         default:
1842                 return (DDI_FAILURE);
1843         }
1844 
1845         /*
1846          * Allocate softc information.
1847          */
1848         if (usba_is_root_hub(dip)) {
1849                 /* soft state has already been allocated */
1850                 hubd = hubd_get_soft_state(dip);
1851                 minor = HUBD_IS_ROOT_HUB;
1852 
1853                 /* generate readable labels for different root hubs */
1854                 root_hub_drvname = ddi_driver_name(dip);
1855                 if (strcmp(root_hub_drvname, "ehci") == 0) {
1856                         log_name = "eusb";
1857                 } else if (strcmp(root_hub_drvname, "uhci") == 0) {
1858                         log_name = "uusb";
1859                 } else {
1860                         /* std. for ohci */
1861                         log_name = "usb";
1862                 }
1863         } else {
1864                 rval = ddi_soft_state_zalloc(hubd_statep, instance);
1865                 minor = 0;
1866 
1867                 if (rval != DDI_SUCCESS) {
1868                         USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle,
1869                             "cannot allocate soft state (%d)", instance);
1870                         goto fail;
1871                 }
1872 
1873                 hubd = hubd_get_soft_state(dip);
1874                 if (hubd == NULL) {
1875                         goto fail;
1876                 }
1877         }
1878 
1879         hubd->h_log_handle = usb_alloc_log_hdl(dip, log_name, &hubd_errlevel,
1880             &hubd_errmask, &hubd_instance_debug, 0);
1881 
1882         hubd->h_usba_device  = child_ud = usba_get_usba_device(dip);
1883         hubd->h_dip          = dip;
1884         hubd->h_instance     = instance;
1885 
1886         mutex_enter(&child_ud->usb_mutex);
1887         child_port_status = child_ud->usb_port_status;
1888         usb_dev_descr = child_ud->usb_dev_descr;
1889         parent_port_status = (child_ud->usb_hs_hub_usba_dev) ?
1890             child_ud->usb_hs_hub_usba_dev->usb_port_status : 0;
1891         mutex_exit(&child_ud->usb_mutex);
1892 
1893         if ((child_port_status == USBA_FULL_SPEED_DEV) &&
1894             (parent_port_status == USBA_HIGH_SPEED_DEV) &&
1895             (usb_dev_descr->bcdUSB == 0x100)) {
1896                 USB_DPRINTF_L0(DPRINT_MASK_ATTA, hubd->h_log_handle,
1897                     "Use of a USB1.0 hub behind a high speed port may "
1898                     "cause unexpected failures");
1899         }
1900 
1901         hubd->h_pipe_policy.pp_max_async_reqs = 1;
1902 
1903         /* register with USBA as client driver */
1904         if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
1905                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
1906                     "client attach failed");
1907 
1908                 goto fail;
1909         }
1910 
1911         if (usb_get_dev_data(dip, &hubd->h_dev_data,
1912             USB_PARSE_LVL_IF, 0) != USB_SUCCESS) {
1913                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
1914                     "cannot get dev_data");
1915 
1916                 goto fail;
1917         }
1918 
1919         if ((ep_data = usb_lookup_ep_data(dip, hubd->h_dev_data,
1920             hubd->h_dev_data->dev_curr_if, 0, 0,
1921             (uint_t)USB_EP_ATTR_INTR, (uint_t)USB_EP_DIR_IN)) == NULL) {
1922                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
1923                     "no interrupt IN endpoint found");
1924 
1925                 goto fail;
1926         }
1927 
1928         hubd->h_ep1_descr = ep_data->ep_descr;
1929         hubd->h_default_pipe = hubd->h_dev_data->dev_default_ph;
1930 
1931         mutex_init(HUBD_MUTEX(hubd), NULL, MUTEX_DRIVER,
1932             hubd->h_dev_data->dev_iblock_cookie);
1933         cv_init(&hubd->h_cv_reset_port, NULL, CV_DRIVER, NULL);
1934         cv_init(&hubd->h_cv_hotplug_dev, NULL, CV_DRIVER, NULL);
1935 
1936         hubd->h_init_state |= HUBD_LOCKS_DONE;
1937 
1938         usb_free_descr_tree(dip, hubd->h_dev_data);
1939 
1940         /*
1941          * register this hub instance with usba
1942          */
1943         rval = usba_hubdi_register(dip, 0);
1944         if (rval != USB_SUCCESS) {
1945                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
1946                     "usba_hubdi_register failed");
1947                 goto fail;
1948         }
1949 
1950         mutex_enter(HUBD_MUTEX(hubd));
1951         hubd->h_init_state |= HUBD_HUBDI_REGISTERED;
1952         hubd->h_dev_state = USB_DEV_ONLINE;
1953         mutex_exit(HUBD_MUTEX(hubd));
1954 
1955         /* now create components to power manage this device */
1956         hubd_create_pm_components(dip, hubd);
1957 
1958         /*
1959          * Event handling: definition and registration
1960          *
1961          * first the  definition:
1962          * get event handle
1963          */
1964         (void) ndi_event_alloc_hdl(dip, 0, &hubd->h_ndi_event_hdl, NDI_SLEEP);
1965 
1966         /* bind event set to the handle */
1967         if (ndi_event_bind_set(hubd->h_ndi_event_hdl, &hubd_ndi_events,
1968             NDI_SLEEP)) {
1969                 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle,
1970                     "binding event set failed");
1971 
1972                 goto fail;
1973         }
1974 
1975         /* event registration */
1976         if (hubd_register_events(hubd) != USB_SUCCESS) {
1977                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
1978                     "hubd_register_events failed");
1979 
1980                 goto fail;
1981         }
1982 
1983         mutex_enter(HUBD_MUTEX(hubd));
1984         hubd->h_init_state |= HUBD_EVENTS_REGISTERED;
1985 
1986         if ((hubd_get_hub_descriptor(hubd)) != USB_SUCCESS) {
1987                 mutex_exit(HUBD_MUTEX(hubd));
1988 
1989                 goto fail;
1990         }
1991 
1992         if (ddi_prop_exists(DDI_DEV_T_ANY, dip,
1993             (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
1994             "hub-ignore-power-budget") == 1) {
1995                 hubd->h_ignore_pwr_budget = B_TRUE;
1996         } else {
1997                 hubd->h_ignore_pwr_budget = B_FALSE;
1998 
1999                 /* initialize hub power budget variables */
2000                 if (hubd_init_power_budget(hubd) != USB_SUCCESS) {
2001                         USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2002                             "hubd_init_power_budget failed");
2003                         mutex_exit(HUBD_MUTEX(hubd));
2004 
2005                         goto fail;
2006                 }
2007         }
2008 
2009         /* initialize and create children */
2010         if (hubd_check_ports(hubd) != USB_SUCCESS) {
2011                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2012                     "hubd_check_ports failed");
2013                 mutex_exit(HUBD_MUTEX(hubd));
2014 
2015                 goto fail;
2016         }
2017 
2018         /*
2019          * create cfgadm nodes
2020          */
2021         hubd->h_ancestry_str = (char *)kmem_zalloc(HUBD_APID_NAMELEN, KM_SLEEP);
2022         hubd_get_ancestry_str(hubd);
2023 
2024         USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2025             "#ports=0x%x", hubd->h_hub_descr.bNbrPorts);
2026 
2027         for (i = 1; i <= hubd->h_hub_descr.bNbrPorts; i++) {
2028                 char ap_name[HUBD_APID_NAMELEN];
2029 
2030                 (void) snprintf(ap_name, HUBD_APID_NAMELEN, "%s%d",
2031                     hubd->h_ancestry_str, i);
2032                 USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2033                     "ap_name=%s", ap_name);
2034 
2035                 if (ddi_create_minor_node(dip, ap_name, S_IFCHR, instance,
2036                     DDI_NT_USB_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
2037                         USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2038                             "cannot create attachment point node (%d)",
2039                             instance);
2040                         mutex_exit(HUBD_MUTEX(hubd));
2041 
2042                         goto fail;
2043                 }
2044         }
2045 
2046         ports_count = hubd->h_hub_descr.bNbrPorts;
2047         mutex_exit(HUBD_MUTEX(hubd));
2048 
2049         /* create minor nodes */
2050         if (ddi_create_minor_node(dip, "hubd", S_IFCHR,
2051             instance | minor, DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
2052 
2053                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2054                     "cannot create devctl minor node (%d)", instance);
2055 
2056                 goto fail;
2057         }
2058 
2059         mutex_enter(HUBD_MUTEX(hubd));
2060         hubd->h_init_state |= HUBD_MINOR_NODE_CREATED;
2061         mutex_exit(HUBD_MUTEX(hubd));
2062 
2063         if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
2064             "usb-port-count", ports_count) != DDI_PROP_SUCCESS) {
2065                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2066                     "usb-port-count update failed");
2067         }
2068 
2069         /*
2070          * host controller driver has already reported this dev
2071          * if we are the root hub
2072          */
2073         if (!usba_is_root_hub(dip)) {
2074                 ddi_report_dev(dip);
2075         }
2076 
2077         /* enable deathrow thread */
2078         hubd->h_cleanup_enabled = B_TRUE;
2079         mutex_enter(HUBD_MUTEX(hubd));
2080         hubd_pm_idle_component(hubd, dip, 0);
2081         mutex_exit(HUBD_MUTEX(hubd));
2082 
2083         return (DDI_SUCCESS);
2084 
2085 fail:
2086         {
2087                 char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
2088 
2089                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle,
2090                     "cannot attach %s", ddi_pathname(dip, pathname));
2091 
2092                 kmem_free(pathname, MAXPATHLEN);
2093         }
2094 
2095         mutex_enter(HUBD_MUTEX(hubd));
2096         hubd_pm_idle_component(hubd, dip, 0);
2097         mutex_exit(HUBD_MUTEX(hubd));
2098 
2099         if (hubd) {
2100                 rval = hubd_cleanup(dip, hubd);
2101                 if (rval != USB_SUCCESS) {
2102                         USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle,
2103                             "failure to complete cleanup after attach failure");
2104                 }
2105         }
2106 
2107         return (DDI_FAILURE);
2108 }
2109 
2110 
2111 int
2112 usba_hubdi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2113 {
2114         hubd_t  *hubd = hubd_get_soft_state(dip);
2115         int     rval;
2116 
2117         USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2118             "hubd_detach: cmd=0x%x", cmd);
2119 
2120         switch (cmd) {
2121         case DDI_DETACH:
2122                 rval = hubd_cleanup(dip, hubd);
2123 
2124                 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
2125         case DDI_SUSPEND:
2126                 rval = hubd_cpr_suspend(hubd);
2127 
2128                 return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
2129         default:
2130                 return (DDI_FAILURE);
2131         }
2132 }
2133 
2134 
2135 /*
2136  * hubd_setdevaddr
2137  *      set the device addrs on this port
2138  */
2139 static int
2140 hubd_setdevaddr(hubd_t *hubd, usb_port_t port)
2141 {
2142         int             rval;
2143         usb_cr_t        completion_reason;
2144         usb_cb_flags_t  cb_flags;
2145         usb_pipe_handle_t ph;
2146         dev_info_t      *child_dip = NULL;
2147         uchar_t         address = 0;
2148         usba_device_t   *usba_device;
2149         int             retry = 0;
2150         long            time_delay;
2151 
2152         USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2153             "hubd_setdevaddr: port=%d", port);
2154 
2155         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
2156 
2157         child_dip = hubd->h_children_dips[port];
2158         address = hubd->h_usba_devices[port]->usb_addr;
2159         usba_device = hubd->h_usba_devices[port];
2160 
2161         /* close the default pipe with addr x */
2162         mutex_exit(HUBD_MUTEX(hubd));
2163         ph = usba_get_dflt_pipe_handle(child_dip);
2164         usb_pipe_close(child_dip, ph,
2165             USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
2166         mutex_enter(HUBD_MUTEX(hubd));
2167 
2168         /*
2169          * As this device has been reset, temporarily
2170          * assign the default address
2171          */
2172         mutex_enter(&usba_device->usb_mutex);
2173         address = usba_device->usb_addr;
2174         usba_device->usb_addr = USBA_DEFAULT_ADDR;
2175         mutex_exit(&usba_device->usb_mutex);
2176 
2177         mutex_exit(HUBD_MUTEX(hubd));
2178 
2179         time_delay = drv_usectohz(hubd_device_delay / 20);
2180         for (retry = 0; retry < hubd_retry_enumerate; retry++) {
2181 
2182                 /* open child's default pipe with USBA_DEFAULT_ADDR */
2183                 if (usb_pipe_open(child_dip, NULL, NULL,
2184                     USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph) !=
2185                     USB_SUCCESS) {
2186                         USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2187                             "hubd_setdevaddr: Unable to open default pipe");
2188 
2189                         break;
2190                 }
2191 
2192                 /* Set the address of the device */
2193                 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
2194                     USB_DEV_REQ_HOST_TO_DEV,
2195                     USB_REQ_SET_ADDRESS,        /* bRequest */
2196                     address,                    /* wValue */
2197                     0,                          /* wIndex */
2198                     0,                          /* wLength */
2199                     NULL, 0,
2200                     &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
2201                         USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2202                             "hubd_setdevaddr(%d): rval=%d cr=%d cb_fl=0x%x",
2203                             retry, rval, completion_reason, cb_flags);
2204                 }
2205 
2206                 usb_pipe_close(child_dip, ph,
2207                     USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
2208 
2209                 if (rval == USB_SUCCESS) {
2210 
2211                         break;
2212                 }
2213 
2214                 delay(time_delay);
2215         }
2216 
2217         /* Reset to the old address */
2218         mutex_enter(&usba_device->usb_mutex);
2219         usba_device->usb_addr = address;
2220         mutex_exit(&usba_device->usb_mutex);
2221         mutex_enter(HUBD_MUTEX(hubd));
2222 
2223         usba_clear_data_toggle(usba_device);
2224 
2225         return (rval);
2226 }
2227 
2228 
2229 /*
2230  * hubd_setdevconfig
2231  *      set the device addrs on this port
2232  */
2233 static void
2234 hubd_setdevconfig(hubd_t *hubd, usb_port_t port)
2235 {
2236         int                     rval;
2237         usb_cr_t                completion_reason;
2238         usb_cb_flags_t          cb_flags;
2239         usb_pipe_handle_t       ph;
2240         dev_info_t              *child_dip = NULL;
2241         usba_device_t           *usba_device = NULL;
2242         uint16_t                config_value;
2243 
2244         USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2245             "hubd_setdevconfig: port=%d", port);
2246 
2247         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
2248 
2249         child_dip = hubd->h_children_dips[port];
2250         usba_device = hubd->h_usba_devices[port];
2251         config_value = hubd->h_usba_devices[port]->usb_cfg_value;
2252         mutex_exit(HUBD_MUTEX(hubd));
2253 
2254         /* open the default control pipe */
2255         if ((rval = usb_pipe_open(child_dip, NULL, NULL,
2256             USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) ==
2257             USB_SUCCESS) {
2258 
2259                 /* Set the default configuration of the device */
2260                 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
2261                     USB_DEV_REQ_HOST_TO_DEV,
2262                     USB_REQ_SET_CFG,            /* bRequest */
2263                     config_value,               /* wValue */
2264                     0,                          /* wIndex */
2265                     0,                          /* wLength */
2266                     NULL, 0,
2267                     &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
2268                         USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2269                             "hubd_setdevconfig: set device config failed: "
2270                             "cr=%d cb_fl=0x%x rval=%d",
2271                             completion_reason, cb_flags, rval);
2272                 }
2273                 /*
2274                  * After setting the configuration, we make this default
2275                  * control pipe persistent, so that it gets re-opened
2276                  * on posting a connect event
2277                  */
2278                 usba_persistent_pipe_close(usba_device);
2279         } else {
2280                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2281                     "pipe open fails: rval=%d", rval);
2282         }
2283         mutex_enter(HUBD_MUTEX(hubd));
2284 }
2285 
2286 
2287 /*ARGSUSED*/
2288 static int
2289 hubd_check_disconnected_ports(dev_info_t *dip, void *arg)
2290 {
2291         int circ;
2292         usb_port_t port;
2293         hubd_t *hubd;
2294         major_t hub_major = ddi_name_to_major("hubd");
2295         major_t hwahc_major = ddi_name_to_major("hwahc");
2296         major_t usbmid_major = ddi_name_to_major("usb_mid");
2297 
2298         /*
2299          * make sure dip is a usb hub, major of root hub is HCD
2300          * major
2301          */
2302         if (!usba_is_root_hub(dip)) {
2303                 if (ddi_driver_major(dip) == usbmid_major) {
2304                         /*
2305                          * need to walk the children since it might be a
2306                          * HWA device
2307                          */
2308 
2309                         return (DDI_WALK_CONTINUE);
2310                 }
2311 
2312                 /* TODO: DWA device may also need special handling */
2313 
2314                 if (((ddi_driver_major(dip) != hub_major) &&
2315                     (ddi_driver_major(dip) != hwahc_major)) ||
2316                     !i_ddi_devi_attached(dip)) {
2317 
2318                         return (DDI_WALK_PRUNECHILD);
2319                 }
2320         }
2321 
2322         hubd = hubd_get_soft_state(dip);
2323         if (hubd == NULL) {
2324 
2325                 return (DDI_WALK_PRUNECHILD);
2326         }
2327 
2328         /* walk child list and remove nodes with flag DEVI_DEVICE_REMOVED */
2329         ndi_devi_enter(dip, &circ);
2330 
2331         if (ddi_driver_major(dip) != hwahc_major) {
2332                 /* for normal usb hub or root hub */
2333                 mutex_enter(HUBD_MUTEX(hubd));
2334                 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) {
2335                         dev_info_t *cdip = hubd->h_children_dips[port];
2336 
2337                         if (cdip == NULL || DEVI_IS_DEVICE_REMOVED(cdip) == 0) {
2338 
2339                                 continue;
2340                         }
2341 
2342                         (void) hubd_delete_child(hubd, port, NDI_DEVI_REMOVE,
2343                             B_TRUE);
2344                 }
2345                 mutex_exit(HUBD_MUTEX(hubd));
2346         } else {
2347                 /* for HWA */
2348                 if (hubd->h_cleanup_child != NULL) {
2349                         if (hubd->h_cleanup_child(dip) != USB_SUCCESS) {
2350                                 ndi_devi_exit(dip, circ);
2351 
2352                                 return (DDI_WALK_PRUNECHILD);
2353                         }
2354                 } else {
2355                         ndi_devi_exit(dip, circ);
2356 
2357                         return (DDI_WALK_PRUNECHILD);
2358                 }
2359         }
2360 
2361         ndi_devi_exit(dip, circ);
2362 
2363         /* skip siblings of root hub */
2364         if (usba_is_root_hub(dip)) {
2365 
2366                 return (DDI_WALK_PRUNESIB);
2367         }
2368 
2369         return (DDI_WALK_CONTINUE);
2370 }
2371 
2372 
2373 /*
2374  * this thread will walk all children under the root hub for this
2375  * USB bus instance and attempt to remove them
2376  */
2377 static void
2378 hubd_root_hub_cleanup_thread(void *arg)
2379 {
2380         int circ;
2381         hubd_t *root_hubd = (hubd_t *)arg;
2382         dev_info_t *rh_dip = root_hubd->h_dip;
2383 #ifndef __lock_lint
2384         callb_cpr_t cprinfo;
2385 
2386         CALLB_CPR_INIT(&cprinfo, HUBD_MUTEX(root_hubd), callb_generic_cpr,
2387             "USB root hub");
2388 #endif
2389 
2390         for (;;) {
2391                 /* don't race with detach */
2392                 ndi_hold_devi(rh_dip);
2393 
2394                 mutex_enter(HUBD_MUTEX(root_hubd));
2395                 root_hubd->h_cleanup_needed = 0;
2396                 mutex_exit(HUBD_MUTEX(root_hubd));
2397 
2398                 (void) devfs_clean(rh_dip, NULL, 0);
2399 
2400                 ndi_devi_enter(ddi_get_parent(rh_dip), &circ);
2401                 ddi_walk_devs(rh_dip, hubd_check_disconnected_ports,
2402                     NULL);
2403 #ifdef __lock_lint
2404                 (void) hubd_check_disconnected_ports(rh_dip, NULL);
2405 #endif
2406                 ndi_devi_exit(ddi_get_parent(rh_dip), circ);
2407 
2408                 /* quit if we are not enabled anymore */
2409                 mutex_enter(HUBD_MUTEX(root_hubd));
2410                 if ((root_hubd->h_cleanup_enabled == B_FALSE) ||
2411                     (root_hubd->h_cleanup_needed == B_FALSE)) {
2412                         root_hubd->h_cleanup_active = B_FALSE;
2413                         mutex_exit(HUBD_MUTEX(root_hubd));
2414                         ndi_rele_devi(rh_dip);
2415 
2416                         break;
2417                 }
2418                 mutex_exit(HUBD_MUTEX(root_hubd));
2419                 ndi_rele_devi(rh_dip);
2420 
2421 #ifndef __lock_lint
2422                 mutex_enter(HUBD_MUTEX(root_hubd));
2423                 CALLB_CPR_SAFE_BEGIN(&cprinfo);
2424                 mutex_exit(HUBD_MUTEX(root_hubd));
2425 
2426                 delay(drv_usectohz(hubd_dip_cleanup_delay));
2427 
2428                 mutex_enter(HUBD_MUTEX(root_hubd));
2429                 CALLB_CPR_SAFE_END(&cprinfo, HUBD_MUTEX(root_hubd));
2430                 mutex_exit(HUBD_MUTEX(root_hubd));
2431 #endif
2432         }
2433 
2434 #ifndef __lock_lint
2435         mutex_enter(HUBD_MUTEX(root_hubd));
2436         CALLB_CPR_EXIT(&cprinfo);
2437 #endif
2438 }
2439 
2440 
2441 void
2442 hubd_schedule_cleanup(dev_info_t *rh_dip)
2443 {
2444         hubd_t  *root_hubd;
2445 
2446         /*
2447          * The usb_root_hub_dip pointer for the child hub of the WUSB
2448          * wire adapter class device points to the wire adapter, not
2449          * the root hub. Need to find the real root hub dip so that
2450          * the cleanup thread only starts from the root hub.
2451          */
2452         while (!usba_is_root_hub(rh_dip)) {
2453                 root_hubd = hubd_get_soft_state(rh_dip);
2454                 if (root_hubd != NULL) {
2455                         rh_dip = root_hubd->h_usba_device->usb_root_hub_dip;
2456                         if (rh_dip == NULL) {
2457                                 USB_DPRINTF_L2(DPRINT_MASK_ATTA,
2458                                     root_hubd->h_log_handle,
2459                                     "hubd_schedule_cleanup: null rh dip");
2460 
2461                                 return;
2462                         }
2463                 } else {
2464                         USB_DPRINTF_L2(DPRINT_MASK_ATTA,
2465                             root_hubd->h_log_handle,
2466                             "hubd_schedule_cleanup: cannot find root hub");
2467 
2468                         return;
2469                 }
2470         }
2471         root_hubd = hubd_get_soft_state(rh_dip);
2472 
2473         mutex_enter(HUBD_MUTEX(root_hubd));
2474         root_hubd->h_cleanup_needed = B_TRUE;
2475         if (root_hubd->h_cleanup_enabled && !(root_hubd->h_cleanup_active)) {
2476                 root_hubd->h_cleanup_active = B_TRUE;
2477                 mutex_exit(HUBD_MUTEX(root_hubd));
2478                 (void) thread_create(NULL, 0,
2479                     hubd_root_hub_cleanup_thread,
2480                     (void *)root_hubd, 0, &p0, TS_RUN,
2481                     minclsyspri);
2482         } else {
2483                 mutex_exit(HUBD_MUTEX(root_hubd));
2484         }
2485 }
2486 
2487 
2488 /*
2489  * hubd_restore_device_state:
2490  *      - set config for the hub
2491  *      - power cycle all the ports
2492  *      - for each port that was connected
2493  *              - reset port
2494  *              - assign addrs to the device on this port
2495  *      - restart polling
2496  *      - reset suspend flag
2497  */
2498 static void
2499 hubd_restore_device_state(dev_info_t *dip, hubd_t *hubd)
2500 {
2501         int             rval;
2502         int             retry;
2503         uint_t          hub_prev_state;
2504         usb_port_t      port;
2505         uint16_t        status;
2506         uint16_t        change;
2507         dev_info_t      *ch_dip;
2508         boolean_t       ehci_root_hub;
2509 
2510         USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2511             "hubd_restore_device_state:");
2512 
2513         mutex_enter(HUBD_MUTEX(hubd));
2514         hub_prev_state = hubd->h_dev_state;
2515         ASSERT(hub_prev_state != USB_DEV_PWRED_DOWN);
2516 
2517         /* First bring the device to full power */
2518         (void) hubd_pm_busy_component(hubd, dip, 0);
2519         mutex_exit(HUBD_MUTEX(hubd));
2520 
2521         (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
2522 
2523         if (!usba_is_root_hub(dip) &&
2524             (usb_check_same_device(dip, hubd->h_log_handle, USB_LOG_L0,
2525             DPRINT_MASK_HOTPLUG,
2526             USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS)) {
2527 
2528                 /* change the device state to disconnected */
2529                 mutex_enter(HUBD_MUTEX(hubd));
2530                 hubd->h_dev_state = USB_DEV_DISCONNECTED;
2531                 (void) hubd_pm_idle_component(hubd, dip, 0);
2532                 mutex_exit(HUBD_MUTEX(hubd));
2533 
2534                 return;
2535         }
2536 
2537         ehci_root_hub = (strcmp(ddi_driver_name(dip), "ehci") == 0);
2538 
2539         mutex_enter(HUBD_MUTEX(hubd));
2540         /* First turn off all port power */
2541         rval = hubd_disable_all_port_power(hubd);
2542         if (rval != USB_SUCCESS) {
2543                 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle,
2544                     "hubd_restore_device_state:"
2545                     "turning off port power failed");
2546         }
2547 
2548         /* Settling time before turning on again */
2549         mutex_exit(HUBD_MUTEX(hubd));
2550         delay(drv_usectohz(hubd_device_delay / 100));
2551         mutex_enter(HUBD_MUTEX(hubd));
2552 
2553         /* enable power on all ports so we can see connects */
2554         if (hubd_enable_all_port_power(hubd) != USB_SUCCESS) {
2555                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2556                     "hubd_restore_device_state: turn on port power failed");
2557 
2558                 /* disable whatever was enabled */
2559                 (void) hubd_disable_all_port_power(hubd);
2560 
2561                 (void) hubd_pm_idle_component(hubd, dip, 0);
2562                 mutex_exit(HUBD_MUTEX(hubd));
2563 
2564                 return;
2565         }
2566 
2567         /*
2568          * wait at least 3 frames before accessing devices
2569          * (note that delay's minimal time is one clock tick which
2570          * is 10ms unless hires_tick has been changed)
2571          */
2572         mutex_exit(HUBD_MUTEX(hubd));
2573         delay(drv_usectohz(10000));
2574         mutex_enter(HUBD_MUTEX(hubd));
2575 
2576         hubd->h_dev_state = USB_DEV_HUB_STATE_RECOVER;
2577 
2578         for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) {
2579                 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle,
2580                     "hubd_restore_device_state: port=%d", port);
2581 
2582                 /*
2583                  * the childen_dips list may have dips that have been
2584                  * already deallocated. we only get a post_detach notification
2585                  * but not a destroy notification
2586                  */
2587                 ch_dip = hubd->h_children_dips[port];
2588                 if (ch_dip) {
2589                         /* get port status */
2590                         (void) hubd_determine_port_status(hubd, port,
2591                             &status, &change, PORT_CHANGE_CSC);
2592 
2593                         /* check if it is truly connected */
2594                         if (status & PORT_STATUS_CCS) {
2595                                 /*
2596                                  * Now reset port and assign the device
2597                                  * its original address
2598                                  */
2599                                 retry = 0;
2600                                 do {
2601                                         (void) hubd_reset_port(hubd, port);
2602 
2603                                         /* required for ppx */
2604                                         (void) hubd_enable_port(hubd, port);
2605 
2606                                         if (retry) {
2607                                                 mutex_exit(HUBD_MUTEX(hubd));
2608                                                 delay(drv_usectohz(
2609                                                     hubd_device_delay/2));
2610                                                 mutex_enter(HUBD_MUTEX(hubd));
2611                                         }
2612 
2613                                         rval = hubd_setdevaddr(hubd, port);
2614                                         retry++;
2615                                 } while ((rval != USB_SUCCESS) &&
2616                                     (retry < hubd_retry_enumerate));
2617 
2618                                 hubd_setdevconfig(hubd, port);
2619 
2620                                 if (hub_prev_state == USB_DEV_DISCONNECTED) {
2621                                         /* post a connect event */
2622                                         mutex_exit(HUBD_MUTEX(hubd));
2623                                         hubd_post_event(hubd, port,
2624                                             USBA_EVENT_TAG_HOT_INSERTION);
2625                                         mutex_enter(HUBD_MUTEX(hubd));
2626                                 } else {
2627                                         /*
2628                                          * Since we have this device connected
2629                                          * mark it reinserted to prevent
2630                                          * cleanup thread from stepping in.
2631                                          */
2632                                         mutex_exit(HUBD_MUTEX(hubd));
2633                                         mutex_enter(&(DEVI(ch_dip)->devi_lock));
2634                                         DEVI_SET_DEVICE_REINSERTED(ch_dip);
2635                                         mutex_exit(&(DEVI(ch_dip)->devi_lock));
2636 
2637                                         /*
2638                                          * reopen pipes for children for
2639                                          * their DDI_RESUME
2640                                          */
2641                                         rval = usba_persistent_pipe_open(
2642                                             usba_get_usba_device(ch_dip));
2643                                         mutex_enter(HUBD_MUTEX(hubd));
2644                                         ASSERT(rval == USB_SUCCESS);
2645                                 }
2646                         } else {
2647                                 /*
2648                                  * Mark this dip for deletion as the device
2649                                  * is not physically present, and schedule
2650                                  * cleanup thread upon post resume
2651                                  */
2652                                 mutex_exit(HUBD_MUTEX(hubd));
2653 
2654                                 USB_DPRINTF_L2(DPRINT_MASK_ATTA,
2655                                     hubd->h_log_handle,
2656                                     "hubd_restore_device_state: "
2657                                     "dip=%p on port=%d marked for cleanup",
2658                                     (void *)ch_dip, port);
2659                                 mutex_enter(&(DEVI(ch_dip)->devi_lock));
2660                                 DEVI_SET_DEVICE_REMOVED(ch_dip);
2661                                 mutex_exit(&(DEVI(ch_dip)->devi_lock));
2662 
2663                                 mutex_enter(HUBD_MUTEX(hubd));
2664                         }
2665                 } else if (ehci_root_hub) {
2666                         /* get port status */
2667                         (void) hubd_determine_port_status(hubd, port,
2668                             &status, &change, PORT_CHANGE_CSC);
2669 
2670                         /* check if it is truly connected */
2671                         if (status & PORT_STATUS_CCS) {
2672                                 /*
2673                                  * reset the port to find out if we have
2674                                  * 2.0 device connected or 1.X. A 2.0
2675                                  * device will still be seen as connected,
2676                                  * while a 1.X device will switch over to
2677                                  * the companion controller.
2678                                  */
2679                                 (void) hubd_reset_port(hubd, port);
2680 
2681                                 (void) hubd_determine_port_status(hubd, port,
2682                                     &status, &change, PORT_CHANGE_CSC);
2683 
2684                                 if (status &
2685                                     (PORT_STATUS_CCS | PORT_STATUS_HSDA)) {
2686                                         /*
2687                                          * We have a USB 2.0 device
2688                                          * connected. Power cycle this port
2689                                          * so that hotplug thread can
2690                                          * enumerate this device.
2691                                          */
2692                                         (void) hubd_toggle_port(hubd, port);
2693                                 } else {
2694                                         USB_DPRINTF_L2(DPRINT_MASK_ATTA,
2695                                             hubd->h_log_handle,
2696                                             "hubd_restore_device_state: "
2697                                             "device on port %d switched over",
2698                                             port);
2699                                 }
2700                         }
2701 
2702                 }
2703         }
2704 
2705 
2706         /* if the device had remote wakeup earlier, enable it again */
2707         if (hubd->h_hubpm->hubp_wakeup_enabled) {
2708                 mutex_exit(HUBD_MUTEX(hubd));
2709                 (void) usb_handle_remote_wakeup(hubd->h_dip,
2710                     USB_REMOTE_WAKEUP_ENABLE);
2711                 mutex_enter(HUBD_MUTEX(hubd));
2712         }
2713 
2714         hubd->h_dev_state = USB_DEV_ONLINE;
2715         hubd_start_polling(hubd, 0);
2716         (void) hubd_pm_idle_component(hubd, dip, 0);
2717         mutex_exit(HUBD_MUTEX(hubd));
2718 }
2719 
2720 
2721 /*
2722  * hubd_cleanup:
2723  *      cleanup hubd and deallocate. this function is called for
2724  *      handling attach failures and detaching including dynamic
2725  *      reconfiguration. If called from attaching, it must clean
2726  *      up the whole thing and return success.
2727  */
2728 /*ARGSUSED*/
2729 static int
2730 hubd_cleanup(dev_info_t *dip, hubd_t *hubd)
2731 {
2732         int             circ, rval, old_dev_state;
2733         hub_power_t     *hubpm;
2734 #ifdef DEBUG
2735         usb_port_t      port;
2736 #endif
2737 
2738         USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2739             "hubd_cleanup:");
2740 
2741         if ((hubd->h_init_state & HUBD_LOCKS_DONE) == 0) {
2742                 goto done;
2743         }
2744 
2745         /* ensure we are the only one active */
2746         ndi_devi_enter(dip, &circ);
2747 
2748         mutex_enter(HUBD_MUTEX(hubd));
2749 
2750         /* Cleanup failure is only allowed if called from detach */
2751         if (DEVI_IS_DETACHING(dip)) {
2752                 dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip;
2753 
2754                 /*
2755                  * We are being called from detach.
2756                  * Fail immediately if the hotplug thread is running
2757                  * else set the dev_state to disconnected so that
2758                  * hotplug thread just exits without doing anything.
2759                  */
2760                 if (hubd->h_bus_ctls || hubd->h_bus_pwr ||
2761                     hubd->h_hotplug_thread) {
2762                         mutex_exit(HUBD_MUTEX(hubd));
2763                         ndi_devi_exit(dip, circ);
2764 
2765                         USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2766                             "hubd_cleanup: hotplug thread/bus ctl active "
2767                             "- failing detach");
2768 
2769                         return (USB_FAILURE);
2770                 }
2771 
2772                 /*
2773                  * if the deathrow thread is still active or about
2774                  * to become active, fail detach
2775                  * the roothup can only be detached if nexus drivers
2776                  * are unloaded or explicitly offlined
2777                  */
2778                 if (rh_dip == dip) {
2779                         if (hubd->h_cleanup_needed ||
2780                             hubd->h_cleanup_active) {
2781                                 mutex_exit(HUBD_MUTEX(hubd));
2782                                 ndi_devi_exit(dip, circ);
2783 
2784                                 USB_DPRINTF_L2(DPRINT_MASK_ATTA,
2785                                     hubd->h_log_handle,
2786                                     "hubd_cleanup: deathrow still active?"
2787                                     "- failing detach");
2788 
2789                                 return (USB_FAILURE);
2790                         }
2791                 }
2792         }
2793 
2794         old_dev_state = hubd->h_dev_state;
2795         hubd->h_dev_state = USB_DEV_DISCONNECTED;
2796 
2797         USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2798             "hubd_cleanup: stop polling");
2799         hubd_close_intr_pipe(hubd);
2800 
2801         ASSERT((hubd->h_bus_ctls || hubd->h_bus_pwr ||
2802             hubd->h_hotplug_thread) == 0);
2803         mutex_exit(HUBD_MUTEX(hubd));
2804 
2805         /*
2806          * deallocate events, if events are still registered
2807          * (ie. children still attached) then we have to fail the detach
2808          */
2809         if (hubd->h_ndi_event_hdl) {
2810 
2811                 rval = ndi_event_free_hdl(hubd->h_ndi_event_hdl);
2812                 if (DEVI_IS_ATTACHING(dip)) {
2813 
2814                         /* It must return success if attaching. */
2815                         ASSERT(rval == NDI_SUCCESS);
2816 
2817                 } else if (rval != NDI_SUCCESS) {
2818 
2819                         USB_DPRINTF_L2(DPRINT_MASK_ALL, hubd->h_log_handle,
2820                             "hubd_cleanup: ndi_event_free_hdl failed");
2821                         ndi_devi_exit(dip, circ);
2822 
2823                         return (USB_FAILURE);
2824 
2825                 }
2826         }
2827 
2828         mutex_enter(HUBD_MUTEX(hubd));
2829 
2830         if (hubd->h_init_state & HUBD_CHILDREN_CREATED) {
2831 #ifdef DEBUG
2832                 for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) {
2833                         ASSERT(hubd->h_usba_devices[port] == NULL);
2834                         ASSERT(hubd->h_children_dips[port] == NULL);
2835                 }
2836 #endif
2837                 kmem_free(hubd->h_children_dips, hubd->h_cd_list_length);
2838                 kmem_free(hubd->h_usba_devices, hubd->h_cd_list_length);
2839         }
2840 
2841         /*
2842          * Disable the event callbacks first, after this point, event
2843          * callbacks will never get called. Note we shouldn't hold
2844          * mutex while unregistering events because there may be a
2845          * competing event callback thread. Event callbacks are done
2846          * with ndi mutex held and this can cause a potential deadlock.
2847          * Note that cleanup can't fail after deregistration of events.
2848          */
2849         if (hubd->h_init_state &  HUBD_EVENTS_REGISTERED) {
2850                 mutex_exit(HUBD_MUTEX(hubd));
2851                 usb_unregister_event_cbs(dip, &hubd_events);
2852                 hubd_unregister_cpr_callback(hubd);
2853                 mutex_enter(HUBD_MUTEX(hubd));
2854         }
2855 
2856         /* restore the old dev state so that device can be put into low power */
2857         hubd->h_dev_state = old_dev_state;
2858         hubpm = hubd->h_hubpm;
2859 
2860         if ((hubpm) && (hubd->h_dev_state != USB_DEV_DISCONNECTED)) {
2861                 (void) hubd_pm_busy_component(hubd, dip, 0);
2862                 mutex_exit(HUBD_MUTEX(hubd));
2863                 if (hubd->h_hubpm->hubp_wakeup_enabled) {
2864                         /*
2865                          * Bring the hub to full power before
2866                          * issuing the disable remote wakeup command
2867                          */
2868                         (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
2869 
2870                         if ((rval = usb_handle_remote_wakeup(hubd->h_dip,
2871                             USB_REMOTE_WAKEUP_DISABLE)) != USB_SUCCESS) {
2872                                 USB_DPRINTF_L2(DPRINT_MASK_PM,
2873                                     hubd->h_log_handle,
2874                                     "hubd_cleanup: disable remote wakeup "
2875                                     "fails=%d", rval);
2876                         }
2877                 }
2878 
2879                 (void) pm_lower_power(hubd->h_dip, 0, USB_DEV_OS_PWR_OFF);
2880 
2881                 mutex_enter(HUBD_MUTEX(hubd));
2882                 (void) hubd_pm_idle_component(hubd, dip, 0);
2883         }
2884 
2885         if (hubpm) {
2886                 if (hubpm->hubp_child_pwrstate) {
2887                         kmem_free(hubpm->hubp_child_pwrstate,
2888                             MAX_PORTS + 1);
2889                 }
2890                 kmem_free(hubpm, sizeof (hub_power_t));
2891         }
2892         mutex_exit(HUBD_MUTEX(hubd));
2893 
2894         USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2895             "hubd_cleanup: freeing space");
2896 
2897         if (hubd->h_init_state & HUBD_HUBDI_REGISTERED) {
2898                 rval = usba_hubdi_unregister(dip);
2899                 ASSERT(rval == USB_SUCCESS);
2900         }
2901 
2902         if (hubd->h_init_state & HUBD_LOCKS_DONE) {
2903                 mutex_destroy(HUBD_MUTEX(hubd));
2904                 cv_destroy(&hubd->h_cv_reset_port);
2905                 cv_destroy(&hubd->h_cv_hotplug_dev);
2906         }
2907 
2908         ndi_devi_exit(dip, circ);
2909 
2910         if (hubd->h_init_state & HUBD_MINOR_NODE_CREATED) {
2911                 ddi_remove_minor_node(dip, NULL);
2912         }
2913 
2914         if (usba_is_root_hub(dip)) {
2915                 usb_pipe_close(dip, hubd->h_default_pipe,
2916                     USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
2917         }
2918 
2919 done:
2920         if (hubd->h_ancestry_str) {
2921                 kmem_free(hubd->h_ancestry_str, HUBD_APID_NAMELEN);
2922         }
2923 
2924         usb_client_detach(dip, hubd->h_dev_data);
2925 
2926         usb_free_log_hdl(hubd->h_log_handle);
2927 
2928         if (!usba_is_root_hub(dip)) {
2929                 ddi_soft_state_free(hubd_statep, ddi_get_instance(dip));
2930         }
2931 
2932         ddi_prop_remove_all(dip);
2933 
2934         return (USB_SUCCESS);
2935 }
2936 
2937 
2938 /*
2939  * hubd_determine_port_connection:
2940  *      Determine which port is in connect status but does not
2941  *      have connect status change bit set, and mark port change
2942  *      bit accordingly.
2943  *      This function is applied during hub attach time.
2944  */
2945 static usb_port_mask_t
2946 hubd_determine_port_connection(hubd_t   *hubd)
2947 {
2948         usb_port_t      port;
2949         usb_hub_descr_t *hub_descr;
2950         uint16_t        status;
2951         uint16_t        change;
2952         usb_port_mask_t port_change = 0;
2953 
2954         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
2955 
2956         hub_descr = &hubd->h_hub_descr;
2957 
2958         for (port = 1; port <= hub_descr->bNbrPorts; port++) {
2959 
2960                 (void) hubd_determine_port_status(hubd, port, &status,
2961                     &change, 0);
2962 
2963                 /* Check if port is in connect status */
2964                 if (!(status & PORT_STATUS_CCS)) {
2965 
2966                         continue;
2967                 }
2968 
2969                 /*
2970                  * Check if port Connect Status Change bit has been set.
2971                  * If already set, the connection will be handled by
2972                  * intr polling callback, not during attach.
2973                  */
2974                 if (change & PORT_CHANGE_CSC) {
2975 
2976                         continue;
2977                 }
2978 
2979                 port_change |= 1 << port;
2980         }
2981 
2982         return (port_change);
2983 }
2984 
2985 
2986 /*
2987  * hubd_check_ports:
2988  *      - get hub descriptor
2989  *      - check initial port status
2990  *      - enable power on all ports
2991  *      - enable polling on ep1
2992  */
2993 static int
2994 hubd_check_ports(hubd_t  *hubd)
2995 {
2996         int                     rval;
2997         usb_port_mask_t         port_change = 0;
2998         hubd_hotplug_arg_t      *arg;
2999 
3000         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
3001 
3002         USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
3003             "hubd_check_ports: addr=0x%x", usb_get_addr(hubd->h_dip));
3004 
3005         /*
3006          * First turn off all port power
3007          */
3008         if ((rval = hubd_disable_all_port_power(hubd)) != USB_SUCCESS) {
3009 
3010                 /* disable whatever was enabled */
3011                 (void) hubd_disable_all_port_power(hubd);
3012 
3013                 return (rval);
3014         }
3015 
3016         /*
3017          * do not switch on immediately (instantly on root hub)
3018          * and allow time to settle
3019          */
3020         mutex_exit(HUBD_MUTEX(hubd));
3021         delay(drv_usectohz(10000));
3022         mutex_enter(HUBD_MUTEX(hubd));
3023 
3024         /*
3025          * enable power on all ports so we can see connects
3026          */
3027         if ((rval = hubd_enable_all_port_power(hubd)) != USB_SUCCESS) {
3028                 /* disable whatever was enabled */
3029                 (void) hubd_disable_all_port_power(hubd);
3030 
3031                 return (rval);
3032         }
3033 
3034         /* wait at least 3 frames before accessing devices */
3035         mutex_exit(HUBD_MUTEX(hubd));
3036         delay(drv_usectohz(10000));
3037         mutex_enter(HUBD_MUTEX(hubd));
3038 
3039         /*
3040          * allocate arrays for saving the dips of each child per port
3041          *
3042          * ports go from 1 - n, allocate 1 more entry
3043          */
3044         hubd->h_cd_list_length =
3045             (sizeof (dev_info_t **)) * (hubd->h_hub_descr.bNbrPorts + 1);
3046 
3047         hubd->h_children_dips = (dev_info_t **)kmem_zalloc(
3048             hubd->h_cd_list_length, KM_SLEEP);
3049         hubd->h_usba_devices = (usba_device_t **)kmem_zalloc(
3050             hubd->h_cd_list_length, KM_SLEEP);
3051 
3052         hubd->h_init_state |= HUBD_CHILDREN_CREATED;
3053 
3054         mutex_exit(HUBD_MUTEX(hubd));
3055         arg = (hubd_hotplug_arg_t *)kmem_zalloc(
3056             sizeof (hubd_hotplug_arg_t), KM_SLEEP);
3057         mutex_enter(HUBD_MUTEX(hubd));
3058 
3059         if ((rval = hubd_open_intr_pipe(hubd)) != USB_SUCCESS) {
3060                 kmem_free(arg, sizeof (hubd_hotplug_arg_t));
3061 
3062                 return (rval);
3063         }
3064 
3065         hubd_start_polling(hubd, 0);
3066 
3067         /*
3068          * Some hub devices, like the embedded hub in the CKS ErgoMagic
3069          * keyboard, may only have connection status bit set, but not
3070          * have connect status change bit set when a device has been
3071          * connected to its downstream port before the hub is enumerated.
3072          * Then when the hub is in enumeration, the devices connected to
3073          * it cannot be detected by the intr pipe and won't be enumerated.
3074          * We need to check such situation here and enumerate the downstream
3075          * devices for such hubs.
3076          */
3077         port_change = hubd_determine_port_connection(hubd);
3078 
3079         if (port_change) {
3080                 hubd_pm_busy_component(hubd, hubd->h_dip, 0);
3081 
3082                 arg->hubd = hubd;
3083                 arg->hotplug_during_attach = B_TRUE;
3084                 hubd->h_port_change |= port_change;
3085 
3086                 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
3087                     "hubd_check_ports: port change=0x%x, need to connect",
3088                     hubd->h_port_change);
3089 
3090                 if (usb_async_req(hubd->h_dip, hubd_hotplug_thread,
3091                     (void *)arg, 0) == USB_SUCCESS) {
3092                         hubd->h_hotplug_thread++;
3093                 } else {
3094                         /* mark this device as idle */
3095                         hubd_pm_idle_component(hubd, hubd->h_dip, 0);
3096                         kmem_free(arg, sizeof (hubd_hotplug_arg_t));
3097                 }
3098         } else {
3099                 kmem_free(arg, sizeof (hubd_hotplug_arg_t));
3100         }
3101 
3102         USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
3103             "hubd_check_ports done");
3104 
3105         return (USB_SUCCESS);
3106 }
3107 
3108 
3109 /*
3110  * hubd_get_hub_descriptor:
3111  */
3112 static int
3113 hubd_get_hub_descriptor(hubd_t *hubd)
3114 {
3115         usb_hub_descr_t *hub_descr = &hubd->h_hub_descr;
3116         mblk_t          *data = NULL;
3117         usb_cr_t        completion_reason;
3118         usb_cb_flags_t  cb_flags;
3119         uint16_t        length;
3120         int             rval;
3121         usb_req_attrs_t attr = 0;
3122 
3123         USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3124             "hubd_get_hub_descriptor:");
3125 
3126         if ((hubd->h_dev_data->dev_descr->idVendor == USB_HUB_INTEL_VID) &&
3127             (hubd->h_dev_data->dev_descr->idProduct == USB_HUB_INTEL_PID)) {
3128                 attr = USB_ATTRS_SHORT_XFER_OK;
3129         }
3130 
3131         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
3132         ASSERT(hubd->h_default_pipe != 0);
3133 
3134         /* get hub descriptor length first by requesting 8 bytes only */
3135         mutex_exit(HUBD_MUTEX(hubd));
3136 
3137         if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
3138             hubd->h_default_pipe,
3139             HUB_CLASS_REQ_TYPE,
3140             USB_REQ_GET_DESCR,          /* bRequest */
3141             USB_DESCR_TYPE_SETUP_HUB,   /* wValue */
3142             0,                          /* wIndex */
3143             8,                          /* wLength */
3144             &data, 0,
3145             &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
3146                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
3147                     "get hub descriptor failed: cr=%d cb_fl=0x%x rval=%d",
3148                     completion_reason, cb_flags, rval);
3149                 freemsg(data);
3150                 mutex_enter(HUBD_MUTEX(hubd));
3151 
3152                 return (rval);
3153         }
3154 
3155         length = *(data->b_rptr);
3156 
3157         if (length > 8) {
3158                 freemsg(data);
3159                 data = NULL;
3160 
3161                 /* get complete hub descriptor */
3162                 rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
3163                     hubd->h_default_pipe,
3164                     HUB_CLASS_REQ_TYPE,
3165                     USB_REQ_GET_DESCR,          /* bRequest */
3166                     USB_DESCR_TYPE_SETUP_HUB,   /* wValue */
3167                     0,                          /* wIndex */
3168                     length,                     /* wLength */
3169                     &data, attr,
3170                     &completion_reason, &cb_flags, 0);
3171 
3172                 /*
3173                  * Hub descriptor data less than 9 bytes is not valid and
3174                  * may cause trouble if we use it. See USB2.0 Tab11-13.
3175                  */
3176                 if ((rval != USB_SUCCESS) || (MBLKL(data) <= 8)) {
3177                         USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
3178                             "get hub descriptor failed: "
3179                             "cr=%d cb_fl=0x%x rval=%d, len=%ld",
3180                             completion_reason, cb_flags, rval,
3181                             (data)?MBLKL(data):0);
3182                         freemsg(data);
3183                         mutex_enter(HUBD_MUTEX(hubd));
3184 
3185                         return (rval);
3186                 }
3187         }
3188 
3189         mutex_enter(HUBD_MUTEX(hubd));
3190 
3191         /* parse the hub descriptor */
3192         /* only 32 ports are supported at present */
3193         ASSERT(*(data->b_rptr + 2) <= 32);
3194         if (usb_parse_CV_descr("cccscccccc",
3195             data->b_rptr, MBLKL(data),
3196             (void *)hub_descr, sizeof (usb_hub_descr_t)) == 0) {
3197                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
3198                     "parsing hub descriptor failed");
3199 
3200                 freemsg(data);
3201 
3202                 return (USB_FAILURE);
3203         }
3204 
3205         freemsg(data);
3206 
3207         USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
3208             "rval=0x%x bNbrPorts=0x%x wHubChars=0x%x "
3209             "PwrOn2PwrGood=0x%x HubContrCurrent=%dmA", rval,
3210             hub_descr->bNbrPorts, hub_descr->wHubCharacteristics,
3211             hub_descr->bPwrOn2PwrGood, hub_descr->bHubContrCurrent);
3212 
3213         if (hub_descr->bNbrPorts > MAX_PORTS) {
3214                 USB_DPRINTF_L0(DPRINT_MASK_ATTA, hubd->h_log_handle,
3215                     "Hub driver supports max of %d ports on hub. "
3216                     "Hence using the first %d port of %d ports available",
3217                     MAX_PORTS, MAX_PORTS, hub_descr->bNbrPorts);
3218 
3219                 hub_descr->bNbrPorts = MAX_PORTS;
3220         }
3221 
3222         return (USB_SUCCESS);
3223 }
3224 
3225 
3226 /*
3227  * hubd_get_hub_status_words:
3228  */
3229 static int
3230 hubd_get_hub_status_words(hubd_t *hubd, uint16_t *status)
3231 {
3232         usb_cr_t        completion_reason;
3233         usb_cb_flags_t  cb_flags;
3234         mblk_t          *data = NULL;
3235 
3236         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
3237 
3238         mutex_exit(HUBD_MUTEX(hubd));
3239 
3240         if (usb_pipe_sync_ctrl_xfer(hubd->h_dip, hubd->h_default_pipe,
3241             HUB_CLASS_REQ_TYPE,
3242             USB_REQ_GET_STATUS,
3243             0,
3244             0,
3245             GET_STATUS_LENGTH,
3246             &data, 0,
3247             &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
3248                 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle,
3249                     "get hub status failed: cr=%d cb=0x%x",
3250                     completion_reason, cb_flags);
3251 
3252                 if (data) {
3253                         freemsg(data);
3254                 }
3255 
3256                 mutex_enter(HUBD_MUTEX(hubd));
3257 
3258                 return (USB_FAILURE);
3259         }
3260 
3261         mutex_enter(HUBD_MUTEX(hubd));
3262 
3263         status[0] = (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
3264         status[1] = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2);
3265 
3266         USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle,
3267             "hub status=0x%x change=0x%x", status[0], status[1]);
3268 
3269         freemsg(data);
3270 
3271         return (USB_SUCCESS);
3272 }
3273 
3274 
3275 /*
3276  * hubd_open_intr_pipe:
3277  *      we read all descriptors first for curiosity and then simply
3278  *      open the pipe
3279  */
3280 static int
3281 hubd_open_intr_pipe(hubd_t      *hubd)
3282 {
3283         int                     rval;
3284 
3285         USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3286             "hubd_open_intr_pipe:");
3287 
3288         ASSERT(hubd->h_intr_pipe_state == HUBD_INTR_PIPE_IDLE);
3289 
3290         hubd->h_intr_pipe_state = HUBD_INTR_PIPE_OPENING;
3291         mutex_exit(HUBD_MUTEX(hubd));
3292 
3293         if ((rval = usb_pipe_open(hubd->h_dip,
3294             &hubd->h_ep1_descr, &hubd->h_pipe_policy,
3295             0, &hubd->h_ep1_ph)) != USB_SUCCESS) {
3296                 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle,
3297                     "open intr pipe failed (%d)", rval);
3298 
3299                 mutex_enter(HUBD_MUTEX(hubd));
3300                 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_IDLE;
3301 
3302                 return (rval);
3303         }
3304 
3305         mutex_enter(HUBD_MUTEX(hubd));
3306         hubd->h_intr_pipe_state = HUBD_INTR_PIPE_ACTIVE;
3307 
3308         USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3309             "open intr pipe succeeded, ph=0x%p", (void *)hubd->h_ep1_ph);
3310 
3311         return (USB_SUCCESS);
3312 }
3313 
3314 
3315 /*
3316  * hubd_start_polling:
3317  *      start or restart the polling
3318  */
3319 static void
3320 hubd_start_polling(hubd_t *hubd, int always)
3321 {
3322         usb_intr_req_t  *reqp;
3323         int                     rval;
3324         usb_pipe_state_t        pipe_state;
3325 
3326         USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3327             "start polling: always=%d dev_state=%d pipe_state=%d\n\t"
3328             "thread=%d ep1_ph=0x%p",
3329             always, hubd->h_dev_state, hubd->h_intr_pipe_state,
3330             hubd->h_hotplug_thread, (void *)hubd->h_ep1_ph);
3331 
3332         /*
3333          * start or restart polling on the intr pipe
3334          * only if hotplug thread is not running
3335          */
3336         if ((always == HUBD_ALWAYS_START_POLLING) ||
3337             ((hubd->h_dev_state == USB_DEV_ONLINE) &&
3338             (hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE) &&
3339             (hubd->h_hotplug_thread == 0) && hubd->h_ep1_ph)) {
3340                 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3341                     "start polling requested");
3342 
3343                 reqp = usb_alloc_intr_req(hubd->h_dip, 0, USB_FLAGS_SLEEP);
3344 
3345                 reqp->intr_client_private = (usb_opaque_t)hubd;
3346                 reqp->intr_attributes = USB_ATTRS_SHORT_XFER_OK |
3347                     USB_ATTRS_AUTOCLEARING;
3348                 reqp->intr_len = hubd->h_ep1_descr.wMaxPacketSize;
3349                 reqp->intr_cb = hubd_read_cb;
3350                 reqp->intr_exc_cb = hubd_exception_cb;
3351                 mutex_exit(HUBD_MUTEX(hubd));
3352                 if ((rval = usb_pipe_intr_xfer(hubd->h_ep1_ph, reqp,
3353                     USB_FLAGS_SLEEP)) != USB_SUCCESS) {
3354                         USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle,
3355                             "start polling failed, rval=%d", rval);
3356                         usb_free_intr_req(reqp);
3357                 }
3358 
3359                 rval = usb_pipe_get_state(hubd->h_ep1_ph, &pipe_state,
3360                     USB_FLAGS_SLEEP);
3361                 if (pipe_state != USB_PIPE_STATE_ACTIVE) {
3362                         USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
3363                             "intr pipe state=%d, rval=%d", pipe_state, rval);
3364                 }
3365                 USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3366                     "start polling request 0x%p", (void *)reqp);
3367 
3368                 mutex_enter(HUBD_MUTEX(hubd));
3369         }
3370 }
3371 
3372 
3373 /*
3374  * hubd_stop_polling
3375  *      stop polling but do not close the pipe
3376  */
3377 static void
3378 hubd_stop_polling(hubd_t *hubd)
3379 {
3380         int                     rval;
3381         usb_pipe_state_t        pipe_state;
3382 
3383         if (hubd->h_ep1_ph) {
3384                 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
3385                     "hubd_stop_polling:");
3386                 hubd->h_intr_pipe_state = HUBD_INTR_PIPE_STOPPED;
3387                 mutex_exit(HUBD_MUTEX(hubd));
3388 
3389                 usb_pipe_stop_intr_polling(hubd->h_ep1_ph, USB_FLAGS_SLEEP);
3390                 rval = usb_pipe_get_state(hubd->h_ep1_ph, &pipe_state,
3391                     USB_FLAGS_SLEEP);
3392 
3393                 if (pipe_state != USB_PIPE_STATE_IDLE) {
3394                         USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
3395                             "intr pipe state=%d, rval=%d", pipe_state, rval);
3396                 }
3397                 mutex_enter(HUBD_MUTEX(hubd));
3398                 if (hubd->h_intr_pipe_state == HUBD_INTR_PIPE_STOPPED) {
3399                         hubd->h_intr_pipe_state = HUBD_INTR_PIPE_ACTIVE;
3400                 }
3401         }
3402 }
3403 
3404 
3405 /*
3406  * hubd_close_intr_pipe:
3407  *      close the pipe (which also stops the polling
3408  *      and wait for the hotplug thread to exit
3409  */
3410 static void
3411 hubd_close_intr_pipe(hubd_t *hubd)
3412 {
3413         USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3414             "hubd_close_intr_pipe:");
3415 
3416         /*
3417          * Now that no async operation is outstanding on pipe,
3418          * we can change the state to HUBD_INTR_PIPE_CLOSING
3419          */
3420         hubd->h_intr_pipe_state = HUBD_INTR_PIPE_CLOSING;
3421 
3422         ASSERT(hubd->h_hotplug_thread == 0);
3423 
3424         if (hubd->h_ep1_ph) {
3425                 mutex_exit(HUBD_MUTEX(hubd));
3426                 usb_pipe_close(hubd->h_dip, hubd->h_ep1_ph, USB_FLAGS_SLEEP,
3427                     NULL, NULL);
3428                 mutex_enter(HUBD_MUTEX(hubd));
3429                 hubd->h_ep1_ph = NULL;
3430         }
3431 
3432         hubd->h_intr_pipe_state = HUBD_INTR_PIPE_IDLE;
3433 }
3434 
3435 
3436 /*
3437  * hubd_exception_cb
3438  *      interrupt ep1 exception callback function.
3439  *      this callback executes in taskq thread context and assumes
3440  *      autoclearing
3441  */
3442 /*ARGSUSED*/
3443 static void
3444 hubd_exception_cb(usb_pipe_handle_t pipe, usb_intr_req_t *reqp)
3445 {
3446         hubd_t          *hubd = (hubd_t *)(reqp->intr_client_private);
3447 
3448         USB_DPRINTF_L2(DPRINT_MASK_CALLBACK, hubd->h_log_handle,
3449             "hubd_exception_cb: "
3450             "req=0x%p cr=%d data=0x%p cb_flags=0x%x", (void *)reqp,
3451             reqp->intr_completion_reason, (void *)reqp->intr_data,
3452             reqp->intr_cb_flags);
3453 
3454         ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0);
3455 
3456         mutex_enter(HUBD_MUTEX(hubd));
3457         (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0);
3458 
3459         switch (reqp->intr_completion_reason) {
3460         case USB_CR_PIPE_RESET:
3461                 /* only restart polling after autoclearing */
3462                 if ((hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE) &&
3463                     (hubd->h_port_reset_wait == 0)) {
3464                         hubd_start_polling(hubd, 0);
3465                 }
3466 
3467                 break;
3468         case USB_CR_DEV_NOT_RESP:
3469         case USB_CR_STOPPED_POLLING:
3470         case USB_CR_PIPE_CLOSING:
3471         case USB_CR_UNSPECIFIED_ERR:
3472                 /* never restart polling on these conditions */
3473         default:
3474                 /* for all others, wait for the autoclearing PIPE_RESET cb */
3475 
3476                 break;
3477         }
3478 
3479         usb_free_intr_req(reqp);
3480         (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0);
3481         mutex_exit(HUBD_MUTEX(hubd));
3482 }
3483 
3484 
3485 /*
3486  * helper function to convert LE bytes to a portmask
3487  */
3488 static usb_port_mask_t
3489 hubd_mblk2portmask(mblk_t *data)
3490 {
3491         int len = min(MBLKL(data), sizeof (usb_port_mask_t));
3492         usb_port_mask_t rval = 0;
3493         int i;
3494 
3495         for (i = 0; i < len; i++) {
3496                 rval |= data->b_rptr[i] << (i * 8);
3497         }
3498 
3499         return (rval);
3500 }
3501 
3502 
3503 /*
3504  * hubd_read_cb:
3505  *      interrupt ep1 callback function
3506  *
3507  *      the status indicates just a change on the pipe with no indication
3508  *      of what the change was
3509  *
3510  *      known conditions:
3511  *              - reset port completion
3512  *              - connect
3513  *              - disconnect
3514  *
3515  *      for handling the hotplugging, create a new thread that can do
3516  *      synchronous usba calls
3517  */
3518 static void
3519 hubd_read_cb(usb_pipe_handle_t pipe, usb_intr_req_t *reqp)
3520 {
3521         hubd_t          *hubd = (hubd_t *)(reqp->intr_client_private);
3522         size_t          length;
3523         mblk_t          *data = reqp->intr_data;
3524         int             mem_flag = 0;
3525         hubd_hotplug_arg_t *arg;
3526 
3527         USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3528             "hubd_read_cb: ph=0x%p req=0x%p", (void *)pipe, (void *)reqp);
3529 
3530         ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0);
3531 
3532         /*
3533          * At present, we are not handling notification for completion of
3534          * asynchronous pipe reset, for which this data ptr could be NULL
3535          */
3536 
3537         if (data == NULL) {
3538                 usb_free_intr_req(reqp);
3539 
3540                 return;
3541         }
3542 
3543         arg = (hubd_hotplug_arg_t *)kmem_zalloc(
3544             sizeof (hubd_hotplug_arg_t), KM_SLEEP);
3545         mem_flag = 1;
3546 
3547         mutex_enter(HUBD_MUTEX(hubd));
3548 
3549         if ((hubd->h_dev_state == USB_DEV_SUSPENDED) ||
3550             (hubd->h_intr_pipe_state != HUBD_INTR_PIPE_ACTIVE)) {
3551                 mutex_exit(HUBD_MUTEX(hubd));
3552                 usb_free_intr_req(reqp);
3553                 kmem_free(arg, sizeof (hubd_hotplug_arg_t));
3554 
3555                 return;
3556         }
3557 
3558         ASSERT(hubd->h_ep1_ph == pipe);
3559 
3560         length = MBLKL(data);
3561 
3562         /*
3563          * Only look at the data and startup the hotplug thread if
3564          * there actually is data.
3565          */
3566         if (length != 0) {
3567                 usb_port_mask_t port_change = hubd_mblk2portmask(data);
3568 
3569                 /*
3570                  * if a port change was already reported and we are waiting for
3571                  * reset port completion then wake up the hotplug thread which
3572                  * should be waiting on reset port completion
3573                  *
3574                  * if there is disconnect event instead of reset completion, let
3575                  * the hotplug thread figure this out
3576                  */
3577 
3578                 /* remove the reset wait bits from the status */
3579                 hubd->h_port_change |= port_change &
3580                     ~hubd->h_port_reset_wait;
3581 
3582                 USB_DPRINTF_L3(DPRINT_MASK_CALLBACK, hubd->h_log_handle,
3583                     "port change=0x%x port_reset_wait=0x%x",
3584                     hubd->h_port_change, hubd->h_port_reset_wait);
3585 
3586                 /* there should be only one reset bit active at the time */
3587                 if (hubd->h_port_reset_wait & port_change) {
3588                         hubd->h_port_reset_wait = 0;
3589                         cv_signal(&hubd->h_cv_reset_port);
3590                 }
3591 
3592                 /*
3593                  * kick off the thread only if device is ONLINE and it is not
3594                  * during attaching or detaching
3595                  */
3596                 if ((hubd->h_dev_state == USB_DEV_ONLINE) &&
3597                     (!DEVI_IS_ATTACHING(hubd->h_dip)) &&
3598                     (!DEVI_IS_DETACHING(hubd->h_dip)) &&
3599                     (hubd->h_port_change) &&
3600                     (hubd->h_hotplug_thread == 0)) {
3601                         USB_DPRINTF_L3(DPRINT_MASK_CALLBACK, hubd->h_log_handle,
3602                             "creating hotplug thread: "
3603                             "dev_state=%d", hubd->h_dev_state);
3604 
3605                         /*
3606                          * Mark this device as busy. The will be marked idle
3607                          * if the async req fails or at the exit of  hotplug
3608                          * thread
3609                          */
3610                         (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0);
3611 
3612                         arg->hubd = hubd;
3613                         arg->hotplug_during_attach = B_FALSE;
3614 
3615                         if (usb_async_req(hubd->h_dip,
3616                             hubd_hotplug_thread,
3617                             (void *)arg, 0) == USB_SUCCESS) {
3618                                 hubd->h_hotplug_thread++;
3619                                 mem_flag = 0;
3620                         } else {
3621                                 /* mark this device as idle */
3622                                 (void) hubd_pm_idle_component(hubd,
3623                                     hubd->h_dip, 0);
3624                         }
3625                 }
3626         }
3627         mutex_exit(HUBD_MUTEX(hubd));
3628 
3629         if (mem_flag == 1) {
3630                 kmem_free(arg, sizeof (hubd_hotplug_arg_t));
3631         }
3632 
3633         usb_free_intr_req(reqp);
3634 }
3635 
3636 
3637 /*
3638  * hubd_hotplug_thread:
3639  *      handles resetting of port, and creating children
3640  *
3641  *      the ports to check are indicated in h_port_change bit mask
3642  * XXX note that one time poll doesn't work on the root hub
3643  */
3644 static void
3645 hubd_hotplug_thread(void *arg)
3646 {
3647         hubd_hotplug_arg_t *hd_arg = (hubd_hotplug_arg_t *)arg;
3648         hubd_t          *hubd = hd_arg->hubd;
3649         boolean_t       attach_flg = hd_arg->hotplug_during_attach;
3650         usb_port_t      port;
3651         uint16_t        nports;
3652         uint16_t        status, change;
3653         hub_power_t     *hubpm;
3654         dev_info_t      *hdip = hubd->h_dip;
3655         dev_info_t      *rh_dip = hubd->h_usba_device->usb_root_hub_dip;
3656         dev_info_t      *child_dip;
3657         boolean_t       online_child = B_FALSE;
3658         boolean_t       offline_child = B_FALSE;
3659         boolean_t       pwrup_child = B_FALSE;
3660         int             prh_circ, rh_circ, chld_circ, circ, old_state;
3661 
3662         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3663             "hubd_hotplug_thread:  started");
3664 
3665         /*
3666          * Before console is init'd, we temporarily block the hotplug
3667          * threads so that BUS_CONFIG_ONE through hubd_bus_config() can be
3668          * processed quickly. This reduces the time needed for vfs_mountroot()
3669          * to mount the root FS from a USB disk. And on SPARC platform,
3670          * in order to load 'consconfig' successfully after OBP is gone,
3671          * we need to check 'modrootloaded' to make sure root filesystem is
3672          * available.
3673          */
3674         while (!modrootloaded || !consconfig_console_is_ready()) {
3675                 delay(drv_usectohz(10000));
3676         }
3677 
3678         kmem_free(arg, sizeof (hubd_hotplug_arg_t));
3679 
3680         /*
3681          * if our bus power entry point is active, process the change
3682          * on the next notification of interrupt pipe
3683          */
3684         mutex_enter(HUBD_MUTEX(hubd));
3685         if (hubd->h_bus_pwr || (hubd->h_hotplug_thread > 1)) {
3686                 hubd->h_hotplug_thread--;
3687 
3688                 /* mark this device as idle */
3689                 hubd_pm_idle_component(hubd, hubd->h_dip, 0);
3690                 mutex_exit(HUBD_MUTEX(hubd));
3691 
3692                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3693                     "hubd_hotplug_thread: "
3694                     "bus_power in progress/hotplugging undesirable - quit");
3695 
3696                 return;
3697         }
3698         mutex_exit(HUBD_MUTEX(hubd));
3699 
3700         ndi_hold_devi(hdip); /* so we don't race with detach */
3701 
3702         mutex_enter(HUBD_MUTEX(hubd));
3703 
3704         /* is this the root hub? */
3705         if (hdip == rh_dip) {
3706                 if (hubd->h_dev_state == USB_DEV_PWRED_DOWN) {
3707                         hubpm = hubd->h_hubpm;
3708 
3709                         /* mark the root hub as full power */
3710                         hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR;
3711                         hubpm->hubp_time_at_full_power = gethrtime();
3712                         mutex_exit(HUBD_MUTEX(hubd));
3713 
3714                         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3715                             "hubd_hotplug_thread: call pm_power_has_changed");
3716 
3717                         (void) pm_power_has_changed(hdip, 0,
3718                             USB_DEV_OS_FULL_PWR);
3719 
3720                         mutex_enter(HUBD_MUTEX(hubd));
3721                         hubd->h_dev_state = USB_DEV_ONLINE;
3722                 }
3723 
3724         } else {
3725                 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3726                     "hubd_hotplug_thread: not root hub");
3727         }
3728 
3729         mutex_exit(HUBD_MUTEX(hubd));
3730 
3731         /*
3732          * this ensures one hotplug activity per system at a time.
3733          * we enter the parent PCI node to have this serialization.
3734          * this also excludes ioctls and deathrow thread
3735          * (a bit crude but easier to debug)
3736          */
3737         ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ);
3738         ndi_devi_enter(rh_dip, &rh_circ);
3739 
3740         /* exclude other threads */
3741         ndi_devi_enter(hdip, &circ);
3742         mutex_enter(HUBD_MUTEX(hubd));
3743 
3744         ASSERT(hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE);
3745 
3746         nports = hubd->h_hub_descr.bNbrPorts;
3747 
3748         hubd_stop_polling(hubd);
3749 
3750         while ((hubd->h_dev_state == USB_DEV_ONLINE) &&
3751             (hubd->h_port_change)) {
3752                 /*
3753                  * The 0th bit is the hub status change bit.
3754                  * handle loss of local power here
3755                  */
3756                 if (hubd->h_port_change & HUB_CHANGE_STATUS) {
3757                         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3758                             "hubd_hotplug_thread: hub status change!");
3759 
3760                         /*
3761                          * This should be handled properly.  For now,
3762                          * mask off the bit.
3763                          */
3764                         hubd->h_port_change &= ~HUB_CHANGE_STATUS;
3765 
3766                         /*
3767                          * check and ack hub status
3768                          * this causes stall conditions
3769                          * when local power is removed
3770                          */
3771                         (void) hubd_get_hub_status(hubd);
3772                 }
3773 
3774                 for (port = 1; port <= nports; port++) {
3775                         usb_port_mask_t port_mask;
3776                         boolean_t was_connected;
3777 
3778                         port_mask = 1 << port;
3779                         was_connected =
3780                             (hubd->h_port_state[port] & PORT_STATUS_CCS) &&
3781                             (hubd->h_children_dips[port]);
3782 
3783                         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3784                             "hubd_hotplug_thread: "
3785                             "port %d mask=0x%x change=0x%x connected=0x%x",
3786                             port, port_mask, hubd->h_port_change,
3787                             was_connected);
3788 
3789                         /*
3790                          * is this a port connection that changed?
3791                          */
3792                         if ((hubd->h_port_change & port_mask) == 0) {
3793 
3794                                 continue;
3795                         }
3796                         hubd->h_port_change &= ~port_mask;
3797 
3798                         /* ack all changes */
3799                         (void) hubd_determine_port_status(hubd, port,
3800                             &status, &change, HUBD_ACK_ALL_CHANGES);
3801 
3802                         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3803                             "handle port %d:\n\t"
3804                             "new status=0x%x change=0x%x was_conn=0x%x ",
3805                             port, status, change, was_connected);
3806 
3807                         /* Recover a disabled port */
3808                         if (change & PORT_CHANGE_PESC) {
3809                                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG,
3810                                     hubd->h_log_handle,
3811                                     "port%d Disabled - "
3812                                     "status=0x%x, change=0x%x",
3813                                     port, status, change);
3814 
3815                                 /*
3816                                  * if the port was connected and is still
3817                                  * connected, recover the port
3818                                  */
3819                                 if (was_connected && (status &
3820                                     PORT_STATUS_CCS)) {
3821                                         online_child |=
3822                                             (hubd_recover_disabled_port(hubd,
3823                                             port) == USB_SUCCESS);
3824                                 }
3825                         }
3826 
3827                         /*
3828                          * Now check what changed on the port
3829                          */
3830                         if ((change & PORT_CHANGE_CSC) || attach_flg) {
3831                                 if ((status & PORT_STATUS_CCS) &&
3832                                     (!was_connected)) {
3833                                         /* new device plugged in */
3834                                         online_child |=
3835                                             (hubd_handle_port_connect(hubd,
3836                                             port) == USB_SUCCESS);
3837 
3838                                 } else if ((status & PORT_STATUS_CCS) &&
3839                                     was_connected) {
3840                                         /*
3841                                          * In this case we can never be sure
3842                                          * if the device indeed got hotplugged
3843                                          * or the hub is falsely reporting the
3844                                          * change.
3845                                          */
3846                                         child_dip = hubd->h_children_dips[port];
3847 
3848                                         mutex_exit(HUBD_MUTEX(hubd));
3849                                         /*
3850                                          * this ensures we do not race with
3851                                          * other threads which are detaching
3852                                          * the child driver at the same time.
3853                                          */
3854                                         ndi_devi_enter(child_dip, &chld_circ);
3855                                         /*
3856                                          * Now check if the driver remains
3857                                          * attached.
3858                                          */
3859                                         if (i_ddi_devi_attached(child_dip)) {
3860                                                 /*
3861                                                  * first post a disconnect event
3862                                                  * to the child.
3863                                                  */
3864                                                 hubd_post_event(hubd, port,
3865                                                     USBA_EVENT_TAG_HOT_REMOVAL);
3866                                                 mutex_enter(HUBD_MUTEX(hubd));
3867 
3868                                                 /*
3869                                                  * then reset the port and
3870                                                  * recover the device
3871                                                  */
3872                                                 online_child |=
3873                                                     (hubd_handle_port_connect(
3874                                                     hubd, port) == USB_SUCCESS);
3875 
3876                                                 mutex_exit(HUBD_MUTEX(hubd));
3877                                         }
3878 
3879                                         ndi_devi_exit(child_dip, chld_circ);
3880                                         mutex_enter(HUBD_MUTEX(hubd));
3881                                 } else if (was_connected) {
3882                                         /* this is a disconnect */
3883                                         mutex_exit(HUBD_MUTEX(hubd));
3884                                         hubd_post_event(hubd, port,
3885                                             USBA_EVENT_TAG_HOT_REMOVAL);
3886                                         mutex_enter(HUBD_MUTEX(hubd));
3887 
3888                                         offline_child = B_TRUE;
3889                                 }
3890                         }
3891 
3892                         /*
3893                          * Check if any port is coming out of suspend
3894                          */
3895                         if (change & PORT_CHANGE_PSSC) {
3896                                 /* a resuming device could have disconnected */
3897                                 if (was_connected &&
3898                                     hubd->h_children_dips[port]) {
3899 
3900                                         /* device on this port resuming */
3901                                         dev_info_t *dip;
3902 
3903                                         dip = hubd->h_children_dips[port];
3904 
3905                                         /*
3906                                          * Don't raise power on detaching child
3907                                          */
3908                                         if (!DEVI_IS_DETACHING(dip)) {
3909                                                 /*
3910                                                  * As this child is not
3911                                                  * detaching, we set this
3912                                                  * flag, causing bus_ctls
3913                                                  * to stall detach till
3914                                                  * pm_raise_power returns
3915                                                  * and flag it for a deferred
3916                                                  * raise_power.
3917                                                  *
3918                                                  * pm_raise_power is deferred
3919                                                  * because we need to release
3920                                                  * the locks first.
3921                                                  */
3922                                                 hubd->h_port_state[port] |=
3923                                                     HUBD_CHILD_RAISE_POWER;
3924                                                 pwrup_child = B_TRUE;
3925                                                 mutex_exit(HUBD_MUTEX(hubd));
3926 
3927                                                 /*
3928                                                  * make sure that child
3929                                                  * doesn't disappear
3930                                                  */
3931                                                 ndi_hold_devi(dip);
3932 
3933                                                 mutex_enter(HUBD_MUTEX(hubd));
3934                                         }
3935                                 }
3936                         }
3937 
3938                         /*
3939                          * Check if the port is over-current
3940                          */
3941                         if (change & PORT_CHANGE_OCIC) {
3942                                 USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG,
3943                                     hubd->h_log_handle,
3944                                     "Port%d in over current condition, "
3945                                     "please check the attached device to "
3946                                     "clear the condition. The system will "
3947                                     "try to recover the port, but if not "
3948                                     "successful, you need to re-connect "
3949                                     "the hub or reboot the system to bring "
3950                                     "the port back to work", port);
3951 
3952                                 if (!(status & PORT_STATUS_PPS)) {
3953                                         /*
3954                                          * Try to enable port power, but
3955                                          * possibly fail. Ignore failure
3956                                          */
3957                                         (void) hubd_enable_port_power(hubd,
3958                                             port);
3959 
3960                                         /*
3961                                          * Delay some time to avoid
3962                                          * over-current event to happen
3963                                          * too frequently in some cases
3964                                          */
3965                                         mutex_exit(HUBD_MUTEX(hubd));
3966                                         delay(drv_usectohz(500000));
3967                                         mutex_enter(HUBD_MUTEX(hubd));
3968                                 }
3969                         }
3970                 }
3971         }
3972 
3973         /* release locks so we can do a devfs_clean */
3974         mutex_exit(HUBD_MUTEX(hubd));
3975 
3976         /* delete cached dv_node's but drop locks first */
3977         ndi_devi_exit(hdip, circ);
3978         ndi_devi_exit(rh_dip, rh_circ);
3979         ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ);
3980 
3981         (void) devfs_clean(rh_dip, NULL, 0);
3982 
3983         /* now check if any children need onlining */
3984         if (online_child) {
3985                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3986                     "hubd_hotplug_thread: onlining children");
3987 
3988                 (void) ndi_devi_online(hubd->h_dip, 0);
3989         }
3990 
3991         /* now check if any disconnected devices need to be cleaned up */
3992         if (offline_child) {
3993                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3994                     "hubd_hotplug_thread: scheduling cleanup");
3995 
3996                 hubd_schedule_cleanup(hubd->h_usba_device->usb_root_hub_dip);
3997         }
3998 
3999         mutex_enter(HUBD_MUTEX(hubd));
4000 
4001         /* now raise power on the children that have woken up */
4002         if (pwrup_child) {
4003                 old_state = hubd->h_dev_state;
4004                 hubd->h_dev_state = USB_DEV_HUB_CHILD_PWRLVL;
4005                 for (port = 1; port <= nports; port++) {
4006                         if (hubd->h_port_state[port] & HUBD_CHILD_RAISE_POWER) {
4007                                 dev_info_t *dip = hubd->h_children_dips[port];
4008 
4009                                 mutex_exit(HUBD_MUTEX(hubd));
4010 
4011                                 /* Get the device to full power */
4012                                 (void) pm_busy_component(dip, 0);
4013                                 (void) pm_raise_power(dip, 0,
4014                                     USB_DEV_OS_FULL_PWR);
4015                                 (void) pm_idle_component(dip, 0);
4016 
4017                                 /* release the hold on the child */
4018                                 ndi_rele_devi(dip);
4019                                 mutex_enter(HUBD_MUTEX(hubd));
4020                                 hubd->h_port_state[port] &=
4021                                     ~HUBD_CHILD_RAISE_POWER;
4022                         }
4023                 }
4024                 /*
4025                  * make sure that we don't accidentally
4026                  * over write the disconnect state
4027                  */
4028                 if (hubd->h_dev_state == USB_DEV_HUB_CHILD_PWRLVL) {
4029                         hubd->h_dev_state = old_state;
4030                 }
4031         }
4032 
4033         /*
4034          * start polling can immediately kick off read callback
4035          * we need to set the h_hotplug_thread to 0 so that
4036          * the callback is not dropped
4037          *
4038          * if there is device during reset, still stop polling to avoid the
4039          * read callback interrupting the reset, the polling will be started
4040          * in hubd_reset_thread.
4041          */
4042         for (port = 1; port <= MAX_PORTS; port++) {
4043                 if (hubd->h_reset_port[port]) {
4044 
4045                         break;
4046                 }
4047         }
4048         if (port > MAX_PORTS) {
4049                 hubd_start_polling(hubd, HUBD_ALWAYS_START_POLLING);
4050         }
4051 
4052         /*
4053          * Earlier we would set the h_hotplug_thread = 0 before
4054          * polling was restarted  so that
4055          * if there is any root hub status change interrupt, we can still kick
4056          * off the hotplug thread. This was valid when this interrupt was
4057          * delivered in hardware, and only ONE interrupt would be delivered.
4058          * Now that we poll on the root hub looking for status change in
4059          * software, this assignment is no longer required.
4060          */
4061         hubd->h_hotplug_thread--;
4062 
4063         /* mark this device as idle */
4064         (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0);
4065 
4066         cv_broadcast(&hubd->h_cv_hotplug_dev);
4067 
4068         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4069             "hubd_hotplug_thread: exit");
4070 
4071         mutex_exit(HUBD_MUTEX(hubd));
4072 
4073         ndi_rele_devi(hdip);
4074 }
4075 
4076 
4077 /*
4078  * hubd_handle_port_connect:
4079  *      Transition a port from Disabled to Enabled.  Ensure that the
4080  *      port is in the correct state before attempting to
4081  *      access the device.
4082  */
4083 static int
4084 hubd_handle_port_connect(hubd_t *hubd, usb_port_t port)
4085 {
4086         int                     rval;
4087         int                     retry;
4088         long                    time_delay;
4089         long                    settling_time;
4090         uint16_t                status;
4091         uint16_t                change;
4092         usb_addr_t              hubd_usb_addr;
4093         usba_device_t           *usba_device;
4094         usb_port_status_t       port_status = 0;
4095         usb_port_status_t       hub_port_status = 0;
4096 
4097         /* Get the hub address and port status */
4098         usba_device = hubd->h_usba_device;
4099         mutex_enter(&usba_device->usb_mutex);
4100         hubd_usb_addr = usba_device->usb_addr;
4101         hub_port_status = usba_device->usb_port_status;
4102         mutex_exit(&usba_device->usb_mutex);
4103 
4104         /*
4105          * If a device is connected, transition the
4106          * port from Disabled to the Enabled state.
4107          * The device will receive downstream packets
4108          * in the Enabled state.
4109          *
4110          * reset port and wait for the hub to report
4111          * completion
4112          */
4113         change = status = 0;
4114 
4115         /*
4116          * According to section 9.1.2 of USB 2.0 spec, the host should
4117          * wait for atleast 100ms to allow completion of an insertion
4118          * process and for power at the device to become stable.
4119          * We wait for 200 ms
4120          */
4121         settling_time = drv_usectohz(hubd_device_delay / 5);
4122         mutex_exit(HUBD_MUTEX(hubd));
4123         delay(settling_time);
4124         mutex_enter(HUBD_MUTEX(hubd));
4125 
4126         /* calculate 600 ms delay time */
4127         time_delay = (6 * drv_usectohz(hubd_device_delay)) / 10;
4128 
4129         for (retry = 0; (hubd->h_dev_state == USB_DEV_ONLINE) &&
4130             (retry < hubd_retry_enumerate); retry++) {
4131                 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4132                     "resetting port%d, retry=%d", port, retry);
4133 
4134                 if ((rval = hubd_reset_port(hubd, port)) != USB_SUCCESS) {
4135                         (void) hubd_determine_port_status(hubd,
4136                             port, &status, &change, 0);
4137 
4138                         /* continue only if port is still connected */
4139                         if (status & PORT_STATUS_CCS) {
4140                                 continue;
4141                         }
4142 
4143                         /* carry on regardless */
4144                 }
4145 
4146                 /*
4147                  * according to USB 2.0 spec section 11.24.2.7.1.2
4148                  * at the end of port reset, the hub enables the port.
4149                  * But for some strange reasons, uhci port remains disabled.
4150                  * And because the port remains disabled for the settling
4151                  * time below, the device connected to the port gets wedged
4152                  * - fails to enumerate (device not responding)
4153                  * Hence, we enable it here immediately and later again after
4154                  * the delay
4155                  */
4156                 (void) hubd_enable_port(hubd, port);
4157 
4158                 /* we skip this delay in the first iteration */
4159                 if (retry) {
4160                         /*
4161                          * delay for device to signal disconnect/connect so
4162                          * that hub properly recognizes the speed of the device
4163                          */
4164                         mutex_exit(HUBD_MUTEX(hubd));
4165                         delay(settling_time);
4166                         mutex_enter(HUBD_MUTEX(hubd));
4167 
4168                         /*
4169                          * When a low speed device is connected to any port of
4170                          * PPX it has to be explicitly enabled
4171                          * Also, if device intentionally signals
4172                          * disconnect/connect, it will disable the port.
4173                          * So enable it again.
4174                          */
4175                         (void) hubd_enable_port(hubd, port);
4176                 }
4177 
4178                 if ((rval = hubd_determine_port_status(hubd, port, &status,
4179                     &change, 0)) != USB_SUCCESS) {
4180 
4181                         USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4182                             "getting status failed (%d)", rval);
4183 
4184                         (void) hubd_disable_port(hubd, port);
4185 
4186                         continue;
4187                 }
4188 
4189                 if (status & PORT_STATUS_POCI) {
4190                         USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4191                             "port %d overcurrent", port);
4192 
4193                         (void) hubd_disable_port(hubd, port);
4194 
4195                         /* ack changes */
4196                         (void) hubd_determine_port_status(hubd,
4197                             port, &status, &change, PORT_CHANGE_OCIC);
4198 
4199                         continue;
4200                 }
4201 
4202                 /* is status really OK? */
4203                 if ((status & PORT_STATUS_OK) != PORT_STATUS_OK) {
4204                         USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4205                             "port %d status (0x%x) not OK on retry %d",
4206                             port, status, retry);
4207 
4208                         /* check if we still have the connection */
4209                         if (!(status & PORT_STATUS_CCS)) {
4210                                 /* lost connection, set exit condition */
4211                                 retry = hubd_retry_enumerate;
4212 
4213                                 break;
4214                         }
4215                 } else {
4216                         /*
4217                          * Determine if the device is high or full
4218                          * or low speed.
4219                          */
4220                         if (status & PORT_STATUS_LSDA) {
4221                                 port_status = USBA_LOW_SPEED_DEV;
4222                         } else if (status & PORT_STATUS_HSDA) {
4223                                 port_status = USBA_HIGH_SPEED_DEV;
4224                         } else {
4225                                 port_status = USBA_FULL_SPEED_DEV;
4226                         }
4227 
4228                         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4229                             "creating child port%d, status=0x%x "
4230                             "port status=0x%x",
4231                             port, status, port_status);
4232 
4233                         /*
4234                          * if the child already exists, set addrs and config
4235                          * to the device post connect event to the child
4236                          */
4237                         if (hubd->h_children_dips[port]) {
4238                                 /* set addrs to this device */
4239                                 rval = hubd_setdevaddr(hubd, port);
4240 
4241                                 /*
4242                                  * This delay is important for the CATC hub
4243                                  * to enumerate. But, avoid delay in the first
4244                                  * iteration
4245                                  */
4246                                 if (retry) {
4247                                         mutex_exit(HUBD_MUTEX(hubd));
4248                                         delay(drv_usectohz(
4249                                             hubd_device_delay/100));
4250                                         mutex_enter(HUBD_MUTEX(hubd));
4251                                 }
4252 
4253                                 if (rval == USB_SUCCESS) {
4254                                         /*
4255                                          * if the port is resetting, check if
4256                                          * device's descriptors have changed.
4257                                          */
4258                                         if ((hubd->h_reset_port[port]) &&
4259                                             (hubd_check_same_device(hubd,
4260                                             port) != USB_SUCCESS)) {
4261                                                 retry = hubd_retry_enumerate;
4262 
4263                                                 break;
4264                                         }
4265 
4266                                         /*
4267                                          * set the default config for
4268                                          * this device
4269                                          */
4270                                         hubd_setdevconfig(hubd, port);
4271 
4272                                         /*
4273                                          * if we are doing Default reset, do
4274                                          * not post reconnect event since we
4275                                          * don't know where reset function is
4276                                          * called.
4277                                          */
4278                                         if (hubd->h_reset_port[port]) {
4279 
4280                                                 return (USB_SUCCESS);
4281                                         }
4282 
4283                                         /*
4284                                          * indicate to the child that
4285                                          * it is online again
4286                                          */
4287                                         mutex_exit(HUBD_MUTEX(hubd));
4288                                         hubd_post_event(hubd, port,
4289                                             USBA_EVENT_TAG_HOT_INSERTION);
4290                                         mutex_enter(HUBD_MUTEX(hubd));
4291 
4292                                         return (USB_SUCCESS);
4293                                 }
4294                         } else {
4295                                 /*
4296                                  * We need to release access here
4297                                  * so that busctls on other ports can
4298                                  * continue and don't cause a deadlock
4299                                  * when busctl and removal of prom node
4300                                  * takes concurrently. This also ensures
4301                                  * busctls for attach of successfully
4302                                  * enumerated devices on other ports can
4303                                  * continue concurrently with the process
4304                                  * of enumerating the new devices. This
4305                                  * reduces the overall boot time of the system.
4306                                  */
4307                                 rval = hubd_create_child(hubd->h_dip,
4308                                     hubd,
4309                                     hubd->h_usba_device,
4310                                     port_status, port,
4311                                     retry);
4312                                 if (rval == USB_SUCCESS) {
4313                                         usba_update_hotplug_stats(hubd->h_dip,
4314                                             USBA_TOTAL_HOTPLUG_SUCCESS|
4315                                             USBA_HOTPLUG_SUCCESS);
4316                                         hubd->h_total_hotplug_success++;
4317 
4318                                         if (retry > 0) {
4319                                                 USB_DPRINTF_L2(
4320                                                     DPRINT_MASK_HOTPLUG,
4321                                                     hubd->h_log_handle,
4322                                                     "device on port %d "
4323                                                     "enumerated after %d %s",
4324                                                     port, retry,
4325                                                     (retry > 1) ? "retries" :
4326                                                     "retry");
4327 
4328                                         }
4329 
4330                                         return (USB_SUCCESS);
4331                                 }
4332                         }
4333                 }
4334 
4335                 /* wait a while until it settles? */
4336                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4337                     "disabling port %d again", port);
4338 
4339                 (void) hubd_disable_port(hubd, port);
4340                 if (retry) {
4341                         mutex_exit(HUBD_MUTEX(hubd));
4342                         delay(time_delay);
4343                         mutex_enter(HUBD_MUTEX(hubd));
4344                 }
4345 
4346                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4347                     "retrying on port %d", port);
4348         }
4349 
4350         if (retry >= hubd_retry_enumerate) {
4351                 /*
4352                  * If it is a High Speed Root Hub and connected device
4353                  * Is a Low/Full Speed, it will be handled by USB 1.1
4354                  * Host Controller. In this case, USB 2.0 Host Controller
4355                  * will transfer the ownership of this port to USB 1.1
4356                  * Host Controller. So don't display any error message on
4357                  * the console.
4358                  */
4359                 if ((hubd_usb_addr == ROOT_HUB_ADDR) &&
4360                     (hub_port_status == USBA_HIGH_SPEED_DEV) &&
4361                     (port_status != USBA_HIGH_SPEED_DEV)) {
4362                         USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
4363                             hubd->h_log_handle,
4364                             "hubd_handle_port_connect: Low/Full speed "
4365                             "device is connected to High Speed root hub");
4366                 } else {
4367                         USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG,
4368                             hubd->h_log_handle,
4369                             "Connecting device on port %d failed", port);
4370                 }
4371 
4372                 (void) hubd_disable_port(hubd, port);
4373                 usba_update_hotplug_stats(hubd->h_dip,
4374                     USBA_TOTAL_HOTPLUG_FAILURE|USBA_HOTPLUG_FAILURE);
4375                 hubd->h_total_hotplug_failure++;
4376 
4377                 /*
4378                  * the port should be automagically
4379                  * disabled but just in case, we do
4380                  * it here
4381                  */
4382                 (void) hubd_disable_port(hubd, port);
4383 
4384                 /* ack all changes because we disabled this port */
4385                 (void) hubd_determine_port_status(hubd,
4386                     port, &status, &change, HUBD_ACK_ALL_CHANGES);
4387 
4388         }
4389 
4390         return (USB_FAILURE);
4391 }
4392 
4393 
4394 /*
4395  * hubd_get_hub_status:
4396  */
4397 static int
4398 hubd_get_hub_status(hubd_t *hubd)
4399 {
4400         int             rval;
4401         usb_cr_t        completion_reason;
4402         usb_cb_flags_t  cb_flags;
4403         uint16_t        stword[2];
4404         uint16_t        status;
4405         uint16_t        change;
4406         usb_cfg_descr_t cfg_descr;
4407         size_t          cfg_length;
4408         uchar_t         *usb_cfg;
4409         uint8_t         MaxPower;
4410         usb_hub_descr_t *hub_descr;
4411         usb_port_t      port;
4412 
4413         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4414             "hubd_get_hub_status:");
4415 
4416         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
4417 
4418         if ((hubd_get_hub_status_words(hubd, stword)) != USB_SUCCESS) {
4419 
4420                 return (USB_FAILURE);
4421         }
4422         status = stword[0];
4423         change = stword[1];
4424 
4425         mutex_exit(HUBD_MUTEX(hubd));
4426 
4427         /* Obtain the raw configuration descriptor */
4428         usb_cfg = usb_get_raw_cfg_data(hubd->h_dip, &cfg_length);
4429 
4430         /* get configuration descriptor */
4431         rval = usb_parse_cfg_descr(usb_cfg, cfg_length,
4432             &cfg_descr, USB_CFG_DESCR_SIZE);
4433 
4434         if (rval != USB_CFG_DESCR_SIZE) {
4435 
4436                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4437                     "get hub configuration descriptor failed.");
4438 
4439                 mutex_enter(HUBD_MUTEX(hubd));
4440 
4441                 return (USB_FAILURE);
4442         } else {
4443                 MaxPower = cfg_descr.bMaxPower;
4444         }
4445 
4446         /* check if local power status changed. */
4447         if (change & C_HUB_LOCAL_POWER_STATUS) {
4448 
4449                 /*
4450                  * local power has been lost, check the maximum
4451                  * power consumption of current configuration.
4452                  * see USB2.0 spec Table 11-12.
4453                  */
4454                 if (status & HUB_LOCAL_POWER_STATUS) {
4455 
4456                         if (MaxPower == 0) {
4457 
4458                                 /*
4459                                  * Self-powered only hub. Because it could
4460                                  * not draw any power from USB bus.
4461                                  * It can't work well on this condition.
4462                                  */
4463                                 USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG,
4464                                     hubd->h_log_handle,
4465                                     "local power has been lost, "
4466                                     "please disconnect hub");
4467                         } else {
4468 
4469                                 /*
4470                                  * Bus-powered only or self/bus-powered hub.
4471                                  */
4472                                 USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG,
4473                                     hubd->h_log_handle,
4474                                     "local power has been lost,"
4475                                     "the hub could draw %d"
4476                                     " mA power from the USB bus.",
4477                                     2*MaxPower);
4478                         }
4479 
4480                 }
4481 
4482                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4483                     "clearing feature C_HUB_LOCAL_POWER ");
4484 
4485                 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
4486                     hubd->h_default_pipe,
4487                     HUB_HANDLE_HUB_FEATURE_TYPE,
4488                     USB_REQ_CLEAR_FEATURE,
4489                     CFS_C_HUB_LOCAL_POWER,
4490                     0,
4491                     0,
4492                     NULL, 0,
4493                     &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
4494                         USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
4495                             hubd->h_log_handle,
4496                             "clear feature C_HUB_LOCAL_POWER "
4497                             "failed (%d 0x%x %d)",
4498                             rval, completion_reason, cb_flags);
4499                 }
4500 
4501         }
4502 
4503         if (change & C_HUB_OVER_CURRENT) {
4504 
4505                 if (status & HUB_OVER_CURRENT) {
4506 
4507                         if (usba_is_root_hub(hubd->h_dip)) {
4508                                 /*
4509                                  * The root hub should be automatically
4510                                  * recovered when over-current condition is
4511                                  * cleared. But there might be exception and
4512                                  * need user interaction to recover.
4513                                  */
4514                                 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG,
4515                                     hubd->h_log_handle,
4516                                     "Root hub over current condition, "
4517                                     "please check your system to clear the "
4518                                     "condition as soon as possible. And you "
4519                                     "may need to reboot the system to bring "
4520                                     "the root hub back to work if it cannot "
4521                                     "recover automatically");
4522                         } else {
4523                                 /*
4524                                  * The driver would try to recover port power
4525                                  * on over current condition. When the recovery
4526                                  * fails, the user may still need to offline
4527                                  * this hub in order to recover.
4528                                  * The port power is automatically disabled,
4529                                  * so we won't see disconnects.
4530                                  */
4531                                 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG,
4532                                     hubd->h_log_handle,
4533                                     "Hub global over current condition, "
4534                                     "please disconnect the devices connected "
4535                                     "to the hub to clear the condition. And "
4536                                     "you may need to re-connect the hub if "
4537                                     "the ports do not work");
4538                         }
4539                 }
4540 
4541                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4542                     "clearing feature C_HUB_OVER_CURRENT");
4543 
4544                 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
4545                     hubd->h_default_pipe,
4546                     HUB_HANDLE_HUB_FEATURE_TYPE,
4547                     USB_REQ_CLEAR_FEATURE,
4548                     CFS_C_HUB_OVER_CURRENT,
4549                     0,
4550                     0,
4551                     NULL, 0,
4552                     &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
4553                         USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
4554                             hubd->h_log_handle,
4555                             "clear feature C_HUB_OVER_CURRENT "
4556                             "failed (%d 0x%x %d)",
4557                             rval, completion_reason, cb_flags);
4558                 }
4559 
4560                 /*
4561                  * Try to recover all port power if they are turned off.
4562                  * Don't do this for root hub, but rely on the root hub
4563                  * to recover itself.
4564                  */
4565                 if (!usba_is_root_hub(hubd->h_dip)) {
4566 
4567                         mutex_enter(HUBD_MUTEX(hubd));
4568 
4569                         /*
4570                          * Only check the power status of the 1st port
4571                          * since all port power status should be the same.
4572                          */
4573                         (void) hubd_determine_port_status(hubd, 1, &status,
4574                             &change, 0);
4575 
4576                         if (status & PORT_STATUS_PPS) {
4577 
4578                                 return (USB_SUCCESS);
4579                         }
4580 
4581                         hub_descr = &hubd->h_hub_descr;
4582 
4583                         for (port = 1; port <= hub_descr->bNbrPorts;
4584                             port++) {
4585 
4586                                 (void) hubd_enable_port_power(hubd, port);
4587                         }
4588 
4589                         mutex_exit(HUBD_MUTEX(hubd));
4590 
4591                         /*
4592                          * Delay some time to avoid over-current event
4593                          * to happen too frequently in some cases
4594                          */
4595                         delay(drv_usectohz(500000));
4596                 }
4597         }
4598 
4599         mutex_enter(HUBD_MUTEX(hubd));
4600 
4601         return (USB_SUCCESS);
4602 }
4603 
4604 
4605 /*
4606  * hubd_reset_port:
4607  */
4608 static int
4609 hubd_reset_port(hubd_t *hubd, usb_port_t port)
4610 {
4611         int     rval;
4612         usb_cr_t completion_reason;
4613         usb_cb_flags_t cb_flags;
4614         usb_port_mask_t port_mask = 1 << port;
4615         mblk_t  *data;
4616         uint16_t status;
4617         uint16_t change;
4618         int     i;
4619         clock_t delta;
4620 
4621         USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
4622             "hubd_reset_port: port=%d", port);
4623 
4624         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
4625 
4626         hubd->h_port_reset_wait |= port_mask;
4627 
4628         mutex_exit(HUBD_MUTEX(hubd));
4629 
4630         if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
4631             hubd->h_default_pipe,
4632             HUB_HANDLE_PORT_FEATURE_TYPE,
4633             USB_REQ_SET_FEATURE,
4634             CFS_PORT_RESET,
4635             port,
4636             0,
4637             NULL, 0,
4638             &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
4639                 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
4640                     "reset port%d failed (%d 0x%x %d)",
4641                     port, completion_reason, cb_flags, rval);
4642 
4643                 mutex_enter(HUBD_MUTEX(hubd));
4644 
4645                 return (USB_FAILURE);
4646         }
4647 
4648         mutex_enter(HUBD_MUTEX(hubd));
4649 
4650         USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
4651             "waiting on cv for reset completion");
4652 
4653         /*
4654          * wait for port status change event
4655          */
4656         delta = drv_usectohz(hubd_device_delay / 10);
4657         for (i = 0; i < hubd_retry_enumerate; i++) {
4658                 /*
4659                  * start polling ep1 for receiving notification on
4660                  * reset completion
4661                  */
4662                 hubd_start_polling(hubd, HUBD_ALWAYS_START_POLLING);
4663 
4664                 /*
4665                  * sleep a max of 100ms for reset completion
4666                  * notification to be received
4667                  */
4668                 if (hubd->h_port_reset_wait & port_mask) {
4669                         rval = cv_reltimedwait(&hubd->h_cv_reset_port,
4670                             &hubd->h_mutex, delta, TR_CLOCK_TICK);
4671                         if ((rval <= 0) &&
4672                             (hubd->h_port_reset_wait & port_mask)) {
4673                                 /* we got woken up because of a timeout */
4674                                 USB_DPRINTF_L2(DPRINT_MASK_PORT,
4675                                     hubd->h_log_handle,
4676                                     "timeout: reset port=%d failed", port);
4677 
4678                                 hubd->h_port_reset_wait &=  ~port_mask;
4679 
4680                                 hubd_stop_polling(hubd);
4681 
4682                                 return (USB_FAILURE);
4683                         }
4684                 }
4685 
4686                 USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
4687                     "reset completion received");
4688 
4689                 hubd_stop_polling(hubd);
4690 
4691                 data = NULL;
4692 
4693                 /* check status to determine whether reset completed */
4694                 mutex_exit(HUBD_MUTEX(hubd));
4695                 if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
4696                     hubd->h_default_pipe,
4697                     HUB_GET_PORT_STATUS_TYPE,
4698                     USB_REQ_GET_STATUS,
4699                     0,
4700                     port,
4701                     GET_STATUS_LENGTH,
4702                     &data, 0,
4703                     &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
4704                         USB_DPRINTF_L2(DPRINT_MASK_PORT,
4705                             hubd->h_log_handle,
4706                             "get status port%d failed (%d 0x%x %d)",
4707                             port, completion_reason, cb_flags, rval);
4708 
4709                         if (data) {
4710                                 freemsg(data);
4711                                 data = NULL;
4712                         }
4713                         mutex_enter(HUBD_MUTEX(hubd));
4714 
4715                         continue;
4716                 }
4717 
4718                 status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
4719                 change = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2);
4720 
4721                 freemsg(data);
4722 
4723                 /* continue only if port is still connected */
4724                 if (!(status & PORT_STATUS_CCS)) {
4725 
4726                         /* lost connection, set exit condition */
4727                         i = hubd_retry_enumerate;
4728 
4729                         mutex_enter(HUBD_MUTEX(hubd));
4730 
4731                         break;
4732                 }
4733 
4734                 if (status & PORT_STATUS_PRS) {
4735                         USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
4736                             "port%d reset active", port);
4737                         mutex_enter(HUBD_MUTEX(hubd));
4738 
4739                         continue;
4740                 } else {
4741                         USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
4742                             "port%d reset inactive", port);
4743                 }
4744 
4745                 if (change & PORT_CHANGE_PRSC) {
4746                         USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
4747                             "clearing feature CFS_C_PORT_RESET");
4748 
4749                         if (usb_pipe_sync_ctrl_xfer(hubd->h_dip,
4750                             hubd->h_default_pipe,
4751                             HUB_HANDLE_PORT_FEATURE_TYPE,
4752                             USB_REQ_CLEAR_FEATURE,
4753                             CFS_C_PORT_RESET,
4754                             port,
4755                             0,
4756                             NULL, 0,
4757                             &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
4758                                 USB_DPRINTF_L2(DPRINT_MASK_PORT,
4759                                     hubd->h_log_handle,
4760                                     "clear feature CFS_C_PORT_RESET"
4761                                     " port%d failed (%d 0x%x %d)",
4762                                     port, completion_reason, cb_flags, rval);
4763                         }
4764                 }
4765                 mutex_enter(HUBD_MUTEX(hubd));
4766 
4767                 break;
4768         }
4769 
4770         if (i >= hubd_retry_enumerate) {
4771                 /* port reset has failed */
4772                 rval = USB_FAILURE;
4773         }
4774 
4775         return (rval);
4776 }
4777 
4778 
4779 /*
4780  * hubd_enable_port:
4781  *      this may fail if the hub as been disconnected
4782  */
4783 static int
4784 hubd_enable_port(hubd_t *hubd, usb_port_t port)
4785 {
4786         int     rval;
4787         usb_cr_t completion_reason;
4788         usb_cb_flags_t cb_flags;
4789 
4790         USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
4791             "hubd_enable_port: port=%d", port);
4792 
4793         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
4794 
4795         mutex_exit(HUBD_MUTEX(hubd));
4796 
4797         /* Do not issue a SetFeature(PORT_ENABLE) on external hubs */
4798         if (!usba_is_root_hub(hubd->h_dip)) {
4799                 mutex_enter(HUBD_MUTEX(hubd));
4800 
4801                 return (USB_SUCCESS);
4802         }
4803 
4804         if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
4805             hubd->h_default_pipe,
4806             HUB_HANDLE_PORT_FEATURE_TYPE,
4807             USB_REQ_SET_FEATURE,
4808             CFS_PORT_ENABLE,
4809             port,
4810             0,
4811             NULL, 0,
4812             &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
4813                 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
4814                     "enable port%d failed (%d 0x%x %d)",
4815                     port, completion_reason, cb_flags, rval);
4816         }
4817 
4818         mutex_enter(HUBD_MUTEX(hubd));
4819 
4820         USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
4821             "enabling port done");
4822 
4823         return (rval);
4824 }
4825 
4826 
4827 /*
4828  * hubd_disable_port
4829  */
4830 static int
4831 hubd_disable_port(hubd_t *hubd, usb_port_t port)
4832 {
4833         int     rval;
4834         usb_cr_t completion_reason;
4835         usb_cb_flags_t cb_flags;
4836 
4837         USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
4838             "hubd_disable_port: port=%d", port);
4839 
4840         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
4841 
4842         mutex_exit(HUBD_MUTEX(hubd));
4843 
4844         if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
4845             hubd->h_default_pipe,
4846             HUB_HANDLE_PORT_FEATURE_TYPE,
4847             USB_REQ_CLEAR_FEATURE,
4848             CFS_PORT_ENABLE,
4849             port,
4850             0,
4851             NULL, 0,
4852             &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
4853                 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
4854                     "disable port%d failed (%d 0x%x %d)", port,
4855                     completion_reason, cb_flags, rval);
4856                 mutex_enter(HUBD_MUTEX(hubd));
4857 
4858                 return (USB_FAILURE);
4859         }
4860 
4861         USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
4862             "clearing feature CFS_C_PORT_ENABLE");
4863 
4864         if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
4865             hubd->h_default_pipe,
4866             HUB_HANDLE_PORT_FEATURE_TYPE,
4867             USB_REQ_CLEAR_FEATURE,
4868             CFS_C_PORT_ENABLE,
4869             port,
4870             0,
4871             NULL, 0,
4872             &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
4873                 USB_DPRINTF_L2(DPRINT_MASK_PORT,
4874                     hubd->h_log_handle,
4875                     "clear feature CFS_C_PORT_ENABLE port%d failed "
4876                     "(%d 0x%x %d)",
4877                     port, completion_reason, cb_flags, rval);
4878 
4879                 mutex_enter(HUBD_MUTEX(hubd));
4880 
4881                 return (USB_FAILURE);
4882         }
4883 
4884         mutex_enter(HUBD_MUTEX(hubd));
4885 
4886         return (USB_SUCCESS);
4887 }
4888 
4889 
4890 /*
4891  * hubd_determine_port_status:
4892  */
4893 static int
4894 hubd_determine_port_status(hubd_t *hubd, usb_port_t port,
4895                 uint16_t *status, uint16_t *change, uint_t ack_flag)
4896 {
4897         int rval;
4898         mblk_t  *data = NULL;
4899         usb_cr_t completion_reason;
4900         usb_cb_flags_t cb_flags;
4901 
4902         USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
4903             "hubd_determine_port_status: port=%d, state=0x%x ack=0x%x", port,
4904             hubd->h_port_state[port], ack_flag);
4905 
4906         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
4907 
4908         mutex_exit(HUBD_MUTEX(hubd));
4909 
4910         if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
4911             hubd->h_default_pipe,
4912             HUB_GET_PORT_STATUS_TYPE,
4913             USB_REQ_GET_STATUS,
4914             0,
4915             port,
4916             GET_STATUS_LENGTH,
4917             &data, 0,
4918             &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
4919                 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
4920                     "port=%d get status failed (%d 0x%x %d)",
4921                     port, completion_reason, cb_flags, rval);
4922 
4923                 if (data) {
4924                         freemsg(data);
4925                 }
4926 
4927                 *status = *change = 0;
4928                 mutex_enter(HUBD_MUTEX(hubd));
4929 
4930                 return (rval);
4931         }
4932 
4933         mutex_enter(HUBD_MUTEX(hubd));
4934         if (MBLKL(data) != GET_STATUS_LENGTH) {
4935                 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
4936                     "port %d: length incorrect %ld",
4937                     port, MBLKL(data));
4938                 freemsg(data);
4939                 *status = *change = 0;
4940 
4941                 return (rval);
4942         }
4943 
4944 
4945         *status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
4946         *change = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2);
4947 
4948         USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
4949             "port%d status=0x%x, change=0x%x", port, *status, *change);
4950 
4951         freemsg(data);
4952 
4953         if (*status & PORT_STATUS_CCS) {
4954                 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
4955                     "port%d connected", port);
4956 
4957                 hubd->h_port_state[port] |= (PORT_STATUS_CCS & ack_flag);
4958         } else {
4959                 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
4960                     "port%d disconnected", port);
4961 
4962                 hubd->h_port_state[port] &= ~(PORT_STATUS_CCS & ack_flag);
4963         }
4964 
4965         if (*status & PORT_STATUS_PES) {
4966                 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
4967                     "port%d enabled", port);
4968 
4969                 hubd->h_port_state[port] |= (PORT_STATUS_PES & ack_flag);
4970         } else {
4971                 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
4972                     "port%d disabled", port);
4973 
4974                 hubd->h_port_state[port] &= ~(PORT_STATUS_PES & ack_flag);
4975         }
4976 
4977         if (*status & PORT_STATUS_PSS) {
4978                 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
4979                     "port%d suspended", port);
4980 
4981                 hubd->h_port_state[port] |= (PORT_STATUS_PSS & ack_flag);
4982         } else {
4983                 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
4984                     "port%d not suspended", port);
4985 
4986                 hubd->h_port_state[port] &= ~(PORT_STATUS_PSS & ack_flag);
4987         }
4988 
4989         if (*change & PORT_CHANGE_PRSC) {
4990                 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
4991                     "port%d reset completed", port);
4992 
4993                 hubd->h_port_state[port] |= (PORT_CHANGE_PRSC & ack_flag);
4994         } else {
4995 
4996                 hubd->h_port_state[port] &= ~(PORT_CHANGE_PRSC & ack_flag);
4997         }
4998 
4999         if (*status & PORT_STATUS_POCI) {
5000                 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
5001                     "port%d overcurrent!", port);
5002 
5003                 hubd->h_port_state[port] |= (PORT_STATUS_POCI & ack_flag);
5004         } else {
5005 
5006                 hubd->h_port_state[port] &= ~(PORT_STATUS_POCI & ack_flag);
5007         }
5008 
5009         if (*status & PORT_STATUS_PRS) {
5010                 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5011                     "port%d reset active", port);
5012 
5013                 hubd->h_port_state[port] |= (PORT_STATUS_PRS & ack_flag);
5014         } else {
5015                 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5016                     "port%d reset inactive", port);
5017 
5018                 hubd->h_port_state[port] &= ~(PORT_STATUS_PRS & ack_flag);
5019         }
5020         if (*status & PORT_STATUS_PPS) {
5021                 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5022                     "port%d power on", port);
5023 
5024                 hubd->h_port_state[port] |= (PORT_STATUS_PPS & ack_flag);
5025         } else {
5026                 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5027                     "port%d power off", port);
5028 
5029                 hubd->h_port_state[port] &= ~(PORT_STATUS_PPS & ack_flag);
5030         }
5031         if (*status & PORT_STATUS_LSDA) {
5032                 USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5033                     "port%d low speed", port);
5034 
5035                 hubd->h_port_state[port] |= (PORT_STATUS_LSDA & ack_flag);
5036         } else {
5037                 hubd->h_port_state[port] &= ~(PORT_STATUS_LSDA & ack_flag);
5038                 if (*status & PORT_STATUS_HSDA) {
5039                         USB_DPRINTF_L3(DPRINT_MASK_PORT,
5040                             hubd->h_log_handle, "port%d "
5041                             "high speed", port);
5042 
5043                         hubd->h_port_state[port] |=
5044                             (PORT_STATUS_HSDA & ack_flag);
5045                 } else {
5046                         USB_DPRINTF_L3(DPRINT_MASK_PORT,
5047                             hubd->h_log_handle, "port%d "
5048                             "full speed", port);
5049 
5050                         hubd->h_port_state[port] &=
5051                             ~(PORT_STATUS_HSDA & ack_flag);
5052                 }
5053         }
5054 
5055         /*
5056          * Acknowledge connection, enable, reset status
5057          */
5058         if (ack_flag) {
5059                 mutex_exit(HUBD_MUTEX(hubd));
5060                 if (*change & PORT_CHANGE_CSC & ack_flag) {
5061                         USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5062                             "clearing feature CFS_C_PORT_CONNECTION");
5063                         if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5064                             hubd->h_default_pipe,
5065                             HUB_HANDLE_PORT_FEATURE_TYPE,
5066                             USB_REQ_CLEAR_FEATURE,
5067                             CFS_C_PORT_CONNECTION,
5068                             port,
5069                             0, NULL, 0,
5070                             &completion_reason, &cb_flags, 0)) !=
5071                             USB_SUCCESS) {
5072                                 USB_DPRINTF_L2(DPRINT_MASK_PORT,
5073                                     hubd->h_log_handle,
5074                                     "clear feature CFS_C_PORT_CONNECTION"
5075                                     " port%d failed (%d 0x%x %d)",
5076                                     port, completion_reason, cb_flags, rval);
5077                         }
5078                 }
5079                 if (*change & PORT_CHANGE_PESC & ack_flag) {
5080                         USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5081                             "clearing feature CFS_C_PORT_ENABLE");
5082                         if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5083                             hubd->h_default_pipe,
5084                             HUB_HANDLE_PORT_FEATURE_TYPE,
5085                             USB_REQ_CLEAR_FEATURE,
5086                             CFS_C_PORT_ENABLE,
5087                             port,
5088                             0, NULL, 0,
5089                             &completion_reason, &cb_flags, 0)) !=
5090                             USB_SUCCESS) {
5091                                 USB_DPRINTF_L2(DPRINT_MASK_PORT,
5092                                     hubd->h_log_handle,
5093                                     "clear feature CFS_C_PORT_ENABLE"
5094                                     " port%d failed (%d 0x%x %d)",
5095                                     port, completion_reason, cb_flags, rval);
5096                         }
5097                 }
5098                 if (*change & PORT_CHANGE_PSSC & ack_flag) {
5099                         USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5100                             "clearing feature CFS_C_PORT_SUSPEND");
5101 
5102                         if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5103                             hubd->h_default_pipe,
5104                             HUB_HANDLE_PORT_FEATURE_TYPE,
5105                             USB_REQ_CLEAR_FEATURE,
5106                             CFS_C_PORT_SUSPEND,
5107                             port,
5108                             0, NULL, 0,
5109                             &completion_reason, &cb_flags, 0)) !=
5110                             USB_SUCCESS) {
5111                                 USB_DPRINTF_L2(DPRINT_MASK_PORT,
5112                                     hubd->h_log_handle,
5113                                     "clear feature CFS_C_PORT_SUSPEND"
5114                                     " port%d failed (%d 0x%x %d)",
5115                                     port, completion_reason, cb_flags, rval);
5116                         }
5117                 }
5118                 if (*change & PORT_CHANGE_OCIC & ack_flag) {
5119                         USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5120                             "clearing feature CFS_C_PORT_OVER_CURRENT");
5121 
5122                         if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5123                             hubd->h_default_pipe,
5124                             HUB_HANDLE_PORT_FEATURE_TYPE,
5125                             USB_REQ_CLEAR_FEATURE,
5126                             CFS_C_PORT_OVER_CURRENT,
5127                             port,
5128                             0, NULL, 0,
5129                             &completion_reason, &cb_flags, 0)) !=
5130                             USB_SUCCESS) {
5131                                 USB_DPRINTF_L2(DPRINT_MASK_PORT,
5132                                     hubd->h_log_handle,
5133                                     "clear feature CFS_C_PORT_OVER_CURRENT"
5134                                     " port%d failed (%d 0x%x %d)",
5135                                     port, completion_reason, cb_flags, rval);
5136                         }
5137                 }
5138                 if (*change & PORT_CHANGE_PRSC & ack_flag) {
5139                         USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5140                             "clearing feature CFS_C_PORT_RESET");
5141                         if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5142                             hubd->h_default_pipe,
5143                             HUB_HANDLE_PORT_FEATURE_TYPE,
5144                             USB_REQ_CLEAR_FEATURE,
5145                             CFS_C_PORT_RESET,
5146                             port,
5147                             0, NULL, 0,
5148                             &completion_reason, &cb_flags, 0)) !=
5149                             USB_SUCCESS) {
5150                                 USB_DPRINTF_L2(DPRINT_MASK_PORT,
5151                                     hubd->h_log_handle,
5152                                     "clear feature CFS_C_PORT_RESET"
5153                                     " port%d failed (%d 0x%x %d)",
5154                                     port, completion_reason, cb_flags, rval);
5155                         }
5156                 }
5157                 mutex_enter(HUBD_MUTEX(hubd));
5158         }
5159 
5160         USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
5161             "new port%d state 0x%x", port, hubd->h_port_state[port]);
5162 
5163 
5164         return (USB_SUCCESS);
5165 }
5166 
5167 
5168 /*
5169  * hubd_recover_disabled_port
5170  * if the port got disabled because of an error
5171  * enable it. If hub doesn't suport enable port,
5172  * reset the port to bring the device to life again
5173  */
5174 static int
5175 hubd_recover_disabled_port(hubd_t *hubd, usb_port_t port)
5176 {
5177         uint16_t        status;
5178         uint16_t        change;
5179         int             rval = USB_FAILURE;
5180 
5181         /* first try enabling the port */
5182         (void) hubd_enable_port(hubd, port);
5183 
5184         /* read the port status */
5185         (void) hubd_determine_port_status(hubd, port, &status, &change,
5186             PORT_CHANGE_PESC);
5187 
5188         if (status & PORT_STATUS_PES) {
5189                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5190                     "Port%d now Enabled", port);
5191         } else if (status & PORT_STATUS_CCS) {
5192                 /* first post a disconnect event to the child */
5193                 mutex_exit(HUBD_MUTEX(hubd));
5194                 hubd_post_event(hubd, port, USBA_EVENT_TAG_HOT_REMOVAL);
5195                 mutex_enter(HUBD_MUTEX(hubd));
5196 
5197                 /* then reset the port and recover the device */
5198                 rval = hubd_handle_port_connect(hubd, port);
5199 
5200                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5201                     "Port%d now Enabled by force", port);
5202         }
5203 
5204         return (rval);
5205 }
5206 
5207 
5208 /*
5209  * hubd_enable_all_port_power:
5210  */
5211 static int
5212 hubd_enable_all_port_power(hubd_t *hubd)
5213 {
5214         usb_hub_descr_t *hub_descr;
5215         int             wait;
5216         usb_port_t      port;
5217         uint_t          retry;
5218         uint16_t        status;
5219         uint16_t        change;
5220 
5221         USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
5222             "hubd_enable_all_port_power");
5223 
5224         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
5225 
5226         hub_descr = &hubd->h_hub_descr;
5227 
5228         /*
5229          * According to section 11.11 of USB, for hubs with no power
5230          * switches, bPwrOn2PwrGood is zero. But we wait for some
5231          * arbitrary time to enable power to become stable.
5232          *
5233          * If an hub supports port power switching, we need to wait
5234          * at least 20ms before accessing corresponding usb port.
5235          */
5236         if ((hub_descr->wHubCharacteristics &
5237             HUB_CHARS_NO_POWER_SWITCHING) || (!hub_descr->bPwrOn2PwrGood)) {
5238                 wait = hubd_device_delay / 10;
5239         } else {
5240                 wait = max(HUB_DEFAULT_POPG,
5241                     hub_descr->bPwrOn2PwrGood) * 2 * 1000;
5242         }
5243 
5244         USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
5245             "hubd_enable_all_port_power: popg=%d wait=%d",
5246             hub_descr->bPwrOn2PwrGood, wait);
5247 
5248         /*
5249          * Enable power per port. we ignore gang power and power mask
5250          * and always enable all ports one by one.
5251          */
5252         for (port = 1; port <= hub_descr->bNbrPorts; port++) {
5253                 /*
5254                  * Transition the port from the Powered Off to the
5255                  * Disconnected state by supplying power to the port.
5256                  */
5257                 USB_DPRINTF_L4(DPRINT_MASK_PORT,
5258                     hubd->h_log_handle,
5259                     "hubd_enable_all_port_power: power port=%d", port);
5260 
5261                 (void) hubd_enable_port_power(hubd, port);
5262         }
5263 
5264         mutex_exit(HUBD_MUTEX(hubd));
5265         delay(drv_usectohz(wait));
5266         mutex_enter(HUBD_MUTEX(hubd));
5267 
5268         /* For retry if any, use some extra delay */
5269         wait = max(wait, hubd_device_delay / 10);
5270 
5271         /* Check each port power status for a given usb hub */
5272         for (port = 1; port <= hub_descr->bNbrPorts; port++) {
5273 
5274                 /* Get port status */
5275                 (void) hubd_determine_port_status(hubd, port,
5276                     &status, &change, 0);
5277 
5278                 for (retry = 0; ((!(status & PORT_STATUS_PPS)) &&
5279                     (retry < HUBD_PORT_RETRY)); retry++) {
5280 
5281                         USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
5282                             "Retry is in progress %d: port %d status %d",
5283                             retry, port, status);
5284 
5285                         (void) hubd_enable_port_power(hubd, port);
5286 
5287                         mutex_exit(HUBD_MUTEX(hubd));
5288                         delay(drv_usectohz(wait));
5289                         mutex_enter(HUBD_MUTEX(hubd));
5290 
5291                         /* Get port status */
5292                         (void) hubd_determine_port_status(hubd, port,
5293                             &status, &change, 0);
5294                 }
5295 
5296                 /* Print warning message if port has no power */
5297                 if (!(status & PORT_STATUS_PPS)) {
5298 
5299                         USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
5300                             "hubd_enable_all_port_power: port %d power-on "
5301                             "failed, port status 0x%x", port, status);
5302                 }
5303         }
5304 
5305         return (USB_SUCCESS);
5306 }
5307 
5308 
5309 /*
5310  * hubd_enable_port_power:
5311  *      enable individual port power
5312  */
5313 static int
5314 hubd_enable_port_power(hubd_t *hubd, usb_port_t port)
5315 {
5316         int             rval;
5317         usb_cr_t        completion_reason;
5318         usb_cb_flags_t  cb_flags;
5319 
5320         USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
5321             "hubd_enable_port_power: port=%d", port);
5322 
5323         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
5324         ASSERT(hubd->h_default_pipe != 0);
5325 
5326         mutex_exit(HUBD_MUTEX(hubd));
5327 
5328         if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5329             hubd->h_default_pipe,
5330             HUB_HANDLE_PORT_FEATURE_TYPE,
5331             USB_REQ_SET_FEATURE,
5332             CFS_PORT_POWER,
5333             port,
5334             0, NULL, 0,
5335             &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
5336                 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
5337                     "set port power failed (%d 0x%x %d)",
5338                     completion_reason, cb_flags, rval);
5339                 mutex_enter(HUBD_MUTEX(hubd));
5340 
5341                 return (USB_FAILURE);
5342         } else {
5343                 mutex_enter(HUBD_MUTEX(hubd));
5344                 hubd->h_port_state[port] |= PORT_STATUS_PPS;
5345 
5346                 return (USB_SUCCESS);
5347         }
5348 }
5349 
5350 
5351 /*
5352  * hubd_disable_all_port_power:
5353  */
5354 static int
5355 hubd_disable_all_port_power(hubd_t *hubd)
5356 {
5357         usb_port_t port;
5358 
5359         USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
5360             "hubd_disable_all_port_power");
5361 
5362         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
5363 
5364         /*
5365          * disable power per port, ignore gang power and power mask
5366          */
5367         for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) {
5368                 (void) hubd_disable_port_power(hubd, port);
5369         }
5370 
5371         return (USB_SUCCESS);
5372 }
5373 
5374 
5375 /*
5376  * hubd_disable_port_power:
5377  *      disable individual port power
5378  */
5379 static int
5380 hubd_disable_port_power(hubd_t *hubd, usb_port_t port)
5381 {
5382         int             rval;
5383         usb_cr_t        completion_reason;
5384         usb_cb_flags_t  cb_flags;
5385 
5386         USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
5387             "hubd_disable_port_power: port=%d", port);
5388 
5389         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
5390 
5391         mutex_exit(HUBD_MUTEX(hubd));
5392 
5393         if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5394             hubd->h_default_pipe,
5395             HUB_HANDLE_PORT_FEATURE_TYPE,
5396             USB_REQ_CLEAR_FEATURE,
5397             CFS_PORT_POWER,
5398             port,
5399             0, NULL, 0,
5400             &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
5401                 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
5402                     "clearing port%d power failed (%d 0x%x %d)",
5403                     port, completion_reason, cb_flags, rval);
5404 
5405                 mutex_enter(HUBD_MUTEX(hubd));
5406 
5407                 return (USB_FAILURE);
5408         } else {
5409 
5410                 mutex_enter(HUBD_MUTEX(hubd));
5411                 ASSERT(completion_reason == 0);
5412                 hubd->h_port_state[port] &= ~PORT_STATUS_PPS;
5413 
5414                 return (USB_SUCCESS);
5415         }
5416 }
5417 
5418 
5419 /*
5420  * Search the database of user preferences and find out the preferred
5421  * configuration for this new device
5422  */
5423 int
5424 hubd_select_device_configuration(hubd_t *hubd, usb_port_t port,
5425         dev_info_t *child_dip, usba_device_t *child_ud)
5426 {
5427         char            *pathname = NULL;
5428         char            *tmp_path = NULL;
5429         int             user_conf;
5430         int             pathlen;
5431         usb_dev_descr_t *usbdev_ptr;
5432         usba_configrec_t *user_pref;
5433 
5434         mutex_enter(&child_ud->usb_mutex);
5435         usbdev_ptr = child_ud->usb_dev_descr;
5436         mutex_exit(&child_ud->usb_mutex);
5437 
5438         /* try to get pathname for this device */
5439         tmp_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
5440         (void) ddi_pathname(child_dip, tmp_path);
5441 
5442         pathlen = strlen(tmp_path) + 32;
5443         pathname = kmem_zalloc(pathlen, KM_SLEEP);
5444 
5445         /*
5446          * We haven't initialized the node and it doesn't have an address
5447          * yet. Append port number to the physical pathname
5448          */
5449         (void) sprintf(pathname, "%s@%d", tmp_path, port);
5450 
5451         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5452             "hubd_select_device_configuration: Device=%s\n\t"
5453             "Child path=%s",
5454             usba_get_mfg_prod_sn_str(child_dip, tmp_path, MAXPATHLEN),
5455             pathname);
5456         kmem_free(tmp_path, MAXPATHLEN);
5457 
5458 
5459         /* database search for user preferences */
5460         user_pref = usba_devdb_get_user_preferences(usbdev_ptr->idVendor,
5461             usbdev_ptr->idProduct, child_ud->usb_serialno_str, pathname);
5462 
5463         if (user_pref) {
5464                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5465                     "hubd_select_device_configuration: "
5466                     "usba_devdb_get_user_preferences "
5467                     "return user_conf=%d\npreferred driver=%s path=%s",
5468                     user_pref->cfg_index, user_pref->driver,
5469                     user_pref->pathname);
5470 
5471                 user_conf = user_pref->cfg_index;
5472 
5473                 if (user_pref->driver) {
5474                         mutex_enter(&child_ud->usb_mutex);
5475                         child_ud->usb_preferred_driver = user_pref->driver;
5476                         mutex_exit(&child_ud->usb_mutex);
5477                 }
5478         } else {
5479                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5480                     "hubd_select_device_configuration: No match found");
5481 
5482                 /* select default configuration for this device */
5483                 user_conf = USBA_DEV_CONFIG_INDEX_UNDEFINED;
5484         }
5485         kmem_free(pathname, pathlen);
5486 
5487         /* if the device has just one configuration, set default value */
5488         if (usbdev_ptr->bNumConfigurations == 1) {
5489                 user_conf = USB_DEV_DEFAULT_CONFIG_INDEX;
5490         }
5491 
5492         return (user_conf);
5493 }
5494 
5495 
5496 /*
5497  * Retrieves config cloud for this configuration
5498  */
5499 int
5500 hubd_get_this_config_cloud(hubd_t *hubd, dev_info_t *dip,
5501         usba_device_t *child_ud, uint16_t conf_index)
5502 {
5503         usb_cfg_descr_t *confdescr;
5504         mblk_t          *pdata = NULL;
5505         int             rval;
5506         size_t          size;
5507         char            *tmpbuf;
5508         usb_cr_t        completion_reason;
5509         usb_cb_flags_t  cb_flags;
5510         usb_pipe_handle_t       def_ph;
5511 
5512         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5513             "hubd_get_this_config_cloud: conf_index=%d", conf_index);
5514 
5515 
5516         /* alloc temporary space for config descriptor */
5517         confdescr = (usb_cfg_descr_t *)kmem_zalloc(USB_CFG_DESCR_SIZE,
5518             KM_SLEEP);
5519 
5520         /* alloc temporary space for string descriptor */
5521         tmpbuf = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
5522 
5523         def_ph = usba_get_dflt_pipe_handle(dip);
5524 
5525         if ((rval = usb_pipe_sync_ctrl_xfer(dip, def_ph,
5526             USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
5527             USB_REQ_GET_DESCR,
5528             USB_DESCR_TYPE_SETUP_CFG | conf_index,
5529             0,
5530             USB_CFG_DESCR_SIZE,
5531             &pdata,
5532             0,
5533             &completion_reason,
5534             &cb_flags,
5535             0)) == USB_SUCCESS) {
5536 
5537                 /* this must be true since we didn't allow data underruns */
5538                 if (MBLKL(pdata) != USB_CFG_DESCR_SIZE) {
5539                         USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5540                             "device returned incorrect configuration "
5541                             "descriptor size.");
5542 
5543                         rval = USB_FAILURE;
5544                         goto done;
5545                 }
5546 
5547                 /*
5548                  * Parse the configuration descriptor
5549                  */
5550                 size = usb_parse_cfg_descr(pdata->b_rptr,
5551                     MBLKL(pdata), confdescr,
5552                     USB_CFG_DESCR_SIZE);
5553 
5554                 /* if parse cfg descr error, it should return failure */
5555                 if (size == USB_PARSE_ERROR) {
5556 
5557                         if (pdata->b_rptr[1] != USB_DESCR_TYPE_CFG) {
5558                                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
5559                                     hubd->h_log_handle,
5560                                     "device returned incorrect "
5561                                     "configuration descriptor type.");
5562                         }
5563                         rval = USB_FAILURE;
5564                         goto done;
5565                 }
5566 
5567                 if (confdescr->wTotalLength < USB_CFG_DESCR_SIZE) {
5568                         USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
5569                             hubd->h_log_handle,
5570                             "device returned incorrect "
5571                             "configuration descriptor size.");
5572 
5573                         rval = USB_FAILURE;
5574                         goto done;
5575                 }
5576 
5577                 freemsg(pdata);
5578                 pdata = NULL;
5579 
5580                 /* Now fetch the complete config cloud */
5581                 if ((rval = usb_pipe_sync_ctrl_xfer(dip, def_ph,
5582                     USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
5583                     USB_REQ_GET_DESCR,
5584                     USB_DESCR_TYPE_SETUP_CFG | conf_index,
5585                     0,
5586                     confdescr->wTotalLength,
5587                     &pdata,
5588                     0,
5589                     &completion_reason,
5590                     &cb_flags,
5591                     0)) == USB_SUCCESS) {
5592 
5593                         if (MBLKL(pdata) !=
5594                             confdescr->wTotalLength) {
5595 
5596                                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
5597                                     hubd->h_log_handle,
5598                                     "device returned incorrect "
5599                                     "configuration descriptor.");
5600 
5601                                 rval = USB_FAILURE;
5602                                 goto done;
5603                         }
5604 
5605                         /*
5606                          * copy config descriptor into usba_device
5607                          */
5608                         mutex_enter(&child_ud->usb_mutex);
5609                         child_ud->usb_cfg_array[conf_index] =
5610                             kmem_alloc(confdescr->wTotalLength, KM_SLEEP);
5611                         child_ud->usb_cfg_array_len[conf_index] =
5612                             confdescr->wTotalLength;
5613                         bcopy((caddr_t)pdata->b_rptr,
5614                             (caddr_t)child_ud->usb_cfg_array[conf_index],
5615                             confdescr->wTotalLength);
5616                         mutex_exit(&child_ud->usb_mutex);
5617 
5618                         /*
5619                          * retrieve string descriptor describing this
5620                          * configuration
5621                          */
5622                         if (confdescr->iConfiguration) {
5623 
5624                                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG,
5625                                     hubd->h_log_handle,
5626                                     "Get conf str descr for config_index=%d",
5627                                     conf_index);
5628 
5629                                 /*
5630                                  * Now fetch the string descriptor describing
5631                                  * this configuration
5632                                  */
5633                                 if ((rval = usb_get_string_descr(dip,
5634                                     USB_LANG_ID, confdescr->iConfiguration,
5635                                     tmpbuf, USB_MAXSTRINGLEN)) ==
5636                                     USB_SUCCESS) {
5637                                         size = strlen(tmpbuf);
5638                                         if (size > 0) {
5639                                                 child_ud->usb_cfg_str_descr
5640                                                     [conf_index] = (char *)
5641                                                     kmem_zalloc(size + 1,
5642                                                     KM_SLEEP);
5643                                                 (void) strcpy(
5644                                                     child_ud->usb_cfg_str_descr
5645                                                     [conf_index], tmpbuf);
5646                                         }
5647                                 } else {
5648                                         USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
5649                                             hubd->h_log_handle,
5650                                             "hubd_get_this_config_cloud: "
5651                                             "getting config string (%d) "
5652                                             "failed",
5653                                             confdescr->iConfiguration);
5654 
5655                                         /* ignore this error */
5656                                         rval = USB_SUCCESS;
5657                                 }
5658                         }
5659                 }
5660         }
5661 
5662 done:
5663         if (rval != USB_SUCCESS) {
5664                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5665                     "hubd_get_this_config_cloud: "
5666                     "error in retrieving config descriptor for "
5667                     "config index=%d rval=%d cr=%d",
5668                     conf_index, rval, completion_reason);
5669         }
5670 
5671         if (pdata) {
5672                 freemsg(pdata);
5673                 pdata = NULL;
5674         }
5675 
5676         kmem_free(confdescr, USB_CFG_DESCR_SIZE);
5677         kmem_free(tmpbuf, USB_MAXSTRINGLEN);
5678 
5679         return (rval);
5680 }
5681 
5682 
5683 /*
5684  * Retrieves the entire config cloud for all configurations of the device
5685  */
5686 int
5687 hubd_get_all_device_config_cloud(hubd_t *hubd, dev_info_t *dip,
5688         usba_device_t *child_ud)
5689 {
5690         int             rval = USB_SUCCESS;
5691         int             ncfgs;
5692         uint16_t        size;
5693         uint16_t        conf_index;
5694         uchar_t         **cfg_array;
5695         uint16_t        *cfg_array_len;
5696         char            **str_descr;
5697 
5698         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5699             "hubd_get_all_device_config_cloud: Start");
5700 
5701         /* alloc pointer array for conf. descriptors */
5702         mutex_enter(&child_ud->usb_mutex);
5703         ncfgs = child_ud->usb_n_cfgs;
5704         mutex_exit(&child_ud->usb_mutex);
5705 
5706         size = sizeof (uchar_t *) * ncfgs;
5707         cfg_array = kmem_zalloc(size, KM_SLEEP);
5708         cfg_array_len = kmem_zalloc(ncfgs * sizeof (uint16_t), KM_SLEEP);
5709         str_descr = kmem_zalloc(size, KM_SLEEP);
5710 
5711         mutex_enter(&child_ud->usb_mutex);
5712         child_ud->usb_cfg_array = cfg_array;
5713         child_ud->usb_cfg_array_len = cfg_array_len;
5714         child_ud->usb_cfg_array_length = size;
5715         child_ud->usb_cfg_array_len_length = ncfgs * sizeof (uint16_t);
5716         child_ud->usb_cfg_str_descr = str_descr;
5717         mutex_exit(&child_ud->usb_mutex);
5718 
5719         /* Get configuration descriptor for each configuration */
5720         for (conf_index = 0; (conf_index < ncfgs) &&
5721             (rval == USB_SUCCESS); conf_index++) {
5722 
5723                 rval = hubd_get_this_config_cloud(hubd, dip, child_ud,
5724                     conf_index);
5725         }
5726 
5727         return (rval);
5728 }
5729 
5730 
5731 /*
5732  * hubd_ready_device:
5733  *      Update the usba_device structure
5734  *      Set the given configuration
5735  *      Prepares the device node for driver to online. If an existing
5736  *      OBP node is found, it will switch to the OBP node.
5737  */
5738 dev_info_t *
5739 hubd_ready_device(hubd_t *hubd, dev_info_t *child_dip, usba_device_t *child_ud,
5740     uint_t config_index)
5741 {
5742         usb_cr_t        completion_reason;
5743         usb_cb_flags_t  cb_flags;
5744         size_t          size;
5745         usb_cfg_descr_t config_descriptor;
5746         usb_pipe_handle_t def_ph;
5747         usba_pipe_handle_data_t *ph;
5748 
5749         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5750             "hubd_ready_device: dip=0x%p, user_conf_index=%d",
5751             (void *)child_dip, config_index);
5752 
5753         size = usb_parse_cfg_descr(
5754             child_ud->usb_cfg_array[config_index], USB_CFG_DESCR_SIZE,
5755             &config_descriptor, USB_CFG_DESCR_SIZE);
5756         ASSERT(size == USB_CFG_DESCR_SIZE);
5757 
5758         def_ph = usba_get_dflt_pipe_handle(child_dip);
5759 
5760         /* Set the configuration */
5761         (void) usb_pipe_sync_ctrl_xfer(child_dip, def_ph,
5762             USB_DEV_REQ_HOST_TO_DEV,
5763             USB_REQ_SET_CFG,    /* bRequest */
5764             config_descriptor.bConfigurationValue,      /* wValue */
5765             0,                          /* wIndex */
5766             0,                          /* wLength */
5767             NULL,
5768             0,
5769             &completion_reason,
5770             &cb_flags,
5771             0);
5772 
5773         mutex_enter(&child_ud->usb_mutex);
5774         child_ud->usb_active_cfg_ndx = config_index;
5775         child_ud->usb_cfg            = child_ud->usb_cfg_array[config_index];
5776         child_ud->usb_cfg_length     = config_descriptor.wTotalLength;
5777         child_ud->usb_cfg_value      = config_descriptor.bConfigurationValue;
5778         child_ud->usb_n_ifs          = config_descriptor.bNumInterfaces;
5779         child_ud->usb_dip            = child_dip;
5780 
5781         child_ud->usb_client_flags   = kmem_zalloc(
5782             child_ud->usb_n_ifs * USBA_CLIENT_FLAG_SIZE, KM_SLEEP);
5783 
5784         child_ud->usb_client_attach_list = kmem_zalloc(
5785             child_ud->usb_n_ifs *
5786             sizeof (*child_ud->usb_client_attach_list), KM_SLEEP);
5787 
5788         child_ud->usb_client_ev_cb_list = kmem_zalloc(
5789             child_ud->usb_n_ifs *
5790             sizeof (*child_ud->usb_client_ev_cb_list), KM_SLEEP);
5791 
5792         mutex_exit(&child_ud->usb_mutex);
5793 
5794         /* ready the device node */
5795         child_dip = usba_ready_device_node(child_dip);
5796 
5797         /* set owner of default pipe to child dip */
5798         ph = usba_get_ph_data(def_ph);
5799         mutex_enter(&ph->p_mutex);
5800         mutex_enter(&ph->p_ph_impl->usba_ph_mutex);
5801         ph->p_ph_impl->usba_ph_dip = ph->p_dip = child_dip;
5802         mutex_exit(&ph->p_ph_impl->usba_ph_mutex);
5803         mutex_exit(&ph->p_mutex);
5804 
5805         return (child_dip);
5806 }
5807 
5808 
5809 /*
5810  * hubd_create_child
5811  *      - create child dip
5812  *      - open default pipe
5813  *      - get device descriptor
5814  *      - set the address
5815  *      - get device string descriptors
5816  *      - get the entire config cloud (all configurations) of the device
5817  *      - set user preferred configuration
5818  *      - close default pipe
5819  *      - load appropriate driver(s)
5820  */
5821 static int
5822 hubd_create_child(dev_info_t *dip,
5823                 hubd_t          *hubd,
5824                 usba_device_t   *hubd_ud,
5825                 usb_port_status_t port_status,
5826                 usb_port_t      port,
5827                 int             iteration)
5828 {
5829         dev_info_t              *child_dip = NULL;
5830         usb_dev_descr_t usb_dev_descr;
5831         int                     rval;
5832         usba_device_t           *child_ud = NULL;
5833         usba_device_t           *parent_ud = NULL;
5834         usb_pipe_handle_t       ph = NULL; /* default pipe handle */
5835         mblk_t                  *pdata = NULL;
5836         usb_cr_t                completion_reason;
5837         int                     user_conf_index;
5838         uint_t                  config_index;
5839         usb_cb_flags_t          cb_flags;
5840         uchar_t                 address = 0;
5841         uint16_t                length;
5842         size_t                  size;
5843         usb_addr_t              parent_usb_addr;
5844         usb_port_t              parent_usb_port;
5845         usba_device_t           *parent_usba_dev;
5846         usb_port_status_t       parent_port_status;
5847 
5848         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5849             "hubd_create_child: port=%d", port);
5850 
5851         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
5852         ASSERT(hubd->h_usba_devices[port] == NULL);
5853 
5854         mutex_exit(HUBD_MUTEX(hubd));
5855 
5856         /*
5857          * create a dip which can be used to open the pipe. we set
5858          * the name after getting the descriptors from the device
5859          */
5860         rval = usba_create_child_devi(dip,
5861             "device",           /* driver name */
5862             hubd_ud->usb_hcdi_ops, /* usba_hcdi ops */
5863             hubd_ud->usb_root_hub_dip,
5864             port_status,                /* low speed device */
5865             child_ud,
5866             &child_dip);
5867 
5868         if (rval != USB_SUCCESS) {
5869 
5870                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5871                     "usb_create_child_devi failed (%d)", rval);
5872 
5873                 goto fail_cleanup;
5874         }
5875 
5876         child_ud = usba_get_usba_device(child_dip);
5877         ASSERT(child_ud != NULL);
5878 
5879         parent_ud = hubd->h_usba_device;
5880         mutex_enter(&parent_ud->usb_mutex);
5881         parent_port_status = parent_ud->usb_port_status;
5882 
5883         /*
5884          * To support split transactions, update address and port
5885          * of high speed hub to which given device is connected.
5886          */
5887         if (parent_port_status == USBA_HIGH_SPEED_DEV) {
5888                 parent_usba_dev = parent_ud;
5889                 parent_usb_addr = parent_ud->usb_addr;
5890                 parent_usb_port = port;
5891         } else {
5892                 parent_usba_dev = parent_ud->usb_hs_hub_usba_dev;
5893                 parent_usb_addr = parent_ud->usb_hs_hub_addr;
5894                 parent_usb_port = parent_ud->usb_hs_hub_port;
5895         }
5896         mutex_exit(&parent_ud->usb_mutex);
5897 
5898         mutex_enter(&child_ud->usb_mutex);
5899         address = child_ud->usb_addr;
5900         child_ud->usb_addr = 0;
5901         child_ud->usb_dev_descr = kmem_alloc(sizeof (usb_dev_descr_t),
5902             KM_SLEEP);
5903         bzero(&usb_dev_descr, sizeof (usb_dev_descr_t));
5904         usb_dev_descr.bMaxPacketSize0 =
5905             (port_status == USBA_LOW_SPEED_DEV) ? 8 : 64;
5906         bcopy(&usb_dev_descr, child_ud->usb_dev_descr,
5907             sizeof (usb_dev_descr_t));
5908         child_ud->usb_port = port;
5909         child_ud->usb_hs_hub_usba_dev = parent_usba_dev;
5910         child_ud->usb_hs_hub_addr = parent_usb_addr;
5911         child_ud->usb_hs_hub_port = parent_usb_port;
5912         mutex_exit(&child_ud->usb_mutex);
5913 
5914         /* Open the default pipe */
5915         if ((rval = usb_pipe_open(child_dip, NULL, NULL,
5916             USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) != USB_SUCCESS) {
5917                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5918                     "usb_pipe_open failed (%d)", rval);
5919 
5920                 goto fail_cleanup;
5921         }
5922 
5923         /*
5924          * get device descriptor
5925          */
5926         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5927             "hubd_create_child: get device descriptor: 64 bytes");
5928 
5929         rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
5930             USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
5931             USB_REQ_GET_DESCR,                  /* bRequest */
5932             USB_DESCR_TYPE_SETUP_DEV,           /* wValue */
5933             0,                                  /* wIndex */
5934             64,                                 /* wLength */
5935             &pdata, USB_ATTRS_SHORT_XFER_OK,
5936             &completion_reason, &cb_flags, 0);
5937 
5938         if ((rval != USB_SUCCESS) &&
5939             (!((completion_reason == USB_CR_DATA_OVERRUN) && pdata))) {
5940 
5941                 /*
5942                  * rval != USB_SUCCESS AND
5943                  * completion_reason != USB_CR_DATA_OVERRUN
5944                  * pdata could be != NULL.
5945                  * Free pdata now to prevent memory leak.
5946                  */
5947                 freemsg(pdata);
5948                 pdata = NULL;
5949 
5950                 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5951                     "hubd_create_child: get device descriptor: 8 bytes");
5952 
5953                 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
5954                     USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
5955                     USB_REQ_GET_DESCR,                  /* bRequest */
5956                     USB_DESCR_TYPE_SETUP_DEV,           /* wValue */
5957                     0,                                  /* wIndex */
5958                     8,                                  /* wLength */
5959                     &pdata, USB_ATTRS_NONE,
5960                     &completion_reason, &cb_flags, 0);
5961 
5962                 if (rval != USB_SUCCESS) {
5963                         USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5964                             "getting device descriptor failed (%s 0x%x %d)",
5965                             usb_str_cr(completion_reason), cb_flags, rval);
5966                         goto fail_cleanup;
5967                 }
5968         } else {
5969                 ASSERT(completion_reason == USB_CR_OK);
5970         }
5971 
5972         ASSERT(pdata != NULL);
5973 
5974         size = usb_parse_dev_descr(
5975             pdata->b_rptr,
5976             MBLKL(pdata),
5977             &usb_dev_descr,
5978             sizeof (usb_dev_descr_t));
5979 
5980         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5981             "parsing device descriptor returned %lu", size);
5982 
5983         length = *(pdata->b_rptr);
5984         freemsg(pdata);
5985         pdata = NULL;
5986         if (size < 8) {
5987                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5988                     "get device descriptor returned %lu bytes", size);
5989 
5990                 goto fail_cleanup;
5991         }
5992 
5993         if (length < 8) {
5994                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5995                     "fail enumeration: bLength=%d", length);
5996 
5997                 goto fail_cleanup;
5998         }
5999 
6000         /* Set the address of the device */
6001         if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
6002             USB_DEV_REQ_HOST_TO_DEV,
6003             USB_REQ_SET_ADDRESS,        /* bRequest */
6004             address,                    /* wValue */
6005             0,                          /* wIndex */
6006             0,                          /* wLength */
6007             NULL, 0,
6008             &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
6009                 char buffer[64];
6010                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6011                     "setting address failed (cr=%s cb_flags=%s rval=%d)",
6012                     usb_str_cr(completion_reason),
6013                     usb_str_cb_flags(cb_flags, buffer, sizeof (buffer)),
6014                     rval);
6015 
6016                 goto fail_cleanup;
6017         }
6018 
6019         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6020             "set address 0x%x done", address);
6021 
6022         /* now close the pipe for addr 0 */
6023         usb_pipe_close(child_dip, ph,
6024             USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
6025 
6026         /*
6027          * This delay is important for the CATC hub to enumerate
6028          * But, avoid delay in the first iteration
6029          */
6030         if (iteration) {
6031                 delay(drv_usectohz(hubd_device_delay/100));
6032         }
6033 
6034         /* assign the address in the usba_device structure */
6035         mutex_enter(&child_ud->usb_mutex);
6036         child_ud->usb_addr = address;
6037         child_ud->usb_no_cpr = 0;
6038         child_ud->usb_port_status = port_status;
6039         /* save this device descriptor */
6040         bcopy(&usb_dev_descr, child_ud->usb_dev_descr,
6041             sizeof (usb_dev_descr_t));
6042         child_ud->usb_n_cfgs = usb_dev_descr.bNumConfigurations;
6043         mutex_exit(&child_ud->usb_mutex);
6044 
6045         /* re-open the pipe for the device with the new address */
6046         if ((rval = usb_pipe_open(child_dip, NULL, NULL,
6047             USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) != USB_SUCCESS) {
6048                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6049                     "usb_pipe_open failed (%d)", rval);
6050 
6051                 goto fail_cleanup;
6052         }
6053 
6054         /*
6055          * Get full device descriptor only if we have not received full
6056          * device descriptor earlier.
6057          */
6058         if (size < length) {
6059                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6060                     "hubd_create_child: get full device descriptor: "
6061                     "%d bytes", length);
6062 
6063                 if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
6064                     USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
6065                     USB_REQ_GET_DESCR,                  /* bRequest */
6066                     USB_DESCR_TYPE_SETUP_DEV,           /* wValue */
6067                     0,                                  /* wIndex */
6068                     length,                             /* wLength */
6069                     &pdata, 0,
6070                     &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
6071                         freemsg(pdata);
6072                         pdata = NULL;
6073 
6074                         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG,
6075                             hubd->h_log_handle,
6076                             "hubd_create_child: get full device descriptor: "
6077                             "64 bytes");
6078 
6079                         rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
6080                             USB_DEV_REQ_DEV_TO_HOST |
6081                             USB_DEV_REQ_TYPE_STANDARD,
6082                             USB_REQ_GET_DESCR,          /* bRequest */
6083                             USB_DESCR_TYPE_SETUP_DEV,   /* wValue */
6084                             0,                          /* wIndex */
6085                             64,                         /* wLength */
6086                             &pdata, USB_ATTRS_SHORT_XFER_OK,
6087                             &completion_reason, &cb_flags, 0);
6088 
6089                         /* we have to trust the data now */
6090                         if (pdata) {
6091                                 int len = *(pdata->b_rptr);
6092 
6093                                 length = MBLKL(pdata);
6094                                 if (length < len) {
6095 
6096                                         goto fail_cleanup;
6097                                 }
6098                         } else if (rval != USB_SUCCESS) {
6099                                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
6100                                     hubd->h_log_handle,
6101                                     "getting device descriptor failed "
6102                                     "(%d 0x%x %d)",
6103                                     completion_reason, cb_flags, rval);
6104 
6105                                 goto fail_cleanup;
6106                         }
6107                 }
6108 
6109                 size = usb_parse_dev_descr(
6110                     pdata->b_rptr,
6111                     MBLKL(pdata),
6112                     &usb_dev_descr,
6113                     sizeof (usb_dev_descr_t));
6114 
6115                 USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6116                     "parsing device descriptor returned %lu", size);
6117 
6118                 /*
6119                  * For now, free the data
6120                  * eventually, each configuration may need to be looked at
6121                  */
6122                 freemsg(pdata);
6123                 pdata = NULL;
6124 
6125                 if (size != USB_DEV_DESCR_SIZE) {
6126                         USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6127                             "fail enumeration: descriptor size=%lu "
6128                             "expected size=%u", size, USB_DEV_DESCR_SIZE);
6129 
6130                         goto fail_cleanup;
6131                 }
6132 
6133                 /*
6134                  * save the device descriptor in usba_device since it is needed
6135                  * later on again
6136                  */
6137                 mutex_enter(&child_ud->usb_mutex);
6138                 bcopy(&usb_dev_descr, child_ud->usb_dev_descr,
6139                     sizeof (usb_dev_descr_t));
6140                 child_ud->usb_n_cfgs = usb_dev_descr.bNumConfigurations;
6141                 mutex_exit(&child_ud->usb_mutex);
6142         }
6143 
6144         if (usb_dev_descr.bNumConfigurations == 0) {
6145                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6146                     "device descriptor:\n\t"
6147                     "l=0x%x type=0x%x USB=0x%x class=0x%x subclass=0x%x\n\t"
6148                     "protocol=0x%x maxpktsize=0x%x "
6149                     "Vid=0x%x Pid=0x%x rel=0x%x\n\t"
6150                     "Mfg=0x%x P=0x%x sn=0x%x #config=0x%x",
6151                     usb_dev_descr.bLength, usb_dev_descr.bDescriptorType,
6152                     usb_dev_descr.bcdUSB, usb_dev_descr.bDeviceClass,
6153                     usb_dev_descr.bDeviceSubClass,
6154                     usb_dev_descr.bDeviceProtocol,
6155                     usb_dev_descr.bMaxPacketSize0,
6156                     usb_dev_descr.idVendor,
6157                     usb_dev_descr.idProduct, usb_dev_descr.bcdDevice,
6158                     usb_dev_descr.iManufacturer, usb_dev_descr.iProduct,
6159                     usb_dev_descr.iSerialNumber,
6160                     usb_dev_descr.bNumConfigurations);
6161                 goto fail_cleanup;
6162         }
6163 
6164 
6165         /* get the device string descriptor(s) */
6166         usba_get_dev_string_descrs(child_dip, child_ud);
6167 
6168         /* retrieve config cloud for all configurations */
6169         rval = hubd_get_all_device_config_cloud(hubd, child_dip, child_ud);
6170         if (rval != USB_SUCCESS) {
6171                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6172                     "failed to get configuration descriptor(s)");
6173 
6174                 goto fail_cleanup;
6175         }
6176 
6177         /* get the preferred configuration for this device */
6178         user_conf_index = hubd_select_device_configuration(hubd, port,
6179             child_dip, child_ud);
6180 
6181         /* Check if the user selected configuration index is in range */
6182         if ((user_conf_index >= usb_dev_descr.bNumConfigurations) ||
6183             (user_conf_index < 0)) {
6184                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6185                     "Configuration index for device idVendor=%d "
6186                     "idProduct=%d is=%d, and is out of range[0..%d]",
6187                     usb_dev_descr.idVendor, usb_dev_descr.idProduct,
6188                     user_conf_index, usb_dev_descr.bNumConfigurations - 1);
6189 
6190                 /* treat this as user didn't specify configuration */
6191                 user_conf_index = USBA_DEV_CONFIG_INDEX_UNDEFINED;
6192         }
6193 
6194 
6195         /*
6196          * Warn users of a performance hit if connecting a
6197          * High Speed behind a 1.1 hub, which is behind a
6198          * 2.0 port.
6199          */
6200         if ((parent_port_status != USBA_HIGH_SPEED_DEV) &&
6201             !(usba_is_root_hub(parent_ud->usb_dip)) &&
6202             (parent_usb_addr)) {
6203 
6204                 /*
6205                  * Now that we know the root port is a high speed port
6206                  * and that the parent port is not a high speed port,
6207                  * let's find out if the device itself is a high speed
6208                  * device.  If it is a high speed device,
6209                  * USB_DESCR_TYPE_SETUP_DEV_QLF should return a value,
6210                  * otherwise the command will fail.
6211                  */
6212                 rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
6213                     USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
6214                     USB_REQ_GET_DESCR,                  /* bRequest */
6215                     USB_DESCR_TYPE_SETUP_DEV_QLF,       /* wValue */
6216                     0,                                  /* wIndex */
6217                     10,                                 /* wLength */
6218                     &pdata, USB_ATTRS_SHORT_XFER_OK,
6219                     &completion_reason, &cb_flags, 0);
6220 
6221                 if (pdata) {
6222                         freemsg(pdata);
6223                         pdata = NULL;
6224                 }
6225 
6226                 /*
6227                  * USB_DESCR_TYPE_SETUP_DEV_QLF query was successful
6228                  * that means this is a high speed device behind a
6229                  * high speed root hub, but running at full speed
6230                  * because there is a full speed hub in the middle.
6231                  */
6232                 if (rval == USB_SUCCESS) {
6233                         USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG,
6234                             hubd->h_log_handle,
6235                             "Connecting a high speed device to a "
6236                             "non high speed hub (port %d) will result "
6237                             "in a loss of performance.  Please connect "
6238                             "the device to a high speed hub to get "
6239                             "the maximum performance.",
6240                             port);
6241                 }
6242         }
6243 
6244         /*
6245          * Now we try to online the device by attaching a driver
6246          * The following truth table illustrates the logic:-
6247          * Cfgndx       Driver  Action
6248          * 0            0       loop all configs for driver with full
6249          *                      compatible properties.
6250          * 0            1       set first configuration,
6251          *                      compatible prop = drivername.
6252          * 1            0       Set config, full compatible prop
6253          * 1            1       Set config, compatible prop = drivername.
6254          *
6255          * Note:
6256          *      cfgndx = user_conf_index
6257          *      Driver = usb_preferred_driver
6258          */
6259         if (user_conf_index == USBA_DEV_CONFIG_INDEX_UNDEFINED) {
6260                 if (child_ud->usb_preferred_driver) {
6261                         /*
6262                          * It is the job of the "preferred driver" to put the
6263                          * device in the desired configuration. Till then
6264                          * put the device in config index 0.
6265                          */
6266                         if ((rval = usba_hubdi_check_power_budget(dip, child_ud,
6267                             USB_DEV_DEFAULT_CONFIG_INDEX)) != USB_SUCCESS) {
6268 
6269                                 goto fail_cleanup;
6270                         }
6271 
6272                         child_dip = hubd_ready_device(hubd, child_dip,
6273                             child_ud, USB_DEV_DEFAULT_CONFIG_INDEX);
6274 
6275                         /*
6276                          * Assign the dip before onlining to avoid race
6277                          * with busctl
6278                          */
6279                         mutex_enter(HUBD_MUTEX(hubd));
6280                         hubd->h_children_dips[port] = child_dip;
6281                         mutex_exit(HUBD_MUTEX(hubd));
6282 
6283                         (void) usba_bind_driver(child_dip);
6284                 } else {
6285                         /*
6286                          * loop through all the configurations to see if we
6287                          * can find a driver for any one config. If not, set
6288                          * the device in config_index 0
6289                          */
6290                         rval = USB_FAILURE;
6291                         for (config_index = 0;
6292                             (config_index < usb_dev_descr.bNumConfigurations) &&
6293                             (rval != USB_SUCCESS); config_index++) {
6294 
6295                                 child_dip = hubd_ready_device(hubd, child_dip,
6296                                     child_ud, config_index);
6297 
6298                                 /*
6299                                  * Assign the dip before onlining to avoid race
6300                                  * with busctl
6301                                  */
6302                                 mutex_enter(HUBD_MUTEX(hubd));
6303                                 hubd->h_children_dips[port] = child_dip;
6304                                 mutex_exit(HUBD_MUTEX(hubd));
6305 
6306                                 rval = usba_bind_driver(child_dip);
6307 
6308                                 /*
6309                                  * Normally power budget should be checked
6310                                  * before device is configured. A failure in
6311                                  * power budget checking will stop the device
6312                                  * from being configured with current
6313                                  * config_index and may enable the device to
6314                                  * be configured in another configuration.
6315                                  * This may break the user experience that a
6316                                  * device which previously worked in config
6317                                  * A now works in config B after power budget
6318                                  * control is enabled. To avoid such situation,
6319                                  * power budget checking is moved here and will
6320                                  * fail the child creation directly if config
6321                                  * A exceeds the power available.
6322                                  */
6323                                 if (rval == USB_SUCCESS) {
6324                                         if ((usba_hubdi_check_power_budget(dip,
6325                                             child_ud, config_index)) !=
6326                                             USB_SUCCESS) {
6327 
6328                                                 goto fail_cleanup;
6329                                         }
6330                                 }
6331                         }
6332                         if (rval != USB_SUCCESS) {
6333 
6334                                 if ((usba_hubdi_check_power_budget(dip,
6335                                     child_ud, 0)) != USB_SUCCESS) {
6336 
6337                                         goto fail_cleanup;
6338                                 }
6339 
6340                                 child_dip = hubd_ready_device(hubd, child_dip,
6341                                     child_ud, 0);
6342                                 mutex_enter(HUBD_MUTEX(hubd));
6343                                 hubd->h_children_dips[port] = child_dip;
6344                                 mutex_exit(HUBD_MUTEX(hubd));
6345                         }
6346                 } /* end else loop all configs */
6347         } else {
6348 
6349                 if ((usba_hubdi_check_power_budget(dip, child_ud,
6350                     (uint_t)user_conf_index)) != USB_SUCCESS) {
6351 
6352                         goto fail_cleanup;
6353                 }
6354 
6355                 child_dip = hubd_ready_device(hubd, child_dip,
6356                     child_ud, (uint_t)user_conf_index);
6357 
6358                 /*
6359                  * Assign the dip before onlining to avoid race
6360                  * with busctl
6361                  */
6362                 mutex_enter(HUBD_MUTEX(hubd));
6363                 hubd->h_children_dips[port] = child_dip;
6364                 mutex_exit(HUBD_MUTEX(hubd));
6365 
6366                 (void) usba_bind_driver(child_dip);
6367         }
6368 
6369         usba_hubdi_decr_power_budget(dip, child_ud);
6370 
6371         mutex_enter(HUBD_MUTEX(hubd));
6372         if (hubd->h_usba_devices[port] == NULL) {
6373                 hubd->h_usba_devices[port] = usba_get_usba_device(child_dip);
6374         } else {
6375                 ASSERT(hubd->h_usba_devices[port] ==
6376                     usba_get_usba_device(child_dip));
6377         }
6378 
6379         return (USB_SUCCESS);
6380 
6381 
6382 fail_cleanup:
6383         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6384             "hubd_create_child: fail_cleanup");
6385 
6386         mutex_enter(HUBD_MUTEX(hubd));
6387         hubd->h_children_dips[port] = NULL;
6388         mutex_exit(HUBD_MUTEX(hubd));
6389 
6390         if (pdata) {
6391                 freemsg(pdata);
6392         }
6393 
6394         if (ph) {
6395                 usb_pipe_close(child_dip, ph,
6396                     USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
6397         }
6398 
6399         if (child_dip) {
6400                 int rval = usba_destroy_child_devi(child_dip,
6401                     NDI_DEVI_REMOVE);
6402                 if (rval != USB_SUCCESS) {
6403                         USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6404                             "failure to remove child node");
6405                 }
6406         }
6407 
6408         if (child_ud) {
6409                 /* to make sure we free the address */
6410                 mutex_enter(&child_ud->usb_mutex);
6411                 child_ud->usb_addr = address;
6412                 ASSERT(child_ud->usb_ref_count == 0);
6413                 mutex_exit(&child_ud->usb_mutex);
6414 
6415                 mutex_enter(HUBD_MUTEX(hubd));
6416                 if (hubd->h_usba_devices[port] == NULL) {
6417                         mutex_exit(HUBD_MUTEX(hubd));
6418                         usba_free_usba_device(child_ud);
6419                 } else {
6420                         hubd_free_usba_device(hubd, hubd->h_usba_devices[port]);
6421                         mutex_exit(HUBD_MUTEX(hubd));
6422                 }
6423         }
6424 
6425         mutex_enter(HUBD_MUTEX(hubd));
6426 
6427         return (USB_FAILURE);
6428 }
6429 
6430 
6431 /*
6432  * hubd_delete_child:
6433  *      - free usb address
6434  *      - lookup child dips, there may be multiple on this port
6435  *      - offline each child devi
6436  */
6437 static int
6438 hubd_delete_child(hubd_t *hubd, usb_port_t port, uint_t flag, boolean_t retry)
6439 {
6440         dev_info_t      *child_dip;
6441         usba_device_t   *usba_device;
6442         int             rval = USB_SUCCESS;
6443 
6444         child_dip = hubd->h_children_dips[port];
6445         usba_device = hubd->h_usba_devices[port];
6446 
6447         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6448             "hubd_delete_child: port=%d, dip=0x%p usba_device=0x%p",
6449             port, (void *)child_dip, (void *)usba_device);
6450 
6451         mutex_exit(HUBD_MUTEX(hubd));
6452         if (child_dip) {
6453                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6454                     "hubd_delete_child:\n\t"
6455                     "dip = 0x%p (%s) at port %d",
6456                     (void *)child_dip, ddi_node_name(child_dip), port);
6457 
6458                 if (usba_device) {
6459                         usba_hubdi_incr_power_budget(hubd->h_dip, usba_device);
6460                 }
6461 
6462                 rval = usba_destroy_child_devi(child_dip, flag);
6463 
6464                 if ((rval == USB_SUCCESS) && (flag & NDI_DEVI_REMOVE)) {
6465                         /*
6466                          * if the child was still < DS_INITIALIZED
6467                          * then our bus_unconfig was not called and
6468                          * we have to zap the child here
6469                          */
6470                         mutex_enter(HUBD_MUTEX(hubd));
6471                         if (hubd->h_children_dips[port] == child_dip) {
6472                                 usba_device_t *ud =
6473                                     hubd->h_usba_devices[port];
6474                                         hubd->h_children_dips[port] = NULL;
6475                                 if (ud) {
6476                                         mutex_exit(HUBD_MUTEX(hubd));
6477 
6478                                         mutex_enter(&ud->usb_mutex);
6479                                         ud->usb_ref_count = 0;
6480                                         mutex_exit(&ud->usb_mutex);
6481 
6482                                         usba_free_usba_device(ud);
6483                                         mutex_enter(HUBD_MUTEX(hubd));
6484                                         hubd->h_usba_devices[port] = NULL;
6485                                 }
6486                         }
6487                         mutex_exit(HUBD_MUTEX(hubd));
6488                 }
6489         }
6490 
6491         if ((rval != USB_SUCCESS) && retry) {
6492 
6493                 hubd_schedule_cleanup(usba_device->usb_root_hub_dip);
6494         }
6495         mutex_enter(HUBD_MUTEX(hubd));
6496 
6497         return (rval);
6498 }
6499 
6500 
6501 /*
6502  * hubd_free_usba_device:
6503  *      free usb device structure unless it is associated with
6504  *      the root hub which is handled differently
6505  */
6506 static void
6507 hubd_free_usba_device(hubd_t *hubd, usba_device_t *usba_device)
6508 {
6509         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6510             "hubd_free_usba_device: hubd=0x%p, usba_device=0x%p",
6511             (void *)hubd, (void *)usba_device);
6512 
6513         if (usba_device && (usba_device->usb_addr != ROOT_HUB_ADDR)) {
6514                 usb_port_t port = usba_device->usb_port;
6515                 dev_info_t *dip = hubd->h_children_dips[port];
6516 
6517 #ifdef DEBUG
6518                 if (dip) {
6519                         ASSERT(i_ddi_node_state(dip) < DS_INITIALIZED);
6520                 }
6521 #endif
6522 
6523                 port = usba_device->usb_port;
6524                 hubd->h_usba_devices[port] = NULL;
6525 
6526                 mutex_exit(HUBD_MUTEX(hubd));
6527                 usba_free_usba_device(usba_device);
6528                 mutex_enter(HUBD_MUTEX(hubd));
6529         }
6530 }
6531 
6532 
6533 /*
6534  * event support
6535  *
6536  * busctl event support
6537  */
6538 static int
6539 hubd_busop_get_eventcookie(dev_info_t *dip,
6540         dev_info_t      *rdip,
6541         char            *eventname,
6542         ddi_eventcookie_t *cookie)
6543 {
6544         hubd_t  *hubd = (hubd_t *)hubd_get_soft_state(dip);
6545 
6546         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6547             "hubd_busop_get_eventcookie: dip=0x%p, rdip=0x%p, "
6548             "event=%s", (void *)dip, (void *)rdip, eventname);
6549         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6550             "(dip=%s%d, rdip=%s%d)",
6551             ddi_driver_name(dip), ddi_get_instance(dip),
6552             ddi_driver_name(rdip), ddi_get_instance(rdip));
6553 
6554         /* return event cookie, iblock cookie, and level */
6555         return (ndi_event_retrieve_cookie(hubd->h_ndi_event_hdl,
6556             rdip, eventname, cookie, NDI_EVENT_NOPASS));
6557 }
6558 
6559 
6560 static int
6561 hubd_busop_add_eventcall(dev_info_t *dip,
6562         dev_info_t      *rdip,
6563         ddi_eventcookie_t cookie,
6564         void            (*callback)(dev_info_t *dip,
6565                         ddi_eventcookie_t cookie, void *arg,
6566                         void *bus_impldata),
6567         void *arg, ddi_callback_id_t *cb_id)
6568 {
6569         hubd_t  *hubd = (hubd_t *)hubd_get_soft_state(dip);
6570         usb_port_t port = hubd_child_dip2port(hubd, rdip);
6571 
6572         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6573             "hubd_busop_add_eventcall: dip=0x%p, rdip=0x%p "
6574             "cookie=0x%p, cb=0x%p, arg=0x%p",
6575             (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg);
6576         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6577             "(dip=%s%d, rdip=%s%d, event=%s)",
6578             ddi_driver_name(dip), ddi_get_instance(dip),
6579             ddi_driver_name(rdip), ddi_get_instance(rdip),
6580             ndi_event_cookie_to_name(hubd->h_ndi_event_hdl, cookie));
6581 
6582         /* Set flag on children registering events */
6583         switch (ndi_event_cookie_to_tag(hubd->h_ndi_event_hdl, cookie)) {
6584         case USBA_EVENT_TAG_HOT_REMOVAL:
6585                 mutex_enter(HUBD_MUTEX(hubd));
6586                 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_DISCONNECT;
6587                 mutex_exit(HUBD_MUTEX(hubd));
6588 
6589                 break;
6590         case USBA_EVENT_TAG_PRE_SUSPEND:
6591                 mutex_enter(HUBD_MUTEX(hubd));
6592                 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_PRESUSPEND;
6593                 mutex_exit(HUBD_MUTEX(hubd));
6594 
6595                 break;
6596         default:
6597 
6598                 break;
6599         }
6600 
6601         /* add callback to our event set */
6602         return (ndi_event_add_callback(hubd->h_ndi_event_hdl,
6603             rdip, cookie, callback, arg, NDI_SLEEP, cb_id));
6604 }
6605 
6606 
6607 static int
6608 hubd_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
6609 {
6610         hubd_t  *hubd = (hubd_t *)hubd_get_soft_state(dip);
6611         ndi_event_callbacks_t *id = (ndi_event_callbacks_t *)cb_id;
6612 
6613         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6614             "hubd_busop_remove_eventcall: dip=0x%p, rdip=0x%p "
6615             "cookie=0x%p", (void *)dip, (void *)id->ndi_evtcb_dip,
6616             (void *)id->ndi_evtcb_cookie);
6617         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6618             "(dip=%s%d, rdip=%s%d, event=%s)",
6619             ddi_driver_name(dip), ddi_get_instance(dip),
6620             ddi_driver_name(id->ndi_evtcb_dip),
6621             ddi_get_instance(id->ndi_evtcb_dip),
6622             ndi_event_cookie_to_name(hubd->h_ndi_event_hdl,
6623             id->ndi_evtcb_cookie));
6624 
6625         /* remove event registration from our event set */
6626         return (ndi_event_remove_callback(hubd->h_ndi_event_hdl, cb_id));
6627 }
6628 
6629 
6630 /*
6631  * event distribution
6632  *
6633  * hubd_do_callback:
6634  *      Post this event to the specified child
6635  */
6636 static void
6637 hubd_do_callback(hubd_t *hubd, dev_info_t *cdip, ddi_eventcookie_t cookie)
6638 {
6639         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6640             "hubd_do_callback");
6641 
6642         (void) ndi_event_do_callback(hubd->h_ndi_event_hdl, cdip, cookie, NULL);
6643 }
6644 
6645 
6646 /*
6647  * hubd_run_callbacks:
6648  *      Send this event to all children
6649  */
6650 static void
6651 hubd_run_callbacks(hubd_t *hubd, usba_event_t type)
6652 {
6653         usb_port_t      port;
6654 
6655         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6656             "hubd_run_callbacks");
6657 
6658         mutex_enter(HUBD_MUTEX(hubd));
6659         for (port = 1; port <= hubd->h_hub_descr.bNbrPorts; port++) {
6660                 /*
6661                  * the childen_dips list may have dips that have been
6662                  * already deallocated. we only get a post_detach notification
6663                  * but not a destroy notification
6664                  */
6665                 if (hubd->h_children_dips[port]) {
6666                         mutex_exit(HUBD_MUTEX(hubd));
6667                         hubd_post_event(hubd, port, type);
6668                         mutex_enter(HUBD_MUTEX(hubd));
6669                 }
6670         }
6671         mutex_exit(HUBD_MUTEX(hubd));
6672 }
6673 
6674 
6675 /*
6676  * hubd_post_event
6677  *      post event to a child on the port depending on the type
6678  */
6679 static void
6680 hubd_post_event(hubd_t *hubd, usb_port_t port, usba_event_t type)
6681 {
6682         int     rval;
6683         dev_info_t      *dip;
6684         usba_device_t   *usba_device;
6685         ddi_eventcookie_t cookie, rm_cookie, suspend_cookie;
6686 
6687         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6688             "hubd_post_event: port=%d event=%s", port,
6689             ndi_event_tag_to_name(hubd->h_ndi_event_hdl, type));
6690 
6691         cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl, type);
6692         rm_cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl,
6693             USBA_EVENT_TAG_HOT_REMOVAL);
6694         suspend_cookie = ndi_event_tag_to_cookie(hubd->h_ndi_event_hdl,
6695             USBA_EVENT_TAG_PRE_SUSPEND);
6696 
6697         /*
6698          * Hotplug daemon may be attaching a driver that may be registering
6699          * event callbacks. So it already has got the device tree lock and
6700          * event handle mutex. So to prevent a deadlock while posting events,
6701          * we grab and release the locks in the same order.
6702          */
6703         mutex_enter(HUBD_MUTEX(hubd));
6704         dip = hubd->h_children_dips[port];
6705         usba_device = hubd->h_usba_devices[port];
6706         mutex_exit(HUBD_MUTEX(hubd));
6707 
6708         switch (type) {
6709         case USBA_EVENT_TAG_HOT_REMOVAL:
6710                 /* Clear the registered event flag */
6711                 mutex_enter(HUBD_MUTEX(hubd));
6712                 hubd->h_child_events[port] &= ~HUBD_CHILD_EVENT_DISCONNECT;
6713                 mutex_exit(HUBD_MUTEX(hubd));
6714 
6715                 hubd_do_callback(hubd, dip, cookie);
6716                 usba_persistent_pipe_close(usba_device);
6717 
6718                 /*
6719                  * Mark the dip for deletion only after the driver has
6720                  * seen the disconnect event to prevent cleanup thread
6721                  * from stepping in between.
6722                  */
6723                 mutex_enter(&(DEVI(dip)->devi_lock));
6724                 DEVI_SET_DEVICE_REMOVED(dip);
6725                 mutex_exit(&(DEVI(dip)->devi_lock));
6726 
6727                 break;
6728         case USBA_EVENT_TAG_PRE_SUSPEND:
6729                 mutex_enter(HUBD_MUTEX(hubd));
6730                 hubd->h_child_events[port] &= ~HUBD_CHILD_EVENT_PRESUSPEND;
6731                 mutex_exit(HUBD_MUTEX(hubd));
6732 
6733                 hubd_do_callback(hubd, dip, cookie);
6734                 /*
6735                  * persistent pipe close for this event is taken care by the
6736                  * caller after verfying that all children can suspend
6737                  */
6738 
6739                 break;
6740         case USBA_EVENT_TAG_HOT_INSERTION:
6741                 /*
6742                  * Check if this child has missed the disconnect event before
6743                  * it registered for event callbacks
6744                  */
6745                 mutex_enter(HUBD_MUTEX(hubd));
6746                 if (hubd->h_child_events[port] & HUBD_CHILD_EVENT_DISCONNECT) {
6747                         /* clear the flag and post disconnect event */
6748                         hubd->h_child_events[port] &=
6749                             ~HUBD_CHILD_EVENT_DISCONNECT;
6750                         mutex_exit(HUBD_MUTEX(hubd));
6751                         hubd_do_callback(hubd, dip, rm_cookie);
6752                         usba_persistent_pipe_close(usba_device);
6753                         mutex_enter(HUBD_MUTEX(hubd));
6754                 }
6755                 mutex_exit(HUBD_MUTEX(hubd));
6756 
6757                 /*
6758                  * Mark the dip as reinserted to prevent cleanup thread
6759                  * from stepping in.
6760                  */
6761                 mutex_enter(&(DEVI(dip)->devi_lock));
6762                 DEVI_SET_DEVICE_REINSERTED(dip);
6763                 mutex_exit(&(DEVI(dip)->devi_lock));
6764 
6765                 rval = usba_persistent_pipe_open(usba_device);
6766                 if (rval != USB_SUCCESS) {
6767                         USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
6768                             hubd->h_log_handle,
6769                             "failed to reopen all pipes on reconnect");
6770                 }
6771 
6772                 hubd_do_callback(hubd, dip, cookie);
6773 
6774                 /*
6775                  * We might see a connect event only if hotplug thread for
6776                  * disconnect event don't run in time.
6777                  * Set the flag again, so we don't miss posting a
6778                  * disconnect event.
6779                  */
6780                 mutex_enter(HUBD_MUTEX(hubd));
6781                 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_DISCONNECT;
6782                 mutex_exit(HUBD_MUTEX(hubd));
6783 
6784                 break;
6785         case USBA_EVENT_TAG_POST_RESUME:
6786                 /*
6787                  * Check if this child has missed the pre-suspend event before
6788                  * it registered for event callbacks
6789                  */
6790                 mutex_enter(HUBD_MUTEX(hubd));
6791                 if (hubd->h_child_events[port] & HUBD_CHILD_EVENT_PRESUSPEND) {
6792                         /* clear the flag and post pre_suspend event */
6793                         hubd->h_port_state[port] &=
6794                             ~HUBD_CHILD_EVENT_PRESUSPEND;
6795                         mutex_exit(HUBD_MUTEX(hubd));
6796                         hubd_do_callback(hubd, dip, suspend_cookie);
6797                         mutex_enter(HUBD_MUTEX(hubd));
6798                 }
6799                 mutex_exit(HUBD_MUTEX(hubd));
6800 
6801                 mutex_enter(&usba_device->usb_mutex);
6802                 usba_device->usb_no_cpr = 0;
6803                 mutex_exit(&usba_device->usb_mutex);
6804 
6805                 /*
6806                  * Since the pipe has already been opened by hub
6807                  * at DDI_RESUME time, there is no need for a
6808                  * persistent pipe open
6809                  */
6810                 hubd_do_callback(hubd, dip, cookie);
6811 
6812                 /*
6813                  * Set the flag again, so we don't miss posting a
6814                  * pre-suspend event. This enforces a tighter
6815                  * dev_state model.
6816                  */
6817                 mutex_enter(HUBD_MUTEX(hubd));
6818                 hubd->h_child_events[port] |= HUBD_CHILD_EVENT_PRESUSPEND;
6819                 mutex_exit(HUBD_MUTEX(hubd));
6820                 break;
6821         }
6822 }
6823 
6824 
6825 /*
6826  * handling of events coming from above
6827  */
6828 static int
6829 hubd_disconnect_event_cb(dev_info_t *dip)
6830 {
6831         hubd_t          *hubd = (hubd_t *)hubd_get_soft_state(dip);
6832         usb_port_t      port, nports;
6833         usba_device_t   *usba_dev;
6834         usba_event_t    tag = USBA_EVENT_TAG_HOT_REMOVAL;
6835         int             circ;
6836 
6837         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6838             "hubd_disconnect_event_cb: tag=%d", tag);
6839 
6840         ndi_devi_enter(dip, &circ);
6841 
6842         mutex_enter(HUBD_MUTEX(hubd));
6843         switch (hubd->h_dev_state) {
6844         case USB_DEV_ONLINE:
6845         case USB_DEV_PWRED_DOWN:
6846                 hubd->h_dev_state = USB_DEV_DISCONNECTED;
6847                 /* stop polling on the interrupt pipe */
6848                 hubd_stop_polling(hubd);
6849 
6850                 /* FALLTHROUGH */
6851         case USB_DEV_SUSPENDED:
6852                 /* we remain in this state */
6853                 mutex_exit(HUBD_MUTEX(hubd));
6854                 hubd_run_callbacks(hubd, tag);
6855                 mutex_enter(HUBD_MUTEX(hubd));
6856 
6857                 /* close all the open pipes of our children */
6858                 nports = hubd->h_hub_descr.bNbrPorts;
6859                 for (port = 1; port <= nports; port++) {
6860                         usba_dev = hubd->h_usba_devices[port];
6861                         if (usba_dev != NULL) {
6862                                 mutex_exit(HUBD_MUTEX(hubd));
6863                                 usba_persistent_pipe_close(usba_dev);
6864                                 mutex_enter(HUBD_MUTEX(hubd));
6865                         }
6866                 }
6867 
6868                 break;
6869         case USB_DEV_DISCONNECTED:
6870                 /* avoid passing multiple disconnects to children */
6871                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6872                     "hubd_disconnect_event_cb: Already disconnected");
6873 
6874                 break;
6875         default:
6876                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6877                     "hubd_disconnect_event_cb: Illegal devstate=%d",
6878                     hubd->h_dev_state);
6879 
6880                 break;
6881         }
6882         mutex_exit(HUBD_MUTEX(hubd));
6883 
6884         ndi_devi_exit(dip, circ);
6885 
6886         return (USB_SUCCESS);
6887 }
6888 
6889 
6890 static int
6891 hubd_reconnect_event_cb(dev_info_t *dip)
6892 {
6893         int     rval, circ;
6894 
6895         ndi_devi_enter(dip, &circ);
6896         rval = hubd_restore_state_cb(dip);
6897         ndi_devi_exit(dip, circ);
6898 
6899         return (rval);
6900 }
6901 
6902 
6903 /*
6904  * hubd_pre_suspend_event_cb
6905  *      propogate event for binary compatibility of old drivers
6906  */
6907 static int
6908 hubd_pre_suspend_event_cb(dev_info_t *dip)
6909 {
6910         int     circ;
6911         hubd_t  *hubd = (hubd_t *)hubd_get_soft_state(dip);
6912 
6913         USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle,
6914             "hubd_pre_suspend_event_cb");
6915 
6916         /* disable hotplug thread */
6917         mutex_enter(HUBD_MUTEX(hubd));
6918         hubd->h_hotplug_thread++;
6919         hubd_stop_polling(hubd);
6920 
6921         /* keep PM out till we see a cpr resume */
6922         (void) hubd_pm_busy_component(hubd, hubd->h_dip, 0);
6923         mutex_exit(HUBD_MUTEX(hubd));
6924 
6925         ndi_devi_enter(dip, &circ);
6926         hubd_run_callbacks(hubd, USBA_EVENT_TAG_PRE_SUSPEND);
6927         ndi_devi_exit(dip, circ);
6928 
6929         return (USB_SUCCESS);
6930 }
6931 
6932 
6933 /*
6934  * hubd_post_resume_event_cb
6935  *      propogate event for binary compatibility of old drivers
6936  */
6937 static int
6938 hubd_post_resume_event_cb(dev_info_t *dip)
6939 {
6940         int     circ;
6941         hubd_t  *hubd = (hubd_t *)hubd_get_soft_state(dip);
6942 
6943         USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle,
6944             "hubd_post_resume_event_cb");
6945 
6946         ndi_devi_enter(dip, &circ);
6947         hubd_run_callbacks(hubd, USBA_EVENT_TAG_POST_RESUME);
6948         ndi_devi_exit(dip, circ);
6949 
6950         mutex_enter(HUBD_MUTEX(hubd));
6951 
6952         /* enable PM */
6953         (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0);
6954 
6955         /* allow hotplug thread */
6956         hubd->h_hotplug_thread--;
6957 
6958         /* start polling */
6959         hubd_start_polling(hubd, 0);
6960         mutex_exit(HUBD_MUTEX(hubd));
6961 
6962         return (USB_SUCCESS);
6963 }
6964 
6965 
6966 /*
6967  * hubd_cpr_suspend
6968  *      save the current state of the driver/device
6969  */
6970 static int
6971 hubd_cpr_suspend(hubd_t *hubd)
6972 {
6973         usb_port_t      port, nports;
6974         usba_device_t   *usba_dev;
6975         uchar_t         no_cpr = 0;
6976         int             rval = USB_FAILURE;
6977 
6978         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6979             "hubd_cpr_suspend: Begin");
6980 
6981         /* Make sure device is powered up to save state. */
6982         mutex_enter(HUBD_MUTEX(hubd));
6983         hubd_pm_busy_component(hubd, hubd->h_dip, 0);
6984         mutex_exit(HUBD_MUTEX(hubd));
6985 
6986         /* bring the device to full power */
6987         (void) pm_raise_power(hubd->h_dip, 0, USB_DEV_OS_FULL_PWR);
6988         mutex_enter(HUBD_MUTEX(hubd));
6989 
6990         switch (hubd->h_dev_state) {
6991         case USB_DEV_ONLINE:
6992         case USB_DEV_PWRED_DOWN:
6993         case USB_DEV_DISCONNECTED:
6994                 /* find out if all our children have been quiesced */
6995                 nports = hubd->h_hub_descr.bNbrPorts;
6996                 for (port = 1; (no_cpr == 0) && (port <= nports); port++) {
6997                         usba_dev = hubd->h_usba_devices[port];
6998                         if (usba_dev != NULL) {
6999                                 mutex_enter(&usba_dev->usb_mutex);
7000                                 no_cpr += usba_dev->usb_no_cpr;
7001                                 mutex_exit(&usba_dev->usb_mutex);
7002                         }
7003                 }
7004                 if (no_cpr > 0) {
7005                         USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
7006                             "Children busy - can't checkpoint");
7007                         /* remain in same state to fail checkpoint */
7008 
7009                         break;
7010                 } else {
7011                         /*
7012                          * do not suspend if our hotplug thread
7013                          * or the deathrow thread is active
7014                          */
7015                         if ((hubd->h_hotplug_thread > 1) ||
7016                             (hubd->h_cleanup_active == B_TRUE)) {
7017                                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
7018                                     hubd->h_log_handle,
7019                                     "hotplug thread active  - can't cpr");
7020                                 /* remain in same state to fail checkpoint */
7021 
7022                                 break;
7023                         }
7024 
7025                         /* quiesce ourselves now */
7026                         hubd_stop_polling(hubd);
7027 
7028                         /* close all the open pipes of our children */
7029                         for (port = 1; port <= nports; port++) {
7030                                 usba_dev = hubd->h_usba_devices[port];
7031                                 if (usba_dev != NULL) {
7032                                         mutex_exit(HUBD_MUTEX(hubd));
7033                                         usba_persistent_pipe_close(usba_dev);
7034                                         if (hubd_suspend_port(hubd, port)) {
7035                                                 USB_DPRINTF_L0(
7036                                                     DPRINT_MASK_HOTPLUG,
7037                                                     hubd->h_log_handle,
7038                                                     "suspending port %d failed",
7039                                                     port);
7040                                         }
7041                                         mutex_enter(HUBD_MUTEX(hubd));
7042                                 }
7043 
7044                         }
7045                         hubd->h_dev_state = USB_DEV_SUSPENDED;
7046 
7047                         /*
7048                          * if we are the root hub, we close our pipes
7049                          * ourselves.
7050                          */
7051                         if (usba_is_root_hub(hubd->h_dip)) {
7052                                 mutex_exit(HUBD_MUTEX(hubd));
7053                                 usba_persistent_pipe_close(
7054                                     usba_get_usba_device(hubd->h_dip));
7055                                 mutex_enter(HUBD_MUTEX(hubd));
7056                         }
7057                         rval = USB_SUCCESS;
7058 
7059                         break;
7060                 }
7061         case USB_DEV_SUSPENDED:
7062         default:
7063                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
7064                     "hubd_cpr_suspend: Illegal dev state=%d",
7065                     hubd->h_dev_state);
7066 
7067                 break;
7068         }
7069 
7070         hubd_pm_idle_component(hubd, hubd->h_dip, 0);
7071         mutex_exit(HUBD_MUTEX(hubd));
7072 
7073         return (rval);
7074 }
7075 
7076 static void
7077 hubd_cpr_resume(dev_info_t *dip)
7078 {
7079         int     rval, circ;
7080 
7081         ndi_devi_enter(dip, &circ);
7082         /*
7083          * if we are the root hub, we open our pipes
7084          * ourselves.
7085          */
7086         if (usba_is_root_hub(dip)) {
7087                 rval = usba_persistent_pipe_open(
7088                     usba_get_usba_device(dip));
7089                 ASSERT(rval == USB_SUCCESS);
7090         }
7091         (void) hubd_restore_state_cb(dip);
7092         ndi_devi_exit(dip, circ);
7093 }
7094 
7095 
7096 /*
7097  * hubd_restore_state_cb
7098  *      Event callback to restore device state
7099  */
7100 static int
7101 hubd_restore_state_cb(dev_info_t *dip)
7102 {
7103         hubd_t  *hubd = (hubd_t *)hubd_get_soft_state(dip);
7104 
7105         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
7106             "hubd_restore_state_cb: Begin");
7107 
7108         /* restore the state of this device */
7109         hubd_restore_device_state(dip, hubd);
7110 
7111         return (USB_SUCCESS);
7112 }
7113 
7114 
7115 /*
7116  * registering for events
7117  */
7118 static int
7119 hubd_register_events(hubd_t *hubd)
7120 {
7121         int             rval = USB_SUCCESS;
7122 
7123         if (usba_is_root_hub(hubd->h_dip)) {
7124                 hubd_register_cpr_callback(hubd);
7125         } else {
7126                 rval = usb_register_event_cbs(hubd->h_dip, &hubd_events, 0);
7127         }
7128 
7129         return (rval);
7130 }
7131 
7132 
7133 /*
7134  * hubd cpr callback related functions
7135  *
7136  * hubd_cpr_post_user_callb:
7137  *      This function is called during checkpoint & resume -
7138  *              1. after user threads are stopped during checkpoint
7139  *              2. after kernel threads are resumed during resume
7140  */
7141 /* ARGSUSED */
7142 static boolean_t
7143 hubd_cpr_post_user_callb(void *arg, int code)
7144 {
7145         hubd_cpr_t      *cpr_cb = (hubd_cpr_t *)arg;
7146         hubd_t          *hubd = cpr_cb->statep;
7147         int             retry = 0;
7148 
7149         USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle,
7150             "hubd_cpr_post_user_callb");
7151 
7152         switch (code) {
7153         case CB_CODE_CPR_CHKPT:
7154                 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, hubd->h_log_handle,
7155                     "hubd_cpr_post_user_callb: CB_CODE_CPR_CHKPT");
7156 
7157                 mutex_enter(HUBD_MUTEX(hubd));
7158 
7159                 /* turn off deathrow thread */
7160                 hubd->h_cleanup_enabled = B_FALSE;
7161 
7162                 /* give up if deathrow thread doesn't exit */
7163                 while ((hubd->h_cleanup_active == B_TRUE) && (retry++ < 3)) {
7164                         mutex_exit(HUBD_MUTEX(hubd));
7165                         delay(drv_usectohz(hubd_dip_cleanup_delay));
7166 
7167                         USB_DPRINTF_L2(DPRINT_MASK_EVENTS, hubd->h_log_handle,
7168                             "hubd_cpr_post_user_callb, waiting for "
7169                             "deathrow thread to exit");
7170                         mutex_enter(HUBD_MUTEX(hubd));
7171                 }
7172 
7173                 mutex_exit(HUBD_MUTEX(hubd));
7174 
7175                 /* save the state of the device */
7176                 (void) hubd_pre_suspend_event_cb(hubd->h_dip);
7177 
7178                 return (B_TRUE);
7179         case CB_CODE_CPR_RESUME:
7180                 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, hubd->h_log_handle,
7181                     "hubd_cpr_post_user_callb: CB_CODE_CPR_RESUME");
7182 
7183                 /* restore the state of the device */
7184                 (void) hubd_post_resume_event_cb(hubd->h_dip);
7185 
7186                 /* turn on deathrow thread */
7187                 mutex_enter(HUBD_MUTEX(hubd));
7188                 hubd->h_cleanup_enabled = B_TRUE;
7189                 mutex_exit(HUBD_MUTEX(hubd));
7190 
7191                 hubd_schedule_cleanup(hubd->h_usba_device->usb_root_hub_dip);
7192 
7193                 return (B_TRUE);
7194         default:
7195 
7196                 return (B_FALSE);
7197         }
7198 
7199 }
7200 
7201 
7202 /* register callback with cpr framework */
7203 void
7204 hubd_register_cpr_callback(hubd_t *hubd)
7205 {
7206         USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle,
7207             "hubd_register_cpr_callback");
7208 
7209         mutex_enter(HUBD_MUTEX(hubd));
7210         hubd->h_cpr_cb =
7211             (hubd_cpr_t *)kmem_zalloc(sizeof (hubd_cpr_t), KM_SLEEP);
7212         mutex_exit(HUBD_MUTEX(hubd));
7213         mutex_init(&hubd->h_cpr_cb->lockp, NULL, MUTEX_DRIVER,
7214             hubd->h_dev_data->dev_iblock_cookie);
7215         hubd->h_cpr_cb->statep = hubd;
7216         hubd->h_cpr_cb->cpr.cc_lockp = &hubd->h_cpr_cb->lockp;
7217         hubd->h_cpr_cb->cpr.cc_id = callb_add(hubd_cpr_post_user_callb,
7218             (void *)hubd->h_cpr_cb, CB_CL_CPR_POST_USER, "hubd");
7219 }
7220 
7221 
7222 /* unregister callback with cpr framework */
7223 void
7224 hubd_unregister_cpr_callback(hubd_t *hubd)
7225 {
7226         USB_DPRINTF_L4(DPRINT_MASK_EVENTS, hubd->h_log_handle,
7227             "hubd_unregister_cpr_callback");
7228 
7229         if (hubd->h_cpr_cb) {
7230                 (void) callb_delete(hubd->h_cpr_cb->cpr.cc_id);
7231                 mutex_destroy(&hubd->h_cpr_cb->lockp);
7232                 mutex_enter(HUBD_MUTEX(hubd));
7233                 kmem_free(hubd->h_cpr_cb, sizeof (hubd_cpr_t));
7234                 mutex_exit(HUBD_MUTEX(hubd));
7235         }
7236 }
7237 
7238 
7239 /*
7240  * Power management
7241  *
7242  * create the pm components required for power management
7243  */
7244 static void
7245 hubd_create_pm_components(dev_info_t *dip, hubd_t *hubd)
7246 {
7247         hub_power_t     *hubpm;
7248 
7249         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
7250             "hubd_create_pm_components: Begin");
7251 
7252         /* Allocate the state structure */
7253         hubpm = kmem_zalloc(sizeof (hub_power_t), KM_SLEEP);
7254 
7255         hubd->h_hubpm = hubpm;
7256         hubpm->hubp_hubd = hubd;
7257         hubpm->hubp_pm_capabilities = 0;
7258         hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR;
7259         hubpm->hubp_time_at_full_power = gethrtime();
7260         hubpm->hubp_min_pm_threshold = hubdi_min_pm_threshold * NANOSEC;
7261 
7262         /* alloc memory to save power states of children */
7263         hubpm->hubp_child_pwrstate = (uint8_t *)
7264             kmem_zalloc(MAX_PORTS + 1, KM_SLEEP);
7265 
7266         /*
7267          * if the enable remote wakeup fails
7268          * we still want to enable
7269          * parent notification so we can PM the children
7270          */
7271         usb_enable_parent_notification(dip);
7272 
7273         if (usb_handle_remote_wakeup(dip,
7274             USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS) {
7275                 uint_t          pwr_states;
7276 
7277                 USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
7278                     "hubd_create_pm_components: "
7279                     "Remote Wakeup Enabled");
7280 
7281                 if (usb_create_pm_components(dip, &pwr_states) ==
7282                     USB_SUCCESS) {
7283                         mutex_enter(HUBD_MUTEX(hubd));
7284                         hubpm->hubp_wakeup_enabled = 1;
7285                         hubpm->hubp_pwr_states = (uint8_t)pwr_states;
7286 
7287                         /* we are busy now till end of the attach */
7288                         hubd_pm_busy_component(hubd, dip, 0);
7289                         mutex_exit(HUBD_MUTEX(hubd));
7290 
7291                         /* bring the device to full power */
7292                         (void) pm_raise_power(dip, 0,
7293                             USB_DEV_OS_FULL_PWR);
7294                 }
7295         }
7296 
7297         USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
7298             "hubd_create_pm_components: END");
7299 }
7300 
7301 
7302 /*
7303  * Attachment point management
7304  */
7305 /* ARGSUSED */
7306 int
7307 usba_hubdi_open(dev_info_t *dip, dev_t *devp, int flags, int otyp,
7308         cred_t *credp)
7309 {
7310         hubd_t *hubd;
7311 
7312         if (otyp != OTYP_CHR)
7313                 return (EINVAL);
7314 
7315         hubd = hubd_get_soft_state(dip);
7316         if (hubd == NULL) {
7317                 return (ENXIO);
7318         }
7319 
7320         USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle,
7321             "hubd_open:");
7322 
7323         mutex_enter(HUBD_MUTEX(hubd));
7324         if ((flags & FEXCL) && (hubd->h_softstate & HUBD_SS_ISOPEN)) {
7325                 mutex_exit(HUBD_MUTEX(hubd));
7326 
7327                 return (EBUSY);
7328         }
7329 
7330         hubd->h_softstate |= HUBD_SS_ISOPEN;
7331         mutex_exit(HUBD_MUTEX(hubd));
7332 
7333         USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "opened");
7334 
7335         return (0);
7336 }
7337 
7338 
7339 /* ARGSUSED */
7340 int
7341 usba_hubdi_close(dev_info_t *dip, dev_t dev, int flag, int otyp,
7342         cred_t *credp)
7343 {
7344         hubd_t *hubd;
7345 
7346         if (otyp != OTYP_CHR) {
7347                 return (EINVAL);
7348         }
7349 
7350         hubd = hubd_get_soft_state(dip);
7351 
7352         if (hubd == NULL) {
7353                 return (ENXIO);
7354         }
7355 
7356         USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "hubd_close:");
7357 
7358         mutex_enter(HUBD_MUTEX(hubd));
7359         hubd->h_softstate &= ~HUBD_SS_ISOPEN;
7360         mutex_exit(HUBD_MUTEX(hubd));
7361 
7362         USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle, "closed");
7363 
7364         return (0);
7365 }
7366 
7367 
7368 /*
7369  * hubd_ioctl: cfgadm controls
7370  */
7371 /* ARGSUSED */
7372 int
7373 usba_hubdi_ioctl(dev_info_t *self, dev_t dev, int cmd, intptr_t arg,
7374         int mode, cred_t *credp, int *rvalp)
7375 {
7376         int                     rv = 0;
7377         char                    *msg;   /* for messages */
7378         hubd_t                  *hubd;
7379         usb_port_t              port = 0;
7380         dev_info_t              *child_dip = NULL;
7381         dev_info_t              *rh_dip;
7382         devctl_ap_state_t       ap_state;
7383         struct devctl_iocdata   *dcp = NULL;
7384         usb_pipe_state_t        prev_pipe_state = 0;
7385         int                     circ, rh_circ, prh_circ;
7386 
7387         if ((hubd = hubd_get_soft_state(self)) == NULL) {
7388 
7389                 return (ENXIO);
7390         }
7391 
7392         rh_dip = hubd->h_usba_device->usb_root_hub_dip;
7393 
7394         USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle,
7395             "usba_hubdi_ioctl: "
7396             "cmd=%x, arg=%lx, mode=%x, cred=%p, rval=%p dev=0x%lx",
7397             cmd, arg, mode, (void *)credp, (void *)rvalp, dev);
7398 
7399         /* read devctl ioctl data */
7400         if ((cmd != DEVCTL_AP_CONTROL) &&
7401             (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)) {
7402 
7403                 return (EFAULT);
7404         }
7405 
7406         /*
7407          * make sure the hub is connected before trying any
7408          * of the following operations:
7409          * configure, connect, disconnect
7410          */
7411         mutex_enter(HUBD_MUTEX(hubd));
7412 
7413         switch (cmd) {
7414         case DEVCTL_AP_DISCONNECT:
7415         case DEVCTL_AP_UNCONFIGURE:
7416         case DEVCTL_AP_CONFIGURE:
7417                 if (hubd->h_dev_state == USB_DEV_DISCONNECTED) {
7418                         USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
7419                             "hubd: already gone");
7420                         mutex_exit(HUBD_MUTEX(hubd));
7421                         if (dcp) {
7422                                 ndi_dc_freehdl(dcp);
7423                         }
7424 
7425                         return (EIO);
7426                 }
7427 
7428                 /* FALLTHROUGH */
7429         case DEVCTL_AP_GETSTATE:
7430                 if ((port = hubd_get_port_num(hubd, dcp)) == 0) {
7431                         USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
7432                             "hubd: bad port");
7433                         mutex_exit(HUBD_MUTEX(hubd));
7434                         if (dcp) {
7435                                 ndi_dc_freehdl(dcp);
7436                         }
7437 
7438                         return (EINVAL);
7439                 }
7440                 break;
7441 
7442         case DEVCTL_AP_CONTROL:
7443 
7444                 break;
7445         default:
7446                 mutex_exit(HUBD_MUTEX(hubd));
7447                 if (dcp) {
7448                         ndi_dc_freehdl(dcp);
7449                 }
7450 
7451                 return (ENOTTY);
7452         }
7453 
7454         /* should not happen, just in case */
7455         if (hubd->h_dev_state == USB_DEV_SUSPENDED) {
7456                 mutex_exit(HUBD_MUTEX(hubd));
7457                 if (dcp) {
7458                         ndi_dc_freehdl(dcp);
7459                 }
7460 
7461                 return (EIO);
7462         }
7463 
7464         if (hubd->h_reset_port[port]) {
7465                 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, hubd->h_log_handle,
7466                     "This port is resetting, just return");
7467                 mutex_exit(HUBD_MUTEX(hubd));
7468                 if (dcp) {
7469                         ndi_dc_freehdl(dcp);
7470                 }
7471 
7472                 return (EIO);
7473         }
7474 
7475         hubd_pm_busy_component(hubd, hubd->h_dip, 0);
7476         mutex_exit(HUBD_MUTEX(hubd));
7477 
7478         /* go full power */
7479         (void) pm_raise_power(hubd->h_dip, 0, USB_DEV_OS_FULL_PWR);
7480 
7481         ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ);
7482         ndi_devi_enter(rh_dip, &rh_circ);
7483         ndi_devi_enter(hubd->h_dip, &circ);
7484 
7485         mutex_enter(HUBD_MUTEX(hubd));
7486 
7487         hubd->h_hotplug_thread++;
7488 
7489         /* stop polling if it was active */
7490         if (hubd->h_ep1_ph) {
7491                 mutex_exit(HUBD_MUTEX(hubd));
7492                 (void) usb_pipe_get_state(hubd->h_ep1_ph, &prev_pipe_state,
7493                     USB_FLAGS_SLEEP);
7494                 mutex_enter(HUBD_MUTEX(hubd));
7495 
7496                 if (prev_pipe_state == USB_PIPE_STATE_ACTIVE) {
7497                         hubd_stop_polling(hubd);
7498                 }
7499         }
7500 
7501         switch (cmd) {
7502         case DEVCTL_AP_DISCONNECT:
7503                 if (hubd_delete_child(hubd, port,
7504                     NDI_DEVI_REMOVE, B_FALSE) != USB_SUCCESS) {
7505                         rv = EIO;
7506                 }
7507 
7508                 break;
7509         case DEVCTL_AP_UNCONFIGURE:
7510                 if (hubd_delete_child(hubd, port,
7511                     NDI_UNCONFIG, B_FALSE) != USB_SUCCESS) {
7512                         rv = EIO;
7513                 }
7514 
7515                 break;
7516         case DEVCTL_AP_CONFIGURE:
7517                 /* toggle port */
7518                 if (hubd_toggle_port(hubd, port) != USB_SUCCESS) {
7519                         rv = EIO;
7520 
7521                         break;
7522                 }
7523 
7524                 (void) hubd_handle_port_connect(hubd, port);
7525                 child_dip = hubd_get_child_dip(hubd, port);
7526                 mutex_exit(HUBD_MUTEX(hubd));
7527 
7528                 ndi_devi_exit(hubd->h_dip, circ);
7529                 ndi_devi_exit(rh_dip, rh_circ);
7530                 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ);
7531                 if (child_dip == NULL) {
7532                         rv = EIO;
7533                 } else {
7534                         ndi_hold_devi(child_dip);
7535                         if (ndi_devi_online(child_dip, 0) != NDI_SUCCESS)
7536                                 rv = EIO;
7537                         ndi_rele_devi(child_dip);
7538                 }
7539                 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ);
7540                 ndi_devi_enter(rh_dip, &rh_circ);
7541                 ndi_devi_enter(hubd->h_dip, &circ);
7542 
7543                 mutex_enter(HUBD_MUTEX(hubd));
7544 
7545                 break;
7546         case DEVCTL_AP_GETSTATE:
7547                 switch (hubd_cfgadm_state(hubd, port)) {
7548                 case HUBD_CFGADM_DISCONNECTED:
7549                         /* port previously 'disconnected' by cfgadm */
7550                         ap_state.ap_rstate = AP_RSTATE_DISCONNECTED;
7551                         ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED;
7552                         ap_state.ap_condition = AP_COND_OK;
7553 
7554                         break;
7555                 case HUBD_CFGADM_UNCONFIGURED:
7556                         ap_state.ap_rstate = AP_RSTATE_CONNECTED;
7557                         ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED;
7558                         ap_state.ap_condition = AP_COND_OK;
7559 
7560                         break;
7561                 case HUBD_CFGADM_CONFIGURED:
7562                         ap_state.ap_rstate = AP_RSTATE_CONNECTED;
7563                         ap_state.ap_ostate = AP_OSTATE_CONFIGURED;
7564                         ap_state.ap_condition = AP_COND_OK;
7565 
7566                         break;
7567                 case HUBD_CFGADM_STILL_REFERENCED:
7568                         ap_state.ap_rstate = AP_RSTATE_EMPTY;
7569                         ap_state.ap_ostate = AP_OSTATE_CONFIGURED;
7570                         ap_state.ap_condition = AP_COND_UNUSABLE;
7571 
7572                         break;
7573                 case HUBD_CFGADM_EMPTY:
7574                 default:
7575                         ap_state.ap_rstate = AP_RSTATE_EMPTY;
7576                         ap_state.ap_ostate = AP_OSTATE_UNCONFIGURED;
7577                         ap_state.ap_condition = AP_COND_OK;
7578 
7579                         break;
7580                 }
7581 
7582                 ap_state.ap_last_change = (time_t)-1;
7583                 ap_state.ap_error_code = 0;
7584                 ap_state.ap_in_transition = 0;
7585 
7586                 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle,
7587                     "DEVCTL_AP_GETSTATE: "
7588                     "ostate=0x%x, rstate=0x%x, condition=0x%x",
7589                     ap_state.ap_ostate,
7590                     ap_state.ap_rstate, ap_state.ap_condition);
7591 
7592                 /* copy the return-AP-state information to the user space */
7593                 if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS) {
7594                         rv = EFAULT;
7595                 }
7596 
7597                 break;
7598         case DEVCTL_AP_CONTROL:
7599         {
7600                 /*
7601                  * Generic devctl for hardware-specific functionality.
7602                  * For list of sub-commands see hubd_impl.h
7603                  */
7604                 hubd_ioctl_data_t       ioc;    /* for 64 byte copies */
7605 
7606                 /* copy user ioctl data in first */
7607 #ifdef _MULTI_DATAMODEL
7608                 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
7609                         hubd_ioctl_data_32_t ioc32;
7610 
7611                         if (ddi_copyin((void *)arg, (void *)&ioc32,
7612                             sizeof (ioc32), mode) != 0) {
7613                                 rv = EFAULT;
7614 
7615                                 break;
7616                         }
7617                         ioc.cmd         = (uint_t)ioc32.cmd;
7618                         ioc.port        = (uint_t)ioc32.port;
7619                         ioc.get_size    = (uint_t)ioc32.get_size;
7620                         ioc.buf         = (caddr_t)(uintptr_t)ioc32.buf;
7621                         ioc.bufsiz      = (uint_t)ioc32.bufsiz;
7622                         ioc.misc_arg    = (uint_t)ioc32.misc_arg;
7623                 } else
7624 #endif /* _MULTI_DATAMODEL */
7625                 if (ddi_copyin((void *)arg, (void *)&ioc, sizeof (ioc),
7626                     mode) != 0) {
7627                         rv = EFAULT;
7628 
7629                         break;
7630                 }
7631 
7632                 USB_DPRINTF_L3(DPRINT_MASK_CBOPS, hubd->h_log_handle,
7633                     "DEVCTL_AP_CONTROL: ioc: cmd=0x%x port=%d get_size=%d"
7634                     "\n\tbuf=0x%p, bufsiz=%d,  misc_arg=%d", ioc.cmd,
7635                     ioc.port, ioc.get_size, (void *)ioc.buf, ioc.bufsiz,
7636                     ioc.misc_arg);
7637 
7638                 /*
7639                  * To avoid BE/LE and 32/64 issues, a get_size always
7640                  * returns a 32-bit number.
7641                  */
7642                 if (ioc.get_size != 0 && ioc.bufsiz != (sizeof (uint32_t))) {
7643                         rv = EINVAL;
7644 
7645                         break;
7646                 }
7647 
7648                 switch (ioc.cmd) {
7649                 case USB_DESCR_TYPE_DEV:
7650                         msg = "DEVCTL_AP_CONTROL: GET_DEVICE_DESC";
7651                         if (ioc.get_size) {
7652                                 /* uint32 so this works 32/64 */
7653                                 uint32_t size = sizeof (usb_dev_descr_t);
7654 
7655                                 if (ddi_copyout((void *)&size, ioc.buf,
7656                                     ioc.bufsiz, mode) != 0) {
7657                                         USB_DPRINTF_L2(DPRINT_MASK_CBOPS,
7658                                             hubd->h_log_handle,
7659                                             "%s: get_size copyout failed", msg);
7660                                         rv = EIO;
7661 
7662                                         break;
7663                                 }
7664                         } else {        /* send out the actual descr */
7665                                 usb_dev_descr_t *dev_descrp;
7666 
7667                                 /* check child_dip */
7668                                 if ((child_dip = hubd_get_child_dip(hubd,
7669                                     ioc.port)) == NULL) {
7670                                         rv = EINVAL;
7671 
7672                                         break;
7673                                 }
7674 
7675                                 dev_descrp = usb_get_dev_descr(child_dip);
7676                                 if (ioc.bufsiz != sizeof (*dev_descrp)) {
7677                                         USB_DPRINTF_L2(DPRINT_MASK_CBOPS,
7678                                             hubd->h_log_handle,
7679                                             "%s: bufsize passed (%d) != sizeof "
7680                                             "usba_device_descr_t (%d)", msg,
7681                                             ioc.bufsiz, dev_descrp->bLength);
7682                                         rv = EINVAL;
7683 
7684                                         break;
7685                                 }
7686 
7687                                 if (ddi_copyout((void *)dev_descrp,
7688                                     ioc.buf, ioc.bufsiz, mode) != 0) {
7689                                         USB_DPRINTF_L2(DPRINT_MASK_CBOPS,
7690                                             hubd->h_log_handle,
7691                                             "%s: copyout failed.", msg);
7692                                         rv = EIO;
7693 
7694                                         break;
7695                                 }
7696                         }
7697                         break;
7698                 case USB_DESCR_TYPE_STRING:
7699                 {
7700                         char            *str;
7701                         uint32_t        size;
7702                         usba_device_t   *usba_device;
7703 
7704                         msg = "DEVCTL_AP_CONTROL: GET_STRING_DESCR";
7705                         USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle,
7706                             "%s: string request: %d", msg, ioc.misc_arg);
7707 
7708                         /* recheck */
7709                         if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) ==
7710                             NULL) {
7711                                 rv = EINVAL;
7712 
7713                                 break;
7714                         }
7715                         usba_device = usba_get_usba_device(child_dip);
7716 
7717                         switch (ioc.misc_arg) {
7718                         case HUBD_MFG_STR:
7719                                 str = usba_device->usb_mfg_str;
7720 
7721                                 break;
7722                         case HUBD_PRODUCT_STR:
7723                                 str = usba_device->usb_product_str;
7724 
7725                                 break;
7726                         case HUBD_SERIALNO_STR:
7727                                 str = usba_device->usb_serialno_str;
7728 
7729                                 break;
7730                         case HUBD_CFG_DESCR_STR:
7731                                 mutex_enter(&usba_device->usb_mutex);
7732                                 str = usba_device->usb_cfg_str_descr[
7733                                     usba_device->usb_active_cfg_ndx];
7734                                 mutex_exit(&usba_device->usb_mutex);
7735 
7736                                 break;
7737                         default:
7738                                 USB_DPRINTF_L2(DPRINT_MASK_CBOPS,
7739                                     hubd->h_log_handle,
7740                                     "%s: Invalid string request", msg);
7741                                 rv = EINVAL;
7742 
7743                                 break;
7744                         } /* end of switch */
7745 
7746                         if (rv != 0) {
7747 
7748                                 break;
7749                         }
7750 
7751                         size = (str != NULL) ? strlen(str) + 1 : 0;
7752                         if (ioc.get_size) {
7753                                 if (ddi_copyout((void *)&size, ioc.buf,
7754                                     ioc.bufsiz, mode) != 0) {
7755                                         USB_DPRINTF_L2(DPRINT_MASK_CBOPS,
7756                                             hubd->h_log_handle,
7757                                             "%s: copyout of size failed.", msg);
7758                                         rv = EIO;
7759 
7760                                         break;
7761                                 }
7762                         } else {
7763                                 if (size == 0) {
7764                                         USB_DPRINTF_L3(DPRINT_MASK_CBOPS,
7765                                             hubd->h_log_handle,
7766                                             "%s: String is NULL", msg);
7767                                         rv = EINVAL;
7768 
7769                                         break;
7770                                 }
7771 
7772                                 if (ioc.bufsiz != size) {
7773                                         USB_DPRINTF_L2(DPRINT_MASK_CBOPS,
7774                                             hubd->h_log_handle,
7775                                             "%s: string buf size wrong", msg);
7776                                         rv = EINVAL;
7777 
7778                                         break;
7779                                 }
7780 
7781                                 if (ddi_copyout((void *)str, ioc.buf,
7782                                     ioc.bufsiz, mode) != 0) {
7783                                         USB_DPRINTF_L2(DPRINT_MASK_CBOPS,
7784                                             hubd->h_log_handle,
7785                                             "%s: copyout failed.", msg);
7786                                         rv = EIO;
7787 
7788                                         break;
7789                                 }
7790                         }
7791                         break;
7792                 }
7793                 case HUBD_GET_CFGADM_NAME:
7794                 {
7795                         uint32_t   name_len;
7796                         const char *name;
7797 
7798                         /* recheck */
7799                         if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) ==
7800                             NULL) {
7801                                 rv = EINVAL;
7802 
7803                                 break;
7804                         }
7805                         name = ddi_node_name(child_dip);
7806                         if (name == NULL) {
7807                                 name = "unsupported";
7808                         }
7809                         name_len = strlen(name) + 1;
7810 
7811                         msg = "DEVCTL_AP_CONTROL: HUBD_GET_CFGADM_NAME";
7812                         USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle,
7813                             "%s: name=%s name_len=%d", msg, name, name_len);
7814 
7815                         if (ioc.get_size) {
7816                                 if (ddi_copyout((void *)&name_len,
7817                                     ioc.buf, ioc.bufsiz, mode) != 0) {
7818                                         USB_DPRINTF_L2(DPRINT_MASK_CBOPS,
7819                                             hubd->h_log_handle,
7820                                             "%s: copyout of size failed", msg);
7821                                         rv = EIO;
7822 
7823                                         break;
7824                                 }
7825                         } else {
7826                                 if (ioc.bufsiz != name_len) {
7827                                         USB_DPRINTF_L2(DPRINT_MASK_CBOPS,
7828                                             hubd->h_log_handle,
7829                                             "%s: string buf length wrong", msg);
7830                                         rv = EINVAL;
7831 
7832                                         break;
7833                                 }
7834 
7835                                 if (ddi_copyout((void *)name, ioc.buf,
7836                                     ioc.bufsiz, mode) != 0) {
7837                                         USB_DPRINTF_L2(DPRINT_MASK_CBOPS,
7838                                             hubd->h_log_handle,
7839                                             "%s: copyout failed.", msg);
7840                                         rv = EIO;
7841 
7842                                         break;
7843                                 }
7844                         }
7845 
7846                         break;
7847                 }
7848 
7849                 /*
7850                  * Return the config index for the currently-configured
7851                  * configuration.
7852                  */
7853                 case HUBD_GET_CURRENT_CONFIG:
7854                 {
7855                         uint_t          config_index;
7856                         uint32_t        size = sizeof (config_index);
7857                         usba_device_t   *usba_device;
7858 
7859                         msg = "DEVCTL_AP_CONTROL: GET_CURRENT_CONFIG";
7860                         USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle,
7861                             "%s", msg);
7862 
7863                         /*
7864                          * Return the config index for the configuration
7865                          * currently in use.
7866                          * Recheck if child_dip exists
7867                          */
7868                         if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) ==
7869                             NULL) {
7870                                 rv = EINVAL;
7871 
7872                                 break;
7873                         }
7874 
7875                         usba_device = usba_get_usba_device(child_dip);
7876                         mutex_enter(&usba_device->usb_mutex);
7877                         config_index = usba_device->usb_active_cfg_ndx;
7878                         mutex_exit(&usba_device->usb_mutex);
7879 
7880                         if (ioc.get_size) {
7881                                 if (ddi_copyout((void *)&size,
7882                                     ioc.buf, ioc.bufsiz, mode) != 0) {
7883                                         USB_DPRINTF_L2(DPRINT_MASK_CBOPS,
7884                                             hubd->h_log_handle,
7885                                             "%s: copyout of size failed.", msg);
7886                                         rv = EIO;
7887 
7888                                         break;
7889                                 }
7890                         } else {
7891                                 if (ioc.bufsiz != size) {
7892                                         USB_DPRINTF_L2(DPRINT_MASK_CBOPS,
7893                                             hubd->h_log_handle,
7894                                             "%s: buffer size wrong", msg);
7895                                         rv = EINVAL;
7896 
7897                                         break;
7898                                 }
7899                                 if (ddi_copyout((void *)&config_index,
7900                                     ioc.buf, ioc.bufsiz, mode) != 0) {
7901                                         USB_DPRINTF_L2(DPRINT_MASK_CBOPS,
7902                                             hubd->h_log_handle,
7903                                             "%s: copyout failed", msg);
7904                                         rv = EIO;
7905                                 }
7906                         }
7907 
7908                         break;
7909                 }
7910                 case HUBD_GET_DEVICE_PATH:
7911                 {
7912                         char            *path;
7913                         uint32_t        size;
7914 
7915                         msg = "DEVCTL_AP_CONTROL: GET_DEVICE_PATH";
7916                         USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle,
7917                             "%s", msg);
7918 
7919                         /* Recheck if child_dip exists */
7920                         if ((child_dip = hubd_get_child_dip(hubd, ioc.port)) ==
7921                             NULL) {
7922                                 rv = EINVAL;
7923 
7924                                 break;
7925                         }
7926 
7927                         /* ddi_pathname doesn't supply /devices, so we do. */
7928                         path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
7929                         (void) strcpy(path, "/devices");
7930                         (void) ddi_pathname(child_dip, path + strlen(path));
7931                         size = strlen(path) + 1;
7932 
7933                         USB_DPRINTF_L4(DPRINT_MASK_CBOPS, hubd->h_log_handle,
7934                             "%s: device path=%s  size=%d", msg, path, size);
7935 
7936                         if (ioc.get_size) {
7937                                 if (ddi_copyout((void *)&size,
7938                                     ioc.buf, ioc.bufsiz, mode) != 0) {
7939 
7940                                         USB_DPRINTF_L2(DPRINT_MASK_CBOPS,
7941                                             hubd->h_log_handle,
7942                                             "%s: copyout of size failed.", msg);
7943                                         rv = EIO;
7944                                 }
7945                         } else {
7946                                 if (ioc.bufsiz != size) {
7947                                         USB_DPRINTF_L2(DPRINT_MASK_CBOPS,
7948                                             hubd->h_log_handle,
7949                                             "%s: buffer wrong size.", msg);
7950                                         rv = EINVAL;
7951                                 } else if (ddi_copyout((void *)path,
7952                                     ioc.buf, ioc.bufsiz, mode) != 0) {
7953                                         USB_DPRINTF_L2(DPRINT_MASK_CBOPS,
7954                                             hubd->h_log_handle,
7955                                             "%s: copyout failed.", msg);
7956                                         rv = EIO;
7957                                 }
7958                         }
7959                         kmem_free(path, MAXPATHLEN);
7960 
7961                         break;
7962                 }
7963                 case HUBD_REFRESH_DEVDB:
7964                         msg = "DEVCTL_AP_CONTROL: HUBD_REFRESH_DEVDB";
7965                         USB_DPRINTF_L3(DPRINT_MASK_CBOPS, hubd->h_log_handle,
7966                             "%s", msg);
7967 
7968                         if ((rv = usba_devdb_refresh()) != USB_SUCCESS) {
7969                                 USB_DPRINTF_L2(DPRINT_MASK_CBOPS,
7970                                     hubd->h_log_handle,
7971                                     "%s: Failed: %d", msg, rv);
7972                                 rv = EIO;
7973                         }
7974 
7975                         break;
7976                 default:
7977                         rv = ENOTSUP;
7978                 }       /* end switch */
7979 
7980                 break;
7981         }
7982 
7983         default:
7984                 rv = ENOTTY;
7985         }
7986 
7987         if (dcp) {
7988                 ndi_dc_freehdl(dcp);
7989         }
7990 
7991         /* allow hotplug thread now */
7992         hubd->h_hotplug_thread--;
7993 
7994         if ((hubd->h_dev_state == USB_DEV_ONLINE) &&
7995             hubd->h_ep1_ph && (prev_pipe_state == USB_PIPE_STATE_ACTIVE)) {
7996                 hubd_start_polling(hubd, 0);
7997         }
7998         mutex_exit(HUBD_MUTEX(hubd));
7999 
8000         ndi_devi_exit(hubd->h_dip, circ);
8001         ndi_devi_exit(rh_dip, rh_circ);
8002         ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ);
8003 
8004         mutex_enter(HUBD_MUTEX(hubd));
8005         hubd_pm_idle_component(hubd, hubd->h_dip, 0);
8006         mutex_exit(HUBD_MUTEX(hubd));
8007 
8008         return (rv);
8009 }
8010 
8011 
8012 /*
8013  * Helper func used only to help construct the names for the attachment point
8014  * minor nodes.  Used only in usba_hubdi_attach.
8015  * Returns whether it found ancestry or not (USB_SUCCESS if yes).
8016  * ports between the root hub and the device represented by dip.
8017  * E.g.,  "2.4.3.1" means this device is
8018  *      plugged into port 1 of a hub that is
8019  *      plugged into port 3 of a hub that is
8020  *      plugged into port 4 of a hub that is
8021  *      plugged into port 2 of the root hub.
8022  * NOTE: Max ap_id path len is HUBD_APID_NAMELEN (32 chars), which is
8023  * more than sufficient (as hubs are a max 6 levels deep, port needs 3
8024  * chars plus NULL each)
8025  */
8026 void
8027 hubd_get_ancestry_str(hubd_t *hubd)
8028 {
8029         char            ap_name[HUBD_APID_NAMELEN];
8030         dev_info_t      *pdip;
8031         hubd_t          *phubd;
8032         usb_port_t      port;
8033 
8034         USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
8035             "hubd_get_ancestry_str: hubd=0x%p", (void *)hubd);
8036 
8037         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
8038 
8039         /*
8040          * The function is extended to support wire adapter class
8041          * devices introduced by WUSB spec. The node name is no
8042          * longer "hub" only.
8043          * Generate the ap_id str based on the parent and child
8044          * relationship instead of retrieving it from the hub
8045          * device path, which simplifies the algorithm.
8046          */
8047         if (usba_is_root_hub(hubd->h_dip)) {
8048                 hubd->h_ancestry_str[0] = '\0';
8049         } else {
8050                 port = hubd->h_usba_device->usb_port;
8051                 mutex_exit(HUBD_MUTEX(hubd));
8052 
8053                 pdip = ddi_get_parent(hubd->h_dip);
8054                 /*
8055                  * The parent of wire adapter device might be usb_mid.
8056                  * Need to look further up for hub device
8057                  */
8058                 if (strcmp(ddi_driver_name(pdip), "usb_mid") == 0) {
8059                         pdip = ddi_get_parent(pdip);
8060                         ASSERT(pdip != NULL);
8061                 }
8062 
8063                 phubd = hubd_get_soft_state(pdip);
8064 
8065                 mutex_enter(HUBD_MUTEX(phubd));
8066                 (void) snprintf(ap_name, HUBD_APID_NAMELEN, "%s%d",
8067                     phubd->h_ancestry_str, port);
8068                 mutex_exit(HUBD_MUTEX(phubd));
8069 
8070                 mutex_enter(HUBD_MUTEX(hubd));
8071                 (void) strcpy(hubd->h_ancestry_str, ap_name);
8072                 (void) strcat(hubd->h_ancestry_str, ".");
8073         }
8074 }
8075 
8076 
8077 /* Get which port to operate on.  */
8078 static usb_port_t
8079 hubd_get_port_num(hubd_t *hubd, struct devctl_iocdata *dcp)
8080 {
8081         int32_t port;
8082 
8083         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
8084 
8085         /* Get which port to operate on.  */
8086         if (nvlist_lookup_int32(ndi_dc_get_ap_data(dcp), "port", &port) != 0) {
8087                 USB_DPRINTF_L2(DPRINT_MASK_CBOPS, hubd->h_log_handle,
8088                     "hubd_get_port_num: port lookup failed");
8089                 port = 0;
8090         }
8091 
8092         USB_DPRINTF_L4(DPRINT_MASK_CBOPS,  hubd->h_log_handle,
8093             "hubd_get_port_num: hubd=0x%p, port=%d", (void *)hubd, port);
8094 
8095         return ((usb_port_t)port);
8096 }
8097 
8098 
8099 /* check if child still exists */
8100 static dev_info_t *
8101 hubd_get_child_dip(hubd_t *hubd, usb_port_t port)
8102 {
8103         dev_info_t *child_dip = hubd->h_children_dips[port];
8104 
8105         USB_DPRINTF_L4(DPRINT_MASK_CBOPS,  hubd->h_log_handle,
8106             "hubd_get_child_dip: hubd=0x%p, port=%d", (void *)hubd, port);
8107 
8108         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
8109 
8110         return (child_dip);
8111 }
8112 
8113 
8114 /*
8115  * hubd_cfgadm_state:
8116  *
8117  *      child_dip list          port_state              cfgadm_state
8118  *      --------------          ----------              ------------
8119  *      != NULL                 connected               configured or
8120  *                                                      unconfigured
8121  *      != NULL                 not connected           disconnect but
8122  *                                                      busy/still referenced
8123  *      NULL                    connected               logically disconnected
8124  *      NULL                    not connected           empty
8125  */
8126 static uint_t
8127 hubd_cfgadm_state(hubd_t *hubd, usb_port_t port)
8128 {
8129         uint_t          state;
8130         dev_info_t      *child_dip = hubd_get_child_dip(hubd, port);
8131 
8132         if (child_dip) {
8133                 if (hubd->h_port_state[port] & PORT_STATUS_CCS) {
8134                         /*
8135                          * connected,  now check if driver exists
8136                          */
8137                         if (DEVI_IS_DEVICE_OFFLINE(child_dip) ||
8138                             !i_ddi_devi_attached(child_dip)) {
8139                                 state = HUBD_CFGADM_UNCONFIGURED;
8140                         } else {
8141                                 state = HUBD_CFGADM_CONFIGURED;
8142                         }
8143                 } else {
8144                         /*
8145                          * this means that the dip is around for
8146                          * a device that is still referenced but
8147                          * has been yanked out. So the cfgadm info
8148                          * for this state should be EMPTY (port empty)
8149                          * and CONFIGURED (dip still valid).
8150                          */
8151                         state = HUBD_CFGADM_STILL_REFERENCED;
8152                 }
8153         } else {
8154                 /* connected but no child dip */
8155                 if (hubd->h_port_state[port] & PORT_STATUS_CCS) {
8156                         /* logically disconnected */
8157                         state = HUBD_CFGADM_DISCONNECTED;
8158                 } else {
8159                         /* physically disconnected */
8160                         state = HUBD_CFGADM_EMPTY;
8161                 }
8162         }
8163 
8164         USB_DPRINTF_L4(DPRINT_MASK_CBOPS,  hubd->h_log_handle,
8165             "hubd_cfgadm_state: hubd=0x%p, port=%d state=0x%x",
8166             (void *)hubd, port, state);
8167 
8168         return (state);
8169 }
8170 
8171 
8172 /*
8173  * hubd_toggle_port:
8174  */
8175 static int
8176 hubd_toggle_port(hubd_t *hubd, usb_port_t port)
8177 {
8178         usb_hub_descr_t *hub_descr;
8179         int             wait;
8180         uint_t          retry;
8181         uint16_t        status;
8182         uint16_t        change;
8183 
8184         USB_DPRINTF_L4(DPRINT_MASK_CBOPS,  hubd->h_log_handle,
8185             "hubd_toggle_port: hubd=0x%p, port=%d", (void *)hubd, port);
8186 
8187         if ((hubd_disable_port_power(hubd, port)) != USB_SUCCESS) {
8188 
8189                 return (USB_FAILURE);
8190         }
8191 
8192         /*
8193          * see hubd_enable_all_port_power() which
8194          * requires longer delay for hubs.
8195          */
8196         mutex_exit(HUBD_MUTEX(hubd));
8197         delay(drv_usectohz(hubd_device_delay / 10));
8198         mutex_enter(HUBD_MUTEX(hubd));
8199 
8200         hub_descr = &hubd->h_hub_descr;
8201 
8202         /*
8203          * According to section 11.11 of USB, for hubs with no power
8204          * switches, bPwrOn2PwrGood is zero. But we wait for some
8205          * arbitrary time to enable power to become stable.
8206          *
8207          * If an hub supports port power swicthing, we need to wait
8208          * at least 20ms before accesing corresonding usb port.
8209          */
8210         if ((hub_descr->wHubCharacteristics &
8211             HUB_CHARS_NO_POWER_SWITCHING) || (!hub_descr->bPwrOn2PwrGood)) {
8212                 wait = hubd_device_delay / 10;
8213         } else {
8214                 wait = max(HUB_DEFAULT_POPG,
8215                     hub_descr->bPwrOn2PwrGood) * 2 * 1000;
8216         }
8217 
8218         USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
8219             "hubd_toggle_port: popg=%d wait=%d",
8220             hub_descr->bPwrOn2PwrGood, wait);
8221 
8222         retry = 0;
8223 
8224         do {
8225                 (void) hubd_enable_port_power(hubd, port);
8226 
8227                 mutex_exit(HUBD_MUTEX(hubd));
8228                 delay(drv_usectohz(wait));
8229                 mutex_enter(HUBD_MUTEX(hubd));
8230 
8231                 /* Get port status */
8232                 (void) hubd_determine_port_status(hubd, port,
8233                     &status, &change, 0);
8234 
8235                 /* For retry if any, use some extra delay */
8236                 wait = max(wait, hubd_device_delay / 10);
8237 
8238                 retry++;
8239 
8240         } while ((!(status & PORT_STATUS_PPS)) && (retry < HUBD_PORT_RETRY));
8241 
8242         /* Print warning message if port has no power */
8243         if (!(status & PORT_STATUS_PPS)) {
8244 
8245                 USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
8246                     "hubd_toggle_port: port %d power-on failed, "
8247                     "port status 0x%x", port, status);
8248 
8249                 return (USB_FAILURE);
8250         }
8251 
8252         return (USB_SUCCESS);
8253 }
8254 
8255 
8256 /*
8257  * hubd_init_power_budget:
8258  *      Init power budget variables in hubd structure. According
8259  *      to USB spec, the power budget rules are:
8260  *      1. local-powered hubs including root-hubs can supply
8261  *         500mA to each port at maximum
8262  *      2. two bus-powered hubs are not allowed to concatenate
8263  *      3. bus-powered hubs can supply 100mA to each port at
8264  *         maximum, and the power consumed by all downstream
8265  *         ports and the hub itself cannot exceed the max power
8266  *         supplied by the upstream port, i.e., 500mA
8267  *      The routine is only called during hub attach time
8268  */
8269 static int
8270 hubd_init_power_budget(hubd_t *hubd)
8271 {
8272         uint16_t        status = 0;
8273         usba_device_t   *hubd_ud = NULL;
8274         size_t          size;
8275         usb_cfg_descr_t cfg_descr;
8276         dev_info_t      *pdip = NULL;
8277         hubd_t          *phubd = NULL;
8278 
8279         if (hubd->h_ignore_pwr_budget) {
8280 
8281                 return (USB_SUCCESS);
8282         }
8283 
8284         USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
8285             "hubd_init_power_budget:");
8286 
8287         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
8288         ASSERT(hubd->h_default_pipe != 0);
8289         mutex_exit(HUBD_MUTEX(hubd));
8290 
8291         /* get device status */
8292         if ((usb_get_status(hubd->h_dip, hubd->h_default_pipe,
8293             HUB_GET_DEVICE_STATUS_TYPE,
8294             0, &status, 0)) != USB_SUCCESS) {
8295                 mutex_enter(HUBD_MUTEX(hubd));
8296 
8297                 return (USB_FAILURE);
8298         }
8299 
8300         hubd_ud = usba_get_usba_device(hubd->h_dip);
8301 
8302         size = usb_parse_cfg_descr(hubd_ud->usb_cfg, hubd_ud->usb_cfg_length,
8303             &cfg_descr, USB_CFG_DESCR_SIZE);
8304 
8305         if (size != USB_CFG_DESCR_SIZE) {
8306                 USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle,
8307                     "get hub configuration descriptor failed");
8308                 mutex_enter(HUBD_MUTEX(hubd));
8309 
8310                 return (USB_FAILURE);
8311         }
8312 
8313         mutex_enter(HUBD_MUTEX(hubd));
8314 
8315         hubd->h_local_pwr_capable = (cfg_descr.bmAttributes &
8316             USB_CFG_ATTR_SELFPWR);
8317 
8318         if (hubd->h_local_pwr_capable) {
8319                 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle,
8320                     "hub is capable of local power");
8321         }
8322 
8323         hubd->h_local_pwr_on = (status &
8324             USB_DEV_SLF_PWRD_STATUS) && hubd->h_local_pwr_capable;
8325 
8326         if (hubd->h_local_pwr_on) {
8327                 USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle,
8328                     "hub is local-powered");
8329 
8330                 hubd->h_pwr_limit = (USB_PWR_UNIT_LOAD *
8331                     USB_HIGH_PWR_VALUE) / USB_CFG_DESCR_PWR_UNIT;
8332         } else {
8333                 hubd->h_pwr_limit = (USB_PWR_UNIT_LOAD *
8334                     USB_LOW_PWR_VALUE) / USB_CFG_DESCR_PWR_UNIT;
8335 
8336                 hubd->h_pwr_left = (USB_PWR_UNIT_LOAD *
8337                     USB_HIGH_PWR_VALUE) / USB_CFG_DESCR_PWR_UNIT;
8338 
8339                 ASSERT(!usba_is_root_hub(hubd->h_dip));
8340 
8341                 if (!usba_is_root_hub(hubd->h_dip)) {
8342                         /*
8343                          * two bus-powered hubs are not
8344                          * allowed to be concatenated
8345                          */
8346                         mutex_exit(HUBD_MUTEX(hubd));
8347 
8348                         pdip = ddi_get_parent(hubd->h_dip);
8349                         phubd = hubd_get_soft_state(pdip);
8350                         ASSERT(phubd != NULL);
8351 
8352                         if (!phubd->h_ignore_pwr_budget) {
8353                                 mutex_enter(HUBD_MUTEX(phubd));
8354                                 if (phubd->h_local_pwr_on == B_FALSE) {
8355                                         USB_DPRINTF_L1(DPRINT_MASK_HUB,
8356                                             hubd->h_log_handle,
8357                                             "two bus-powered hubs cannot "
8358                                             "be concatenated");
8359 
8360                                         mutex_exit(HUBD_MUTEX(phubd));
8361                                         mutex_enter(HUBD_MUTEX(hubd));
8362 
8363                                         return (USB_FAILURE);
8364                                 }
8365                                 mutex_exit(HUBD_MUTEX(phubd));
8366                         }
8367 
8368                         mutex_enter(HUBD_MUTEX(hubd));
8369 
8370                         USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle,
8371                             "hub is bus-powered");
8372                 } else {
8373                         USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle,
8374                             "root-hub must be local-powered");
8375                 }
8376 
8377                 /*
8378                  * Subtract the power consumed by the hub itself
8379                  * and get the power that can be supplied to
8380                  * downstream ports
8381                  */
8382                 hubd->h_pwr_left -=
8383                     hubd->h_hub_descr.bHubContrCurrent /
8384                     USB_CFG_DESCR_PWR_UNIT;
8385                 if (hubd->h_pwr_left < 0) {
8386                         USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle,
8387                             "hubd->h_pwr_left is less than bHubContrCurrent, "
8388                             "should fail");
8389 
8390                         return (USB_FAILURE);
8391                 }
8392         }
8393 
8394         return (USB_SUCCESS);
8395 }
8396 
8397 
8398 /*
8399  * usba_hubdi_check_power_budget:
8400  *      Check if the hub has enough power budget to allow a
8401  *      child device to select a configuration of config_index.
8402  */
8403 int
8404 usba_hubdi_check_power_budget(dev_info_t *dip, usba_device_t *child_ud,
8405         uint_t config_index)
8406 {
8407         int16_t         pwr_left, pwr_limit, pwr_required;
8408         size_t          size;
8409         usb_cfg_descr_t cfg_descr;
8410         hubd_t          *hubd;
8411 
8412         if ((hubd = hubd_get_soft_state(dip)) == NULL) {
8413 
8414                 return (USB_FAILURE);
8415         }
8416 
8417         if (hubd->h_ignore_pwr_budget) {
8418 
8419                 return (USB_SUCCESS);
8420         }
8421 
8422         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
8423             "usba_hubdi_check_power_budget: "
8424             "dip=0x%p child_ud=0x%p conf_index=%d", (void *)dip,
8425             (void *)child_ud, config_index);
8426 
8427         mutex_enter(HUBD_MUTEX(hubd));
8428         pwr_limit = hubd->h_pwr_limit;
8429         if (hubd->h_local_pwr_on == B_FALSE) {
8430                 pwr_left = hubd->h_pwr_left;
8431                 pwr_limit = (pwr_limit <= pwr_left) ? pwr_limit : pwr_left;
8432         }
8433         mutex_exit(HUBD_MUTEX(hubd));
8434 
8435         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
8436             "usba_hubdi_check_power_budget: "
8437             "available power is %dmA", pwr_limit * USB_CFG_DESCR_PWR_UNIT);
8438 
8439         size = usb_parse_cfg_descr(
8440             child_ud->usb_cfg_array[config_index], USB_CFG_DESCR_SIZE,
8441             &cfg_descr, USB_CFG_DESCR_SIZE);
8442 
8443         if (size != USB_CFG_DESCR_SIZE) {
8444                 USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
8445                     "get hub configuration descriptor failed");
8446 
8447                 return (USB_FAILURE);
8448         }
8449 
8450         pwr_required = cfg_descr.bMaxPower;
8451 
8452         USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
8453             "usba_hubdi_check_power_budget: "
8454             "child bmAttributes=0x%x bMaxPower=%d "
8455             "with config_index=%d", cfg_descr.bmAttributes,
8456             pwr_required, config_index);
8457 
8458         if (pwr_required > pwr_limit) {
8459                 USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
8460                     "configuration %d for device %s %s at port %d "
8461                     "exceeds power available for this port, please "
8462                     "re-insert your device into another hub port which "
8463                     "has enough power",
8464                     config_index,
8465                     child_ud->usb_mfg_str,
8466                     child_ud->usb_product_str,
8467                     child_ud->usb_port);
8468 
8469                 return (USB_FAILURE);
8470         }
8471 
8472         return (USB_SUCCESS);
8473 }
8474 
8475 
8476 /*
8477  * usba_hubdi_incr_power_budget:
8478  *      Increase the hub power budget value when a child device
8479  *      is removed from a bus-powered hub port.
8480  */
8481 void
8482 usba_hubdi_incr_power_budget(dev_info_t *dip, usba_device_t *child_ud)
8483 {
8484         uint16_t        pwr_value;
8485         hubd_t          *hubd = hubd_get_soft_state(dip);
8486 
8487         ASSERT(hubd != NULL);
8488 
8489         if (hubd->h_ignore_pwr_budget) {
8490 
8491                 return;
8492         }
8493 
8494         USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
8495             "usba_hubdi_incr_power_budget: "
8496             "dip=0x%p child_ud=0x%p", (void *)dip, (void *)child_ud);
8497 
8498         mutex_enter(HUBD_MUTEX(hubd));
8499         if (hubd->h_local_pwr_on == B_TRUE) {
8500                 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle,
8501                     "usba_hubdi_incr_power_budget: "
8502                     "hub is local powered");
8503                 mutex_exit(HUBD_MUTEX(hubd));
8504 
8505                 return;
8506         }
8507         mutex_exit(HUBD_MUTEX(hubd));
8508 
8509         mutex_enter(&child_ud->usb_mutex);
8510         if (child_ud->usb_pwr_from_hub == 0) {
8511                 mutex_exit(&child_ud->usb_mutex);
8512 
8513                 return;
8514         }
8515         pwr_value = child_ud->usb_pwr_from_hub;
8516         mutex_exit(&child_ud->usb_mutex);
8517 
8518         mutex_enter(HUBD_MUTEX(hubd));
8519         hubd->h_pwr_left += pwr_value;
8520 
8521         USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle,
8522             "usba_hubdi_incr_power_budget: "
8523             "available power is %dmA, increased by %dmA",
8524             hubd->h_pwr_left * USB_CFG_DESCR_PWR_UNIT,
8525             pwr_value * USB_CFG_DESCR_PWR_UNIT);
8526 
8527         mutex_exit(HUBD_MUTEX(hubd));
8528 
8529         mutex_enter(&child_ud->usb_mutex);
8530         child_ud->usb_pwr_from_hub = 0;
8531         mutex_exit(&child_ud->usb_mutex);
8532 }
8533 
8534 
8535 /*
8536  * usba_hubdi_decr_power_budget:
8537  *      Decrease the hub power budget value when a child device
8538  *      is inserted to a bus-powered hub port.
8539  */
8540 void
8541 usba_hubdi_decr_power_budget(dev_info_t *dip, usba_device_t *child_ud)
8542 {
8543         uint16_t        pwr_value;
8544         size_t          size;
8545         usb_cfg_descr_t cfg_descr;
8546         hubd_t          *hubd = hubd_get_soft_state(dip);
8547 
8548         ASSERT(hubd != NULL);
8549 
8550         if (hubd->h_ignore_pwr_budget) {
8551 
8552                 return;
8553         }
8554 
8555         USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
8556             "usba_hubdi_decr_power_budget: "
8557             "dip=0x%p child_ud=0x%p", (void *)dip, (void *)child_ud);
8558 
8559         mutex_enter(HUBD_MUTEX(hubd));
8560         if (hubd->h_local_pwr_on == B_TRUE) {
8561                 USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle,
8562                     "usba_hubdi_decr_power_budget: "
8563                     "hub is local powered");
8564                 mutex_exit(HUBD_MUTEX(hubd));
8565 
8566                 return;
8567         }
8568         mutex_exit(HUBD_MUTEX(hubd));
8569 
8570         mutex_enter(&child_ud->usb_mutex);
8571         if (child_ud->usb_pwr_from_hub > 0) {
8572                 mutex_exit(&child_ud->usb_mutex);
8573 
8574                 return;
8575         }
8576         mutex_exit(&child_ud->usb_mutex);
8577 
8578         size = usb_parse_cfg_descr(
8579             child_ud->usb_cfg, child_ud->usb_cfg_length,
8580             &cfg_descr, USB_CFG_DESCR_SIZE);
8581         ASSERT(size == USB_CFG_DESCR_SIZE);
8582 
8583         mutex_enter(HUBD_MUTEX(hubd));
8584         pwr_value = cfg_descr.bMaxPower;
8585         hubd->h_pwr_left -= pwr_value;
8586         ASSERT(hubd->h_pwr_left >= 0);
8587 
8588         USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle,
8589             "usba_hubdi_decr_power_budget: "
8590             "available power is %dmA, decreased by %dmA",
8591             hubd->h_pwr_left * USB_CFG_DESCR_PWR_UNIT,
8592             pwr_value * USB_CFG_DESCR_PWR_UNIT);
8593 
8594         mutex_exit(HUBD_MUTEX(hubd));
8595 
8596         mutex_enter(&child_ud->usb_mutex);
8597         child_ud->usb_pwr_from_hub = pwr_value;
8598         mutex_exit(&child_ud->usb_mutex);
8599 }
8600 
8601 /*
8602  * hubd_wait_for_hotplug_exit:
8603  *      Waiting for the exit of the running hotplug thread or ioctl thread.
8604  */
8605 static int
8606 hubd_wait_for_hotplug_exit(hubd_t *hubd)
8607 {
8608         clock_t         until = drv_sectohz(1);
8609         int             rval;
8610 
8611         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
8612 
8613         if (hubd->h_hotplug_thread) {
8614                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
8615                     "waiting for hubd hotplug thread exit");
8616                 rval = cv_reltimedwait(&hubd->h_cv_hotplug_dev,
8617                     &hubd->h_mutex, until, TR_CLOCK_TICK);
8618 
8619                 if ((rval <= 0) && (hubd->h_hotplug_thread)) {
8620 
8621                         return (USB_FAILURE);
8622                 }
8623         }
8624 
8625         return (USB_SUCCESS);
8626 }
8627 
8628 /*
8629  * hubd_reset_thread:
8630  *      handles the "USB_RESET_LVL_REATTACH" reset of usb device.
8631  *
8632  *      - delete the child (force detaching the device and its children)
8633  *      - reset the corresponding parent hub port
8634  *      - create the child (force re-attaching the device and its children)
8635  */
8636 static void
8637 hubd_reset_thread(void *arg)
8638 {
8639         hubd_reset_arg_t *hd_arg = (hubd_reset_arg_t *)arg;
8640         hubd_t          *hubd = hd_arg->hubd;
8641         uint16_t        reset_port = hd_arg->reset_port;
8642         uint16_t        status, change;
8643         hub_power_t     *hubpm;
8644         dev_info_t      *hdip = hubd->h_dip;
8645         dev_info_t      *rh_dip = hubd->h_usba_device->usb_root_hub_dip;
8646         dev_info_t      *child_dip;
8647         boolean_t       online_child = B_FALSE;
8648         int             prh_circ, rh_circ, circ, devinst;
8649         char            *devname;
8650         int             i = 0;
8651         int             rval = USB_FAILURE;
8652 
8653         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
8654             "hubd_reset_thread:  started, hubd_reset_port = 0x%x", reset_port);
8655 
8656         kmem_free(arg, sizeof (hubd_reset_arg_t));
8657 
8658         mutex_enter(HUBD_MUTEX(hubd));
8659 
8660         child_dip = hubd->h_children_dips[reset_port];
8661         ASSERT(child_dip != NULL);
8662 
8663         devname = (char *)ddi_driver_name(child_dip);
8664         devinst = ddi_get_instance(child_dip);
8665 
8666         /* if our bus power entry point is active, quit the reset */
8667         if (hubd->h_bus_pwr) {
8668                 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
8669                     "%s%d is under bus power management, cannot be reset. "
8670                     "Please disconnect and reconnect this device.",
8671                     devname, devinst);
8672 
8673                 goto Fail;
8674         }
8675 
8676         if (hubd_wait_for_hotplug_exit(hubd) == USB_FAILURE) {
8677                 /* we got woken up because of a timeout */
8678                 USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG,
8679                     hubd->h_log_handle, "Time out when resetting the device"
8680                     " %s%d. Please disconnect and reconnect this device.",
8681                     devname, devinst);
8682 
8683                 goto Fail;
8684         }
8685 
8686         hubd->h_hotplug_thread++;
8687 
8688         /* is this the root hub? */
8689         if ((hdip == rh_dip) &&
8690             (hubd->h_dev_state == USB_DEV_PWRED_DOWN)) {
8691                 hubpm = hubd->h_hubpm;
8692 
8693                 /* mark the root hub as full power */
8694                 hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR;
8695                 hubpm->hubp_time_at_full_power = gethrtime();
8696                 mutex_exit(HUBD_MUTEX(hubd));
8697 
8698                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
8699                     "hubd_reset_thread: call pm_power_has_changed");
8700 
8701                 (void) pm_power_has_changed(hdip, 0,
8702                     USB_DEV_OS_FULL_PWR);
8703 
8704                 mutex_enter(HUBD_MUTEX(hubd));
8705                 hubd->h_dev_state = USB_DEV_ONLINE;
8706         }
8707 
8708         mutex_exit(HUBD_MUTEX(hubd));
8709 
8710         /*
8711          * this ensures one reset activity per system at a time.
8712          * we enter the parent PCI node to have this serialization.
8713          * this also excludes ioctls and deathrow thread
8714          */
8715         ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ);
8716         ndi_devi_enter(rh_dip, &rh_circ);
8717 
8718         /* exclude other threads */
8719         ndi_devi_enter(hdip, &circ);
8720         mutex_enter(HUBD_MUTEX(hubd));
8721 
8722         /*
8723          * We need to make sure that the child is still online for a hotplug
8724          * thread could have inserted which detached the child.
8725          */
8726         if (hubd->h_children_dips[reset_port]) {
8727                 mutex_exit(HUBD_MUTEX(hubd));
8728                 /* First disconnect the device */
8729                 hubd_post_event(hubd, reset_port, USBA_EVENT_TAG_HOT_REMOVAL);
8730 
8731                 /* delete cached dv_node's but drop locks first */
8732                 ndi_devi_exit(hdip, circ);
8733                 ndi_devi_exit(rh_dip, rh_circ);
8734                 ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ);
8735 
8736                 (void) devfs_clean(rh_dip, NULL, DV_CLEAN_FORCE);
8737 
8738                 /*
8739                  * workaround only for storage device. When it's able to force
8740                  * detach a driver, this code can be removed safely.
8741                  *
8742                  * If we're to reset storage device and the device is used, we
8743                  * will wait at most extra 20s for applications to exit and
8744                  * close the device. This is especially useful for HAL-based
8745                  * applications.
8746                  */
8747                 if ((strcmp(devname, "scsa2usb") == 0) &&
8748                     DEVI(child_dip)->devi_ref != 0) {
8749                         while (i++ < hubdi_reset_delay) {
8750                                 mutex_enter(HUBD_MUTEX(hubd));
8751                                 rval = hubd_delete_child(hubd, reset_port,
8752                                     NDI_DEVI_REMOVE, B_FALSE);
8753                                 mutex_exit(HUBD_MUTEX(hubd));
8754                                 if (rval == USB_SUCCESS)
8755                                         break;
8756 
8757                                 delay(drv_sectohz(1));
8758                         }
8759                 }
8760 
8761                 ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ);
8762                 ndi_devi_enter(rh_dip, &rh_circ);
8763                 ndi_devi_enter(hdip, &circ);
8764 
8765                 mutex_enter(HUBD_MUTEX(hubd));
8766 
8767                 /* Then force detaching the device */
8768                 if ((rval != USB_SUCCESS) && (hubd_delete_child(hubd,
8769                     reset_port, NDI_DEVI_REMOVE, B_FALSE) != USB_SUCCESS)) {
8770                         USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
8771                             "%s%d cannot be reset due to other applications "
8772                             "are using it, please first close these "
8773                             "applications, then disconnect and reconnect"
8774                             "the device.", devname, devinst);
8775 
8776                         mutex_exit(HUBD_MUTEX(hubd));
8777                         /* post a re-connect event */
8778                         hubd_post_event(hubd, reset_port,
8779                             USBA_EVENT_TAG_HOT_INSERTION);
8780                         mutex_enter(HUBD_MUTEX(hubd));
8781                 } else {
8782                         (void) hubd_determine_port_status(hubd, reset_port,
8783                             &status, &change, HUBD_ACK_ALL_CHANGES);
8784 
8785                         /* Reset the parent hubd port and create new child */
8786                         if (status & PORT_STATUS_CCS) {
8787                                 online_child |= (hubd_handle_port_connect(hubd,
8788                                     reset_port) == USB_SUCCESS);
8789                         }
8790                 }
8791         }
8792 
8793         /* release locks so we can do a devfs_clean */
8794         mutex_exit(HUBD_MUTEX(hubd));
8795 
8796         /* delete cached dv_node's but drop locks first */
8797         ndi_devi_exit(hdip, circ);
8798         ndi_devi_exit(rh_dip, rh_circ);
8799         ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ);
8800 
8801         (void) devfs_clean(rh_dip, NULL, 0);
8802 
8803         /* now check if any children need onlining */
8804         if (online_child) {
8805                 USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
8806                     "hubd_reset_thread: onlining children");
8807 
8808                 (void) ndi_devi_online(hubd->h_dip, 0);
8809         }
8810 
8811         mutex_enter(HUBD_MUTEX(hubd));
8812 
8813         /* allow hotplug thread now */
8814         hubd->h_hotplug_thread--;
8815 Fail:
8816         hubd_start_polling(hubd, 0);
8817 
8818         /* mark this device as idle */
8819         (void) hubd_pm_idle_component(hubd, hubd->h_dip, 0);
8820 
8821         USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
8822             "hubd_reset_thread: exit, %d", hubd->h_hotplug_thread);
8823 
8824         hubd->h_reset_port[reset_port] = B_FALSE;
8825 
8826         mutex_exit(HUBD_MUTEX(hubd));
8827 
8828         ndi_rele_devi(hdip);
8829 }
8830 
8831 /*
8832  * hubd_check_same_device:
8833  *      - open the default pipe of the device.
8834  *      - compare the old and new descriptors of the device.
8835  *      - close the default pipe.
8836  */
8837 static int
8838 hubd_check_same_device(hubd_t *hubd, usb_port_t port)
8839 {
8840         dev_info_t              *dip = hubd->h_children_dips[port];
8841         usb_pipe_handle_t       ph;
8842         int                     rval = USB_FAILURE;
8843 
8844         ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
8845 
8846         mutex_exit(HUBD_MUTEX(hubd));
8847         /* Open the default pipe to operate the device */
8848         if (usb_pipe_open(dip, NULL, NULL,
8849             USB_FLAGS_SLEEP| USBA_FLAGS_PRIVILEGED,
8850             &ph) == USB_SUCCESS) {
8851                 /*
8852                  * Check that if the device's descriptors are different
8853                  * from the values saved before the port reset.
8854                  */
8855                 rval = usb_check_same_device(dip,
8856                     hubd->h_log_handle, USB_LOG_L0,
8857                     DPRINT_MASK_ALL, USB_CHK_ALL, NULL);
8858 
8859                 usb_pipe_close(dip, ph, USB_FLAGS_SLEEP |
8860                     USBA_FLAGS_PRIVILEGED, NULL, NULL);
8861         }
8862         mutex_enter(HUBD_MUTEX(hubd));
8863 
8864         return (rval);
8865 }
8866 
8867 /*
8868  * usba_hubdi_reset_device
8869  *      Called by usb_reset_device to handle usb device reset.
8870  */
8871 int
8872 usba_hubdi_reset_device(dev_info_t *dip, usb_dev_reset_lvl_t reset_level)
8873 {
8874         hubd_t                  *hubd;
8875         usb_port_t              port = 0;
8876         dev_info_t              *hdip;
8877         usb_pipe_state_t        prev_pipe_state = 0;
8878         usba_device_t           *usba_device;
8879         hubd_reset_arg_t        *arg;
8880         int                     i, ph_open_cnt;
8881         int                     rval = USB_FAILURE;
8882 
8883         if ((!dip) || usba_is_root_hub(dip)) {
8884                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle,
8885                     "usba_hubdi_reset_device: NULL dip or root hub");
8886 
8887                 return (USB_INVALID_ARGS);
8888         }
8889 
8890         if (!usb_owns_device(dip)) {
8891                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle,
8892                     "usba_hubdi_reset_device: Not owns the device");
8893 
8894                 return (USB_INVALID_PERM);
8895         }
8896 
8897         if ((reset_level != USB_RESET_LVL_REATTACH) &&
8898             (reset_level != USB_RESET_LVL_DEFAULT)) {
8899                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle,
8900                     "usba_hubdi_reset_device: Unknown flags");
8901 
8902                 return (USB_INVALID_ARGS);
8903         }
8904 
8905         if ((hdip = ddi_get_parent(dip)) == NULL) {
8906                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle,
8907                     "usba_hubdi_reset_device: fail to get parent hub");
8908 
8909                 return (USB_INVALID_ARGS);
8910         }
8911 
8912         if ((hubd = hubd_get_soft_state(hdip)) == NULL) {
8913                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle,
8914                     "usba_hubdi_reset_device: fail to get hub softstate");
8915 
8916                 return (USB_INVALID_ARGS);
8917         }
8918 
8919         mutex_enter(HUBD_MUTEX(hubd));
8920 
8921         /* make sure the hub is connected before trying any kinds of reset. */
8922         if ((hubd->h_dev_state == USB_DEV_DISCONNECTED) ||
8923             (hubd->h_dev_state == USB_DEV_SUSPENDED)) {
8924                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
8925                     "usb_reset_device: the state %d of the hub/roothub "
8926                     "associated to the device 0x%p is incorrect",
8927                     hubd->h_dev_state, (void *)dip);
8928                 mutex_exit(HUBD_MUTEX(hubd));
8929 
8930                 return (USB_INVALID_ARGS);
8931         }
8932 
8933         mutex_exit(HUBD_MUTEX(hubd));
8934 
8935         port = hubd_child_dip2port(hubd, dip);
8936 
8937         mutex_enter(HUBD_MUTEX(hubd));
8938 
8939         if (hubd->h_reset_port[port]) {
8940                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
8941                     "usb_reset_device: the corresponding port is resetting");
8942                 mutex_exit(HUBD_MUTEX(hubd));
8943 
8944                 return (USB_SUCCESS);
8945         }
8946 
8947         /*
8948          * For Default reset, client drivers should first close all the pipes
8949          * except default pipe before calling the function, also should not
8950          * call the function during interrupt context.
8951          */
8952         if (reset_level == USB_RESET_LVL_DEFAULT) {
8953                 usba_device = hubd->h_usba_devices[port];
8954                 mutex_exit(HUBD_MUTEX(hubd));
8955 
8956                 if (servicing_interrupt()) {
8957                         USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
8958                             "usb_reset_device: during interrput context, quit");
8959 
8960                         return (USB_INVALID_CONTEXT);
8961                 }
8962                 /* Check if all the pipes have been closed */
8963                 for (ph_open_cnt = 0, i = 1; i < USBA_N_ENDPOINTS; i++) {
8964                         if (usba_device->usb_ph_list[i].usba_ph_data) {
8965                                 ph_open_cnt++;
8966                                 break;
8967                         }
8968                 }
8969                 if (ph_open_cnt) {
8970                         USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
8971                             "usb_reset_device: %d pipes are still open",
8972                             ph_open_cnt);
8973 
8974                         return (USB_BUSY);
8975                 }
8976                 mutex_enter(HUBD_MUTEX(hubd));
8977         }
8978 
8979         /* Don't perform reset while the device is detaching */
8980         if (hubd->h_port_state[port] & HUBD_CHILD_DETACHING) {
8981                 USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
8982                     "usb_reset_device: the device is detaching, "
8983                     "cannot be reset");
8984                 mutex_exit(HUBD_MUTEX(hubd));
8985 
8986                 return (USB_FAILURE);
8987         }
8988 
8989         hubd->h_reset_port[port] = B_TRUE;
8990         hdip = hubd->h_dip;
8991         mutex_exit(HUBD_MUTEX(hubd));
8992 
8993         /* Don't allow hub detached during the reset */
8994         ndi_hold_devi(hdip);
8995 
8996         mutex_enter(HUBD_MUTEX(hubd));
8997         hubd_pm_busy_component(hubd, hdip, 0);
8998         mutex_exit(HUBD_MUTEX(hubd));
8999         /* go full power */
9000         (void) pm_raise_power(hdip, 0, USB_DEV_OS_FULL_PWR);
9001         mutex_enter(HUBD_MUTEX(hubd));
9002 
9003         hubd->h_hotplug_thread++;
9004 
9005         /* stop polling if it was active */
9006         if (hubd->h_ep1_ph) {
9007                 mutex_exit(HUBD_MUTEX(hubd));
9008                 (void) usb_pipe_get_state(hubd->h_ep1_ph, &prev_pipe_state,
9009                     USB_FLAGS_SLEEP);
9010                 mutex_enter(HUBD_MUTEX(hubd));
9011 
9012                 if (prev_pipe_state == USB_PIPE_STATE_ACTIVE) {
9013                         hubd_stop_polling(hubd);
9014                 }
9015         }
9016 
9017         switch (reset_level) {
9018         case USB_RESET_LVL_REATTACH:
9019                 mutex_exit(HUBD_MUTEX(hubd));
9020                 arg = (hubd_reset_arg_t *)kmem_zalloc(
9021                     sizeof (hubd_reset_arg_t), KM_SLEEP);
9022                 arg->hubd = hubd;
9023                 arg->reset_port = port;
9024                 mutex_enter(HUBD_MUTEX(hubd));
9025 
9026                 if ((rval = usb_async_req(hdip, hubd_reset_thread,
9027                     (void *)arg, 0)) == USB_SUCCESS) {
9028                         hubd->h_hotplug_thread--;
9029                         mutex_exit(HUBD_MUTEX(hubd));
9030 
9031                         return (USB_SUCCESS);
9032                 } else {
9033                         USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
9034                             "Cannot create reset thread, the device %s%d failed"
9035                             " to reset", ddi_driver_name(dip),
9036                             ddi_get_instance(dip));
9037 
9038                         kmem_free(arg, sizeof (hubd_reset_arg_t));
9039                 }
9040 
9041                 break;
9042         case USB_RESET_LVL_DEFAULT:
9043                 /*
9044                  * Reset hub port and then recover device's address, set back
9045                  * device's configuration, hubd_handle_port_connect() will
9046                  * handle errors happened during this process.
9047                  */
9048                 if ((rval = hubd_handle_port_connect(hubd, port))
9049                     == USB_SUCCESS) {
9050                         mutex_exit(HUBD_MUTEX(hubd));
9051                         /* re-open the default pipe */
9052                         rval = usba_persistent_pipe_open(usba_device);
9053                         mutex_enter(HUBD_MUTEX(hubd));
9054                         if (rval != USB_SUCCESS) {
9055                                 USB_DPRINTF_L2(DPRINT_MASK_ATTA,
9056                                     hubd->h_log_handle, "failed to reopen "
9057                                     "default pipe after reset, disable hub"
9058                                     "port for %s%d", ddi_driver_name(dip),
9059                                     ddi_get_instance(dip));
9060                                 /*
9061                                  * Disable port to set out a hotplug thread
9062                                  * which will handle errors.
9063                                  */
9064                                 (void) hubd_disable_port(hubd, port);
9065                         }
9066                 }
9067 
9068                 break;
9069         default:
9070 
9071                 break;
9072         }
9073 
9074         /* allow hotplug thread now */
9075         hubd->h_hotplug_thread--;
9076 
9077         if ((hubd->h_dev_state == USB_DEV_ONLINE) && hubd->h_ep1_ph &&
9078             (prev_pipe_state == USB_PIPE_STATE_ACTIVE)) {
9079                 hubd_start_polling(hubd, 0);
9080         }
9081 
9082         hubd_pm_idle_component(hubd, hdip, 0);
9083 
9084         /* Clear reset mark for the port. */
9085         hubd->h_reset_port[port] = B_FALSE;
9086 
9087         mutex_exit(HUBD_MUTEX(hubd));
9088 
9089         ndi_rele_devi(hdip);
9090 
9091         return (rval);
9092 }