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