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