1 /*
   2  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   4  */
   5 
   6 /*
   7  * Copyright (c) 2004, 2005
   8  *      Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
   9  *
  10  * Redistribution and use in source and binary forms, with or without
  11  * modification, are permitted provided that the following conditions
  12  * are met:
  13  * 1. Redistributions of source code must retain the above copyright
  14  *    notice unmodified, this list of conditions, and the following
  15  *    disclaimer.
  16  * 2. Redistributions in binary form must reproduce the above copyright
  17  *    notice, this list of conditions and the following disclaimer in the
  18  *    documentation and/or other materials provided with the distribution.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30  * SUCH DAMAGE.
  31  */
  32 
  33 #include <sys/types.h>
  34 #include <sys/byteorder.h>
  35 #include <sys/conf.h>
  36 #include <sys/cmn_err.h>
  37 #include <sys/stat.h>
  38 #include <sys/ddi.h>
  39 #include <sys/sunddi.h>
  40 #include <sys/strsubr.h>
  41 #include <sys/ethernet.h>
  42 #include <inet/common.h>
  43 #include <inet/nd.h>
  44 #include <inet/mi.h>
  45 #include <sys/note.h>
  46 #include <sys/stream.h>
  47 #include <sys/strsun.h>
  48 #include <sys/modctl.h>
  49 #include <sys/devops.h>
  50 #include <sys/dlpi.h>
  51 #include <sys/mac_provider.h>
  52 #include <sys/mac_wifi.h>
  53 #include <sys/varargs.h>
  54 #include <sys/pci.h>
  55 #include <sys/policy.h>
  56 #include <sys/random.h>
  57 #include <sys/crypto/common.h>
  58 #include <sys/crypto/api.h>
  59 
  60 #include "ipw2200.h"
  61 #include "ipw2200_impl.h"
  62 #include <inet/wifi_ioctl.h>
  63 
  64 /*
  65  * for net80211 kernel usage
  66  */
  67 #include <sys/net80211.h>
  68 #include <sys/net80211_proto.h>
  69 
  70 /*
  71  * minimal size reserved in tx-ring
  72  */
  73 #define IPW2200_TX_RING_MIN     (8)
  74 #define IPW2200_TXBUF_SIZE      (IEEE80211_MAX_LEN)
  75 #define IPW2200_RXBUF_SIZE      (4096)
  76 
  77 static void  *ipw2200_ssp = NULL;
  78 static char ipw2200_ident[] = IPW2200_DRV_DESC;
  79 
  80 /*
  81  * PIO access attributor for registers
  82  */
  83 static ddi_device_acc_attr_t ipw2200_csr_accattr = {
  84         DDI_DEVICE_ATTR_V0,
  85         DDI_STRUCTURE_LE_ACC,
  86         DDI_STRICTORDER_ACC
  87 };
  88 
  89 /*
  90  * DMA access attributor for descriptors
  91  */
  92 static ddi_device_acc_attr_t ipw2200_dma_accattr = {
  93         DDI_DEVICE_ATTR_V0,
  94         DDI_NEVERSWAP_ACC,
  95         DDI_STRICTORDER_ACC
  96 };
  97 
  98 /*
  99  * Describes the chip's DMA engine
 100  */
 101 static ddi_dma_attr_t ipw2200_dma_attr = {
 102         DMA_ATTR_V0,            /* version */
 103         0x0000000000000000ULL,  /* addr_lo */
 104         0x00000000ffffffffULL,  /* addr_hi */
 105         0x00000000ffffffffULL,  /* counter */
 106         0x0000000000000004ULL,  /* alignment */
 107         0xfff,                  /* burst */
 108         1,                      /* min xfer */
 109         0x00000000ffffffffULL,  /* max xfer */
 110         0x00000000ffffffffULL,  /* seg boud */
 111         1,                      /* s/g list */
 112         1,                      /* granularity */
 113         0                       /* flags */
 114 };
 115 
 116 static uint8_t ipw2200_broadcast_addr[] = {
 117         0xff, 0xff, 0xff, 0xff, 0xff, 0xff
 118 };
 119 static const struct ieee80211_rateset ipw2200_rateset_11a = { 8,
 120         {12, 18, 24, 36, 48, 72, 96, 108}
 121 };
 122 static const struct ieee80211_rateset ipw2200_rateset_11b = { 4,
 123         {2, 4, 11, 22}
 124 };
 125 static const struct ieee80211_rateset ipw2200_rateset_11g = { 12,
 126         {2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108}
 127 };
 128 
 129 /*
 130  * Used by multi function thread
 131  */
 132 extern pri_t minclsyspri;
 133 
 134 /*
 135  * ipw2200 specific hardware operations
 136  */
 137 static void     ipw2200_hwconf_get(struct ipw2200_softc *sc);
 138 static int      ipw2200_chip_reset(struct ipw2200_softc *sc);
 139 static void     ipw2200_master_stop(struct ipw2200_softc *sc);
 140 static void     ipw2200_stop(struct ipw2200_softc *sc);
 141 static int      ipw2200_config(struct ipw2200_softc *sc);
 142 static int      ipw2200_cmd(struct ipw2200_softc *sc,
 143     uint32_t type, void *buf, size_t len, int async);
 144 static void     ipw2200_ring_hwsetup(struct ipw2200_softc *sc);
 145 static int      ipw2200_ring_alloc(struct ipw2200_softc *sc);
 146 static void     ipw2200_ring_free(struct ipw2200_softc *sc);
 147 static void     ipw2200_ring_reset(struct ipw2200_softc *sc);
 148 static int      ipw2200_ring_init(struct ipw2200_softc *sc);
 149 
 150 /*
 151  * GLD specific operations
 152  */
 153 static int      ipw2200_m_stat(void *arg, uint_t stat, uint64_t *val);
 154 static int      ipw2200_m_start(void *arg);
 155 static void     ipw2200_m_stop(void *arg);
 156 static int      ipw2200_m_unicst(void *arg, const uint8_t *macaddr);
 157 static int      ipw2200_m_multicst(void *arg, boolean_t add, const uint8_t *m);
 158 static int      ipw2200_m_promisc(void *arg, boolean_t on);
 159 static void     ipw2200_m_ioctl(void *arg, queue_t *wq, mblk_t *mp);
 160 static mblk_t  *ipw2200_m_tx(void *arg, mblk_t *mp);
 161 static int      ipw2200_m_setprop(void *arg, const char *pr_name,
 162     mac_prop_id_t wldp_pr_num, uint_t wldp_length, const void *wldp_buf);
 163 static int      ipw2200_m_getprop(void *arg, const char *pr_name,
 164     mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf);
 165 static void     ipw2200_m_propinfo(void *arg, const char *pr_name,
 166     mac_prop_id_t wldp_pr_num, mac_prop_info_handle_t mph);
 167 
 168 /*
 169  * Interrupt and Data transferring operations
 170  */
 171 static uint_t   ipw2200_intr(caddr_t arg);
 172 static int      ipw2200_send(struct ieee80211com *ic, mblk_t *mp, uint8_t type);
 173 static void     ipw2200_rcv_frame(struct ipw2200_softc *sc,
 174     struct ipw2200_frame *frame);
 175 static void     ipw2200_rcv_notif(struct ipw2200_softc *sc,
 176     struct ipw2200_notif *notif);
 177 
 178 /*
 179  * WiFi specific operations
 180  */
 181 static int      ipw2200_newstate(struct ieee80211com *ic,
 182     enum ieee80211_state state, int arg);
 183 static void     ipw2200_thread(struct ipw2200_softc *sc);
 184 
 185 /*
 186  * IOCTL Handler
 187  */
 188 static int      ipw2200_ioctl(struct ipw2200_softc *sc, queue_t *q, mblk_t *m);
 189 static int      ipw2200_getset(struct ipw2200_softc *sc,
 190     mblk_t *m, uint32_t cmd, boolean_t *need_net80211);
 191 static int      iwi_wificfg_radio(struct ipw2200_softc *sc,
 192     uint32_t cmd,  wldp_t *outfp);
 193 static int      iwi_wificfg_desrates(wldp_t *outfp);
 194 
 195 /*
 196  * net80211 functions
 197  */
 198 extern uint8_t  ieee80211_crypto_getciphertype(ieee80211com_t *ic);
 199 extern void     ieee80211_notify_node_join(ieee80211com_t *ic,
 200     ieee80211_node_t *in);
 201 extern void     ieee80211_notify_node_leave(ieee80211com_t *ic,
 202     ieee80211_node_t *in);
 203 
 204 /*
 205  * Mac Call Back entries
 206  */
 207 mac_callbacks_t ipw2200_m_callbacks = {
 208         MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
 209         ipw2200_m_stat,
 210         ipw2200_m_start,
 211         ipw2200_m_stop,
 212         ipw2200_m_promisc,
 213         ipw2200_m_multicst,
 214         ipw2200_m_unicst,
 215         ipw2200_m_tx,
 216         NULL,
 217         ipw2200_m_ioctl,
 218         NULL,
 219         NULL,
 220         NULL,
 221         ipw2200_m_setprop,
 222         ipw2200_m_getprop,
 223         ipw2200_m_propinfo
 224 };
 225 
 226 /*
 227  * DEBUG Facility
 228  */
 229 #define         MAX_MSG         (128)
 230 uint32_t        ipw2200_debug = 0;
 231 /*
 232  * supported debug marks are:
 233  *      | IPW2200_DBG_CSR
 234  *      | IPW2200_DBG_TABLE
 235  *      | IPW2200_DBG_HWCAP
 236  *      | IPW2200_DBG_TX
 237  *      | IPW2200_DBG_INIT
 238  *      | IPW2200_DBG_FW
 239  *      | IPW2200_DBG_NOTIF
 240  *      | IPW2200_DBG_SCAN
 241  *      | IPW2200_DBG_IOCTL
 242  *      | IPW2200_DBG_RING
 243  *      | IPW2200_DBG_INT
 244  *      | IPW2200_DBG_RX
 245  *      | IPW2200_DBG_DMA
 246  *      | IPW2200_DBG_GLD
 247  *      | IPW2200_DBG_WIFI
 248  *      | IPW2200_DBG_SOFTINT
 249  *      | IPW2200_DBG_SUSPEND
 250  *      | IPW2200_DBG_BRUSSELS
 251  */
 252 
 253 /*
 254  * Global tunning parameter to work around unknown hardware issues
 255  */
 256 static uint32_t delay_config_stable     = 100000;       /* 100ms */
 257 static uint32_t delay_fatal_recover     = 100000 * 20;  /* 2s */
 258 static uint32_t delay_aux_thread        = 100000;       /* 100ms */
 259 
 260 #define IEEE80211_IS_CHAN_2GHZ(_c) \
 261         (((_c)->ich_flags & IEEE80211_CHAN_2GHZ) != 0)
 262 #define IEEE80211_IS_CHAN_5GHZ(_c) \
 263         (((_c)->ich_flags & IEEE80211_CHAN_5GHZ) != 0)
 264 #define isset(a, i)     ((a)[(i)/NBBY] & (1 << ((i)%NBBY)))
 265 
 266 void
 267 ipw2200_dbg(dev_info_t *dip, int level, const char *fmt, ...)
 268 {
 269         va_list ap;
 270         char    buf[MAX_MSG];
 271         int     instance;
 272 
 273         va_start(ap, fmt);
 274         (void) vsnprintf(buf, sizeof (buf), fmt, ap);
 275         va_end(ap);
 276 
 277         if (dip) {
 278                 instance = ddi_get_instance(dip);
 279                 cmn_err(level, "%s%d: %s", IPW2200_DRV_NAME, instance, buf);
 280         } else
 281                 cmn_err(level, "%s: %s", IPW2200_DRV_NAME, buf);
 282 
 283 }
 284 
 285 /*
 286  * Set up pci
 287  */
 288 int
 289 ipw2200_setup_pci(dev_info_t *dip, struct ipw2200_softc *sc)
 290 {
 291         ddi_acc_handle_t        cfgh;
 292         caddr_t                 regs;
 293         int                     err;
 294 
 295         /*
 296          * Map config spaces register to read the vendor id, device id, sub
 297          * vendor id, and sub device id.
 298          */
 299         err = ddi_regs_map_setup(dip, IPW2200_PCI_CFG_RNUM, &regs,
 300             0, 0, &ipw2200_csr_accattr, &cfgh);
 301         if (err != DDI_SUCCESS) {
 302                 IPW2200_WARN((dip, CE_WARN,
 303                     "ipw2200_attach(): unable to map spaces regs\n"));
 304                 return (DDI_FAILURE);
 305         }
 306 
 307         ddi_put8(cfgh, (uint8_t *)(regs + 0x41), 0);
 308         sc->sc_vendor = ddi_get16(cfgh,
 309             (uint16_t *)((uintptr_t)regs + PCI_CONF_VENID));
 310         sc->sc_device = ddi_get16(cfgh,
 311             (uint16_t *)((uintptr_t)regs + PCI_CONF_DEVID));
 312         sc->sc_subven = ddi_get16(cfgh,
 313             (uint16_t *)((uintptr_t)regs + PCI_CONF_SUBVENID));
 314         sc->sc_subdev = ddi_get16(cfgh,
 315             (uint16_t *)((uintptr_t)regs + PCI_CONF_SUBSYSID));
 316         IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
 317             "ipw2200_setup_pci(): vendor = 0x%04x, devic = 0x%04x,"
 318             "subversion = 0x%04x, subdev = 0x%04x",
 319             sc->sc_vendor, sc->sc_device, sc->sc_subven, sc->sc_subdev));
 320 
 321         ddi_regs_map_free(&cfgh);
 322 
 323         return (DDI_SUCCESS);
 324 
 325 }
 326 
 327 /*
 328  * Device operations
 329  */
 330 int
 331 ipw2200_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 332 {
 333         struct ipw2200_softc    *sc;
 334         struct ieee80211com     *ic;
 335         int                     instance, err, i;
 336         char                    strbuf[32];
 337         wifi_data_t             wd = { 0 };
 338         mac_register_t          *macp;
 339 
 340         switch (cmd) {
 341         case DDI_ATTACH:
 342                 break;
 343         case DDI_RESUME:
 344                 sc = ddi_get_soft_state(ipw2200_ssp, ddi_get_instance(dip));
 345                 ASSERT(sc != NULL);
 346 
 347                 /*
 348                  * set up pci
 349                  */
 350                 err = ipw2200_setup_pci(dip, sc);
 351                 if (err != DDI_SUCCESS) {
 352                         IPW2200_DBG(IPW2200_DBG_SUSPEND, (sc->sc_dip, CE_CONT,
 353                             "ipw2200_attach(): resume failure\n"));
 354                         return (DDI_FAILURE);
 355                 }
 356 
 357                 /*
 358                  * resume hardware.
 359                  * If it was on runnning status, reset to INIT state
 360                  */
 361                 sc->sc_flags &= ~IPW2200_FLAG_SUSPEND;
 362                 if (sc->sc_flags & IPW2200_FLAG_RUNNING)
 363                         (void) ipw2200_init(sc);
 364 
 365                 IPW2200_DBG(IPW2200_DBG_SUSPEND, (sc->sc_dip, CE_CONT,
 366                     "ipw2200_attach(): resume successful\n"));
 367                 return (DDI_SUCCESS);
 368         default:
 369                 return (DDI_FAILURE);
 370         }
 371 
 372         instance = ddi_get_instance(dip);
 373         err = ddi_soft_state_zalloc(ipw2200_ssp, instance);
 374         if (err != DDI_SUCCESS) {
 375                 IPW2200_WARN((dip, CE_WARN,
 376                     "ipw2200_attach(): unable to allocate soft state\n"));
 377                 goto fail1;
 378         }
 379         sc = ddi_get_soft_state(ipw2200_ssp, instance);
 380         sc->sc_dip = dip;
 381 
 382         /* set up pci, put reg+0x41 0 */
 383         err = ipw2200_setup_pci(dip, sc);
 384         if (err != DDI_SUCCESS) {
 385                 IPW2200_WARN((dip, CE_WARN,
 386                     "ipw2200_attach(): unable to setup pci\n"));
 387                 goto fail2;
 388         }
 389 
 390         /*
 391          * Map operating registers
 392          */
 393         err = ddi_regs_map_setup(dip, IPW2200_PCI_CSR_RNUM, &sc->sc_regs,
 394             0, 0, &ipw2200_csr_accattr, &sc->sc_ioh);
 395         if (err != DDI_SUCCESS) {
 396                 IPW2200_WARN((dip, CE_WARN,
 397                     "ipw2200_attach(): ddi_regs_map_setup() failed\n"));
 398                 goto fail2;
 399         }
 400 
 401         /*
 402          * Reset the chip
 403          */
 404         err = ipw2200_chip_reset(sc);
 405         if (err != DDI_SUCCESS) {
 406                 IPW2200_WARN((dip, CE_WARN,
 407                     "ipw2200_attach(): ipw2200_chip_reset() failed\n"));
 408                 goto fail3;
 409         }
 410 
 411         /*
 412          * Get the hardware configuration, including the MAC address
 413          * Then, init all the rings needed.
 414          */
 415         ipw2200_hwconf_get(sc);
 416         err = ipw2200_ring_init(sc);
 417         if (err != DDI_SUCCESS) {
 418                 IPW2200_WARN((dip, CE_WARN,
 419                     "ipw2200_attach(): ipw2200_ring_init() failed\n"));
 420                 goto fail3;
 421         }
 422 
 423         /*
 424          * Initialize mutexs and condvars
 425          */
 426         err = ddi_get_iblock_cookie(dip, 0, &sc->sc_iblk);
 427         if (err != DDI_SUCCESS) {
 428                 IPW2200_WARN((dip, CE_WARN,
 429                     "ipw2200_attach(): ddi_get_iblock_cookie() failed\n"));
 430                 goto fail4;
 431         }
 432 
 433         /*
 434          * interrupt lock
 435          */
 436         mutex_init(&sc->sc_ilock, "intr-lock", MUTEX_DRIVER,
 437             (void *) sc->sc_iblk);
 438         cv_init(&sc->sc_fw_cond, "firmware-ok", CV_DRIVER, NULL);
 439         cv_init(&sc->sc_cmd_status_cond, "cmd-status-ring", CV_DRIVER, NULL);
 440 
 441         /*
 442          * command ring lock
 443          */
 444         mutex_init(&sc->sc_cmd_lock, "cmd-ring", MUTEX_DRIVER,
 445             (void *) sc->sc_iblk);
 446         cv_init(&sc->sc_cmd_cond, "cmd-ring", CV_DRIVER, NULL);
 447 
 448         /*
 449          * tx ring lock
 450          */
 451         mutex_init(&sc->sc_tx_lock, "tx-ring", MUTEX_DRIVER,
 452             (void *) sc->sc_iblk);
 453 
 454         /*
 455          * rescheduled lock
 456          */
 457         mutex_init(&sc->sc_resched_lock, "reschedule-lock", MUTEX_DRIVER,
 458             (void *) sc->sc_iblk);
 459 
 460         /*
 461          * multi-function lock, may acquire this during interrupt
 462          */
 463         mutex_init(&sc->sc_mflock, "function-lock", MUTEX_DRIVER,
 464             (void *) sc->sc_iblk);
 465         cv_init(&sc->sc_mfthread_cv, NULL, CV_DRIVER, NULL);
 466         sc->sc_mf_thread = NULL;
 467         sc->sc_mfthread_switch = 0;
 468 
 469         /*
 470          * Initialize the WiFi part
 471          */
 472         ic = &sc->sc_ic;
 473         ic->ic_phytype  = IEEE80211_T_OFDM;
 474         ic->ic_opmode   = IEEE80211_M_STA;
 475         ic->ic_state    = IEEE80211_S_INIT;
 476         ic->ic_maxrssi  = 100; /* experimental number */
 477         ic->ic_caps =
 478             IEEE80211_C_SHPREAMBLE |
 479             IEEE80211_C_TXPMGT |
 480             IEEE80211_C_PMGT |
 481             IEEE80211_C_WPA;
 482 
 483         /*
 484          * set mac addr
 485          */
 486         IEEE80211_ADDR_COPY(ic->ic_macaddr, sc->sc_macaddr);
 487 
 488         /*
 489          * set supported .11a rates and channel - (2915ABG only)
 490          */
 491         if (sc->sc_device >= 0x4223) {
 492                 /* .11a rates */
 493                 ic->ic_sup_rates[IEEE80211_MODE_11A] = ipw2200_rateset_11a;
 494                 /* .11a channels */
 495                 for (i = 36; i <= 64; i += 4) {
 496                         ic->ic_sup_channels[i].ich_freq =
 497                             ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
 498                         ic->ic_sup_channels[i].ich_flags = /* CHAN_A */
 499                             IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM;
 500                 }
 501                 for (i = 149; i <= 165; i += 4) {
 502                         ic->ic_sup_channels[i].ich_freq =
 503                             ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
 504                         ic->ic_sup_channels[i].ich_flags = /* CHAN_A */
 505                             IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM;
 506                 }
 507         }
 508 
 509         /*
 510          * set supported .11b and .11g rates
 511          */
 512         ic->ic_sup_rates[IEEE80211_MODE_11B] = ipw2200_rateset_11b;
 513         ic->ic_sup_rates[IEEE80211_MODE_11G] = ipw2200_rateset_11g;
 514 
 515         /*
 516          * set supported .11b and .11g channels(1 through 14)
 517          */
 518         for (i = 1; i < 14; i++) {
 519                 ic->ic_sup_channels[i].ich_freq  =
 520                     ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
 521                 ic->ic_sup_channels[i].ich_flags =
 522                     IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
 523                     IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
 524         }
 525 
 526         /*
 527          * IBSS channal undefined for now
 528          */
 529         ic->ic_ibss_chan = &ic->ic_sup_channels[0];
 530         ic->ic_xmit = ipw2200_send;
 531 
 532         /*
 533          * init generic layer, then override state transition machine
 534          */
 535         ieee80211_attach(ic);
 536 
 537         /*
 538          * different instance has different WPA door
 539          */
 540         ieee80211_register_door(ic, ddi_driver_name(dip), instance);
 541 
 542         /*
 543          * Override 80211 default routines
 544          */
 545         ieee80211_media_init(ic); /* initial the node table and bss */
 546         sc->sc_newstate = ic->ic_newstate;
 547         ic->ic_newstate = ipw2200_newstate;
 548         ic->ic_def_txkey = 0;
 549         sc->sc_authmode = IEEE80211_AUTH_OPEN;
 550 
 551         /*
 552          * Add the interrupt handler
 553          */
 554         err = ddi_add_intr(dip, 0, &sc->sc_iblk, NULL,
 555             ipw2200_intr, (caddr_t)sc);
 556         if (err != DDI_SUCCESS) {
 557                 IPW2200_WARN((dip, CE_WARN,
 558                     "ipw2200_attach(): ddi_add_intr() failed\n"));
 559                 goto fail5;
 560         }
 561 
 562         /*
 563          * Initialize pointer to device specific functions
 564          */
 565         wd.wd_secalloc = WIFI_SEC_NONE;
 566         wd.wd_opmode = ic->ic_opmode;
 567         IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
 568 
 569         macp = mac_alloc(MAC_VERSION);
 570         if (err != 0) {
 571                 IPW2200_WARN((dip, CE_WARN,
 572                     "ipw2200_attach(): mac_alloc() failed\n"));
 573                 goto fail6;
 574         }
 575 
 576         macp->m_type_ident   = MAC_PLUGIN_IDENT_WIFI;
 577         macp->m_driver               = sc;
 578         macp->m_dip          = dip;
 579         macp->m_src_addr     = ic->ic_macaddr;
 580         macp->m_callbacks    = &ipw2200_m_callbacks;
 581         macp->m_min_sdu              = 0;
 582         macp->m_max_sdu              = IEEE80211_MTU;
 583         macp->m_pdata                = &wd;
 584         macp->m_pdata_size   = sizeof (wd);
 585 
 586         /*
 587          * Register the macp to mac
 588          */
 589         err = mac_register(macp, &ic->ic_mach);
 590         mac_free(macp);
 591         if (err != DDI_SUCCESS) {
 592                 IPW2200_WARN((dip, CE_WARN,
 593                     "ipw2200_attach(): mac_register() failed\n"));
 594                 goto fail6;
 595         }
 596 
 597         /*
 598          * Create minor node of type DDI_NT_NET_WIFI
 599          */
 600         (void) snprintf(strbuf, sizeof (strbuf), "%s%d",
 601             IPW2200_DRV_NAME, instance);
 602         err = ddi_create_minor_node(dip, strbuf, S_IFCHR,
 603             instance + 1, DDI_NT_NET_WIFI, 0);
 604         if (err != DDI_SUCCESS)
 605                 IPW2200_WARN((dip, CE_WARN,
 606                     "ipw2200_attach(): ddi_create_minor_node() failed\n"));
 607 
 608         /*
 609          * Cache firmware will always be true
 610          */
 611         (void) ipw2200_cache_firmware(sc);
 612 
 613         /*
 614          * Notify link is down now
 615          */
 616         mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
 617 
 618         /*
 619          * Create the mf thread to handle the link status,
 620          * recovery fatal error, etc.
 621          */
 622         sc->sc_mfthread_switch = 1;
 623         if (sc->sc_mf_thread == NULL)
 624                 sc->sc_mf_thread = thread_create((caddr_t)NULL, 0,
 625                     ipw2200_thread, sc, 0, &p0, TS_RUN, minclsyspri);
 626 
 627         return (DDI_SUCCESS);
 628 
 629 fail6:
 630         ddi_remove_intr(dip, 0, sc->sc_iblk);
 631 fail5:
 632         ieee80211_detach(ic);
 633 
 634         mutex_destroy(&sc->sc_ilock);
 635         mutex_destroy(&sc->sc_cmd_lock);
 636         mutex_destroy(&sc->sc_tx_lock);
 637         mutex_destroy(&sc->sc_mflock);
 638         mutex_destroy(&sc->sc_resched_lock);
 639         cv_destroy(&sc->sc_fw_cond);
 640         cv_destroy(&sc->sc_cmd_status_cond);
 641         cv_destroy(&sc->sc_cmd_cond);
 642         cv_destroy(&sc->sc_mfthread_cv);
 643 fail4:
 644         ipw2200_ring_free(sc);
 645 fail3:
 646         ddi_regs_map_free(&sc->sc_ioh);
 647 fail2:
 648         ddi_soft_state_free(ipw2200_ssp, instance);
 649 fail1:
 650         return (err);
 651 }
 652 
 653 
 654 int
 655 ipw2200_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 656 {
 657         struct ipw2200_softc    *sc;
 658         int                     err;
 659 
 660         sc = ddi_get_soft_state(ipw2200_ssp, ddi_get_instance(dip));
 661         ASSERT(sc != NULL);
 662 
 663         switch (cmd) {
 664         case DDI_DETACH:
 665                 break;
 666         case DDI_SUSPEND:
 667                 if (sc->sc_flags & IPW2200_FLAG_RUNNING) {
 668                         ipw2200_stop(sc);
 669                 }
 670                 sc->sc_flags |= IPW2200_FLAG_SUSPEND;
 671 
 672                 IPW2200_DBG(IPW2200_DBG_SUSPEND, (sc->sc_dip, CE_CONT,
 673                     "ipw2200_detach(): suspend\n"));
 674                 return (DDI_SUCCESS);
 675         default:
 676                 return (DDI_FAILURE);
 677         }
 678 
 679         err = mac_disable(sc->sc_ic.ic_mach);
 680         if (err != DDI_SUCCESS)
 681                 return (err);
 682 
 683         ipw2200_stop(sc);
 684 
 685         /*
 686          * Destroy the mf_thread
 687          */
 688         mutex_enter(&sc->sc_mflock);
 689         sc->sc_mfthread_switch = 0;
 690         while (sc->sc_mf_thread != NULL) {
 691                 if (cv_wait_sig(&sc->sc_mfthread_cv, &sc->sc_mflock) == 0)
 692                         break;
 693         }
 694         mutex_exit(&sc->sc_mflock);
 695 
 696         /*
 697          * Unregister from the MAC layer subsystem
 698          */
 699         (void) mac_unregister(sc->sc_ic.ic_mach);
 700 
 701         ddi_remove_intr(dip, IPW2200_PCI_INTR_NUM, sc->sc_iblk);
 702 
 703         mutex_destroy(&sc->sc_ilock);
 704         mutex_destroy(&sc->sc_cmd_lock);
 705         mutex_destroy(&sc->sc_tx_lock);
 706         mutex_destroy(&sc->sc_mflock);
 707         mutex_destroy(&sc->sc_resched_lock);
 708         cv_destroy(&sc->sc_fw_cond);
 709         cv_destroy(&sc->sc_cmd_status_cond);
 710         cv_destroy(&sc->sc_cmd_cond);
 711         cv_destroy(&sc->sc_mfthread_cv);
 712 
 713         /*
 714          * Detach ieee80211
 715          */
 716         ieee80211_detach(&sc->sc_ic);
 717 
 718         (void) ipw2200_free_firmware(sc);
 719         ipw2200_ring_free(sc);
 720 
 721         ddi_regs_map_free(&sc->sc_ioh);
 722         ddi_remove_minor_node(dip, NULL);
 723         ddi_soft_state_free(ipw2200_ssp, ddi_get_instance(dip));
 724 
 725         return (DDI_SUCCESS);
 726 }
 727 
 728 /*
 729  * quiesce(9E) entry point.
 730  * This function is called when the system is single-threaded at high
 731  * PIL with preemption disabled. Therefore, this function must not be
 732  * blocked.
 733  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
 734  * DDI_FAILURE indicates an error condition and should almost never happen.
 735  */
 736 static int
 737 ipw2200_quiesce(dev_info_t *dip)
 738 {
 739         struct ipw2200_softc    *sc =
 740             ddi_get_soft_state(ipw2200_ssp, ddi_get_instance(dip));
 741         if (sc == NULL)
 742                 return (DDI_FAILURE);
 743 
 744         /* by pass any messages, if it's quiesce */
 745         ipw2200_debug = 0;
 746 
 747         /*
 748          * No more blocking is allowed while we are in the
 749          * quiesce(9E) entry point.
 750          */
 751         sc->sc_flags |= IPW2200_FLAG_QUIESCED;
 752 
 753         /*
 754          * Disable and mask all interrupts.
 755          */
 756         ipw2200_master_stop(sc);
 757         ipw2200_csr_put32(sc, IPW2200_CSR_RST, IPW2200_RST_SW_RESET);
 758         return (DDI_SUCCESS);
 759 }
 760 
 761 static void
 762 ipw2200_stop(struct ipw2200_softc *sc)
 763 {
 764         struct ieee80211com     *ic = &sc->sc_ic;
 765 
 766         IPW2200_DBG(IPW2200_DBG_HWCAP, (sc->sc_dip, CE_CONT,
 767             "ipw2200_stop(): enter\n"));
 768 
 769         ipw2200_master_stop(sc);
 770         ipw2200_csr_put32(sc, IPW2200_CSR_RST, IPW2200_RST_SW_RESET);
 771 
 772         /*
 773          * Reset ring
 774          */
 775         ipw2200_ring_reset(sc);
 776 
 777         ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
 778         sc->sc_flags &= ~IPW2200_FLAG_SCANNING;
 779         sc->sc_flags &= ~IPW2200_FLAG_ASSOCIATED;
 780 
 781         IPW2200_DBG(IPW2200_DBG_HWCAP, (sc->sc_dip, CE_CONT,
 782             "ipw2200_stop(): exit\n"));
 783 }
 784 
 785 static int
 786 ipw2200_config(struct ipw2200_softc *sc)
 787 {
 788         struct ieee80211com             *ic = &sc->sc_ic;
 789         struct ipw2200_configuration    cfg;
 790         uint32_t                        data;
 791         struct ipw2200_txpower          pwr;
 792         struct ipw2200_rateset          rs;
 793         struct ipw2200_wep_key          wkey;
 794         int                             err, i;
 795 
 796         /*
 797          * Set the IBSS mode channel: Tx power
 798          */
 799         if (ic->ic_opmode == IEEE80211_M_IBSS) {
 800                 pwr.mode  = IPW2200_MODE_11B;
 801                 pwr.nchan = 11;
 802                 for (i = 0; i < pwr.nchan; i++) {
 803                         pwr.chan[i].chan  = i + 1;
 804                         pwr.chan[i].power = IPW2200_TXPOWER_MAX;
 805                 }
 806                 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
 807                     "ipw2200_config(): Setting .11b channels Tx power\n"));
 808                 err = ipw2200_cmd(sc, IPW2200_CMD_SET_TX_POWER,
 809                     &pwr, sizeof (pwr), 0);
 810                 if (err != DDI_SUCCESS)
 811                         return (err);
 812 
 813                 pwr.mode  = IPW2200_MODE_11G;
 814                 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
 815                     "ipw2200_config(): Setting .11g channels Tx power\n"));
 816                 err = ipw2200_cmd(sc, IPW2200_CMD_SET_TX_POWER,
 817                     &pwr, sizeof (pwr), 0);
 818                 if (err != DDI_SUCCESS)
 819                         return (err);
 820         }
 821 
 822         /*
 823          * Set MAC address
 824          */
 825         IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
 826             "ipw2200_config(): Setting MAC address to "
 827             "%02x:%02x:%02x:%02x:%02x:%02x\n",
 828             ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2],
 829             ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5]));
 830         err = ipw2200_cmd(sc, IPW2200_CMD_SET_MAC_ADDRESS, ic->ic_macaddr,
 831             IEEE80211_ADDR_LEN, 0);
 832         if (err != DDI_SUCCESS)
 833                 return (err);
 834 
 835         /*
 836          * Set basic system config settings: configuration(capabilities)
 837          */
 838         (void) memset(&cfg, 0, sizeof (cfg));
 839         cfg.bluetooth_coexistence        = 1;
 840         cfg.multicast_enabled            = 1;
 841         cfg.answer_pbreq                 = 1;
 842         cfg.noise_reported               = 1;
 843         cfg.disable_multicast_decryption = 1; /* WPA */
 844         cfg.disable_unicast_decryption   = 1; /* WPA */
 845 
 846         IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
 847             "ipw2200_config(): Configuring adapter\n"));
 848         err = ipw2200_cmd(sc, IPW2200_CMD_SET_CONFIG,
 849             &cfg, sizeof (cfg), 0);
 850         if (err != DDI_SUCCESS)
 851                 return (err);
 852 
 853         /*
 854          * Set power mode
 855          */
 856         data = LE_32(IPW2200_POWER_MODE_CAM);
 857         IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
 858             "ipw2200_config(): Setting power mode to %u\n", LE_32(data)));
 859         err = ipw2200_cmd(sc, IPW2200_CMD_SET_POWER_MODE,
 860             &data, sizeof (data), 0);
 861         if (err != DDI_SUCCESS)
 862                 return (err);
 863 
 864         /*
 865          * Set supported rates
 866          */
 867         rs.mode = IPW2200_MODE_11G;
 868         rs.type = IPW2200_RATESET_TYPE_SUPPORTED;
 869         rs.nrates = ic->ic_sup_rates[IEEE80211_MODE_11G].ir_nrates;
 870         (void) memcpy(rs.rates, ic->ic_sup_rates[IEEE80211_MODE_11G].ir_rates,
 871             rs.nrates);
 872         IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
 873             "ipw2200_config(): Setting .11g supported rates(%u)\n", rs.nrates));
 874         err = ipw2200_cmd(sc, IPW2200_CMD_SET_RATES, &rs, sizeof (rs), 0);
 875         if (err != DDI_SUCCESS)
 876                 return (err);
 877 
 878         rs.mode = IPW2200_MODE_11A;
 879         rs.type = IPW2200_RATESET_TYPE_SUPPORTED;
 880         rs.nrates = ic->ic_sup_rates[IEEE80211_MODE_11A].ir_nrates;
 881         (void) memcpy(rs.rates, ic->ic_sup_rates[IEEE80211_MODE_11A].ir_rates,
 882             rs.nrates);
 883         IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
 884             "ipw2200_config(): Setting .11a supported rates(%u)\n", rs.nrates));
 885         err = ipw2200_cmd(sc, IPW2200_CMD_SET_RATES, &rs, sizeof (rs), 0);
 886         if (err != DDI_SUCCESS)
 887                 return (err);
 888 
 889         /*
 890          * Set RTS(request-to-send) threshold
 891          */
 892         data = LE_32(ic->ic_rtsthreshold);
 893         IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
 894             "ipw2200_config(): Setting RTS threshold to %u\n", LE_32(data)));
 895         err = ipw2200_cmd(sc, IPW2200_CMD_SET_RTS_THRESHOLD, &data,
 896             sizeof (data), 0);
 897         if (err != DDI_SUCCESS)
 898                 return (err);
 899 
 900         /*
 901          * Set fragmentation threshold
 902          */
 903         data = LE_32(ic->ic_fragthreshold);
 904         IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
 905             "ipw2200_config(): Setting fragmentation threshold to %u\n",
 906             LE_32(data)));
 907         err = ipw2200_cmd(sc, IPW2200_CMD_SET_FRAG_THRESHOLD, &data,
 908             sizeof (data), 0);
 909         if (err != DDI_SUCCESS)
 910                 return (err);
 911 
 912         /*
 913          * Set desired ESSID if we have
 914          */
 915         if (ic->ic_des_esslen != 0) {
 916                 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
 917                     "ipw2200_config(): Setting desired ESSID to "
 918                     "(%u),%c%c%c%c%c%c%c%c\n",
 919                     ic->ic_des_esslen,
 920                     ic->ic_des_essid[0], ic->ic_des_essid[1],
 921                     ic->ic_des_essid[2], ic->ic_des_essid[3],
 922                     ic->ic_des_essid[4], ic->ic_des_essid[5],
 923                     ic->ic_des_essid[6], ic->ic_des_essid[7]));
 924                 err = ipw2200_cmd(sc, IPW2200_CMD_SET_ESSID, ic->ic_des_essid,
 925                     ic->ic_des_esslen, 0);
 926                 if (err != DDI_SUCCESS)
 927                         return (err);
 928         }
 929 
 930         /*
 931          * Set WEP initial vector(random seed)
 932          */
 933         (void) random_get_pseudo_bytes((uint8_t *)&data, sizeof (data));
 934         IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
 935             "ipw2200_config(): Setting initialization vector to %u\n",
 936             LE_32(data)));
 937         err = ipw2200_cmd(sc, IPW2200_CMD_SET_IV, &data, sizeof (data), 0);
 938         if (err != DDI_SUCCESS)
 939                 return (err);
 940 
 941         /*
 942          * Set WEP if any
 943          */
 944         if (ic->ic_flags & IEEE80211_F_PRIVACY) {
 945                 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
 946                     "ipw2200_config(): Setting Wep Key\n", LE_32(data)));
 947                 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
 948                         wkey.cmd = IPW2200_WEP_KEY_CMD_SETKEY;
 949                         wkey.idx = (uint8_t)i;
 950                         wkey.len = ic->ic_nw_keys[i].wk_keylen;
 951                         (void) memset(wkey.key, 0, sizeof (wkey.key));
 952                         if (ic->ic_nw_keys[i].wk_keylen)
 953                                 (void) memcpy(wkey.key,
 954                                     ic->ic_nw_keys[i].wk_key,
 955                                     ic->ic_nw_keys[i].wk_keylen);
 956                         err = ipw2200_cmd(sc, IPW2200_CMD_SET_WEP_KEY,
 957                             &wkey, sizeof (wkey), 0);
 958                         if (err != DDI_SUCCESS)
 959                                 return (err);
 960                 }
 961         }
 962 
 963         IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
 964             "ipw2200_config(): Enabling adapter\n"));
 965 
 966         return (ipw2200_cmd(sc, IPW2200_CMD_ENABLE, NULL, 0, 0));
 967 }
 968 
 969 static int
 970 ipw2200_cmd(struct ipw2200_softc *sc,
 971         uint32_t type, void *buf, size_t len, int async)
 972 {
 973         struct          ipw2200_cmd_desc *cmd;
 974         clock_t         clk;
 975         uint32_t        idx;
 976 
 977         mutex_enter(&sc->sc_cmd_lock);
 978         while (sc->sc_cmd_free < 1)
 979                 cv_wait(&sc->sc_cmd_cond, &sc->sc_cmd_lock);
 980 
 981         idx = sc->sc_cmd_cur;
 982         cmd = &sc->sc_cmdsc[idx];
 983         (void) memset(cmd, 0, sizeof (*cmd));
 984 
 985         IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT,
 986             "ipw2200_cmd(): cmd-cur=%d\n", idx));
 987 
 988         cmd->hdr.type   = IPW2200_HDR_TYPE_COMMAND;
 989         cmd->hdr.flags  = IPW2200_HDR_FLAG_IRQ;
 990         cmd->type    = (uint8_t)type;
 991         if (len == 0 || buf == NULL)
 992                 cmd->len  = 0;
 993         else {
 994                 cmd->len  = (uint8_t)len;
 995                 (void) memcpy(cmd->data, buf, len);
 996         }
 997         sc->sc_done[idx] = 0;
 998 
 999         /*
1000          * DMA sync
1001          */
1002         (void) ddi_dma_sync(sc->sc_dma_cmdsc.dr_hnd,
1003             idx * sizeof (struct ipw2200_cmd_desc),
1004             sizeof (struct ipw2200_cmd_desc), DDI_DMA_SYNC_FORDEV);
1005 
1006         sc->sc_cmd_cur = RING_FORWARD(sc->sc_cmd_cur, 1, IPW2200_CMD_RING_SIZE);
1007         sc->sc_cmd_free--;
1008 
1009         ipw2200_csr_put32(sc, IPW2200_CSR_CMD_WRITE_INDEX, sc->sc_cmd_cur);
1010 
1011         mutex_exit(&sc->sc_cmd_lock);
1012 
1013         if (async)
1014                 goto out;
1015 
1016         /*
1017          * Wait for command done
1018          */
1019         clk = drv_usectohz(5000000);
1020         mutex_enter(&sc->sc_ilock);
1021         while (sc->sc_done[idx] == 0) {
1022                 /* pending */
1023                 if (cv_reltimedwait(&sc->sc_cmd_status_cond, &sc->sc_ilock,
1024                     clk, TR_CLOCK_TICK) < 0)
1025                         break;
1026         }
1027         mutex_exit(&sc->sc_ilock);
1028 
1029         IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT,
1030             "ipw2200_cmd(): cmd-done=%s\n", sc->sc_done[idx] ? "yes" : "no"));
1031 
1032         if (sc->sc_done[idx] == 0)
1033                 return (DDI_FAILURE);
1034 
1035 out:
1036         return (DDI_SUCCESS);
1037 }
1038 
1039 /*
1040  * If init failed, it will call stop internally. Therefore, it's unnecessary
1041  * to call ipw2200_stop() when this subroutine is failed. Otherwise, it may
1042  * be called twice.
1043  */
1044 int
1045 ipw2200_init(struct ipw2200_softc *sc)
1046 {
1047         int     err;
1048 
1049         /*
1050          * No firmware is available, failed
1051          */
1052         if (!(sc->sc_flags & IPW2200_FLAG_FW_CACHED)) {
1053                 IPW2200_WARN((sc->sc_dip, CE_WARN,
1054                     "ipw2200_init(): no firmware is available\n"));
1055                 return (DDI_FAILURE); /* return directly */
1056         }
1057 
1058         ipw2200_stop(sc);
1059 
1060         err = ipw2200_chip_reset(sc);
1061         if (err != DDI_SUCCESS) {
1062                 IPW2200_WARN((sc->sc_dip, CE_WARN,
1063                     "ipw2200_init(): could not reset adapter\n"));
1064                 goto fail;
1065         }
1066 
1067         /*
1068          * Load boot code
1069          */
1070         err = ipw2200_load_fw(sc, sc->sc_fw.boot_base, sc->sc_fw.boot_size);
1071         if (err != DDI_SUCCESS) {
1072                 IPW2200_WARN((sc->sc_dip, CE_WARN,
1073                     "ipw2200_init(): could not load boot code\n"));
1074                 goto fail;
1075         }
1076 
1077         /*
1078          * Load boot microcode
1079          */
1080         err = ipw2200_load_uc(sc, sc->sc_fw.uc_base, sc->sc_fw.uc_size);
1081         if (err != DDI_SUCCESS) {
1082                 IPW2200_WARN((sc->sc_dip, CE_WARN,
1083                     "ipw2200_init(): could not load microcode\n"));
1084                 goto fail;
1085         }
1086 
1087         ipw2200_master_stop(sc);
1088         ipw2200_ring_hwsetup(sc);
1089 
1090         /*
1091          * Load firmware
1092          */
1093         err = ipw2200_load_fw(sc, sc->sc_fw.fw_base, sc->sc_fw.fw_size);
1094         if (err != DDI_SUCCESS) {
1095                 IPW2200_WARN((sc->sc_dip, CE_WARN,
1096                     "ipw2200_init(): could not load firmware\n"));
1097                 goto fail;
1098         }
1099 
1100         sc->sc_flags |= IPW2200_FLAG_FW_INITED;
1101 
1102         /*
1103          * Hardware will be enabled after configuration
1104          */
1105         err = ipw2200_config(sc);
1106         if (err != DDI_SUCCESS) {
1107                 IPW2200_WARN((sc->sc_dip, CE_WARN,
1108                     "ipw2200_init(): device configuration failed\n"));
1109                 goto fail;
1110         }
1111 
1112         /*
1113          * workround to prevent too many h/w error.
1114          * delay for a while till h/w is stable.
1115          */
1116         delay(drv_usectohz(delay_config_stable));
1117 
1118         return (DDI_SUCCESS); /* return successfully */
1119 fail:
1120         ipw2200_stop(sc);
1121         return (err);
1122 }
1123 
1124 /*
1125  * get hardware configurations from EEPROM embedded within PRO/2200
1126  */
1127 static void
1128 ipw2200_hwconf_get(struct ipw2200_softc *sc)
1129 {
1130         int             i;
1131         uint16_t        val;
1132 
1133         /*
1134          * Get mac address
1135          */
1136         i = 0;
1137         val = ipw2200_rom_get16(sc, IPW2200_EEPROM_MAC + 0);
1138         sc->sc_macaddr[i++] = val >> 8;
1139         sc->sc_macaddr[i++] = val & 0xff;
1140         val = ipw2200_rom_get16(sc, IPW2200_EEPROM_MAC + 1);
1141         sc->sc_macaddr[i++] = val >> 8;
1142         sc->sc_macaddr[i++] = val & 0xff;
1143         val = ipw2200_rom_get16(sc, IPW2200_EEPROM_MAC + 2);
1144         sc->sc_macaddr[i++] = val >> 8;
1145         sc->sc_macaddr[i++] = val & 0xff;
1146 
1147         /*
1148          * formatted MAC address string
1149          */
1150         (void) snprintf(sc->sc_macstr, sizeof (sc->sc_macstr),
1151             "%02x:%02x:%02x:%02x:%02x:%02x",
1152             sc->sc_macaddr[0], sc->sc_macaddr[1],
1153             sc->sc_macaddr[2], sc->sc_macaddr[3],
1154             sc->sc_macaddr[4], sc->sc_macaddr[5]);
1155 
1156 }
1157 
1158 /*
1159  * all ipw2200 interrupts will be masked by this routine
1160  */
1161 static void
1162 ipw2200_master_stop(struct ipw2200_softc *sc)
1163 {
1164         int     ntries;
1165 
1166         /*
1167          * disable interrupts
1168          */
1169         ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, 0);
1170         ipw2200_csr_put32(sc, IPW2200_CSR_RST, IPW2200_RST_STOP_MASTER);
1171 
1172         /*
1173          * wait long enough to ensure hardware stop successfully.
1174          */
1175         for (ntries = 0; ntries < 500; ntries++) {
1176                 if (ipw2200_csr_get32(sc, IPW2200_CSR_RST) &
1177                     IPW2200_RST_MASTER_DISABLED)
1178                         break;
1179                 /* wait for a while */
1180                 drv_usecwait(100);
1181         }
1182         if (ntries == 500)
1183                 IPW2200_WARN((sc->sc_dip, CE_WARN,
1184                     "ipw2200_master_stop(): timeout\n"));
1185 
1186         ipw2200_csr_put32(sc, IPW2200_CSR_RST,
1187             IPW2200_RST_PRINCETON_RESET |
1188             ipw2200_csr_get32(sc, IPW2200_CSR_RST));
1189 
1190         sc->sc_flags &= ~IPW2200_FLAG_FW_INITED;
1191 }
1192 
1193 /*
1194  * all ipw2200 interrupts will be masked by this routine
1195  */
1196 static int
1197 ipw2200_chip_reset(struct ipw2200_softc *sc)
1198 {
1199         uint32_t        tmp;
1200         int             ntries, i;
1201 
1202         ipw2200_master_stop(sc);
1203 
1204         /*
1205          * Move adapter to DO state
1206          */
1207         tmp = ipw2200_csr_get32(sc, IPW2200_CSR_CTL);
1208         ipw2200_csr_put32(sc, IPW2200_CSR_CTL, tmp | IPW2200_CTL_INIT);
1209 
1210         /*
1211          * Initialize Phase-Locked Level (PLL)
1212          */
1213         ipw2200_csr_put32(sc, IPW2200_CSR_READ_INT, IPW2200_READ_INT_INIT_HOST);
1214 
1215         /*
1216          * Wait for clock stabilization
1217          */
1218         for (ntries = 0; ntries < 1000; ntries++) {
1219                 if (ipw2200_csr_get32(sc, IPW2200_CSR_CTL) &
1220                     IPW2200_CTL_CLOCK_READY)
1221                         break;
1222                 drv_usecwait(200);
1223         }
1224         if (ntries == 1000) {
1225                 IPW2200_WARN((sc->sc_dip, CE_WARN,
1226                     "ipw2200_chip_reset(): timeout\n"));
1227                 return (DDI_FAILURE);
1228         }
1229 
1230         tmp = ipw2200_csr_get32(sc, IPW2200_CSR_RST);
1231         ipw2200_csr_put32(sc, IPW2200_CSR_RST, tmp | IPW2200_RST_SW_RESET);
1232 
1233         drv_usecwait(10);
1234 
1235         tmp = ipw2200_csr_get32(sc, IPW2200_CSR_CTL);
1236         ipw2200_csr_put32(sc, IPW2200_CSR_CTL, tmp | IPW2200_CTL_INIT);
1237 
1238         /*
1239          * clear NIC memory
1240          */
1241         ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_ADDR, 0);
1242         for (i = 0; i < 0xc000; i++)
1243                 ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_DATA, 0);
1244 
1245         return (DDI_SUCCESS);
1246 }
1247 
1248 /*
1249  * This function is used by wificonfig/dladm to get the current
1250  * radio status, it is off/on
1251  */
1252 int
1253 ipw2200_radio_status(struct ipw2200_softc *sc)
1254 {
1255         int     val;
1256 
1257         val = (ipw2200_csr_get32(sc, IPW2200_CSR_IO) &
1258             IPW2200_IO_RADIO_ENABLED) ? 1 : 0;
1259 
1260         return (val);
1261 }
1262 /*
1263  * This function is used to get the statistic
1264  */
1265 void
1266 ipw2200_get_statistics(struct ipw2200_softc *sc)
1267 {
1268         struct ieee80211com     *ic = &sc->sc_ic;
1269 
1270         uint32_t size, buf[128];
1271 
1272         if (!(sc->sc_flags & IPW2200_FLAG_FW_INITED)) {
1273                 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT,
1274                     "ipw2200_get_statistic(): fw doesn't download yet."));
1275                 return;
1276         }
1277 
1278         size = min(ipw2200_csr_get32(sc, IPW2200_CSR_TABLE0_SIZE), 128 - 1);
1279         ipw2200_csr_getbuf32(sc, IPW2200_CSR_TABLE0_BASE, &buf[1], size);
1280 
1281         /*
1282          * To retrieve the statistic information into proper places. There are
1283          * lot of information. These table will be read once a second.
1284          * Hopefully, it will not effect the performance.
1285          */
1286 
1287         /*
1288          * For the tx/crc information, we can get them from chip directly;
1289          * For the rx/wep error/(rts) related information, leave them net80211.
1290          */
1291         /* WIFI_STAT_TX_FRAGS */
1292         ic->ic_stats.is_tx_frags = (uint32_t)buf[5];
1293         /* WIFI_STAT_MCAST_TX */
1294         ic->ic_stats.is_tx_mcast = (uint32_t)buf[31];
1295         /* WIFI_STAT_TX_RETRANS */
1296         ic->ic_stats.is_tx_retries = (uint32_t)buf[56];
1297         /* WIFI_STAT_TX_FAILED */
1298         ic->ic_stats.is_tx_failed = (uint32_t)buf[57];
1299         /* MAC_STAT_OBYTES */
1300         ic->ic_stats.is_tx_bytes = (uint32_t)buf[64];
1301 }
1302 
1303 /*
1304  * DMA region alloc subroutine
1305  */
1306 int
1307 ipw2200_dma_region_alloc(struct ipw2200_softc *sc, struct dma_region *dr,
1308         size_t size, uint_t dir, uint_t flags)
1309 {
1310         dev_info_t      *dip = sc->sc_dip;
1311         int             err;
1312 
1313         IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT,
1314             "ipw2200_dma_region_alloc(): size =%u\n", size));
1315 
1316         err = ddi_dma_alloc_handle(dip, &ipw2200_dma_attr, DDI_DMA_SLEEP, NULL,
1317             &dr->dr_hnd);
1318         if (err != DDI_SUCCESS) {
1319                 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT,
1320                     "ipw2200_dma_region_alloc(): "
1321                     "ddi_dma_alloc_handle() failed\n"));
1322                 goto fail0;
1323         }
1324 
1325         err = ddi_dma_mem_alloc(dr->dr_hnd, size, &ipw2200_dma_accattr,
1326             flags, DDI_DMA_SLEEP, NULL,
1327             &dr->dr_base, &dr->dr_size, &dr->dr_acc);
1328         if (err != DDI_SUCCESS) {
1329                 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT,
1330                     "ipw2200_dma_region_alloc(): "
1331                     "ddi_dma_mem_alloc() failed\n"));
1332                 goto fail1;
1333         }
1334 
1335         err = ddi_dma_addr_bind_handle(dr->dr_hnd, NULL,
1336             dr->dr_base, dr->dr_size,
1337             dir | flags, DDI_DMA_SLEEP, NULL,
1338             &dr->dr_cookie, &dr->dr_ccnt);
1339         if (err != DDI_DMA_MAPPED) {
1340                 IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT,
1341                     "ipw2200_dma_region_alloc(): "
1342                     "ddi_dma_addr_bind_handle() failed\n"));
1343                 goto fail2;
1344         }
1345 
1346         IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT,
1347             "ipw2200_dma_region_alloc(): ccnt=%u\n", dr->dr_ccnt));
1348 
1349         if (dr->dr_ccnt != 1) {
1350                 err = DDI_FAILURE;
1351                 goto fail3;
1352         }
1353 
1354         dr->dr_pbase = dr->dr_cookie.dmac_address;
1355 
1356         IPW2200_DBG(IPW2200_DBG_DMA, (sc->sc_dip, CE_CONT,
1357             "ipw2200_dma_region_alloc(): get physical-base=0x%08x\n",
1358             dr->dr_pbase));
1359 
1360         return (DDI_SUCCESS);
1361 
1362 fail3:
1363         (void) ddi_dma_unbind_handle(dr->dr_hnd);
1364 fail2:
1365         ddi_dma_mem_free(&dr->dr_acc);
1366 fail1:
1367         ddi_dma_free_handle(&dr->dr_hnd);
1368 fail0:
1369         return (err);
1370 }
1371 
1372 void
1373 ipw2200_dma_region_free(struct dma_region *dr)
1374 {
1375         (void) ddi_dma_unbind_handle(dr->dr_hnd);
1376         ddi_dma_mem_free(&dr->dr_acc);
1377         ddi_dma_free_handle(&dr->dr_hnd);
1378 }
1379 
1380 static int
1381 ipw2200_ring_alloc(struct ipw2200_softc *sc)
1382 {
1383         int     err, i;
1384 
1385         /*
1386          * tx desc ring
1387          */
1388         sc->sc_dma_txdsc.dr_name = "ipw2200-tx-desc-ring";
1389         err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_txdsc,
1390             IPW2200_TX_RING_SIZE * sizeof (struct ipw2200_tx_desc),
1391             DDI_DMA_WRITE, DDI_DMA_CONSISTENT);
1392         if (err != DDI_SUCCESS)
1393                 goto fail0;
1394         /*
1395          * tx buffer array
1396          */
1397         for (i = 0; i < IPW2200_TX_RING_SIZE; i++) {
1398                 sc->sc_dma_txbufs[i].dr_name = "ipw2200-tx-buf";
1399                 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_txbufs[i],
1400                     IPW2200_TXBUF_SIZE, DDI_DMA_WRITE, DDI_DMA_STREAMING);
1401                 if (err != DDI_SUCCESS) {
1402                         while (i >= 0) {
1403                                 ipw2200_dma_region_free(&sc->sc_dma_txbufs[i]);
1404                                 i--;
1405                         }
1406                         goto fail1;
1407                 }
1408         }
1409         /*
1410          * rx buffer array
1411          */
1412         for (i = 0; i < IPW2200_RX_RING_SIZE; i++) {
1413                 sc->sc_dma_rxbufs[i].dr_name = "ipw2200-rx-buf";
1414                 err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_rxbufs[i],
1415                     IPW2200_RXBUF_SIZE, DDI_DMA_READ, DDI_DMA_STREAMING);
1416                 if (err != DDI_SUCCESS) {
1417                         while (i >= 0) {
1418                                 ipw2200_dma_region_free(&sc->sc_dma_rxbufs[i]);
1419                                 i--;
1420                         }
1421                         goto fail2;
1422                 }
1423         }
1424         /*
1425          * cmd desc ring
1426          */
1427         sc->sc_dma_cmdsc.dr_name = "ipw2200-cmd-desc-ring";
1428         err = ipw2200_dma_region_alloc(sc, &sc->sc_dma_cmdsc,
1429             IPW2200_CMD_RING_SIZE * sizeof (struct ipw2200_cmd_desc),
1430             DDI_DMA_WRITE, DDI_DMA_CONSISTENT);
1431         if (err != DDI_SUCCESS)
1432                 goto fail3;
1433 
1434         return (DDI_SUCCESS);
1435 
1436 fail3:
1437         for (i = 0; i < IPW2200_RX_RING_SIZE; i++)
1438                 ipw2200_dma_region_free(&sc->sc_dma_rxbufs[i]);
1439 fail2:
1440         for (i = 0; i < IPW2200_TX_RING_SIZE; i++)
1441                 ipw2200_dma_region_free(&sc->sc_dma_txbufs[i]);
1442 fail1:
1443         ipw2200_dma_region_free(&sc->sc_dma_txdsc);
1444 fail0:
1445         return (err);
1446 }
1447 
1448 static void
1449 ipw2200_ring_free(struct ipw2200_softc *sc)
1450 {
1451         int     i;
1452 
1453         /*
1454          * tx ring desc
1455          */
1456         ipw2200_dma_region_free(&sc->sc_dma_txdsc);
1457         /*
1458          * tx buf
1459          */
1460         for (i = 0; i < IPW2200_TX_RING_SIZE; i++)
1461                 ipw2200_dma_region_free(&sc->sc_dma_txbufs[i]);
1462         /*
1463          * rx buf
1464          */
1465         for (i = 0; i < IPW2200_RX_RING_SIZE; i++)
1466                 ipw2200_dma_region_free(&sc->sc_dma_rxbufs[i]);
1467         /*
1468          * command ring desc
1469          */
1470         ipw2200_dma_region_free(&sc->sc_dma_cmdsc);
1471 }
1472 
1473 static void
1474 ipw2200_ring_reset(struct ipw2200_softc *sc)
1475 {
1476         int i;
1477 
1478         /*
1479          * tx desc ring & buffer array
1480          */
1481         sc->sc_tx_cur   = 0;
1482         sc->sc_tx_free  = IPW2200_TX_RING_SIZE;
1483         sc->sc_txdsc    = (struct ipw2200_tx_desc *)sc->sc_dma_txdsc.dr_base;
1484         for (i = 0; i < IPW2200_TX_RING_SIZE; i++)
1485                 sc->sc_txbufs[i] = (uint8_t *)sc->sc_dma_txbufs[i].dr_base;
1486         /*
1487          * rx buffer array
1488          */
1489         sc->sc_rx_cur   = 0;
1490         sc->sc_rx_free  = IPW2200_RX_RING_SIZE;
1491         for (i = 0; i < IPW2200_RX_RING_SIZE; i++)
1492                 sc->sc_rxbufs[i] = (uint8_t *)sc->sc_dma_rxbufs[i].dr_base;
1493 
1494         /*
1495          * command desc ring
1496          */
1497         sc->sc_cmd_cur  = 0;
1498         sc->sc_cmd_free = IPW2200_CMD_RING_SIZE;
1499         sc->sc_cmdsc    = (struct ipw2200_cmd_desc *)sc->sc_dma_cmdsc.dr_base;
1500 }
1501 
1502 /*
1503  * tx, rx rings and command initialization
1504  */
1505 static int
1506 ipw2200_ring_init(struct ipw2200_softc *sc)
1507 {
1508         int     err;
1509 
1510         err = ipw2200_ring_alloc(sc);
1511         if (err != DDI_SUCCESS)
1512                 return (err);
1513 
1514         ipw2200_ring_reset(sc);
1515 
1516         return (DDI_SUCCESS);
1517 }
1518 
1519 static void
1520 ipw2200_ring_hwsetup(struct ipw2200_softc *sc)
1521 {
1522         int     i;
1523 
1524         /*
1525          * command desc ring
1526          */
1527         ipw2200_csr_put32(sc, IPW2200_CSR_CMD_BASE, sc->sc_dma_cmdsc.dr_pbase);
1528         ipw2200_csr_put32(sc, IPW2200_CSR_CMD_SIZE, IPW2200_CMD_RING_SIZE);
1529         ipw2200_csr_put32(sc, IPW2200_CSR_CMD_WRITE_INDEX, sc->sc_cmd_cur);
1530 
1531         /*
1532          * tx desc ring.  only tx1 is used, tx2, tx3, and tx4 are unused
1533          */
1534         ipw2200_csr_put32(sc, IPW2200_CSR_TX1_BASE, sc->sc_dma_txdsc.dr_pbase);
1535         ipw2200_csr_put32(sc, IPW2200_CSR_TX1_SIZE, IPW2200_TX_RING_SIZE);
1536         ipw2200_csr_put32(sc, IPW2200_CSR_TX1_WRITE_INDEX, sc->sc_tx_cur);
1537 
1538         /*
1539          * tx2, tx3, tx4 is not used
1540          */
1541         ipw2200_csr_put32(sc, IPW2200_CSR_TX2_BASE, sc->sc_dma_txdsc.dr_pbase);
1542         ipw2200_csr_put32(sc, IPW2200_CSR_TX2_SIZE, IPW2200_TX_RING_SIZE);
1543         ipw2200_csr_put32(sc, IPW2200_CSR_TX2_READ_INDEX, 0);
1544         ipw2200_csr_put32(sc, IPW2200_CSR_TX2_WRITE_INDEX, 0);
1545         ipw2200_csr_put32(sc, IPW2200_CSR_TX3_BASE, sc->sc_dma_txdsc.dr_pbase);
1546         ipw2200_csr_put32(sc, IPW2200_CSR_TX3_SIZE, IPW2200_TX_RING_SIZE);
1547         ipw2200_csr_put32(sc, IPW2200_CSR_TX3_READ_INDEX, 0);
1548         ipw2200_csr_put32(sc, IPW2200_CSR_TX3_WRITE_INDEX, 0);
1549         ipw2200_csr_put32(sc, IPW2200_CSR_TX4_BASE, sc->sc_dma_txdsc.dr_pbase);
1550         ipw2200_csr_put32(sc, IPW2200_CSR_TX4_SIZE, IPW2200_TX_RING_SIZE);
1551         ipw2200_csr_put32(sc, IPW2200_CSR_TX4_READ_INDEX, 0);
1552         ipw2200_csr_put32(sc, IPW2200_CSR_TX4_WRITE_INDEX, 0);
1553 
1554         /*
1555          * rx buffer ring
1556          */
1557         for (i = 0; i < IPW2200_RX_RING_SIZE; i++)
1558                 ipw2200_csr_put32(sc, IPW2200_CSR_RX_BASE + i * 4,
1559                     sc->sc_dma_rxbufs[i].dr_pbase);
1560         /*
1561          * all rx buffer are empty, rx-rd-index == 0 && rx-wr-index == N-1
1562          */
1563         ipw2200_csr_put32(sc, IPW2200_CSR_RX_WRITE_INDEX,
1564             RING_BACKWARD(sc->sc_rx_cur, 1, IPW2200_RX_RING_SIZE));
1565 }
1566 
1567 int
1568 ipw2200_start_scan(struct ipw2200_softc *sc)
1569 {
1570         struct ieee80211com     *ic = &sc->sc_ic;
1571         struct ipw2200_scan     scan;
1572         uint8_t                 *ch;
1573         int                     cnt, i;
1574 
1575         IPW2200_DBG(IPW2200_DBG_SCAN, (sc->sc_dip, CE_CONT,
1576             "ipw2200_start_scan(): start scanning \n"));
1577 
1578         /*
1579          * start scanning
1580          */
1581         sc->sc_flags |= IPW2200_FLAG_SCANNING;
1582 
1583         (void) memset(&scan, 0, sizeof (scan));
1584         scan.type = (ic->ic_des_esslen != 0) ? IPW2200_SCAN_TYPE_BDIRECTED :
1585             IPW2200_SCAN_TYPE_BROADCAST;
1586         scan.dwelltime = LE_16(40); /* The interval is set up to 40 */
1587 
1588         /*
1589          * Compact supported channel number(5G) into a single buffer
1590          */
1591         ch = scan.channels;
1592         cnt = 0;
1593         for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
1594                 if (IEEE80211_IS_CHAN_5GHZ(&ic->ic_sup_channels[i]) &&
1595                     isset(ic->ic_chan_active, i)) {
1596                         *++ch = (uint8_t)i;
1597                         cnt++;
1598                 }
1599         }
1600         *(ch - cnt) = IPW2200_CHAN_5GHZ | (uint8_t)cnt;
1601         ch = (cnt > 0) ? (ch + 1) : (scan.channels);
1602 
1603         /*
1604          * Compact supported channel number(2G) into a single buffer
1605          */
1606         cnt = 0;
1607         for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
1608                 if (IEEE80211_IS_CHAN_2GHZ(&ic->ic_sup_channels[i]) &&
1609                     isset(ic->ic_chan_active, i)) {
1610                         *++ch = (uint8_t)i;
1611                         cnt++;
1612                 }
1613         }
1614         *(ch - cnt) = IPW2200_CHAN_2GHZ | cnt;
1615 
1616         return (ipw2200_cmd(sc, IPW2200_CMD_SCAN, &scan, sizeof (scan), 1));
1617 }
1618 
1619 int
1620 ipw2200_auth_and_assoc(struct ipw2200_softc *sc)
1621 {
1622         struct ieee80211com             *ic = &sc->sc_ic;
1623         struct ieee80211_node           *in = ic->ic_bss;
1624         struct ipw2200_configuration    cfg;
1625         struct ipw2200_rateset          rs;
1626         struct ipw2200_associate        assoc;
1627         uint32_t                        data;
1628         int                             err;
1629         uint8_t                         *wpa_level;
1630 
1631         if (sc->sc_flags & IPW2200_FLAG_ASSOCIATED) {
1632                 /* already associated */
1633                 return (-1);
1634         }
1635 
1636         /*
1637          * set the confiuration
1638          */
1639         if (IEEE80211_IS_CHAN_2GHZ(in->in_chan)) {
1640                 /* enable b/g auto-detection */
1641                 (void) memset(&cfg, 0, sizeof (cfg));
1642                 cfg.bluetooth_coexistence = 1;
1643                 cfg.multicast_enabled     = 1;
1644                 cfg.use_protection        = 1;
1645                 cfg.answer_pbreq          = 1;
1646                 cfg.noise_reported        = 1;
1647                 cfg.disable_multicast_decryption = 1; /* WPA */
1648                 cfg.disable_unicast_decryption   = 1; /* WPA */
1649                 err = ipw2200_cmd(sc, IPW2200_CMD_SET_CONFIG,
1650                     &cfg, sizeof (cfg), 1);
1651                 if (err != DDI_SUCCESS)
1652                         return (err);
1653         }
1654 
1655         /*
1656          * set the essid, may be null/hidden AP
1657          */
1658         IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
1659             "ipw2200_auth_and_assoc(): "
1660             "setting ESSID to(%u),%c%c%c%c%c%c%c%c\n",
1661             in->in_esslen,
1662             in->in_essid[0], in->in_essid[1],
1663             in->in_essid[2], in->in_essid[3],
1664             in->in_essid[4], in->in_essid[5],
1665             in->in_essid[6], in->in_essid[7]));
1666         err = ipw2200_cmd(sc, IPW2200_CMD_SET_ESSID, in->in_essid,
1667             in->in_esslen, 1);
1668         if (err != DDI_SUCCESS)
1669                 return (err);
1670 
1671         /*
1672          * set the rate: the rate set has already been ''negocitated''
1673          */
1674         rs.mode = IEEE80211_IS_CHAN_5GHZ(in->in_chan) ?
1675             IPW2200_MODE_11A : IPW2200_MODE_11G;
1676         rs.type = IPW2200_RATESET_TYPE_NEGOCIATED;
1677         rs.nrates = in->in_rates.ir_nrates;
1678         (void) memcpy(rs.rates, in->in_rates.ir_rates, in->in_rates.ir_nrates);
1679         IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
1680             "ipw2200_auth_and_assoc(): "
1681             "setting negotiated rates to(nrates = %u)\n", rs.nrates));
1682         err = ipw2200_cmd(sc, IPW2200_CMD_SET_RATES, &rs, sizeof (rs), 1);
1683         if (err != DDI_SUCCESS)
1684                 return (err);
1685 
1686         /*
1687          * invoke command associate
1688          */
1689         (void) memset(&assoc, 0, sizeof (assoc));
1690 
1691         /*
1692          * set opt_ie to h/w if associated is WPA, opt_ie has been verified
1693          * by net80211 kernel module.
1694          */
1695         if (ic->ic_opt_ie != NULL) {
1696 
1697                 wpa_level = (uint8_t *)ic->ic_opt_ie;
1698 
1699                 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
1700                     "ipw2200_auth_and_assoc(): "
1701                     "set wpa_ie and wpa_ie_len to h/w. "
1702                     "length is %d\n"
1703                     "opt_ie[0] = %02X - element vendor\n"
1704                     "opt_ie[1] = %02X - length\n"
1705                     "opt_ie[2,3,4] = %02X %02X %02X - oui\n"
1706                     "opt_ie[5] = %02X - oui type\n"
1707                     "opt_ie[6,7] = %02X %02X - spec version \n"
1708                     "opt_ie[8,9,10,11] = %02X %02X %02X %02X - gk cipher\n"
1709                     "opt_ie[12,13] = %02X %02X - pairwise key cipher(1)\n"
1710                     "opt_ie[14,15,16,17] = %02X %02X %02X %02X - ciphers\n"
1711                     "opt_ie[18,19] = %02X %02X - authselcont(1) \n"
1712                     "opt_ie[20,21,22,23] = %02X %02X %02X %02X - authsels\n",
1713                     wpa_level[1], wpa_level[0], wpa_level[1],
1714                     wpa_level[2], wpa_level[3], wpa_level[4],
1715                     wpa_level[5], wpa_level[6], wpa_level[7],
1716                     wpa_level[8], wpa_level[9], wpa_level[10],
1717                     wpa_level[11], wpa_level[12], wpa_level[13],
1718                     wpa_level[14], wpa_level[15], wpa_level[16],
1719                     wpa_level[17], wpa_level[18], wpa_level[19],
1720                     wpa_level[20], wpa_level[21], wpa_level[22],
1721                     wpa_level[23]));
1722 
1723                 err = ipw2200_cmd(sc, IPW2200_CMD_SET_OPTIE,
1724                     ic->ic_opt_ie, ic->ic_opt_ie_len, 1);
1725                 if (err != DDI_SUCCESS)
1726                         return (err);
1727         }
1728 
1729         /*
1730          * set the sensitive
1731          */
1732         data = LE_32(in->in_rssi);
1733         IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
1734             "ipw2200_auth_and_assoc(): "
1735             "setting sensitivity to rssi:(%u)\n", (uint8_t)in->in_rssi));
1736         err = ipw2200_cmd(sc, IPW2200_CMD_SET_SENSITIVITY,
1737             &data, sizeof (data), 1);
1738         if (err != DDI_SUCCESS)
1739                 return (err);
1740 
1741         /*
1742          * set mode and channel for assocation command
1743          */
1744         assoc.mode = IEEE80211_IS_CHAN_5GHZ(in->in_chan) ?
1745             IPW2200_MODE_11A : IPW2200_MODE_11G;
1746         assoc.chan = ieee80211_chan2ieee(ic, in->in_chan);
1747 
1748         /*
1749          * use the value set to ic_bss to retraive current sharedmode
1750          */
1751         if (ic->ic_bss->in_authmode == WL_SHAREDKEY) {
1752                 assoc.auth = (ic->ic_def_txkey << 4) | IPW2200_AUTH_SHARED;
1753                 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT,
1754                     "ipw2200_auth_and_assoc(): "
1755                     "associate to shared key mode, set thru. ioctl"));
1756         }
1757 
1758         if (ic->ic_flags & IEEE80211_F_WPA)
1759                 assoc.policy = LE_16(IPW2200_POLICY_WPA); /* RSN/WPA active */
1760         (void) memcpy(assoc.tstamp, in->in_tstamp.data, 8);
1761         assoc.capinfo = LE_16(in->in_capinfo);
1762         assoc.lintval = LE_16(ic->ic_lintval);
1763         assoc.intval  = LE_16(in->in_intval);
1764         IEEE80211_ADDR_COPY(assoc.bssid, in->in_bssid);
1765         if (ic->ic_opmode == IEEE80211_M_IBSS)
1766                 IEEE80211_ADDR_COPY(assoc.dst, ipw2200_broadcast_addr);
1767         else
1768                 IEEE80211_ADDR_COPY(assoc.dst, in->in_bssid);
1769 
1770         IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
1771             "ipw2200_auth_and_assoc(): "
1772             "associate to bssid(%2x:%2x:%2x:%2x:%2x:%2x:), "
1773             "chan(%u), auth(%u)\n",
1774             assoc.bssid[0], assoc.bssid[1], assoc.bssid[2],
1775             assoc.bssid[3], assoc.bssid[4], assoc.bssid[5],
1776             assoc.chan, assoc.auth));
1777         return (ipw2200_cmd(sc, IPW2200_CMD_ASSOCIATE,
1778             &assoc, sizeof (assoc), 1));
1779 }
1780 
1781 /*
1782  * Send the dis-association command to h/w, will receive notification to claim
1783  * the connection is dis-associated. So, it's not marked as disassociated this
1784  * moment.
1785  */
1786 static int
1787 ipw2200_disassoc(struct ipw2200_softc *sc)
1788 {
1789         struct ipw2200_associate assoc;
1790         assoc.type = 2;
1791         return (ipw2200_cmd(sc, IPW2200_CMD_ASSOCIATE, &assoc,
1792             sizeof (assoc), 1));
1793 }
1794 
1795 /* ARGSUSED */
1796 static int
1797 ipw2200_newstate(struct ieee80211com *ic, enum ieee80211_state state, int arg)
1798 {
1799         struct ipw2200_softc    *sc = (struct ipw2200_softc *)ic;
1800         wifi_data_t             wd = { 0 };
1801 
1802         switch (state) {
1803         case IEEE80211_S_SCAN:
1804                 if (!(sc->sc_flags & IPW2200_FLAG_SCANNING)) {
1805                         ic->ic_flags |= IEEE80211_F_SCAN | IEEE80211_F_ASCAN;
1806                         (void) ipw2200_start_scan(sc);
1807                 }
1808                 break;
1809         case IEEE80211_S_AUTH:
1810                 /*
1811                  * The firmware will fail if we are already associated
1812                  */
1813                 if (sc->sc_flags & IPW2200_FLAG_ASSOCIATED)
1814                         (void) ipw2200_disassoc(sc);
1815                 (void) ipw2200_auth_and_assoc(sc);
1816                 break;
1817         case IEEE80211_S_RUN:
1818                 /*
1819                  * We can send data now; update the fastpath with our
1820                  * current associated BSSID and other relevant settings.
1821                  */
1822                 wd.wd_secalloc = ieee80211_crypto_getciphertype(ic);
1823                 wd.wd_opmode = ic->ic_opmode;
1824                 IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
1825                 (void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd));
1826                 break;
1827         case IEEE80211_S_ASSOC:
1828         case IEEE80211_S_INIT:
1829                 break;
1830         }
1831 
1832         /*
1833          * notify to update the link, and WPA
1834          */
1835         if ((ic->ic_state != IEEE80211_S_RUN) && (state == IEEE80211_S_RUN)) {
1836                 ieee80211_notify_node_join(ic, ic->ic_bss);
1837         } else if ((ic->ic_state == IEEE80211_S_RUN) &&
1838             (state != IEEE80211_S_RUN)) {
1839                 ieee80211_notify_node_leave(ic, ic->ic_bss);
1840         }
1841 
1842         IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
1843             "ipw2200_newstat(): %s -> %s\n",
1844             ieee80211_state_name[ic->ic_state],
1845             ieee80211_state_name[state]));
1846 
1847         ic->ic_state = state;
1848         return (DDI_SUCCESS);
1849 }
1850 /*
1851  * GLD operations
1852  */
1853 /* ARGSUSED */
1854 static int
1855 ipw2200_m_stat(void *arg, uint_t stat, uint64_t *val)
1856 {
1857         ieee80211com_t          *ic = (ieee80211com_t *)arg;
1858         struct ipw2200_softc    *sc = (struct ipw2200_softc *)ic;
1859 
1860         IPW2200_DBG(IPW2200_DBG_GLD, (((struct ipw2200_softc *)arg)->sc_dip,
1861             CE_CONT,
1862             "ipw2200_m_stat(): enter\n"));
1863         /*
1864          * Some of below statistic data are from hardware, some from net80211
1865          */
1866         switch (stat) {
1867         case MAC_STAT_NOXMTBUF:
1868                 *val = ic->ic_stats.is_tx_nobuf;
1869                 break;
1870         case MAC_STAT_IERRORS:
1871                 *val = sc->sc_stats.sc_rx_len_err;
1872                 break;
1873         case MAC_STAT_OERRORS:
1874                 *val = sc->sc_stats.sc_tx_discard +
1875                     sc->sc_stats.sc_tx_alloc_fail +
1876                     sc->sc_stats.sc_tx_encap_fail +
1877                     sc->sc_stats.sc_tx_crypto_fail;
1878                 break;
1879         case MAC_STAT_RBYTES:
1880                 *val = ic->ic_stats.is_rx_bytes;
1881                 break;
1882         case MAC_STAT_IPACKETS:
1883                 *val = ic->ic_stats.is_rx_frags;
1884                 break;
1885         case MAC_STAT_OBYTES:
1886                 *val = ic->ic_stats.is_tx_bytes;
1887                 break;
1888         case MAC_STAT_OPACKETS:
1889                 *val = ic->ic_stats.is_tx_frags;
1890                 break;
1891         /*
1892          * Get below from hardware statistic, retraive net80211 value once 1s
1893          */
1894         case WIFI_STAT_TX_FRAGS:
1895         case WIFI_STAT_MCAST_TX:
1896         case WIFI_STAT_TX_FAILED:
1897         case WIFI_STAT_TX_RETRANS:
1898         /*
1899          * Get blow information from net80211
1900          */
1901         case WIFI_STAT_RTS_SUCCESS:
1902         case WIFI_STAT_RTS_FAILURE:
1903         case WIFI_STAT_ACK_FAILURE:
1904         case WIFI_STAT_RX_FRAGS:
1905         case WIFI_STAT_MCAST_RX:
1906         case WIFI_STAT_RX_DUPS:
1907         case WIFI_STAT_FCS_ERRORS:
1908         case WIFI_STAT_WEP_ERRORS:
1909                 return (ieee80211_stat(ic, stat, val));
1910         /*
1911          * Need be supported later
1912          */
1913         case MAC_STAT_IFSPEED:
1914         default:
1915                 return (ENOTSUP);
1916         }
1917         return (0);
1918 }
1919 
1920 /* ARGSUSED */
1921 static int
1922 ipw2200_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
1923 {
1924         /* not supported */
1925         IPW2200_DBG(IPW2200_DBG_GLD, (((struct ipw2200_softc *)arg)->sc_dip,
1926             CE_CONT,
1927             "ipw2200_m_multicst(): enter\n"));
1928 
1929         return (0);
1930 }
1931 
1932 /*
1933  * Multithread handler for linkstatus, fatal error recovery, get statistic
1934  */
1935 static void
1936 ipw2200_thread(struct ipw2200_softc *sc)
1937 {
1938         struct ieee80211com     *ic = &sc->sc_ic;
1939         enum ieee80211_state    ostate;
1940         int32_t                 nlstate;
1941         int                     stat_cnt = 0;
1942 
1943         IPW2200_DBG(IPW2200_DBG_SOFTINT, (sc->sc_dip, CE_CONT,
1944             "ipw2200_thread(): enter, linkstate %d\n", sc->sc_linkstate));
1945 
1946         mutex_enter(&sc->sc_mflock);
1947 
1948         while (sc->sc_mfthread_switch) {
1949                 /*
1950                  * when radio is off or SUSPEND status, nothing to do
1951                  */
1952                 if ((ipw2200_radio_status(sc) == 0) ||
1953                     sc->sc_flags & IPW2200_FLAG_SUSPEND) {
1954                         goto wait_loop;
1955                 }
1956 
1957                 /*
1958                  * notify the link state
1959                  */
1960                 if (ic->ic_mach && (sc->sc_flags & IPW2200_FLAG_LINK_CHANGE)) {
1961 
1962                         IPW2200_DBG(IPW2200_DBG_SOFTINT, (sc->sc_dip, CE_CONT,
1963                             "ipw2200_thread(): link status --> %d\n",
1964                             sc->sc_linkstate));
1965 
1966                         sc->sc_flags &= ~IPW2200_FLAG_LINK_CHANGE;
1967                         nlstate = sc->sc_linkstate;
1968 
1969                         mutex_exit(&sc->sc_mflock);
1970                         mac_link_update(ic->ic_mach, nlstate);
1971                         mutex_enter(&sc->sc_mflock);
1972                 }
1973 
1974                 /*
1975                  * recovery fatal error
1976                  */
1977                 if (ic->ic_mach &&
1978                     (sc->sc_flags & IPW2200_FLAG_HW_ERR_RECOVER)) {
1979 
1980                         IPW2200_DBG(IPW2200_DBG_FATAL, (sc->sc_dip, CE_CONT,
1981                             "ipw2200_thread(): "
1982                             "try to recover fatal hw error\n"));
1983 
1984                         sc->sc_flags &= ~IPW2200_FLAG_HW_ERR_RECOVER;
1985                         mutex_exit(&sc->sc_mflock);
1986 
1987                         /* stop again */
1988                         ostate = ic->ic_state;
1989                         (void) ipw2200_init(sc); /* Force state machine */
1990 
1991                         /*
1992                          * workround. Delay for a while after init especially
1993                          * when something wrong happened already.
1994                          */
1995                         delay(drv_usectohz(delay_fatal_recover));
1996 
1997                         /*
1998                          * Init scan will recovery the original connection if
1999                          * the original state is run
2000                          */
2001                         if (ostate != IEEE80211_S_INIT)
2002                                 ieee80211_begin_scan(ic, 0);
2003 
2004                         mutex_enter(&sc->sc_mflock);
2005                 }
2006 
2007                 /*
2008                  * get statistic, the value will be retrieved by m_stat
2009                  */
2010                 if (stat_cnt == 10) {
2011 
2012                         stat_cnt = 0; /* re-start */
2013                         mutex_exit(&sc->sc_mflock);
2014                         ipw2200_get_statistics(sc);
2015                         mutex_enter(&sc->sc_mflock);
2016 
2017                 } else
2018                         stat_cnt++; /* until 1s */
2019 
2020 wait_loop:
2021                 mutex_exit(&sc->sc_mflock);
2022                 delay(drv_usectohz(delay_aux_thread));
2023                 mutex_enter(&sc->sc_mflock);
2024 
2025         }
2026         sc->sc_mf_thread = NULL;
2027         cv_signal(&sc->sc_mfthread_cv);
2028         mutex_exit(&sc->sc_mflock);
2029 }
2030 
2031 static int
2032 ipw2200_m_start(void *arg)
2033 {
2034         struct ipw2200_softc    *sc = (struct ipw2200_softc *)arg;
2035         struct ieee80211com     *ic = &sc->sc_ic;
2036 
2037         IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT,
2038             "ipw2200_m_start(): enter\n"));
2039         /*
2040          * initialize ipw2200 hardware, everything ok will start scan
2041          */
2042         (void) ipw2200_init(sc);
2043 
2044         /*
2045          * set the state machine to INIT
2046          */
2047         ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
2048 
2049         sc->sc_flags |= IPW2200_FLAG_RUNNING;
2050 
2051         /*
2052          * fix KCF bug. - workaround, need to fix it in net80211
2053          */
2054         (void) crypto_mech2id(SUN_CKM_RC4);
2055 
2056         return (0);
2057 }
2058 
2059 static void
2060 ipw2200_m_stop(void *arg)
2061 {
2062         struct ipw2200_softc    *sc = (struct ipw2200_softc *)arg;
2063         struct ieee80211com     *ic = &sc->sc_ic;
2064 
2065         IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT,
2066             "ipw2200_m_stop(): enter\n"));
2067 
2068         ipw2200_stop(sc);
2069         /*
2070          * set the state machine to INIT
2071          */
2072         ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
2073 
2074         sc->sc_flags &= ~IPW2200_FLAG_RUNNING;
2075 }
2076 
2077 static int
2078 ipw2200_m_unicst(void *arg, const uint8_t *macaddr)
2079 {
2080         struct ipw2200_softc    *sc = (struct ipw2200_softc *)arg;
2081         struct ieee80211com     *ic = &sc->sc_ic;
2082         int                     err;
2083 
2084         IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT,
2085             "ipw2200_m_unicst(): enter\n"));
2086 
2087         IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT,
2088             "ipw2200_m_unicst(): GLD setting MAC address to "
2089             "%02x:%02x:%02x:%02x:%02x:%02x\n",
2090             macaddr[0], macaddr[1], macaddr[2],
2091             macaddr[3], macaddr[4], macaddr[5]));
2092 
2093         if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) {
2094 
2095                 IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr);
2096 
2097                 if (sc->sc_flags & IPW2200_FLAG_RUNNING) {
2098                         err = ipw2200_config(sc);
2099                         if (err != DDI_SUCCESS) {
2100                                 IPW2200_WARN((sc->sc_dip, CE_WARN,
2101                                     "ipw2200_m_unicst(): "
2102                                     "device configuration failed\n"));
2103                                 goto fail;
2104                         }
2105                 }
2106         }
2107         return (0);
2108 fail:
2109         return (EIO);
2110 }
2111 
2112 static int
2113 ipw2200_m_promisc(void *arg, boolean_t on)
2114 {
2115         /* not supported */
2116         struct ipw2200_softc    *sc = (struct ipw2200_softc *)arg;
2117 
2118         IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT,
2119             "ipw2200_m_promisc(): enter. "
2120             "GLD setting promiscuous mode - %d\n", on));
2121 
2122         return (0);
2123 }
2124 
2125 static mblk_t *
2126 ipw2200_m_tx(void *arg, mblk_t *mp)
2127 {
2128         struct ipw2200_softc    *sc = (struct ipw2200_softc *)arg;
2129         struct ieee80211com     *ic = &sc->sc_ic;
2130         mblk_t                  *next;
2131 
2132         /*
2133          * when driver in on suspend state, freemsgchain directly
2134          */
2135         if (sc->sc_flags & IPW2200_FLAG_SUSPEND) {
2136                 IPW2200_DBG(IPW2200_DBG_SUSPEND, (sc->sc_dip, CE_CONT,
2137                     "ipw2200_m_tx(): suspend status, discard msg\n"));
2138                 sc->sc_stats.sc_tx_discard++; /* discard data */
2139                 freemsgchain(mp);
2140                 return (NULL);
2141         }
2142 
2143         /*
2144          * No data frames go out unless we're associated; this
2145          * should not happen as the 802.11 layer does not enable
2146          * the xmit queue until we enter the RUN state.
2147          */
2148         if (ic->ic_state != IEEE80211_S_RUN) {
2149                 IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT,
2150                     "ipw2200_m_tx(): discard msg, ic_state = %u\n",
2151                     ic->ic_state));
2152                 sc->sc_stats.sc_tx_discard++; /* discard data */
2153                 freemsgchain(mp);
2154                 return (NULL);
2155         }
2156 
2157         while (mp != NULL) {
2158                 next = mp->b_next;
2159                 mp->b_next = NULL;
2160                 if (ipw2200_send(ic, mp, IEEE80211_FC0_TYPE_DATA) ==
2161                     ENOMEM) {
2162                         mp->b_next = next;
2163                         break;
2164                 }
2165                 mp = next;
2166         }
2167         return (mp);
2168 }
2169 
2170 /*
2171  * ipw2200_send(): send data. softway to handle crypto_encap.
2172  */
2173 static int
2174 ipw2200_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
2175 {
2176         struct ipw2200_softc    *sc = (struct ipw2200_softc *)ic;
2177         struct ieee80211_node   *in;
2178         struct ieee80211_frame  *wh;
2179         struct ieee80211_key    *k;
2180         mblk_t                  *m0, *m;
2181         size_t                  cnt, off;
2182         struct ipw2200_tx_desc  *txdsc;
2183         struct dma_region       *dr;
2184         uint32_t                idx;
2185         int                     err = DDI_SUCCESS;
2186         /* tmp pointer, used to pack header and payload */
2187         uint8_t                 *p;
2188 
2189         ASSERT(mp->b_next == NULL);
2190         IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT,
2191             "ipw2200_send(): enter\n"));
2192 
2193         if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA) {
2194                 /*
2195                  * skip all management frames since ipw2200 won't generate any
2196                  * management frames. Therefore, drop this package.
2197                  */
2198                 freemsg(mp);
2199                 err = DDI_FAILURE;
2200                 goto fail0;
2201         }
2202 
2203         mutex_enter(&sc->sc_tx_lock);
2204         if (sc->sc_flags & IPW2200_FLAG_SUSPEND) {
2205                 /*
2206                  * when sending data, system runs into suspend status,
2207                  * return fail directly
2208                  */
2209                 err = ENXIO;
2210                 goto fail0;
2211         }
2212 
2213         /*
2214          * need 1 empty descriptor
2215          */
2216         if (sc->sc_tx_free <= IPW2200_TX_RING_MIN) {
2217                 mutex_enter(&sc->sc_resched_lock);
2218                 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_WARN,
2219                     "ipw2200_send(): no enough descriptors(%d)\n",
2220                     sc->sc_tx_free));
2221                 ic->ic_stats.is_tx_nobuf++; /* no enough buffer */
2222                 sc->sc_flags |= IPW2200_FLAG_TX_SCHED;
2223                 err = ENOMEM;
2224                 mutex_exit(&sc->sc_resched_lock);
2225                 goto fail1;
2226         }
2227         IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT,
2228             "ipw2200_send():  tx-free=%d,tx-curr=%d\n",
2229             sc->sc_tx_free, sc->sc_tx_cur));
2230 
2231         /*
2232          * put the mp into one blk, and use it to do the crypto_encap
2233          * if necessaary.
2234          */
2235         m = allocb(msgdsize(mp) + 32, BPRI_MED);
2236         if (m == NULL) { /* can not alloc buf, drop this package */
2237                 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
2238                     "ipw2200_send(): msg allocation failed\n"));
2239                 freemsg(mp);
2240                 sc->sc_stats.sc_tx_alloc_fail++; /* alloc fail */
2241                 ic->ic_stats.is_tx_failed++;  /* trans failed */
2242                 err = DDI_FAILURE;
2243                 goto fail1;
2244         }
2245         for (off = 0, m0 = mp; m0 != NULL; m0 = m0->b_cont) {
2246                 cnt = MBLKL(m0);
2247                 (void) memcpy(m->b_rptr + off, m0->b_rptr, cnt);
2248                 off += cnt;
2249         }
2250         m->b_wptr += off;
2251 
2252         /*
2253          * find tx_node, and encapsulate the data
2254          */
2255         wh = (struct ieee80211_frame *)m->b_rptr;
2256         in = ieee80211_find_txnode(ic, wh->i_addr1);
2257         if (in == NULL) { /* can not find the tx node, drop the package */
2258                 sc->sc_stats.sc_tx_encap_fail++; /* tx encap fail */
2259                 ic->ic_stats.is_tx_failed++; /* trans failed */
2260                 freemsg(mp);
2261                 err = DDI_FAILURE;
2262                 goto fail2;
2263         }
2264         in->in_inact = 0;
2265 
2266         (void) ieee80211_encap(ic, m, in);
2267         ieee80211_free_node(in);
2268 
2269         if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
2270                 k = ieee80211_crypto_encap(ic, m);
2271                 if (k == NULL) { /* can not get the key, drop packages */
2272                         IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
2273                             "ipw2200_send(): "
2274                             "Encrypting 802.11 frame failed\n"));
2275                         sc->sc_stats.sc_tx_crypto_fail++; /* tx encap fail */
2276                         ic->ic_stats.is_tx_failed++; /* trans failed */
2277                         freemsg(mp);
2278                         err = DDI_FAILURE;
2279                         goto fail2;
2280                 }
2281                 wh = (struct ieee80211_frame *)m->b_rptr;
2282         }
2283 
2284         /*
2285          * get txdsc
2286          */
2287         idx     = sc->sc_tx_cur;
2288         txdsc   = &sc->sc_txdsc[idx];
2289         (void) memset(txdsc, 0, sizeof (*txdsc));
2290         /*
2291          * extract header from message
2292          */
2293         p       = (uint8_t *)&txdsc->wh;
2294         off     = sizeof (struct ieee80211_frame);
2295         (void) memcpy(p, m->b_rptr, off);
2296         /*
2297          * extract payload from message
2298          */
2299         dr      = &sc->sc_dma_txbufs[idx];
2300         p       = sc->sc_txbufs[idx];
2301         cnt     = MBLKL(m);
2302         (void) memcpy(p, m->b_rptr + off, cnt - off);
2303         cnt    -= off;
2304 
2305         txdsc->hdr.type   = IPW2200_HDR_TYPE_DATA;
2306         txdsc->hdr.flags  = IPW2200_HDR_FLAG_IRQ;
2307         txdsc->cmd     = IPW2200_DATA_CMD_TX;
2308         txdsc->len     = LE_16(cnt);
2309         txdsc->flags   = 0;
2310 
2311         if (ic->ic_opmode == IEEE80211_M_IBSS) {
2312                 if (!IEEE80211_IS_MULTICAST(wh->i_addr1))
2313                         txdsc->flags |= IPW2200_DATA_FLAG_NEED_ACK;
2314         } else if (!IEEE80211_IS_MULTICAST(wh->i_addr3))
2315                 txdsc->flags |= IPW2200_DATA_FLAG_NEED_ACK;
2316 
2317         /* always set it to none wep, because it's handled by software */
2318         txdsc->flags |= IPW2200_DATA_FLAG_NO_WEP;
2319 
2320         if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
2321                 txdsc->flags |= IPW2200_DATA_FLAG_SHPREAMBLE;
2322 
2323         txdsc->nseg      = LE_32(1);
2324         txdsc->seg_addr[0]  = LE_32(dr->dr_pbase);
2325         txdsc->seg_len[0]   = LE_32(cnt);
2326 
2327         /*
2328          * DMA sync: buffer and desc
2329          */
2330         (void) ddi_dma_sync(dr->dr_hnd, 0,
2331             IPW2200_TXBUF_SIZE, DDI_DMA_SYNC_FORDEV);
2332         (void) ddi_dma_sync(sc->sc_dma_txdsc.dr_hnd,
2333             idx * sizeof (struct ipw2200_tx_desc),
2334             sizeof (struct ipw2200_tx_desc), DDI_DMA_SYNC_FORDEV);
2335 
2336         sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2200_TX_RING_SIZE);
2337         sc->sc_tx_free--;
2338 
2339         /*
2340          * update txcur
2341          */
2342         ipw2200_csr_put32(sc, IPW2200_CSR_TX1_WRITE_INDEX, sc->sc_tx_cur);
2343 
2344         /*
2345          * success, free the original message
2346          */
2347         if (mp)
2348                 freemsg(mp);
2349 fail2:
2350         if (m)
2351                 freemsg(m);
2352 fail1:
2353         mutex_exit(&sc->sc_tx_lock);
2354 fail0:
2355         IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT,
2356             "ipw2200_send(): exit - err=%d\n", err));
2357 
2358         return (err);
2359 }
2360 
2361 /*
2362  * IOCTL handlers
2363  */
2364 #define IEEE80211_IOCTL_REQUIRED        (1)
2365 #define IEEE80211_IOCTL_NOT_REQUIRED    (0)
2366 static void
2367 ipw2200_m_ioctl(void *arg, queue_t *q, mblk_t *m)
2368 {
2369         struct ipw2200_softc    *sc = (struct ipw2200_softc *)arg;
2370         struct ieee80211com     *ic = &sc->sc_ic;
2371         uint32_t                err;
2372 
2373         IPW2200_DBG(IPW2200_DBG_GLD, (sc->sc_dip, CE_CONT,
2374             "ipw2200_m_ioctl(): enter\n"));
2375 
2376         /*
2377          * Check whether or not need to handle this in net80211
2378          *
2379          */
2380         if (ipw2200_ioctl(sc, q, m) == IEEE80211_IOCTL_NOT_REQUIRED)
2381                 return;
2382 
2383         err = ieee80211_ioctl(ic, q, m);
2384         if (err == ENETRESET) {
2385                 if (sc->sc_flags & IPW2200_FLAG_RUNNING) {
2386                         (void) ipw2200_m_start(sc);
2387                         (void) ieee80211_new_state(ic,
2388                             IEEE80211_S_SCAN, -1);
2389                 }
2390         }
2391         if (err == ERESTART) {
2392                 if (sc->sc_flags & IPW2200_FLAG_RUNNING)
2393                         (void) ipw2200_chip_reset(sc);
2394         }
2395 }
2396 static int
2397 ipw2200_ioctl(struct ipw2200_softc *sc, queue_t *q, mblk_t *m)
2398 {
2399         struct iocblk   *iocp;
2400         uint32_t        len, ret, cmd, mblen;
2401         mblk_t          *m0;
2402         boolean_t       need_privilege;
2403         boolean_t       need_net80211;
2404 
2405         mblen = MBLKL(m);
2406         if (mblen < sizeof (struct iocblk)) {
2407                 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT,
2408                     "ipw2200_ioctl(): ioctl buffer too short, %u\n",
2409                     mblen));
2410                 miocnak(q, m, 0, EINVAL);
2411                 /*
2412                  * Buf not enough, do not need net80211 either
2413                  */
2414                 return (IEEE80211_IOCTL_NOT_REQUIRED);
2415         }
2416 
2417         /*
2418          * Validate the command
2419          */
2420         iocp = (struct iocblk *)(uintptr_t)m->b_rptr;
2421         iocp->ioc_error = 0;
2422         cmd = iocp->ioc_cmd;
2423         need_privilege = B_TRUE;
2424         switch (cmd) {
2425         case WLAN_SET_PARAM:
2426         case WLAN_COMMAND:
2427                 break;
2428         case WLAN_GET_PARAM:
2429                 need_privilege = B_FALSE;
2430                 break;
2431         default:
2432                 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT,
2433                     "ipw2200_ioctl(): unknown cmd 0x%x", cmd));
2434                 miocnak(q, m, 0, EINVAL);
2435                 /*
2436                  * Unknown cmd, do not need net80211 either
2437                  */
2438                 return (IEEE80211_IOCTL_NOT_REQUIRED);
2439         }
2440 
2441         if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0) {
2442                 miocnak(q, m, 0, ret);
2443                 /*
2444                  * privilege check fail, do not need net80211 either
2445                  */
2446                 return (IEEE80211_IOCTL_NOT_REQUIRED);
2447         }
2448 
2449         /*
2450          * sanity check
2451          */
2452         m0 = m->b_cont;
2453         if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) ||
2454             m0 == NULL) {
2455                 miocnak(q, m, 0, EINVAL);
2456                 /*
2457                  * invalid format, do not need net80211 either
2458                  */
2459                 return (IEEE80211_IOCTL_NOT_REQUIRED);
2460         }
2461         /*
2462          * assuming single data block
2463          */
2464         if (m0->b_cont) {
2465                 freemsg(m0->b_cont);
2466                 m0->b_cont = NULL;
2467         }
2468 
2469         need_net80211 = B_FALSE;
2470         ret = ipw2200_getset(sc, m0, cmd, &need_net80211);
2471         if (!need_net80211) {
2472                 len = msgdsize(m0);
2473 
2474                 IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT,
2475                     "ipw2200_ioctl(): go to call miocack with "
2476                     "ret = %d, len = %d\n", ret, len));
2477                 miocack(q, m, len, ret);
2478                 return (IEEE80211_IOCTL_NOT_REQUIRED);
2479         }
2480 
2481         /*
2482          * IEEE80211_IOCTL - need net80211 handle
2483          */
2484         return (IEEE80211_IOCTL_REQUIRED);
2485 }
2486 
2487 static int
2488 ipw2200_getset(struct ipw2200_softc *sc, mblk_t *m, uint32_t cmd,
2489         boolean_t *need_net80211)
2490 {
2491         wldp_t          *infp, *outfp;
2492         uint32_t        id;
2493         int             ret;
2494 
2495         infp  = (wldp_t *)(uintptr_t)m->b_rptr;
2496         outfp = (wldp_t *)(uintptr_t)m->b_rptr;
2497         outfp->wldp_result = WL_NOTSUPPORTED;
2498 
2499         id = infp->wldp_id;
2500         IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT,
2501             "ipw2200_getset(): id = 0x%x\n", id));
2502         switch (id) {
2503         case WL_RADIO: /* which is not supported by net80211 */
2504                 ret = iwi_wificfg_radio(sc, cmd, outfp);
2505                 break;
2506         case WL_DESIRED_RATES: /* hardware doesn't support fix-rates */
2507                 ret = iwi_wificfg_desrates(outfp);
2508                 break;
2509         default:
2510                 /*
2511                  * The wifi IOCTL net80211 supported:
2512                  *      case WL_ESSID:
2513                  *      case WL_BSSID:
2514                  *      case WL_WEP_KEY_TAB:
2515                  *      case WL_WEP_KEY_ID:
2516                  *      case WL_AUTH_MODE:
2517                  *      case WL_ENCRYPTION:
2518                  *      case WL_BSS_TYPE:
2519                  *      case WL_ESS_LIST:
2520                  *      case WL_LINKSTATUS:
2521                  *      case WL_RSSI:
2522                  *      case WL_SCAN:
2523                  *      case WL_LOAD_DEFAULTS:
2524                  *      case WL_DISASSOCIATE:
2525                  */
2526 
2527                 /*
2528                  * When radio is off, need to ignore all ioctl.  What need to
2529                  * do is to check radio status firstly.  If radio is ON, pass
2530                  * it to net80211, otherwise, return to upper layer directly.
2531                  *
2532                  * Considering the WL_SUCCESS also means WL_CONNECTED for
2533                  * checking linkstatus, one exception for WL_LINKSTATUS is to
2534                  * let net80211 handle it.
2535                  */
2536                 if ((ipw2200_radio_status(sc) == 0) &&
2537                     (id != WL_LINKSTATUS)) {
2538 
2539                         IPW2200_REPORT((sc->sc_dip, CE_CONT,
2540                             "iwi: radio is OFF\n"));
2541 
2542                         outfp->wldp_length = WIFI_BUF_OFFSET;
2543                         outfp->wldp_result = WL_SUCCESS;
2544                         ret = 0;
2545                         break;
2546                 }
2547 
2548                 *need_net80211 = B_TRUE; /* let net80211 do the rest */
2549                 return (0);
2550         }
2551         /*
2552          * we will overwrite everything
2553          */
2554         m->b_wptr = m->b_rptr + outfp->wldp_length;
2555         return (ret);
2556 }
2557 
2558 /*
2559  * Call back functions for get/set proporty
2560  */
2561 static int
2562 ipw2200_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2563     uint_t wldp_length, void *wldp_buf)
2564 {
2565         struct ipw2200_softc    *sc = (struct ipw2200_softc *)arg;
2566         struct ieee80211com     *ic = &sc->sc_ic;
2567         int                     err = 0;
2568 
2569         switch (wldp_pr_num) {
2570         /* mac_prop_id */
2571         case MAC_PROP_WL_DESIRED_RATES:
2572                 IPW2200_DBG(IPW2200_DBG_BRUSSELS, (sc->sc_dip, CE_CONT,
2573                     "ipw2200_m_getprop(): Not Support DESIRED_RATES\n"));
2574                 break;
2575         case MAC_PROP_WL_RADIO:
2576                 *(wl_linkstatus_t *)wldp_buf = ipw2200_radio_status(sc);
2577                 break;
2578         default:
2579                 /* go through net80211 */
2580                 err = ieee80211_getprop(ic, pr_name, wldp_pr_num,
2581                     wldp_length, wldp_buf);
2582                 break;
2583         }
2584 
2585         return (err);
2586 }
2587 
2588 static void
2589 ipw2200_m_propinfo(void *arg, const char *pr_name,
2590     mac_prop_id_t wlpd_pr_num, mac_prop_info_handle_t mph)
2591 {
2592         struct ipw2200_softc    *sc = (struct ipw2200_softc *)arg;
2593         struct ieee80211com     *ic = &sc->sc_ic;
2594 
2595         ieee80211_propinfo(ic, pr_name, wlpd_pr_num, mph);
2596 }
2597 
2598 static int
2599 ipw2200_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
2600     uint_t wldp_length, const void *wldp_buf)
2601 {
2602         struct ipw2200_softc    *sc = (struct ipw2200_softc *)arg;
2603         struct ieee80211com     *ic = &sc->sc_ic;
2604         int                     err;
2605 
2606         switch (wldp_pr_num) {
2607         /* mac_prop_id */
2608         case MAC_PROP_WL_DESIRED_RATES:
2609                 IPW2200_DBG(IPW2200_DBG_BRUSSELS, (sc->sc_dip, CE_CONT,
2610                     "ipw2200_m_setprop(): Not Support DESIRED_RATES\n"));
2611                 err = ENOTSUP;
2612                 break;
2613         case MAC_PROP_WL_RADIO:
2614                 IPW2200_DBG(IPW2200_DBG_BRUSSELS, (sc->sc_dip, CE_CONT,
2615                     "ipw2200_m_setprop(): Not Support RADIO\n"));
2616                 err = ENOTSUP;
2617                 break;
2618         default:
2619                 /* go through net80211 */
2620                 err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length,
2621                     wldp_buf);
2622                 break;
2623         }
2624 
2625         if (err == ENETRESET) {
2626                 if (sc->sc_flags & IPW2200_FLAG_RUNNING) {
2627                         (void) ipw2200_m_start(sc);
2628                         (void) ieee80211_new_state(ic,
2629                             IEEE80211_S_SCAN, -1);
2630                 }
2631                 err = 0;
2632         }
2633 
2634         return (err);
2635 }
2636 
2637 static int
2638 iwi_wificfg_radio(struct ipw2200_softc *sc, uint32_t cmd, wldp_t *outfp)
2639 {
2640         uint32_t        ret = ENOTSUP;
2641 
2642         switch (cmd) {
2643         case WLAN_GET_PARAM:
2644                 *(wl_linkstatus_t *)(outfp->wldp_buf) =
2645                     ipw2200_radio_status(sc);
2646                 outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t);
2647                 outfp->wldp_result = WL_SUCCESS;
2648                 ret = 0; /* command success */
2649                 break;
2650         case WLAN_SET_PARAM:
2651         default:
2652                 break;
2653         }
2654         return (ret);
2655 }
2656 
2657 static int
2658 iwi_wificfg_desrates(wldp_t *outfp)
2659 {
2660         /* return success, but with result NOTSUPPORTED */
2661         outfp->wldp_length = WIFI_BUF_OFFSET;
2662         outfp->wldp_result = WL_NOTSUPPORTED;
2663         return (0);
2664 }
2665 /* End of IOCTL Handlers */
2666 
2667 void
2668 ipw2200_fix_channel(struct ieee80211com *ic, mblk_t *m)
2669 {
2670         struct ieee80211_frame  *wh;
2671         uint8_t                 subtype;
2672         uint8_t                 *frm, *efrm;
2673 
2674         wh = (struct ieee80211_frame *)m->b_rptr;
2675 
2676         if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT)
2677                 return;
2678 
2679         subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
2680 
2681         if (subtype != IEEE80211_FC0_SUBTYPE_BEACON &&
2682             subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP)
2683                 return;
2684 
2685         /*
2686          * assume the message contains only 1 block
2687          */
2688         frm   = (uint8_t *)(wh + 1);
2689         efrm  = (uint8_t *)m->b_wptr;
2690         frm  += 12;  /* skip tstamp, bintval and capinfo fields */
2691         while (frm < efrm) {
2692                 if (*frm == IEEE80211_ELEMID_DSPARMS)
2693 #if IEEE80211_CHAN_MAX < 255
2694                 if (frm[2] <= IEEE80211_CHAN_MAX)
2695 #endif
2696                         ic->ic_curchan = &ic->ic_sup_channels[frm[2]];
2697                 frm += frm[1] + 2;
2698         }
2699 }
2700 
2701 static void
2702 ipw2200_rcv_frame(struct ipw2200_softc *sc, struct ipw2200_frame *frame)
2703 {
2704         struct ieee80211com     *ic = &sc->sc_ic;
2705         uint8_t                 *data = (uint8_t *)frame;
2706         uint32_t                len;
2707         struct ieee80211_frame  *wh;
2708         struct ieee80211_node   *in;
2709         mblk_t                  *m;
2710 
2711         len = LE_16(frame->len);
2712         if ((len < sizeof (struct ieee80211_frame_min)) ||
2713             (len > IPW2200_RXBUF_SIZE)) {
2714                 IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT,
2715                     "ipw2200_rcv_frame(): bad frame length=%u\n",
2716                     LE_16(frame->len)));
2717                 sc->sc_stats.sc_rx_len_err++; /* length doesn't work */
2718                 return;
2719         }
2720         IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT,
2721             "ipw2200_rcv_frame(): chan = %d, length = %d\n", frame->chan, len));
2722 
2723         /*
2724          * Skip the frame header, get the real data from the input
2725          */
2726         data += sizeof (struct ipw2200_frame);
2727 
2728         m = allocb(len, BPRI_MED);
2729         if (m) {
2730                 (void) memcpy(m->b_wptr, data, len);
2731                 m->b_wptr += len;
2732 
2733                 if (ic->ic_state == IEEE80211_S_SCAN) {
2734                         ic->ic_ibss_chan = &ic->ic_sup_channels[frame->chan];
2735                         ipw2200_fix_channel(ic, m);
2736                 }
2737                 wh = (struct ieee80211_frame *)m->b_rptr;
2738 
2739                 in = ieee80211_find_rxnode(ic, wh);
2740 
2741                 IPW2200_DBG(IPW2200_DBG_RX, (sc->sc_dip, CE_CONT,
2742                     "ipw2200_rcv_frame(): "
2743                     "type = %x, subtype = %x, i_fc[1] = %x, "
2744                     "ni_esslen:%d, ni_essid[0-5]:%c%c%c%c%c%c\n",
2745                     wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK,
2746                     wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK,
2747                     wh->i_fc[1] & IEEE80211_FC1_WEP,
2748                     in->in_esslen,
2749                     in->in_essid[0], in->in_essid[1], in->in_essid[2],
2750                     in->in_essid[3], in->in_essid[4], in->in_essid[5]));
2751 
2752                 (void) ieee80211_input(ic, m, in, frame->rssi_dbm, 0);
2753 
2754                 ieee80211_free_node(in);
2755         }
2756         else
2757                 IPW2200_WARN((sc->sc_dip, CE_WARN,
2758                     "ipw2200_rcv_frame(): "
2759                     "cannot allocate receive message(%u)\n",
2760                     LE_16(frame->len)));
2761 }
2762 
2763 static void
2764 ipw2200_rcv_notif(struct ipw2200_softc *sc, struct ipw2200_notif *notif)
2765 {
2766         struct ieee80211com                     *ic = &sc->sc_ic;
2767         struct ipw2200_notif_association        *assoc;
2768         struct ipw2200_notif_authentication     *auth;
2769         uint8_t                                 *ndata = (uint8_t *)notif;
2770 
2771         IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT,
2772             "ipw2200_rcv_notif(): type=%u\n", notif->type));
2773 
2774         ndata += sizeof (struct ipw2200_notif);
2775         switch (notif->type) {
2776         case IPW2200_NOTIF_TYPE_ASSOCIATION:
2777                 assoc = (struct ipw2200_notif_association *)ndata;
2778 
2779                 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
2780                     "ipw2200_rcv_notif(): association=%u,%u\n",
2781                     assoc->state, assoc->status));
2782 
2783                 switch (assoc->state) {
2784                 case IPW2200_ASSOC_SUCCESS:
2785                         sc->sc_flags |= IPW2200_FLAG_ASSOCIATED;
2786                         ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
2787                         break;
2788                 case IPW2200_ASSOC_FAIL:
2789                         sc->sc_flags &= ~IPW2200_FLAG_ASSOCIATED;
2790                         ieee80211_begin_scan(ic, 1);
2791                         break;
2792                 default:
2793                         break;
2794                 }
2795                 break;
2796 
2797         case IPW2200_NOTIF_TYPE_AUTHENTICATION:
2798                 auth = (struct ipw2200_notif_authentication *)ndata;
2799 
2800                 IPW2200_DBG(IPW2200_DBG_WIFI, (sc->sc_dip, CE_CONT,
2801                     "ipw2200_rcv_notif(): authentication=%u\n", auth->state));
2802 
2803                 switch (auth->state) {
2804                 case IPW2200_AUTH_SUCCESS:
2805                         ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1);
2806                         break;
2807                 case IPW2200_AUTH_FAIL:
2808                         sc->sc_flags &= ~IPW2200_FLAG_ASSOCIATED;
2809                         break;
2810                 default:
2811                         IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT,
2812                             "ipw2200_rcv_notif(): "
2813                             "unknown authentication state(%u)\n", auth->state));
2814                         break;
2815                 }
2816                 break;
2817 
2818         case IPW2200_NOTIF_TYPE_SCAN_CHANNEL:
2819                 IPW2200_DBG(IPW2200_DBG_SCAN, (sc->sc_dip, CE_CONT,
2820                     "ipw2200_rcv_notif(): scan-channel=%u\n",
2821                     ((struct ipw2200_notif_scan_channel *)ndata)->nchan));
2822                 break;
2823 
2824         case IPW2200_NOTIF_TYPE_SCAN_COMPLETE:
2825                 IPW2200_DBG(IPW2200_DBG_SCAN, (sc->sc_dip, CE_CONT,
2826                     "ipw2200_rcv_notif():scan-completed,(%u,%u)\n",
2827                     ((struct ipw2200_notif_scan_complete *)ndata)->nchan,
2828                     ((struct ipw2200_notif_scan_complete *)ndata)->status));
2829 
2830                 /*
2831                  * scan complete
2832                  */
2833                 sc->sc_flags &= ~IPW2200_FLAG_SCANNING;
2834                 ieee80211_end_scan(ic);
2835                 break;
2836 
2837         case IPW2200_NOTIF_TYPE_BEACON:
2838         case IPW2200_NOTIF_TYPE_CALIBRATION:
2839         case IPW2200_NOTIF_TYPE_NOISE:
2840                 /*
2841                  * just ignore
2842                  */
2843                 break;
2844         default:
2845                 IPW2200_DBG(IPW2200_DBG_NOTIF, (sc->sc_dip, CE_CONT,
2846                     "ipw2200_rcv_notif(): unknown notification type(%u)\n",
2847                     notif->type));
2848                 break;
2849         }
2850 }
2851 
2852 static uint_t
2853 ipw2200_intr(caddr_t arg)
2854 {
2855         struct ipw2200_softc    *sc = (struct ipw2200_softc *)(uintptr_t)arg;
2856         struct ieee80211com     *ic = &sc->sc_ic;
2857         uint32_t                ireg, ridx, len, i;
2858         uint8_t                 *p, *rxbuf;
2859         struct dma_region       *dr;
2860         struct ipw2200_hdr      *hdr;
2861         uint32_t                widx;
2862 
2863         /* when it is on suspend, unclaim all interrupt directly */
2864         if (sc->sc_flags & IPW2200_FLAG_SUSPEND)
2865                 return (DDI_INTR_UNCLAIMED);
2866 
2867         /* unclaim interrupt when it is not for iwi */
2868         ireg = ipw2200_csr_get32(sc, IPW2200_CSR_INTR);
2869         if (ireg == 0xffffffff ||
2870             !(ireg & IPW2200_INTR_MASK_ALL))
2871                 return (DDI_INTR_UNCLAIMED);
2872 
2873         /*
2874          * mask all interrupts
2875          */
2876         ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, 0);
2877 
2878         /*
2879          * acknowledge all fired interrupts
2880          */
2881         ipw2200_csr_put32(sc, IPW2200_CSR_INTR, ireg);
2882 
2883         IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT,
2884             "ipw2200_intr(): enter. interrupt fired, int=0x%08x\n", ireg));
2885 
2886         if (ireg & IPW2200_INTR_MASK_ERR) {
2887 
2888                 IPW2200_DBG(IPW2200_DBG_FATAL, (sc->sc_dip, CE_CONT,
2889                     "ipw2200 interrupt(): int= 0x%08x\n", ireg));
2890 
2891                 /*
2892                  * inform mfthread to recover hw error by stopping it
2893                  */
2894                 mutex_enter(&sc->sc_mflock);
2895                 sc->sc_flags |= IPW2200_FLAG_HW_ERR_RECOVER;
2896                 mutex_exit(&sc->sc_mflock);
2897 
2898                 goto enable_interrupt;
2899         }
2900 
2901         /*
2902          * FW intr
2903          */
2904         if (ireg & IPW2200_INTR_FW_INITED) {
2905                 mutex_enter(&sc->sc_ilock);
2906                 sc->sc_fw_ok = 1;
2907                 cv_signal(&sc->sc_fw_cond);
2908                 mutex_exit(&sc->sc_ilock);
2909         }
2910 
2911         /*
2912          * Radio OFF
2913          */
2914         if (ireg & IPW2200_INTR_RADIO_OFF) {
2915                 IPW2200_REPORT((sc->sc_dip, CE_CONT,
2916                     "ipw2200_intr(): radio is OFF\n"));
2917 
2918                 /*
2919                  * Stop hardware, will notify LINK is down.
2920                  * Need a better scan solution to ensure
2921                  * table has right value.
2922                  */
2923                 ipw2200_stop(sc);
2924         }
2925 
2926         /*
2927          * CMD intr
2928          */
2929         if (ireg & IPW2200_INTR_CMD_TRANSFER) {
2930                 mutex_enter(&sc->sc_cmd_lock);
2931                 ridx = ipw2200_csr_get32(sc,
2932                     IPW2200_CSR_CMD_READ_INDEX);
2933                 i = RING_FORWARD(sc->sc_cmd_cur,
2934                     sc->sc_cmd_free, IPW2200_CMD_RING_SIZE);
2935                 len = RING_FLEN(i, ridx, IPW2200_CMD_RING_SIZE);
2936 
2937                 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT,
2938                     "ipw2200_intr(): cmd-ring,i=%u,ridx=%u,len=%u\n",
2939                     i, ridx, len));
2940 
2941                 if (len > 0) {
2942                         sc->sc_cmd_free += len;
2943                         cv_signal(&sc->sc_cmd_cond);
2944                 }
2945                 for (; i != ridx;
2946                     i = RING_FORWARD(i, 1, IPW2200_CMD_RING_SIZE))
2947                         sc->sc_done[i] = 1;
2948                 mutex_exit(&sc->sc_cmd_lock);
2949 
2950                 mutex_enter(&sc->sc_ilock);
2951                 cv_signal(&sc->sc_cmd_status_cond);
2952                 mutex_exit(&sc->sc_ilock);
2953         }
2954 
2955         /*
2956          * RX intr
2957          */
2958         if (ireg & IPW2200_INTR_RX_TRANSFER) {
2959                 ridx = ipw2200_csr_get32(sc,
2960                     IPW2200_CSR_RX_READ_INDEX);
2961                 widx = ipw2200_csr_get32(sc,
2962                     IPW2200_CSR_RX_WRITE_INDEX);
2963 
2964                 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT,
2965                     "ipw2200_intr(): rx-ring,widx=%u,ridx=%u\n",
2966                     ridx, widx));
2967 
2968                 for (; sc->sc_rx_cur != ridx;
2969                     sc->sc_rx_cur = RING_FORWARD(sc->sc_rx_cur, 1,
2970                     IPW2200_RX_RING_SIZE)) {
2971                         i       = sc->sc_rx_cur;
2972                         rxbuf   = sc->sc_rxbufs[i];
2973                         dr      = &sc->sc_dma_rxbufs[i];
2974 
2975                         /*
2976                          * DMA sync
2977                          */
2978                         (void) ddi_dma_sync(dr->dr_hnd, 0,
2979                             IPW2200_RXBUF_SIZE, DDI_DMA_SYNC_FORKERNEL);
2980                         /*
2981                          * Get rx header(hdr) and rx data(p) from rxbuf
2982                          */
2983                         p       = rxbuf;
2984                         hdr     = (struct ipw2200_hdr *)p;
2985                         p       += sizeof (struct ipw2200_hdr);
2986 
2987                         IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip, CE_CONT,
2988                             "ipw2200_intr(): Rx hdr type %u\n",
2989                             hdr->type));
2990 
2991                         switch (hdr->type) {
2992                         case IPW2200_HDR_TYPE_FRAME:
2993                                 ipw2200_rcv_frame(sc,
2994                                     (struct ipw2200_frame *)p);
2995                                 break;
2996 
2997                         case IPW2200_HDR_TYPE_NOTIF:
2998                                 ipw2200_rcv_notif(sc,
2999                                     (struct ipw2200_notif *)p);
3000                                 break;
3001 
3002                         default:
3003                                 IPW2200_DBG(IPW2200_DBG_INT, (sc->sc_dip,
3004                                     CE_CONT,
3005                                     "ipw2200_intr(): unknown Rx hdr type %u\n",
3006                                     hdr->type));
3007                                 break;
3008                         }
3009                 }
3010                 /*
3011                  * write sc_rx_cur backward 1 step into RX_WRITE_INDEX
3012                  */
3013                 ipw2200_csr_put32(sc, IPW2200_CSR_RX_WRITE_INDEX,
3014                     RING_BACKWARD(sc->sc_rx_cur, 1,
3015                     IPW2200_RX_RING_SIZE));
3016         }
3017 
3018         /*
3019          * TX intr
3020          */
3021         if (ireg & IPW2200_INTR_TX1_TRANSFER) {
3022                 mutex_enter(&sc->sc_tx_lock);
3023                 ridx = ipw2200_csr_get32(sc,
3024                     IPW2200_CSR_TX1_READ_INDEX);
3025                 len  = RING_FLEN(RING_FORWARD(sc->sc_tx_cur,
3026                     sc->sc_tx_free, IPW2200_TX_RING_SIZE),
3027                     ridx, IPW2200_TX_RING_SIZE);
3028                 sc->sc_tx_free += len;
3029                 IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip, CE_CONT,
3030                     "ipw2200_intr(): tx-ring,ridx=%u,len=%u\n",
3031                     ridx, len));
3032                 mutex_exit(&sc->sc_tx_lock);
3033 
3034                 mutex_enter(&sc->sc_resched_lock);
3035                 if ((sc->sc_tx_free > IPW2200_TX_RING_MIN) &&
3036                     (sc->sc_flags & IPW2200_FLAG_TX_SCHED)) {
3037                         IPW2200_DBG(IPW2200_DBG_RING, (sc->sc_dip,
3038                             CE_CONT,
3039                             "ipw2200_intr(): Need Reschedule!"));
3040                         sc->sc_flags &= ~IPW2200_FLAG_TX_SCHED;
3041                         mac_tx_update(ic->ic_mach);
3042                 }
3043                 mutex_exit(&sc->sc_resched_lock);
3044         }
3045 
3046 enable_interrupt:
3047         /*
3048          * enable all interrupts
3049          */
3050         ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, IPW2200_INTR_MASK_ALL);
3051 
3052         return (DDI_INTR_CLAIMED);
3053 }
3054 
3055 
3056 /*
3057  *  Module Loading Data & Entry Points
3058  */
3059 DDI_DEFINE_STREAM_OPS(ipw2200_devops, nulldev, nulldev, ipw2200_attach,
3060     ipw2200_detach, nodev, NULL, D_MP, NULL, ipw2200_quiesce);
3061 
3062 static struct modldrv ipw2200_modldrv = {
3063         &mod_driverops,
3064         ipw2200_ident,
3065         &ipw2200_devops
3066 };
3067 
3068 static struct modlinkage ipw2200_modlinkage = {
3069         MODREV_1,
3070         { &ipw2200_modldrv, NULL }
3071 };
3072 
3073 int
3074 _init(void)
3075 {
3076         int status;
3077 
3078         status = ddi_soft_state_init(&ipw2200_ssp,
3079             sizeof (struct ipw2200_softc), 1);
3080         if (status != DDI_SUCCESS)
3081                 return (status);
3082 
3083         mac_init_ops(&ipw2200_devops, IPW2200_DRV_NAME);
3084         status = mod_install(&ipw2200_modlinkage);
3085         if (status != DDI_SUCCESS) {
3086                 mac_fini_ops(&ipw2200_devops);
3087                 ddi_soft_state_fini(&ipw2200_ssp);
3088         }
3089 
3090         return (status);
3091 }
3092 
3093 int
3094 _fini(void)
3095 {
3096         int status;
3097 
3098         status = mod_remove(&ipw2200_modlinkage);
3099         if (status == DDI_SUCCESS) {
3100                 mac_fini_ops(&ipw2200_devops);
3101                 ddi_soft_state_fini(&ipw2200_ssp);
3102         }
3103 
3104         return (status);
3105 }
3106 
3107 int
3108 _info(struct modinfo *modinfop)
3109 {
3110         return (mod_info(&ipw2200_modlinkage, modinfop));
3111 }