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