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