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