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