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