1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
25 * Copyright 2019, Joyent, Inc.
26 */
27
28/*
29 * USBA: Solaris USB Architecture support for the hub
30 * including root hub
31 * Most of the code for hubd resides in this file and
32 * is shared between the HCD root hub support and hubd
33 */
34#define	USBA_FRAMEWORK
35#include <sys/usb/usba.h>
36#include <sys/usb/usba/usba_devdb.h>
37#include <sys/sunndi.h>
38#include <sys/usb/usba/usba_impl.h>
39#include <sys/usb/usba/usba_types.h>
40#include <sys/usb/usba/hubdi.h>
41#include <sys/usb/usba/hcdi_impl.h>
42#include <sys/usb/hubd/hub.h>
43#include <sys/usb/hubd/hubdvar.h>
44#include <sys/usb/hubd/hubd_impl.h>
45#include <sys/kobj.h>
46#include <sys/kobj_lex.h>
47#include <sys/fs/dv_node.h>
48#include <sys/strsun.h>
49
50/*
51 * External functions
52 */
53extern boolean_t consconfig_console_is_ready(void);
54
55/*
56 * Prototypes for static functions
57 */
58static	int	usba_hubdi_bus_ctl(dev_info_t *dip,
59    dev_info_t *rdip,
60    ddi_ctl_enum_t op,
61    void *arg,
62    void *result);
63
64static int	usba_hubdi_map_fault(dev_info_t *dip,
65    dev_info_t *rdip,
66    struct hat *hat,
67    struct seg *seg,
68    caddr_t addr,
69    struct devpage *dp,
70    pfn_t pfn,
71    uint_t prot,
72    uint_t lock);
73
74static int hubd_busop_get_eventcookie(dev_info_t *dip,
75    dev_info_t *rdip,
76    char *eventname,
77    ddi_eventcookie_t *cookie);
78static int hubd_busop_add_eventcall(dev_info_t *dip,
79    dev_info_t *rdip,
80    ddi_eventcookie_t cookie,
81    void (*callback)(dev_info_t *dip, ddi_eventcookie_t cookie, void *arg,
82	void *bus_impldata),
83    void *arg, ddi_callback_id_t *cb_id);
84static int hubd_busop_remove_eventcall(dev_info_t *dip,
85    ddi_callback_id_t cb_id);
86static int hubd_bus_config(dev_info_t *dip,
87    uint_t flag,
88    ddi_bus_config_op_t op,
89    void *arg,
90    dev_info_t **child);
91static int hubd_bus_unconfig(dev_info_t *dip,
92    uint_t flag,
93    ddi_bus_config_op_t op,
94    void *arg);
95static int hubd_bus_power(dev_info_t *dip, void *impl_arg,
96    pm_bus_power_op_t op, void *arg, void *result);
97
98static usb_port_t  hubd_get_port_num(hubd_t *, struct devctl_iocdata *);
99static dev_info_t *hubd_get_child_dip(hubd_t *, usb_port_t);
100static uint_t hubd_cfgadm_state(hubd_t *, usb_port_t);
101static int hubd_toggle_port(hubd_t *, usb_port_t);
102static void hubd_register_cpr_callback(hubd_t *);
103static void hubd_unregister_cpr_callback(hubd_t *);
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	NULL,				/* 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#define	USB_HUB_INTEL_VID	0x8087
140#define	USB_HUB_INTEL_PID	0x0020
141
142/*
143 * local variables
144 */
145static kmutex_t	usba_hubdi_mutex;	/* protects USBA HUB data structures */
146
147static usba_list_entry_t	usba_hubdi_list;
148
149usb_log_handle_t	hubdi_log_handle;
150uint_t			hubdi_errlevel = USB_LOG_L4;
151uint_t			hubdi_errmask = (uint_t)-1;
152uint8_t			hubdi_min_pm_threshold = 5; /* seconds */
153uint8_t			hubdi_reset_delay = 20; /* seconds */
154extern int modrootloaded;
155
156/*
157 * initialize private data
158 */
159void
160usba_hubdi_initialization()
161{
162	hubdi_log_handle = usb_alloc_log_hdl(NULL, "hubdi", &hubdi_errlevel,
163	    &hubdi_errmask, NULL, 0);
164
165	USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle,
166	    "usba_hubdi_initialization");
167
168	mutex_init(&usba_hubdi_mutex, NULL, MUTEX_DRIVER, NULL);
169
170	usba_init_list(&usba_hubdi_list, NULL, NULL);
171}
172
173
174void
175usba_hubdi_destroy()
176{
177	USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle,
178	    "usba_hubdi_destroy");
179
180	mutex_destroy(&usba_hubdi_mutex);
181	usba_destroy_list(&usba_hubdi_list);
182
183	usb_free_log_hdl(hubdi_log_handle);
184}
185
186
187/*
188 * Called by an	HUB to attach an instance of the driver
189 *	make this instance known to USBA
190 *	the HUB	should initialize usba_hubdi structure prior
191 *	to calling this	interface
192 */
193int
194usba_hubdi_register(dev_info_t	*dip, uint_t flags)
195{
196	usba_hubdi_t *hubdi = kmem_zalloc(sizeof (usba_hubdi_t), KM_SLEEP);
197	usba_device_t *usba_device = usba_get_usba_device(dip);
198
199	USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle,
200	    "usba_hubdi_register: %s", ddi_node_name(dip));
201
202	hubdi->hubdi_dip = dip;
203	hubdi->hubdi_flags = flags;
204
205	usba_device->usb_hubdi = hubdi;
206
207	/*
208	 * add this hubdi instance to the list of known hubdi's
209	 */
210	usba_init_list(&hubdi->hubdi_list, (usb_opaque_t)hubdi,
211	    usba_hcdi_get_hcdi(usba_device->usb_root_hub_dip)->
212	    hcdi_iblock_cookie);
213	mutex_enter(&usba_hubdi_mutex);
214	usba_add_to_list(&usba_hubdi_list, &hubdi->hubdi_list);
215	mutex_exit(&usba_hubdi_mutex);
216
217	return (DDI_SUCCESS);
218}
219
220
221/*
222 * Called by an	HUB to detach an instance of the driver
223 */
224int
225usba_hubdi_unregister(dev_info_t *dip)
226{
227	usba_device_t *usba_device = usba_get_usba_device(dip);
228	usba_hubdi_t *hubdi = usba_device->usb_hubdi;
229
230	USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubdi_log_handle,
231	    "usba_hubdi_unregister: %s", ddi_node_name(dip));
232
233	mutex_enter(&usba_hubdi_mutex);
234	(void) usba_rm_from_list(&usba_hubdi_list, &hubdi->hubdi_list);
235	mutex_exit(&usba_hubdi_mutex);
236
237	usba_destroy_list(&hubdi->hubdi_list);
238
239	kmem_free(hubdi, sizeof (usba_hubdi_t));
240
241	return (DDI_SUCCESS);
242}
243
244
245/*
246 * misc bus routines currently not used
247 */
248/*ARGSUSED*/
249static int
250usba_hubdi_map_fault(dev_info_t *dip,
251    dev_info_t	*rdip,
252    struct hat	*hat,
253    struct seg	*seg,
254    caddr_t	addr,
255    struct devpage	*dp,
256    pfn_t		pfn,
257    uint_t		prot,
258    uint_t		lock)
259{
260	return (DDI_FAILURE);
261}
262
263
264/*
265 * root hub support. the root hub uses the same devi as the HCD
266 */
267int
268usba_hubdi_bind_root_hub(dev_info_t *dip,
269    uchar_t	*root_hub_config_descriptor,
270    size_t config_length,
271    usb_dev_descr_t *root_hub_device_descriptor)
272{
273	usba_device_t *usba_device;
274	usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
275	hubd_t	*root_hubd;
276	usb_pipe_handle_t ph = NULL;
277	dev_info_t *child = ddi_get_child(dip);
278
279	if (ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
280	    "root-hub") != NDI_SUCCESS) {
281
282		return (USB_FAILURE);
283	}
284
285	usba_add_root_hub(dip);
286
287	root_hubd = kmem_zalloc(sizeof (hubd_t), KM_SLEEP);
288
289	/*
290	 * create and initialize a usba_device structure
291	 */
292	usba_device = usba_alloc_usba_device(dip);
293
294	mutex_enter(&usba_device->usb_mutex);
295	usba_device->usb_hcdi_ops = hcdi->hcdi_ops;
296	usba_device->usb_cfg = root_hub_config_descriptor;
297	usba_device->usb_cfg_length = config_length;
298	usba_device->usb_dev_descr = root_hub_device_descriptor;
299	usba_device->usb_port = 1;
300	usba_device->usb_addr = ROOT_HUB_ADDR;
301	usba_device->usb_root_hubd = root_hubd;
302	usba_device->usb_cfg_array = kmem_zalloc(sizeof (uchar_t *),
303	    KM_SLEEP);
304	usba_device->usb_cfg_array_length = sizeof (uchar_t *);
305
306	usba_device->usb_cfg_array_len = kmem_zalloc(sizeof (uint16_t),
307	    KM_SLEEP);
308	usba_device->usb_cfg_array_len_length = sizeof (uint16_t);
309
310	usba_device->usb_cfg_array[0] = root_hub_config_descriptor;
311	usba_device->usb_cfg_array_len[0] =
312	    sizeof (root_hub_config_descriptor);
313
314	usba_device->usb_cfg_str_descr = kmem_zalloc(sizeof (uchar_t *),
315	    KM_SLEEP);
316	usba_device->usb_n_cfgs = 1;
317	usba_device->usb_n_ifs = 1;
318	usba_device->usb_dip = dip;
319
320	usba_device->usb_client_flags = kmem_zalloc(
321	    usba_device->usb_n_ifs * USBA_CLIENT_FLAG_SIZE, KM_SLEEP);
322
323	usba_device->usb_client_attach_list = kmem_zalloc(
324	    usba_device->usb_n_ifs *
325	    sizeof (*usba_device->usb_client_attach_list), KM_SLEEP);
326
327	usba_device->usb_client_ev_cb_list = kmem_zalloc(
328	    usba_device->usb_n_ifs *
329	    sizeof (*usba_device->usb_client_ev_cb_list), KM_SLEEP);
330
331	/*
332	 * The bDeviceProtocol field of root hub device specifies,
333	 * whether root hub is a Super, High, or Full speed usb device.
334	 */
335	if (root_hub_device_descriptor->bDeviceProtocol >= 0x3) {
336		usba_device->usb_port_status = USBA_SUPER_SPEED_DEV;
337	} else if (root_hub_device_descriptor->bDeviceProtocol > 0) {
338		usba_device->usb_port_status = USBA_HIGH_SPEED_DEV;
339	} else {
340		usba_device->usb_port_status = USBA_FULL_SPEED_DEV;
341	}
342
343	mutex_exit(&usba_device->usb_mutex);
344
345	usba_set_usba_device(dip, usba_device);
346
347	/*
348	 * For the root hub the default pipe is not yet open
349	 */
350	if (usb_pipe_open(dip, NULL, NULL,
351	    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph) != USB_SUCCESS) {
352		goto fail;
353	}
354
355	/*
356	 * kill off all OBP children, they may not be fully
357	 * enumerated
358	 */
359	while (child) {
360		dev_info_t *next = ddi_get_next_sibling(child);
361		(void) ddi_remove_child(child, 0);
362		child = next;
363	}
364
365	/*
366	 * "attach" the root hub driver
367	 */
368	if (usba_hubdi_attach(dip, DDI_ATTACH) != DDI_SUCCESS) {
369		goto fail;
370	}
371
372	return (USB_SUCCESS);
373
374fail:
375	if (ph) {
376		usb_pipe_close(dip, ph,
377		    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
378	}
379
380	kmem_free(usba_device->usb_cfg_array,
381	    usba_device->usb_cfg_array_length);
382	kmem_free(usba_device->usb_cfg_array_len,
383	    usba_device->usb_cfg_array_len_length);
384
385	kmem_free(usba_device->usb_cfg_str_descr, sizeof (uchar_t *));
386
387	usba_free_usba_device(usba_device);
388
389	usba_set_usba_device(dip, NULL);
390
391	if (root_hubd) {
392		kmem_free(root_hubd, sizeof (hubd_t));
393	}
394
395	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "root-hub");
396
397	usba_rem_root_hub(dip);
398
399	return (USB_FAILURE);
400}
401
402
403int
404usba_hubdi_unbind_root_hub(dev_info_t *dip)
405{
406	usba_device_t *usba_device;
407
408	/* was root hub attached? */
409	if (!(usba_is_root_hub(dip))) {
410
411		/* return success anyway */
412		return (USB_SUCCESS);
413	}
414
415	/*
416	 * usba_hubdi_detach also closes the default pipe
417	 * and removes properties so there is no need to
418	 * do it here
419	 */
420	if (usba_hubdi_detach(dip, DDI_DETACH) != DDI_SUCCESS) {
421
422		if (DEVI_IS_ATTACHING(dip)) {
423			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle,
424			    "failure to unbind root hub after attach failure");
425		}
426
427		return (USB_FAILURE);
428	}
429
430	usba_device = usba_get_usba_device(dip);
431
432	kmem_free(usba_device->usb_root_hubd, sizeof (hubd_t));
433
434	kmem_free(usba_device->usb_cfg_array,
435	    usba_device->usb_cfg_array_length);
436	kmem_free(usba_device->usb_cfg_array_len,
437	    usba_device->usb_cfg_array_len_length);
438
439	kmem_free(usba_device->usb_cfg_str_descr, sizeof (uchar_t *));
440
441	usba_free_usba_device(usba_device);
442
443	usba_rem_root_hub(dip);
444
445	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "root-hub");
446
447	return (USB_SUCCESS);
448}
449
450
451/*
452 * Actual Hub Driver support code:
453 *	shared by root hub and non-root hubs
454 */
455#include <sys/usb/usba/usbai_version.h>
456
457/* Debugging support */
458uint_t hubd_errlevel	= USB_LOG_L4;
459uint_t hubd_errmask	= (uint_t)DPRINT_MASK_ALL;
460uint_t hubd_instance_debug = (uint_t)-1;
461static uint_t hubdi_bus_config_debug = 0;
462
463_NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_errlevel))
464_NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_errmask))
465_NOTE(DATA_READABLE_WITHOUT_LOCK(hubd_instance_debug))
466
467_NOTE(SCHEME_PROTECTS_DATA("unique", msgb))
468_NOTE(SCHEME_PROTECTS_DATA("unique", dev_info))
469
470
471/*
472 * local variables:
473 *
474 * Amount of time to wait between resetting the port and accessing
475 * the device.	The value is in microseconds.
476 */
477static uint_t hubd_device_delay = 1000000;
478
479/*
480 * enumeration retry
481 */
482#define	HUBD_PORT_RETRY 5
483static uint_t hubd_retry_enumerate = HUBD_PORT_RETRY;
484
485/*
486 * Stale hotremoved device cleanup delay
487 */
488#define	HUBD_STALE_DIP_CLEANUP_DELAY	5000000
489static uint_t hubd_dip_cleanup_delay = HUBD_STALE_DIP_CLEANUP_DELAY;
490
491/*
492 * retries for USB suspend and resume
493 */
494#define	HUBD_SUS_RES_RETRY	2
495
496void	*hubd_statep;
497
498/*
499 * prototypes
500 */
501static int hubd_cleanup(dev_info_t *dip, hubd_t  *hubd);
502static int hubd_check_ports(hubd_t  *hubd);
503
504static int  hubd_open_intr_pipe(hubd_t *hubd);
505static void hubd_start_polling(hubd_t *hubd, int always);
506static void hubd_stop_polling(hubd_t *hubd);
507static void hubd_close_intr_pipe(hubd_t *hubd);
508
509static void hubd_read_cb(usb_pipe_handle_t pipe, usb_intr_req_t *req);
510static void hubd_exception_cb(usb_pipe_handle_t pipe,
511						usb_intr_req_t *req);
512static void hubd_hotplug_thread(void *arg);
513static void hubd_reset_thread(void *arg);
514static int hubd_create_child(dev_info_t *dip,
515		hubd_t		*hubd,
516		usba_device_t	*usba_device,
517		usb_port_status_t port_status,
518		usb_port_t	port,
519		int		iteration);
520
521static int hubd_delete_child(hubd_t *hubd, usb_port_t port, uint_t flag,
522	boolean_t retry);
523
524static int hubd_get_hub_descriptor(hubd_t *hubd);
525
526static int hubd_set_hub_depth(hubd_t *hubd);
527
528static int hubd_get_hub_status_words(hubd_t *hubd, uint16_t *status);
529
530static int hubd_reset_port(hubd_t *hubd, usb_port_t port);
531
532static int hubd_get_hub_status(hubd_t *hubd);
533
534static int hubd_handle_port_connect(hubd_t *hubd, usb_port_t port);
535
536static int hubd_disable_port(hubd_t *hubd, usb_port_t port);
537
538static int hubd_enable_port(hubd_t *hubd, usb_port_t port);
539static int hubd_recover_disabled_port(hubd_t *hubd, usb_port_t port);
540
541static int hubd_determine_port_status(hubd_t *hubd, usb_port_t port,
542	uint16_t *status, uint16_t *change, usb_port_status_t *speed,
543	uint_t ack_flag);
544
545static int hubd_enable_all_port_power(hubd_t *hubd);
546static int hubd_disable_all_port_power(hubd_t *hubd);
547static int hubd_disable_port_power(hubd_t *hubd, usb_port_t port);
548static int hubd_enable_port_power(hubd_t *hubd, usb_port_t port);
549
550static void hubd_free_usba_device(hubd_t *hubd, usba_device_t *usba_device);
551
552static int hubd_can_suspend(hubd_t *hubd);
553static void hubd_restore_device_state(dev_info_t *dip, hubd_t *hubd);
554static int hubd_setdevaddr(hubd_t *hubd, usb_port_t port);
555static void hubd_setdevconfig(hubd_t *hubd, usb_port_t port);
556
557static int hubd_register_events(hubd_t *hubd);
558static void hubd_do_callback(hubd_t *hubd, dev_info_t *dip,
559	ddi_eventcookie_t cookie);
560static void hubd_run_callbacks(hubd_t *hubd, usba_event_t type);
561static void hubd_post_event(hubd_t *hubd, usb_port_t port, usba_event_t type);
562static void hubd_create_pm_components(dev_info_t *dip, hubd_t *hubd);
563
564static int hubd_disconnect_event_cb(dev_info_t *dip);
565static int hubd_reconnect_event_cb(dev_info_t *dip);
566static int hubd_pre_suspend_event_cb(dev_info_t *dip);
567static int hubd_post_resume_event_cb(dev_info_t *dip);
568static int hubd_cpr_suspend(hubd_t *hubd);
569static void hubd_cpr_resume(dev_info_t *dip);
570static int hubd_restore_state_cb(dev_info_t *dip);
571static int hubd_check_same_device(hubd_t *hubd, usb_port_t port);
572
573static int hubd_init_power_budget(hubd_t *hubd);
574
575static ndi_event_definition_t hubd_ndi_event_defs[] = {
576	{USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL,
577						NDI_EVENT_POST_TO_ALL},
578	{USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL,
579						NDI_EVENT_POST_TO_ALL},
580	{USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL,
581						NDI_EVENT_POST_TO_ALL},
582	{USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL,
583						NDI_EVENT_POST_TO_ALL}
584};
585
586#define	HUBD_N_NDI_EVENTS \
587	(sizeof (hubd_ndi_event_defs) / sizeof (ndi_event_definition_t))
588
589static ndi_event_set_t hubd_ndi_events = {
590	NDI_EVENTS_REV1, HUBD_N_NDI_EVENTS, hubd_ndi_event_defs};
591
592/* events received from parent */
593static usb_event_t hubd_events = {
594	hubd_disconnect_event_cb,
595	hubd_reconnect_event_cb,
596	hubd_pre_suspend_event_cb,
597	hubd_post_resume_event_cb
598};
599
600
601/*
602 * hubd_get_soft_state() returns the hubd soft state
603 */
604hubd_t *
605hubd_get_soft_state(dev_info_t *dip)
606{
607	if (dip == NULL) {
608		return (NULL);
609	}
610
611	if (usba_is_root_hub(dip)) {
612		usba_device_t *usba_device = usba_get_usba_device(dip);
613
614		return (usba_device->usb_root_hubd);
615	} else {
616		int instance = ddi_get_instance(dip);
617
618		return (ddi_get_soft_state(hubd_statep, instance));
619	}
620}
621
622
623/*
624 * PM support functions:
625 */
626/*ARGSUSED*/
627static void
628hubd_pm_busy_component(hubd_t *hubd, dev_info_t *dip, int component)
629{
630	if (hubd->h_hubpm != NULL) {
631		hubd->h_hubpm->hubp_busy_pm++;
632		mutex_exit(HUBD_MUTEX(hubd));
633		if (pm_busy_component(dip, 0) != DDI_SUCCESS) {
634			mutex_enter(HUBD_MUTEX(hubd));
635			hubd->h_hubpm->hubp_busy_pm--;
636			mutex_exit(HUBD_MUTEX(hubd));
637		}
638		mutex_enter(HUBD_MUTEX(hubd));
639		USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
640		    "hubd_pm_busy_component: %d", hubd->h_hubpm->hubp_busy_pm);
641	}
642}
643
644
645/*ARGSUSED*/
646static void
647hubd_pm_idle_component(hubd_t *hubd, dev_info_t *dip, int component)
648{
649	if (hubd->h_hubpm != NULL) {
650		mutex_exit(HUBD_MUTEX(hubd));
651		if (pm_idle_component(dip, 0) == DDI_SUCCESS) {
652			mutex_enter(HUBD_MUTEX(hubd));
653			ASSERT(hubd->h_hubpm->hubp_busy_pm > 0);
654			hubd->h_hubpm->hubp_busy_pm--;
655			mutex_exit(HUBD_MUTEX(hubd));
656		}
657		mutex_enter(HUBD_MUTEX(hubd));
658		USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
659		    "hubd_pm_idle_component: %d", hubd->h_hubpm->hubp_busy_pm);
660	}
661}
662
663
664/*
665 * track power level changes for children of this instance
666 */
667static void
668hubd_set_child_pwrlvl(hubd_t *hubd, usb_port_t port, uint8_t power)
669{
670	int	old_power, new_power, pwr;
671	usb_port_t	portno;
672	hub_power_t	*hubpm;
673
674	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
675	    "hubd_set_child_pwrlvl: port=%d power=%d",
676	    port, power);
677
678	mutex_enter(HUBD_MUTEX(hubd));
679	hubpm = hubd->h_hubpm;
680
681	old_power = 0;
682	for (portno = 1; portno <= hubd->h_nports; portno++) {
683		old_power += hubpm->hubp_child_pwrstate[portno];
684	}
685
686	/* assign the port power */
687	pwr = hubd->h_hubpm->hubp_child_pwrstate[port];
688	hubd->h_hubpm->hubp_child_pwrstate[port] = power;
689	new_power = old_power - pwr + power;
690
691	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
692	    "hubd_set_child_pwrlvl: new_power=%d old_power=%d",
693	    new_power, old_power);
694
695	if ((new_power > 0) && (old_power == 0)) {
696		/* we have the first child coming out of low power */
697		(void) hubd_pm_busy_component(hubd, hubd->h_dip, 0);
698	} else if ((new_power == 0) && (old_power > 0)) {
699		/* we have the last child going to low power */
700		(void) hubd_pm_idle_component(hubd, hubd->h_dip, 0);
701	}
702	mutex_exit(HUBD_MUTEX(hubd));
703}
704
705
706/*
707 * given a child dip, locate its port number
708 */
709static usb_port_t
710hubd_child_dip2port(hubd_t *hubd, dev_info_t *dip)
711{
712	usb_port_t	port;
713
714	mutex_enter(HUBD_MUTEX(hubd));
715	for (port = 1; port <= hubd->h_nports; port++) {
716		if (hubd->h_children_dips[port] == dip) {
717
718			break;
719		}
720	}
721	ASSERT(port <= hubd->h_nports);
722	mutex_exit(HUBD_MUTEX(hubd));
723
724	return (port);
725}
726
727
728/*
729 * if the hub can be put into low power mode, return success
730 * NOTE: suspend here means going to lower power, not CPR suspend.
731 */
732static int
733hubd_can_suspend(hubd_t *hubd)
734{
735	hub_power_t	*hubpm;
736	int		total_power = 0;
737	usb_port_t	port;
738
739	hubpm = hubd->h_hubpm;
740
741	if (DEVI_IS_DETACHING(hubd->h_dip)) {
742
743		return (USB_SUCCESS);
744	}
745
746	/*
747	 * Don't go to lower power if haven't been at full power for enough
748	 * time to let hotplug thread kickoff.
749	 */
750	if (gethrtime() < (hubpm->hubp_time_at_full_power +
751	    hubpm->hubp_min_pm_threshold)) {
752
753		return (USB_FAILURE);
754	}
755
756	for (port = 1; (total_power == 0) &&
757	    (port <= hubd->h_nports); port++) {
758		total_power += hubpm->hubp_child_pwrstate[port];
759	}
760
761	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
762	    "hubd_can_suspend: %d", total_power);
763
764	return (total_power ? USB_FAILURE : USB_SUCCESS);
765}
766
767
768/*
769 * resume port depending on current device state
770 */
771static int
772hubd_resume_port(hubd_t *hubd, usb_port_t port)
773{
774	int		rval, retry;
775	usb_cr_t	completion_reason;
776	usb_cb_flags_t	cb_flags;
777	uint16_t	status;
778	uint16_t	change;
779	int		retval = USB_FAILURE;
780
781	mutex_enter(HUBD_MUTEX(hubd));
782
783	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
784	    "hubd_resume_port: port=%d state=0x%x (%s)", port,
785	    hubd->h_dev_state, usb_str_dev_state(hubd->h_dev_state));
786
787	switch (hubd->h_dev_state) {
788	case USB_DEV_HUB_CHILD_PWRLVL:
789		/*
790		 * This could be a bus ctl for a port other than the one
791		 * that has a remote wakeup condition. So check.
792		 */
793		if ((hubd->h_port_state[port] & PORT_STATUS_PSS) == 0) {
794			/* the port isn't suspended, so don't resume */
795			retval = USB_SUCCESS;
796
797			USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
798			    "hubd_resume_port: port=%d not suspended", port);
799
800			break;
801		}
802		/*
803		 * Device has initiated a wakeup.
804		 * Issue a ClearFeature(PortSuspend)
805		 */
806		mutex_exit(HUBD_MUTEX(hubd));
807		if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
808		    hubd->h_default_pipe,
809		    HUB_HANDLE_PORT_FEATURE_TYPE,
810		    USB_REQ_CLEAR_FEATURE,
811		    CFS_PORT_SUSPEND,
812		    port,
813		    0, NULL, 0,
814		    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
815			USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
816			    "ClearFeature(PortSuspend) fails "
817			    "rval=%d cr=%d cb=0x%x", rval,
818			    completion_reason, cb_flags);
819		}
820		mutex_enter(HUBD_MUTEX(hubd));
821
822		/* either way ack changes on the port */
823		(void) hubd_determine_port_status(hubd, port,
824		    &status, &change, NULL, PORT_CHANGE_PSSC);
825		retval = USB_SUCCESS;
826
827		break;
828	case USB_DEV_HUB_STATE_RECOVER:
829		/*
830		 * When hubd's connect event callback posts a connect
831		 * event to its child, it results in this busctl call
832		 * which is valid
833		 */
834		/* FALLTHRU */
835	case USB_DEV_ONLINE:
836		if (((hubd->h_port_state[port] & PORT_STATUS_CCS) == 0) ||
837		    ((hubd->h_port_state[port] & PORT_STATUS_PSS) == 0)) {
838			/*
839			 * the port isn't suspended, or connected
840			 * so don't resume
841			 */
842			retval = USB_SUCCESS;
843
844			USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
845			    "hubd_resume_port: port=%d not suspended", port);
846
847			break;
848		}
849		/*
850		 * prevent kicking off the hotplug thread
851		 */
852		hubd->h_hotplug_thread++;
853		hubd_stop_polling(hubd);
854
855		/* Now ClearFeature(PortSuspend) */
856		for (retry = 0; retry < HUBD_SUS_RES_RETRY; retry++) {
857			mutex_exit(HUBD_MUTEX(hubd));
858			rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
859			    hubd->h_default_pipe,
860			    HUB_HANDLE_PORT_FEATURE_TYPE,
861			    USB_REQ_CLEAR_FEATURE,
862			    CFS_PORT_SUSPEND,
863			    port,
864			    0, NULL, 0,
865			    &completion_reason, &cb_flags, 0);
866			mutex_enter(HUBD_MUTEX(hubd));
867			if (rval != USB_SUCCESS) {
868				USB_DPRINTF_L2(DPRINT_MASK_PM,
869				    hubd->h_log_handle,
870				    "ClearFeature(PortSuspend) fails"
871				    "rval=%d cr=%d cb=0x%x", rval,
872				    completion_reason, cb_flags);
873			} else {
874				/*
875				 * As per spec section 11.9 and 7.1.7.7
876				 * hub need to provide at least 20ms of
877				 * resume signalling, and s/w provide 10ms of
878				 * recovery time before accessing the port.
879				 */
880				mutex_exit(HUBD_MUTEX(hubd));
881				delay(drv_usectohz(40000));
882				mutex_enter(HUBD_MUTEX(hubd));
883				(void) hubd_determine_port_status(hubd, port,
884				    &status, &change, NULL, PORT_CHANGE_PSSC);
885
886				if ((status & PORT_STATUS_PSS) == 0) {
887					/* the port did finally resume */
888					retval = USB_SUCCESS;
889
890					break;
891				}
892			}
893		}
894
895		/* allow hotplug thread again */
896		hubd->h_hotplug_thread--;
897		hubd_start_polling(hubd, 0);
898
899		break;
900	case USB_DEV_DISCONNECTED:
901		/* Ignore - NO Operation */
902		retval = USB_SUCCESS;
903
904		break;
905	case USB_DEV_SUSPENDED:
906	case USB_DEV_PWRED_DOWN:
907	default:
908		USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
909		    "Improper state for port Resume");
910
911		break;
912	}
913	mutex_exit(HUBD_MUTEX(hubd));
914
915	return (retval);
916}
917
918
919/*
920 * suspend port depending on device state
921 */
922static int
923hubd_suspend_port(hubd_t *hubd, usb_port_t port)
924{
925	int		rval, retry;
926	int		retval = USB_FAILURE;
927	usb_cr_t	completion_reason;
928	usb_cb_flags_t	cb_flags;
929	uint16_t	status;
930	uint16_t	change;
931
932	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
933	    "hubd_suspend_port: port=%d", port);
934
935	mutex_enter(HUBD_MUTEX(hubd));
936
937	switch (hubd->h_dev_state) {
938	case USB_DEV_HUB_STATE_RECOVER:
939		/*
940		 * When hubd's connect event callback posts a connect
941		 * event to its child, it results in this busctl call
942		 * which is valid
943		 */
944		/* FALLTHRU */
945	case USB_DEV_HUB_CHILD_PWRLVL:
946		/*
947		 * When one child is resuming, the other could timeout
948		 * and go to low power mode, which is valid
949		 */
950		/* FALLTHRU */
951	case USB_DEV_ONLINE:
952		hubd->h_hotplug_thread++;
953		hubd_stop_polling(hubd);
954
955		/*
956		 * Some devices start an unprovoked resume.  According to spec,
957		 * normal resume time for port is 10ms.  Wait for double that
958		 * time, then check to be sure port is really suspended.
959		 */
960		for (retry = 0; retry < HUBD_SUS_RES_RETRY; retry++) {
961			/* Now SetFeature(PortSuspend) */
962			mutex_exit(HUBD_MUTEX(hubd));
963			if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
964			    hubd->h_default_pipe,
965			    HUB_HANDLE_PORT_FEATURE_TYPE,
966			    USB_REQ_SET_FEATURE,
967			    CFS_PORT_SUSPEND,
968			    port,
969			    0, NULL, 0,
970			    &completion_reason, &cb_flags, 0)) !=
971			    USB_SUCCESS) {
972				USB_DPRINTF_L2(DPRINT_MASK_PM,
973				    hubd->h_log_handle,
974				    "SetFeature(PortSuspend) fails"
975				    "rval=%d cr=%d cb=0x%x",
976				    rval, completion_reason, cb_flags);
977			}
978
979			/*
980			 * some devices start an unprovoked resume
981			 * wait and check port status after some time
982			 */
983			delay(drv_usectohz(20000));
984
985			/* either ways ack changes on the port */
986			mutex_enter(HUBD_MUTEX(hubd));
987			(void) hubd_determine_port_status(hubd, port,
988			    &status, &change, NULL, PORT_CHANGE_PSSC);
989			if (status & PORT_STATUS_PSS) {
990				/* the port is indeed suspended */
991				retval = USB_SUCCESS;
992
993				break;
994			} else {
995				USB_DPRINTF_L0(DPRINT_MASK_PM,
996				    hubd->h_log_handle,
997				    "hubdi: port%d failed to be suspended!",
998				    port);
999			}
1000		}
1001
1002		hubd->h_hotplug_thread--;
1003		hubd_start_polling(hubd, 0);
1004
1005		break;
1006
1007	case USB_DEV_DISCONNECTED:
1008		/* Ignore - No Operation */
1009		retval = USB_SUCCESS;
1010
1011		break;
1012
1013	case USB_DEV_SUSPENDED:
1014	case USB_DEV_PWRED_DOWN:
1015	default:
1016		USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
1017		    "Improper state for port Suspend");
1018
1019		break;
1020	}
1021	mutex_exit(HUBD_MUTEX(hubd));
1022
1023	return (retval);
1024}
1025
1026
1027/*
1028 * child post attach/detach notifications
1029 */
1030static void
1031hubd_post_attach(hubd_t *hubd, usb_port_t port, struct attachspec *as)
1032{
1033	dev_info_t	*dip;
1034
1035	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
1036	    "hubd_post_attach: port=%d result=%d",
1037	    port, as->result);
1038
1039	if (as->result == DDI_SUCCESS) {
1040		/*
1041		 * Check if the child created wants to be power managed.
1042		 * If yes, the childs power level gets automatically tracked
1043		 * by DDI_CTLOPS_POWER busctl.
1044		 * If no, we set power of the new child by default
1045		 * to USB_DEV_OS_FULL_PWR. Because we should never suspend.
1046		 */
1047		mutex_enter(HUBD_MUTEX(hubd));
1048		dip = hubd->h_children_dips[port];
1049		mutex_exit(HUBD_MUTEX(hubd));
1050		if (DEVI(dip)->devi_pm_info == NULL) {
1051			hubd_set_child_pwrlvl(hubd, port, USB_DEV_OS_FULL_PWR);
1052		}
1053	}
1054}
1055
1056
1057static void
1058hubd_post_detach(hubd_t *hubd, usb_port_t port, struct detachspec *ds)
1059{
1060	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
1061	    "hubd_post_detach: port=%d result=%d", port, ds->result);
1062
1063	/*
1064	 * if the device is successfully detached and is the
1065	 * last device to detach, mark component as idle
1066	 */
1067	mutex_enter(HUBD_MUTEX(hubd));
1068	if (ds->result == DDI_SUCCESS) {
1069		usba_device_t	*usba_device = hubd->h_usba_devices[port];
1070		dev_info_t	*pdip = hubd->h_dip;
1071		mutex_exit(HUBD_MUTEX(hubd));
1072
1073		usba_hubdi_incr_power_budget(pdip, usba_device);
1074
1075		/*
1076		 * We set power of the detached child
1077		 * to 0, so that we can suspend if all
1078		 * our children are gone
1079		 */
1080		hubd_set_child_pwrlvl(hubd, port, USB_DEV_OS_PWR_OFF);
1081
1082		/* check for leaks on detaching */
1083		if ((usba_device) && (ds->cmd == DDI_DETACH)) {
1084			usba_check_for_leaks(usba_device);
1085		}
1086	} else {
1087		mutex_exit(HUBD_MUTEX(hubd));
1088	}
1089}
1090
1091
1092/*
1093 * hubd_post_power
1094 *	After the child's power entry point has been called
1095 *	we record its power level in our local struct.
1096 *	If the device has powered off, we suspend port
1097 */
1098static int
1099hubd_post_power(hubd_t *hubd, usb_port_t port, pm_bp_child_pwrchg_t *bpc,
1100    int result)
1101{
1102	int	retval = USB_SUCCESS;
1103
1104	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1105	    "hubd_post_power: port=%d", port);
1106
1107	if (result == DDI_SUCCESS) {
1108
1109		/* record this power in our local struct */
1110		hubd_set_child_pwrlvl(hubd, port, bpc->bpc_nlevel);
1111
1112		if (bpc->bpc_nlevel == USB_DEV_OS_PWR_OFF) {
1113
1114			/* now suspend the port */
1115			retval = hubd_suspend_port(hubd, port);
1116		} else if (bpc->bpc_nlevel == USB_DEV_OS_FULL_PWR) {
1117
1118			/* make sure the port is resumed */
1119			retval = hubd_resume_port(hubd, port);
1120		}
1121	} else {
1122
1123		/* record old power in our local struct */
1124		hubd_set_child_pwrlvl(hubd, port, bpc->bpc_olevel);
1125
1126		if (bpc->bpc_olevel == USB_DEV_OS_PWR_OFF) {
1127
1128			/*
1129			 * As this device failed to transition from
1130			 * power off state, suspend the port again
1131			 */
1132			retval = hubd_suspend_port(hubd, port);
1133		}
1134	}
1135
1136	return (retval);
1137}
1138
1139
1140/*
1141 * bus ctl notifications are handled here, the rest goes up to root hub/hcd
1142 */
1143static int
1144usba_hubdi_bus_ctl(dev_info_t *dip,
1145    dev_info_t	*rdip,
1146    ddi_ctl_enum_t	op,
1147    void		*arg,
1148    void		*result)
1149{
1150	usba_device_t *hub_usba_device = usba_get_usba_device(rdip);
1151	dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip;
1152	struct attachspec *as;
1153	struct detachspec *ds;
1154	hubd_t		*hubd;
1155	usb_port_t	port;
1156	int		circ, rval;
1157	int		retval = DDI_FAILURE;
1158
1159	hubd = hubd_get_soft_state(dip);
1160
1161	mutex_enter(HUBD_MUTEX(hubd));
1162
1163	/* flag that we are currently running bus_ctl */
1164	hubd->h_bus_ctls++;
1165	mutex_exit(HUBD_MUTEX(hubd));
1166
1167	USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1168	    "usba_hubdi_bus_ctl:\n\t"
1169	    "dip=0x%p, rdip=0x%p, op=0x%x, arg=0x%p",
1170	    (void *)dip, (void *)rdip, op, arg);
1171
1172	switch (op) {
1173	case DDI_CTLOPS_ATTACH:
1174		as = (struct attachspec *)arg;
1175		port = hubd_child_dip2port(hubd, rdip);
1176
1177		/* there is nothing to do at resume time */
1178		if (as->cmd == DDI_RESUME) {
1179			break;
1180		}
1181
1182		/* serialize access */
1183		ndi_devi_enter(hubd->h_dip, &circ);
1184
1185		switch (as->when) {
1186		case DDI_PRE:
1187			USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1188			    "DDI_PRE DDI_CTLOPS_ATTACH: dip=%p, port=%d",
1189			    (void *)rdip, port);
1190
1191			mutex_enter(HUBD_MUTEX(hubd));
1192			hubd->h_port_state[port] |= HUBD_CHILD_ATTACHING;
1193
1194			/* Go busy here.  Matching idle is DDI_POST case. */
1195			(void) hubd_pm_busy_component(hubd, dip, 0);
1196			mutex_exit(HUBD_MUTEX(hubd));
1197
1198			/*
1199			 * if we suspended the port previously
1200			 * because child went to low power state, and
1201			 * someone unloaded the driver, the port would
1202			 * still be suspended and needs to be resumed
1203			 */
1204			rval = hubd_resume_port(hubd, port);
1205			if (rval == USB_SUCCESS) {
1206				retval = DDI_SUCCESS;
1207			}
1208
1209			break;
1210		case DDI_POST:
1211			USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1212			    "DDI_POST DDI_CTLOPS_ATTACH: dip=%p, port=%d",
1213			    (void *)rdip, port);
1214
1215			mutex_enter(HUBD_MUTEX(hubd));
1216			hubd->h_port_state[port] &= ~HUBD_CHILD_ATTACHING;
1217			mutex_exit(HUBD_MUTEX(hubd));
1218
1219			hubd_post_attach(hubd, port, (struct attachspec *)arg);
1220			retval = DDI_SUCCESS;
1221			mutex_enter(HUBD_MUTEX(hubd));
1222
1223			/* Matching idle call for DDI_PRE busy call. */
1224			(void) hubd_pm_idle_component(hubd, dip, 0);
1225			mutex_exit(HUBD_MUTEX(hubd));
1226		}
1227		ndi_devi_exit(hubd->h_dip, circ);
1228
1229		break;
1230	case DDI_CTLOPS_DETACH:
1231		ds = (struct detachspec *)arg;
1232		port = hubd_child_dip2port(hubd, rdip);
1233
1234		/* there is nothing to do at suspend time */
1235		if (ds->cmd == DDI_SUSPEND) {
1236			break;
1237		}
1238
1239		/* serialize access */
1240		ndi_devi_enter(hubd->h_dip, &circ);
1241
1242		switch (ds->when) {
1243		case DDI_PRE:
1244			USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1245			    "DDI_PRE DDI_CTLOPS_DETACH: dip=%p port=%d",
1246			    (void *)rdip, port);
1247
1248			mutex_enter(HUBD_MUTEX(hubd));
1249			hubd->h_port_state[port] |= HUBD_CHILD_DETACHING;
1250
1251			/* Go busy here.  Matching idle is DDI_POST case. */
1252			(void) hubd_pm_busy_component(hubd, dip, 0);
1253
1254			mutex_exit(HUBD_MUTEX(hubd));
1255			retval = DDI_SUCCESS;
1256
1257			break;
1258		case DDI_POST:
1259			USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1260			    "DDI_POST DDI_CTLOPS_DETACH: dip=%p port=%d",
1261			    (void *)rdip, port);
1262
1263			mutex_enter(HUBD_MUTEX(hubd));
1264			hubd->h_port_state[port] &= ~HUBD_CHILD_DETACHING;
1265			mutex_exit(HUBD_MUTEX(hubd));
1266
1267			/* Matching idle call for DDI_PRE busy call. */
1268			hubd_post_detach(hubd, port, (struct detachspec *)arg);
1269			retval = DDI_SUCCESS;
1270			mutex_enter(HUBD_MUTEX(hubd));
1271			(void) hubd_pm_idle_component(hubd, dip, 0);
1272			mutex_exit(HUBD_MUTEX(hubd));
1273
1274			break;
1275		}
1276		ndi_devi_exit(hubd->h_dip, circ);
1277
1278		break;
1279	default:
1280		retval = usba_bus_ctl(root_hub_dip, rdip, op, arg, result);
1281	}
1282
1283	/* decrement bus_ctls count */
1284	mutex_enter(HUBD_MUTEX(hubd));
1285	hubd->h_bus_ctls--;
1286	ASSERT(hubd->h_bus_ctls >= 0);
1287	mutex_exit(HUBD_MUTEX(hubd));
1288
1289	return (retval);
1290}
1291
1292/*
1293 * hubd_config_one:
1294 *	enumerate one child according to 'port'
1295 */
1296
1297static boolean_t
1298hubd_config_one(hubd_t *hubd, int port)
1299{
1300	dev_info_t	*hdip = hubd->h_dip;
1301	dev_info_t	*rh_dip = hubd->h_usba_device->usb_root_hub_dip;
1302	boolean_t	online_child = B_FALSE, found = B_FALSE;
1303	int		prh_circ, rh_circ, circ;
1304
1305	USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
1306	    "hubd_config_one:  started, hubd_reset_port = 0x%x", port);
1307
1308	ndi_hold_devi(hdip); /* so we don't race with detach */
1309
1310	/*
1311	 * this ensures one config activity per system at a time.
1312	 * we enter the parent PCI node to have this serialization.
1313	 * this also excludes ioctls and deathrow thread
1314	 */
1315	ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ);
1316	ndi_devi_enter(rh_dip, &rh_circ);
1317
1318	/* exclude other threads */
1319	ndi_devi_enter(hdip, &circ);
1320	mutex_enter(HUBD_MUTEX(hubd));
1321
1322	hubd_pm_busy_component(hubd, hubd->h_dip, 0);
1323
1324	if (!hubd->h_children_dips[port]) {
1325		uint16_t	status, change;
1326
1327		(void) hubd_determine_port_status(hubd, port,
1328		    &status, &change, NULL, HUBD_ACK_ALL_CHANGES);
1329
1330		if (status & PORT_STATUS_CCS) {
1331			online_child |=	(hubd_handle_port_connect(hubd,
1332			    port) == USB_SUCCESS);
1333			found = online_child;
1334		}
1335	} else {
1336		found = B_TRUE;
1337	}
1338
1339	mutex_exit(HUBD_MUTEX(hubd));
1340
1341	ndi_devi_exit(hdip, circ);
1342	ndi_devi_exit(rh_dip, rh_circ);
1343	ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ);
1344
1345	if (online_child) {
1346		USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
1347		    "hubd_config_one: onlining child");
1348
1349		(void) ndi_devi_online(hubd->h_dip, 0);
1350	}
1351
1352	mutex_enter(HUBD_MUTEX(hubd));
1353
1354	(void) hubd_pm_idle_component(hubd, hubd->h_dip, 0);
1355
1356	USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
1357	    "hubd_config_one: exit");
1358
1359	mutex_exit(HUBD_MUTEX(hubd));
1360
1361	ndi_rele_devi(hdip);
1362
1363	return (found);
1364}
1365
1366/*
1367 * bus enumeration entry points
1368 */
1369static int
1370hubd_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
1371    void *arg, dev_info_t **child)
1372{
1373	hubd_t	*hubd = hubd_get_soft_state(dip);
1374	int	rval, circ;
1375	long port;
1376
1377	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1378	    "hubd_bus_config: op=%d", op);
1379
1380	if (hubdi_bus_config_debug) {
1381		flag |= NDI_DEVI_DEBUG;
1382	}
1383
1384	if (op == BUS_CONFIG_ONE) {
1385		boolean_t found;
1386		char cname[80];
1387		char *name, *addr;
1388
1389		USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
1390		    "hubd_bus_config: op=%d (BUS_CONFIG_ONE)", op);
1391
1392		(void) snprintf(cname, 80, "%s", (char *)arg);
1393		/* split name into "name@addr" parts */
1394		i_ddi_parse_name(cname, &name, &addr, NULL);
1395		if (addr && *addr) {
1396			(void) ddi_strtol(addr, NULL, 16, &port);
1397		} else {
1398			return (NDI_FAILURE);
1399		}
1400
1401		found = hubd_config_one(hubd, port);
1402
1403		if (found == 0) {
1404			return (NDI_FAILURE);
1405		}
1406
1407	}
1408	ndi_devi_enter(hubd->h_dip, &circ);
1409	rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0);
1410	ndi_devi_exit(hubd->h_dip, circ);
1411
1412	return (rval);
1413}
1414
1415
1416static int
1417hubd_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
1418    void *arg)
1419{
1420	hubd_t		*hubd = hubd_get_soft_state(dip);
1421	dev_info_t	*cdip;
1422	usb_port_t	port;
1423	int		circ;
1424	int		rval;
1425
1426	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1427	    "hubd_bus_unconfig: op=%d", op);
1428
1429	if (hubdi_bus_config_debug) {
1430		flag |= NDI_DEVI_DEBUG;
1431	}
1432
1433	if ((op == BUS_UNCONFIG_ALL) && (flag & NDI_AUTODETACH) == 0) {
1434		flag |= NDI_DEVI_REMOVE;
1435	}
1436
1437	/* serialize access */
1438	ndi_devi_enter(dip, &circ);
1439
1440	rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
1441
1442	/* logically zap children's list */
1443	mutex_enter(HUBD_MUTEX(hubd));
1444	for (port = 1; port <= hubd->h_nports; port++) {
1445		hubd->h_port_state[port] |= HUBD_CHILD_ZAP;
1446	}
1447	mutex_exit(HUBD_MUTEX(hubd));
1448
1449	/* fill in what's left */
1450	for (cdip = ddi_get_child(dip); cdip;
1451	    cdip = ddi_get_next_sibling(cdip)) {
1452		usba_device_t *usba_device = usba_get_usba_device(cdip);
1453
1454		if (usba_device == NULL) {
1455
1456			continue;
1457		}
1458		mutex_enter(HUBD_MUTEX(hubd));
1459		port = usba_device->usb_port;
1460		hubd->h_children_dips[port] = cdip;
1461		hubd->h_port_state[port] &= ~HUBD_CHILD_ZAP;
1462		mutex_exit(HUBD_MUTEX(hubd));
1463	}
1464
1465	/* physically zap the children we didn't find */
1466	mutex_enter(HUBD_MUTEX(hubd));
1467	for (port = 1; port <= hubd->h_nports; port++) {
1468		if (hubd->h_port_state[port] &	HUBD_CHILD_ZAP) {
1469			/* zap the dip and usba_device structure as well */
1470			hubd_free_usba_device(hubd, hubd->h_usba_devices[port]);
1471			hubd->h_children_dips[port] = NULL;
1472			hubd->h_port_state[port] &= ~HUBD_CHILD_ZAP;
1473		}
1474	}
1475	mutex_exit(HUBD_MUTEX(hubd));
1476
1477	ndi_devi_exit(dip, circ);
1478
1479	USB_DPRINTF_L4(DPRINT_MASK_PM, hubd->h_log_handle,
1480	    "hubd_bus_unconfig: rval=%d", rval);
1481
1482	return (rval);
1483}
1484
1485
1486/* bus_power entry point */
1487static int
1488hubd_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op,
1489    void *arg, void *result)
1490{
1491	hubd_t		*hubd;
1492	int		rval, pwrup_res;
1493	usb_port_t	port;
1494	int		retval = DDI_FAILURE;
1495	pm_bp_child_pwrchg_t	*bpc;
1496	pm_bp_nexus_pwrup_t	bpn;
1497
1498	hubd = hubd_get_soft_state(dip);
1499
1500	USB_DPRINTF_L4(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1501	    "hubd_bus_power: dip=%p, impl_arg=%p, power_op=%d, arg=%p, "
1502	    "result=%d\n", (void *)dip, impl_arg, op, arg, *(int *)result);
1503
1504	bpc = (pm_bp_child_pwrchg_t *)arg;
1505
1506	mutex_enter(HUBD_MUTEX(hubd));
1507	hubd->h_bus_pwr++;
1508	mutex_exit(HUBD_MUTEX(hubd));
1509
1510	switch (op) {
1511	case BUS_POWER_PRE_NOTIFICATION:
1512		port = hubd_child_dip2port(hubd, bpc->bpc_dip);
1513		USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1514		    "hubd_bus_power: BUS_POWER_PRE_NOTIFICATION, port=%d",
1515		    port);
1516
1517		/* go to full power if we are powered down */
1518		mutex_enter(HUBD_MUTEX(hubd));
1519
1520		/*
1521		 * If this case completes normally, idle will be in
1522		 * hubd_bus_power / BUS_POWER_POST_NOTIFICATION
1523		 */
1524		hubd_pm_busy_component(hubd, dip, 0);
1525
1526		/*
1527		 * raise power only if we have created the components
1528		 * and are currently in low power
1529		 */
1530		if ((hubd->h_dev_state == USB_DEV_PWRED_DOWN) &&
1531		    hubd->h_hubpm->hubp_wakeup_enabled) {
1532			mutex_exit(HUBD_MUTEX(hubd));
1533
1534			bpn.bpn_comp = 0;
1535			bpn.bpn_dip = dip;
1536			bpn.bpn_level = USB_DEV_OS_FULL_PWR;
1537			bpn.bpn_private = bpc->bpc_private;
1538
1539			rval = pm_busop_bus_power(dip, impl_arg,
1540			    BUS_POWER_NEXUS_PWRUP, (void *)&bpn,
1541			    (void *)&pwrup_res);
1542
1543			if (rval != DDI_SUCCESS || pwrup_res != DDI_SUCCESS) {
1544				mutex_enter(HUBD_MUTEX(hubd));
1545				hubd_pm_idle_component(hubd, dip, 0);
1546				mutex_exit(HUBD_MUTEX(hubd));
1547
1548				break;
1549			}
1550			mutex_enter(HUBD_MUTEX(hubd));
1551		}
1552
1553		/* indicate that child is changing power level */
1554		hubd->h_port_state[port] |= HUBD_CHILD_PWRLVL_CHNG;
1555		mutex_exit(HUBD_MUTEX(hubd));
1556
1557		if ((bpc->bpc_olevel == 0) &&
1558		    (bpc->bpc_nlevel > bpc->bpc_olevel)) {
1559			/*
1560			 * this child is transitioning from power off
1561			 * to power on state - resume port
1562			 */
1563			rval = hubd_resume_port(hubd, port);
1564			if (rval == USB_SUCCESS) {
1565				retval = DDI_SUCCESS;
1566			} else {
1567				/* reset this flag on failure */
1568				mutex_enter(HUBD_MUTEX(hubd));
1569				hubd->h_port_state[port] &=
1570				    ~HUBD_CHILD_PWRLVL_CHNG;
1571				hubd_pm_idle_component(hubd, dip, 0);
1572				mutex_exit(HUBD_MUTEX(hubd));
1573			}
1574		} else {
1575			retval = DDI_SUCCESS;
1576		}
1577
1578		break;
1579	case BUS_POWER_POST_NOTIFICATION:
1580		port = hubd_child_dip2port(hubd, bpc->bpc_dip);
1581		USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1582		    "hubd_bus_power: BUS_POWER_POST_NOTIFICATION, port=%d",
1583		    port);
1584
1585		mutex_enter(HUBD_MUTEX(hubd));
1586		hubd->h_port_state[port] &= ~HUBD_CHILD_PWRLVL_CHNG;
1587		mutex_exit(HUBD_MUTEX(hubd));
1588
1589		/* record child's pwr and suspend port if required */
1590		rval = hubd_post_power(hubd, port, bpc, *(int *)result);
1591		if (rval == USB_SUCCESS) {
1592
1593			retval = DDI_SUCCESS;
1594		}
1595
1596		mutex_enter(HUBD_MUTEX(hubd));
1597
1598		/*
1599		 * Matching idle for the busy in
1600		 * hubd_bus_power / BUS_POWER_PRE_NOTIFICATION
1601		 */
1602		hubd_pm_idle_component(hubd, dip, 0);
1603
1604		mutex_exit(HUBD_MUTEX(hubd));
1605
1606		break;
1607	default:
1608		retval = pm_busop_bus_power(dip, impl_arg, op, arg, result);
1609
1610		break;
1611	}
1612
1613	mutex_enter(HUBD_MUTEX(hubd));
1614	hubd->h_bus_pwr--;
1615	mutex_exit(HUBD_MUTEX(hubd));
1616
1617	return (retval);
1618}
1619
1620
1621/*
1622 * functions to handle power transition for OS levels 0 -> 3
1623 */
1624static int
1625hubd_pwrlvl0(hubd_t *hubd)
1626{
1627	hub_power_t	*hubpm;
1628
1629	/* We can't power down if hotplug thread is running */
1630	if (hubd->h_hotplug_thread || hubd->h_hubpm->hubp_busy_pm ||
1631	    (hubd_can_suspend(hubd) == USB_FAILURE)) {
1632
1633		return (USB_FAILURE);
1634	}
1635
1636	switch (hubd->h_dev_state) {
1637	case USB_DEV_ONLINE:
1638		hubpm = hubd->h_hubpm;
1639
1640		/*
1641		 * To avoid race with bus_power pre_notify on check over
1642		 * dev_state, we need to correctly set the dev state
1643		 * before the mutex is dropped in stop polling.
1644		 */
1645		hubd->h_dev_state = USB_DEV_PWRED_DOWN;
1646		hubpm->hubp_current_power = USB_DEV_OS_PWR_OFF;
1647
1648		/*
1649		 * if we are the root hub, do not stop polling
1650		 * otherwise, we will never see a resume
1651		 */
1652		if (usba_is_root_hub(hubd->h_dip)) {
1653			/* place holder to implement Global Suspend */
1654			USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
1655			    "Global Suspend: Not Yet Implemented");
1656		} else {
1657			hubd_stop_polling(hubd);
1658		}
1659
1660		/* Issue USB D3 command to the device here */
1661		(void) usb_set_device_pwrlvl3(hubd->h_dip);
1662
1663		break;
1664	case USB_DEV_DISCONNECTED:
1665	case USB_DEV_SUSPENDED:
1666	case USB_DEV_PWRED_DOWN:
1667	default:
1668
1669		break;
1670	}
1671
1672	return (USB_SUCCESS);
1673}
1674
1675
1676/* ARGSUSED */
1677static int
1678hubd_pwrlvl1(hubd_t *hubd)
1679{
1680	/* Issue USB D2 command to the device here */
1681	(void) usb_set_device_pwrlvl2(hubd->h_dip);
1682
1683	return (USB_FAILURE);
1684}
1685
1686
1687/* ARGSUSED */
1688static int
1689hubd_pwrlvl2(hubd_t *hubd)
1690{
1691	/* Issue USB D1 command to the device here */
1692	(void) usb_set_device_pwrlvl1(hubd->h_dip);
1693
1694	return (USB_FAILURE);
1695}
1696
1697
1698static int
1699hubd_pwrlvl3(hubd_t *hubd)
1700{
1701	hub_power_t	*hubpm;
1702	int		rval;
1703
1704	USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle, "hubd_pwrlvl3");
1705
1706	hubpm = hubd->h_hubpm;
1707	switch (hubd->h_dev_state) {
1708	case USB_DEV_PWRED_DOWN:
1709		ASSERT(hubpm->hubp_current_power == USB_DEV_OS_PWR_OFF);
1710		if (usba_is_root_hub(hubd->h_dip)) {
1711			/* implement global resume here */
1712			USB_DPRINTF_L2(DPRINT_MASK_PM,
1713			    hubd->h_log_handle,
1714			    "Global Resume: Not Yet Implemented");
1715		}
1716		/* Issue USB D0 command to the device here */
1717		rval = usb_set_device_pwrlvl0(hubd->h_dip);
1718		ASSERT(rval == USB_SUCCESS);
1719		hubd->h_dev_state = USB_DEV_ONLINE;
1720		hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR;
1721		hubpm->hubp_time_at_full_power = gethrtime();
1722		hubd_start_polling(hubd, 0);
1723
1724		/* FALLTHRU */
1725	case USB_DEV_ONLINE:
1726		/* we are already in full power */
1727
1728		/* FALLTHRU */
1729	case USB_DEV_DISCONNECTED:
1730	case USB_DEV_SUSPENDED:
1731		/*
1732		 * PM framework tries to put you in full power
1733		 * during system shutdown. If we are disconnected
1734		 * return success. Also, we should not change state
1735		 * when we are disconnected or suspended or about to
1736		 * transition to that state
1737		 */
1738
1739		return (USB_SUCCESS);
1740	default:
1741		USB_DPRINTF_L2(DPRINT_MASK_PM, hubd->h_log_handle,
1742		    "hubd_pwrlvl3: Illegal dev_state=%d", hubd->h_dev_state);
1743
1744		return (USB_FAILURE);
1745	}
1746}
1747
1748
1749/* power entry point */
1750/* ARGSUSED */
1751int
1752usba_hubdi_power(dev_info_t *dip, int comp, int level)
1753{
1754	hubd_t		*hubd;
1755	hub_power_t	*hubpm;
1756	int		retval;
1757	int		circ;
1758
1759	hubd = hubd_get_soft_state(dip);
1760	USB_DPRINTF_L3(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1761	    "usba_hubdi_power: level=%d", level);
1762
1763	ndi_devi_enter(dip, &circ);
1764
1765	mutex_enter(HUBD_MUTEX(hubd));
1766	hubpm = hubd->h_hubpm;
1767
1768	/* check if we are transitioning to a legal power level */
1769	if (USB_DEV_PWRSTATE_OK(hubpm->hubp_pwr_states, level)) {
1770		USB_DPRINTF_L2(DPRINT_MASK_HUBDI, hubd->h_log_handle,
1771		    "usba_hubdi_power: illegal power level=%d "
1772		    "hubp_pwr_states=0x%x", level, hubpm->hubp_pwr_states);
1773		mutex_exit(HUBD_MUTEX(hubd));
1774
1775		ndi_devi_exit(dip, circ);
1776
1777		return (DDI_FAILURE);
1778	}
1779
1780	switch (level) {
1781	case USB_DEV_OS_PWR_OFF:
1782		retval = hubd_pwrlvl0(hubd);
1783
1784		break;
1785	case USB_DEV_OS_PWR_1:
1786		retval = hubd_pwrlvl1(hubd);
1787
1788		break;
1789	case USB_DEV_OS_PWR_2:
1790		retval = hubd_pwrlvl2(hubd);
1791
1792		break;
1793	case USB_DEV_OS_FULL_PWR:
1794		retval = hubd_pwrlvl3(hubd);
1795
1796		break;
1797	default:
1798		retval = USB_FAILURE;
1799
1800		break;
1801	}
1802	mutex_exit(HUBD_MUTEX(hubd));
1803
1804	ndi_devi_exit(dip, circ);
1805
1806	return ((retval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
1807}
1808
1809
1810/* power entry point for the root hub */
1811int
1812usba_hubdi_root_hub_power(dev_info_t *dip, int comp, int level)
1813{
1814	return (usba_hubdi_power(dip, comp, level));
1815}
1816
1817
1818/*
1819 * standard driver entry points support code
1820 */
1821int
1822usba_hubdi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1823{
1824	int			instance = ddi_get_instance(dip);
1825	hubd_t			*hubd = NULL;
1826	int			i, rval;
1827	int			minor;
1828	uint8_t			ports_count;
1829	char			*log_name = NULL;
1830	const char		*root_hub_drvname;
1831	usb_ep_data_t		*ep_data;
1832	usba_device_t		*child_ud = NULL;
1833	usb_dev_descr_t		*usb_dev_descr;
1834	usb_port_status_t	parent_port_status, child_port_status;
1835
1836	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubdi_log_handle,
1837	    "hubd_attach instance %d, cmd=0x%x", instance, cmd);
1838
1839	switch (cmd) {
1840	case DDI_ATTACH:
1841
1842		break;
1843	case DDI_RESUME:
1844		hubd_cpr_resume(dip);
1845
1846		return (DDI_SUCCESS);
1847	default:
1848		return (DDI_FAILURE);
1849	}
1850
1851	/*
1852	 * Allocate softc information.
1853	 */
1854	if (usba_is_root_hub(dip)) {
1855		/* soft state has already been allocated */
1856		hubd = hubd_get_soft_state(dip);
1857		minor = HUBD_IS_ROOT_HUB;
1858
1859		/* generate readable labels for different root hubs */
1860		root_hub_drvname = ddi_driver_name(dip);
1861		if (strcmp(root_hub_drvname, "xhci") == 0) {
1862			log_name = "xusb";
1863		} else if (strcmp(root_hub_drvname, "ehci") == 0) {
1864			log_name = "eusb";
1865		} else if (strcmp(root_hub_drvname, "uhci") == 0) {
1866			log_name = "uusb";
1867		} else {
1868			/* std. for ohci */
1869			log_name = "usb";
1870		}
1871	} else {
1872		rval = ddi_soft_state_zalloc(hubd_statep, instance);
1873		minor = 0;
1874
1875		if (rval != DDI_SUCCESS) {
1876			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle,
1877			    "cannot allocate soft state (%d)", instance);
1878			goto fail;
1879		}
1880
1881		hubd = hubd_get_soft_state(dip);
1882		if (hubd == NULL) {
1883			goto fail;
1884		}
1885	}
1886
1887	hubd->h_log_handle = usb_alloc_log_hdl(dip, log_name, &hubd_errlevel,
1888	    &hubd_errmask, &hubd_instance_debug, 0);
1889
1890	hubd->h_usba_device	= child_ud = usba_get_usba_device(dip);
1891	hubd->h_dip		= dip;
1892	hubd->h_instance	= instance;
1893
1894	mutex_enter(&child_ud->usb_mutex);
1895	child_port_status = child_ud->usb_port_status;
1896	usb_dev_descr = child_ud->usb_dev_descr;
1897	parent_port_status = (child_ud->usb_hs_hub_usba_dev) ?
1898	    child_ud->usb_hs_hub_usba_dev->usb_port_status : 0;
1899	mutex_exit(&child_ud->usb_mutex);
1900
1901	if ((child_port_status == USBA_FULL_SPEED_DEV) &&
1902	    (parent_port_status >= USBA_HIGH_SPEED_DEV) &&
1903	    (usb_dev_descr->bcdUSB == 0x100)) {
1904		USB_DPRINTF_L0(DPRINT_MASK_ATTA, hubd->h_log_handle,
1905		    "Use of a USB1.0 hub behind a higher speed port may "
1906		    "cause unexpected failures");
1907	}
1908
1909	hubd->h_pipe_policy.pp_max_async_reqs = 1;
1910
1911	/* register with USBA as client driver */
1912	if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
1913		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
1914		    "client attach failed");
1915
1916		goto fail;
1917	}
1918
1919	if (usb_get_dev_data(dip, &hubd->h_dev_data,
1920	    USB_PARSE_LVL_IF, 0) != USB_SUCCESS) {
1921		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
1922		    "cannot get dev_data");
1923
1924		goto fail;
1925	}
1926
1927	if ((ep_data = usb_lookup_ep_data(dip, hubd->h_dev_data,
1928	    hubd->h_dev_data->dev_curr_if, 0, 0,
1929	    (uint_t)USB_EP_ATTR_INTR, (uint_t)USB_EP_DIR_IN)) == NULL) {
1930		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
1931		    "no interrupt IN endpoint found");
1932
1933		goto fail;
1934	}
1935
1936	if (usb_ep_xdescr_fill(USB_EP_XDESCR_CURRENT_VERSION, dip, ep_data,
1937	    &hubd->h_ep1_xdescr) != USB_SUCCESS) {
1938		goto fail;
1939	}
1940
1941	hubd->h_default_pipe = hubd->h_dev_data->dev_default_ph;
1942
1943	mutex_init(HUBD_MUTEX(hubd), NULL, MUTEX_DRIVER,
1944	    hubd->h_dev_data->dev_iblock_cookie);
1945	cv_init(&hubd->h_cv_reset_port, NULL, CV_DRIVER, NULL);
1946	cv_init(&hubd->h_cv_hotplug_dev, NULL, CV_DRIVER, NULL);
1947
1948	hubd->h_init_state |= HUBD_LOCKS_DONE;
1949
1950	usb_free_descr_tree(dip, hubd->h_dev_data);
1951
1952	/*
1953	 * register this hub instance with usba
1954	 */
1955	rval = usba_hubdi_register(dip, 0);
1956	if (rval != USB_SUCCESS) {
1957		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
1958		    "usba_hubdi_register failed");
1959		goto fail;
1960	}
1961
1962	mutex_enter(HUBD_MUTEX(hubd));
1963	hubd->h_init_state |= HUBD_HUBDI_REGISTERED;
1964	hubd->h_dev_state = USB_DEV_ONLINE;
1965	mutex_exit(HUBD_MUTEX(hubd));
1966
1967	/* now create components to power manage this device */
1968	hubd_create_pm_components(dip, hubd);
1969
1970	/*
1971	 * Event handling: definition and registration
1972	 *
1973	 * first the  definition:
1974	 * get event handle
1975	 */
1976	(void) ndi_event_alloc_hdl(dip, 0, &hubd->h_ndi_event_hdl, NDI_SLEEP);
1977
1978	/* bind event set to the handle */
1979	if (ndi_event_bind_set(hubd->h_ndi_event_hdl, &hubd_ndi_events,
1980	    NDI_SLEEP)) {
1981		USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle,
1982		    "binding event set failed");
1983
1984		goto fail;
1985	}
1986
1987	/* event registration */
1988	if (hubd_register_events(hubd) != USB_SUCCESS) {
1989		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
1990		    "hubd_register_events failed");
1991
1992		goto fail;
1993	}
1994
1995	mutex_enter(HUBD_MUTEX(hubd));
1996	hubd->h_init_state |= HUBD_EVENTS_REGISTERED;
1997
1998	if (hubd_get_hub_descriptor(hubd) != USB_SUCCESS) {
1999		mutex_exit(HUBD_MUTEX(hubd));
2000
2001		goto fail;
2002	}
2003
2004	/*
2005	 * Now that we have our descriptors, we need to give the host controller
2006	 * a chance to properly configure the device if needed (this is required
2007	 * for xHCI).
2008	 *
2009	 * Note, if anyone ever adds support for using the Multi TT mode for USB
2010	 * 2 High speed Hubs, the xhci driver will need to be updated and that
2011	 * will need to be done before this is called.
2012	 */
2013	if (hubd->h_usba_device->usb_hcdi_ops->usba_hcdi_hub_update != NULL &&
2014	    !usba_is_root_hub(dip)) {
2015		int ret;
2016		uint8_t chars;
2017		usba_device_t *ud = hubd->h_usba_device;
2018
2019		chars = (hubd->h_hub_chars & HUB_CHARS_TT_THINK_TIME) >>
2020		    HUB_CHARS_TT_SHIFT;
2021		ret = ud->usb_hcdi_ops->usba_hcdi_hub_update(ud,
2022		    hubd->h_nports, chars);
2023		if (ret != USB_SUCCESS) {
2024			mutex_exit(HUBD_MUTEX(hubd));
2025			goto fail;
2026		}
2027	}
2028
2029	if (hubd_set_hub_depth(hubd) != USB_SUCCESS) {
2030
2031		goto fail;
2032	}
2033
2034	if (ddi_prop_exists(DDI_DEV_T_ANY, dip,
2035	    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2036	    "hub-ignore-power-budget") == 1) {
2037		hubd->h_ignore_pwr_budget = B_TRUE;
2038	} else {
2039		hubd->h_ignore_pwr_budget = B_FALSE;
2040
2041		/* initialize hub power budget variables */
2042		if (hubd_init_power_budget(hubd) != USB_SUCCESS) {
2043			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2044			    "hubd_init_power_budget failed");
2045			mutex_exit(HUBD_MUTEX(hubd));
2046
2047			goto fail;
2048		}
2049	}
2050
2051	/* initialize and create children */
2052	if (hubd_check_ports(hubd) != USB_SUCCESS) {
2053		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2054		    "hubd_check_ports failed");
2055		mutex_exit(HUBD_MUTEX(hubd));
2056
2057		goto fail;
2058	}
2059
2060	/*
2061	 * create cfgadm nodes
2062	 */
2063	hubd->h_ancestry_str = (char *)kmem_zalloc(HUBD_APID_NAMELEN, KM_SLEEP);
2064	hubd_get_ancestry_str(hubd);
2065
2066	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2067	    "#ports=0x%x", hubd->h_nports);
2068
2069	for (i = 1; i <= hubd->h_nports; i++) {
2070		char ap_name[HUBD_APID_NAMELEN];
2071
2072		(void) snprintf(ap_name, HUBD_APID_NAMELEN, "%s%d",
2073		    hubd->h_ancestry_str, i);
2074		USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2075		    "ap_name=%s", ap_name);
2076
2077		if (ddi_create_minor_node(dip, ap_name, S_IFCHR, instance,
2078		    DDI_NT_USB_ATTACHMENT_POINT, 0) != DDI_SUCCESS) {
2079			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2080			    "cannot create attachment point node (%d)",
2081			    instance);
2082			mutex_exit(HUBD_MUTEX(hubd));
2083
2084			goto fail;
2085		}
2086	}
2087
2088	ports_count = hubd->h_nports;
2089	mutex_exit(HUBD_MUTEX(hubd));
2090
2091	/* create minor nodes */
2092	if (ddi_create_minor_node(dip, "hubd", S_IFCHR,
2093	    instance | minor, DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
2094
2095		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2096		    "cannot create devctl minor node (%d)", instance);
2097
2098		goto fail;
2099	}
2100
2101	mutex_enter(HUBD_MUTEX(hubd));
2102	hubd->h_init_state |= HUBD_MINOR_NODE_CREATED;
2103	mutex_exit(HUBD_MUTEX(hubd));
2104
2105	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
2106	    "usb-port-count", ports_count) != DDI_PROP_SUCCESS) {
2107		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2108		    "usb-port-count update failed");
2109	}
2110
2111	/*
2112	 * host controller driver has already reported this dev
2113	 * if we are the root hub
2114	 */
2115	if (!usba_is_root_hub(dip)) {
2116		ddi_report_dev(dip);
2117	}
2118
2119	/* enable deathrow thread */
2120	hubd->h_cleanup_enabled = B_TRUE;
2121	mutex_enter(HUBD_MUTEX(hubd));
2122	hubd_pm_idle_component(hubd, dip, 0);
2123	mutex_exit(HUBD_MUTEX(hubd));
2124
2125	return (DDI_SUCCESS);
2126
2127fail:
2128	{
2129		char *pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
2130
2131		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle,
2132		    "cannot attach %s", ddi_pathname(dip, pathname));
2133
2134		kmem_free(pathname, MAXPATHLEN);
2135	}
2136
2137	if (hubd != NULL) {
2138		mutex_enter(HUBD_MUTEX(hubd));
2139		hubd_pm_idle_component(hubd, dip, 0);
2140		mutex_exit(HUBD_MUTEX(hubd));
2141
2142		rval = hubd_cleanup(dip, hubd);
2143		if (rval != USB_SUCCESS) {
2144			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubdi_log_handle,
2145			    "failure to complete cleanup after attach failure");
2146		}
2147	}
2148
2149	return (DDI_FAILURE);
2150}
2151
2152
2153int
2154usba_hubdi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2155{
2156	hubd_t	*hubd = hubd_get_soft_state(dip);
2157	int	rval;
2158
2159	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2160	    "hubd_detach: cmd=0x%x", cmd);
2161
2162	switch (cmd) {
2163	case DDI_DETACH:
2164		rval = hubd_cleanup(dip, hubd);
2165
2166		return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
2167	case DDI_SUSPEND:
2168		rval = hubd_cpr_suspend(hubd);
2169
2170		return ((rval == USB_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
2171	default:
2172		return (DDI_FAILURE);
2173	}
2174}
2175
2176
2177/*
2178 * hubd_setdevaddr
2179 *	set the device addrs on this port
2180 */
2181static int
2182hubd_setdevaddr(hubd_t *hubd, usb_port_t port)
2183{
2184	int		rval = USB_FAILURE;
2185	usb_cr_t	completion_reason;
2186	usb_cb_flags_t	cb_flags;
2187	usb_pipe_handle_t ph;
2188	dev_info_t	*child_dip = NULL;
2189	uchar_t		address = 0;
2190	usba_device_t	*usba_device;
2191	int		retry = 0;
2192	long		time_delay;
2193
2194	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2195	    "hubd_setdevaddr: port=%d", port);
2196
2197	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
2198
2199	child_dip = hubd->h_children_dips[port];
2200	address = hubd->h_usba_devices[port]->usb_addr;
2201	usba_device = hubd->h_usba_devices[port];
2202
2203	/* close the default pipe with addr x */
2204	mutex_exit(HUBD_MUTEX(hubd));
2205	ph = usba_get_dflt_pipe_handle(child_dip);
2206	usb_pipe_close(child_dip, ph,
2207	    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
2208	mutex_enter(HUBD_MUTEX(hubd));
2209
2210	/*
2211	 * If the host controller is in charge of addressing, have it do that
2212	 * now and skip everything else.
2213	 */
2214	if (usba_device->usb_hcdi_ops->usba_hcdi_device_address != NULL) {
2215		mutex_exit(HUBD_MUTEX(hubd));
2216		rval = usba_device->usb_hcdi_ops->usba_hcdi_device_address(
2217		    usba_device);
2218		mutex_enter(HUBD_MUTEX(hubd));
2219
2220		usba_clear_data_toggle(usba_device);
2221		return (rval);
2222	}
2223
2224	/*
2225	 * As this device has been reset, temporarily
2226	 * assign the default address
2227	 */
2228	mutex_enter(&usba_device->usb_mutex);
2229	address = usba_device->usb_addr;
2230	usba_device->usb_addr = USBA_DEFAULT_ADDR;
2231	mutex_exit(&usba_device->usb_mutex);
2232
2233	mutex_exit(HUBD_MUTEX(hubd));
2234
2235	time_delay = drv_usectohz(hubd_device_delay / 20);
2236	for (retry = 0; retry < hubd_retry_enumerate; retry++) {
2237
2238		/* open child's default pipe with USBA_DEFAULT_ADDR */
2239		if ((rval = usb_pipe_open(child_dip, NULL, NULL,
2240		    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) !=
2241		    USB_SUCCESS) {
2242			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2243			    "hubd_setdevaddr: Unable to open default pipe");
2244
2245			break;
2246		}
2247
2248		/* Set the address of the device */
2249		if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
2250		    USB_DEV_REQ_HOST_TO_DEV,
2251		    USB_REQ_SET_ADDRESS,	/* bRequest */
2252		    address,			/* wValue */
2253		    0,				/* wIndex */
2254		    0,				/* wLength */
2255		    NULL, 0,
2256		    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
2257			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2258			    "hubd_setdevaddr(%d): rval=%d cr=%d cb_fl=0x%x",
2259			    retry, rval, completion_reason, cb_flags);
2260		}
2261
2262		usb_pipe_close(child_dip, ph,
2263		    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
2264
2265		if (rval == USB_SUCCESS) {
2266
2267			break;
2268		}
2269
2270		delay(time_delay);
2271	}
2272
2273	/* Reset to the old address */
2274	mutex_enter(&usba_device->usb_mutex);
2275	usba_device->usb_addr = address;
2276	mutex_exit(&usba_device->usb_mutex);
2277	mutex_enter(HUBD_MUTEX(hubd));
2278
2279	usba_clear_data_toggle(usba_device);
2280
2281	return (rval);
2282}
2283
2284
2285/*
2286 * hubd_setdevconfig
2287 *	set the device addrs on this port
2288 */
2289static void
2290hubd_setdevconfig(hubd_t *hubd, usb_port_t port)
2291{
2292	int			rval;
2293	usb_cr_t		completion_reason;
2294	usb_cb_flags_t		cb_flags;
2295	usb_pipe_handle_t	ph;
2296	dev_info_t		*child_dip = NULL;
2297	usba_device_t		*usba_device = NULL;
2298	uint16_t		config_value;
2299
2300	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2301	    "hubd_setdevconfig: port=%d", port);
2302
2303	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
2304
2305	child_dip = hubd->h_children_dips[port];
2306	usba_device = hubd->h_usba_devices[port];
2307	config_value = hubd->h_usba_devices[port]->usb_cfg_value;
2308	mutex_exit(HUBD_MUTEX(hubd));
2309
2310	/* open the default control pipe */
2311	if ((rval = usb_pipe_open(child_dip, NULL, NULL,
2312	    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) ==
2313	    USB_SUCCESS) {
2314
2315		/* Set the default configuration of the device */
2316		if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
2317		    USB_DEV_REQ_HOST_TO_DEV,
2318		    USB_REQ_SET_CFG,		/* bRequest */
2319		    config_value,		/* wValue */
2320		    0,				/* wIndex */
2321		    0,				/* wLength */
2322		    NULL, 0,
2323		    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
2324			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2325			    "hubd_setdevconfig: set device config failed: "
2326			    "cr=%d cb_fl=0x%x rval=%d",
2327			    completion_reason, cb_flags, rval);
2328		}
2329		/*
2330		 * After setting the configuration, we make this default
2331		 * control pipe persistent, so that it gets re-opened
2332		 * on posting a connect event
2333		 */
2334		usba_persistent_pipe_close(usba_device);
2335	} else {
2336		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2337		    "pipe open fails: rval=%d", rval);
2338	}
2339	mutex_enter(HUBD_MUTEX(hubd));
2340}
2341
2342
2343/*ARGSUSED*/
2344static int
2345hubd_check_disconnected_ports(dev_info_t *dip, void *arg)
2346{
2347	int circ;
2348	usb_port_t port;
2349	hubd_t *hubd;
2350	major_t hub_major = ddi_name_to_major("hubd");
2351	major_t hwahc_major = ddi_name_to_major("hwahc");
2352	major_t usbmid_major = ddi_name_to_major("usb_mid");
2353
2354	/*
2355	 * make sure dip is a usb hub, major of root hub is HCD
2356	 * major
2357	 */
2358	if (!usba_is_root_hub(dip)) {
2359		if (ddi_driver_major(dip) == usbmid_major) {
2360			/*
2361			 * need to walk the children since it might be a
2362			 * HWA device
2363			 */
2364
2365			return (DDI_WALK_CONTINUE);
2366		}
2367
2368		/* TODO: DWA device may also need special handling */
2369
2370		if (((ddi_driver_major(dip) != hub_major) &&
2371		    (ddi_driver_major(dip) != hwahc_major)) ||
2372		    !i_ddi_devi_attached(dip)) {
2373
2374			return (DDI_WALK_PRUNECHILD);
2375		}
2376	}
2377
2378	hubd = hubd_get_soft_state(dip);
2379	if (hubd == NULL) {
2380
2381		return (DDI_WALK_PRUNECHILD);
2382	}
2383
2384	/* walk child list and remove nodes with flag DEVI_DEVICE_REMOVED */
2385	ndi_devi_enter(dip, &circ);
2386
2387	if (ddi_driver_major(dip) != hwahc_major) {
2388		/* for normal usb hub or root hub */
2389		mutex_enter(HUBD_MUTEX(hubd));
2390		for (port = 1; port <= hubd->h_nports; port++) {
2391			dev_info_t *cdip = hubd->h_children_dips[port];
2392
2393			if (cdip == NULL || DEVI_IS_DEVICE_REMOVED(cdip) == 0) {
2394
2395				continue;
2396			}
2397
2398			(void) hubd_delete_child(hubd, port, NDI_DEVI_REMOVE,
2399			    B_TRUE);
2400		}
2401		mutex_exit(HUBD_MUTEX(hubd));
2402	} else {
2403		/* for HWA */
2404		if (hubd->h_cleanup_child != NULL) {
2405			if (hubd->h_cleanup_child(dip) != USB_SUCCESS) {
2406				ndi_devi_exit(dip, circ);
2407
2408				return (DDI_WALK_PRUNECHILD);
2409			}
2410		} else {
2411			ndi_devi_exit(dip, circ);
2412
2413			return (DDI_WALK_PRUNECHILD);
2414		}
2415	}
2416
2417	ndi_devi_exit(dip, circ);
2418
2419	/* skip siblings of root hub */
2420	if (usba_is_root_hub(dip)) {
2421
2422		return (DDI_WALK_PRUNESIB);
2423	}
2424
2425	return (DDI_WALK_CONTINUE);
2426}
2427
2428
2429/*
2430 * this thread will walk all children under the root hub for this
2431 * USB bus instance and attempt to remove them
2432 */
2433static void
2434hubd_root_hub_cleanup_thread(void *arg)
2435{
2436	int circ;
2437	hubd_t *root_hubd = (hubd_t *)arg;
2438	dev_info_t *rh_dip = root_hubd->h_dip;
2439#ifndef __lock_lint
2440	callb_cpr_t cprinfo;
2441
2442	CALLB_CPR_INIT(&cprinfo, HUBD_MUTEX(root_hubd), callb_generic_cpr,
2443	    "USB root hub");
2444#endif
2445
2446	for (;;) {
2447		/* don't race with detach */
2448		ndi_hold_devi(rh_dip);
2449
2450		mutex_enter(HUBD_MUTEX(root_hubd));
2451		root_hubd->h_cleanup_needed = 0;
2452		mutex_exit(HUBD_MUTEX(root_hubd));
2453
2454		(void) devfs_clean(rh_dip, NULL, 0);
2455
2456		ndi_devi_enter(ddi_get_parent(rh_dip), &circ);
2457		ddi_walk_devs(rh_dip, hubd_check_disconnected_ports,
2458		    NULL);
2459#ifdef __lock_lint
2460		(void) hubd_check_disconnected_ports(rh_dip, NULL);
2461#endif
2462		ndi_devi_exit(ddi_get_parent(rh_dip), circ);
2463
2464		/* quit if we are not enabled anymore */
2465		mutex_enter(HUBD_MUTEX(root_hubd));
2466		if ((root_hubd->h_cleanup_enabled == B_FALSE) ||
2467		    (root_hubd->h_cleanup_needed == B_FALSE)) {
2468			root_hubd->h_cleanup_active = B_FALSE;
2469			mutex_exit(HUBD_MUTEX(root_hubd));
2470			ndi_rele_devi(rh_dip);
2471
2472			break;
2473		}
2474		mutex_exit(HUBD_MUTEX(root_hubd));
2475		ndi_rele_devi(rh_dip);
2476
2477#ifndef __lock_lint
2478		mutex_enter(HUBD_MUTEX(root_hubd));
2479		CALLB_CPR_SAFE_BEGIN(&cprinfo);
2480		mutex_exit(HUBD_MUTEX(root_hubd));
2481
2482		delay(drv_usectohz(hubd_dip_cleanup_delay));
2483
2484		mutex_enter(HUBD_MUTEX(root_hubd));
2485		CALLB_CPR_SAFE_END(&cprinfo, HUBD_MUTEX(root_hubd));
2486		mutex_exit(HUBD_MUTEX(root_hubd));
2487#endif
2488	}
2489
2490#ifndef __lock_lint
2491	mutex_enter(HUBD_MUTEX(root_hubd));
2492	CALLB_CPR_EXIT(&cprinfo);
2493#endif
2494}
2495
2496
2497void
2498hubd_schedule_cleanup(dev_info_t *rh_dip)
2499{
2500	hubd_t	*root_hubd;
2501
2502	/*
2503	 * The usb_root_hub_dip pointer for the child hub of the WUSB
2504	 * wire adapter class device points to the wire adapter, not
2505	 * the root hub. Need to find the real root hub dip so that
2506	 * the cleanup thread only starts from the root hub.
2507	 */
2508	while (!usba_is_root_hub(rh_dip)) {
2509		root_hubd = hubd_get_soft_state(rh_dip);
2510		if (root_hubd != NULL) {
2511			rh_dip = root_hubd->h_usba_device->usb_root_hub_dip;
2512			if (rh_dip == NULL) {
2513				USB_DPRINTF_L2(DPRINT_MASK_ATTA,
2514				    root_hubd->h_log_handle,
2515				    "hubd_schedule_cleanup: null rh dip");
2516
2517				return;
2518			}
2519		} else {
2520			USB_DPRINTF_L2(DPRINT_MASK_ATTA,
2521			    root_hubd->h_log_handle,
2522			    "hubd_schedule_cleanup: cannot find root hub");
2523
2524			return;
2525		}
2526	}
2527	root_hubd = hubd_get_soft_state(rh_dip);
2528
2529	mutex_enter(HUBD_MUTEX(root_hubd));
2530	root_hubd->h_cleanup_needed = B_TRUE;
2531	if (root_hubd->h_cleanup_enabled && !(root_hubd->h_cleanup_active)) {
2532		root_hubd->h_cleanup_active = B_TRUE;
2533		mutex_exit(HUBD_MUTEX(root_hubd));
2534		(void) thread_create(NULL, 0,
2535		    hubd_root_hub_cleanup_thread,
2536		    (void *)root_hubd, 0, &p0, TS_RUN,
2537		    minclsyspri);
2538	} else {
2539		mutex_exit(HUBD_MUTEX(root_hubd));
2540	}
2541}
2542
2543
2544/*
2545 * hubd_restore_device_state:
2546 *	- set config for the hub
2547 *	- power cycle all the ports
2548 *	- for each port that was connected
2549 *		- reset port
2550 *		- assign addrs to the device on this port
2551 *	- restart polling
2552 *	- reset suspend flag
2553 */
2554static void
2555hubd_restore_device_state(dev_info_t *dip, hubd_t *hubd)
2556{
2557	int		rval;
2558	int		retry;
2559	uint_t		hub_prev_state;
2560	usb_port_t	port;
2561	uint16_t	status;
2562	uint16_t	change;
2563	dev_info_t	*ch_dip;
2564	boolean_t	ehci_root_hub;
2565
2566	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2567	    "hubd_restore_device_state:");
2568
2569	mutex_enter(HUBD_MUTEX(hubd));
2570	hub_prev_state = hubd->h_dev_state;
2571	ASSERT(hub_prev_state != USB_DEV_PWRED_DOWN);
2572
2573	/* First bring the device to full power */
2574	(void) hubd_pm_busy_component(hubd, dip, 0);
2575	mutex_exit(HUBD_MUTEX(hubd));
2576
2577	(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
2578
2579	if (!usba_is_root_hub(dip) &&
2580	    (usb_check_same_device(dip, hubd->h_log_handle, USB_LOG_L0,
2581	    DPRINT_MASK_HOTPLUG,
2582	    USB_CHK_BASIC|USB_CHK_CFG, NULL) != USB_SUCCESS)) {
2583
2584		/* change the device state to disconnected */
2585		mutex_enter(HUBD_MUTEX(hubd));
2586		hubd->h_dev_state = USB_DEV_DISCONNECTED;
2587		(void) hubd_pm_idle_component(hubd, dip, 0);
2588		mutex_exit(HUBD_MUTEX(hubd));
2589
2590		return;
2591	}
2592
2593	ehci_root_hub = (strcmp(ddi_driver_name(dip), "ehci") == 0);
2594
2595	mutex_enter(HUBD_MUTEX(hubd));
2596	/* First turn off all port power */
2597	rval = hubd_disable_all_port_power(hubd);
2598	if (rval != USB_SUCCESS) {
2599		USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle,
2600		    "hubd_restore_device_state:"
2601		    "turning off port power failed");
2602	}
2603
2604	/* Settling time before turning on again */
2605	mutex_exit(HUBD_MUTEX(hubd));
2606	delay(drv_usectohz(hubd_device_delay / 100));
2607	mutex_enter(HUBD_MUTEX(hubd));
2608
2609	/* enable power on all ports so we can see connects */
2610	if (hubd_enable_all_port_power(hubd) != USB_SUCCESS) {
2611		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2612		    "hubd_restore_device_state: turn on port power failed");
2613
2614		/* disable whatever was enabled */
2615		(void) hubd_disable_all_port_power(hubd);
2616
2617		(void) hubd_pm_idle_component(hubd, dip, 0);
2618		mutex_exit(HUBD_MUTEX(hubd));
2619
2620		return;
2621	}
2622
2623	/*
2624	 * wait at least 3 frames before accessing devices
2625	 * (note that delay's minimal time is one clock tick).
2626	 */
2627	mutex_exit(HUBD_MUTEX(hubd));
2628	delay(drv_usectohz(10000));
2629	mutex_enter(HUBD_MUTEX(hubd));
2630
2631	hubd->h_dev_state = USB_DEV_HUB_STATE_RECOVER;
2632
2633	for (port = 1; port <= hubd->h_nports; port++) {
2634		USB_DPRINTF_L3(DPRINT_MASK_ATTA, hubd->h_log_handle,
2635		    "hubd_restore_device_state: port=%d", port);
2636
2637		/*
2638		 * the childen_dips list may have dips that have been
2639		 * already deallocated. we only get a post_detach notification
2640		 * but not a destroy notification
2641		 */
2642		ch_dip = hubd->h_children_dips[port];
2643		if (ch_dip) {
2644			/* get port status */
2645			(void) hubd_determine_port_status(hubd, port,
2646			    &status, &change, NULL, PORT_CHANGE_CSC);
2647
2648			/* check if it is truly connected */
2649			if (status & PORT_STATUS_CCS) {
2650				/*
2651				 * Now reset port and assign the device
2652				 * its original address
2653				 */
2654				retry = 0;
2655				do {
2656					(void) hubd_reset_port(hubd, port);
2657
2658					/* required for ppx */
2659					(void) hubd_enable_port(hubd, port);
2660
2661					if (retry) {
2662						mutex_exit(HUBD_MUTEX(hubd));
2663						delay(drv_usectohz(
2664						    hubd_device_delay/2));
2665						mutex_enter(HUBD_MUTEX(hubd));
2666					}
2667
2668					rval = hubd_setdevaddr(hubd, port);
2669					retry++;
2670				} while ((rval != USB_SUCCESS) &&
2671				    (retry < hubd_retry_enumerate));
2672
2673				hubd_setdevconfig(hubd, port);
2674
2675				if (hub_prev_state == USB_DEV_DISCONNECTED) {
2676					/* post a connect event */
2677					mutex_exit(HUBD_MUTEX(hubd));
2678					hubd_post_event(hubd, port,
2679					    USBA_EVENT_TAG_HOT_INSERTION);
2680					mutex_enter(HUBD_MUTEX(hubd));
2681				} else {
2682					/*
2683					 * Since we have this device connected
2684					 * mark it reinserted to prevent
2685					 * cleanup thread from stepping in.
2686					 */
2687					mutex_exit(HUBD_MUTEX(hubd));
2688					mutex_enter(&(DEVI(ch_dip)->devi_lock));
2689					DEVI_SET_DEVICE_REINSERTED(ch_dip);
2690					mutex_exit(&(DEVI(ch_dip)->devi_lock));
2691
2692					/*
2693					 * reopen pipes for children for
2694					 * their DDI_RESUME
2695					 */
2696					rval = usba_persistent_pipe_open(
2697					    usba_get_usba_device(ch_dip));
2698					mutex_enter(HUBD_MUTEX(hubd));
2699					ASSERT(rval == USB_SUCCESS);
2700				}
2701			} else {
2702				/*
2703				 * Mark this dip for deletion as the device
2704				 * is not physically present, and schedule
2705				 * cleanup thread upon post resume
2706				 */
2707				mutex_exit(HUBD_MUTEX(hubd));
2708
2709				USB_DPRINTF_L2(DPRINT_MASK_ATTA,
2710				    hubd->h_log_handle,
2711				    "hubd_restore_device_state: "
2712				    "dip=%p on port=%d marked for cleanup",
2713				    (void *)ch_dip, port);
2714				mutex_enter(&(DEVI(ch_dip)->devi_lock));
2715				DEVI_SET_DEVICE_REMOVED(ch_dip);
2716				mutex_exit(&(DEVI(ch_dip)->devi_lock));
2717
2718				mutex_enter(HUBD_MUTEX(hubd));
2719			}
2720		} else if (ehci_root_hub) {
2721			/* get port status */
2722			(void) hubd_determine_port_status(hubd, port,
2723			    &status, &change, NULL, PORT_CHANGE_CSC);
2724
2725			/* check if it is truly connected */
2726			if (status & PORT_STATUS_CCS) {
2727				/*
2728				 * reset the port to find out if we have
2729				 * 2.0 device connected or 1.X. A 2.0
2730				 * device will still be seen as connected,
2731				 * while a 1.X device will switch over to
2732				 * the companion controller.
2733				 */
2734				(void) hubd_reset_port(hubd, port);
2735
2736				(void) hubd_determine_port_status(hubd, port,
2737				    &status, &change, NULL, PORT_CHANGE_CSC);
2738
2739				if (status &
2740				    (PORT_STATUS_CCS | PORT_STATUS_HSDA)) {
2741					/*
2742					 * We have a USB 2.0 device
2743					 * connected. Power cycle this port
2744					 * so that hotplug thread can
2745					 * enumerate this device.
2746					 */
2747					(void) hubd_toggle_port(hubd, port);
2748				} else {
2749					USB_DPRINTF_L2(DPRINT_MASK_ATTA,
2750					    hubd->h_log_handle,
2751					    "hubd_restore_device_state: "
2752					    "device on port %d switched over",
2753					    port);
2754				}
2755			}
2756
2757		}
2758	}
2759
2760
2761	/* if the device had remote wakeup earlier, enable it again */
2762	if (hubd->h_hubpm->hubp_wakeup_enabled) {
2763		mutex_exit(HUBD_MUTEX(hubd));
2764		(void) usb_handle_remote_wakeup(hubd->h_dip,
2765		    USB_REMOTE_WAKEUP_ENABLE);
2766		mutex_enter(HUBD_MUTEX(hubd));
2767	}
2768
2769	hubd->h_dev_state = USB_DEV_ONLINE;
2770	hubd_start_polling(hubd, 0);
2771	(void) hubd_pm_idle_component(hubd, dip, 0);
2772	mutex_exit(HUBD_MUTEX(hubd));
2773}
2774
2775
2776/*
2777 * hubd_cleanup:
2778 *	cleanup hubd and deallocate. this function is called for
2779 *	handling attach failures and detaching including dynamic
2780 *	reconfiguration. If called from attaching, it must clean
2781 *	up the whole thing and return success.
2782 */
2783/*ARGSUSED*/
2784static int
2785hubd_cleanup(dev_info_t *dip, hubd_t *hubd)
2786{
2787	int		circ, rval, old_dev_state;
2788	hub_power_t	*hubpm;
2789#ifdef DEBUG
2790	usb_port_t	port;
2791#endif
2792
2793	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2794	    "hubd_cleanup:");
2795
2796	if ((hubd->h_init_state & HUBD_LOCKS_DONE) == 0) {
2797		goto done;
2798	}
2799
2800	/* ensure we are the only one active */
2801	ndi_devi_enter(dip, &circ);
2802
2803	mutex_enter(HUBD_MUTEX(hubd));
2804
2805	/* Cleanup failure is only allowed if called from detach */
2806	if (DEVI_IS_DETACHING(dip)) {
2807		dev_info_t *rh_dip = hubd->h_usba_device->usb_root_hub_dip;
2808
2809		/*
2810		 * We are being called from detach.
2811		 * Fail immediately if the hotplug thread is running
2812		 * else set the dev_state to disconnected so that
2813		 * hotplug thread just exits without doing anything.
2814		 */
2815		if (hubd->h_bus_ctls || hubd->h_bus_pwr ||
2816		    hubd->h_hotplug_thread) {
2817			mutex_exit(HUBD_MUTEX(hubd));
2818			ndi_devi_exit(dip, circ);
2819
2820			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
2821			    "hubd_cleanup: hotplug thread/bus ctl active "
2822			    "- failing detach");
2823
2824			return (USB_FAILURE);
2825		}
2826
2827		/*
2828		 * if the deathrow thread is still active or about
2829		 * to become active, fail detach
2830		 * the roothup can only be detached if nexus drivers
2831		 * are unloaded or explicitly offlined
2832		 */
2833		if (rh_dip == dip) {
2834			if (hubd->h_cleanup_needed ||
2835			    hubd->h_cleanup_active) {
2836				mutex_exit(HUBD_MUTEX(hubd));
2837				ndi_devi_exit(dip, circ);
2838
2839				USB_DPRINTF_L2(DPRINT_MASK_ATTA,
2840				    hubd->h_log_handle,
2841				    "hubd_cleanup: deathrow still active?"
2842				    "- failing detach");
2843
2844				return (USB_FAILURE);
2845			}
2846		}
2847	}
2848
2849	old_dev_state = hubd->h_dev_state;
2850	hubd->h_dev_state = USB_DEV_DISCONNECTED;
2851
2852	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2853	    "hubd_cleanup: stop polling");
2854	hubd_close_intr_pipe(hubd);
2855
2856	ASSERT((hubd->h_bus_ctls || hubd->h_bus_pwr ||
2857	    hubd->h_hotplug_thread) == 0);
2858	mutex_exit(HUBD_MUTEX(hubd));
2859
2860	/*
2861	 * deallocate events, if events are still registered
2862	 * (ie. children still attached) then we have to fail the detach
2863	 */
2864	if (hubd->h_ndi_event_hdl) {
2865
2866		rval = ndi_event_free_hdl(hubd->h_ndi_event_hdl);
2867		if (DEVI_IS_ATTACHING(dip)) {
2868
2869			/* It must return success if attaching. */
2870			ASSERT(rval == NDI_SUCCESS);
2871
2872		} else if (rval != NDI_SUCCESS) {
2873
2874			USB_DPRINTF_L2(DPRINT_MASK_ALL, hubd->h_log_handle,
2875			    "hubd_cleanup: ndi_event_free_hdl failed");
2876			ndi_devi_exit(dip, circ);
2877
2878			return (USB_FAILURE);
2879
2880		}
2881	}
2882
2883	mutex_enter(HUBD_MUTEX(hubd));
2884
2885	if (hubd->h_init_state & HUBD_CHILDREN_CREATED) {
2886#ifdef DEBUG
2887		for (port = 1; port <= hubd->h_nports; port++) {
2888			ASSERT(hubd->h_usba_devices[port] == NULL);
2889			ASSERT(hubd->h_children_dips[port] == NULL);
2890		}
2891#endif
2892		kmem_free(hubd->h_children_dips, hubd->h_cd_list_length);
2893		kmem_free(hubd->h_usba_devices, hubd->h_cd_list_length);
2894	}
2895
2896	/*
2897	 * Disable the event callbacks first, after this point, event
2898	 * callbacks will never get called. Note we shouldn't hold
2899	 * mutex while unregistering events because there may be a
2900	 * competing event callback thread. Event callbacks are done
2901	 * with ndi mutex held and this can cause a potential deadlock.
2902	 * Note that cleanup can't fail after deregistration of events.
2903	 */
2904	if (hubd->h_init_state &  HUBD_EVENTS_REGISTERED) {
2905		mutex_exit(HUBD_MUTEX(hubd));
2906		usb_unregister_event_cbs(dip, &hubd_events);
2907		hubd_unregister_cpr_callback(hubd);
2908		mutex_enter(HUBD_MUTEX(hubd));
2909	}
2910
2911	/* restore the old dev state so that device can be put into low power */
2912	hubd->h_dev_state = old_dev_state;
2913	hubpm = hubd->h_hubpm;
2914
2915	if ((hubpm) && (hubd->h_dev_state != USB_DEV_DISCONNECTED)) {
2916		(void) hubd_pm_busy_component(hubd, dip, 0);
2917		mutex_exit(HUBD_MUTEX(hubd));
2918		if (hubd->h_hubpm->hubp_wakeup_enabled) {
2919			/*
2920			 * Bring the hub to full power before
2921			 * issuing the disable remote wakeup command
2922			 */
2923			(void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
2924
2925			if ((rval = usb_handle_remote_wakeup(hubd->h_dip,
2926			    USB_REMOTE_WAKEUP_DISABLE)) != USB_SUCCESS) {
2927				USB_DPRINTF_L2(DPRINT_MASK_PM,
2928				    hubd->h_log_handle,
2929				    "hubd_cleanup: disable remote wakeup "
2930				    "fails=%d", rval);
2931			}
2932		}
2933
2934		(void) pm_lower_power(hubd->h_dip, 0, USB_DEV_OS_PWR_OFF);
2935
2936		mutex_enter(HUBD_MUTEX(hubd));
2937		(void) hubd_pm_idle_component(hubd, dip, 0);
2938	}
2939
2940	if (hubpm) {
2941		if (hubpm->hubp_child_pwrstate) {
2942			kmem_free(hubpm->hubp_child_pwrstate,
2943			    MAX_PORTS + 1);
2944		}
2945		kmem_free(hubpm, sizeof (hub_power_t));
2946	}
2947	mutex_exit(HUBD_MUTEX(hubd));
2948
2949	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
2950	    "hubd_cleanup: freeing space");
2951
2952	if (hubd->h_init_state & HUBD_HUBDI_REGISTERED) {
2953		rval = usba_hubdi_unregister(dip);
2954		ASSERT(rval == USB_SUCCESS);
2955	}
2956
2957	if (hubd->h_init_state & HUBD_LOCKS_DONE) {
2958		mutex_destroy(HUBD_MUTEX(hubd));
2959		cv_destroy(&hubd->h_cv_reset_port);
2960		cv_destroy(&hubd->h_cv_hotplug_dev);
2961	}
2962
2963	ndi_devi_exit(dip, circ);
2964
2965	if (hubd->h_init_state & HUBD_MINOR_NODE_CREATED) {
2966		ddi_remove_minor_node(dip, NULL);
2967	}
2968
2969	if (usba_is_root_hub(dip)) {
2970		usb_pipe_close(dip, hubd->h_default_pipe,
2971		    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
2972	}
2973
2974done:
2975	if (hubd->h_ancestry_str) {
2976		kmem_free(hubd->h_ancestry_str, HUBD_APID_NAMELEN);
2977	}
2978
2979	usb_client_detach(dip, hubd->h_dev_data);
2980
2981	usb_free_log_hdl(hubd->h_log_handle);
2982
2983	if (!usba_is_root_hub(dip)) {
2984		ddi_soft_state_free(hubd_statep, ddi_get_instance(dip));
2985	}
2986
2987	ddi_prop_remove_all(dip);
2988
2989	return (USB_SUCCESS);
2990}
2991
2992
2993/*
2994 * hubd_determine_port_connection:
2995 *	Determine which port is in connect status but does not
2996 *	have connect status change bit set, and mark port change
2997 *	bit accordingly.
2998 *	This function is applied during hub attach time.
2999 */
3000static usb_port_mask_t
3001hubd_determine_port_connection(hubd_t	*hubd)
3002{
3003	usb_port_t	port;
3004	uint16_t	status;
3005	uint16_t	change;
3006	usb_port_mask_t	port_change = 0;
3007
3008	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
3009
3010	for (port = 1; port <= hubd->h_nports; port++) {
3011
3012		(void) hubd_determine_port_status(hubd, port, &status,
3013		    &change, NULL, 0);
3014
3015		/* Check if port is in connect status */
3016		if (!(status & PORT_STATUS_CCS)) {
3017
3018			continue;
3019		}
3020
3021		/*
3022		 * Check if port Connect Status Change bit has been set.
3023		 * If already set, the connection will be handled by
3024		 * intr polling callback, not during attach.
3025		 */
3026		if (change & PORT_CHANGE_CSC) {
3027
3028			continue;
3029		}
3030
3031		port_change |= 1 << port;
3032	}
3033
3034	return (port_change);
3035}
3036
3037
3038/*
3039 * hubd_check_ports:
3040 *	- get hub descriptor
3041 *	- check initial port status
3042 *	- enable power on all ports
3043 *	- enable polling on ep1
3044 */
3045static int
3046hubd_check_ports(hubd_t  *hubd)
3047{
3048	int			rval;
3049	usb_port_mask_t		port_change = 0;
3050	hubd_hotplug_arg_t	*arg;
3051
3052	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
3053
3054	USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
3055	    "hubd_check_ports: addr=0x%x", usb_get_addr(hubd->h_dip));
3056
3057	/*
3058	 * First turn off all port power
3059	 */
3060	if ((rval = hubd_disable_all_port_power(hubd)) != USB_SUCCESS) {
3061
3062		/* disable whatever was enabled */
3063		(void) hubd_disable_all_port_power(hubd);
3064
3065		return (rval);
3066	}
3067
3068	/*
3069	 * do not switch on immediately (instantly on root hub)
3070	 * and allow time to settle
3071	 */
3072	mutex_exit(HUBD_MUTEX(hubd));
3073	delay(drv_usectohz(10000));
3074	mutex_enter(HUBD_MUTEX(hubd));
3075
3076	/*
3077	 * enable power on all ports so we can see connects
3078	 */
3079	if ((rval = hubd_enable_all_port_power(hubd)) != USB_SUCCESS) {
3080		/* disable whatever was enabled */
3081		(void) hubd_disable_all_port_power(hubd);
3082
3083		return (rval);
3084	}
3085
3086	/* wait at least 3 frames before accessing devices */
3087	mutex_exit(HUBD_MUTEX(hubd));
3088	delay(drv_usectohz(10000));
3089	mutex_enter(HUBD_MUTEX(hubd));
3090
3091	/*
3092	 * allocate arrays for saving the dips of each child per port
3093	 *
3094	 * ports go from 1 - n, allocate 1 more entry
3095	 */
3096	hubd->h_cd_list_length =
3097	    (sizeof (dev_info_t **)) * (hubd->h_nports + 1);
3098
3099	hubd->h_children_dips = (dev_info_t **)kmem_zalloc(
3100	    hubd->h_cd_list_length, KM_SLEEP);
3101	hubd->h_usba_devices = (usba_device_t **)kmem_zalloc(
3102	    hubd->h_cd_list_length, KM_SLEEP);
3103
3104	hubd->h_init_state |= HUBD_CHILDREN_CREATED;
3105
3106	mutex_exit(HUBD_MUTEX(hubd));
3107	arg = (hubd_hotplug_arg_t *)kmem_zalloc(
3108	    sizeof (hubd_hotplug_arg_t), KM_SLEEP);
3109	mutex_enter(HUBD_MUTEX(hubd));
3110
3111	if ((rval = hubd_open_intr_pipe(hubd)) != USB_SUCCESS) {
3112		kmem_free(arg, sizeof (hubd_hotplug_arg_t));
3113
3114		return (rval);
3115	}
3116
3117	hubd_start_polling(hubd, 0);
3118
3119	/*
3120	 * Some hub devices, like the embedded hub in the CKS ErgoMagic
3121	 * keyboard, may only have connection status bit set, but not
3122	 * have connect status change bit set when a device has been
3123	 * connected to its downstream port before the hub is enumerated.
3124	 * Then when the hub is in enumeration, the devices connected to
3125	 * it cannot be detected by the intr pipe and won't be enumerated.
3126	 * We need to check such situation here and enumerate the downstream
3127	 * devices for such hubs.
3128	 */
3129	port_change = hubd_determine_port_connection(hubd);
3130
3131	if (port_change != 0 || hubd->h_port_change != 0) {
3132		hubd_pm_busy_component(hubd, hubd->h_dip, 0);
3133
3134		arg->hubd = hubd;
3135		arg->hotplug_during_attach = B_TRUE;
3136		hubd->h_port_change |= port_change;
3137
3138		USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
3139		    "hubd_check_ports: port change=0x%x, need to connect",
3140		    hubd->h_port_change);
3141
3142		if (usb_async_req(hubd->h_dip, hubd_hotplug_thread,
3143		    (void *)arg, 0) == USB_SUCCESS) {
3144			hubd->h_hotplug_thread++;
3145		} else {
3146			/* mark this device as idle */
3147			hubd_pm_idle_component(hubd, hubd->h_dip, 0);
3148			kmem_free(arg, sizeof (hubd_hotplug_arg_t));
3149		}
3150	} else {
3151		kmem_free(arg, sizeof (hubd_hotplug_arg_t));
3152	}
3153
3154	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
3155	    "hubd_check_ports done");
3156
3157	return (USB_SUCCESS);
3158}
3159
3160
3161/*
3162 * hubd_get_hub_descriptor:
3163 */
3164static int
3165hubd_get_hub_descriptor(hubd_t *hubd)
3166{
3167	mblk_t		*data = NULL;
3168	usb_cr_t	completion_reason;
3169	usb_cb_flags_t	cb_flags;
3170	uint16_t	length, wValue;
3171	int		rval;
3172	usb_req_attrs_t attr = 0;
3173
3174	USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3175	    "hubd_get_hub_descriptor:");
3176
3177	if ((hubd->h_dev_data->dev_descr->idVendor == USB_HUB_INTEL_VID) &&
3178	    (hubd->h_dev_data->dev_descr->idProduct == USB_HUB_INTEL_PID)) {
3179		attr = USB_ATTRS_SHORT_XFER_OK;
3180	}
3181
3182	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
3183	ASSERT(hubd->h_default_pipe != 0);
3184
3185	mutex_exit(HUBD_MUTEX(hubd));
3186
3187	/*
3188	 * The contents of wValue change depending on whether this is a USB 2 or
3189	 * USB 3 device. SuperSpeed Hubs have different descriptors and you
3190	 * cannot ask them for the traditional USB 2 descriptor.
3191	 */
3192	if (hubd->h_usba_device->usb_port_status >= USBA_SUPER_SPEED_DEV) {
3193		wValue = USB_DESCR_TYPE_SS_HUB << 8 | HUBD_DEFAULT_DESC_INDEX;
3194	} else {
3195		wValue = USB_DESCR_TYPE_HUB << 8 | HUBD_DEFAULT_DESC_INDEX;
3196	}
3197
3198	/*
3199	 * The hub descriptor length varies in various versions of USB. For
3200	 * example, in USB 2 it's at least 9 bytes long. To start with, we
3201	 * always get the first 8 bytes so we can figure out how long it
3202	 * actually is.
3203	 */
3204	if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
3205	    hubd->h_default_pipe,
3206	    HUB_CLASS_REQ_TYPE,
3207	    USB_REQ_GET_DESCR,		/* bRequest */
3208	    wValue,			/* wValue */
3209	    0,				/* wIndex */
3210	    8,				/* wLength */
3211	    &data, 0,
3212	    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
3213		USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
3214		    "get hub descriptor failed: cr=%d cb_fl=0x%x rval=%d",
3215		    completion_reason, cb_flags, rval);
3216		freemsg(data);
3217		mutex_enter(HUBD_MUTEX(hubd));
3218
3219		return (rval);
3220	}
3221
3222	length = *(data->b_rptr);
3223
3224	if (length > 8) {
3225		freemsg(data);
3226		data = NULL;
3227
3228		/* get complete hub descriptor */
3229		rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
3230		    hubd->h_default_pipe,
3231		    HUB_CLASS_REQ_TYPE,
3232		    USB_REQ_GET_DESCR,		/* bRequest */
3233		    wValue,			/* wValue */
3234		    0,				/* wIndex */
3235		    length,			/* wLength */
3236		    &data, attr,
3237		    &completion_reason, &cb_flags, 0);
3238
3239		/*
3240		 * Hub descriptor data less than 9 bytes is not valid and
3241		 * may cause trouble if we use it. See USB2.0 Tab11-13.
3242		 */
3243		if ((rval != USB_SUCCESS) || (MBLKL(data) <= 8)) {
3244			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
3245			    "get hub descriptor failed: "
3246			    "cr=%d cb_fl=0x%x rval=%d, len=%ld",
3247			    completion_reason, cb_flags, rval,
3248			    (data)?MBLKL(data):0);
3249			freemsg(data);
3250			mutex_enter(HUBD_MUTEX(hubd));
3251
3252			return (rval);
3253		}
3254	}
3255
3256	mutex_enter(HUBD_MUTEX(hubd));
3257
3258	/*
3259	 * Parse the hub descriptor. Note that the format of the descriptor
3260	 * itself depends on the USB version. We handle the different ones and
3261	 * transform it into a single uniform view.
3262	 */
3263
3264	ASSERT(*(data->b_rptr + 2) <= (MAX_PORTS + 1));
3265	if (hubd->h_usba_device->usb_port_status >= USBA_SUPER_SPEED_DEV) {
3266		usb_ss_hub_descr_t hub_descr;
3267		char *desc = "cccscccs";
3268		ASSERT(*(data->b_rptr + 1) == ROOT_HUB_SS_DESCRIPTOR_TYPE);
3269
3270		/*
3271		 * Note many hubs may support less than the 255 devices that the
3272		 * USB specification allows for. In those cases, we'll simply
3273		 * read less and it should be okay.
3274		 */
3275		if (usb_parse_CV_descr(desc, data->b_rptr, MBLKL(data),
3276		    (void *)&hub_descr, sizeof (hub_descr)) == 0) {
3277			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
3278			    "parsing hub descriptor failed");
3279			freemsg(data);
3280			return (USB_FAILURE);
3281		}
3282
3283		hubd->h_nports = hub_descr.bNbrPorts;
3284		hubd->h_hub_chars = hub_descr.wHubCharacteristics;
3285		hubd->h_power_good = hub_descr.bPwrOn2PwrGood;
3286		hubd->h_current = hub_descr.bHubContrCurrent;
3287	} else {
3288		usb_hub_descr_t hub_descr;
3289		if (usb_parse_CV_descr("cccscccccc",
3290		    data->b_rptr, MBLKL(data),
3291		    (void *)&hub_descr, sizeof (usb_hub_descr_t)) == 0) {
3292			USB_DPRINTF_L2(DPRINT_MASK_ATTA, hubd->h_log_handle,
3293			    "parsing hub descriptor failed");
3294			freemsg(data);
3295			return (USB_FAILURE);
3296		}
3297
3298		hubd->h_nports = hub_descr.bNbrPorts;
3299		hubd->h_hub_chars = hub_descr.wHubCharacteristics;
3300		hubd->h_power_good = hub_descr.bPwrOn2PwrGood;
3301		hubd->h_current = hub_descr.bHubContrCurrent;
3302	}
3303
3304	freemsg(data);
3305
3306	USB_DPRINTF_L4(DPRINT_MASK_ATTA, hubd->h_log_handle,
3307	    "rval=0x%x bNbrPorts=0x%x wHubChars=0x%x "
3308	    "PwrOn2PwrGood=0x%x HubContrCurrent=%dmA", rval,
3309	    hubd->h_nports, hubd->h_hub_chars,
3310	    hubd->h_power_good, hubd->h_current);
3311
3312	if (hubd->h_nports > MAX_PORTS) {
3313		USB_DPRINTF_L0(DPRINT_MASK_ATTA, hubd->h_log_handle,
3314		    "Hub driver supports max of %d ports on hub. "
3315		    "Hence using the first %d port of %d ports available",
3316		    MAX_PORTS, MAX_PORTS, hubd->h_nports);
3317
3318		hubd->h_nports = MAX_PORTS;
3319	}
3320
3321	return (USB_SUCCESS);
3322}
3323
3324static int
3325hubd_set_hub_depth(hubd_t *hubd)
3326{
3327	int rval;
3328	usb_cr_t	completion_reason;
3329	usb_cb_flags_t	cb_flags;
3330	usba_device_t	*ud;
3331	uint16_t	depth;
3332
3333	/*
3334	 * We only need to set the hub depth devices for hubs that are at least
3335	 * SuperSpeed devices. This didn't exist for USB 2.0 and older hubs.
3336	 * There's also no need to call this on the root hub.
3337	 */
3338	if (hubd->h_usba_device->usb_port_status < USBA_SUPER_SPEED_DEV ||
3339	    usba_is_root_hub(hubd->h_dip))
3340		return (USB_SUCCESS);
3341
3342	depth = 0;
3343	ud = hubd->h_usba_device;
3344	while (ud->usb_parent_hub != NULL) {
3345		depth++;
3346		ud = ud->usb_parent_hub;
3347	}
3348	ASSERT(depth > 0);
3349
3350	if (depth > HUBD_SS_MAX_DEPTH) {
3351		const char *mfg, *prod;
3352
3353		ud = hubd->h_usba_device;
3354		prod = ud->usb_product_str;
3355		if (prod == NULL)
3356			prod = "Unknown Device";
3357		mfg = ud->usb_mfg_str;
3358		if (mfg == NULL)
3359			mfg = "Unknown Manufacturer";
3360		cmn_err(CE_WARN, "Unable to attach USB 3.x hub %s %s. A "
3361		    "maximum of %d hubs may be cascaded", mfg, prod,
3362		    HUBD_SS_MAX_DEPTH);
3363		return (USB_FAILURE);
3364	}
3365
3366	/*
3367	 * When making the HUB_REQ_SET_HUB_DEPTH request, a hub connected to a
3368	 * root port is considered to have a hub depth of zero whereas we
3369	 * consider having a hub depth of one above.
3370	 */
3371	depth--;
3372
3373	if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
3374	    hubd->h_default_pipe,
3375	    HUB_SET_HUB_DEPTH_TYPE,
3376	    HUB_REQ_SET_HUB_DEPTH,	/* bRequest */
3377	    depth,			/* wValue */
3378	    0,				/* wIndex */
3379	    0,				/* wLength */
3380	    NULL, 0,
3381	    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
3382		USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle,
3383		    "get set hub depth failed: cr=%d cb=0x%x",
3384		    completion_reason, cb_flags);
3385	}
3386
3387	return (rval);
3388}
3389
3390/*
3391 * hubd_get_hub_status_words:
3392 */
3393static int
3394hubd_get_hub_status_words(hubd_t *hubd, uint16_t *status)
3395{
3396	usb_cr_t	completion_reason;
3397	usb_cb_flags_t	cb_flags;
3398	mblk_t		*data = NULL;
3399
3400	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
3401
3402	mutex_exit(HUBD_MUTEX(hubd));
3403
3404	if (usb_pipe_sync_ctrl_xfer(hubd->h_dip, hubd->h_default_pipe,
3405	    HUB_CLASS_REQ_TYPE,
3406	    USB_REQ_GET_STATUS,
3407	    0,
3408	    0,
3409	    GET_STATUS_LENGTH,
3410	    &data, 0,
3411	    &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
3412		USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle,
3413		    "get hub status failed: cr=%d cb=0x%x",
3414		    completion_reason, cb_flags);
3415
3416		if (data) {
3417			freemsg(data);
3418		}
3419
3420		mutex_enter(HUBD_MUTEX(hubd));
3421
3422		return (USB_FAILURE);
3423	}
3424
3425	mutex_enter(HUBD_MUTEX(hubd));
3426
3427	status[0] = (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
3428	status[1] = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2);
3429
3430	USB_DPRINTF_L3(DPRINT_MASK_HUB, hubd->h_log_handle,
3431	    "hub status=0x%x change=0x%x", status[0], status[1]);
3432
3433	freemsg(data);
3434
3435	return (USB_SUCCESS);
3436}
3437
3438
3439/*
3440 * hubd_open_intr_pipe:
3441 *	we read all descriptors first for curiosity and then simply
3442 *	open the pipe
3443 */
3444static int
3445hubd_open_intr_pipe(hubd_t	*hubd)
3446{
3447	int			rval;
3448
3449	USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3450	    "hubd_open_intr_pipe:");
3451
3452	ASSERT(hubd->h_intr_pipe_state == HUBD_INTR_PIPE_IDLE);
3453
3454	hubd->h_intr_pipe_state = HUBD_INTR_PIPE_OPENING;
3455	mutex_exit(HUBD_MUTEX(hubd));
3456
3457	if ((rval = usb_pipe_xopen(hubd->h_dip,
3458	    &hubd->h_ep1_xdescr, &hubd->h_pipe_policy,
3459	    0, &hubd->h_ep1_ph)) != USB_SUCCESS) {
3460		USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle,
3461		    "open intr pipe failed (%d)", rval);
3462
3463		mutex_enter(HUBD_MUTEX(hubd));
3464		hubd->h_intr_pipe_state = HUBD_INTR_PIPE_IDLE;
3465
3466		return (rval);
3467	}
3468
3469	mutex_enter(HUBD_MUTEX(hubd));
3470	hubd->h_intr_pipe_state = HUBD_INTR_PIPE_ACTIVE;
3471
3472	USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3473	    "open intr pipe succeeded, ph=0x%p", (void *)hubd->h_ep1_ph);
3474
3475	return (USB_SUCCESS);
3476}
3477
3478
3479/*
3480 * hubd_start_polling:
3481 *	start or restart the polling
3482 */
3483static void
3484hubd_start_polling(hubd_t *hubd, int always)
3485{
3486	usb_intr_req_t	*reqp;
3487	int			rval;
3488	usb_pipe_state_t	pipe_state;
3489
3490	USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3491	    "start polling: always=%d dev_state=%d pipe_state=%d\n\t"
3492	    "thread=%d ep1_ph=0x%p",
3493	    always, hubd->h_dev_state, hubd->h_intr_pipe_state,
3494	    hubd->h_hotplug_thread, (void *)hubd->h_ep1_ph);
3495
3496	/*
3497	 * start or restart polling on the intr pipe
3498	 * only if hotplug thread is not running
3499	 */
3500	if ((always == HUBD_ALWAYS_START_POLLING) ||
3501	    ((hubd->h_dev_state == USB_DEV_ONLINE) &&
3502	    (hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE) &&
3503	    (hubd->h_hotplug_thread == 0) && hubd->h_ep1_ph)) {
3504		USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3505		    "start polling requested");
3506
3507		reqp = usb_alloc_intr_req(hubd->h_dip, 0, USB_FLAGS_SLEEP);
3508
3509		reqp->intr_client_private = (usb_opaque_t)hubd;
3510		reqp->intr_attributes = USB_ATTRS_SHORT_XFER_OK |
3511		    USB_ATTRS_AUTOCLEARING;
3512		reqp->intr_len = hubd->h_ep1_xdescr.uex_ep.wMaxPacketSize;
3513		reqp->intr_cb = hubd_read_cb;
3514		reqp->intr_exc_cb = hubd_exception_cb;
3515		mutex_exit(HUBD_MUTEX(hubd));
3516		if ((rval = usb_pipe_intr_xfer(hubd->h_ep1_ph, reqp,
3517		    USB_FLAGS_SLEEP)) != USB_SUCCESS) {
3518			USB_DPRINTF_L2(DPRINT_MASK_HUB, hubd->h_log_handle,
3519			    "start polling failed, rval=%d", rval);
3520			usb_free_intr_req(reqp);
3521		}
3522
3523		rval = usb_pipe_get_state(hubd->h_ep1_ph, &pipe_state,
3524		    USB_FLAGS_SLEEP);
3525		if (pipe_state != USB_PIPE_STATE_ACTIVE) {
3526			USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
3527			    "intr pipe state=%d, rval=%d", pipe_state, rval);
3528		}
3529		USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3530		    "start polling request 0x%p", (void *)reqp);
3531
3532		mutex_enter(HUBD_MUTEX(hubd));
3533	}
3534}
3535
3536
3537/*
3538 * hubd_stop_polling
3539 *	stop polling but do not close the pipe
3540 */
3541static void
3542hubd_stop_polling(hubd_t *hubd)
3543{
3544	int			rval;
3545	usb_pipe_state_t	pipe_state;
3546
3547	if (hubd->h_ep1_ph) {
3548		USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
3549		    "hubd_stop_polling:");
3550		hubd->h_intr_pipe_state = HUBD_INTR_PIPE_STOPPED;
3551		mutex_exit(HUBD_MUTEX(hubd));
3552
3553		usb_pipe_stop_intr_polling(hubd->h_ep1_ph, USB_FLAGS_SLEEP);
3554		rval = usb_pipe_get_state(hubd->h_ep1_ph, &pipe_state,
3555		    USB_FLAGS_SLEEP);
3556
3557		if (pipe_state != USB_PIPE_STATE_IDLE) {
3558			USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
3559			    "intr pipe state=%d, rval=%d", pipe_state, rval);
3560		}
3561		mutex_enter(HUBD_MUTEX(hubd));
3562		if (hubd->h_intr_pipe_state == HUBD_INTR_PIPE_STOPPED) {
3563			hubd->h_intr_pipe_state = HUBD_INTR_PIPE_ACTIVE;
3564		}
3565	}
3566}
3567
3568
3569/*
3570 * hubd_close_intr_pipe:
3571 *	close the pipe (which also stops the polling
3572 *	and wait for the hotplug thread to exit
3573 */
3574static void
3575hubd_close_intr_pipe(hubd_t *hubd)
3576{
3577	USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3578	    "hubd_close_intr_pipe:");
3579
3580	/*
3581	 * Now that no async operation is outstanding on pipe,
3582	 * we can change the state to HUBD_INTR_PIPE_CLOSING
3583	 */
3584	hubd->h_intr_pipe_state = HUBD_INTR_PIPE_CLOSING;
3585
3586	ASSERT(hubd->h_hotplug_thread == 0);
3587
3588	if (hubd->h_ep1_ph) {
3589		mutex_exit(HUBD_MUTEX(hubd));
3590		usb_pipe_close(hubd->h_dip, hubd->h_ep1_ph, USB_FLAGS_SLEEP,
3591		    NULL, NULL);
3592		mutex_enter(HUBD_MUTEX(hubd));
3593		hubd->h_ep1_ph = NULL;
3594	}
3595
3596	hubd->h_intr_pipe_state = HUBD_INTR_PIPE_IDLE;
3597}
3598
3599
3600/*
3601 * hubd_exception_cb
3602 *	interrupt ep1 exception callback function.
3603 *	this callback executes in taskq thread context and assumes
3604 *	autoclearing
3605 */
3606/*ARGSUSED*/
3607static void
3608hubd_exception_cb(usb_pipe_handle_t pipe, usb_intr_req_t *reqp)
3609{
3610	hubd_t		*hubd = (hubd_t *)(reqp->intr_client_private);
3611
3612	USB_DPRINTF_L2(DPRINT_MASK_CALLBACK, hubd->h_log_handle,
3613	    "hubd_exception_cb: "
3614	    "req=0x%p cr=%d data=0x%p cb_flags=0x%x", (void *)reqp,
3615	    reqp->intr_completion_reason, (void *)reqp->intr_data,
3616	    reqp->intr_cb_flags);
3617
3618	ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0);
3619
3620	mutex_enter(HUBD_MUTEX(hubd));
3621	(void) hubd_pm_busy_component(hubd, hubd->h_dip, 0);
3622
3623	switch (reqp->intr_completion_reason) {
3624	case USB_CR_PIPE_RESET:
3625		/* only restart polling after autoclearing */
3626		if ((hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE) &&
3627		    (hubd->h_port_reset_wait == 0)) {
3628			hubd_start_polling(hubd, 0);
3629		}
3630
3631		break;
3632	case USB_CR_DEV_NOT_RESP:
3633	case USB_CR_STOPPED_POLLING:
3634	case USB_CR_PIPE_CLOSING:
3635	case USB_CR_UNSPECIFIED_ERR:
3636		/* never restart polling on these conditions */
3637	default:
3638		/* for all others, wait for the autoclearing PIPE_RESET cb */
3639
3640		break;
3641	}
3642
3643	usb_free_intr_req(reqp);
3644	(void) hubd_pm_idle_component(hubd, hubd->h_dip, 0);
3645	mutex_exit(HUBD_MUTEX(hubd));
3646}
3647
3648
3649/*
3650 * helper function to convert LE bytes to a portmask
3651 */
3652static usb_port_mask_t
3653hubd_mblk2portmask(mblk_t *data)
3654{
3655	int len = min(MBLKL(data), sizeof (usb_port_mask_t));
3656	usb_port_mask_t rval = 0;
3657	int i;
3658
3659	for (i = 0; i < len; i++) {
3660		rval |= data->b_rptr[i] << (i * 8);
3661	}
3662
3663	return (rval);
3664}
3665
3666
3667/*
3668 * hubd_read_cb:
3669 *	interrupt ep1 callback function
3670 *
3671 *	the status indicates just a change on the pipe with no indication
3672 *	of what the change was
3673 *
3674 *	known conditions:
3675 *		- reset port completion
3676 *		- connect
3677 *		- disconnect
3678 *
3679 *	for handling the hotplugging, create a new thread that can do
3680 *	synchronous usba calls
3681 */
3682static void
3683hubd_read_cb(usb_pipe_handle_t pipe, usb_intr_req_t *reqp)
3684{
3685	hubd_t		*hubd = (hubd_t *)(reqp->intr_client_private);
3686	size_t		length;
3687	mblk_t		*data = reqp->intr_data;
3688	int		mem_flag = 0;
3689	hubd_hotplug_arg_t *arg;
3690
3691	USB_DPRINTF_L4(DPRINT_MASK_HUB, hubd->h_log_handle,
3692	    "hubd_read_cb: ph=0x%p req=0x%p", (void *)pipe, (void *)reqp);
3693
3694	ASSERT((reqp->intr_cb_flags & USB_CB_INTR_CONTEXT) == 0);
3695
3696	/*
3697	 * At present, we are not handling notification for completion of
3698	 * asynchronous pipe reset, for which this data ptr could be NULL
3699	 */
3700
3701	if (data == NULL) {
3702		usb_free_intr_req(reqp);
3703
3704		return;
3705	}
3706
3707	arg = (hubd_hotplug_arg_t *)kmem_zalloc(
3708	    sizeof (hubd_hotplug_arg_t), KM_SLEEP);
3709	mem_flag = 1;
3710
3711	mutex_enter(HUBD_MUTEX(hubd));
3712
3713	if ((hubd->h_dev_state == USB_DEV_SUSPENDED) ||
3714	    (hubd->h_intr_pipe_state != HUBD_INTR_PIPE_ACTIVE)) {
3715		mutex_exit(HUBD_MUTEX(hubd));
3716		usb_free_intr_req(reqp);
3717		kmem_free(arg, sizeof (hubd_hotplug_arg_t));
3718
3719		return;
3720	}
3721
3722	ASSERT(hubd->h_ep1_ph == pipe);
3723
3724	length = MBLKL(data);
3725
3726	/*
3727	 * Only look at the data and startup the hotplug thread if
3728	 * there actually is data.
3729	 */
3730	if (length != 0) {
3731		usb_port_mask_t port_change = hubd_mblk2portmask(data);
3732
3733		/*
3734		 * if a port change was already reported and we are waiting for
3735		 * reset port completion then wake up the hotplug thread which
3736		 * should be waiting on reset port completion
3737		 *
3738		 * if there is disconnect event instead of reset completion, let
3739		 * the hotplug thread figure this out
3740		 */
3741
3742		/* remove the reset wait bits from the status */
3743		hubd->h_port_change |= port_change &
3744		    ~hubd->h_port_reset_wait;
3745
3746		USB_DPRINTF_L3(DPRINT_MASK_CALLBACK, hubd->h_log_handle,
3747		    "port change=0x%x port_reset_wait=0x%x",
3748		    hubd->h_port_change, hubd->h_port_reset_wait);
3749
3750		/* there should be only one reset bit active at the time */
3751		if (hubd->h_port_reset_wait & port_change) {
3752			hubd->h_port_reset_wait = 0;
3753			cv_signal(&hubd->h_cv_reset_port);
3754		}
3755
3756		/*
3757		 * kick off the thread only if device is ONLINE and it is not
3758		 * during attaching or detaching
3759		 */
3760		if ((hubd->h_dev_state == USB_DEV_ONLINE) &&
3761		    (!DEVI_IS_ATTACHING(hubd->h_dip)) &&
3762		    (!DEVI_IS_DETACHING(hubd->h_dip)) &&
3763		    (hubd->h_port_change) &&
3764		    (hubd->h_hotplug_thread == 0)) {
3765			USB_DPRINTF_L3(DPRINT_MASK_CALLBACK, hubd->h_log_handle,
3766			    "creating hotplug thread: "
3767			    "dev_state=%d", hubd->h_dev_state);
3768
3769			/*
3770			 * Mark this device as busy. The will be marked idle
3771			 * if the async req fails or at the exit of  hotplug
3772			 * thread
3773			 */
3774			(void) hubd_pm_busy_component(hubd, hubd->h_dip, 0);
3775
3776			arg->hubd = hubd;
3777			arg->hotplug_during_attach = B_FALSE;
3778
3779			if (usb_async_req(hubd->h_dip,
3780			    hubd_hotplug_thread,
3781			    (void *)arg, 0) == USB_SUCCESS) {
3782				hubd->h_hotplug_thread++;
3783				mem_flag = 0;
3784			} else {
3785				/* mark this device as idle */
3786				(void) hubd_pm_idle_component(hubd,
3787				    hubd->h_dip, 0);
3788			}
3789		}
3790	}
3791	mutex_exit(HUBD_MUTEX(hubd));
3792
3793	if (mem_flag == 1) {
3794		kmem_free(arg, sizeof (hubd_hotplug_arg_t));
3795	}
3796
3797	usb_free_intr_req(reqp);
3798}
3799
3800
3801/*
3802 * hubd_hotplug_thread:
3803 *	handles resetting of port, and creating children
3804 *
3805 *	the ports to check are indicated in h_port_change bit mask
3806 * XXX note that one time poll doesn't work on the root hub
3807 */
3808static void
3809hubd_hotplug_thread(void *arg)
3810{
3811	hubd_hotplug_arg_t *hd_arg = (hubd_hotplug_arg_t *)arg;
3812	hubd_t		*hubd = hd_arg->hubd;
3813	boolean_t	attach_flg = hd_arg->hotplug_during_attach;
3814	usb_port_t	port;
3815	uint16_t	nports;
3816	uint16_t	status, change;
3817	hub_power_t	*hubpm;
3818	dev_info_t	*hdip = hubd->h_dip;
3819	dev_info_t	*rh_dip = hubd->h_usba_device->usb_root_hub_dip;
3820	dev_info_t	*child_dip;
3821	boolean_t	online_child = B_FALSE;
3822	boolean_t	offline_child = B_FALSE;
3823	boolean_t	pwrup_child = B_FALSE;
3824	int		prh_circ, rh_circ, chld_circ, circ, old_state;
3825
3826	USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3827	    "hubd_hotplug_thread:  started");
3828
3829	/*
3830	 * Before console is init'd, we temporarily block the hotplug
3831	 * threads so that BUS_CONFIG_ONE through hubd_bus_config() can be
3832	 * processed quickly. This reduces the time needed for vfs_mountroot()
3833	 * to mount the root FS from a USB disk. And on SPARC platform,
3834	 * in order to load 'consconfig' successfully after OBP is gone,
3835	 * we need to check 'modrootloaded' to make sure root filesystem is
3836	 * available.
3837	 */
3838	while (!modrootloaded || !consconfig_console_is_ready()) {
3839		delay(drv_usectohz(10000));
3840	}
3841
3842	kmem_free(arg, sizeof (hubd_hotplug_arg_t));
3843
3844	/*
3845	 * if our bus power entry point is active, process the change
3846	 * on the next notification of interrupt pipe
3847	 */
3848	mutex_enter(HUBD_MUTEX(hubd));
3849	if (hubd->h_bus_pwr || (hubd->h_hotplug_thread > 1)) {
3850		hubd->h_hotplug_thread--;
3851
3852		/* mark this device as idle */
3853		hubd_pm_idle_component(hubd, hubd->h_dip, 0);
3854		mutex_exit(HUBD_MUTEX(hubd));
3855
3856		USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3857		    "hubd_hotplug_thread: "
3858		    "bus_power in progress/hotplugging undesirable - quit");
3859
3860		return;
3861	}
3862	mutex_exit(HUBD_MUTEX(hubd));
3863
3864	ndi_hold_devi(hdip); /* so we don't race with detach */
3865
3866	mutex_enter(HUBD_MUTEX(hubd));
3867
3868	/* is this the root hub? */
3869	if (hdip == rh_dip) {
3870		if (hubd->h_dev_state == USB_DEV_PWRED_DOWN) {
3871			hubpm = hubd->h_hubpm;
3872
3873			/* mark the root hub as full power */
3874			hubpm->hubp_current_power = USB_DEV_OS_FULL_PWR;
3875			hubpm->hubp_time_at_full_power = gethrtime();
3876			mutex_exit(HUBD_MUTEX(hubd));
3877
3878			USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3879			    "hubd_hotplug_thread: call pm_power_has_changed");
3880
3881			(void) pm_power_has_changed(hdip, 0,
3882			    USB_DEV_OS_FULL_PWR);
3883
3884			mutex_enter(HUBD_MUTEX(hubd));
3885			hubd->h_dev_state = USB_DEV_ONLINE;
3886		}
3887
3888	} else {
3889		USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3890		    "hubd_hotplug_thread: not root hub");
3891	}
3892
3893	mutex_exit(HUBD_MUTEX(hubd));
3894
3895	/*
3896	 * this ensures one hotplug activity per system at a time.
3897	 * we enter the parent PCI node to have this serialization.
3898	 * this also excludes ioctls and deathrow thread
3899	 * (a bit crude but easier to debug)
3900	 */
3901	ndi_devi_enter(ddi_get_parent(rh_dip), &prh_circ);
3902	ndi_devi_enter(rh_dip, &rh_circ);
3903
3904	/* exclude other threads */
3905	ndi_devi_enter(hdip, &circ);
3906	mutex_enter(HUBD_MUTEX(hubd));
3907
3908	ASSERT(hubd->h_intr_pipe_state == HUBD_INTR_PIPE_ACTIVE);
3909
3910	nports = hubd->h_nports;
3911
3912	hubd_stop_polling(hubd);
3913
3914	while ((hubd->h_dev_state == USB_DEV_ONLINE) &&
3915	    (hubd->h_port_change)) {
3916		/*
3917		 * The 0th bit is the hub status change bit.
3918		 * handle loss of local power here
3919		 */
3920		if (hubd->h_port_change & HUB_CHANGE_STATUS) {
3921			USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3922			    "hubd_hotplug_thread: hub status change!");
3923
3924			/*
3925			 * This should be handled properly.  For now,
3926			 * mask off the bit.
3927			 */
3928			hubd->h_port_change &= ~HUB_CHANGE_STATUS;
3929
3930			/*
3931			 * check and ack hub status
3932			 * this causes stall conditions
3933			 * when local power is removed
3934			 */
3935			(void) hubd_get_hub_status(hubd);
3936		}
3937
3938		for (port = 1; port <= nports; port++) {
3939			usb_port_mask_t port_mask;
3940			boolean_t was_connected;
3941
3942			port_mask = 1 << port;
3943			was_connected =
3944			    (hubd->h_port_state[port] & PORT_STATUS_CCS) &&
3945			    (hubd->h_children_dips[port]);
3946
3947			USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3948			    "hubd_hotplug_thread: "
3949			    "port %d mask=0x%x change=0x%x connected=0x%x",
3950			    port, port_mask, hubd->h_port_change,
3951			    was_connected);
3952
3953			/*
3954			 * is this a port connection that changed?
3955			 */
3956			if ((hubd->h_port_change & port_mask) == 0) {
3957
3958				continue;
3959			}
3960			hubd->h_port_change &= ~port_mask;
3961
3962			/* ack all changes */
3963			(void) hubd_determine_port_status(hubd, port,
3964			    &status, &change, NULL, HUBD_ACK_ALL_CHANGES);
3965
3966			USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
3967			    "handle port %d:\n\t"
3968			    "new status=0x%x change=0x%x was_conn=0x%x ",
3969			    port, status, change, was_connected);
3970
3971			/* Recover a disabled port */
3972			if (change & PORT_CHANGE_PESC) {
3973				USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG,
3974				    hubd->h_log_handle,
3975				    "port%d Disabled - "
3976				    "status=0x%x, change=0x%x",
3977				    port, status, change);
3978
3979				/*
3980				 * if the port was connected and is still
3981				 * connected, recover the port
3982				 */
3983				if (was_connected && (status &
3984				    PORT_STATUS_CCS)) {
3985					online_child |=
3986					    (hubd_recover_disabled_port(hubd,
3987					    port) == USB_SUCCESS);
3988				}
3989			}
3990
3991			/*
3992			 * Now check what changed on the port
3993			 */
3994			if ((change & PORT_CHANGE_CSC) || attach_flg) {
3995				if ((status & PORT_STATUS_CCS) &&
3996				    (!was_connected)) {
3997					/* new device plugged in */
3998					online_child |=
3999					    (hubd_handle_port_connect(hubd,
4000					    port) == USB_SUCCESS);
4001
4002				} else if ((status & PORT_STATUS_CCS) &&
4003				    was_connected) {
4004					/*
4005					 * In this case we can never be sure
4006					 * if the device indeed got hotplugged
4007					 * or the hub is falsely reporting the
4008					 * change.
4009					 */
4010					child_dip = hubd->h_children_dips[port];
4011
4012					mutex_exit(HUBD_MUTEX(hubd));
4013					/*
4014					 * this ensures we do not race with
4015					 * other threads which are detaching
4016					 * the child driver at the same time.
4017					 */
4018					ndi_devi_enter(child_dip, &chld_circ);
4019					/*
4020					 * Now check if the driver remains
4021					 * attached.
4022					 */
4023					if (i_ddi_devi_attached(child_dip)) {
4024						/*
4025						 * first post a disconnect event
4026						 * to the child.
4027						 */
4028						hubd_post_event(hubd, port,
4029						    USBA_EVENT_TAG_HOT_REMOVAL);
4030						mutex_enter(HUBD_MUTEX(hubd));
4031
4032						/*
4033						 * then reset the port and
4034						 * recover the device
4035						 */
4036						online_child |=
4037						    (hubd_handle_port_connect(
4038						    hubd, port) == USB_SUCCESS);
4039
4040						mutex_exit(HUBD_MUTEX(hubd));
4041					}
4042
4043					ndi_devi_exit(child_dip, chld_circ);
4044					mutex_enter(HUBD_MUTEX(hubd));
4045				} else if (was_connected) {
4046					/* this is a disconnect */
4047					mutex_exit(HUBD_MUTEX(hubd));
4048					hubd_post_event(hubd, port,
4049					    USBA_EVENT_TAG_HOT_REMOVAL);
4050					mutex_enter(HUBD_MUTEX(hubd));
4051
4052					offline_child = B_TRUE;
4053				}
4054			}
4055
4056			/*
4057			 * Check if any port is coming out of suspend
4058			 */
4059			if (change & PORT_CHANGE_PSSC) {
4060				/* a resuming device could have disconnected */
4061				if (was_connected &&
4062				    hubd->h_children_dips[port]) {
4063
4064					/* device on this port resuming */
4065					dev_info_t *dip;
4066
4067					dip = hubd->h_children_dips[port];
4068
4069					/*
4070					 * Don't raise power on detaching child
4071					 */
4072					if (!DEVI_IS_DETACHING(dip)) {
4073						/*
4074						 * As this child is not
4075						 * detaching, we set this
4076						 * flag, causing bus_ctls
4077						 * to stall detach till
4078						 * pm_raise_power returns
4079						 * and flag it for a deferred
4080						 * raise_power.
4081						 *
4082						 * pm_raise_power is deferred
4083						 * because we need to release
4084						 * the locks first.
4085						 */
4086						hubd->h_port_state[port] |=
4087						    HUBD_CHILD_RAISE_POWER;
4088						pwrup_child = B_TRUE;
4089						mutex_exit(HUBD_MUTEX(hubd));
4090
4091						/*
4092						 * make sure that child
4093						 * doesn't disappear
4094						 */
4095						ndi_hold_devi(dip);
4096
4097						mutex_enter(HUBD_MUTEX(hubd));
4098					}
4099				}
4100			}
4101
4102			/*
4103			 * Check if the port is over-current
4104			 */
4105			if (change & PORT_CHANGE_OCIC) {
4106				USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG,
4107				    hubd->h_log_handle,
4108				    "Port%d in over current condition, "
4109				    "please check the attached device to "
4110				    "clear the condition. The system will "
4111				    "try to recover the port, but if not "
4112				    "successful, you need to re-connect "
4113				    "the hub or reboot the system to bring "
4114				    "the port back to work", port);
4115
4116				if (!(status & PORT_STATUS_PPS)) {
4117					/*
4118					 * Try to enable port power, but
4119					 * possibly fail. Ignore failure
4120					 */
4121					(void) hubd_enable_port_power(hubd,
4122					    port);
4123
4124					/*
4125					 * Delay some time to avoid
4126					 * over-current event to happen
4127					 * too frequently in some cases
4128					 */
4129					mutex_exit(HUBD_MUTEX(hubd));
4130					delay(drv_usectohz(500000));
4131					mutex_enter(HUBD_MUTEX(hubd));
4132				}
4133			}
4134		}
4135	}
4136
4137	/* release locks so we can do a devfs_clean */
4138	mutex_exit(HUBD_MUTEX(hubd));
4139
4140	/* delete cached dv_node's but drop locks first */
4141	ndi_devi_exit(hdip, circ);
4142	ndi_devi_exit(rh_dip, rh_circ);
4143	ndi_devi_exit(ddi_get_parent(rh_dip), prh_circ);
4144
4145	(void) devfs_clean(rh_dip, NULL, 0);
4146
4147	/* now check if any children need onlining */
4148	if (online_child) {
4149		USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4150		    "hubd_hotplug_thread: onlining children");
4151
4152		(void) ndi_devi_online(hubd->h_dip, 0);
4153	}
4154
4155	/* now check if any disconnected devices need to be cleaned up */
4156	if (offline_child) {
4157		USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4158		    "hubd_hotplug_thread: scheduling cleanup");
4159
4160		hubd_schedule_cleanup(hubd->h_usba_device->usb_root_hub_dip);
4161	}
4162
4163	mutex_enter(HUBD_MUTEX(hubd));
4164
4165	/* now raise power on the children that have woken up */
4166	if (pwrup_child) {
4167		old_state = hubd->h_dev_state;
4168		hubd->h_dev_state = USB_DEV_HUB_CHILD_PWRLVL;
4169		for (port = 1; port <= nports; port++) {
4170			if (hubd->h_port_state[port] & HUBD_CHILD_RAISE_POWER) {
4171				dev_info_t *dip = hubd->h_children_dips[port];
4172
4173				mutex_exit(HUBD_MUTEX(hubd));
4174
4175				/* Get the device to full power */
4176				(void) pm_busy_component(dip, 0);
4177				(void) pm_raise_power(dip, 0,
4178				    USB_DEV_OS_FULL_PWR);
4179				(void) pm_idle_component(dip, 0);
4180
4181				/* release the hold on the child */
4182				ndi_rele_devi(dip);
4183				mutex_enter(HUBD_MUTEX(hubd));
4184				hubd->h_port_state[port] &=
4185				    ~HUBD_CHILD_RAISE_POWER;
4186			}
4187		}
4188		/*
4189		 * make sure that we don't accidentally
4190		 * over write the disconnect state
4191		 */
4192		if (hubd->h_dev_state == USB_DEV_HUB_CHILD_PWRLVL) {
4193			hubd->h_dev_state = old_state;
4194		}
4195	}
4196
4197	/*
4198	 * start polling can immediately kick off read callback
4199	 * we need to set the h_hotplug_thread to 0 so that
4200	 * the callback is not dropped
4201	 *
4202	 * if there is device during reset, still stop polling to avoid the
4203	 * read callback interrupting the reset, the polling will be started
4204	 * in hubd_reset_thread.
4205	 */
4206	for (port = 1; port <= MAX_PORTS; port++) {
4207		if (hubd->h_reset_port[port]) {
4208
4209			break;
4210		}
4211	}
4212	if (port > MAX_PORTS) {
4213		hubd_start_polling(hubd, HUBD_ALWAYS_START_POLLING);
4214	}
4215
4216	/*
4217	 * Earlier we would set the h_hotplug_thread = 0 before
4218	 * polling was restarted  so that
4219	 * if there is any root hub status change interrupt, we can still kick
4220	 * off the hotplug thread. This was valid when this interrupt was
4221	 * delivered in hardware, and only ONE interrupt would be delivered.
4222	 * Now that we poll on the root hub looking for status change in
4223	 * software, this assignment is no longer required.
4224	 */
4225	hubd->h_hotplug_thread--;
4226
4227	/* mark this device as idle */
4228	(void) hubd_pm_idle_component(hubd, hubd->h_dip, 0);
4229
4230	cv_broadcast(&hubd->h_cv_hotplug_dev);
4231
4232	USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4233	    "hubd_hotplug_thread: exit");
4234
4235	mutex_exit(HUBD_MUTEX(hubd));
4236
4237	ndi_rele_devi(hdip);
4238}
4239
4240
4241/*
4242 * hubd_handle_port_connect:
4243 *	Transition a port from Disabled to Enabled.  Ensure that the
4244 *	port is in the correct state before attempting to
4245 *	access the device.
4246 */
4247static int
4248hubd_handle_port_connect(hubd_t *hubd, usb_port_t port)
4249{
4250	int			rval;
4251	int			retry;
4252	long			time_delay;
4253	long			settling_time;
4254	uint16_t		status;
4255	uint16_t		change;
4256	usb_port_status_t	speed;
4257	usb_addr_t		hubd_usb_addr;
4258	usba_device_t		*usba_device;
4259	usb_port_status_t	port_status = 0;
4260	usb_port_status_t	hub_port_status = 0;
4261
4262	/* Get the hub address and port status */
4263	usba_device = hubd->h_usba_device;
4264	mutex_enter(&usba_device->usb_mutex);
4265	hubd_usb_addr = usba_device->usb_addr;
4266	hub_port_status = usba_device->usb_port_status;
4267	mutex_exit(&usba_device->usb_mutex);
4268
4269	/*
4270	 * If a device is connected, transition the
4271	 * port from Disabled to the Enabled state.
4272	 * The device will receive downstream packets
4273	 * in the Enabled state.
4274	 *
4275	 * reset port and wait for the hub to report
4276	 * completion
4277	 */
4278	change = status = 0;
4279
4280	/*
4281	 * According to section 9.1.2 of USB 2.0 spec, the host should
4282	 * wait for atleast 100ms to allow completion of an insertion
4283	 * process and for power at the device to become stable.
4284	 * We wait for 200 ms
4285	 */
4286	settling_time = drv_usectohz(hubd_device_delay / 5);
4287	mutex_exit(HUBD_MUTEX(hubd));
4288	delay(settling_time);
4289	mutex_enter(HUBD_MUTEX(hubd));
4290
4291	/* calculate 600 ms delay time */
4292	time_delay = (6 * drv_usectohz(hubd_device_delay)) / 10;
4293
4294	for (retry = 0; (hubd->h_dev_state == USB_DEV_ONLINE) &&
4295	    (retry < hubd_retry_enumerate); retry++) {
4296		USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4297		    "resetting port%d, retry=%d", port, retry);
4298
4299		if ((rval = hubd_reset_port(hubd, port)) != USB_SUCCESS) {
4300			(void) hubd_determine_port_status(hubd,
4301			    port, &status, &change, &speed, 0);
4302
4303			/* continue only if port is still connected */
4304			if (status & PORT_STATUS_CCS) {
4305				continue;
4306			}
4307
4308			/* carry on regardless */
4309		}
4310
4311		/*
4312		 * according to USB 2.0 spec section 11.24.2.7.1.2
4313		 * at the end of port reset, the hub enables the port.
4314		 * But for some strange reasons, uhci port remains disabled.
4315		 * And because the port remains disabled for the settling
4316		 * time below, the device connected to the port gets wedged
4317		 * - fails to enumerate (device not responding)
4318		 * Hence, we enable it here immediately and later again after
4319		 * the delay
4320		 */
4321		(void) hubd_enable_port(hubd, port);
4322
4323		/* we skip this delay in the first iteration */
4324		if (retry) {
4325			/*
4326			 * delay for device to signal disconnect/connect so
4327			 * that hub properly recognizes the speed of the device
4328			 */
4329			mutex_exit(HUBD_MUTEX(hubd));
4330			delay(settling_time);
4331			mutex_enter(HUBD_MUTEX(hubd));
4332
4333			/*
4334			 * When a low speed device is connected to any port of
4335			 * PPX it has to be explicitly enabled
4336			 * Also, if device intentionally signals
4337			 * disconnect/connect, it will disable the port.
4338			 * So enable it again.
4339			 */
4340			(void) hubd_enable_port(hubd, port);
4341		}
4342
4343		if ((rval = hubd_determine_port_status(hubd, port, &status,
4344		    &change, &speed, 0)) != USB_SUCCESS) {
4345
4346			USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4347			    "getting status failed (%d)", rval);
4348
4349			(void) hubd_disable_port(hubd, port);
4350
4351			continue;
4352		}
4353
4354		if (status & PORT_STATUS_POCI) {
4355			USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4356			    "port %d overcurrent", port);
4357
4358			(void) hubd_disable_port(hubd, port);
4359
4360			/* ack changes */
4361			(void) hubd_determine_port_status(hubd,
4362			    port, &status, &change, &speed, PORT_CHANGE_OCIC);
4363
4364			continue;
4365		}
4366
4367		/* is status really OK? */
4368		if ((status & PORT_STATUS_OK) != PORT_STATUS_OK) {
4369			USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4370			    "port %d status (0x%x) not OK on retry %d",
4371			    port, status, retry);
4372
4373			/* check if we still have the connection */
4374			if (!(status & PORT_STATUS_CCS)) {
4375				/* lost connection, set exit condition */
4376				retry = hubd_retry_enumerate;
4377
4378				break;
4379			}
4380		} else {
4381			port_status = speed;
4382			USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4383			    "creating child port%d, status=0x%x "
4384			    "port status=0x%x",
4385			    port, status, port_status);
4386
4387			/*
4388			 * if the child already exists, set addrs and config
4389			 * to the device post connect event to the child
4390			 */
4391			if (hubd->h_children_dips[port]) {
4392				/* set addrs to this device */
4393				rval = hubd_setdevaddr(hubd, port);
4394
4395				/*
4396				 * This delay is important for the CATC hub
4397				 * to enumerate. But, avoid delay in the first
4398				 * iteration
4399				 */
4400				if (retry) {
4401					mutex_exit(HUBD_MUTEX(hubd));
4402					delay(drv_usectohz(
4403					    hubd_device_delay/100));
4404					mutex_enter(HUBD_MUTEX(hubd));
4405				}
4406
4407				if (rval == USB_SUCCESS) {
4408					/*
4409					 * if the port is resetting, check if
4410					 * device's descriptors have changed.
4411					 */
4412					if ((hubd->h_reset_port[port]) &&
4413					    (hubd_check_same_device(hubd,
4414					    port) != USB_SUCCESS)) {
4415						retry = hubd_retry_enumerate;
4416
4417						break;
4418					}
4419
4420					/*
4421					 * set the default config for
4422					 * this device
4423					 */
4424					hubd_setdevconfig(hubd, port);
4425
4426					/*
4427					 * if we are doing Default reset, do
4428					 * not post reconnect event since we
4429					 * don't know where reset function is
4430					 * called.
4431					 */
4432					if (hubd->h_reset_port[port]) {
4433
4434						return (USB_SUCCESS);
4435					}
4436
4437					/*
4438					 * indicate to the child that
4439					 * it is online again
4440					 */
4441					mutex_exit(HUBD_MUTEX(hubd));
4442					hubd_post_event(hubd, port,
4443					    USBA_EVENT_TAG_HOT_INSERTION);
4444					mutex_enter(HUBD_MUTEX(hubd));
4445
4446					return (USB_SUCCESS);
4447				}
4448			} else {
4449				/*
4450				 * We need to release access here
4451				 * so that busctls on other ports can
4452				 * continue and don't cause a deadlock
4453				 * when busctl and removal of prom node
4454				 * takes concurrently. This also ensures
4455				 * busctls for attach of successfully
4456				 * enumerated devices on other ports can
4457				 * continue concurrently with the process
4458				 * of enumerating the new devices. This
4459				 * reduces the overall boot time of the system.
4460				 */
4461				rval = hubd_create_child(hubd->h_dip,
4462				    hubd,
4463				    hubd->h_usba_device,
4464				    port_status, port,
4465				    retry);
4466				if (rval == USB_SUCCESS) {
4467					usba_update_hotplug_stats(hubd->h_dip,
4468					    USBA_TOTAL_HOTPLUG_SUCCESS|
4469					    USBA_HOTPLUG_SUCCESS);
4470					hubd->h_total_hotplug_success++;
4471
4472					if (retry > 0) {
4473						USB_DPRINTF_L2(
4474						    DPRINT_MASK_HOTPLUG,
4475						    hubd->h_log_handle,
4476						    "device on port %d "
4477						    "enumerated after %d %s",
4478						    port, retry,
4479						    (retry > 1) ? "retries" :
4480						    "retry");
4481
4482					}
4483
4484					return (USB_SUCCESS);
4485				}
4486			}
4487		}
4488
4489		/* wait a while until it settles? */
4490		USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4491		    "disabling port %d again", port);
4492
4493		(void) hubd_disable_port(hubd, port);
4494		if (retry) {
4495			mutex_exit(HUBD_MUTEX(hubd));
4496			delay(time_delay);
4497			mutex_enter(HUBD_MUTEX(hubd));
4498		}
4499
4500		USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4501		    "retrying on port %d", port);
4502	}
4503
4504	if (retry >= hubd_retry_enumerate) {
4505		/*
4506		 * If it is a High Speed Root Hub and connected device
4507		 * Is a Low/Full Speed, it will be handled by USB 1.1
4508		 * Host Controller. In this case, USB 2.0 Host Controller
4509		 * will transfer the ownership of this port to USB 1.1
4510		 * Host Controller. So don't display any error message on
4511		 * the console. Note, this isn't the case for USB 3.x.
4512		 */
4513		if ((hubd_usb_addr == ROOT_HUB_ADDR) &&
4514		    (hub_port_status == USBA_HIGH_SPEED_DEV) &&
4515		    (port_status != USBA_HIGH_SPEED_DEV)) {
4516			USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
4517			    hubd->h_log_handle,
4518			    "hubd_handle_port_connect: Low/Full speed "
4519			    "device is connected to High Speed root hub");
4520		} else {
4521			USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG,
4522			    hubd->h_log_handle,
4523			    "Connecting device on port %d failed", port);
4524		}
4525
4526		(void) hubd_disable_port(hubd, port);
4527		usba_update_hotplug_stats(hubd->h_dip,
4528		    USBA_TOTAL_HOTPLUG_FAILURE|USBA_HOTPLUG_FAILURE);
4529		hubd->h_total_hotplug_failure++;
4530
4531		/*
4532		 * the port should be automagically
4533		 * disabled but just in case, we do
4534		 * it here
4535		 */
4536		(void) hubd_disable_port(hubd, port);
4537
4538		/* ack all changes because we disabled this port */
4539		(void) hubd_determine_port_status(hubd,
4540		    port, &status, &change, NULL, HUBD_ACK_ALL_CHANGES);
4541
4542	}
4543
4544	return (USB_FAILURE);
4545}
4546
4547
4548/*
4549 * hubd_get_hub_status:
4550 */
4551static int
4552hubd_get_hub_status(hubd_t *hubd)
4553{
4554	int		rval;
4555	usb_cr_t	completion_reason;
4556	usb_cb_flags_t	cb_flags;
4557	uint16_t	stword[2];
4558	uint16_t	status;
4559	uint16_t	change;
4560	usb_cfg_descr_t	cfg_descr;
4561	size_t		cfg_length;
4562	uchar_t		*usb_cfg;
4563	uint8_t		MaxPower;
4564	usb_port_t	port;
4565
4566	USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4567	    "hubd_get_hub_status:");
4568
4569	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
4570
4571	if ((hubd_get_hub_status_words(hubd, stword)) != USB_SUCCESS) {
4572
4573		return (USB_FAILURE);
4574	}
4575	status = stword[0];
4576	change = stword[1];
4577
4578	mutex_exit(HUBD_MUTEX(hubd));
4579
4580	/* Obtain the raw configuration descriptor */
4581	usb_cfg = usb_get_raw_cfg_data(hubd->h_dip, &cfg_length);
4582
4583	/* get configuration descriptor */
4584	rval = usb_parse_cfg_descr(usb_cfg, cfg_length,
4585	    &cfg_descr, USB_CFG_DESCR_SIZE);
4586
4587	if (rval != USB_CFG_DESCR_SIZE) {
4588
4589		USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4590		    "get hub configuration descriptor failed.");
4591
4592		mutex_enter(HUBD_MUTEX(hubd));
4593
4594		return (USB_FAILURE);
4595	} else {
4596		MaxPower = cfg_descr.bMaxPower;
4597	}
4598
4599	/* check if local power status changed. */
4600	if (change & C_HUB_LOCAL_POWER_STATUS) {
4601
4602		/*
4603		 * local power has been lost, check the maximum
4604		 * power consumption of current configuration.
4605		 * see USB2.0 spec Table 11-12.
4606		 */
4607		if (status & HUB_LOCAL_POWER_STATUS) {
4608
4609			if (MaxPower == 0) {
4610
4611				/*
4612				 * Self-powered only hub. Because it could
4613				 * not draw any power from USB bus.
4614				 * It can't work well on this condition.
4615				 */
4616				USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG,
4617				    hubd->h_log_handle,
4618				    "local power has been lost, "
4619				    "please disconnect hub");
4620			} else {
4621
4622				/*
4623				 * Bus-powered only or self/bus-powered hub.
4624				 */
4625				USB_DPRINTF_L1(DPRINT_MASK_HOTPLUG,
4626				    hubd->h_log_handle,
4627				    "local power has been lost,"
4628				    "the hub could draw %d"
4629				    " mA power from the USB bus.",
4630				    2*MaxPower);
4631			}
4632
4633		}
4634
4635		USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4636		    "clearing feature C_HUB_LOCAL_POWER ");
4637
4638		if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
4639		    hubd->h_default_pipe,
4640		    HUB_HANDLE_HUB_FEATURE_TYPE,
4641		    USB_REQ_CLEAR_FEATURE,
4642		    CFS_C_HUB_LOCAL_POWER,
4643		    0,
4644		    0,
4645		    NULL, 0,
4646		    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
4647			USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
4648			    hubd->h_log_handle,
4649			    "clear feature C_HUB_LOCAL_POWER "
4650			    "failed (%d 0x%x %d)",
4651			    rval, completion_reason, cb_flags);
4652		}
4653
4654	}
4655
4656	if (change & C_HUB_OVER_CURRENT) {
4657
4658		if (status & HUB_OVER_CURRENT) {
4659
4660			if (usba_is_root_hub(hubd->h_dip)) {
4661				/*
4662				 * The root hub should be automatically
4663				 * recovered when over-current condition is
4664				 * cleared. But there might be exception and
4665				 * need user interaction to recover.
4666				 */
4667				USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG,
4668				    hubd->h_log_handle,
4669				    "Root hub over current condition, "
4670				    "please check your system to clear the "
4671				    "condition as soon as possible. And you "
4672				    "may need to reboot the system to bring "
4673				    "the root hub back to work if it cannot "
4674				    "recover automatically");
4675			} else {
4676				/*
4677				 * The driver would try to recover port power
4678				 * on over current condition. When the recovery
4679				 * fails, the user may still need to offline
4680				 * this hub in order to recover.
4681				 * The port power is automatically disabled,
4682				 * so we won't see disconnects.
4683				 */
4684				USB_DPRINTF_L0(DPRINT_MASK_HOTPLUG,
4685				    hubd->h_log_handle,
4686				    "Hub global over current condition, "
4687				    "please disconnect the devices connected "
4688				    "to the hub to clear the condition. And "
4689				    "you may need to re-connect the hub if "
4690				    "the ports do not work");
4691			}
4692		}
4693
4694		USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
4695		    "clearing feature C_HUB_OVER_CURRENT");
4696
4697		if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
4698		    hubd->h_default_pipe,
4699		    HUB_HANDLE_HUB_FEATURE_TYPE,
4700		    USB_REQ_CLEAR_FEATURE,
4701		    CFS_C_HUB_OVER_CURRENT,
4702		    0,
4703		    0,
4704		    NULL, 0,
4705		    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
4706			USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
4707			    hubd->h_log_handle,
4708			    "clear feature C_HUB_OVER_CURRENT "
4709			    "failed (%d 0x%x %d)",
4710			    rval, completion_reason, cb_flags);
4711		}
4712
4713		/*
4714		 * Try to recover all port power if they are turned off.
4715		 * Don't do this for root hub, but rely on the root hub
4716		 * to recover itself.
4717		 */
4718		if (!usba_is_root_hub(hubd->h_dip)) {
4719
4720			mutex_enter(HUBD_MUTEX(hubd));
4721
4722			/*
4723			 * Only check the power status of the 1st port
4724			 * since all port power status should be the same.
4725			 */
4726			(void) hubd_determine_port_status(hubd, 1, &status,
4727			    &change, NULL, 0);
4728
4729			if (status & PORT_STATUS_PPS) {
4730				return (USB_SUCCESS);
4731			}
4732
4733			for (port = 1; port <= hubd->h_nports; port++) {
4734				(void) hubd_enable_port_power(hubd, port);
4735			}
4736
4737			mutex_exit(HUBD_MUTEX(hubd));
4738
4739			/*
4740			 * Delay some time to avoid over-current event
4741			 * to happen too frequently in some cases
4742			 */
4743			delay(drv_usectohz(500000));
4744		}
4745	}
4746
4747	mutex_enter(HUBD_MUTEX(hubd));
4748
4749	return (USB_SUCCESS);
4750}
4751
4752/*
4753 * Convert a series of USB status requests from USB 2 and USB 3 into a single
4754 * uniform type. We separate out the speed into its own value from both USB 2
4755 * and USB 3 and from there we transform the status to look like a USB 2 one.
4756 */
4757static void
4758hubd_status_uniform(hubd_t *hubd, usb_port_t port, uint16_t *status,
4759    usb_port_status_t *speed)
4760{
4761	uint16_t os = *status;
4762
4763	hubd->h_port_raw[port] = os;
4764
4765	if (hubd->h_usba_device->usb_port_status >= USBA_SUPER_SPEED_DEV) {
4766		/*
4767		 * USB 3 devices are always at super speed when plugged into a
4768		 * super speed hub. However, this is only true if we're talking
4769		 * about actual hubs. This doesn't hold for the root hub, which
4770		 * can support USB 3.x, USB 2.x, and USB 1.x devices operating
4771		 * at different speeds. To handle this, the USB 3 HCD driver
4772		 * (xhci) uses some of the extra status bits to stash the
4773		 * current device's detected speed.
4774		 */
4775		if (usba_is_root_hub(hubd->h_dip)) {
4776			if (speed != NULL) {
4777				*speed = (os & PORT_STATUS_SPMASK_SS) >>
4778				    PORT_STATUS_SPSHIFT_SS;
4779			}
4780		} else {
4781			if (speed != NULL)
4782				*speed = USBA_SUPER_SPEED_DEV;
4783		}
4784
4785		if (os & PORT_STATUS_PPS_SS) {
4786			os &= ~PORT_STATUS_PPS_SS;
4787			os |= PORT_STATUS_PPS;
4788			*status = os;
4789		}
4790	} else {
4791		/*
4792		 * For USB 2, the only thing we need to do is transform the
4793		 * speed.
4794		 */
4795		if (speed == NULL)
4796			return;
4797
4798		if (os & PORT_STATUS_HSDA)
4799			*speed = USBA_HIGH_SPEED_DEV;
4800		else if (os & PORT_STATUS_LSDA)
4801			*speed = USBA_LOW_SPEED_DEV;
4802		else
4803			*speed = USBA_FULL_SPEED_DEV;
4804	}
4805}
4806
4807
4808/*
4809 * Attempt to reset a port. This feels a bit more complicated than it should be
4810 * in part due to how HCD, change status notifications, and the hotplug thread
4811 * might interact. Basically we try to block port changes by using the
4812 * h_port_reset_wait which says we should get signalled rather than kicking off
4813 * the hotplug thread. We'll give this a shot for about 100ms at best.
4814 */
4815static int
4816hubd_reset_port(hubd_t *hubd, usb_port_t port)
4817{
4818	int	rval;
4819	usb_cr_t completion_reason;
4820	usb_cb_flags_t cb_flags;
4821	usb_port_mask_t port_mask = 1 << port;
4822	mblk_t	*data;
4823	uint16_t status;
4824	uint16_t change;
4825	clock_t	delta;
4826	boolean_t first;
4827
4828	USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
4829	    "hubd_reset_port: port=%d", port);
4830
4831	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
4832
4833	hubd->h_port_reset_wait |= port_mask;
4834
4835	mutex_exit(HUBD_MUTEX(hubd));
4836
4837	if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
4838	    hubd->h_default_pipe,
4839	    HUB_HANDLE_PORT_FEATURE_TYPE,
4840	    USB_REQ_SET_FEATURE,
4841	    CFS_PORT_RESET,
4842	    port,
4843	    0,
4844	    NULL, 0,
4845	    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
4846		USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
4847		    "reset port%d failed (%d 0x%x %d)",
4848		    port, completion_reason, cb_flags, rval);
4849
4850		mutex_enter(HUBD_MUTEX(hubd));
4851
4852		return (USB_FAILURE);
4853	}
4854
4855	mutex_enter(HUBD_MUTEX(hubd));
4856
4857	USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
4858	    "waiting on cv for reset completion");
4859
4860	/*
4861	 * wait for port status change event
4862	 */
4863	delta = drv_usectohz(hubd_device_delay / 10);
4864
4865	first = B_TRUE;
4866	for (;;) {
4867		if (delta < 0) {
4868			rval = USB_FAILURE;
4869			break;
4870		}
4871
4872		if (first == B_FALSE)
4873			hubd->h_port_reset_wait |= port_mask;
4874		else
4875			first = B_FALSE;
4876
4877		hubd_start_polling(hubd, HUBD_ALWAYS_START_POLLING);
4878
4879		/*
4880		 * Regardless of the status, we always check to see if the port
4881		 * has been reset.
4882		 */
4883		delta = cv_reltimedwait(&hubd->h_cv_reset_port,
4884		    &hubd->h_mutex, delta, TR_CLOCK_TICK);
4885		if (delta < 0)
4886			hubd->h_port_reset_wait &= ~port_mask;
4887
4888		hubd_stop_polling(hubd);
4889
4890		data = NULL;
4891
4892		/* check status to determine whether reset completed */
4893		mutex_exit(HUBD_MUTEX(hubd));
4894		if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
4895		    hubd->h_default_pipe,
4896		    HUB_GET_PORT_STATUS_TYPE,
4897		    USB_REQ_GET_STATUS,
4898		    0,
4899		    port,
4900		    GET_STATUS_LENGTH,
4901		    &data, 0,
4902		    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
4903			USB_DPRINTF_L2(DPRINT_MASK_PORT,
4904			    hubd->h_log_handle,
4905			    "get status port%d failed (%d 0x%x %d)",
4906			    port, completion_reason, cb_flags, rval);
4907
4908			if (data) {
4909				freemsg(data);
4910				data = NULL;
4911			}
4912			mutex_enter(HUBD_MUTEX(hubd));
4913
4914			continue;
4915		}
4916
4917		status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
4918		change = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2);
4919
4920		freemsg(data);
4921
4922		hubd_status_uniform(hubd, port, &status, NULL);
4923
4924		/* continue only if port is still connected */
4925		if (!(status & PORT_STATUS_CCS)) {
4926
4927			/* lost connection, set exit condition */
4928			delta = -1;
4929
4930			mutex_enter(HUBD_MUTEX(hubd));
4931
4932			break;
4933		}
4934
4935		if (status & PORT_STATUS_PRS) {
4936			USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
4937			    "port%d reset active", port);
4938			mutex_enter(HUBD_MUTEX(hubd));
4939
4940			continue;
4941		} else {
4942			USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
4943			    "port%d reset inactive", port);
4944		}
4945
4946		if (change & PORT_CHANGE_PRSC) {
4947			USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
4948			    "clearing feature CFS_C_PORT_RESET");
4949
4950			if (usb_pipe_sync_ctrl_xfer(hubd->h_dip,
4951			    hubd->h_default_pipe,
4952			    HUB_HANDLE_PORT_FEATURE_TYPE,
4953			    USB_REQ_CLEAR_FEATURE,
4954			    CFS_C_PORT_RESET,
4955			    port,
4956			    0,
4957			    NULL, 0,
4958			    &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
4959				USB_DPRINTF_L2(DPRINT_MASK_PORT,
4960				    hubd->h_log_handle,
4961				    "clear feature CFS_C_PORT_RESET"
4962				    " port%d failed (%d 0x%x %d)",
4963				    port, completion_reason, cb_flags, rval);
4964			}
4965		}
4966
4967		/*
4968		 * In addition to a normal reset, a warm reset may have
4969		 * happened. Acknowledge that as well.
4970		 */
4971		if (change & PORT_CHANGE_BHPR) {
4972			USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
4973			    "clearing feature CFS_C_BH_PORT_RESET");
4974
4975			if (usb_pipe_sync_ctrl_xfer(hubd->h_dip,
4976			    hubd->h_default_pipe,
4977			    HUB_HANDLE_PORT_FEATURE_TYPE,
4978			    USB_REQ_CLEAR_FEATURE,
4979			    CFS_C_BH_PORT_RESET,
4980			    port,
4981			    0,
4982			    NULL, 0,
4983			    &completion_reason, &cb_flags, 0) != USB_SUCCESS) {
4984				USB_DPRINTF_L2(DPRINT_MASK_PORT,
4985				    hubd->h_log_handle,
4986				    "clear feature CFS_C_BH_PORT_RESET"
4987				    " port%d failed (%d 0x%x %d)",
4988				    port, completion_reason, cb_flags, rval);
4989			}
4990		}
4991
4992		rval = USB_SUCCESS;
4993		mutex_enter(HUBD_MUTEX(hubd));
4994
4995		break;
4996	}
4997
4998	return (rval);
4999}
5000
5001
5002/*
5003 * hubd_enable_port:
5004 *	this may fail if the hub as been disconnected
5005 */
5006static int
5007hubd_enable_port(hubd_t *hubd, usb_port_t port)
5008{
5009	int	rval;
5010	usb_cr_t completion_reason;
5011	usb_cb_flags_t cb_flags;
5012
5013	USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
5014	    "hubd_enable_port: port=%d", port);
5015
5016	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
5017
5018	mutex_exit(HUBD_MUTEX(hubd));
5019
5020	/* Do not issue a SetFeature(PORT_ENABLE) on external hubs */
5021	if (!usba_is_root_hub(hubd->h_dip)) {
5022		mutex_enter(HUBD_MUTEX(hubd));
5023
5024		return (USB_SUCCESS);
5025	}
5026
5027	if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5028	    hubd->h_default_pipe,
5029	    HUB_HANDLE_PORT_FEATURE_TYPE,
5030	    USB_REQ_SET_FEATURE,
5031	    CFS_PORT_ENABLE,
5032	    port,
5033	    0,
5034	    NULL, 0,
5035	    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
5036		USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
5037		    "enable port%d failed (%d 0x%x %d)",
5038		    port, completion_reason, cb_flags, rval);
5039	}
5040
5041	mutex_enter(HUBD_MUTEX(hubd));
5042
5043	USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
5044	    "enabling port done");
5045
5046	return (rval);
5047}
5048
5049
5050/*
5051 * hubd_disable_port
5052 */
5053static int
5054hubd_disable_port(hubd_t *hubd, usb_port_t port)
5055{
5056	int	rval;
5057	usb_cr_t completion_reason;
5058	usb_cb_flags_t cb_flags;
5059
5060	USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
5061	    "hubd_disable_port: port=%d", port);
5062
5063	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
5064
5065	mutex_exit(HUBD_MUTEX(hubd));
5066
5067	if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5068	    hubd->h_default_pipe,
5069	    HUB_HANDLE_PORT_FEATURE_TYPE,
5070	    USB_REQ_CLEAR_FEATURE,
5071	    CFS_PORT_ENABLE,
5072	    port,
5073	    0,
5074	    NULL, 0,
5075	    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
5076		USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
5077		    "disable port%d failed (%d 0x%x %d)", port,
5078		    completion_reason, cb_flags, rval);
5079		mutex_enter(HUBD_MUTEX(hubd));
5080
5081		return (USB_FAILURE);
5082	}
5083
5084	USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5085	    "clearing feature CFS_C_PORT_ENABLE");
5086
5087	if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5088	    hubd->h_default_pipe,
5089	    HUB_HANDLE_PORT_FEATURE_TYPE,
5090	    USB_REQ_CLEAR_FEATURE,
5091	    CFS_C_PORT_ENABLE,
5092	    port,
5093	    0,
5094	    NULL, 0,
5095	    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
5096		USB_DPRINTF_L2(DPRINT_MASK_PORT,
5097		    hubd->h_log_handle,
5098		    "clear feature CFS_C_PORT_ENABLE port%d failed "
5099		    "(%d 0x%x %d)",
5100		    port, completion_reason, cb_flags, rval);
5101
5102		mutex_enter(HUBD_MUTEX(hubd));
5103
5104		return (USB_FAILURE);
5105	}
5106
5107	mutex_enter(HUBD_MUTEX(hubd));
5108
5109	return (USB_SUCCESS);
5110}
5111
5112
5113/*
5114 * hubd_determine_port_status:
5115 */
5116static int
5117hubd_determine_port_status(hubd_t *hubd, usb_port_t port, uint16_t *status,
5118    uint16_t *change, usb_port_status_t *speed, uint_t ack_flag)
5119{
5120	int rval;
5121	mblk_t	*data = NULL;
5122	usb_cr_t completion_reason;
5123	usb_cb_flags_t cb_flags;
5124	uint16_t st, ch;
5125	usb_port_status_t sp;
5126
5127	if (status == NULL)
5128		status = &st;
5129	if (change == NULL)
5130		change = &ch;
5131	if (speed == NULL)
5132		speed = &sp;
5133
5134	*status = *change = 0;
5135	*speed = 0;
5136
5137	USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
5138	    "hubd_determine_port_status: port=%d, state=0x%x ack=0x%x", port,
5139	    hubd->h_port_state[port], ack_flag);
5140
5141	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
5142
5143	mutex_exit(HUBD_MUTEX(hubd));
5144
5145	if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5146	    hubd->h_default_pipe,
5147	    HUB_GET_PORT_STATUS_TYPE,
5148	    USB_REQ_GET_STATUS,
5149	    0,
5150	    port,
5151	    GET_STATUS_LENGTH,
5152	    &data, 0,
5153	    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
5154		USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
5155		    "port=%d get status failed (%d 0x%x %d)",
5156		    port, completion_reason, cb_flags, rval);
5157
5158		if (data) {
5159			freemsg(data);
5160		}
5161
5162		mutex_enter(HUBD_MUTEX(hubd));
5163
5164		return (rval);
5165	}
5166
5167	mutex_enter(HUBD_MUTEX(hubd));
5168	if (MBLKL(data) != GET_STATUS_LENGTH) {
5169		USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
5170		    "port %d: length incorrect %ld",
5171		    port, MBLKL(data));
5172		freemsg(data);
5173
5174		return (rval);
5175	}
5176
5177
5178	*status = (*(data->b_rptr + 1) << 8) | *(data->b_rptr);
5179	*change = (*(data->b_rptr + 3) << 8) | *(data->b_rptr + 2);
5180	hubd_status_uniform(hubd, port, status, speed);
5181
5182	USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5183	    "port%d status=0x%x, change=0x%x", port, *status, *change);
5184
5185	freemsg(data);
5186
5187	if (*status & PORT_STATUS_CCS) {
5188		USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5189		    "port%d connected", port);
5190
5191		hubd->h_port_state[port] |= (PORT_STATUS_CCS & ack_flag);
5192	} else {
5193		USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5194		    "port%d disconnected", port);
5195
5196		hubd->h_port_state[port] &= ~(PORT_STATUS_CCS & ack_flag);
5197	}
5198
5199	if (*status & PORT_STATUS_PES) {
5200		USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5201		    "port%d enabled", port);
5202
5203		hubd->h_port_state[port] |= (PORT_STATUS_PES & ack_flag);
5204	} else {
5205		USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5206		    "port%d disabled", port);
5207
5208		hubd->h_port_state[port] &= ~(PORT_STATUS_PES & ack_flag);
5209	}
5210
5211	if (*status & PORT_STATUS_PSS) {
5212		USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5213		    "port%d suspended", port);
5214
5215		hubd->h_port_state[port] |= (PORT_STATUS_PSS & ack_flag);
5216	} else {
5217		USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5218		    "port%d not suspended", port);
5219
5220		hubd->h_port_state[port] &= ~(PORT_STATUS_PSS & ack_flag);
5221	}
5222
5223	if (*change & PORT_CHANGE_PRSC) {
5224		USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5225		    "port%d reset completed", port);
5226
5227		hubd->h_port_state[port] |= (PORT_CHANGE_PRSC & ack_flag);
5228	} else {
5229
5230		hubd->h_port_state[port] &= ~(PORT_CHANGE_PRSC & ack_flag);
5231	}
5232
5233	if (*status & PORT_STATUS_POCI) {
5234		USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
5235		    "port%d overcurrent!", port);
5236
5237		hubd->h_port_state[port] |= (PORT_STATUS_POCI & ack_flag);
5238	} else {
5239
5240		hubd->h_port_state[port] &= ~(PORT_STATUS_POCI & ack_flag);
5241	}
5242
5243	if (*status & PORT_STATUS_PRS) {
5244		USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5245		    "port%d reset active", port);
5246
5247		hubd->h_port_state[port] |= (PORT_STATUS_PRS & ack_flag);
5248	} else {
5249		USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5250		    "port%d reset inactive", port);
5251
5252		hubd->h_port_state[port] &= ~(PORT_STATUS_PRS & ack_flag);
5253	}
5254	if (*status & PORT_STATUS_PPS) {
5255		USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5256		    "port%d power on", port);
5257
5258		hubd->h_port_state[port] |= (PORT_STATUS_PPS & ack_flag);
5259	} else {
5260		USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5261		    "port%d power off", port);
5262
5263		hubd->h_port_state[port] &= ~(PORT_STATUS_PPS & ack_flag);
5264	}
5265
5266	/*
5267	 * Acknowledge connection, enable, reset status
5268	 */
5269	if (ack_flag) {
5270		mutex_exit(HUBD_MUTEX(hubd));
5271		if (*change & PORT_CHANGE_CSC & ack_flag) {
5272			USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5273			    "clearing feature CFS_C_PORT_CONNECTION");
5274			if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5275			    hubd->h_default_pipe,
5276			    HUB_HANDLE_PORT_FEATURE_TYPE,
5277			    USB_REQ_CLEAR_FEATURE,
5278			    CFS_C_PORT_CONNECTION,
5279			    port,
5280			    0, NULL, 0,
5281			    &completion_reason, &cb_flags, 0)) !=
5282			    USB_SUCCESS) {
5283				USB_DPRINTF_L2(DPRINT_MASK_PORT,
5284				    hubd->h_log_handle,
5285				    "clear feature CFS_C_PORT_CONNECTION"
5286				    " port%d failed (%d 0x%x %d)",
5287				    port, completion_reason, cb_flags, rval);
5288			}
5289		}
5290		if (*change & PORT_CHANGE_PESC & ack_flag) {
5291			USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5292			    "clearing feature CFS_C_PORT_ENABLE");
5293			if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5294			    hubd->h_default_pipe,
5295			    HUB_HANDLE_PORT_FEATURE_TYPE,
5296			    USB_REQ_CLEAR_FEATURE,
5297			    CFS_C_PORT_ENABLE,
5298			    port,
5299			    0, NULL, 0,
5300			    &completion_reason, &cb_flags, 0)) !=
5301			    USB_SUCCESS) {
5302				USB_DPRINTF_L2(DPRINT_MASK_PORT,
5303				    hubd->h_log_handle,
5304				    "clear feature CFS_C_PORT_ENABLE"
5305				    " port%d failed (%d 0x%x %d)",
5306				    port, completion_reason, cb_flags, rval);
5307			}
5308		}
5309		if (*change & PORT_CHANGE_PSSC & ack_flag) {
5310			USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5311			    "clearing feature CFS_C_PORT_SUSPEND");
5312
5313			if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5314			    hubd->h_default_pipe,
5315			    HUB_HANDLE_PORT_FEATURE_TYPE,
5316			    USB_REQ_CLEAR_FEATURE,
5317			    CFS_C_PORT_SUSPEND,
5318			    port,
5319			    0, NULL, 0,
5320			    &completion_reason, &cb_flags, 0)) !=
5321			    USB_SUCCESS) {
5322				USB_DPRINTF_L2(DPRINT_MASK_PORT,
5323				    hubd->h_log_handle,
5324				    "clear feature CFS_C_PORT_SUSPEND"
5325				    " port%d failed (%d 0x%x %d)",
5326				    port, completion_reason, cb_flags, rval);
5327			}
5328		}
5329		if (*change & PORT_CHANGE_OCIC & ack_flag) {
5330			USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5331			    "clearing feature CFS_C_PORT_OVER_CURRENT");
5332
5333			if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5334			    hubd->h_default_pipe,
5335			    HUB_HANDLE_PORT_FEATURE_TYPE,
5336			    USB_REQ_CLEAR_FEATURE,
5337			    CFS_C_PORT_OVER_CURRENT,
5338			    port,
5339			    0, NULL, 0,
5340			    &completion_reason, &cb_flags, 0)) !=
5341			    USB_SUCCESS) {
5342				USB_DPRINTF_L2(DPRINT_MASK_PORT,
5343				    hubd->h_log_handle,
5344				    "clear feature CFS_C_PORT_OVER_CURRENT"
5345				    " port%d failed (%d 0x%x %d)",
5346				    port, completion_reason, cb_flags, rval);
5347			}
5348		}
5349		if (*change & PORT_CHANGE_PRSC & ack_flag) {
5350			USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5351			    "clearing feature CFS_C_PORT_RESET");
5352			if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5353			    hubd->h_default_pipe,
5354			    HUB_HANDLE_PORT_FEATURE_TYPE,
5355			    USB_REQ_CLEAR_FEATURE,
5356			    CFS_C_PORT_RESET,
5357			    port,
5358			    0, NULL, 0,
5359			    &completion_reason, &cb_flags, 0)) !=
5360			    USB_SUCCESS) {
5361				USB_DPRINTF_L2(DPRINT_MASK_PORT,
5362				    hubd->h_log_handle,
5363				    "clear feature CFS_C_PORT_RESET"
5364				    " port%d failed (%d 0x%x %d)",
5365				    port, completion_reason, cb_flags, rval);
5366			}
5367		}
5368		if (*change & PORT_CHANGE_BHPR & ack_flag) {
5369			USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5370			    "clearing feature CFS_C_BH_PORT_RESET");
5371			if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5372			    hubd->h_default_pipe,
5373			    HUB_HANDLE_PORT_FEATURE_TYPE,
5374			    USB_REQ_CLEAR_FEATURE,
5375			    CFS_C_BH_PORT_RESET,
5376			    port,
5377			    0, NULL, 0,
5378			    &completion_reason, &cb_flags, 0)) !=
5379			    USB_SUCCESS) {
5380				USB_DPRINTF_L2(DPRINT_MASK_PORT,
5381				    hubd->h_log_handle,
5382				    "clear feature CFS_C_BH_PORT_RESET"
5383				    " port%d failed (%d 0x%x %d)",
5384				    port, completion_reason, cb_flags, rval);
5385			}
5386		}
5387		if (*change & PORT_CHANGE_PLSC & ack_flag) {
5388			USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5389			    "clearing feature CFS_C_PORT_LINK_STATE");
5390			if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5391			    hubd->h_default_pipe,
5392			    HUB_HANDLE_PORT_FEATURE_TYPE,
5393			    USB_REQ_CLEAR_FEATURE,
5394			    CFS_C_PORT_LINK_STATE,
5395			    port,
5396			    0, NULL, 0,
5397			    &completion_reason, &cb_flags, 0)) !=
5398			    USB_SUCCESS) {
5399				USB_DPRINTF_L2(DPRINT_MASK_PORT,
5400				    hubd->h_log_handle,
5401				    "clear feature CFS_C_PORT_LINK_STATE"
5402				    " port%d failed (%d 0x%x %d)",
5403				    port, completion_reason, cb_flags, rval);
5404			}
5405		}
5406		if (*change & PORT_CHANGE_PCE & ack_flag) {
5407			USB_DPRINTF_L3(DPRINT_MASK_PORT, hubd->h_log_handle,
5408			    "clearing feature CFS_C_PORT_CONFIG_ERROR");
5409			if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5410			    hubd->h_default_pipe,
5411			    HUB_HANDLE_PORT_FEATURE_TYPE,
5412			    USB_REQ_CLEAR_FEATURE,
5413			    CFS_C_PORT_CONFIG_ERROR,
5414			    port,
5415			    0, NULL, 0,
5416			    &completion_reason, &cb_flags, 0)) !=
5417			    USB_SUCCESS) {
5418				USB_DPRINTF_L2(DPRINT_MASK_PORT,
5419				    hubd->h_log_handle,
5420				    "clear feature CFS_C_PORT_CONFIG_ERROR"
5421				    " port%d failed (%d 0x%x %d)",
5422				    port, completion_reason, cb_flags, rval);
5423			}
5424		}
5425		mutex_enter(HUBD_MUTEX(hubd));
5426	}
5427
5428	USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
5429	    "new port%d state 0x%x", port, hubd->h_port_state[port]);
5430
5431
5432	return (USB_SUCCESS);
5433}
5434
5435
5436/*
5437 * hubd_recover_disabled_port
5438 * if the port got disabled because of an error
5439 * enable it. If hub doesn't suport enable port,
5440 * reset the port to bring the device to life again
5441 */
5442static int
5443hubd_recover_disabled_port(hubd_t *hubd, usb_port_t port)
5444{
5445	uint16_t	status;
5446	uint16_t	change;
5447	int		rval = USB_FAILURE;
5448
5449	/* first try enabling the port */
5450	(void) hubd_enable_port(hubd, port);
5451
5452	/* read the port status */
5453	(void) hubd_determine_port_status(hubd, port, &status, &change, NULL,
5454	    PORT_CHANGE_PESC);
5455
5456	if (status & PORT_STATUS_PES) {
5457		USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5458		    "Port%d now Enabled", port);
5459	} else if (status & PORT_STATUS_CCS) {
5460		/* first post a disconnect event to the child */
5461		mutex_exit(HUBD_MUTEX(hubd));
5462		hubd_post_event(hubd, port, USBA_EVENT_TAG_HOT_REMOVAL);
5463		mutex_enter(HUBD_MUTEX(hubd));
5464
5465		/* then reset the port and recover the device */
5466		rval = hubd_handle_port_connect(hubd, port);
5467
5468		USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5469		    "Port%d now Enabled by force", port);
5470	}
5471
5472	return (rval);
5473}
5474
5475
5476/*
5477 * hubd_enable_all_port_power:
5478 */
5479static int
5480hubd_enable_all_port_power(hubd_t *hubd)
5481{
5482	int		wait;
5483	usb_port_t	port;
5484	uint_t		retry;
5485	uint16_t	status;
5486	uint16_t	change;
5487
5488	USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
5489	    "hubd_enable_all_port_power");
5490
5491	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
5492
5493	/*
5494	 * According to section 11.11 of USB, for hubs with no power
5495	 * switches, bPwrOn2PwrGood is zero. But we wait for some
5496	 * arbitrary time to enable power to become stable.
5497	 *
5498	 * If an hub supports port power switching, we need to wait
5499	 * at least 20ms before accessing corresponding usb port. Note,
5500	 * this member is stored in the h_power_good member.
5501	 */
5502	if ((hubd->h_hub_chars & HUB_CHARS_NO_POWER_SWITCHING) ||
5503	    (hubd->h_power_good == 0)) {
5504		wait = hubd_device_delay / 10;
5505	} else {
5506		wait = max(HUB_DEFAULT_POPG,
5507		    hubd->h_power_good) * 2 * 1000;
5508	}
5509
5510	USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
5511	    "hubd_enable_all_port_power: popg=%d wait=%d",
5512	    hubd->h_power_good, wait);
5513
5514	/*
5515	 * Enable power per port. we ignore gang power and power mask
5516	 * and always enable all ports one by one.
5517	 */
5518	for (port = 1; port <= hubd->h_nports; port++) {
5519		/*
5520		 * Transition the port from the Powered Off to the
5521		 * Disconnected state by supplying power to the port.
5522		 */
5523		USB_DPRINTF_L4(DPRINT_MASK_PORT,
5524		    hubd->h_log_handle,
5525		    "hubd_enable_all_port_power: power port=%d", port);
5526
5527		(void) hubd_enable_port_power(hubd, port);
5528	}
5529
5530	mutex_exit(HUBD_MUTEX(hubd));
5531	delay(drv_usectohz(wait));
5532	mutex_enter(HUBD_MUTEX(hubd));
5533
5534	/* For retry if any, use some extra delay */
5535	wait = max(wait, hubd_device_delay / 10);
5536
5537	/* Check each port power status for a given usb hub */
5538	for (port = 1; port <= hubd->h_nports; port++) {
5539
5540		/* Get port status */
5541		(void) hubd_determine_port_status(hubd, port,
5542		    &status, &change, NULL, 0);
5543
5544		for (retry = 0; ((!(status & PORT_STATUS_PPS)) &&
5545		    (retry < HUBD_PORT_RETRY)); retry++) {
5546
5547			USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
5548			    "Retry is in progress %d: port %d status %d",
5549			    retry, port, status);
5550
5551			(void) hubd_enable_port_power(hubd, port);
5552
5553			mutex_exit(HUBD_MUTEX(hubd));
5554			delay(drv_usectohz(wait));
5555			mutex_enter(HUBD_MUTEX(hubd));
5556
5557			/* Get port status */
5558			(void) hubd_determine_port_status(hubd, port,
5559			    &status, &change, NULL, 0);
5560		}
5561
5562		/* Print warning message if port has no power */
5563		if (!(status & PORT_STATUS_PPS)) {
5564
5565			USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
5566			    "hubd_enable_all_port_power: port %d power-on "
5567			    "failed, port status 0x%x", port, status);
5568		}
5569	}
5570
5571	return (USB_SUCCESS);
5572}
5573
5574
5575/*
5576 * hubd_enable_port_power:
5577 *	enable individual port power
5578 */
5579static int
5580hubd_enable_port_power(hubd_t *hubd, usb_port_t port)
5581{
5582	int		rval;
5583	usb_cr_t	completion_reason;
5584	usb_cb_flags_t	cb_flags;
5585
5586	USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
5587	    "hubd_enable_port_power: port=%d", port);
5588
5589	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
5590	ASSERT(hubd->h_default_pipe != 0);
5591
5592	mutex_exit(HUBD_MUTEX(hubd));
5593
5594	if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5595	    hubd->h_default_pipe,
5596	    HUB_HANDLE_PORT_FEATURE_TYPE,
5597	    USB_REQ_SET_FEATURE,
5598	    CFS_PORT_POWER,
5599	    port,
5600	    0, NULL, 0,
5601	    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
5602		USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
5603		    "set port power failed (%d 0x%x %d)",
5604		    completion_reason, cb_flags, rval);
5605		mutex_enter(HUBD_MUTEX(hubd));
5606
5607		return (USB_FAILURE);
5608	} else {
5609		mutex_enter(HUBD_MUTEX(hubd));
5610		hubd->h_port_state[port] |= PORT_STATUS_PPS;
5611
5612		return (USB_SUCCESS);
5613	}
5614}
5615
5616
5617/*
5618 * hubd_disable_all_port_power:
5619 */
5620static int
5621hubd_disable_all_port_power(hubd_t *hubd)
5622{
5623	usb_port_t port;
5624
5625	USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
5626	    "hubd_disable_all_port_power");
5627
5628	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
5629
5630	/*
5631	 * disable power per port, ignore gang power and power mask
5632	 */
5633	for (port = 1; port <= hubd->h_nports; port++) {
5634		(void) hubd_disable_port_power(hubd, port);
5635	}
5636
5637	return (USB_SUCCESS);
5638}
5639
5640
5641/*
5642 * hubd_disable_port_power:
5643 *	disable individual port power
5644 */
5645static int
5646hubd_disable_port_power(hubd_t *hubd, usb_port_t port)
5647{
5648	int		rval;
5649	usb_cr_t	completion_reason;
5650	usb_cb_flags_t	cb_flags;
5651
5652	USB_DPRINTF_L4(DPRINT_MASK_PORT, hubd->h_log_handle,
5653	    "hubd_disable_port_power: port=%d", port);
5654
5655	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
5656
5657	mutex_exit(HUBD_MUTEX(hubd));
5658
5659	if ((rval = usb_pipe_sync_ctrl_xfer(hubd->h_dip,
5660	    hubd->h_default_pipe,
5661	    HUB_HANDLE_PORT_FEATURE_TYPE,
5662	    USB_REQ_CLEAR_FEATURE,
5663	    CFS_PORT_POWER,
5664	    port,
5665	    0, NULL, 0,
5666	    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
5667		USB_DPRINTF_L2(DPRINT_MASK_PORT, hubd->h_log_handle,
5668		    "clearing port%d power failed (%d 0x%x %d)",
5669		    port, completion_reason, cb_flags, rval);
5670
5671		mutex_enter(HUBD_MUTEX(hubd));
5672
5673		return (USB_FAILURE);
5674	} else {
5675
5676		mutex_enter(HUBD_MUTEX(hubd));
5677		ASSERT(completion_reason == 0);
5678		hubd->h_port_state[port] &= ~PORT_STATUS_PPS;
5679
5680		return (USB_SUCCESS);
5681	}
5682}
5683
5684
5685/*
5686 * Search the database of user preferences and find out the preferred
5687 * configuration for this new device
5688 */
5689int
5690hubd_select_device_configuration(hubd_t *hubd, usb_port_t port,
5691    dev_info_t *child_dip, usba_device_t *child_ud)
5692{
5693	char		*pathname = NULL;
5694	char		*tmp_path = NULL;
5695	int		user_conf;
5696	int		pathlen;
5697	usb_dev_descr_t	*usbdev_ptr;
5698	usba_configrec_t *user_pref;
5699
5700	mutex_enter(&child_ud->usb_mutex);
5701	usbdev_ptr = child_ud->usb_dev_descr;
5702	mutex_exit(&child_ud->usb_mutex);
5703
5704	/* try to get pathname for this device */
5705	tmp_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
5706	(void) ddi_pathname(child_dip, tmp_path);
5707
5708	pathlen = strlen(tmp_path) + 32;
5709	pathname = kmem_zalloc(pathlen, KM_SLEEP);
5710
5711	/*
5712	 * We haven't initialized the node and it doesn't have an address
5713	 * yet. Append port number to the physical pathname
5714	 */
5715	(void) sprintf(pathname, "%s@%d", tmp_path, port);
5716
5717	USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5718	    "hubd_select_device_configuration: Device=%s\n\t"
5719	    "Child path=%s",
5720	    usba_get_mfg_prod_sn_str(child_dip, tmp_path, MAXPATHLEN),
5721	    pathname);
5722	kmem_free(tmp_path, MAXPATHLEN);
5723
5724
5725	/* database search for user preferences */
5726	user_pref = usba_devdb_get_user_preferences(usbdev_ptr->idVendor,
5727	    usbdev_ptr->idProduct, child_ud->usb_serialno_str, pathname);
5728
5729	if (user_pref) {
5730		USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5731		    "hubd_select_device_configuration: "
5732		    "usba_devdb_get_user_preferences "
5733		    "return user_conf=%d\npreferred driver=%s path=%s",
5734		    user_pref->cfg_index, user_pref->driver,
5735		    user_pref->pathname);
5736
5737		user_conf = user_pref->cfg_index;
5738
5739		if (user_pref->driver) {
5740			mutex_enter(&child_ud->usb_mutex);
5741			child_ud->usb_preferred_driver = user_pref->driver;
5742			mutex_exit(&child_ud->usb_mutex);
5743		}
5744	} else {
5745		USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5746		    "hubd_select_device_configuration: No match found");
5747
5748		/* select default configuration for this device */
5749		user_conf = USBA_DEV_CONFIG_INDEX_UNDEFINED;
5750	}
5751	kmem_free(pathname, pathlen);
5752
5753	/* if the device has just one configuration, set default value */
5754	if (usbdev_ptr->bNumConfigurations == 1) {
5755		user_conf = USB_DEV_DEFAULT_CONFIG_INDEX;
5756	}
5757
5758	return (user_conf);
5759}
5760
5761
5762/*
5763 * Retrieves config cloud for this configuration
5764 */
5765int
5766hubd_get_this_config_cloud(hubd_t *hubd, dev_info_t *dip,
5767    usba_device_t *child_ud, uint16_t conf_index)
5768{
5769	usb_cfg_descr_t	*confdescr;
5770	mblk_t		*pdata = NULL;
5771	int		rval;
5772	size_t		size;
5773	char		*tmpbuf;
5774	usb_cr_t	completion_reason;
5775	usb_cb_flags_t	cb_flags;
5776	usb_pipe_handle_t	def_ph;
5777
5778	USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5779	    "hubd_get_this_config_cloud: conf_index=%d", conf_index);
5780
5781
5782	/* alloc temporary space for config descriptor */
5783	confdescr = (usb_cfg_descr_t *)kmem_zalloc(USB_CFG_DESCR_SIZE,
5784	    KM_SLEEP);
5785
5786	/* alloc temporary space for string descriptor */
5787	tmpbuf = kmem_zalloc(USB_MAXSTRINGLEN, KM_SLEEP);
5788
5789	def_ph = usba_get_dflt_pipe_handle(dip);
5790
5791	if ((rval = usb_pipe_sync_ctrl_xfer(dip, def_ph,
5792	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
5793	    USB_REQ_GET_DESCR,
5794	    USB_DESCR_TYPE_SETUP_CFG | conf_index,
5795	    0,
5796	    USB_CFG_DESCR_SIZE,
5797	    &pdata,
5798	    0,
5799	    &completion_reason,
5800	    &cb_flags,
5801	    0)) == USB_SUCCESS) {
5802
5803		/* this must be true since we didn't allow data underruns */
5804		if (MBLKL(pdata) != USB_CFG_DESCR_SIZE) {
5805			USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5806			    "device returned incorrect configuration "
5807			    "descriptor size.");
5808
5809			rval = USB_FAILURE;
5810			goto done;
5811		}
5812
5813		/*
5814		 * Parse the configuration descriptor
5815		 */
5816		size = usb_parse_cfg_descr(pdata->b_rptr,
5817		    MBLKL(pdata), confdescr,
5818		    USB_CFG_DESCR_SIZE);
5819
5820		/* if parse cfg descr error, it should return failure */
5821		if (size == USB_PARSE_ERROR) {
5822
5823			if (pdata->b_rptr[1] != USB_DESCR_TYPE_CFG) {
5824				USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
5825				    hubd->h_log_handle,
5826				    "device returned incorrect "
5827				    "configuration descriptor type.");
5828			}
5829			rval = USB_FAILURE;
5830			goto done;
5831		}
5832
5833		if (confdescr->wTotalLength < USB_CFG_DESCR_SIZE) {
5834			USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
5835			    hubd->h_log_handle,
5836			    "device returned incorrect "
5837			    "configuration descriptor size.");
5838
5839			rval = USB_FAILURE;
5840			goto done;
5841		}
5842
5843		freemsg(pdata);
5844		pdata = NULL;
5845
5846		/* Now fetch the complete config cloud */
5847		if ((rval = usb_pipe_sync_ctrl_xfer(dip, def_ph,
5848		    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
5849		    USB_REQ_GET_DESCR,
5850		    USB_DESCR_TYPE_SETUP_CFG | conf_index,
5851		    0,
5852		    confdescr->wTotalLength,
5853		    &pdata,
5854		    0,
5855		    &completion_reason,
5856		    &cb_flags,
5857		    0)) == USB_SUCCESS) {
5858
5859			if (MBLKL(pdata) !=
5860			    confdescr->wTotalLength) {
5861
5862				USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
5863				    hubd->h_log_handle,
5864				    "device returned incorrect "
5865				    "configuration descriptor.");
5866
5867				rval = USB_FAILURE;
5868				goto done;
5869			}
5870
5871			/*
5872			 * copy config descriptor into usba_device
5873			 */
5874			mutex_enter(&child_ud->usb_mutex);
5875			child_ud->usb_cfg_array[conf_index] =
5876			    kmem_alloc(confdescr->wTotalLength, KM_SLEEP);
5877			child_ud->usb_cfg_array_len[conf_index] =
5878			    confdescr->wTotalLength;
5879			bcopy((caddr_t)pdata->b_rptr,
5880			    (caddr_t)child_ud->usb_cfg_array[conf_index],
5881			    confdescr->wTotalLength);
5882			mutex_exit(&child_ud->usb_mutex);
5883
5884			/*
5885			 * retrieve string descriptor describing this
5886			 * configuration
5887			 */
5888			if (confdescr->iConfiguration) {
5889
5890				USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG,
5891				    hubd->h_log_handle,
5892				    "Get conf str descr for config_index=%d",
5893				    conf_index);
5894
5895				/*
5896				 * Now fetch the string descriptor describing
5897				 * this configuration
5898				 */
5899				if ((rval = usb_get_string_descr(dip,
5900				    USB_LANG_ID, confdescr->iConfiguration,
5901				    tmpbuf, USB_MAXSTRINGLEN)) ==
5902				    USB_SUCCESS) {
5903					size = strlen(tmpbuf);
5904					if (size > 0) {
5905						child_ud->usb_cfg_str_descr
5906						    [conf_index] = (char *)
5907						    kmem_zalloc(size + 1,
5908						    KM_SLEEP);
5909						(void) strcpy(
5910						    child_ud->usb_cfg_str_descr
5911						    [conf_index], tmpbuf);
5912					}
5913				} else {
5914					USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
5915					    hubd->h_log_handle,
5916					    "hubd_get_this_config_cloud: "
5917					    "getting config string (%d) "
5918					    "failed",
5919					    confdescr->iConfiguration);
5920
5921					/* ignore this error */
5922					rval = USB_SUCCESS;
5923				}
5924			}
5925		}
5926	}
5927
5928done:
5929	if (rval != USB_SUCCESS) {
5930		USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5931		    "hubd_get_this_config_cloud: "
5932		    "error in retrieving config descriptor for "
5933		    "config index=%d rval=%d cr=%d",
5934		    conf_index, rval, completion_reason);
5935	}
5936
5937	if (pdata) {
5938		freemsg(pdata);
5939		pdata = NULL;
5940	}
5941
5942	kmem_free(confdescr, USB_CFG_DESCR_SIZE);
5943	kmem_free(tmpbuf, USB_MAXSTRINGLEN);
5944
5945	return (rval);
5946}
5947
5948
5949/*
5950 * Retrieves the entire config cloud for all configurations of the device
5951 */
5952int
5953hubd_get_all_device_config_cloud(hubd_t *hubd, dev_info_t *dip,
5954    usba_device_t *child_ud)
5955{
5956	int		rval = USB_SUCCESS;
5957	int		ncfgs;
5958	uint16_t	size;
5959	uint16_t	conf_index;
5960	uchar_t		**cfg_array;
5961	uint16_t	*cfg_array_len;
5962	char		**str_descr;
5963
5964	USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
5965	    "hubd_get_all_device_config_cloud: Start");
5966
5967	/* alloc pointer array for conf. descriptors */
5968	mutex_enter(&child_ud->usb_mutex);
5969	ncfgs = child_ud->usb_n_cfgs;
5970	mutex_exit(&child_ud->usb_mutex);
5971
5972	size = sizeof (uchar_t *) * ncfgs;
5973	cfg_array = kmem_zalloc(size, KM_SLEEP);
5974	cfg_array_len = kmem_zalloc(ncfgs * sizeof (uint16_t), KM_SLEEP);
5975	str_descr = kmem_zalloc(size, KM_SLEEP);
5976
5977	mutex_enter(&child_ud->usb_mutex);
5978	child_ud->usb_cfg_array = cfg_array;
5979	child_ud->usb_cfg_array_len = cfg_array_len;
5980	child_ud->usb_cfg_array_length = size;
5981	child_ud->usb_cfg_array_len_length = ncfgs * sizeof (uint16_t);
5982	child_ud->usb_cfg_str_descr = str_descr;
5983	mutex_exit(&child_ud->usb_mutex);
5984
5985	/* Get configuration descriptor for each configuration */
5986	for (conf_index = 0; (conf_index < ncfgs) &&
5987	    (rval == USB_SUCCESS); conf_index++) {
5988
5989		rval = hubd_get_this_config_cloud(hubd, dip, child_ud,
5990		    conf_index);
5991	}
5992
5993	return (rval);
5994}
5995
5996
5997/*
5998 * hubd_ready_device:
5999 *	Update the usba_device structure
6000 *	Set the given configuration
6001 *	Prepares the device node for driver to online. If an existing
6002 *	OBP node is found, it will switch to the OBP node.
6003 */
6004dev_info_t *
6005hubd_ready_device(hubd_t *hubd, dev_info_t *child_dip, usba_device_t *child_ud,
6006    uint_t config_index)
6007{
6008	usb_cr_t	completion_reason;
6009	usb_cb_flags_t	cb_flags;
6010	size_t		size;
6011	usb_cfg_descr_t	config_descriptor;
6012	usb_pipe_handle_t def_ph;
6013	usba_pipe_handle_data_t	*ph;
6014
6015	USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6016	    "hubd_ready_device: dip=0x%p, user_conf_index=%d",
6017	    (void *)child_dip, config_index);
6018
6019	size = usb_parse_cfg_descr(
6020	    child_ud->usb_cfg_array[config_index], USB_CFG_DESCR_SIZE,
6021	    &config_descriptor, USB_CFG_DESCR_SIZE);
6022	ASSERT(size == USB_CFG_DESCR_SIZE);
6023
6024	def_ph = usba_get_dflt_pipe_handle(child_dip);
6025
6026	/* Set the configuration */
6027	(void) usb_pipe_sync_ctrl_xfer(child_dip, def_ph,
6028	    USB_DEV_REQ_HOST_TO_DEV,
6029	    USB_REQ_SET_CFG,	/* bRequest */
6030	    config_descriptor.bConfigurationValue,	/* wValue */
6031	    0,				/* wIndex */
6032	    0,				/* wLength */
6033	    NULL,
6034	    0,
6035	    &completion_reason,
6036	    &cb_flags,
6037	    0);
6038
6039	mutex_enter(&child_ud->usb_mutex);
6040	child_ud->usb_active_cfg_ndx	= config_index;
6041	child_ud->usb_cfg		= child_ud->usb_cfg_array[config_index];
6042	child_ud->usb_cfg_length	= config_descriptor.wTotalLength;
6043	child_ud->usb_cfg_value		= config_descriptor.bConfigurationValue;
6044	child_ud->usb_n_ifs		= config_descriptor.bNumInterfaces;
6045	child_ud->usb_dip		= child_dip;
6046
6047	child_ud->usb_client_flags	= kmem_zalloc(
6048	    child_ud->usb_n_ifs * USBA_CLIENT_FLAG_SIZE, KM_SLEEP);
6049
6050	child_ud->usb_client_attach_list = kmem_zalloc(
6051	    child_ud->usb_n_ifs *
6052	    sizeof (*child_ud->usb_client_attach_list), KM_SLEEP);
6053
6054	child_ud->usb_client_ev_cb_list = kmem_zalloc(
6055	    child_ud->usb_n_ifs *
6056	    sizeof (*child_ud->usb_client_ev_cb_list), KM_SLEEP);
6057
6058	mutex_exit(&child_ud->usb_mutex);
6059
6060	/* ready the device node */
6061	child_dip = usba_ready_device_node(child_dip);
6062
6063	/* set owner of default pipe to child dip */
6064	ph = usba_get_ph_data(def_ph);
6065	mutex_enter(&ph->p_mutex);
6066	mutex_enter(&ph->p_ph_impl->usba_ph_mutex);
6067	ph->p_ph_impl->usba_ph_dip = ph->p_dip = child_dip;
6068	mutex_exit(&ph->p_ph_impl->usba_ph_mutex);
6069	mutex_exit(&ph->p_mutex);
6070
6071	return (child_dip);
6072}
6073
6074/*
6075 * hubd_create_child
6076 *	- create child dip
6077 *	- open default pipe
6078 *	- get device descriptor
6079 *	- set the address
6080 *	- get device string descriptors
6081 *	- get the entire config cloud (all configurations) of the device
6082 *	- set user preferred configuration
6083 *	- close default pipe
6084 *	- load appropriate driver(s)
6085 */
6086static int
6087hubd_create_child(dev_info_t *dip,
6088    hubd_t		*hubd,
6089    usba_device_t	*hubd_ud,
6090    usb_port_status_t port_status,
6091    usb_port_t	port,
6092    int		iteration)
6093{
6094	dev_info_t		*child_dip = NULL;
6095	usb_dev_descr_t	usb_dev_descr;
6096	int			rval;
6097	usba_device_t		*child_ud = NULL;
6098	usba_device_t		*parent_ud = NULL;
6099	usb_pipe_handle_t	ph = NULL; /* default pipe handle */
6100	mblk_t			*pdata = NULL;
6101	usb_cr_t		completion_reason;
6102	int			user_conf_index;
6103	uint_t			config_index;
6104	usb_cb_flags_t		cb_flags;
6105	uchar_t			address = 0;
6106	uint16_t		length;
6107	size_t			size;
6108	usb_addr_t		parent_usb_addr;
6109	usb_port_t		parent_usb_port;
6110	usba_device_t		*parent_usba_dev;
6111	usb_port_status_t	parent_port_status;
6112	boolean_t		hcd_called = B_FALSE;
6113
6114	USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6115	    "hubd_create_child: port=%d", port);
6116
6117	ASSERT(mutex_owned(HUBD_MUTEX(hubd)));
6118	ASSERT(hubd->h_usba_devices[port] == NULL);
6119
6120	mutex_exit(HUBD_MUTEX(hubd));
6121
6122	/*
6123	 * create a dip which can be used to open the pipe. we set
6124	 * the name after getting the descriptors from the device
6125	 */
6126	rval = usba_create_child_devi(dip,
6127	    "device",		/* driver name */
6128	    hubd_ud->usb_hcdi_ops, /* usba_hcdi ops */
6129	    hubd_ud->usb_root_hub_dip,
6130	    port_status,		/* low speed device */
6131	    child_ud,
6132	    &child_dip);
6133
6134	if (rval != USB_SUCCESS) {
6135
6136		USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6137		    "usb_create_child_devi failed (%d)", rval);
6138
6139		goto fail_cleanup;
6140	}
6141
6142	child_ud = usba_get_usba_device(child_dip);
6143	ASSERT(child_ud != NULL);
6144
6145	parent_ud = hubd->h_usba_device;
6146	mutex_enter(&parent_ud->usb_mutex);
6147	parent_port_status = parent_ud->usb_port_status;
6148
6149	/*
6150	 * To support split transactions, update address and port of high speed
6151	 * hub to which given device is connected.  Note, split transactions
6152	 * only exist for high speed devices.
6153	 */
6154	if (parent_port_status == USBA_HIGH_SPEED_DEV) {
6155		parent_usba_dev = parent_ud;
6156		parent_usb_addr = parent_ud->usb_addr;
6157		parent_usb_port = port;
6158	} else {
6159		parent_usba_dev = parent_ud->usb_hs_hub_usba_dev;
6160		parent_usb_addr = parent_ud->usb_hs_hub_addr;
6161		parent_usb_port = parent_ud->usb_hs_hub_port;
6162	}
6163	mutex_exit(&parent_ud->usb_mutex);
6164
6165	mutex_enter(&child_ud->usb_mutex);
6166	address = child_ud->usb_addr;
6167	child_ud->usb_addr = 0;
6168	child_ud->usb_dev_descr = kmem_alloc(sizeof (usb_dev_descr_t),
6169	    KM_SLEEP);
6170	bzero(&usb_dev_descr, sizeof (usb_dev_descr_t));
6171
6172	switch (port_status) {
6173	case USBA_SUPER_SPEED_DEV:
6174		usb_dev_descr.bMaxPacketSize0 = 9;
6175		break;
6176	case USBA_LOW_SPEED_DEV:
6177		usb_dev_descr.bMaxPacketSize0 = 8;
6178		break;
6179	default:
6180		usb_dev_descr.bMaxPacketSize0 = 64;
6181		break;
6182	}
6183	bcopy(&usb_dev_descr, child_ud->usb_dev_descr,
6184	    sizeof (usb_dev_descr_t));
6185	child_ud->usb_port = port;
6186
6187	/*
6188	 * The parent hub always keeps track of the hub this device is connected
6189	 * to; however, the hs_hub_* variables are only keeping track of the
6190	 * closest high speed hub. Unfortunately, we need both.
6191	 */
6192	child_ud->usb_parent_hub = parent_ud;
6193	child_ud->usb_hs_hub_usba_dev = parent_usba_dev;
6194	child_ud->usb_hs_hub_addr = parent_usb_addr;
6195	child_ud->usb_hs_hub_port = parent_usb_port;
6196	mutex_exit(&child_ud->usb_mutex);
6197
6198	/*
6199	 * Before we open up the default pipe, give the HCD a chance to do
6200	 * something here.
6201	 */
6202	if (child_ud->usb_hcdi_ops->usba_hcdi_device_init != NULL) {
6203		int rval;
6204		void *priv = NULL;
6205
6206		rval = child_ud->usb_hcdi_ops->usba_hcdi_device_init(child_ud,
6207		    port, &priv);
6208		if (rval != USB_SUCCESS) {
6209			USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6210			    "HCD usba_hcdi_Device_init failed (%d)", rval);
6211			goto fail_cleanup;
6212		}
6213
6214		child_ud->usb_hcd_private = priv;
6215		hcd_called = B_TRUE;
6216	}
6217
6218
6219
6220	/* Open the default pipe */
6221	if ((rval = usb_pipe_open(child_dip, NULL, NULL,
6222	    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) != USB_SUCCESS) {
6223		USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6224		    "usb_pipe_open failed (%d)", rval);
6225
6226		goto fail_cleanup;
6227	}
6228
6229	/*
6230	 * get device descriptor
6231	 */
6232	USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6233	    "hubd_create_child: get device descriptor: 64 bytes");
6234
6235	rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
6236	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
6237	    USB_REQ_GET_DESCR,			/* bRequest */
6238	    USB_DESCR_TYPE_SETUP_DEV,		/* wValue */
6239	    0,					/* wIndex */
6240	    64,					/* wLength */
6241	    &pdata, USB_ATTRS_SHORT_XFER_OK,
6242	    &completion_reason, &cb_flags, 0);
6243
6244	/*
6245	 * If this is a full speed device, we cannot assume that its default
6246	 * packet size is 64 bytes, it may be 8 bytes.
6247	 */
6248
6249	if ((rval != USB_SUCCESS) &&
6250	    (!((completion_reason == USB_CR_DATA_OVERRUN) && pdata))) {
6251
6252		/*
6253		 * rval != USB_SUCCESS AND
6254		 * completion_reason != USB_CR_DATA_OVERRUN
6255		 * pdata could be != NULL.
6256		 * Free pdata now to prevent memory leak.
6257		 */
6258		freemsg(pdata);
6259		pdata = NULL;
6260
6261		USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6262		    "hubd_create_child: get device descriptor: 8 bytes");
6263
6264		rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
6265		    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
6266		    USB_REQ_GET_DESCR,			/* bRequest */
6267		    USB_DESCR_TYPE_SETUP_DEV,		/* wValue */
6268		    0,					/* wIndex */
6269		    8,					/* wLength */
6270		    &pdata, USB_ATTRS_NONE,
6271		    &completion_reason, &cb_flags, 0);
6272
6273		if (rval != USB_SUCCESS) {
6274			USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6275			    "getting device descriptor failed (%s 0x%x %d)",
6276			    usb_str_cr(completion_reason), cb_flags, rval);
6277			goto fail_cleanup;
6278		}
6279	} else {
6280		ASSERT(completion_reason == USB_CR_OK);
6281	}
6282
6283	ASSERT(pdata != NULL);
6284
6285	size = usb_parse_dev_descr(
6286	    pdata->b_rptr,
6287	    MBLKL(pdata),
6288	    &usb_dev_descr,
6289	    sizeof (usb_dev_descr_t));
6290
6291	USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6292	    "parsing device descriptor returned %lu", size);
6293
6294	length = *(pdata->b_rptr);
6295	freemsg(pdata);
6296	pdata = NULL;
6297	if (size < 8) {
6298		USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6299		    "get device descriptor returned %lu bytes", size);
6300
6301		goto fail_cleanup;
6302	}
6303
6304	if (length < 8) {
6305		USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6306		    "fail enumeration: bLength=%d", length);
6307
6308		goto fail_cleanup;
6309	}
6310
6311	if (child_ud->usb_hcdi_ops->usba_hcdi_device_address != NULL) {
6312		rval = child_ud->usb_hcdi_ops->usba_hcdi_device_address(
6313		    child_ud);
6314		if (rval != USB_SUCCESS)
6315			goto fail_cleanup;
6316	} else {
6317		/* Set the address of the device */
6318		if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
6319		    USB_DEV_REQ_HOST_TO_DEV,
6320		    USB_REQ_SET_ADDRESS,	/* bRequest */
6321		    address,			/* wValue */
6322		    0,				/* wIndex */
6323		    0,				/* wLength */
6324		    NULL, 0,
6325		    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
6326			char buffer[64];
6327			USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6328			    "setting address failed (cr=%s cb_flags=%s "
6329			    "rval=%d)", usb_str_cr(completion_reason),
6330			    usb_str_cb_flags(cb_flags, buffer, sizeof (buffer)),
6331			    rval);
6332
6333			goto fail_cleanup;
6334		}
6335	}
6336
6337	USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6338	    "set address 0x%x done", address);
6339
6340	/* now close the pipe for addr 0 */
6341	usb_pipe_close(child_dip, ph,
6342	    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
6343
6344	/*
6345	 * This delay is important for the CATC hub to enumerate
6346	 * But, avoid delay in the first iteration
6347	 */
6348	if (iteration) {
6349		delay(drv_usectohz(hubd_device_delay/100));
6350	}
6351
6352	/* assign the address in the usba_device structure */
6353	mutex_enter(&child_ud->usb_mutex);
6354	child_ud->usb_addr = address;
6355	child_ud->usb_no_cpr = 0;
6356	child_ud->usb_port_status = port_status;
6357	/* save this device descriptor */
6358	bcopy(&usb_dev_descr, child_ud->usb_dev_descr,
6359	    sizeof (usb_dev_descr_t));
6360	child_ud->usb_n_cfgs = usb_dev_descr.bNumConfigurations;
6361	mutex_exit(&child_ud->usb_mutex);
6362
6363	/* re-open the pipe for the device with the new address */
6364	if ((rval = usb_pipe_open(child_dip, NULL, NULL,
6365	    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &ph)) != USB_SUCCESS) {
6366		USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6367		    "usb_pipe_open failed (%d)", rval);
6368
6369		goto fail_cleanup;
6370	}
6371
6372	/*
6373	 * Get full device descriptor only if we have not received full
6374	 * device descriptor earlier.
6375	 */
6376	if (size < length) {
6377		USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6378		    "hubd_create_child: get full device descriptor: "
6379		    "%d bytes", length);
6380
6381		if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
6382		    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
6383		    USB_REQ_GET_DESCR,			/* bRequest */
6384		    USB_DESCR_TYPE_SETUP_DEV,		/* wValue */
6385		    0,					/* wIndex */
6386		    length,				/* wLength */
6387		    &pdata, 0,
6388		    &completion_reason, &cb_flags, 0)) != USB_SUCCESS) {
6389			freemsg(pdata);
6390			pdata = NULL;
6391
6392			USB_DPRINTF_L3(DPRINT_MASK_HOTPLUG,
6393			    hubd->h_log_handle,
6394			    "hubd_create_child: get full device descriptor: "
6395			    "64 bytes");
6396
6397			rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
6398			    USB_DEV_REQ_DEV_TO_HOST |
6399			    USB_DEV_REQ_TYPE_STANDARD,
6400			    USB_REQ_GET_DESCR,		/* bRequest */
6401			    USB_DESCR_TYPE_SETUP_DEV,	/* wValue */
6402			    0,				/* wIndex */
6403			    64,				/* wLength */
6404			    &pdata, USB_ATTRS_SHORT_XFER_OK,
6405			    &completion_reason, &cb_flags, 0);
6406
6407			/* we have to trust the data now */
6408			if (pdata) {
6409				int len = *(pdata->b_rptr);
6410
6411				length = MBLKL(pdata);
6412				if (length < len) {
6413
6414					goto fail_cleanup;
6415				}
6416			} else if (rval != USB_SUCCESS) {
6417				USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG,
6418				    hubd->h_log_handle,
6419				    "getting device descriptor failed "
6420				    "(%d 0x%x %d)",
6421				    completion_reason, cb_flags, rval);
6422
6423				goto fail_cleanup;
6424			}
6425		}
6426
6427		size = usb_parse_dev_descr(
6428		    pdata->b_rptr,
6429		    MBLKL(pdata),
6430		    &usb_dev_descr,
6431		    sizeof (usb_dev_descr_t));
6432
6433		USB_DPRINTF_L4(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6434		    "parsing device descriptor returned %lu", size);
6435
6436		/*
6437		 * For now, free the data
6438		 * eventually, each configuration may need to be looked at
6439		 */
6440		freemsg(pdata);
6441		pdata = NULL;
6442
6443		if (size != USB_DEV_DESCR_SIZE) {
6444			USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6445			    "fail enumeration: descriptor size=%lu "
6446			    "expected size=%u", size, USB_DEV_DESCR_SIZE);
6447
6448			goto fail_cleanup;
6449		}
6450
6451		/*
6452		 * save the device descriptor in usba_device since it is needed
6453		 * later on again
6454		 */
6455		mutex_enter(&child_ud->usb_mutex);
6456		bcopy(&usb_dev_descr, child_ud->usb_dev_descr,
6457		    sizeof (usb_dev_descr_t));
6458		child_ud->usb_n_cfgs = usb_dev_descr.bNumConfigurations;
6459		mutex_exit(&child_ud->usb_mutex);
6460	}
6461
6462	if (usb_dev_descr.bNumConfigurations == 0) {
6463		USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6464		    "device descriptor:\n\t"
6465		    "l=0x%x type=0x%x USB=0x%x class=0x%x subclass=0x%x\n\t"
6466		    "protocol=0x%x maxpktsize=0x%x "
6467		    "Vid=0x%x Pid=0x%x rel=0x%x\n\t"
6468		    "Mfg=0x%x P=0x%x sn=0x%x #config=0x%x",
6469		    usb_dev_descr.bLength, usb_dev_descr.bDescriptorType,
6470		    usb_dev_descr.bcdUSB, usb_dev_descr.bDeviceClass,
6471		    usb_dev_descr.bDeviceSubClass,
6472		    usb_dev_descr.bDeviceProtocol,
6473		    usb_dev_descr.bMaxPacketSize0,
6474		    usb_dev_descr.idVendor,
6475		    usb_dev_descr.idProduct, usb_dev_descr.bcdDevice,
6476		    usb_dev_descr.iManufacturer, usb_dev_descr.iProduct,
6477		    usb_dev_descr.iSerialNumber,
6478		    usb_dev_descr.bNumConfigurations);
6479		goto fail_cleanup;
6480	}
6481
6482	/* Read the BOS data */
6483	usba_get_binary_object_store(child_dip, child_ud);
6484
6485	/* get the device string descriptor(s) */
6486	usba_get_dev_string_descrs(child_dip, child_ud);
6487
6488	/* retrieve config cloud for all configurations */
6489	rval = hubd_get_all_device_config_cloud(hubd, child_dip, child_ud);
6490	if (rval != USB_SUCCESS) {
6491		USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6492		    "failed to get configuration descriptor(s)");
6493
6494		goto fail_cleanup;
6495	}
6496
6497	/* get the preferred configuration for this device */
6498	user_conf_index = hubd_select_device_configuration(hubd, port,
6499	    child_dip, child_ud);
6500
6501	/* Check if the user selected configuration index is in range */
6502	if ((user_conf_index >= usb_dev_descr.bNumConfigurations) ||
6503	    (user_conf_index < 0)) {
6504		USB_DPRINTF_L2(DPRINT_MASK_HOTPLUG, hubd->h_log_handle,
6505		    "Configuration index for device idVendor=%d "
6506		    "idProduct=%d is=%d, and is out of range[0..%d]",
6507		    usb_dev_descr.idVendor, usb_dev_descr.idProduct,
6508		    user_conf_index, usb_dev_descr.bNumConfigurations - 1);
6509
6510		/* treat this as user didn't specify configuration */
6511		user_conf_index = USBA_DEV_CONFIG_INDEX_UNDEFINED;
6512	}
6513
6514
6515	/*
6516	 * Warn users of a performance hit if connecting a
6517	 * High Speed behind a 1.1 hub, which is behind a
6518	 * 2.0 port. Don't worry about this for USB 3.x for now.
6519	 */
6520	if ((parent_port_status != USBA_HIGH_SPEED_DEV) &&
6521	    !(usba_is_root_hub(parent_ud->usb_dip)) &&
6522	    (parent_usb_addr)) {
6523
6524		/*
6525		 * Now that we know the root port is a high speed port
6526		 * and that the parent port is not a high speed port,
6527		 * let's find out if the device itself is a high speed
6528		 * device.  If it is a high speed device,
6529		 * USB_DESCR_TYPE_SETUP_DEV_QLF should return a value,
6530		 * otherwise the command will fail.
6531		 */
6532		rval = usb_pipe_sync_ctrl_xfer(child_dip, ph,
6533		    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
6534		    USB_REQ_GET_DESCR,			/* bRequest */
6535		    USB_DESCR_TYPE_SETUP_DEV_QLF,	/* wValue */
6536		    0,					/* wIndex */
6537		    10,					/* wLength */
6538		    &pdata, USB_ATTRS_SHORT_XFER_OK,
6539		    &completion_reason, &cb_flags, 0);
6540
6541		if (pdata) {
6542			freemsg(pdata);
6543			pdata = NULL;
6544		}
6545
6546		/*
6547		 * USB_DESCR_TYPE_SETUP_DEV_QLF query was successful
6548		 * that means this is a high speed device behind a
6549		 * high speed root hub, but running at full speed
6