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