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