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