xref: /illumos-gate/usr/src/uts/common/io/uath/uath.c (revision d48be21240dfd051b689384ce2b23479d757f2d8)
1 /*
2  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright 2019 Joyent, Inc.
8  */
9 
10 /*
11  * Copyright (c) 2006 Sam Leffler, Errno Consulting
12  * Copyright (c) 2008-2009 Weongyo Jeong <weongyo@freebsd.org>
13  * All rights reserved.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer,
20  *    without modification.
21  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
22  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
23  *    redistribution must be conditioned upon including a substantially
24  *    similar Disclaimer requirement for further binary redistribution.
25  *
26  * NO WARRANTY
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
30  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
31  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
32  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
35  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
37  * THE POSSIBILITY OF SUCH DAMAGES.
38  */
39 
40 /*
41  * This driver is distantly derived from a driver of the same name
42  * by Damien Bergamini.  The original copyright is included below:
43  *
44  * Copyright (c) 2006
45  *	Damien Bergamini <damien.bergamini@free.fr>
46  *
47  * Permission to use, copy, modify, and distribute this software for any
48  * purpose with or without fee is hereby granted, provided that the above
49  * copyright notice and this permission notice appear in all copies.
50  *
51  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
52  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
53  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
54  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
55  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
56  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
57  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
58  */
59 
60 
61 #include <sys/types.h>
62 #include <sys/cmn_err.h>
63 #include <sys/strsubr.h>
64 #include <sys/strsun.h>
65 #include <sys/modctl.h>
66 #include <sys/devops.h>
67 #include <sys/byteorder.h>
68 #include <sys/mac_provider.h>
69 #include <sys/mac_wifi.h>
70 #include <sys/net80211.h>
71 
72 #define	USBDRV_MAJOR_VER	2
73 #define	USBDRV_MINOR_VER	0
74 #include <sys/usb/usba.h>
75 #include <sys/usb/usba/usba_types.h>
76 
77 #include "uath_reg.h"
78 #include "uath_var.h"
79 
80 static void *uath_soft_state_p = NULL;
81 
82 /*
83  * Bit flags in the ral_dbg_flags
84  */
85 #define	UATH_DBG_MSG		0x000001
86 #define	UATH_DBG_ERR		0x000002
87 #define	UATH_DBG_USB		0x000004
88 #define	UATH_DBG_TX		0x000008
89 #define	UATH_DBG_RX		0x000010
90 #define	UATH_DBG_FW		0x000020
91 #define	UATH_DBG_TX_CMD		0x000040
92 #define	UATH_DBG_RX_CMD		0x000080
93 #define	UATH_DBG_ALL		0x000fff
94 
95 uint32_t uath_dbg_flags = 0;
96 
97 #ifdef DEBUG
98 #define	UATH_DEBUG \
99 	uath_debug
100 #else
101 #define	UATH_DEBUG(...) (void)(0)
102 #endif
103 
104 /*
105  * Various supported device vendors/products.
106  * UB51: AR5005UG 802.11b/g, UB52: AR5005UX 802.11b/g
107  */
108 #define	UATH_FLAG_PRE_FIRMWARE	(1 << 0)
109 #define	UATH_FLAG_ABG		(1 << 1)
110 #define	UATH_FLAG_ERR		(1 << 2)
111 #define	UATH_DEV(v, p, f)						\
112 	{ { USB_VENDOR_##v, USB_PRODUCT_##v##_##p }, (f) },		\
113 	{ { USB_VENDOR_##v, USB_PRODUCT_##v##_##p##_NF },		\
114 	    (f) | UATH_FLAG_PRE_FIRMWARE }
115 #define	UATH_DEV_UG(v, p)	UATH_DEV(v, p, 0)
116 #define	UATH_DEV_UX(v, p)	UATH_DEV(v, p, UATH_FLAG_ABG)
117 
118 struct uath_devno {
119 	uint16_t vendor_id;
120 	uint16_t product_id;
121 };
122 
123 static const struct uath_type {
124 	struct uath_devno	dev;
125 	uint8_t			flags;
126 } uath_devs[] = {
127 	UATH_DEV_UG(ACCTON,		SMCWUSBTG2),
128 	UATH_DEV_UG(ATHEROS,		AR5523),
129 	UATH_DEV_UG(ATHEROS2,		AR5523_1),
130 	UATH_DEV_UG(ATHEROS2,		AR5523_2),
131 	UATH_DEV_UX(ATHEROS2,		AR5523_3),
132 	UATH_DEV_UG(CONCEPTRONIC,	AR5523_1),
133 	UATH_DEV_UX(CONCEPTRONIC,	AR5523_2),
134 	UATH_DEV_UX(DLINK,		DWLAG122),
135 	UATH_DEV_UX(DLINK,		DWLAG132),
136 	UATH_DEV_UG(DLINK,		DWLG132),
137 	UATH_DEV_UG(GIGASET,		AR5523),
138 	UATH_DEV_UG(GIGASET,		SMCWUSBTG),
139 	UATH_DEV_UG(GLOBALSUN,		AR5523_1),
140 	UATH_DEV_UX(GLOBALSUN,		AR5523_2),
141 	UATH_DEV_UG(IODATA,		USBWNG54US),
142 	UATH_DEV_UG(MELCO,		WLIU2KAMG54),
143 	UATH_DEV_UX(NETGEAR,		WG111U),
144 	UATH_DEV_UG(NETGEAR3,		WG111T),
145 	UATH_DEV_UG(NETGEAR3,		WPN111),
146 	UATH_DEV_UG(PHILIPS,		SNU6500),
147 	UATH_DEV_UX(UMEDIA,		AR5523_2),
148 	UATH_DEV_UG(UMEDIA,		TEW444UBEU),
149 	UATH_DEV_UG(WISTRONNEWEB,	AR5523_1),
150 	UATH_DEV_UX(WISTRONNEWEB,	AR5523_2),
151 	UATH_DEV_UG(ZCOM,		AR5523)
152 };
153 
154 static char uath_fwmod[] = "uathfw";
155 static char uath_binmod[] = "uathbin";
156 
157 /*
158  * Supported rates for 802.11b/g modes (in 500Kbps unit).
159  */
160 static const struct ieee80211_rateset uath_rateset_11b =
161 	{ 4, { 2, 4, 11, 22 } };
162 
163 static const struct ieee80211_rateset uath_rateset_11g =
164 	{ 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
165 
166 /*
167  * device operations
168  */
169 static int uath_attach(dev_info_t *, ddi_attach_cmd_t);
170 static int uath_detach(dev_info_t *, ddi_detach_cmd_t);
171 
172 /*
173  * Module Loading Data & Entry Points
174  */
175 DDI_DEFINE_STREAM_OPS(uath_dev_ops, nulldev, nulldev, uath_attach,
176     uath_detach, nodev, NULL, D_MP, NULL, ddi_quiesce_not_needed);
177 
178 static struct modldrv uath_modldrv = {
179 	&mod_driverops,		/* Type of module.  This one is a driver */
180 	"Atheros AR5523 USB Driver v1.1",	/* short description */
181 	&uath_dev_ops		/* driver specific ops */
182 };
183 
184 static struct modlinkage modlinkage = {
185 	MODREV_1,
186 	(void *)&uath_modldrv,
187 	NULL
188 };
189 
190 static int	uath_m_stat(void *,  uint_t, uint64_t *);
191 static int	uath_m_start(void *);
192 static void	uath_m_stop(void *);
193 static int	uath_m_promisc(void *, boolean_t);
194 static int	uath_m_multicst(void *, boolean_t, const uint8_t *);
195 static int	uath_m_unicst(void *, const uint8_t *);
196 static mblk_t	*uath_m_tx(void *, mblk_t *);
197 static void	uath_m_ioctl(void *, queue_t *, mblk_t *);
198 static int	uath_m_setprop(void *, const char *, mac_prop_id_t,
199 		    uint_t, const void *);
200 static int	uath_m_getprop(void *, const char *, mac_prop_id_t,
201 		    uint_t, void *);
202 static void	uath_m_propinfo(void *, const char *, mac_prop_id_t,
203 		    mac_prop_info_handle_t);
204 
205 static mac_callbacks_t uath_m_callbacks = {
206 	MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
207 	uath_m_stat,
208 	uath_m_start,
209 	uath_m_stop,
210 	uath_m_promisc,
211 	uath_m_multicst,
212 	uath_m_unicst,
213 	uath_m_tx,
214 	NULL,
215 	uath_m_ioctl,
216 	NULL,
217 	NULL,
218 	NULL,
219 	uath_m_setprop,
220 	uath_m_getprop,
221 	uath_m_propinfo
222 };
223 
224 static usb_alt_if_data_t *
225 		uath_lookup_alt_if(usb_client_dev_data_t *,
226 		    uint_t, uint_t, uint_t);
227 static usb_ep_data_t *
228 		uath_lookup_ep_data(dev_info_t *,
229 		    usb_client_dev_data_t *, uint_t, uint_t, uint8_t, uint8_t);
230 static const char *
231 		uath_codename(int code);
232 
233 static uint_t	uath_lookup(uint16_t, uint16_t);
234 static void	uath_list_all_eps(usb_alt_if_data_t *);
235 static int	uath_open_pipes(struct uath_softc *);
236 static void	uath_close_pipes(struct uath_softc *);
237 static int	uath_fw_send(struct uath_softc *,
238 		    usb_pipe_handle_t, const void *, size_t);
239 static int	uath_fw_ack(struct uath_softc *, int);
240 static int	uath_loadsym(ddi_modhandle_t, char *, char **, size_t *);
241 static int	uath_loadfirmware(struct uath_softc *);
242 static int	uath_alloc_cmd_list(struct uath_softc *,
243 		    struct uath_cmd *, int, int);
244 static int	uath_init_cmd_list(struct uath_softc *);
245 static void	uath_free_cmd_list(struct uath_cmd *, int);
246 static int	uath_host_available(struct uath_softc *);
247 static void	uath_get_capability(struct uath_softc *, uint32_t, uint32_t *);
248 static int	uath_get_devcap(struct uath_softc *);
249 static int	uath_get_devstatus(struct uath_softc *,
250 		    uint8_t [IEEE80211_ADDR_LEN]);
251 static int	uath_get_status(struct uath_softc *, uint32_t, void *, int);
252 
253 static void	uath_cmd_lock_init(struct uath_cmd_lock *);
254 static void	uath_cmd_lock_destroy(struct uath_cmd_lock *);
255 static int	uath_cmd_lock_wait(struct uath_cmd_lock *, clock_t);
256 static void	uath_cmd_lock_signal(struct uath_cmd_lock *);
257 
258 static int	uath_cmd_read(struct uath_softc *, uint32_t, const void *,
259 		    int, void *, int, int);
260 static int	uath_cmd_write(struct uath_softc *, uint32_t, const void *,
261 		    int, int);
262 static int	uath_cmdsend(struct uath_softc *, uint32_t,
263 		    const void *, int, void *, int, int);
264 static int	uath_rx_cmd_xfer(struct uath_softc *);
265 static int	uath_tx_cmd_xfer(struct uath_softc *,
266 		    usb_pipe_handle_t, const void *, uint_t);
267 static void	uath_cmd_txeof(usb_pipe_handle_t, struct usb_bulk_req *);
268 static void	uath_cmd_rxeof(usb_pipe_handle_t, usb_bulk_req_t *);
269 static void	uath_cmdeof(struct uath_softc *, struct uath_cmd *);
270 
271 static void	uath_init_data_queue(struct uath_softc *);
272 static int	uath_rx_data_xfer(struct uath_softc *sc);
273 static int	uath_tx_data_xfer(struct uath_softc *, mblk_t *);
274 static void	uath_data_txeof(usb_pipe_handle_t, usb_bulk_req_t *);
275 static void	uath_data_rxeof(usb_pipe_handle_t, usb_bulk_req_t *);
276 
277 static int	uath_create_connection(struct uath_softc *, uint32_t);
278 static int	uath_set_rates(struct uath_softc *,
279 		    const struct ieee80211_rateset *);
280 static int	uath_write_associd(struct uath_softc *);
281 static int	uath_set_ledsteady(struct uath_softc *, int, int);
282 static int	uath_set_ledblink(struct uath_softc *, int, int, int, int);
283 static void	uath_update_rxstat(struct uath_softc *, uint32_t);
284 static int	uath_send(ieee80211com_t *, mblk_t *, uint8_t);
285 static int	uath_reconnect(dev_info_t *);
286 static int	uath_disconnect(dev_info_t *);
287 static int	uath_newstate(struct ieee80211com *, enum ieee80211_state, int);
288 
289 static int	uath_dataflush(struct uath_softc *);
290 static int	uath_cmdflush(struct uath_softc *);
291 static int	uath_flush(struct uath_softc *);
292 static int	uath_set_ledstate(struct uath_softc *, int);
293 static int	uath_set_chan(struct uath_softc *, struct ieee80211_channel *);
294 static int	uath_reset_tx_queues(struct uath_softc *);
295 static int	uath_wme_init(struct uath_softc *);
296 static int	uath_config_multi(struct uath_softc *,
297 		    uint32_t, const void *, int);
298 static void	uath_config(struct uath_softc *, uint32_t, uint32_t);
299 static int	uath_switch_channel(struct uath_softc *,
300 		    struct ieee80211_channel *);
301 static int	uath_set_rxfilter(struct uath_softc *, uint32_t, uint32_t);
302 static int	uath_init_locked(void *);
303 static void	uath_stop_locked(void *);
304 static int	uath_init(struct uath_softc *);
305 static void	uath_stop(struct uath_softc *);
306 static void	uath_resume(struct uath_softc *);
307 
308 static void
309 uath_debug(uint32_t dbg_flags, const int8_t *fmt, ...)
310 {
311 	va_list args;
312 
313 	if (dbg_flags & uath_dbg_flags) {
314 		va_start(args, fmt);
315 		vcmn_err(CE_CONT, fmt, args);
316 		va_end(args);
317 	}
318 }
319 
320 static uint_t
321 uath_lookup(uint16_t vendor_id, uint16_t product_id)
322 {
323 	int i, size;
324 
325 	size = sizeof (uath_devs) / sizeof (struct uath_type);
326 
327 	for (i = 0; i < size; i++) {
328 		if ((vendor_id == uath_devs[i].dev.vendor_id) &&
329 		    (product_id == uath_devs[i].dev.product_id))
330 			return (uath_devs[i].flags);
331 	}
332 	return (UATH_FLAG_ERR);
333 }
334 
335 /*
336  * Return a specific alt_if from the device descriptor tree.
337  */
338 static usb_alt_if_data_t *
339 uath_lookup_alt_if(usb_client_dev_data_t *dev_data, uint_t config,
340     uint_t interface, uint_t alt)
341 {
342 	usb_cfg_data_t *cfg_data;
343 	usb_if_data_t *if_data;
344 	usb_alt_if_data_t *if_alt_data;
345 
346 	/*
347 	 * Assume everything is in the tree for now,
348 	 * (USB_PARSE_LVL_ALL)
349 	 * so we can directly index the array.
350 	 */
351 
352 	/* Descend to configuration, configs are 1-based */
353 	if (config < 1 || config > dev_data->dev_n_cfg)
354 		return (NULL);
355 	cfg_data = &dev_data->dev_cfg[config - 1];
356 
357 	/* Descend to interface */
358 	if (interface > cfg_data->cfg_n_if - 1)
359 		return (NULL);
360 	if_data = &cfg_data->cfg_if[interface];
361 
362 	/* Descend to alt */
363 	if (alt > if_data->if_n_alt - 1)
364 		return (NULL);
365 	if_alt_data = &if_data->if_alt[alt];
366 
367 	return (if_alt_data);
368 }
369 
370 /*
371  * Print all endpoints of an alt_if.
372  */
373 static void
374 uath_list_all_eps(usb_alt_if_data_t *ifalt)
375 {
376 	usb_ep_data_t *ep_data;
377 	usb_ep_descr_t *ep_descr;
378 	int i;
379 
380 	for (i = 0; i < ifalt->altif_n_ep; i++) {
381 		ep_data = &ifalt->altif_ep[i];
382 		ep_descr = &ep_data->ep_descr;
383 		UATH_DEBUG(UATH_DBG_USB,
384 		    "uath: uath_list_all_endpoint: "
385 		    "ep addresa[%x] is %x",
386 		    i, ep_descr->bEndpointAddress);
387 	}
388 }
389 
390 static usb_ep_data_t *
391 uath_lookup_ep_data(dev_info_t *dip,
392     usb_client_dev_data_t *dev_datap,
393     uint_t interface,
394     uint_t alternate,
395     uint8_t address,
396     uint8_t type)
397 {
398 	usb_alt_if_data_t *altif_data;
399 	int i;
400 
401 	if ((dip == NULL) || (dev_datap == NULL))
402 		return (NULL);
403 
404 	altif_data = &dev_datap->dev_curr_cfg->
405 	    cfg_if[interface].if_alt[alternate];
406 
407 	for (i = 0; i < altif_data->altif_n_ep; i++) {
408 		usb_ep_descr_t *ept = &altif_data->altif_ep[i].ep_descr;
409 		uint8_t ept_type = ept->bmAttributes & USB_EP_ATTR_MASK;
410 		uint8_t ept_address = ept->bEndpointAddress;
411 
412 		if (ept->bLength == 0)
413 			continue;
414 		if ((ept_type == type) &&
415 		    ((type == USB_EP_ATTR_CONTROL) || (address == ept_address)))
416 			return (&altif_data->altif_ep[i]);
417 	}
418 	return (NULL);
419 }
420 
421 /*
422  * Open communication pipes.
423  * The following pipes are used by the AR5523:
424  * ep0: 0x81 IN  Rx cmd
425  * ep1: 0x01 OUT Tx cmd
426  * ep2: 0x82 IN  Rx data
427  * ep3: 0x02 OUT Tx data
428  */
429 static int
430 uath_open_pipes(struct uath_softc *sc)
431 {
432 	usb_ep_data_t *ep_node;
433 	usb_ep_descr_t *ep_descr;
434 	usb_pipe_policy_t policy;
435 	int err;
436 
437 #ifdef DEBUG
438 	usb_alt_if_data_t *altif_data;
439 
440 	altif_data = uath_lookup_alt_if(sc->sc_udev, UATH_CONFIG_NO,
441 	    UATH_IFACE_INDEX, UATH_ALT_IF_INDEX);
442 	if (altif_data == NULL) {
443 		UATH_DEBUG(UATH_DBG_ERR, "alt_if not found");
444 		return (USB_FAILURE);
445 	}
446 
447 	uath_list_all_eps(altif_data);
448 #endif
449 
450 	/*
451 	 * XXX pipes numbers are hardcoded because we don't have any way
452 	 * to distinguish the data pipes from the firmware command pipes
453 	 * (both are bulk pipes) using the endpoints descriptors.
454 	 */
455 	ep_node = uath_lookup_ep_data(sc->sc_dev, sc->sc_udev,
456 	    0, 0, 0x81, USB_EP_ATTR_BULK);
457 	ep_descr = &ep_node->ep_descr;
458 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_open_pipes(): "
459 	    "find pipe %x\n", ep_descr->bEndpointAddress);
460 
461 	bzero(&policy, sizeof (usb_pipe_policy_t));
462 	policy.pp_max_async_reqs = UATH_CMD_LIST_COUNT;
463 
464 	err = usb_pipe_open(sc->sc_dev, &ep_node->ep_descr,
465 	    &policy, USB_FLAGS_SLEEP, &sc->rx_cmd_pipe);
466 	if (err != USB_SUCCESS) {
467 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
468 		    "failed to open rx data pipe, err = %x\n",
469 		    err);
470 		goto fail;
471 	}
472 
473 
474 	ep_node = uath_lookup_ep_data(sc->sc_dev, sc->sc_udev,
475 	    0, 0, 0x01, USB_EP_ATTR_BULK);
476 	ep_descr = &ep_node->ep_descr;
477 	UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
478 	    "find pipe %x\n",
479 	    ep_descr->bEndpointAddress);
480 
481 	bzero(&policy, sizeof (usb_pipe_policy_t));
482 	policy.pp_max_async_reqs = UATH_CMD_LIST_COUNT;
483 
484 	err = usb_pipe_open(sc->sc_dev, &ep_node->ep_descr,
485 	    &policy, USB_FLAGS_SLEEP, &sc->tx_cmd_pipe);
486 	if (err != USB_SUCCESS) {
487 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
488 		    "failed to open tx command pipe, err = %x\n",
489 		    err);
490 		goto fail;
491 	}
492 
493 	ep_node = uath_lookup_ep_data(sc->sc_dev, sc->sc_udev,
494 	    0, 0, 0x82, USB_EP_ATTR_BULK);
495 	ep_descr = &ep_node->ep_descr;
496 	UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
497 	    "find pipe %x\n",
498 	    ep_descr->bEndpointAddress);
499 
500 	bzero(&policy, sizeof (usb_pipe_policy_t));
501 	policy.pp_max_async_reqs = UATH_RX_DATA_LIST_COUNT;
502 
503 	err = usb_pipe_open(sc->sc_dev, &ep_node->ep_descr,
504 	    &policy, USB_FLAGS_SLEEP, &sc->rx_data_pipe);
505 	if (err != USB_SUCCESS) {
506 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
507 		    "failed to open tx pipe, err = %x\n",
508 		    err);
509 		goto fail;
510 	}
511 
512 	ep_node = uath_lookup_ep_data(sc->sc_dev, sc->sc_udev,
513 	    0, 0, 0x02, USB_EP_ATTR_BULK);
514 	ep_descr = &ep_node->ep_descr;
515 	UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
516 	    "find pipe %x\n",
517 	    ep_descr->bEndpointAddress);
518 
519 	bzero(&policy, sizeof (usb_pipe_policy_t));
520 	policy.pp_max_async_reqs = UATH_TX_DATA_LIST_COUNT;
521 
522 	err = usb_pipe_open(sc->sc_dev, &ep_node->ep_descr,
523 	    &policy, USB_FLAGS_SLEEP, &sc->tx_data_pipe);
524 	if (err != USB_SUCCESS) {
525 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_open_pipes(): "
526 		    "failed to open rx command pipe, err = %x\n",
527 		    err);
528 		goto fail;
529 	}
530 
531 	return (UATH_SUCCESS);
532 fail:
533 	uath_close_pipes(sc);
534 	return (err);
535 }
536 
537 static void
538 uath_close_pipes(struct uath_softc *sc)
539 {
540 	usb_flags_t flags = USB_FLAGS_SLEEP;
541 
542 	if (sc->rx_cmd_pipe != NULL) {
543 		usb_pipe_reset(sc->sc_dev, sc->rx_cmd_pipe, flags, NULL, 0);
544 		usb_pipe_close(sc->sc_dev, sc->rx_cmd_pipe, flags, NULL, 0);
545 		sc->rx_cmd_pipe = NULL;
546 	}
547 
548 	if (sc->tx_cmd_pipe != NULL) {
549 		usb_pipe_reset(sc->sc_dev, sc->tx_cmd_pipe, flags, NULL, 0);
550 		usb_pipe_close(sc->sc_dev, sc->tx_cmd_pipe, flags, NULL, 0);
551 		sc->tx_cmd_pipe = NULL;
552 	}
553 
554 	if (sc->rx_data_pipe != NULL) {
555 		usb_pipe_reset(sc->sc_dev, sc->rx_data_pipe, flags, NULL, 0);
556 		usb_pipe_close(sc->sc_dev, sc->rx_data_pipe, flags, NULL, 0);
557 		sc->rx_data_pipe = NULL;
558 	}
559 
560 	if (sc->tx_data_pipe != NULL) {
561 		usb_pipe_reset(sc->sc_dev, sc->tx_data_pipe, flags, NULL, 0);
562 		usb_pipe_close(sc->sc_dev, sc->tx_data_pipe, flags, NULL, 0);
563 		sc->tx_data_pipe = NULL;
564 	}
565 
566 }
567 
568 static const char *
569 uath_codename(int code)
570 {
571 #define	N(a)	(sizeof (a)/sizeof (a[0]))
572 	static const char *names[] = {
573 	    "0x00",
574 	    "HOST_AVAILABLE",
575 	    "BIND",
576 	    "TARGET_RESET",
577 	    "TARGET_GET_CAPABILITY",
578 	    "TARGET_SET_CONFIG",
579 	    "TARGET_GET_STATUS",
580 	    "TARGET_GET_STATS",
581 	    "TARGET_START",
582 	    "TARGET_STOP",
583 	    "TARGET_ENABLE",
584 	    "TARGET_DISABLE",
585 	    "CREATE_CONNECTION",
586 	    "UPDATE_CONNECT_ATTR",
587 	    "DELETE_CONNECT",
588 	    "SEND",
589 	    "FLUSH",
590 	    "STATS_UPDATE",
591 	    "BMISS",
592 	    "DEVICE_AVAIL",
593 	    "SEND_COMPLETE",
594 	    "DATA_AVAIL",
595 	    "SET_PWR_MODE",
596 	    "BMISS_ACK",
597 	    "SET_LED_STEADY",
598 	    "SET_LED_BLINK",
599 	    "SETUP_BEACON_DESC",
600 	    "BEACON_INIT",
601 	    "RESET_KEY_CACHE",
602 	    "RESET_KEY_CACHE_ENTRY",
603 	    "SET_KEY_CACHE_ENTRY",
604 	    "SET_DECOMP_MASK",
605 	    "SET_REGULATORY_DOMAIN",
606 	    "SET_LED_STATE",
607 	    "WRITE_ASSOCID",
608 	    "SET_STA_BEACON_TIMERS",
609 	    "GET_TSF",
610 	    "RESET_TSF",
611 	    "SET_ADHOC_MODE",
612 	    "SET_BASIC_RATE",
613 	    "MIB_CONTROL",
614 	    "GET_CHANNEL_DATA",
615 	    "GET_CUR_RSSI",
616 	    "SET_ANTENNA_SWITCH",
617 	    "0x2c", "0x2d", "0x2e",
618 	    "USE_SHORT_SLOT_TIME",
619 	    "SET_POWER_MODE",
620 	    "SETUP_PSPOLL_DESC",
621 	    "SET_RX_MULTICAST_FILTER",
622 	    "RX_FILTER",
623 	    "PER_CALIBRATION",
624 	    "RESET",
625 	    "DISABLE",
626 	    "PHY_DISABLE",
627 	    "SET_TX_POWER_LIMIT",
628 	    "SET_TX_QUEUE_PARAMS",
629 	    "SETUP_TX_QUEUE",
630 	    "RELEASE_TX_QUEUE",
631 	};
632 	static char buf[8];
633 
634 	if (code < N(names))
635 		return (names[code]);
636 	if (code == WDCMSG_SET_DEFAULT_KEY)
637 		return ("SET_DEFAULT_KEY");
638 
639 	(void) snprintf(buf, sizeof (buf), "0x%02x", code);
640 	return (buf);
641 #undef N
642 }
643 
644 static int
645 uath_fw_send(struct uath_softc *sc, usb_pipe_handle_t pipe,
646     const void *data, size_t len)
647 {
648 	usb_bulk_req_t *send_req;
649 	mblk_t *mblk;
650 	int res;
651 
652 	send_req = usb_alloc_bulk_req(sc->sc_dev, len, USB_FLAGS_SLEEP);
653 
654 	send_req->bulk_len = (int)len;
655 	send_req->bulk_attributes = USB_ATTRS_AUTOCLEARING;
656 	send_req->bulk_timeout = UATH_CMD_TIMEOUT;
657 
658 	mblk = send_req->bulk_data;
659 	bcopy(data, mblk->b_wptr, len);
660 	mblk->b_wptr += len;
661 
662 	res = usb_pipe_bulk_xfer(pipe, send_req, USB_FLAGS_SLEEP);
663 	if (res != USB_SUCCESS) {
664 		UATH_DEBUG(UATH_DBG_FW, "uath: uath_fw_send(): "
665 		    "Error %x writing data to bulk/out pipe", res);
666 		return (UATH_FAILURE);
667 	}
668 
669 	usb_free_bulk_req(send_req);
670 	return (UATH_SUCCESS);
671 }
672 
673 static int
674 uath_fw_ack(struct uath_softc *sc, int len)
675 {
676 	struct uath_fwblock *rxblock;
677 	usb_bulk_req_t *req;
678 	mblk_t *mp;
679 	int err;
680 
681 	req = usb_alloc_bulk_req(sc->sc_dev, len, USB_FLAGS_SLEEP);
682 	if (req == NULL) {
683 		UATH_DEBUG(UATH_DBG_FW,
684 		    "uath: uath_fw_ack(): "
685 		    "uath_rx_transfer(): failed to allocate req");
686 		return (UATH_FAILURE);
687 	}
688 
689 	req->bulk_len			= len;
690 	req->bulk_client_private	= (usb_opaque_t)sc;
691 	req->bulk_timeout		= 0;
692 	req->bulk_attributes		= USB_ATTRS_SHORT_XFER_OK
693 	    | USB_ATTRS_AUTOCLEARING;
694 
695 	err = usb_pipe_bulk_xfer(sc->rx_cmd_pipe, req, USB_FLAGS_SLEEP);
696 	if (err != USB_SUCCESS) {
697 		UATH_DEBUG(UATH_DBG_FW, "uath: uath_fw_ack(): "
698 		    "failed to do rx xfer, %d", err);
699 		usb_free_bulk_req(req);
700 		return (UATH_FAILURE);
701 	}
702 
703 	mp = req->bulk_data;
704 	req->bulk_data = NULL;
705 
706 	rxblock = (struct uath_fwblock *)mp->b_rptr;
707 	UATH_DEBUG(UATH_DBG_FW, "uath: uath_fw_ack() "
708 	    "rxblock flags=0x%x total=%d\n",
709 	    BE_32(rxblock->flags), BE_32(rxblock->rxtotal));
710 
711 	freemsg(mp);
712 	usb_free_bulk_req(req);
713 
714 	return (UATH_SUCCESS);
715 }
716 
717 /*
718  * find uath firmware module's "_start" "_end" symbols
719  * and get its size.
720  */
721 static int
722 uath_loadsym(ddi_modhandle_t modp, char *sym, char **start, size_t *len)
723 {
724 	char start_sym[64];
725 	char end_sym[64];
726 	char *p, *end;
727 	int rv;
728 	size_t n;
729 
730 	(void) snprintf(start_sym, sizeof (start_sym), "%s_start", sym);
731 	(void) snprintf(end_sym, sizeof (end_sym), "%s_end", sym);
732 
733 	p = (char *)ddi_modsym(modp, start_sym, &rv);
734 	if (p == NULL || rv != 0) {
735 		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_loadsym(): "
736 		    "mod %s: symbol %s not found\n", uath_fwmod, start_sym);
737 		return (UATH_FAILURE);
738 	}
739 
740 	end = (char *)ddi_modsym(modp, end_sym, &rv);
741 	if (end == NULL || rv != 0) {
742 		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_loadsym(): "
743 		    "mod %s: symbol %s not found\n", uath_fwmod, end_sym);
744 		return (UATH_FAILURE);
745 	}
746 
747 	n = _PTRDIFF(end, p);
748 	*start = p;
749 	*len = n;
750 
751 	return (UATH_SUCCESS);
752 }
753 
754 /*
755  * Load the MIPS R4000 microcode into the device.  Once the image is loaded,
756  * the device will detach itself from the bus and reattach later with a new
757  * product Id (a la ezusb).  XXX this could also be implemented in userland
758  * through /dev/ugen.
759  */
760 static int
761 uath_loadfirmware(struct uath_softc *sc)
762 {
763 	struct uath_fwblock txblock;
764 	ddi_modhandle_t modp;
765 	char *fw_index, *fw_image = NULL;
766 	size_t fw_size, len;
767 	int err = DDI_SUCCESS, rv = 0;
768 
769 	modp = ddi_modopen(uath_fwmod, KRTLD_MODE_FIRST, &rv);
770 	if (modp == NULL) {
771 		cmn_err(CE_WARN, "uath: uath_loadfirmware(): "
772 		    "module %s not found\n", uath_fwmod);
773 		goto label;
774 	}
775 
776 	err = uath_loadsym(modp, uath_binmod, &fw_index, &fw_size);
777 	if (err != UATH_SUCCESS) {
778 		cmn_err(CE_WARN, "uath: uath_loadfirmware(): "
779 		    "could not get firmware\n");
780 		goto label;
781 	}
782 
783 	fw_image = (char *)kmem_alloc(fw_size, KM_SLEEP);
784 	if (fw_image == NULL) {
785 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_loadfirmware(): "
786 		    "failed to alloc firmware memory\n");
787 		err = UATH_FAILURE;
788 		goto label;
789 	}
790 
791 	(void) memcpy(fw_image, fw_index, fw_size);
792 	fw_index = fw_image;
793 	len = fw_size;
794 	UATH_DEBUG(UATH_DBG_MSG, "loading firmware size = %lu\n", fw_size);
795 
796 	/* bzero(txblock, sizeof (struct uath_fwblock)); */
797 	txblock.flags = BE_32(UATH_WRITE_BLOCK);
798 	txblock.total = BE_32(fw_size);
799 
800 	while (len > 0) {
801 		size_t mlen = min(len, UATH_MAX_FWBLOCK_SIZE);
802 
803 		txblock.remain = BE_32(len - mlen);
804 		txblock.len = BE_32(mlen);
805 
806 		UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware(): "
807 		    "sending firmware block: %d bytes sending\n", mlen);
808 		UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware(): "
809 		    "sending firmware block: %d bytes remaining\n",
810 		    len - mlen);
811 
812 		/* send firmware block meta-data */
813 		err = uath_fw_send(sc, sc->tx_cmd_pipe, &txblock,
814 		    sizeof (struct uath_fwblock));
815 		if (err != UATH_SUCCESS) {
816 			UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware(): "
817 			    "send block meta-data error");
818 			goto label;
819 		}
820 
821 		/* send firmware block data */
822 		err = uath_fw_send(sc, sc->tx_data_pipe, fw_index, mlen);
823 		if (err != UATH_SUCCESS) {
824 			UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware() "
825 			    "send block data err");
826 			goto label;
827 		}
828 
829 		/* wait for ack from firmware */
830 		err = uath_fw_ack(sc, sizeof (struct uath_fwblock));
831 		if (err != UATH_SUCCESS) {
832 			UATH_DEBUG(UATH_DBG_FW, "uath: uath_loadfirmware() "
833 			    "rx block ack err");
834 			goto label;
835 		}
836 
837 		fw_index += mlen;
838 		len -= mlen;
839 	}
840 
841 label:
842 	if (fw_image != NULL)
843 		kmem_free(fw_image, fw_size);
844 	fw_image = fw_index = NULL;
845 	if (modp != NULL)
846 		(void) ddi_modclose(modp);
847 	return (err);
848 }
849 
850 static int
851 uath_alloc_cmd_list(struct uath_softc *sc, struct uath_cmd cmds[],
852     int ncmd, int maxsz)
853 {
854 	int i, err;
855 
856 	for (i = 0; i < ncmd; i++) {
857 		struct uath_cmd *cmd = &cmds[i];
858 
859 		cmd->sc = sc;	/* backpointer for callbacks */
860 		cmd->msgid = i;
861 		cmd->buf = kmem_zalloc(maxsz, KM_NOSLEEP);
862 		if (cmd->buf == NULL) {
863 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_alloc_cmd_list(): "
864 			    "could not allocate xfer buffer\n");
865 			err = DDI_ENOMEM;
866 			goto fail;
867 		}
868 	}
869 	return (UATH_SUCCESS);
870 
871 fail:
872 	uath_free_cmd_list(cmds, ncmd);
873 	return (err);
874 }
875 
876 static int
877 uath_init_cmd_list(struct uath_softc *sc)
878 {
879 	int i;
880 
881 	sc->sc_cmdid = sc->rx_cmd_queued = sc->tx_cmd_queued = 0;
882 	for (i = 0; i < UATH_CMD_LIST_COUNT; i++) {
883 		if (uath_rx_cmd_xfer(sc) != UATH_SUCCESS) {
884 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init_cmd_list(): "
885 			    "failed to init cmd list %x\n", i);
886 			return (UATH_FAILURE);
887 		}
888 	}
889 	return (UATH_SUCCESS);
890 }
891 
892 static void
893 uath_free_cmd_list(struct uath_cmd cmds[], int ncmd)
894 {
895 	int i;
896 
897 	for (i = 0; i < ncmd; i++)
898 		if (cmds[i].buf != NULL) {
899 			kmem_free(cmds[i].buf, UATH_MAX_CMDSZ);
900 			cmds[i].buf = NULL;
901 		}
902 }
903 
904 static int
905 uath_host_available(struct uath_softc *sc)
906 {
907 	struct uath_cmd_host_available setup;
908 
909 	/* inform target the host is available */
910 	setup.sw_ver_major = BE_32(ATH_SW_VER_MAJOR);
911 	setup.sw_ver_minor = BE_32(ATH_SW_VER_MINOR);
912 	setup.sw_ver_patch = BE_32(ATH_SW_VER_PATCH);
913 	setup.sw_ver_build = BE_32(ATH_SW_VER_BUILD);
914 	return (uath_cmd_read(sc, WDCMSG_HOST_AVAILABLE,
915 	    &setup, sizeof (setup), NULL, 0, 0));
916 }
917 
918 static void
919 uath_get_capability(struct uath_softc *sc, uint32_t cap, uint32_t *val)
920 {
921 	int err;
922 
923 	cap = BE_32(cap);
924 	err = uath_cmd_read(sc, WDCMSG_TARGET_GET_CAPABILITY, &cap,
925 	    sizeof (cap), val, sizeof (uint32_t), UATH_CMD_FLAG_MAGIC);
926 	if (err == UATH_SUCCESS)
927 		*val = BE_32(*val);
928 	else
929 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_get_capability(): "
930 		    "could not read capability %u\n", BE_32(cap));
931 }
932 
933 static int
934 uath_get_devcap(struct uath_softc *sc)
935 {
936 	struct uath_devcap *cap = &sc->sc_devcap;
937 
938 	/* collect device capabilities */
939 	uath_get_capability(sc, CAP_TARGET_VERSION,
940 	    &cap->targetVersion);
941 	uath_get_capability(sc, CAP_TARGET_REVISION,
942 	    &cap->targetRevision);
943 	uath_get_capability(sc, CAP_MAC_VERSION,
944 	    &cap->macVersion);
945 	uath_get_capability(sc, CAP_MAC_REVISION,
946 	    &cap->macRevision);
947 	uath_get_capability(sc, CAP_PHY_REVISION,
948 	    &cap->phyRevision);
949 	uath_get_capability(sc, CAP_ANALOG_5GHz_REVISION,
950 	    &cap->analog5GhzRevision);
951 	uath_get_capability(sc, CAP_ANALOG_2GHz_REVISION,
952 	    &cap->analog2GhzRevision);
953 	uath_get_capability(sc, CAP_REG_DOMAIN,
954 	    &cap->regDomain);
955 	uath_get_capability(sc, CAP_REG_CAP_BITS,
956 	    &cap->regCapBits);
957 
958 	/* NB: not supported in rev 1.5 */
959 	/* uath_get_capability(sc, CAP_COUNTRY_CODE, cap->countryCode); */
960 
961 	uath_get_capability(sc, CAP_WIRELESS_MODES,
962 	    &cap->wirelessModes);
963 	uath_get_capability(sc, CAP_CHAN_SPREAD_SUPPORT,
964 	    &cap->chanSpreadSupport);
965 	uath_get_capability(sc, CAP_COMPRESS_SUPPORT,
966 	    &cap->compressSupport);
967 	uath_get_capability(sc, CAP_BURST_SUPPORT,
968 	    &cap->burstSupport);
969 	uath_get_capability(sc, CAP_FAST_FRAMES_SUPPORT,
970 	    &cap->fastFramesSupport);
971 	uath_get_capability(sc, CAP_CHAP_TUNING_SUPPORT,
972 	    &cap->chapTuningSupport);
973 	uath_get_capability(sc, CAP_TURBOG_SUPPORT,
974 	    &cap->turboGSupport);
975 	uath_get_capability(sc, CAP_TURBO_PRIME_SUPPORT,
976 	    &cap->turboPrimeSupport);
977 	uath_get_capability(sc, CAP_DEVICE_TYPE,
978 	    &cap->deviceType);
979 	uath_get_capability(sc, CAP_WME_SUPPORT,
980 	    &cap->wmeSupport);
981 	uath_get_capability(sc, CAP_TOTAL_QUEUES,
982 	    &cap->numTxQueues);
983 	uath_get_capability(sc, CAP_CONNECTION_ID_MAX,
984 	    &cap->connectionIdMax);
985 
986 	uath_get_capability(sc, CAP_LOW_5GHZ_CHAN,
987 	    &cap->low5GhzChan);
988 	uath_get_capability(sc, CAP_HIGH_5GHZ_CHAN,
989 	    &cap->high5GhzChan);
990 	uath_get_capability(sc, CAP_LOW_2GHZ_CHAN,
991 	    &cap->low2GhzChan);
992 	uath_get_capability(sc, CAP_HIGH_2GHZ_CHAN,
993 	    &cap->high2GhzChan);
994 	uath_get_capability(sc, CAP_TWICE_ANTENNAGAIN_5G,
995 	    &cap->twiceAntennaGain5G);
996 	uath_get_capability(sc, CAP_TWICE_ANTENNAGAIN_2G,
997 	    &cap->twiceAntennaGain2G);
998 
999 	uath_get_capability(sc, CAP_CIPHER_AES_CCM,
1000 	    &cap->supportCipherAES_CCM);
1001 	uath_get_capability(sc, CAP_CIPHER_TKIP,
1002 	    &cap->supportCipherTKIP);
1003 	uath_get_capability(sc, CAP_MIC_TKIP,
1004 	    &cap->supportMicTKIP);
1005 
1006 	cap->supportCipherWEP = 1;	/* NB: always available */
1007 	return (UATH_SUCCESS);
1008 }
1009 
1010 static int
1011 uath_get_status(struct uath_softc *sc, uint32_t which, void *odata, int olen)
1012 {
1013 	int err;
1014 
1015 	which = BE_32(which);
1016 	err = uath_cmd_read(sc, WDCMSG_TARGET_GET_STATUS,
1017 	    &which, sizeof (which), odata, olen, UATH_CMD_FLAG_MAGIC);
1018 	if (err != UATH_SUCCESS)
1019 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_get_status(): "
1020 		    "could not read EEPROM offset 0x%02x\n", BE_32(which));
1021 	return (err);
1022 }
1023 
1024 static int
1025 uath_get_devstatus(struct uath_softc *sc, uint8_t macaddr[IEEE80211_ADDR_LEN])
1026 {
1027 	int err;
1028 
1029 	/* retrieve MAC address */
1030 	err = uath_get_status(sc, ST_MAC_ADDR, macaddr, IEEE80211_ADDR_LEN);
1031 	if (err != UATH_SUCCESS) {
1032 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_get_devstatus(): "
1033 		    "could not read MAC address\n");
1034 		return (err);
1035 	}
1036 
1037 	err = uath_get_status(sc, ST_SERIAL_NUMBER,
1038 	    &sc->sc_serial[0], sizeof (sc->sc_serial));
1039 	if (err != UATH_SUCCESS) {
1040 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_get_devstatus(): "
1041 		    "could not read device serial number\n");
1042 		return (err);
1043 	}
1044 
1045 	return (UATH_SUCCESS);
1046 }
1047 
1048 /*
1049  * uath_cmd_lock: a special signal structure that is used for notification
1050  * that a callback function has been called.
1051  */
1052 
1053 /* Initializes the uath_cmd_lock structure. */
1054 static void
1055 uath_cmd_lock_init(struct uath_cmd_lock *lock)
1056 {
1057 	ASSERT(lock != NULL);
1058 	mutex_init(&lock->mutex, NULL, MUTEX_DRIVER, NULL);
1059 	cv_init(&lock->cv, NULL, CV_DRIVER, NULL);
1060 	lock->done = B_FALSE;
1061 }
1062 
1063 /* Deinitalizes the uath_cb_lock structure. */
1064 void
1065 uath_cmd_lock_destroy(struct uath_cmd_lock *lock)
1066 {
1067 	ASSERT(lock != NULL);
1068 	mutex_destroy(&lock->mutex);
1069 	cv_destroy(&lock->cv);
1070 }
1071 
1072 /*
1073  * Wait on lock until someone calls the "signal" function or the timeout
1074  * expires. Note: timeout is in microseconds.
1075  */
1076 static int
1077 uath_cmd_lock_wait(struct uath_cmd_lock *lock, clock_t timeout)
1078 {
1079 	int res, cv_res;
1080 	clock_t etime;
1081 
1082 	ASSERT(lock != NULL);
1083 	mutex_enter(&lock->mutex);
1084 
1085 	if (timeout < 0) {
1086 		/* no timeout - wait as long as needed */
1087 		while (lock->done == B_FALSE)
1088 			cv_wait(&lock->cv, &lock->mutex);
1089 	} else {
1090 		/* wait with timeout (given in usec) */
1091 		etime = ddi_get_lbolt() + drv_usectohz(timeout);
1092 		while (lock->done == B_FALSE) {
1093 			cv_res = cv_timedwait_sig(&lock->cv,
1094 			    &lock->mutex, etime);
1095 			if (cv_res <= 0) break;
1096 		}
1097 	}
1098 
1099 	res = (lock->done == B_TRUE) ? UATH_SUCCESS : UATH_FAILURE;
1100 	mutex_exit(&lock->mutex);
1101 
1102 	return (res);
1103 }
1104 
1105 /* Signal that the job (eg. callback) is done and unblock anyone who waits. */
1106 static void
1107 uath_cmd_lock_signal(struct uath_cmd_lock *lock)
1108 {
1109 	ASSERT(lock != NULL);
1110 
1111 	mutex_enter(&lock->mutex);
1112 	lock->done = B_TRUE;
1113 	cv_broadcast(&lock->cv);
1114 	mutex_exit(&lock->mutex);
1115 }
1116 
1117 static int
1118 uath_cmd_read(struct uath_softc *sc, uint32_t code, const void *idata,
1119     int ilen, void *odata, int olen, int flags)
1120 {
1121 	flags |= UATH_CMD_FLAG_READ;
1122 	return (uath_cmdsend(sc, code, idata, ilen, odata, olen, flags));
1123 }
1124 
1125 static int
1126 uath_cmd_write(struct uath_softc *sc, uint32_t code, const void *data,
1127     int len, int flags)
1128 {
1129 	flags &= ~UATH_CMD_FLAG_READ;
1130 	return (uath_cmdsend(sc, code, data, len, NULL, 0, flags));
1131 }
1132 
1133 /*
1134  * Low-level function to send read or write commands to the firmware.
1135  */
1136 static int
1137 uath_cmdsend(struct uath_softc *sc, uint32_t code, const void *idata, int ilen,
1138     void *odata, int olen, int flags)
1139 {
1140 	struct uath_cmd_hdr *hdr;
1141 	struct uath_cmd *cmd;
1142 	int err;
1143 
1144 	/* grab a xfer */
1145 	cmd = &sc->sc_cmd[sc->sc_cmdid];
1146 
1147 	cmd->flags = flags;
1148 	/* always bulk-out a multiple of 4 bytes */
1149 	cmd->buflen = (sizeof (struct uath_cmd_hdr) + ilen + 3) & ~3;
1150 
1151 	hdr = (struct uath_cmd_hdr *)cmd->buf;
1152 	bzero(hdr, sizeof (struct uath_cmd_hdr));
1153 	hdr->len   = BE_32(cmd->buflen);
1154 	hdr->code  = BE_32(code);
1155 	hdr->msgid = cmd->msgid;	/* don't care about endianness */
1156 	hdr->magic = BE_32((cmd->flags & UATH_CMD_FLAG_MAGIC) ? 1 << 24 : 0);
1157 	bcopy(idata, (uint8_t *)(hdr + 1), ilen);
1158 
1159 	UATH_DEBUG(UATH_DBG_TX_CMD, "uath: uath_cmdsend(): "
1160 	    "queue %x send %s [flags 0x%x] olen %d\n",
1161 	    cmd->msgid, uath_codename(code), cmd->flags, olen);
1162 
1163 	cmd->odata = odata;
1164 	if (odata == NULL)
1165 		UATH_DEBUG(UATH_DBG_TX_CMD, "uath: uath_cmdsend(): "
1166 		    "warning - odata is NULL\n");
1167 	else if (olen < UATH_MAX_CMDSZ - sizeof (*hdr) + sizeof (uint32_t))
1168 		UATH_DEBUG(UATH_DBG_TX_CMD, "uath: uath_cmdsend(): "
1169 		    "warning - olen %x is short\n, olen");
1170 	cmd->olen = olen;
1171 
1172 	err = uath_tx_cmd_xfer(sc, sc->tx_cmd_pipe, cmd->buf, cmd->buflen);
1173 	if (err != UATH_SUCCESS) {
1174 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_cmdsend(): "
1175 		    "Error writing command\n");
1176 		return (UATH_FAILURE);
1177 	}
1178 
1179 	sc->sc_cmdid = (sc->sc_cmdid + 1) % UATH_CMD_LIST_COUNT;
1180 
1181 	if (cmd->flags & UATH_CMD_FLAG_READ) {
1182 		/* wait at most two seconds for command reply */
1183 		uath_cmd_lock_init(&sc->rlock);
1184 		err = uath_cmd_lock_wait(&sc->rlock, 2000000);
1185 		cmd->odata = NULL;	/* in case reply comes too late */
1186 		if (err != UATH_SUCCESS) {
1187 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_cmdsend(): "
1188 			    "timeout waiting for reply, "
1189 			    "to cmd 0x%x (%u), queue %x\n",
1190 			    code, code, cmd->msgid);
1191 			err = UATH_FAILURE;
1192 		} else if (cmd->olen != olen) {
1193 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_cmdsend(): "
1194 			    "unexpected reply data count "
1195 			    "to cmd 0x%x (%x), got %u, expected %u\n",
1196 			    code, cmd->msgid, cmd->olen, olen);
1197 			err = UATH_FAILURE;
1198 		}
1199 		uath_cmd_lock_destroy(&sc->rlock);
1200 		return (err);
1201 	}
1202 
1203 	return (UATH_SUCCESS);
1204 }
1205 
1206 /* ARGSUSED */
1207 static void
1208 uath_cmd_txeof(usb_pipe_handle_t pipe, struct usb_bulk_req *req)
1209 {
1210 	struct uath_softc *sc = (struct uath_softc *)req->bulk_client_private;
1211 
1212 	UATH_DEBUG(UATH_DBG_TX_CMD, "uath: uath_cmd_txeof(): "
1213 	    "cr:%s(%d), flags:0x%x, tx queued %d\n",
1214 	    usb_str_cr(req->bulk_completion_reason),
1215 	    req->bulk_completion_reason,
1216 	    req->bulk_cb_flags,
1217 	    sc->tx_cmd_queued);
1218 
1219 	if (req->bulk_completion_reason != USB_CR_OK)
1220 		sc->sc_tx_err++;
1221 
1222 	mutex_enter(&sc->sc_txlock_cmd);
1223 	sc->tx_cmd_queued--;
1224 	mutex_exit(&sc->sc_txlock_cmd);
1225 	usb_free_bulk_req(req);
1226 }
1227 
1228 static int
1229 uath_tx_cmd_xfer(struct uath_softc *sc,
1230     usb_pipe_handle_t pipe, const void *data, uint_t len)
1231 {
1232 	usb_bulk_req_t *send_req;
1233 	mblk_t *mblk;
1234 	int res;
1235 
1236 	send_req = usb_alloc_bulk_req(sc->sc_dev, len, USB_FLAGS_SLEEP);
1237 
1238 	send_req->bulk_client_private		= (usb_opaque_t)sc;
1239 	send_req->bulk_len			= (int)len;
1240 	send_req->bulk_attributes		= USB_ATTRS_AUTOCLEARING;
1241 	send_req->bulk_timeout			= UATH_CMD_TIMEOUT;
1242 	send_req->bulk_cb			= uath_cmd_txeof;
1243 	send_req->bulk_exc_cb			= uath_cmd_txeof;
1244 	send_req->bulk_completion_reason	= 0;
1245 	send_req->bulk_cb_flags			= 0;
1246 
1247 	mblk = send_req->bulk_data;
1248 	bcopy(data, mblk->b_rptr, len);
1249 	mblk->b_wptr += len;
1250 
1251 	res = usb_pipe_bulk_xfer(pipe, send_req, USB_FLAGS_NOSLEEP);
1252 	if (res != UATH_SUCCESS) {
1253 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_tx_cmd_xfer(): "
1254 		    "Error %x writing cmd to bulk/out pipe", res);
1255 		return (UATH_FAILURE);
1256 	}
1257 
1258 	mutex_enter(&sc->sc_txlock_cmd);
1259 	sc->tx_cmd_queued++;
1260 	mutex_exit(&sc->sc_txlock_cmd);
1261 	return (UATH_SUCCESS);
1262 }
1263 
1264 static void
1265 uath_cmdeof(struct uath_softc *sc, struct uath_cmd *cmd)
1266 {
1267 	struct uath_cmd_hdr *hdr;
1268 	int dlen;
1269 
1270 	hdr = (struct uath_cmd_hdr *)cmd->buf;
1271 
1272 	hdr->code = BE_32(hdr->code);
1273 	hdr->len = BE_32(hdr->len);
1274 	hdr->magic = BE_32(hdr->magic);	/* target status on return */
1275 
1276 	/* NB: msgid is passed thru w/o byte swapping */
1277 	UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): "
1278 	    "%s: [ix %x] len=%x status %x\n",
1279 	    uath_codename(hdr->code),
1280 	    hdr->msgid,
1281 	    hdr->len,
1282 	    hdr->magic);
1283 
1284 	switch (hdr->code & 0xff) {
1285 	/* reply to a read command */
1286 	default:
1287 		dlen = hdr->len - sizeof (*hdr);
1288 		UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): "
1289 		    "code %x data len %u\n",
1290 		    hdr->code & 0xff, dlen);
1291 
1292 		/*
1293 		 * The first response from the target after the
1294 		 * HOST_AVAILABLE has an invalid msgid so we must
1295 		 * treat it specially.
1296 		 */
1297 		if ((hdr->msgid < UATH_CMD_LIST_COUNT) && (hdr->code != 0x13)) {
1298 			uint32_t *rp = (uint32_t *)(hdr + 1);
1299 			uint_t olen;
1300 
1301 			if (!(sizeof (*hdr) <= hdr->len &&
1302 			    hdr->len < UATH_MAX_CMDSZ)) {
1303 				UATH_DEBUG(UATH_DBG_RX_CMD,
1304 				    "uath: uath_cmdeof(): "
1305 				    "invalid WDC msg length %u; "
1306 				    "msg ignored\n",
1307 				    hdr->len);
1308 				return;
1309 			}
1310 
1311 			/*
1312 			 * Calculate return/receive payload size; the
1313 			 * first word, if present, always gives the
1314 			 * number of bytes--unless it's 0 in which
1315 			 * case a single 32-bit word should be present.
1316 			 */
1317 			if (dlen >= sizeof (uint32_t)) {
1318 				olen = BE_32(rp[0]);
1319 				dlen -= sizeof (uint32_t);
1320 				if (olen == 0) {
1321 					/* convention is 0 =>'s one word */
1322 					olen = sizeof (uint32_t);
1323 					/* XXX KASSERT(olen == dlen ) */
1324 				}
1325 			} else
1326 				olen = 0;
1327 
1328 			if (cmd->odata != NULL) {
1329 				/* NB: cmd->olen validated in uath_cmd */
1330 				if (olen > cmd->olen) {
1331 					/* XXX complain? */
1332 					UATH_DEBUG(UATH_DBG_RX_CMD,
1333 					    "uath: uath_cmdeof(): "
1334 					    "cmd 0x%x olen %u cmd olen %u\n",
1335 					    hdr->code, olen, cmd->olen);
1336 					olen = cmd->olen;
1337 				}
1338 				if (olen > dlen) {
1339 					/* XXX complain, shouldn't happen */
1340 					UATH_DEBUG(UATH_DBG_RX_CMD,
1341 					    "uath: uath_cmdeof(): "
1342 					    "cmd 0x%x olen %u dlen %u\n",
1343 					    hdr->code, olen, dlen);
1344 					olen = dlen;
1345 				}
1346 				/* XXX have submitter do this */
1347 				/* copy answer into caller's supplied buffer */
1348 				bcopy(&rp[1], cmd->odata, olen);
1349 				cmd->olen = olen;
1350 			}
1351 		}
1352 
1353 		/* Just signal that something happened */
1354 		uath_cmd_lock_signal(&sc->rlock);
1355 		break;
1356 
1357 	case WDCMSG_TARGET_START:
1358 		UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): "
1359 		    "receive TARGET STAERT\n");
1360 
1361 		if (hdr->msgid >= UATH_CMD_LIST_COUNT) {
1362 			/* XXX */
1363 			return;
1364 		}
1365 		dlen = hdr->len - sizeof (*hdr);
1366 		if (dlen != sizeof (uint32_t)) {
1367 			/* XXX something wrong */
1368 			return;
1369 		}
1370 		/* XXX have submitter do this */
1371 		/* copy answer into caller's supplied buffer */
1372 		bcopy(hdr + 1, cmd->odata, sizeof (uint32_t));
1373 		cmd->olen = sizeof (uint32_t);
1374 
1375 		/* wake up caller */
1376 		uath_cmd_lock_signal(&sc->rlock);
1377 		break;
1378 
1379 	case WDCMSG_SEND_COMPLETE:
1380 		/* this notification is sent when UATH_TX_NOTIFY is set */
1381 		UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): "
1382 		    "receive Tx notification\n");
1383 		break;
1384 
1385 	case WDCMSG_TARGET_GET_STATS:
1386 		UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmdeof(): "
1387 		    "received device statistics\n");
1388 		break;
1389 	}
1390 }
1391 
1392 /* ARGSUSED */
1393 static void
1394 uath_cmd_rxeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1395 {
1396 	struct uath_softc *sc = (struct uath_softc *)req->bulk_client_private;
1397 	struct uath_cmd_hdr *hdr;
1398 	struct uath_cmd *cmd;
1399 	mblk_t *m, *mp;
1400 	int len;
1401 
1402 	UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmd_rxeof(): "
1403 	    "cr:%s(%d), flags:0x%x, rx queued %d\n",
1404 	    usb_str_cr(req->bulk_completion_reason),
1405 	    req->bulk_completion_reason,
1406 	    req->bulk_cb_flags,
1407 	    sc->rx_cmd_queued);
1408 
1409 	m = req->bulk_data;
1410 	req->bulk_data = NULL;
1411 
1412 	if (req->bulk_completion_reason != USB_CR_OK) {
1413 		UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_cmd_rxeof(): "
1414 		    "USB CR is not OK\n");
1415 		goto fail;
1416 	}
1417 
1418 	if (m->b_cont != NULL) {
1419 		/* Fragmented message, concatenate */
1420 		mp = msgpullup(m, -1);
1421 		freemsg(m);
1422 		m = mp;
1423 		mp = NULL;
1424 	}
1425 
1426 	len = msgdsize(m);
1427 	if (len < sizeof (struct uath_cmd_hdr)) {
1428 		UATH_DEBUG(UATH_DBG_RX_CMD, "uath: uath_rx_cmdeof(): "
1429 		    "short xfer error\n");
1430 		goto fail;
1431 	}
1432 
1433 	hdr = (struct uath_cmd_hdr *)m->b_rptr;
1434 	if (BE_32(hdr->code) == 0x13)
1435 		cmd = &sc->sc_cmd[0];
1436 	else
1437 		cmd = &sc->sc_cmd[hdr->msgid];
1438 
1439 	bcopy(m->b_rptr, cmd->buf, len);
1440 	uath_cmdeof(sc, cmd);
1441 	(void) uath_rx_cmd_xfer(sc);
1442 fail:
1443 	mutex_enter(&sc->sc_rxlock_cmd);
1444 	sc->rx_cmd_queued--;
1445 	mutex_exit(&sc->sc_rxlock_cmd);
1446 	if (m) freemsg(m);
1447 	usb_free_bulk_req(req);
1448 }
1449 
1450 static int
1451 uath_rx_cmd_xfer(struct uath_softc *sc)
1452 {
1453 	usb_bulk_req_t *req;
1454 	int err;
1455 
1456 	req = usb_alloc_bulk_req(sc->sc_dev, UATH_MAX_CMDSZ, USB_FLAGS_SLEEP);
1457 	if (req == NULL) {
1458 		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_rx_cmd_xfer(): "
1459 		    "failed to allocate req");
1460 		return (UATH_FAILURE);
1461 	}
1462 
1463 	req->bulk_len			= UATH_MAX_CMDSZ;
1464 	req->bulk_client_private	= (usb_opaque_t)sc;
1465 	req->bulk_cb			= uath_cmd_rxeof;
1466 	req->bulk_exc_cb		= uath_cmd_rxeof;
1467 	req->bulk_timeout		= 0;
1468 	req->bulk_completion_reason	= 0;
1469 	req->bulk_cb_flags		= 0;
1470 	req->bulk_attributes		= USB_ATTRS_SHORT_XFER_OK
1471 	    | USB_ATTRS_AUTOCLEARING;
1472 
1473 	err = usb_pipe_bulk_xfer(sc->rx_cmd_pipe, req, USB_FLAGS_NOSLEEP);
1474 	if (err != USB_SUCCESS) {
1475 		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_rx_cmd_xfer(): "
1476 		    "failed to do rx xfer, %d", err);
1477 		usb_free_bulk_req(req);
1478 		return (UATH_FAILURE);
1479 	}
1480 
1481 	mutex_enter(&sc->sc_rxlock_cmd);
1482 	sc->rx_cmd_queued++;
1483 	mutex_exit(&sc->sc_rxlock_cmd);
1484 	return (UATH_SUCCESS);
1485 }
1486 
1487 static void
1488 uath_init_data_queue(struct uath_softc *sc)
1489 {
1490 	sc->tx_data_queued = sc->rx_data_queued = 0;
1491 }
1492 
1493 /* ARGSUSED */
1494 static void
1495 uath_data_txeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1496 {
1497 	struct uath_softc *sc = (struct uath_softc *)req->bulk_client_private;
1498 	struct ieee80211com *ic = &sc->sc_ic;
1499 
1500 	UATH_DEBUG(UATH_DBG_TX, "uath: uath_data_txeof(): "
1501 	    "uath_txeof(): cr:%s(%d), flags:0x%x, tx_data_queued %d\n",
1502 	    usb_str_cr(req->bulk_completion_reason),
1503 	    req->bulk_completion_reason,
1504 	    req->bulk_cb_flags,
1505 	    sc->tx_data_queued);
1506 
1507 	if (req->bulk_completion_reason != USB_CR_OK)
1508 		sc->sc_tx_err++;
1509 
1510 	mutex_enter(&sc->sc_txlock_data);
1511 	sc->tx_data_queued--;
1512 
1513 	if (sc->sc_need_sched) {
1514 		sc->sc_need_sched = 0;
1515 		mac_tx_update(ic->ic_mach);
1516 	}
1517 
1518 	mutex_exit(&sc->sc_txlock_data);
1519 	usb_free_bulk_req(req);
1520 }
1521 
1522 static int
1523 uath_tx_data_xfer(struct uath_softc *sc, mblk_t *mp)
1524 {
1525 	usb_bulk_req_t *req;
1526 	int err;
1527 
1528 	req = usb_alloc_bulk_req(sc->sc_dev, 0, USB_FLAGS_SLEEP);
1529 	if (req == NULL) {
1530 		UATH_DEBUG(UATH_DBG_TX, "uath: uath_tx_data_xfer(): "
1531 		    "uath_tx_data_xfer(): failed to allocate req");
1532 		freemsg(mp);
1533 		return (UATH_FAILURE);
1534 	}
1535 
1536 	req->bulk_len			= msgdsize(mp);
1537 	req->bulk_data			= mp;
1538 	req->bulk_client_private	= (usb_opaque_t)sc;
1539 	req->bulk_timeout		= UATH_DATA_TIMEOUT;
1540 	req->bulk_attributes		= USB_ATTRS_AUTOCLEARING;
1541 	req->bulk_cb			= uath_data_txeof;
1542 	req->bulk_exc_cb		= uath_data_txeof;
1543 	req->bulk_completion_reason	= 0;
1544 	req->bulk_cb_flags		= 0;
1545 
1546 	if ((err = usb_pipe_bulk_xfer(sc->tx_data_pipe, req, 0)) !=
1547 	    USB_SUCCESS) {
1548 
1549 		UATH_DEBUG(UATH_DBG_TX, "uath: uath_tx_data_xfer(): "
1550 		    "failed to do tx xfer, %d", err);
1551 		usb_free_bulk_req(req);
1552 		return (UATH_FAILURE);
1553 	}
1554 
1555 	sc->tx_data_queued++;
1556 	return (UATH_SUCCESS);
1557 }
1558 
1559 /* ARGSUSED */
1560 static void
1561 uath_data_rxeof(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1562 {
1563 	struct uath_softc *sc = (struct uath_softc *)req->bulk_client_private;
1564 	struct ieee80211com *ic = &sc->sc_ic;
1565 	struct uath_chunk *chunk;
1566 	struct uath_rx_desc *desc;
1567 	struct ieee80211_frame *wh;
1568 	struct ieee80211_node *ni;
1569 
1570 	mblk_t *m, *mp;
1571 	uint8_t *rxbuf;
1572 	int actlen, pktlen;
1573 
1574 	mutex_enter(&sc->sc_rxlock_data);
1575 
1576 	UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
1577 	    "cr:%s(%d), flags:0x%x, rx_data_queued %d\n",
1578 	    usb_str_cr(req->bulk_completion_reason),
1579 	    req->bulk_completion_reason,
1580 	    req->bulk_cb_flags,
1581 	    sc->rx_data_queued);
1582 
1583 	mp = req->bulk_data;
1584 	req->bulk_data = NULL;
1585 
1586 	if (req->bulk_completion_reason != USB_CR_OK) {
1587 		UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
1588 		    "USB CR is not OK\n");
1589 		sc->sc_rx_err++;
1590 		goto fail;
1591 	}
1592 
1593 	rxbuf = (uint8_t *)mp->b_rptr;
1594 	actlen = (uintptr_t)mp->b_wptr - (uintptr_t)mp->b_rptr;
1595 	if (actlen < UATH_MIN_RXBUFSZ) {
1596 		UATH_DEBUG(UATH_DBG_RX, "uath_data_rxeof(): "
1597 		    "wrong recv size %d\n", actlen);
1598 		sc->sc_rx_err++;
1599 		goto fail;
1600 	}
1601 
1602 	chunk = (struct uath_chunk *)rxbuf;
1603 	if (chunk->seqnum == 0 && chunk->flags == 0 && chunk->length == 0) {
1604 		UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
1605 		    "strange response\n");
1606 		UATH_RESET_INTRX(sc);
1607 		sc->sc_rx_err++;
1608 		goto fail;
1609 	}
1610 
1611 	if (chunk->seqnum != sc->sc_intrx_nextnum) {
1612 		UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
1613 		    "invalid seqnum %d, expected %d\n",
1614 		    chunk->seqnum, sc->sc_intrx_nextnum);
1615 		UATH_STAT_INC(sc, st_badchunkseqnum);
1616 		UATH_RESET_INTRX(sc);
1617 		sc->sc_rx_err++;
1618 		goto fail;
1619 	}
1620 
1621 	/* check multi-chunk frames  */
1622 	if ((chunk->seqnum == 0 && !(chunk->flags & UATH_CFLAGS_FINAL)) ||
1623 	    (chunk->seqnum != 0 && (chunk->flags & UATH_CFLAGS_FINAL)) ||
1624 	    chunk->flags & UATH_CFLAGS_RXMSG) {
1625 		UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
1626 		    "receive multi-chunk frames "
1627 		    "chunk seqnum %x, flags %x, length %u\n",
1628 		    chunk->seqnum, chunk->flags, BE_16(chunk->length));
1629 		UATH_STAT_INC(sc, st_multichunk);
1630 	}
1631 
1632 
1633 	/* if the frame is not final continue the transfer  */
1634 	if (!(chunk->flags & UATH_CFLAGS_FINAL))
1635 		sc->sc_intrx_nextnum++;
1636 
1637 	/*
1638 	 * if the frame is not set UATH_CFLAGS_RXMSG, then rx descriptor is
1639 	 * located at the end, 32-bit aligned
1640 	 */
1641 	desc = (chunk->flags & UATH_CFLAGS_RXMSG) ?
1642 	    (struct uath_rx_desc *)(chunk + 1) :
1643 	    (struct uath_rx_desc *)(((uint8_t *)chunk) +
1644 	    sizeof (struct uath_chunk) + BE_16(chunk->length) -
1645 	    sizeof (struct uath_rx_desc));
1646 
1647 	UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
1648 	    "frame len %u code %u status %u rate %u antenna %u "
1649 	    "rssi %d channel %u phyerror %u connix %u "
1650 	    "decrypterror %u keycachemiss %u\n",
1651 	    BE_32(desc->framelen), BE_32(desc->code), BE_32(desc->status),
1652 	    BE_32(desc->rate), BE_32(desc->antenna), BE_32(desc->rssi),
1653 	    BE_32(desc->channel), BE_32(desc->phyerror), BE_32(desc->connix),
1654 	    BE_32(desc->decrypterror), BE_32(desc->keycachemiss));
1655 
1656 	if (BE_32(desc->len) > IEEE80211_MAX_LEN) {
1657 		UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
1658 		    "bad descriptor (len=%d)\n", BE_32(desc->len));
1659 		UATH_STAT_INC(sc, st_toobigrxpkt);
1660 		goto fail;
1661 	}
1662 
1663 	uath_update_rxstat(sc, BE_32(desc->status));
1664 
1665 	pktlen = BE_32(desc->framelen) - UATH_RX_DUMMYSIZE;
1666 
1667 	if ((m = allocb(pktlen, BPRI_MED)) == NULL) {
1668 		UATH_DEBUG(UATH_DBG_RX, "uath: uath_data_rxeof(): "
1669 		    "allocate mblk failed.\n");
1670 		sc->sc_rx_nobuf++;
1671 		goto fail;
1672 	}
1673 	bcopy((rxbuf + sizeof (struct uath_chunk)), m->b_rptr, pktlen);
1674 
1675 	m->b_wptr = m->b_rptr + pktlen;
1676 	wh = (struct ieee80211_frame *)m->b_rptr;
1677 	ni = ieee80211_find_rxnode(ic, wh);
1678 
1679 	/* send the frame to the 802.11 layer */
1680 	(void) ieee80211_input(ic, m, ni, (int)BE_32(desc->rssi), 0);
1681 
1682 	/* node is no longer needed */
1683 	ieee80211_free_node(ni);
1684 fail:
1685 	sc->rx_data_queued--;
1686 	if (mp) freemsg(mp);
1687 	usb_free_bulk_req(req);
1688 	mutex_exit(&sc->sc_rxlock_data);
1689 	if (UATH_IS_RUNNING(sc) && !UATH_IS_SUSPEND(sc)) {
1690 		(void) uath_rx_data_xfer(sc);
1691 	}
1692 }
1693 
1694 static int
1695 uath_rx_data_xfer(struct uath_softc *sc)
1696 {
1697 	usb_bulk_req_t *req;
1698 	int err;
1699 
1700 	req = usb_alloc_bulk_req(sc->sc_dev,
1701 	    IEEE80211_MAX_LEN, USB_FLAGS_SLEEP);
1702 	if (req == NULL) {
1703 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_rx_data_xfer(): "
1704 		    "failed to allocate req");
1705 		return (UATH_SUCCESS);
1706 	}
1707 
1708 	req->bulk_len			= IEEE80211_MAX_LEN;
1709 	req->bulk_cb			= uath_data_rxeof;
1710 	req->bulk_exc_cb		= uath_data_rxeof;
1711 	req->bulk_client_private	= (usb_opaque_t)sc;
1712 	req->bulk_timeout		= 0;
1713 	req->bulk_completion_reason	= 0;
1714 	req->bulk_cb_flags		= 0;
1715 	req->bulk_attributes		= USB_ATTRS_SHORT_XFER_OK
1716 	    | USB_ATTRS_AUTOCLEARING;
1717 
1718 	err = usb_pipe_bulk_xfer(sc->rx_data_pipe, req, 0);
1719 	if (err != UATH_SUCCESS) {
1720 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_rx_data_xfer(): "
1721 		    "failed to do rx xfer, %d", err);
1722 		usb_free_bulk_req(req);
1723 		return (UATH_FAILURE);
1724 	}
1725 
1726 	mutex_enter(&sc->sc_rxlock_data);
1727 	sc->rx_data_queued++;
1728 	mutex_exit(&sc->sc_rxlock_data);
1729 	return (UATH_SUCCESS);
1730 }
1731 
1732 static void
1733 uath_update_rxstat(struct uath_softc *sc, uint32_t status)
1734 {
1735 
1736 	switch (status) {
1737 	case UATH_STATUS_STOP_IN_PROGRESS:
1738 		UATH_STAT_INC(sc, st_stopinprogress);
1739 		break;
1740 	case UATH_STATUS_CRC_ERR:
1741 		UATH_STAT_INC(sc, st_crcerr);
1742 		break;
1743 	case UATH_STATUS_PHY_ERR:
1744 		UATH_STAT_INC(sc, st_phyerr);
1745 		break;
1746 	case UATH_STATUS_DECRYPT_CRC_ERR:
1747 		UATH_STAT_INC(sc, st_decrypt_crcerr);
1748 		break;
1749 	case UATH_STATUS_DECRYPT_MIC_ERR:
1750 		UATH_STAT_INC(sc, st_decrypt_micerr);
1751 		break;
1752 	case UATH_STATUS_DECOMP_ERR:
1753 		UATH_STAT_INC(sc, st_decomperr);
1754 		break;
1755 	case UATH_STATUS_KEY_ERR:
1756 		UATH_STAT_INC(sc, st_keyerr);
1757 		break;
1758 	case UATH_STATUS_ERR:
1759 		UATH_STAT_INC(sc, st_err);
1760 		break;
1761 	default:
1762 		break;
1763 	}
1764 }
1765 
1766 static void
1767 uath_next_scan(void *arg)
1768 {
1769 	struct uath_softc	*sc = arg;
1770 	struct ieee80211com	*ic = &sc->sc_ic;
1771 
1772 	if (ic->ic_state == IEEE80211_S_SCAN)
1773 		ieee80211_next_scan(ic);
1774 
1775 	sc->sc_scan_id = 0;
1776 }
1777 
1778 static int
1779 uath_create_connection(struct uath_softc *sc, uint32_t connid)
1780 {
1781 	const struct ieee80211_rateset *rs;
1782 	struct ieee80211com *ic = &sc->sc_ic;
1783 	struct ieee80211_node *ni = ic->ic_bss;
1784 	struct uath_cmd_create_connection create;
1785 	int err;
1786 
1787 	bzero(&create, sizeof (create));
1788 	create.connid = BE_32(connid);
1789 	create.bssid = BE_32(0);
1790 	/* XXX packed or not?  */
1791 	create.size = BE_32(sizeof (struct uath_cmd_rateset));
1792 
1793 	rs = &ni->in_rates;
1794 	create.connattr.rateset.length = rs->ir_nrates;
1795 	bcopy(rs->ir_rates, &create.connattr.rateset.set[0],
1796 	    rs->ir_nrates);
1797 
1798 	/* XXX turbo */
1799 	if (UATH_IS_CHAN_A(ni->in_chan))
1800 		create.connattr.wlanmode = BE_32(WLAN_MODE_11a);
1801 	else if (UATH_IS_CHAN_ANYG(ni->in_chan))
1802 		create.connattr.wlanmode = BE_32(WLAN_MODE_11g);
1803 	else
1804 		create.connattr.wlanmode = BE_32(WLAN_MODE_11b);
1805 
1806 	err = uath_cmd_write(sc, WDCMSG_CREATE_CONNECTION, &create,
1807 	    sizeof (create), 0);
1808 	return (err);
1809 }
1810 
1811 static int
1812 uath_set_rates(struct uath_softc *sc, const struct ieee80211_rateset *rs)
1813 {
1814 	struct uath_cmd_rates rates;
1815 	int err;
1816 
1817 	bzero(&rates, sizeof (rates));
1818 	rates.connid = BE_32(UATH_ID_BSS);		/* XXX */
1819 	rates.size   = BE_32(sizeof (struct uath_cmd_rateset));
1820 	/* XXX bounds check rs->rs_nrates */
1821 	rates.rateset.length = rs->ir_nrates;
1822 	bcopy(rs->ir_rates, &rates.rateset.set[0], rs->ir_nrates);
1823 
1824 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_rates(): "
1825 	    "setting supported rates nrates=%d\n", rs->ir_nrates);
1826 	err = uath_cmd_write(sc, WDCMSG_SET_BASIC_RATE,
1827 	    &rates, sizeof (rates), 0);
1828 	return (err);
1829 }
1830 
1831 static int
1832 uath_write_associd(struct uath_softc *sc)
1833 {
1834 	struct ieee80211com *ic = &sc->sc_ic;
1835 	struct ieee80211_node *ni = ic->ic_bss;
1836 	struct uath_cmd_set_associd associd;
1837 	int err;
1838 
1839 	bzero(&associd, sizeof (associd));
1840 	associd.defaultrateix = BE_32(1);	/* XXX */
1841 	associd.associd = BE_32(ni->in_associd);
1842 	associd.timoffset = BE_32(0x3b);	/* XXX */
1843 	IEEE80211_ADDR_COPY(associd.bssid, ni->in_bssid);
1844 	err = uath_cmd_write(sc, WDCMSG_WRITE_ASSOCID, &associd,
1845 	    sizeof (associd), 0);
1846 	return (err);
1847 }
1848 
1849 static int
1850 uath_set_ledsteady(struct uath_softc *sc, int lednum, int ledmode)
1851 {
1852 	struct uath_cmd_ledsteady led;
1853 	int err;
1854 
1855 	led.lednum = BE_32(lednum);
1856 	led.ledmode = BE_32(ledmode);
1857 
1858 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_ledsteady(): "
1859 	    "set %s led %s (steady)\n",
1860 	    (lednum == UATH_LED_LINK) ? "link" : "activity",
1861 	    ledmode ? "on" : "off");
1862 	err = uath_cmd_write(sc, WDCMSG_SET_LED_STEADY, &led, sizeof (led), 0);
1863 	return (err);
1864 }
1865 
1866 static int
1867 uath_set_ledblink(struct uath_softc *sc, int lednum, int ledmode,
1868     int blinkrate, int slowmode)
1869 {
1870 	struct uath_cmd_ledblink led;
1871 	int err;
1872 
1873 	led.lednum = BE_32(lednum);
1874 	led.ledmode = BE_32(ledmode);
1875 	led.blinkrate = BE_32(blinkrate);
1876 	led.slowmode = BE_32(slowmode);
1877 
1878 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_ledblink(): "
1879 	    "set %s led %s (blink)\n",
1880 	    (lednum == UATH_LED_LINK) ? "link" : "activity",
1881 	    ledmode ? "on" : "off");
1882 
1883 	err = uath_cmd_write(sc, WDCMSG_SET_LED_BLINK,
1884 	    &led, sizeof (led), 0);
1885 	return (err);
1886 }
1887 
1888 
1889 static int
1890 uath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
1891 {
1892 	struct uath_softc *sc = (struct uath_softc *)ic;
1893 	struct ieee80211_node *ni = ic->ic_bss;
1894 	enum ieee80211_state ostate;
1895 	int err;
1896 
1897 	ostate = ic->ic_state;
1898 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_newstate(): "
1899 	    "%d -> %d\n", ostate, nstate);
1900 
1901 	if (sc->sc_scan_id != 0) {
1902 		(void) untimeout(sc->sc_scan_id);
1903 		sc->sc_scan_id = 0;
1904 	}
1905 
1906 	UATH_LOCK(sc);
1907 
1908 	if (UATH_IS_DISCONNECT(sc) && (nstate != IEEE80211_S_INIT)) {
1909 		UATH_UNLOCK(sc);
1910 		return (DDI_SUCCESS);
1911 	}
1912 
1913 	if (UATH_IS_SUSPEND(sc) && (nstate != IEEE80211_S_INIT)) {
1914 		UATH_UNLOCK(sc);
1915 		return (DDI_SUCCESS);
1916 	}
1917 
1918 	switch (nstate) {
1919 	case IEEE80211_S_INIT:
1920 		if (ostate == IEEE80211_S_RUN) {
1921 			/* turn link and activity LEDs off */
1922 			(void) uath_set_ledstate(sc, 0);
1923 		}
1924 		break;
1925 	case IEEE80211_S_SCAN:
1926 		if (uath_switch_channel(sc, ic->ic_curchan) != UATH_SUCCESS) {
1927 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): "
1928 			    "could not switch channel\n");
1929 			break;
1930 		}
1931 		sc->sc_scan_id = timeout(uath_next_scan, (void *)sc,
1932 		    drv_usectohz(250000));
1933 		break;
1934 	case IEEE80211_S_AUTH:
1935 		/* XXX good place?  set RTS threshold  */
1936 		uath_config(sc, CFG_USER_RTS_THRESHOLD, ic->ic_rtsthreshold);
1937 
1938 		if (uath_switch_channel(sc, ni->in_chan) != 0) {
1939 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): "
1940 			    "could not switch channel\n");
1941 			break;
1942 		}
1943 		if (uath_create_connection(sc, UATH_ID_BSS) != 0) {
1944 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): "
1945 			    "could not create connection\n");
1946 			break;
1947 		}
1948 		break;
1949 	case IEEE80211_S_ASSOC:
1950 		if (uath_set_rates(sc, &ni->in_rates) != 0) {
1951 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): "
1952 			    "could not set negotiated rate set\n");
1953 			break;
1954 		}
1955 		break;
1956 	case IEEE80211_S_RUN:
1957 		/* XXX monitor mode doesn't be supported  */
1958 		if (ic->ic_opmode == IEEE80211_M_MONITOR) {
1959 			(void) uath_set_ledstate(sc, 1);
1960 			break;
1961 		}
1962 
1963 		/*
1964 		 * Tx rate is controlled by firmware, report the maximum
1965 		 * negotiated rate in ifconfig output.
1966 		 */
1967 		ni->in_txrate = ni->in_rates.ir_nrates - 1;
1968 
1969 		if (uath_write_associd(sc) != 0) {
1970 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_newstate(): "
1971 			    "could not write association id\n");
1972 			break;
1973 		}
1974 		/* turn link LED on */
1975 		(void) uath_set_ledsteady(sc, UATH_LED_LINK, UATH_LED_ON);
1976 		/* make activity LED blink */
1977 		(void) uath_set_ledblink(sc, UATH_LED_ACTIVITY,
1978 		    UATH_LED_ON, 1, 2);
1979 		/* set state to associated */
1980 		(void) uath_set_ledstate(sc, 1);
1981 		break;
1982 	}
1983 
1984 	UATH_UNLOCK(sc);
1985 
1986 	err = sc->sc_newstate(ic, nstate, arg);
1987 	return (err);
1988 }
1989 
1990 static int
1991 uath_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
1992 {
1993 	struct uath_softc *sc = (struct uath_softc *)ic;
1994 	struct uath_chunk *chunk;
1995 	struct uath_tx_desc *desc;
1996 	struct ieee80211_frame *wh;
1997 	struct ieee80211_node *ni = NULL;
1998 	struct ieee80211_key *k;
1999 
2000 	mblk_t *m, *m0;
2001 	int err, off, mblen;
2002 	int pktlen, framelen, msglen;
2003 
2004 	err = UATH_SUCCESS;
2005 
2006 	mutex_enter(&sc->sc_txlock_data);
2007 
2008 	if (UATH_IS_SUSPEND(sc)) {
2009 		err = 0;
2010 		goto fail;
2011 	}
2012 
2013 	if (sc->tx_data_queued > UATH_TX_DATA_LIST_COUNT) {
2014 		UATH_DEBUG(UATH_DBG_TX, "uath: uath_send(): "
2015 		    "no TX buffer available!\n");
2016 		if ((type & IEEE80211_FC0_TYPE_MASK) ==
2017 		    IEEE80211_FC0_TYPE_DATA) {
2018 			sc->sc_need_sched = 1;
2019 		}
2020 		sc->sc_tx_nobuf++;
2021 		err = ENOMEM;
2022 		goto fail;
2023 	}
2024 
2025 	m = allocb(UATH_MAX_TXBUFSZ, BPRI_MED);
2026 	if (m == NULL) {
2027 		UATH_DEBUG(UATH_DBG_TX, "uath: uath_send(): "
2028 		    "can't alloc mblk.\n");
2029 		err = DDI_FAILURE;
2030 		goto fail;
2031 	}
2032 
2033 	/* skip TX descriptor */
2034 	m->b_rptr += sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc);
2035 	m->b_wptr += sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc);
2036 
2037 	for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
2038 		mblen = (uintptr_t)m0->b_wptr - (uintptr_t)m0->b_rptr;
2039 		(void) memcpy(m->b_rptr + off, m0->b_rptr, mblen);
2040 		off += mblen;
2041 	}
2042 	m->b_wptr += off;
2043 
2044 	wh = (struct ieee80211_frame *)m->b_rptr;
2045 
2046 	ni = ieee80211_find_txnode(ic, wh->i_addr1);
2047 	if (ni == NULL) {
2048 		err = DDI_FAILURE;
2049 		freemsg(m);
2050 		goto fail;
2051 	}
2052 
2053 	if ((type & IEEE80211_FC0_TYPE_MASK) ==
2054 	    IEEE80211_FC0_TYPE_DATA) {
2055 		(void) ieee80211_encap(ic, m, ni);
2056 	}
2057 
2058 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
2059 		k = ieee80211_crypto_encap(ic, m);
2060 		if (k == NULL) {
2061 			freemsg(m);
2062 			err = DDI_FAILURE;
2063 			goto fail;
2064 		}
2065 		/* packet header may have moved, reset our local pointer */
2066 		wh = (struct ieee80211_frame *)m->b_rptr;
2067 	}
2068 
2069 	pktlen = (uintptr_t)m->b_wptr - (uintptr_t)m->b_rptr;
2070 	framelen = pktlen + IEEE80211_CRC_LEN;
2071 	msglen = framelen + sizeof (struct uath_tx_desc);
2072 
2073 	m->b_rptr -= sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc);
2074 
2075 	chunk = (struct uath_chunk *)m->b_rptr;
2076 	desc = (struct uath_tx_desc *)(chunk + 1);
2077 
2078 	/* one chunk only for now */
2079 	chunk->seqnum = 0;
2080 	chunk->flags = UATH_CFLAGS_FINAL;
2081 	chunk->length = BE_16(msglen);
2082 
2083 	/* fill Tx descriptor */
2084 	desc->msglen = BE_32(msglen);
2085 	/* NB: to get UATH_TX_NOTIFY reply, `msgid' must be larger than 0  */
2086 	desc->msgid  = sc->sc_msgid; /* don't care about endianness */
2087 	desc->type   = BE_32(WDCMSG_SEND);
2088 	switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
2089 	case IEEE80211_FC0_TYPE_CTL:
2090 	case IEEE80211_FC0_TYPE_MGT:
2091 		/* NB: force all management frames to highest queue */
2092 		if (ni->in_flags & UATH_NODE_QOS) {
2093 			/* NB: force all management frames to highest queue */
2094 			desc->txqid = BE_32(WME_AC_VO | UATH_TXQID_MINRATE);
2095 		} else
2096 			desc->txqid = BE_32(WME_AC_BE | UATH_TXQID_MINRATE);
2097 		break;
2098 	case IEEE80211_FC0_TYPE_DATA:
2099 		/* XXX multicast frames should honor mcastrate */
2100 		desc->txqid = BE_32(WME_AC_BE);
2101 		break;
2102 	default:
2103 		UATH_DEBUG(UATH_DBG_TX, "uath: uath_send(): "
2104 		    "bogus frame type 0x%x (%s)\n",
2105 		    wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
2106 		err = EIO;
2107 		goto fail;
2108 	}
2109 
2110 	if (ic->ic_state == IEEE80211_S_AUTH ||
2111 	    ic->ic_state == IEEE80211_S_ASSOC ||
2112 	    ic->ic_state == IEEE80211_S_RUN)
2113 		desc->connid = BE_32(UATH_ID_BSS);
2114 	else
2115 		desc->connid = BE_32(UATH_ID_INVALID);
2116 	desc->flags  = BE_32(0 /* no UATH_TX_NOTIFY */);
2117 	desc->buflen = BE_32(pktlen);
2118 
2119 	(void) uath_tx_data_xfer(sc, m);
2120 
2121 	sc->sc_msgid = (sc->sc_msgid + 1) % UATH_TX_DATA_LIST_COUNT;
2122 
2123 	ic->ic_stats.is_tx_frags++;
2124 	ic->ic_stats.is_tx_bytes += pktlen;
2125 
2126 fail:
2127 	if (ni != NULL)
2128 		ieee80211_free_node(ni);
2129 	if ((mp) &&
2130 	    ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA ||
2131 	    err == 0)) {
2132 		freemsg(mp);
2133 	}
2134 	mutex_exit(&sc->sc_txlock_data);
2135 	return (err);
2136 }
2137 
2138 static int
2139 uath_reconnect(dev_info_t *devinfo)
2140 {
2141 	struct uath_softc *sc;
2142 	struct ieee80211com *ic;
2143 	int err;
2144 	uint16_t vendor_id, product_id;
2145 
2146 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_reconnect(): "
2147 	    "uath online\n");
2148 
2149 	sc = ddi_get_soft_state(uath_soft_state_p, ddi_get_instance(devinfo));
2150 	ASSERT(sc != NULL);
2151 	ic = (struct ieee80211com *)&sc->sc_ic;
2152 
2153 	if (!UATH_IS_RECONNECT(sc)) {
2154 		err = uath_open_pipes(sc);
2155 		if (err != UATH_SUCCESS) {
2156 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2157 			    "could not open pipes\n");
2158 			return (DDI_FAILURE);
2159 		}
2160 
2161 		err = uath_loadfirmware(sc);
2162 		if (err != DDI_SUCCESS) {
2163 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2164 			    "could not download firmware\n");
2165 			return (DDI_FAILURE);
2166 		}
2167 
2168 		uath_close_pipes(sc);
2169 		usb_client_detach(sc->sc_dev, sc->sc_udev);
2170 
2171 		/* reset device */
2172 		err = usb_reset_device(sc->sc_dev, USB_RESET_LVL_DEFAULT);
2173 		if (err != USB_SUCCESS) {
2174 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2175 			    "could not reset device %x\n", err);
2176 		}
2177 
2178 		err = usb_client_attach(devinfo, USBDRV_VERSION, 0);
2179 		if (err != USB_SUCCESS) {
2180 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2181 			    "usb_client_attach failed\n");
2182 		}
2183 
2184 		err = usb_get_dev_data(devinfo, &sc->sc_udev,
2185 		    USB_PARSE_LVL_ALL, 0);
2186 		if (err != USB_SUCCESS) {
2187 			sc->sc_udev = NULL;
2188 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2189 			    "usb_get_dev_data failed\n");
2190 		}
2191 
2192 		vendor_id = sc->sc_udev->dev_descr->idVendor;
2193 		product_id = sc->sc_udev->dev_descr->idProduct;
2194 		sc->dev_flags = uath_lookup(vendor_id, product_id);
2195 		if (sc->dev_flags == UATH_FLAG_ERR) {
2196 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2197 			    "HW does not match\n");
2198 		}
2199 
2200 		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_reconnect(): "
2201 		    "vendorId = %x,deviceID = %x, flags = %x\n",
2202 		    vendor_id, product_id, sc->dev_flags);
2203 
2204 		UATH_LOCK(sc);
2205 		sc->sc_flags |= UATH_FLAG_RECONNECT;
2206 		UATH_UNLOCK(sc);
2207 
2208 	} else {
2209 		err = uath_open_pipes(sc);
2210 		if (err != UATH_SUCCESS) {
2211 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2212 			    "could not open pipes\n");
2213 			return (DDI_FAILURE);
2214 		}
2215 
2216 		/*
2217 		 * Allocate xfers for firmware commands.
2218 		 */
2219 		err = uath_alloc_cmd_list(sc, sc->sc_cmd, UATH_CMD_LIST_COUNT,
2220 		    UATH_MAX_CMDSZ);
2221 		if (err != UATH_SUCCESS) {
2222 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2223 			    "could not allocate Tx command list\n");
2224 			return (DDI_FAILURE);
2225 		}
2226 
2227 		err = uath_init_cmd_list(sc);
2228 		if (err != UATH_SUCCESS) {
2229 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2230 			    "could not init RX command list\n");
2231 			return (DDI_FAILURE);
2232 		}
2233 
2234 		/*
2235 		 * We're now ready to send+receive firmware commands.
2236 		 */
2237 		err = uath_host_available(sc);
2238 		if (err != UATH_SUCCESS) {
2239 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2240 			    "could not initialize adapter\n");
2241 			return (DDI_FAILURE);
2242 		}
2243 
2244 		err = uath_get_devcap(sc);
2245 		if (err != UATH_SUCCESS) {
2246 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2247 			    "could not get device capabilities\n");
2248 			return (DDI_FAILURE);
2249 		}
2250 
2251 		err = uath_get_devstatus(sc, ic->ic_macaddr);
2252 		if (err != UATH_SUCCESS) {
2253 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2254 			    "could not get dev status\n");
2255 			return (DDI_FAILURE);
2256 		}
2257 
2258 		err = usb_check_same_device(sc->sc_dev, NULL, USB_LOG_L2, -1,
2259 		    USB_CHK_BASIC, NULL);
2260 		if (err != USB_SUCCESS) {
2261 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2262 			    "different device connected %x\n", err);
2263 			return (DDI_FAILURE);
2264 		}
2265 
2266 		err = uath_init(sc);
2267 		if (err != UATH_SUCCESS) {
2268 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_reconnect(): "
2269 			    "device re-connect failed\n");
2270 			return (DDI_FAILURE);
2271 		}
2272 
2273 		UATH_LOCK(sc);
2274 		sc->sc_flags &= ~UATH_FLAG_RECONNECT;
2275 		sc->sc_flags &= ~UATH_FLAG_DISCONNECT;
2276 		sc->sc_flags |= UATH_FLAG_RUNNING;
2277 		UATH_UNLOCK(sc);
2278 	}
2279 
2280 	return (DDI_SUCCESS);
2281 }
2282 
2283 static int
2284 uath_disconnect(dev_info_t *devinfo)
2285 {
2286 	struct uath_softc *sc;
2287 	struct ieee80211com *ic;
2288 
2289 	/*
2290 	 * We can't call uath_stop() here, since the hardware is removed,
2291 	 * we can't access the register anymore.
2292 	 */
2293 	sc = ddi_get_soft_state(uath_soft_state_p, ddi_get_instance(devinfo));
2294 	ASSERT(sc != NULL);
2295 
2296 	if (sc->sc_flags & UATH_FLAG_RECONNECT) {
2297 		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_disconnect(): "
2298 		    "stage 0 in re-connect\n");
2299 		uath_close_pipes(sc);
2300 		return (DDI_SUCCESS);
2301 	}
2302 
2303 	UATH_LOCK(sc);
2304 	sc->sc_flags |= UATH_FLAG_DISCONNECT;
2305 	UATH_UNLOCK(sc);
2306 
2307 	ic = (struct ieee80211com *)&sc->sc_ic;
2308 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
2309 
2310 	UATH_LOCK(sc);
2311 	sc->sc_flags &= ~UATH_FLAG_RUNNING;	/* STOP */
2312 	UATH_UNLOCK(sc);
2313 
2314 	/* abort and free xfers */
2315 	uath_free_cmd_list(sc->sc_cmd, UATH_CMD_LIST_COUNT);
2316 
2317 	/* close Tx/Rx pipes */
2318 	uath_close_pipes(sc);
2319 
2320 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_disconnect(): "
2321 	    "offline success\n");
2322 
2323 	return (DDI_SUCCESS);
2324 }
2325 
2326 static int
2327 uath_dataflush(struct uath_softc *sc)
2328 {
2329 	struct uath_chunk *chunk;
2330 	struct uath_tx_desc *desc;
2331 	uint8_t *buf;
2332 	int err;
2333 
2334 	buf = kmem_alloc(UATH_MAX_TXBUFSZ, KM_NOSLEEP);
2335 	if (buf == NULL) {
2336 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_dataflush(): "
2337 		    "no bufs\n");
2338 		return (ENOBUFS);
2339 	}
2340 
2341 	chunk = (struct uath_chunk *)buf;
2342 	desc = (struct uath_tx_desc *)(chunk + 1);
2343 
2344 	/* one chunk only */
2345 	chunk->seqnum = 0;
2346 	chunk->flags = UATH_CFLAGS_FINAL;
2347 	chunk->length = BE_16(sizeof (struct uath_tx_desc));
2348 
2349 	bzero(desc, sizeof (struct uath_tx_desc));
2350 	desc->msglen = BE_32(sizeof (struct uath_tx_desc));
2351 	desc->msgid  = sc->sc_msgid; /* don't care about endianness */
2352 	desc->type   = BE_32(WDCMSG_FLUSH);
2353 	desc->txqid  = BE_32(0);
2354 	desc->connid = BE_32(0);
2355 	desc->flags  = BE_32(0);
2356 
2357 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_dataflush(): "
2358 	    "send flush ix %d\n", desc->msgid);
2359 
2360 	err = uath_fw_send(sc, sc->tx_data_pipe, buf,
2361 	    sizeof (struct uath_chunk) + sizeof (struct uath_tx_desc));
2362 	if (err != UATH_SUCCESS) {
2363 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_dataflush(): "
2364 		    "data flush error");
2365 		return (UATH_FAILURE);
2366 	}
2367 
2368 	kmem_free(buf, UATH_MAX_TXBUFSZ);
2369 	sc->sc_msgid = (sc->sc_msgid + 1) % UATH_TX_DATA_LIST_COUNT;
2370 
2371 	return (UATH_SUCCESS);
2372 }
2373 
2374 static int
2375 uath_cmdflush(struct uath_softc *sc)
2376 {
2377 	return (uath_cmd_write(sc, WDCMSG_FLUSH, NULL, 0, 0));
2378 }
2379 
2380 static int
2381 uath_flush(struct uath_softc *sc)
2382 {
2383 	int err;
2384 
2385 	err = uath_dataflush(sc);
2386 	if (err != UATH_SUCCESS)
2387 		goto failed;
2388 
2389 	err = uath_cmdflush(sc);
2390 	if (err != UATH_SUCCESS)
2391 		goto failed;
2392 
2393 	return (UATH_SUCCESS);
2394 failed:
2395 	return (err);
2396 }
2397 
2398 static int
2399 uath_set_ledstate(struct uath_softc *sc, int connected)
2400 {
2401 	int err;
2402 
2403 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_ledstate(): "
2404 	    "set led state %sconnected\n", connected ? "" : "!");
2405 
2406 	connected = BE_32(connected);
2407 	err = uath_cmd_write(sc, WDCMSG_SET_LED_STATE,
2408 	    &connected, sizeof (connected), 0);
2409 	return (err);
2410 }
2411 
2412 static int
2413 uath_config_multi(struct uath_softc *sc, uint32_t reg, const void *data,
2414     int len)
2415 {
2416 	struct uath_write_mac write;
2417 	int err;
2418 
2419 	write.reg = BE_32(reg);
2420 	write.len = BE_32(len);
2421 	bcopy(data, write.data, len);
2422 
2423 	/* properly handle the case where len is zero (reset) */
2424 	err = uath_cmd_write(sc, WDCMSG_TARGET_SET_CONFIG, &write,
2425 	    (len == 0) ? sizeof (uint32_t) : 2 * sizeof (uint32_t) + len, 0);
2426 	if (err != UATH_SUCCESS) {
2427 		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_config_multi(): "
2428 		    "could not write %d bytes to register 0x%02x\n", len, reg);
2429 	}
2430 	return (err);
2431 }
2432 
2433 static void
2434 uath_config(struct uath_softc *sc, uint32_t reg, uint32_t val)
2435 {
2436 	struct uath_write_mac write;
2437 	int err;
2438 
2439 	write.reg = BE_32(reg);
2440 	write.len = BE_32(0);	/* 0 = single write */
2441 	*(uint32_t *)write.data = BE_32(val);
2442 
2443 	err = uath_cmd_write(sc, WDCMSG_TARGET_SET_CONFIG, &write,
2444 	    3 * sizeof (uint32_t), 0);
2445 	if (err != UATH_SUCCESS) {
2446 		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_config(): "
2447 		    "could not write register 0x%02x\n",
2448 		    reg);
2449 	}
2450 }
2451 
2452 static int
2453 uath_switch_channel(struct uath_softc *sc, struct ieee80211_channel *c)
2454 {
2455 	int err;
2456 
2457 	/* set radio frequency */
2458 	err = uath_set_chan(sc, c);
2459 	if (err) {
2460 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): "
2461 		    "could not set channel\n");
2462 		goto failed;
2463 	}
2464 
2465 	/* reset Tx rings */
2466 	err = uath_reset_tx_queues(sc);
2467 	if (err) {
2468 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): "
2469 		    "could not reset Tx queues\n");
2470 		goto failed;
2471 	}
2472 
2473 	/* set Tx rings WME properties */
2474 	err = uath_wme_init(sc);
2475 	if (err) {
2476 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): "
2477 		    "could not init Tx queues\n");
2478 		goto failed;
2479 	}
2480 
2481 	err = uath_set_ledstate(sc, 0);
2482 	if (err) {
2483 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): "
2484 		    "could not set led state\n");
2485 		goto failed;
2486 	}
2487 
2488 	err = uath_flush(sc);
2489 	if (err) {
2490 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_switch_channel(): "
2491 		    "could not flush pipes\n");
2492 		goto failed;
2493 	}
2494 
2495 failed:
2496 	return (err);
2497 }
2498 
2499 static int
2500 uath_set_rxfilter(struct uath_softc *sc, uint32_t bits, uint32_t op)
2501 {
2502 	struct uath_cmd_rx_filter rxfilter;
2503 
2504 	rxfilter.bits = BE_32(bits);
2505 	rxfilter.op = BE_32(op);
2506 
2507 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_rxfilter(): "
2508 	    "setting Rx filter=0x%x flags=0x%x\n", bits, op);
2509 
2510 	return ((uath_cmd_write(sc, WDCMSG_RX_FILTER, &rxfilter,
2511 	    sizeof (rxfilter), 0)));
2512 }
2513 
2514 static int
2515 uath_set_chan(struct uath_softc *sc, struct ieee80211_channel *c)
2516 {
2517 	struct ieee80211com *ic = &sc->sc_ic;
2518 	struct uath_cmd_reset reset;
2519 
2520 	bzero(&reset, sizeof (reset));
2521 	if (IEEE80211_IS_CHAN_2GHZ(c))
2522 		reset.flags |= BE_32(UATH_CHAN_2GHZ);
2523 	if (IEEE80211_IS_CHAN_5GHZ(c))
2524 		reset.flags |= BE_32(UATH_CHAN_5GHZ);
2525 	/* NB: 11g =>'s 11b so don't specify both OFDM and CCK */
2526 	if (UATH_IS_CHAN_OFDM(c))
2527 		reset.flags |= BE_32(UATH_CHAN_OFDM);
2528 	else if (UATH_IS_CHAN_CCK(c))
2529 		reset.flags |= BE_32(UATH_CHAN_CCK);
2530 	/* turbo can be used in either 2GHz or 5GHz */
2531 	if (c->ich_flags & IEEE80211_CHAN_TURBO)
2532 		reset.flags |= BE_32(UATH_CHAN_TURBO);
2533 
2534 	reset.freq = BE_32(c->ich_freq);
2535 	reset.maxrdpower = BE_32(50);	/* XXX */
2536 	reset.channelchange = BE_32(1);
2537 	reset.keeprccontent = BE_32(0);
2538 
2539 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_set_chan(): "
2540 	    "set channel %d, flags 0x%x freq %u\n",
2541 	    ieee80211_chan2ieee(ic, c),
2542 	    BE_32(reset.flags), BE_32(reset.freq));
2543 
2544 	return (uath_cmd_write(sc, WDCMSG_RESET, &reset, sizeof (reset), 0));
2545 }
2546 
2547 static int
2548 uath_reset_tx_queues(struct uath_softc *sc)
2549 {
2550 	int ac, err;
2551 
2552 	for (ac = 0; ac < 4; ac++) {
2553 		const uint32_t qid = BE_32(ac);
2554 		err = uath_cmd_write(sc, WDCMSG_RELEASE_TX_QUEUE, &qid,
2555 		    sizeof (qid), 0);
2556 		if (err != UATH_SUCCESS)
2557 			break;
2558 	}
2559 	return (err);
2560 }
2561 
2562 static int
2563 uath_wme_init(struct uath_softc *sc)
2564 {
2565 	/* XXX get from net80211 */
2566 	static const struct uath_wme_settings uath_wme_11g[4] = {
2567 		{ 7, 4, 10,  0, 0 },	/* Background */
2568 		{ 3, 4, 10,  0, 0 },	/* Best-Effort */
2569 		{ 3, 3,  4, 26, 0 },	/* Video */
2570 		{ 2, 2,  3, 47, 0 }	/* Voice */
2571 	};
2572 
2573 	struct uath_cmd_txq_setup qinfo;
2574 	int ac, err;
2575 
2576 	for (ac = 0; ac < 4; ac++) {
2577 		qinfo.qid		= BE_32(ac);
2578 		qinfo.len		= BE_32(sizeof (qinfo.attr));
2579 		qinfo.attr.priority	= BE_32(ac);	/* XXX */
2580 		qinfo.attr.aifs		= BE_32(uath_wme_11g[ac].aifsn);
2581 		qinfo.attr.logcwmin	= BE_32(uath_wme_11g[ac].logcwmin);
2582 		qinfo.attr.logcwmax	= BE_32(uath_wme_11g[ac].logcwmax);
2583 		qinfo.attr.mode		= BE_32(uath_wme_11g[ac].acm);
2584 		qinfo.attr.qflags	= BE_32(1);
2585 		qinfo.attr.bursttime	=
2586 		    BE_32(UATH_TXOP_TO_US(uath_wme_11g[ac].txop));
2587 
2588 		err = uath_cmd_write(sc, WDCMSG_SETUP_TX_QUEUE, &qinfo,
2589 		    sizeof (qinfo), 0);
2590 		if (err != UATH_SUCCESS)
2591 			break;
2592 	}
2593 	return (err);
2594 }
2595 
2596 static void
2597 uath_stop_locked(void *arg)
2598 {
2599 	struct uath_softc *sc = (struct uath_softc *)arg;
2600 
2601 	/* flush data & control requests into the target  */
2602 	(void) uath_flush(sc);
2603 
2604 	/* set a LED status to the disconnected.  */
2605 	(void) uath_set_ledstate(sc, 0);
2606 
2607 	/* stop the target  */
2608 	(void) uath_cmd_write(sc, WDCMSG_TARGET_STOP, NULL, 0, 0);
2609 
2610 	/* abort any pending transfers */
2611 	usb_pipe_reset(sc->sc_dev, sc->rx_data_pipe, USB_FLAGS_SLEEP, NULL, 0);
2612 	usb_pipe_reset(sc->sc_dev, sc->tx_data_pipe, USB_FLAGS_SLEEP, NULL, 0);
2613 	usb_pipe_reset(sc->sc_dev, sc->tx_cmd_pipe, USB_FLAGS_SLEEP, NULL, 0);
2614 }
2615 
2616 static int
2617 uath_init_locked(void *arg)
2618 {
2619 	struct uath_softc *sc = arg;
2620 	struct ieee80211com *ic = &sc->sc_ic;
2621 	uint32_t val;
2622 	int i, err;
2623 
2624 	if (UATH_IS_RUNNING(sc))
2625 		uath_stop_locked(sc);
2626 
2627 	uath_init_data_queue(sc);
2628 
2629 	/* reset variables */
2630 	sc->sc_intrx_nextnum = sc->sc_msgid = 0;
2631 
2632 	val = BE_32(0);
2633 	(void) uath_cmd_write(sc, WDCMSG_BIND, &val, sizeof (val), 0);
2634 
2635 	/* set MAC address */
2636 	(void) uath_config_multi(sc, CFG_MAC_ADDR,
2637 	    ic->ic_macaddr, IEEE80211_ADDR_LEN);
2638 
2639 	/* XXX honor net80211 state */
2640 	uath_config(sc, CFG_RATE_CONTROL_ENABLE, 0x00000001);
2641 	uath_config(sc, CFG_DIVERSITY_CTL, 0x00000001);
2642 	uath_config(sc, CFG_ABOLT, 0x0000003f);
2643 	uath_config(sc, CFG_WME_ENABLED, 0x00000001);
2644 
2645 	uath_config(sc, CFG_SERVICE_TYPE, 1);
2646 	uath_config(sc, CFG_TP_SCALE, 0x00000000);
2647 	uath_config(sc, CFG_TPC_HALF_DBM5, 0x0000003c);
2648 	uath_config(sc, CFG_TPC_HALF_DBM2, 0x0000003c);
2649 	uath_config(sc, CFG_OVERRD_TX_POWER, 0x00000000);
2650 	uath_config(sc, CFG_GMODE_PROTECTION, 0x00000000);
2651 	uath_config(sc, CFG_GMODE_PROTECT_RATE_INDEX, 0x00000003);
2652 	uath_config(sc, CFG_PROTECTION_TYPE, 0x00000000);
2653 	uath_config(sc, CFG_MODE_CTS, 0x00000002);
2654 
2655 	err = uath_cmd_read(sc, WDCMSG_TARGET_START, NULL, 0,
2656 	    &val, sizeof (val), UATH_CMD_FLAG_MAGIC);
2657 	if (err) {
2658 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init_locked(): "
2659 		    "could not start target\n");
2660 		goto fail;
2661 	}
2662 
2663 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_init_locked(): "
2664 	    "%s returns handle: 0x%x\n",
2665 	    uath_codename(WDCMSG_TARGET_START), BE_32(val));
2666 
2667 	/* set default channel */
2668 	err = uath_switch_channel(sc, ic->ic_curchan);
2669 	if (err) {
2670 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init_locked(): "
2671 		    "could not switch channel, error %d\n", err);
2672 		goto fail;
2673 	}
2674 
2675 	val = BE_32(TARGET_DEVICE_AWAKE);
2676 	(void) uath_cmd_write(sc, WDCMSG_SET_PWR_MODE, &val, sizeof (val), 0);
2677 	/* XXX? check */
2678 	(void) uath_cmd_write(sc, WDCMSG_RESET_KEY_CACHE, NULL, 0, 0);
2679 
2680 	for (i = 0; i < UATH_RX_DATA_LIST_COUNT; i++) {
2681 		err = uath_rx_data_xfer(sc);
2682 		if (err != UATH_SUCCESS) {
2683 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init_locked(): "
2684 			    "could not alloc rx xfer %x\n", i);
2685 			goto fail;
2686 		}
2687 	}
2688 
2689 	/* enable Rx */
2690 	(void) uath_set_rxfilter(sc, 0x0, UATH_FILTER_OP_INIT);
2691 	(void) uath_set_rxfilter(sc,
2692 	    UATH_FILTER_RX_UCAST | UATH_FILTER_RX_MCAST |
2693 	    UATH_FILTER_RX_BCAST | UATH_FILTER_RX_BEACON,
2694 	    UATH_FILTER_OP_SET);
2695 
2696 	return (UATH_SUCCESS);
2697 
2698 fail:
2699 	uath_stop_locked(sc);
2700 	return (err);
2701 }
2702 
2703 static int
2704 uath_init(struct uath_softc *sc)
2705 {
2706 	int err;
2707 
2708 	UATH_LOCK(sc);
2709 	err = uath_init_locked(sc);
2710 	if (err != UATH_SUCCESS) {
2711 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_init(): "
2712 		    "failed to initialize uath hardware\n");
2713 		UATH_UNLOCK(sc);
2714 		return (DDI_FAILURE);
2715 	}
2716 	UATH_UNLOCK(sc);
2717 	return (DDI_SUCCESS);
2718 }
2719 
2720 static void
2721 uath_stop(struct uath_softc *sc)
2722 {
2723 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_stop(): "
2724 	    "uath stop now\n");
2725 
2726 	UATH_LOCK(sc);
2727 	uath_stop_locked(sc);
2728 	UATH_UNLOCK(sc);
2729 }
2730 
2731 static void
2732 uath_resume(struct uath_softc *sc)
2733 {
2734 	int err;
2735 
2736 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_resume(): "
2737 	    "uath resume now\n");
2738 
2739 	/* check device changes after suspend */
2740 	if (usb_check_same_device(sc->sc_dev, NULL, USB_LOG_L2, -1,
2741 	    USB_CHK_BASIC | USB_CHK_CFG, NULL) != USB_SUCCESS) {
2742 		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_resume: "
2743 		    "no or different device connected\n");
2744 		return;
2745 	}
2746 
2747 	/*
2748 	 * initialize hardware
2749 	 */
2750 	err = uath_init_cmd_list(sc);
2751 	if (err != UATH_SUCCESS) {
2752 		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_resume(): "
2753 		    "could not init RX command list\n");
2754 		return;
2755 	}
2756 
2757 	err = uath_init(sc);
2758 	if (err != UATH_SUCCESS) {
2759 		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_resume(): "
2760 		    "hardware init failed\n");
2761 		uath_stop(sc);
2762 		return;
2763 	}
2764 
2765 	ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
2766 	UATH_LOCK(sc);
2767 	sc->sc_flags &= ~UATH_FLAG_SUSPEND;
2768 	sc->sc_flags |= UATH_FLAG_RUNNING;
2769 	UATH_UNLOCK(sc);
2770 }
2771 
2772 static int
2773 uath_m_start(void *arg)
2774 {
2775 	struct uath_softc *sc = (struct uath_softc *)arg;
2776 	struct ieee80211com *ic = &sc->sc_ic;
2777 	int err;
2778 
2779 	/*
2780 	 * initialize hardware
2781 	 */
2782 	err = uath_init(sc);
2783 	if (err != UATH_SUCCESS) {
2784 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_m_start(): "
2785 		    "device configuration failed\n");
2786 		uath_stop(sc);
2787 		return (err);
2788 	}
2789 
2790 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
2791 
2792 	UATH_LOCK(sc);
2793 	sc->sc_flags |= UATH_FLAG_RUNNING;
2794 	UATH_UNLOCK(sc);
2795 	return (DDI_SUCCESS);
2796 }
2797 
2798 static void
2799 uath_m_stop(void *arg)
2800 {
2801 	struct uath_softc *sc = (struct uath_softc *)arg;
2802 	struct ieee80211com *ic = &sc->sc_ic;
2803 
2804 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
2805 
2806 	if (!UATH_IS_DISCONNECT(sc))
2807 		uath_stop(sc);
2808 
2809 	UATH_LOCK(sc);
2810 	sc->sc_flags &= ~UATH_FLAG_RUNNING;
2811 	UATH_UNLOCK(sc);
2812 }
2813 
2814 static void
2815 uath_m_ioctl(void* arg, queue_t *wq, mblk_t *mp)
2816 {
2817 	struct uath_softc *sc = (struct uath_softc *)arg;
2818 	struct ieee80211com *ic = &sc->sc_ic;
2819 	int err;
2820 
2821 	err = ieee80211_ioctl(ic, wq, mp);
2822 	UATH_LOCK(sc);
2823 	if (err == ENETRESET) {
2824 		if (ic->ic_des_esslen) {
2825 			if (UATH_IS_RUNNING(sc)) {
2826 				UATH_UNLOCK(sc);
2827 				(void) uath_init(sc);
2828 				(void) ieee80211_new_state(ic,
2829 				    IEEE80211_S_SCAN, -1);
2830 				UATH_LOCK(sc);
2831 			}
2832 		}
2833 	}
2834 	UATH_UNLOCK(sc);
2835 }
2836 
2837 /*ARGSUSED*/
2838 static int
2839 uath_m_unicst(void *arg, const uint8_t *macaddr)
2840 {
2841 	return (0);
2842 }
2843 
2844 /*ARGSUSED*/
2845 static int
2846 uath_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
2847 {
2848 	return (0);
2849 }
2850 
2851 /*ARGSUSED*/
2852 static int
2853 uath_m_promisc(void *arg, boolean_t on)
2854 {
2855 	return (0);
2856 }
2857 
2858 /*
2859  * callback functions for /get/set properties
2860  */
2861 static int
2862 uath_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2863     uint_t wldp_length, const void *wldp_buf)
2864 {
2865 	struct uath_softc *sc = (struct uath_softc *)arg;
2866 	struct ieee80211com *ic = &sc->sc_ic;
2867 	int err;
2868 
2869 	err = ieee80211_setprop(ic, pr_name, wldp_pr_num,
2870 	    wldp_length, wldp_buf);
2871 	UATH_LOCK(sc);
2872 	if (err == ENETRESET) {
2873 		if (ic->ic_des_esslen && UATH_IS_RUNNING(sc)) {
2874 			UATH_UNLOCK(sc);
2875 			(void) uath_init(sc);
2876 			(void) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
2877 			UATH_LOCK(sc);
2878 		}
2879 		err = 0;
2880 	}
2881 	UATH_UNLOCK(sc);
2882 	return (err);
2883 }
2884 
2885 static int
2886 uath_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2887     uint_t wldp_length, void *wldp_buf)
2888 {
2889 	struct uath_softc *sc = (struct uath_softc *)arg;
2890 	int err;
2891 
2892 	err = ieee80211_getprop(&sc->sc_ic, pr_name, wldp_pr_num,
2893 	    wldp_length, wldp_buf);
2894 	return (err);
2895 }
2896 
2897 static void
2898 uath_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2899     mac_prop_info_handle_t prh)
2900 {
2901 	struct uath_softc *sc = (struct uath_softc *)arg;
2902 
2903 	ieee80211_propinfo(&sc->sc_ic, pr_name, wldp_pr_num, prh);
2904 }
2905 
2906 static int
2907 uath_m_stat(void *arg, uint_t stat, uint64_t *val)
2908 {
2909 	struct uath_softc *sc  = (struct uath_softc *)arg;
2910 	struct ieee80211com *ic = &sc->sc_ic;
2911 	struct ieee80211_node *ni = NULL;
2912 	struct ieee80211_rateset *rs = NULL;
2913 
2914 	UATH_LOCK(sc);
2915 	switch (stat) {
2916 	case MAC_STAT_IFSPEED:
2917 		ni = ic->ic_bss;
2918 		rs = &ni->in_rates;
2919 		*val = ((ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) ?
2920 		    (rs->ir_rates[ni->in_txrate] & IEEE80211_RATE_VAL)
2921 		    : ic->ic_fixed_rate) * 5000000ull;
2922 		break;
2923 	case MAC_STAT_NOXMTBUF:
2924 		*val = sc->sc_tx_nobuf;
2925 		break;
2926 	case MAC_STAT_NORCVBUF:
2927 		*val = sc->sc_rx_nobuf;
2928 		break;
2929 	case MAC_STAT_IERRORS:
2930 		*val = sc->sc_rx_err;
2931 		break;
2932 	case MAC_STAT_RBYTES:
2933 		*val = ic->ic_stats.is_rx_bytes;
2934 		break;
2935 	case MAC_STAT_IPACKETS:
2936 		*val = ic->ic_stats.is_rx_frags;
2937 		break;
2938 	case MAC_STAT_OBYTES:
2939 		*val = ic->ic_stats.is_tx_bytes;
2940 		break;
2941 	case MAC_STAT_OPACKETS:
2942 		*val = ic->ic_stats.is_tx_frags;
2943 		break;
2944 	case MAC_STAT_OERRORS:
2945 	case WIFI_STAT_TX_FAILED:
2946 		*val = sc->sc_tx_err;
2947 		break;
2948 	case WIFI_STAT_TX_RETRANS:
2949 		*val = sc->sc_tx_retries;
2950 		break;
2951 	case WIFI_STAT_FCS_ERRORS:
2952 	case WIFI_STAT_WEP_ERRORS:
2953 	case WIFI_STAT_TX_FRAGS:
2954 	case WIFI_STAT_MCAST_TX:
2955 	case WIFI_STAT_RTS_SUCCESS:
2956 	case WIFI_STAT_RTS_FAILURE:
2957 	case WIFI_STAT_ACK_FAILURE:
2958 	case WIFI_STAT_RX_FRAGS:
2959 	case WIFI_STAT_MCAST_RX:
2960 	case WIFI_STAT_RX_DUPS:
2961 		UATH_UNLOCK(sc);
2962 		return (ieee80211_stat(ic, stat, val));
2963 	default:
2964 		UATH_UNLOCK(sc);
2965 		return (ENOTSUP);
2966 	}
2967 	UATH_UNLOCK(sc);
2968 
2969 	return (0);
2970 }
2971 
2972 static mblk_t *
2973 uath_m_tx(void *arg, mblk_t *mp)
2974 {
2975 	struct uath_softc *sc = (struct uath_softc *)arg;
2976 	struct ieee80211com *ic = &sc->sc_ic;
2977 	mblk_t *next;
2978 
2979 	/*
2980 	 * No data frames go out unless we're associated; this
2981 	 * should not happen as the 802.11 layer does not enable
2982 	 * the xmit queue until we enter the RUN state.
2983 	 */
2984 	if ((ic->ic_state != IEEE80211_S_RUN) ||
2985 	    UATH_IS_SUSPEND(sc)) {
2986 		UATH_DEBUG(UATH_DBG_MSG, "uath: uath_m_tx(): "
2987 		    "discard, state %u\n", ic->ic_state);
2988 		freemsgchain(mp);
2989 		return (NULL);
2990 	}
2991 
2992 	while (mp != NULL) {
2993 		next = mp->b_next;
2994 		mp->b_next = NULL;
2995 		if (uath_send(ic, mp, IEEE80211_FC0_TYPE_DATA) != DDI_SUCCESS) {
2996 			mp->b_next = next;
2997 			break;
2998 		}
2999 		mp = next;
3000 	}
3001 	return (mp);
3002 }
3003 
3004 static int
3005 uath_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
3006 {
3007 	struct uath_softc *sc;
3008 	struct ieee80211com *ic;
3009 
3010 	int i, err, instance;
3011 	char strbuf[32];
3012 	uint16_t vendor_id, product_id;
3013 
3014 	wifi_data_t wd = { 0 };
3015 	mac_register_t *macp;
3016 
3017 	switch (cmd) {
3018 	case DDI_ATTACH:
3019 		break;
3020 	case DDI_RESUME:
3021 		sc = ddi_get_soft_state(uath_soft_state_p,
3022 		    ddi_get_instance(devinfo));
3023 		ASSERT(sc != NULL);
3024 		uath_resume(sc);
3025 		return (DDI_SUCCESS);
3026 	default:
3027 		return (DDI_FAILURE);
3028 	}
3029 
3030 	instance = ddi_get_instance(devinfo);
3031 	err = ddi_soft_state_zalloc(uath_soft_state_p, instance);
3032 	if (err != DDI_SUCCESS) {
3033 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3034 		    "ddi_soft_state_zalloc failed\n");
3035 		return (DDI_FAILURE);
3036 	}
3037 
3038 	sc = ddi_get_soft_state(uath_soft_state_p, instance);
3039 	ic = (ieee80211com_t *)&sc->sc_ic;
3040 	sc->sc_dev = devinfo;
3041 
3042 	err = usb_client_attach(devinfo, USBDRV_VERSION, 0);
3043 	if (err != USB_SUCCESS) {
3044 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3045 		    "usb_client_attach failed\n");
3046 		goto fail1;
3047 	}
3048 
3049 	err = usb_get_dev_data(devinfo, &sc->sc_udev, USB_PARSE_LVL_ALL, 0);
3050 	if (err != USB_SUCCESS) {
3051 		sc->sc_udev = NULL;
3052 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3053 		    "usb_get_dev_data failed\n");
3054 		goto fail2;
3055 	}
3056 
3057 	vendor_id = sc->sc_udev->dev_descr->idVendor;
3058 	product_id = sc->sc_udev->dev_descr->idProduct;
3059 	sc->dev_flags = uath_lookup(vendor_id, product_id);
3060 	if (sc->dev_flags == UATH_FLAG_ERR) {
3061 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3062 		    "HW does not match\n");
3063 		goto fail2;
3064 	}
3065 
3066 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_attach(): "
3067 	    "vendorId = %x,deviceID = %x, flags = %x\n",
3068 	    vendor_id, product_id, sc->dev_flags);
3069 
3070 	/*
3071 	 * We must open the pipes early because they're used to upload the
3072 	 * firmware (pre-firmware devices) or to send firmware commands.
3073 	 */
3074 	err = uath_open_pipes(sc);
3075 	if (err != UATH_SUCCESS) {
3076 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3077 		    "could not open pipes\n");
3078 		goto fail3;
3079 	}
3080 
3081 	if (sc->dev_flags & UATH_FLAG_PRE_FIRMWARE) {
3082 		err = uath_loadfirmware(sc);
3083 		if (err != DDI_SUCCESS) {
3084 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3085 			    "could not read firmware %s, err %d\n",
3086 			    "uath-ar5523", err);
3087 			goto fail3;
3088 		}
3089 
3090 		uath_close_pipes(sc);
3091 		usb_client_detach(sc->sc_dev, sc->sc_udev);
3092 
3093 		err = usb_reset_device(devinfo, USB_RESET_LVL_REATTACH);
3094 		if (err != USB_SUCCESS) {
3095 			UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3096 			    "could not re-attach, err %d\n", err);
3097 			goto fail1;
3098 		}
3099 		return (DDI_SUCCESS);
3100 	}
3101 
3102 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_attach(): "
3103 	    "firmware download and re-attach successfully\n");
3104 
3105 	/*
3106 	 * Only post-firmware devices here.
3107 	 */
3108 	mutex_init(&sc->sc_genlock, NULL, MUTEX_DRIVER, NULL);
3109 	mutex_init(&sc->sc_rxlock_cmd, NULL, MUTEX_DRIVER, NULL);
3110 	mutex_init(&sc->sc_txlock_cmd, NULL, MUTEX_DRIVER, NULL);
3111 	mutex_init(&sc->sc_rxlock_data, NULL, MUTEX_DRIVER, NULL);
3112 	mutex_init(&sc->sc_txlock_data, NULL, MUTEX_DRIVER, NULL);
3113 
3114 	/*
3115 	 * Allocate xfers for firmware commands.
3116 	 */
3117 	err = uath_alloc_cmd_list(sc, sc->sc_cmd, UATH_CMD_LIST_COUNT,
3118 	    UATH_MAX_CMDSZ);
3119 	if (err != UATH_SUCCESS) {
3120 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3121 		    "could not allocate Tx command list\n");
3122 		goto fail4;
3123 	}
3124 
3125 	err = uath_init_cmd_list(sc);
3126 	if (err != UATH_SUCCESS) {
3127 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3128 		    "could not init RX command list\n");
3129 		goto fail5;
3130 	}
3131 
3132 	/*
3133 	 * We're now ready to send+receive firmware commands.
3134 	 */
3135 	err = uath_host_available(sc);
3136 	if (err != UATH_SUCCESS) {
3137 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3138 		    "could not initialize adapter\n");
3139 		goto fail5;
3140 	}
3141 
3142 	err = uath_get_devcap(sc);
3143 	if (err != UATH_SUCCESS) {
3144 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3145 		    "could not get device capabilities\n");
3146 		goto fail5;
3147 	}
3148 
3149 	err = uath_get_devstatus(sc, ic->ic_macaddr);
3150 	if (err != UATH_SUCCESS) {
3151 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3152 		    "could not get dev status\n");
3153 		goto fail5;
3154 	}
3155 
3156 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_attach(): "
3157 	    "MAC address is: %x:%x:%x:%x:%x:%x\n",
3158 	    ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2],
3159 	    ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5]);
3160 
3161 	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
3162 	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
3163 	ic->ic_state = IEEE80211_S_INIT;
3164 
3165 	ic->ic_maxrssi = 40;
3166 
3167 	ic->ic_xmit = uath_send;
3168 
3169 	/* set device capabilities */
3170 	ic->ic_caps =
3171 	    IEEE80211_C_TXPMGT |	/* tx power management */
3172 	    IEEE80211_C_SHPREAMBLE |	/* short preamble supported */
3173 	    IEEE80211_C_SHSLOT;		/* short slot time supported */
3174 
3175 	ic->ic_caps |= IEEE80211_C_WPA;  /* Support WPA/WPA2 */
3176 
3177 	/* set supported .11b and .11g rates */
3178 	ic->ic_sup_rates[IEEE80211_MODE_11B] = uath_rateset_11b;
3179 	ic->ic_sup_rates[IEEE80211_MODE_11G] = uath_rateset_11g;
3180 
3181 	/* set supported .11b and .11g channels (1 through 11) */
3182 	for (i = 1; i <= 11; i++) {
3183 		ic->ic_sup_channels[i].ich_freq =
3184 		    ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
3185 		ic->ic_sup_channels[i].ich_flags =
3186 		    IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
3187 		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
3188 	}
3189 
3190 	ieee80211_attach(ic);
3191 
3192 	/* register WPA door */
3193 	ieee80211_register_door(ic, ddi_driver_name(devinfo),
3194 	    ddi_get_instance(devinfo));
3195 
3196 	/* override state transition machine */
3197 	sc->sc_newstate = ic->ic_newstate;
3198 	ic->ic_newstate = uath_newstate;
3199 	ieee80211_media_init(ic);
3200 	ic->ic_def_txkey = 0;
3201 
3202 	sc->sc_flags = 0;
3203 
3204 	/*
3205 	 * Provide initial settings for the WiFi plugin; whenever this
3206 	 * information changes, we need to call mac_plugindata_update()
3207 	 */
3208 	wd.wd_opmode = ic->ic_opmode;
3209 	wd.wd_secalloc = WIFI_SEC_NONE;
3210 	IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
3211 
3212 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
3213 		UATH_DEBUG(UATH_DBG_ERR, "uath_attach(): "
3214 		    "MAC version mismatch\n");
3215 		goto fail5;
3216 	}
3217 
3218 	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
3219 	macp->m_driver		= sc;
3220 	macp->m_dip		= devinfo;
3221 	macp->m_src_addr	= ic->ic_macaddr;
3222 	macp->m_callbacks	= &uath_m_callbacks;
3223 	macp->m_min_sdu		= 0;
3224 	macp->m_max_sdu		= IEEE80211_MTU;
3225 	macp->m_pdata		= &wd;
3226 	macp->m_pdata_size	= sizeof (wd);
3227 
3228 	err = mac_register(macp, &ic->ic_mach);
3229 	mac_free(macp);
3230 	if (err != 0) {
3231 		UATH_DEBUG(UATH_DBG_ERR, "uath_attach(): "
3232 		    "mac_register() error %x\n", err);
3233 		goto fail5;
3234 	};
3235 
3236 	err = usb_register_hotplug_cbs(devinfo,
3237 	    uath_disconnect, uath_reconnect);
3238 	if (err != USB_SUCCESS) {
3239 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3240 		    "failed to register events\n");
3241 		goto fail6;
3242 	}
3243 
3244 	/*
3245 	 * Create minor node of type DDI_NT_NET_WIFI
3246 	 */
3247 	(void) snprintf(strbuf, sizeof (strbuf), "%s%d",
3248 	    "uath", instance);
3249 	err = ddi_create_minor_node(devinfo, strbuf, S_IFCHR,
3250 	    instance + 1, DDI_NT_NET_WIFI, 0);
3251 	if (err != DDI_SUCCESS)
3252 		UATH_DEBUG(UATH_DBG_ERR, "uath: uath_attach(): "
3253 		    "ddi_create_minor_node() failed\n");
3254 
3255 	/*
3256 	 * Notify link is down now
3257 	 */
3258 	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
3259 
3260 	UATH_DEBUG(UATH_DBG_MSG, "uath: uath_attach(): "
3261 	    "attach success\n");
3262 	return (DDI_SUCCESS);
3263 
3264 fail6:
3265 	(void) mac_unregister(ic->ic_mach);
3266 fail5:
3267 	uath_free_cmd_list(sc->sc_cmd, UATH_CMD_LIST_COUNT);
3268 fail4:
3269 	mutex_destroy(&sc->sc_genlock);
3270 	mutex_destroy(&sc->sc_rxlock_cmd);
3271 	mutex_destroy(&sc->sc_rxlock_data);
3272 	mutex_destroy(&sc->sc_txlock_cmd);
3273 	mutex_destroy(&sc->sc_txlock_data);
3274 fail3:
3275 	uath_close_pipes(sc);
3276 fail2:
3277 	usb_client_detach(sc->sc_dev, sc->sc_udev);
3278 fail1:
3279 	ddi_soft_state_free(uath_soft_state_p, ddi_get_instance(devinfo));
3280 	return (DDI_FAILURE);
3281 }
3282 
3283 static int
3284 uath_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
3285 {
3286 	struct uath_softc *sc;
3287 
3288 	sc = ddi_get_soft_state(uath_soft_state_p, ddi_get_instance(devinfo));
3289 	ASSERT(sc != NULL);
3290 
3291 	switch (cmd) {
3292 	case DDI_DETACH:
3293 		break;
3294 	case DDI_SUSPEND:
3295 		if (UATH_IS_RUNNING(sc)) {
3296 			ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1);
3297 			uath_stop(sc);
3298 		}
3299 		UATH_LOCK(sc);
3300 		sc->sc_flags &= ~UATH_FLAG_RUNNING;
3301 		sc->sc_flags |= UATH_FLAG_SUSPEND;
3302 		UATH_UNLOCK(sc);
3303 		return (DDI_SUCCESS);
3304 	default:
3305 		return (DDI_FAILURE);
3306 	}
3307 
3308 	if (sc->dev_flags & UATH_FLAG_PRE_FIRMWARE) {
3309 		ddi_soft_state_free(uath_soft_state_p,
3310 		    ddi_get_instance(devinfo));
3311 		return (DDI_SUCCESS);
3312 	}
3313 
3314 	if (!UATH_IS_DISCONNECT(sc) && UATH_IS_RUNNING(sc))
3315 		uath_stop(sc);
3316 
3317 	uath_free_cmd_list(sc->sc_cmd, UATH_CMD_LIST_COUNT);
3318 
3319 	if (mac_disable(sc->sc_ic.ic_mach) != 0)
3320 		return (DDI_FAILURE);
3321 
3322 	/*
3323 	 * Unregister from the MAC layer subsystem
3324 	 */
3325 	if (mac_unregister(sc->sc_ic.ic_mach) != 0)
3326 		return (DDI_FAILURE);
3327 
3328 	/*
3329 	 * detach ieee80211 layer
3330 	 */
3331 	ieee80211_detach(&sc->sc_ic);
3332 
3333 	/* close Tx/Rx pipes */
3334 	uath_close_pipes(sc);
3335 	usb_unregister_hotplug_cbs(devinfo);
3336 
3337 	mutex_destroy(&sc->sc_genlock);
3338 	mutex_destroy(&sc->sc_rxlock_cmd);
3339 	mutex_destroy(&sc->sc_rxlock_data);
3340 	mutex_destroy(&sc->sc_txlock_cmd);
3341 	mutex_destroy(&sc->sc_txlock_data);
3342 
3343 	/* pipes will be close in uath_stop() */
3344 	usb_client_detach(devinfo, sc->sc_udev);
3345 	sc->sc_udev = NULL;
3346 
3347 	ddi_remove_minor_node(devinfo, NULL);
3348 	ddi_soft_state_free(uath_soft_state_p, ddi_get_instance(devinfo));
3349 
3350 	return (DDI_SUCCESS);
3351 }
3352 
3353 int
3354 _info(struct modinfo *modinfop)
3355 {
3356 	return (mod_info(&modlinkage, modinfop));
3357 }
3358 
3359 int
3360 _init(void)
3361 {
3362 	int status;
3363 
3364 	status = ddi_soft_state_init(&uath_soft_state_p,
3365 	    sizeof (struct uath_softc), 1);
3366 	if (status != 0)
3367 		return (status);
3368 
3369 	mac_init_ops(&uath_dev_ops, "uath");
3370 	status = mod_install(&modlinkage);
3371 	if (status != 0) {
3372 		mac_fini_ops(&uath_dev_ops);
3373 		ddi_soft_state_fini(&uath_soft_state_p);
3374 	}
3375 	return (status);
3376 }
3377 
3378 int
3379 _fini(void)
3380 {
3381 	int status;
3382 
3383 	status = mod_remove(&modlinkage);
3384 	if (status == 0) {
3385 		mac_fini_ops(&uath_dev_ops);
3386 		ddi_soft_state_fini(&uath_soft_state_p);
3387 	}
3388 	return (status);
3389 }
3390