Home | History | Annotate | Download | only in ipw
      1 /*
      2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 /*
      7  * Copyright(c) 2004
      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 <net/if.h>
     53 #include <sys/mac_wifi.h>
     54 #include <sys/varargs.h>
     55 #include <sys/policy.h>
     56 
     57 #include "ipw2100.h"
     58 #include "ipw2100_impl.h"
     59 #include <inet/wifi_ioctl.h>
     60 
     61 /*
     62  * kCF framework include files
     63  */
     64 #include <sys/crypto/common.h>
     65 #include <sys/crypto/api.h>
     66 
     67 static void   *ipw2100_ssp	= NULL;
     68 static char   ipw2100_ident[]	= IPW2100_DRV_DESC;
     69 
     70 /*
     71  * PIO access attribute for register
     72  */
     73 static ddi_device_acc_attr_t ipw2100_csr_accattr = {
     74 	DDI_DEVICE_ATTR_V0,
     75 	DDI_STRUCTURE_LE_ACC,
     76 	DDI_STRICTORDER_ACC
     77 };
     78 
     79 static ddi_device_acc_attr_t ipw2100_dma_accattr = {
     80 	DDI_DEVICE_ATTR_V0,
     81 	DDI_NEVERSWAP_ACC,
     82 	DDI_STRICTORDER_ACC
     83 };
     84 
     85 static ddi_dma_attr_t ipw2100_dma_attr = {
     86 	DMA_ATTR_V0,
     87 	0x0000000000000000ULL,
     88 	0x00000000ffffffffULL,
     89 	0x00000000ffffffffULL,
     90 	0x0000000000000004ULL,
     91 	0xfff,
     92 	1,
     93 	0x00000000ffffffffULL,
     94 	0x00000000ffffffffULL,
     95 	1,
     96 	1,
     97 	0
     98 };
     99 
    100 static const struct ieee80211_rateset ipw2100_rateset_11b = { 4,
    101 	{2, 4, 11, 22}
    102 };
    103 
    104 /*
    105  * For mfthread only
    106  */
    107 extern pri_t minclsyspri;
    108 
    109 /*
    110  * ipw2100 specific hardware operations
    111  */
    112 static void	ipw2100_hwconf_get(struct ipw2100_softc *sc);
    113 static int	ipw2100_chip_reset(struct ipw2100_softc *sc);
    114 static void	ipw2100_master_stop(struct ipw2100_softc *sc);
    115 static void	ipw2100_stop(struct ipw2100_softc *sc);
    116 static int	ipw2100_config(struct ipw2100_softc *sc);
    117 static int	ipw2100_cmd(struct ipw2100_softc *sc, uint32_t type,
    118     void *buf, size_t len);
    119 static int	ipw2100_dma_region_alloc(struct ipw2100_softc *sc,
    120     struct dma_region *dr, size_t size, uint_t dir, uint_t flags);
    121 static void	ipw2100_dma_region_free(struct dma_region *dr);
    122 static void	ipw2100_tables_init(struct ipw2100_softc *sc);
    123 static void	ipw2100_ring_hwsetup(struct ipw2100_softc *sc);
    124 static int	ipw2100_ring_alloc(struct ipw2100_softc *sc);
    125 static void	ipw2100_ring_free(struct ipw2100_softc *sc);
    126 static void	ipw2100_ring_reset(struct ipw2100_softc *sc);
    127 static int	ipw2100_ring_init(struct ipw2100_softc *sc);
    128 
    129 /*
    130  * GLD specific operations
    131  */
    132 static int	ipw2100_m_stat(void *arg, uint_t stat, uint64_t *val);
    133 static int	ipw2100_m_start(void *arg);
    134 static void	ipw2100_m_stop(void *arg);
    135 static int	ipw2100_m_unicst(void *arg, const uint8_t *macaddr);
    136 static int	ipw2100_m_multicst(void *arg, boolean_t add, const uint8_t *m);
    137 static int	ipw2100_m_promisc(void *arg, boolean_t on);
    138 static mblk_t  *ipw2100_m_tx(void *arg, mblk_t *mp);
    139 static void	ipw2100_m_ioctl(void *arg, queue_t *wq, mblk_t *mp);
    140 static int	ipw2100_m_setprop(void *arg, const char *pr_name,
    141     mac_prop_id_t wldp_pr_num, uint_t wldp_length, const void *wldp_buf);
    142 static int	ipw2100_m_getprop(void *arg, const char *pr_name,
    143     mac_prop_id_t wldp_pr_num, uint_t pr_flags, uint_t wldp_length,
    144     void *wldp_buf, uint_t *perm);
    145 
    146 
    147 /*
    148  * Interrupt and Data transferring operations
    149  */
    150 static uint_t	ipw2100_intr(caddr_t arg);
    151 static int	ipw2100_send(struct ieee80211com *ic, mblk_t *mp, uint8_t type);
    152 static void	ipw2100_rcvpkt(struct ipw2100_softc *sc,
    153     struct ipw2100_status *status, uint8_t *rxbuf);
    154 
    155 /*
    156  * WiFi specific operations
    157  */
    158 static int	ipw2100_newstate(struct ieee80211com *ic,
    159     enum ieee80211_state state, int arg);
    160 static void	ipw2100_thread(struct ipw2100_softc *sc);
    161 
    162 /*
    163  * IOCTL Handler
    164  */
    165 static int	ipw2100_ioctl(struct ipw2100_softc *sc, queue_t *q, mblk_t *m);
    166 static int	ipw2100_getset(struct ipw2100_softc *sc,
    167     mblk_t *m, uint32_t cmd, boolean_t *need_net80211);
    168 static int	ipw_wificfg_radio(struct ipw2100_softc *sc,
    169     uint32_t cmd,  wldp_t *outfp);
    170 static int	ipw_wificfg_desrates(wldp_t *outfp);
    171 static int	ipw_wificfg_disassoc(struct ipw2100_softc *sc,
    172     wldp_t *outfp);
    173 
    174 /*
    175  * Suspend / Resume operations
    176  */
    177 static int	ipw2100_cpr_suspend(struct ipw2100_softc *sc);
    178 static int	ipw2100_cpr_resume(struct ipw2100_softc *sc);
    179 
    180 /*
    181  * Mac Call Back entries
    182  */
    183 mac_callbacks_t	ipw2100_m_callbacks = {
    184 	MC_IOCTL | MC_SETPROP | MC_GETPROP,
    185 	ipw2100_m_stat,
    186 	ipw2100_m_start,
    187 	ipw2100_m_stop,
    188 	ipw2100_m_promisc,
    189 	ipw2100_m_multicst,
    190 	ipw2100_m_unicst,
    191 	ipw2100_m_tx,
    192 	ipw2100_m_ioctl,
    193 	NULL,
    194 	NULL,
    195 	NULL,
    196 	ipw2100_m_setprop,
    197 	ipw2100_m_getprop
    198 };
    199 
    200 
    201 /*
    202  * DEBUG Facility
    203  */
    204 #define	MAX_MSG (128)
    205 uint32_t ipw2100_debug = 0;
    206 /*
    207  * supported debug marsks:
    208  *	| IPW2100_DBG_INIT
    209  *	| IPW2100_DBG_GLD
    210  *	| IPW2100_DBG_TABLE
    211  *	| IPW2100_DBG_SOFTINT
    212  *	| IPW2100_DBG_CSR
    213  *	| IPW2100_DBG_INT
    214  *	| IPW2100_DBG_FW
    215  *	| IPW2100_DBG_IOCTL
    216  *	| IPW2100_DBG_HWCAP
    217  *	| IPW2100_DBG_STATISTIC
    218  *	| IPW2100_DBG_RING
    219  *	| IPW2100_DBG_WIFI
    220  *	| IPW2100_DBG_BRUSSELS
    221  */
    222 
    223 /*
    224  * global tuning parameters to work around unknown hardware issues
    225  */
    226 static uint32_t delay_config_stable 	= 100000;	/* 100ms */
    227 static uint32_t delay_fatal_recover	= 100000 * 20;	/* 2s */
    228 static uint32_t delay_aux_thread 	= 100000;	/* 100ms */
    229 
    230 void
    231 ipw2100_dbg(dev_info_t *dip, int level, const char *fmt, ...)
    232 {
    233 	va_list	ap;
    234 	char    buf[MAX_MSG];
    235 	int	instance;
    236 
    237 	va_start(ap, fmt);
    238 	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
    239 	va_end(ap);
    240 
    241 	if (dip) {
    242 		instance = ddi_get_instance(dip);
    243 		cmn_err(level, "%s%d: %s", IPW2100_DRV_NAME, instance, buf);
    244 	} else
    245 		cmn_err(level, "%s: %s", IPW2100_DRV_NAME, buf);
    246 }
    247 
    248 /*
    249  * device operations
    250  */
    251 int
    252 ipw2100_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
    253 {
    254 	struct ipw2100_softc	*sc;
    255 	ddi_acc_handle_t	cfgh;
    256 	caddr_t			regs;
    257 	struct ieee80211com	*ic;
    258 	int			instance, err, i;
    259 	char			strbuf[32];
    260 	wifi_data_t		wd = { 0 };
    261 	mac_register_t		*macp;
    262 
    263 	switch (cmd) {
    264 	case DDI_ATTACH:
    265 		break;
    266 	case DDI_RESUME:
    267 		sc = ddi_get_soft_state(ipw2100_ssp, ddi_get_instance(dip));
    268 		if (sc == NULL) {
    269 			err = DDI_FAILURE;
    270 			goto fail1;
    271 		}
    272 		return (ipw2100_cpr_resume(sc));
    273 	default:
    274 		err = DDI_FAILURE;
    275 		goto fail1;
    276 	}
    277 
    278 	instance = ddi_get_instance(dip);
    279 	err = ddi_soft_state_zalloc(ipw2100_ssp, instance);
    280 	if (err != DDI_SUCCESS) {
    281 		IPW2100_WARN((dip, CE_WARN,
    282 		    "ipw2100_attach(): unable to allocate soft state\n"));
    283 		goto fail1;
    284 	}
    285 	sc = ddi_get_soft_state(ipw2100_ssp, instance);
    286 	sc->sc_dip = dip;
    287 
    288 	/*
    289 	 * Map config spaces register
    290 	 */
    291 	err = ddi_regs_map_setup(dip, IPW2100_PCI_CFG_RNUM, &regs,
    292 	    0, 0, &ipw2100_csr_accattr, &cfgh);
    293 	if (err != DDI_SUCCESS) {
    294 		IPW2100_WARN((dip, CE_WARN,
    295 		    "ipw2100_attach(): unable to map spaces regs\n"));
    296 		goto fail2;
    297 	}
    298 	ddi_put8(cfgh, (uint8_t *)(regs + 0x41), 0);
    299 	ddi_regs_map_free(&cfgh);
    300 
    301 	/*
    302 	 * Map operating registers
    303 	 */
    304 	err = ddi_regs_map_setup(dip, IPW2100_PCI_CSR_RNUM, &sc->sc_regs,
    305 	    0, 0, &ipw2100_csr_accattr, &sc->sc_ioh);
    306 	if (err != DDI_SUCCESS) {
    307 		IPW2100_WARN((dip, CE_WARN,
    308 		    "ipw2100_attach(): unable to map device regs\n"));
    309 		goto fail2;
    310 	}
    311 
    312 	/*
    313 	 * Reset the chip
    314 	 */
    315 	err = ipw2100_chip_reset(sc);
    316 	if (err != DDI_SUCCESS) {
    317 		IPW2100_WARN((dip, CE_WARN,
    318 		    "ipw2100_attach(): reset failed\n"));
    319 		goto fail3;
    320 	}
    321 
    322 	/*
    323 	 * Get the hw conf, including MAC address, then init all rings.
    324 	 */
    325 	ipw2100_hwconf_get(sc);
    326 	err = ipw2100_ring_init(sc);
    327 	if (err != DDI_SUCCESS) {
    328 		IPW2100_WARN((dip, CE_WARN,
    329 		    "ipw2100_attach(): "
    330 		    "unable to allocate and initialize rings\n"));
    331 		goto fail3;
    332 	}
    333 
    334 	/*
    335 	 * Initialize mutexs and condvars
    336 	 */
    337 	err = ddi_get_iblock_cookie(dip, 0, &sc->sc_iblk);
    338 	if (err != DDI_SUCCESS) {
    339 		IPW2100_WARN((dip, CE_WARN,
    340 		    "ipw2100_attach(): ddi_get_iblock_cookie() failed\n"));
    341 		goto fail4;
    342 	}
    343 	/*
    344 	 * interrupt lock
    345 	 */
    346 	mutex_init(&sc->sc_ilock, "interrupt-lock", MUTEX_DRIVER,
    347 	    (void *) sc->sc_iblk);
    348 	cv_init(&sc->sc_fw_cond, "firmware", CV_DRIVER, NULL);
    349 	cv_init(&sc->sc_cmd_cond, "command", CV_DRIVER, NULL);
    350 	/*
    351 	 * tx ring lock
    352 	 */
    353 	mutex_init(&sc->sc_tx_lock, "tx-ring", MUTEX_DRIVER,
    354 	    (void *) sc->sc_iblk);
    355 	cv_init(&sc->sc_tx_cond, "tx-ring", CV_DRIVER, NULL);
    356 	/*
    357 	 * rescheuled lock
    358 	 */
    359 	mutex_init(&sc->sc_resched_lock, "reschedule-lock", MUTEX_DRIVER,
    360 	    (void *) sc->sc_iblk);
    361 	/*
    362 	 * initialize the mfthread
    363 	 */
    364 	mutex_init(&sc->sc_mflock, "function-lock", MUTEX_DRIVER,
    365 	    (void *) sc->sc_iblk);
    366 	cv_init(&sc->sc_mfthread_cv, NULL, CV_DRIVER, NULL);
    367 	sc->sc_mf_thread = NULL;
    368 	sc->sc_mfthread_switch = 0;
    369 	/*
    370 	 * Initialize the wifi part, which will be used by
    371 	 * generic layer
    372 	 */
    373 	ic = &sc->sc_ic;
    374 	ic->ic_phytype  = IEEE80211_T_DS;
    375 	ic->ic_opmode   = IEEE80211_M_STA;
    376 	ic->ic_state    = IEEE80211_S_INIT;
    377 	ic->ic_maxrssi  = 49;
    378 	/*
    379 	 * Future, could use s/w to handle encryption: IEEE80211_C_WEP
    380 	 * and need to add support for IEEE80211_C_IBSS
    381 	 */
    382 	ic->ic_caps = IEEE80211_C_SHPREAMBLE | IEEE80211_C_TXPMGT |
    383 	    IEEE80211_C_PMGT;
    384 	ic->ic_sup_rates[IEEE80211_MODE_11B] = ipw2100_rateset_11b;
    385 	IEEE80211_ADDR_COPY(ic->ic_macaddr, sc->sc_macaddr);
    386 	for (i = 1; i < 16; i++) {
    387 		if (sc->sc_chmask &(1 << i)) {
    388 			/* IEEE80211_CHAN_B */
    389 			ic->ic_sup_channels[i].ich_freq  = ieee80211_ieee2mhz(i,
    390 			    IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK);
    391 			ic->ic_sup_channels[i].ich_flags =
    392 			    IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK;
    393 		}
    394 	}
    395 	ic->ic_ibss_chan = &ic->ic_sup_channels[0];
    396 	ic->ic_xmit = ipw2100_send;
    397 	/*
    398 	 * init Wifi layer
    399 	 */
    400 	ieee80211_attach(ic);
    401 
    402 	/*
    403 	 * Override 80211 default routines
    404 	 */
    405 	ieee80211_media_init(ic);
    406 	sc->sc_newstate = ic->ic_newstate;
    407 	ic->ic_newstate = ipw2100_newstate;
    408 	/*
    409 	 * initialize default tx key
    410 	 */
    411 	ic->ic_def_txkey = 0;
    412 	/*
    413 	 * Set the Authentication to AUTH_Open only.
    414 	 */
    415 	sc->sc_authmode = IEEE80211_AUTH_OPEN;
    416 
    417 	/*
    418 	 * Add the interrupt handler
    419 	 */
    420 	err = ddi_add_intr(dip, 0, &sc->sc_iblk, NULL,
    421 	    ipw2100_intr, (caddr_t)sc);
    422 	if (err != DDI_SUCCESS) {
    423 		IPW2100_WARN((dip, CE_WARN,
    424 		    "ipw2100_attach(): ddi_add_intr() failed\n"));
    425 		goto fail5;
    426 	}
    427 
    428 	/*
    429 	 * Initialize pointer to device specific functions
    430 	 */
    431 	wd.wd_secalloc = WIFI_SEC_NONE;
    432 	wd.wd_opmode = ic->ic_opmode;
    433 	IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
    434 
    435 	macp = mac_alloc(MAC_VERSION);
    436 	if (err != 0) {
    437 		IPW2100_WARN((dip, CE_WARN,
    438 		    "ipw2100_attach(): mac_alloc() failed\n"));
    439 		goto fail6;
    440 	}
    441 
    442 	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
    443 	macp->m_driver		= sc;
    444 	macp->m_dip		= dip;
    445 	macp->m_src_addr	= ic->ic_macaddr;
    446 	macp->m_callbacks	= &ipw2100_m_callbacks;
    447 	macp->m_min_sdu		= 0;
    448 	macp->m_max_sdu		= IEEE80211_MTU;
    449 	macp->m_pdata		= &wd;
    450 	macp->m_pdata_size	= sizeof (wd);
    451 
    452 	/*
    453 	 * Register the macp to mac
    454 	 */
    455 	err = mac_register(macp, &ic->ic_mach);
    456 	mac_free(macp);
    457 	if (err != DDI_SUCCESS) {
    458 		IPW2100_WARN((dip, CE_WARN,
    459 		    "ipw2100_attach(): mac_register() failed\n"));
    460 		goto fail6;
    461 	}
    462 
    463 	/*
    464 	 * Create minor node of type DDI_NT_NET_WIFI
    465 	 */
    466 	(void) snprintf(strbuf, sizeof (strbuf), "%s%d",
    467 	    IPW2100_DRV_NAME, instance);
    468 	err = ddi_create_minor_node(dip, strbuf, S_IFCHR,
    469 	    instance + 1, DDI_NT_NET_WIFI, 0);
    470 	if (err != DDI_SUCCESS)
    471 		IPW2100_WARN((dip, CE_WARN,
    472 		    "ipw2100_attach(): ddi_create_minor_node() failed\n"));
    473 
    474 	/*
    475 	 * Cache firmware, always return true
    476 	 */
    477 	(void) ipw2100_cache_firmware(sc);
    478 
    479 	/*
    480 	 * Notify link is down now
    481 	 */
    482 	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
    483 
    484 	/*
    485 	 * create the mf thread to handle the link status,
    486 	 * recovery fatal error, etc.
    487 	 */
    488 	sc->sc_mfthread_switch = 1;
    489 	if (sc->sc_mf_thread == NULL)
    490 		sc->sc_mf_thread = thread_create((caddr_t)NULL, 0,
    491 		    ipw2100_thread, sc, 0, &p0, TS_RUN, minclsyspri);
    492 
    493 	return (DDI_SUCCESS);
    494 
    495 fail6:
    496 	ddi_remove_intr(dip, 0, sc->sc_iblk);
    497 fail5:
    498 	ieee80211_detach(ic);
    499 
    500 	mutex_destroy(&sc->sc_ilock);
    501 	mutex_destroy(&sc->sc_tx_lock);
    502 	mutex_destroy(&sc->sc_mflock);
    503 	mutex_destroy(&sc->sc_resched_lock);
    504 	cv_destroy(&sc->sc_mfthread_cv);
    505 	cv_destroy(&sc->sc_tx_cond);
    506 	cv_destroy(&sc->sc_cmd_cond);
    507 	cv_destroy(&sc->sc_fw_cond);
    508 fail4:
    509 	ipw2100_ring_free(sc);
    510 fail3:
    511 	ddi_regs_map_free(&sc->sc_ioh);
    512 fail2:
    513 	ddi_soft_state_free(ipw2100_ssp, instance);
    514 fail1:
    515 	return (err);
    516 }
    517 
    518 int
    519 ipw2100_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
    520 {
    521 	struct ipw2100_softc	*sc =
    522 	    ddi_get_soft_state(ipw2100_ssp, ddi_get_instance(dip));
    523 	int err;
    524 
    525 	ASSERT(sc != NULL);
    526 
    527 	switch (cmd) {
    528 	case DDI_DETACH:
    529 		break;
    530 	case DDI_SUSPEND:
    531 		return (ipw2100_cpr_suspend(sc));
    532 	default:
    533 		return (DDI_FAILURE);
    534 	}
    535 
    536 	/*
    537 	 * Destroy the mf_thread
    538 	 */
    539 	mutex_enter(&sc->sc_mflock);
    540 	sc->sc_mfthread_switch = 0;
    541 	while (sc->sc_mf_thread != NULL) {
    542 		if (cv_wait_sig(&sc->sc_mfthread_cv, &sc->sc_mflock) == 0)
    543 			break;
    544 	}
    545 	mutex_exit(&sc->sc_mflock);
    546 
    547 	/*
    548 	 * Unregister from the MAC layer subsystem
    549 	 */
    550 	err = mac_unregister(sc->sc_ic.ic_mach);
    551 	if (err != DDI_SUCCESS)
    552 		return (err);
    553 
    554 	ddi_remove_intr(dip, 0, sc->sc_iblk);
    555 
    556 	/*
    557 	 * destroy the cv
    558 	 */
    559 	mutex_destroy(&sc->sc_ilock);
    560 	mutex_destroy(&sc->sc_tx_lock);
    561 	mutex_destroy(&sc->sc_mflock);
    562 	mutex_destroy(&sc->sc_resched_lock);
    563 	cv_destroy(&sc->sc_mfthread_cv);
    564 	cv_destroy(&sc->sc_tx_cond);
    565 	cv_destroy(&sc->sc_cmd_cond);
    566 	cv_destroy(&sc->sc_fw_cond);
    567 
    568 	/*
    569 	 * detach ieee80211
    570 	 */
    571 	ieee80211_detach(&sc->sc_ic);
    572 
    573 	(void) ipw2100_free_firmware(sc);
    574 	ipw2100_ring_free(sc);
    575 
    576 	ddi_regs_map_free(&sc->sc_ioh);
    577 	ddi_remove_minor_node(dip, NULL);
    578 	ddi_soft_state_free(ipw2100_ssp, ddi_get_instance(dip));
    579 
    580 	return (DDI_SUCCESS);
    581 }
    582 
    583 int
    584 ipw2100_cpr_suspend(struct ipw2100_softc *sc)
    585 {
    586 	IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT,
    587 	    "ipw2100_cpr_suspend(): enter\n"));
    588 
    589 	/*
    590 	 * Destroy the mf_thread
    591 	 */
    592 	mutex_enter(&sc->sc_mflock);
    593 	sc->sc_mfthread_switch = 0;
    594 	while (sc->sc_mf_thread != NULL) {
    595 		if (cv_wait_sig(&sc->sc_mfthread_cv, &sc->sc_mflock) == 0)
    596 			break;
    597 	}
    598 	mutex_exit(&sc->sc_mflock);
    599 
    600 	/*
    601 	 * stop the hardware; this mask all interrupts
    602 	 */
    603 	ipw2100_stop(sc);
    604 	sc->sc_flags &= ~IPW2100_FLAG_RUNNING;
    605 	sc->sc_suspended = 1;
    606 
    607 	(void) ipw2100_free_firmware(sc);
    608 	ipw2100_ring_free(sc);
    609 
    610 	return (DDI_SUCCESS);
    611 }
    612 
    613 int
    614 ipw2100_cpr_resume(struct ipw2100_softc *sc)
    615 {
    616 	struct ieee80211com	*ic = &sc->sc_ic;
    617 	dev_info_t		*dip = sc->sc_dip;
    618 	int			err;
    619 
    620 	IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT,
    621 	    "ipw2100_cpr_resume(): enter\n"));
    622 
    623 	/*
    624 	 * Reset the chip
    625 	 */
    626 	err = ipw2100_chip_reset(sc);
    627 	if (err != DDI_SUCCESS) {
    628 		IPW2100_WARN((dip, CE_WARN,
    629 		    "ipw2100_attach(): reset failed\n"));
    630 		return (DDI_FAILURE);
    631 	}
    632 
    633 	/*
    634 	 * Get the hw conf, including MAC address, then init all rings.
    635 	 */
    636 	/* ipw2100_hwconf_get(sc); */
    637 	err = ipw2100_ring_init(sc);
    638 	if (err != DDI_SUCCESS) {
    639 		IPW2100_WARN((dip, CE_WARN,
    640 		    "ipw2100_attach(): "
    641 		    "unable to allocate and initialize rings\n"));
    642 		return (DDI_FAILURE);
    643 	}
    644 
    645 	/*
    646 	 * Cache firmware, always return true
    647 	 */
    648 	(void) ipw2100_cache_firmware(sc);
    649 
    650 	/*
    651 	 * Notify link is down now
    652 	 */
    653 	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
    654 
    655 	/*
    656 	 * create the mf thread to handle the link status,
    657 	 * recovery fatal error, etc.
    658 	 */
    659 	sc->sc_mfthread_switch = 1;
    660 	if (sc->sc_mf_thread == NULL)
    661 		sc->sc_mf_thread = thread_create((caddr_t)NULL, 0,
    662 		    ipw2100_thread, sc, 0, &p0, TS_RUN, minclsyspri);
    663 
    664 	/*
    665 	 * enable all interrupts
    666 	 */
    667 	sc->sc_suspended = 0;
    668 	ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, IPW2100_INTR_MASK_ALL);
    669 
    670 	/*
    671 	 * initialize ipw2100 hardware
    672 	 */
    673 	(void) ipw2100_init(sc);
    674 
    675 	sc->sc_flags |= IPW2100_FLAG_RUNNING;
    676 
    677 	return (DDI_SUCCESS);
    678 }
    679 
    680 /*
    681  * quiesce(9E) entry point.
    682  * This function is called when the system is single-threaded at high
    683  * PIL with preemption disabled. Therefore, this function must not be
    684  * blocked.
    685  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
    686  * DDI_FAILURE indicates an error condition and should almost never happen.
    687  * Contributed by Juergen Keil, <jk (at) tools.de>.
    688  */
    689 static int
    690 ipw2100_quiesce(dev_info_t *dip)
    691 {
    692 	struct ipw2100_softc	*sc =
    693 	    ddi_get_soft_state(ipw2100_ssp, ddi_get_instance(dip));
    694 
    695 	if (sc == NULL)
    696 		return (DDI_FAILURE);
    697 
    698 	/*
    699 	 * No more blocking is allowed while we are in the
    700 	 * quiesce(9E) entry point.
    701 	 */
    702 	sc->sc_flags |= IPW2100_FLAG_QUIESCED;
    703 
    704 	/*
    705 	 * Disable and mask all interrupts.
    706 	 */
    707 	ipw2100_stop(sc);
    708 	return (DDI_SUCCESS);
    709 }
    710 
    711 static void
    712 ipw2100_tables_init(struct ipw2100_softc *sc)
    713 {
    714 	sc->sc_table1_base = ipw2100_csr_get32(sc, IPW2100_CSR_TABLE1_BASE);
    715 	sc->sc_table2_base = ipw2100_csr_get32(sc, IPW2100_CSR_TABLE2_BASE);
    716 }
    717 
    718 static void
    719 ipw2100_stop(struct ipw2100_softc *sc)
    720 {
    721 	struct ieee80211com	*ic = &sc->sc_ic;
    722 
    723 	ipw2100_master_stop(sc);
    724 	ipw2100_csr_put32(sc, IPW2100_CSR_RST, IPW2100_RST_SW_RESET);
    725 	sc->sc_flags &= ~IPW2100_FLAG_FW_INITED;
    726 
    727 	if (!(sc->sc_flags & IPW2100_FLAG_QUIESCED))
    728 		ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
    729 }
    730 
    731 static int
    732 ipw2100_config(struct ipw2100_softc *sc)
    733 {
    734 	struct ieee80211com		*ic = &sc->sc_ic;
    735 	struct ipw2100_security		sec;
    736 	struct ipw2100_wep_key		wkey;
    737 	struct ipw2100_scan_options	sopt;
    738 	struct ipw2100_configuration	cfg;
    739 	uint32_t			data;
    740 	int				err, i;
    741 
    742 	/*
    743 	 * operation mode
    744 	 */
    745 	switch (ic->ic_opmode) {
    746 	case IEEE80211_M_STA:
    747 	case IEEE80211_M_HOSTAP:
    748 		data = LE_32(IPW2100_MODE_BSS);
    749 		break;
    750 
    751 	case IEEE80211_M_IBSS:
    752 	case IEEE80211_M_AHDEMO:
    753 		data = LE_32(IPW2100_MODE_IBSS);
    754 		break;
    755 	}
    756 
    757 	IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
    758 	    "ipw2100_config(): Setting mode to %u\n", LE_32(data)));
    759 
    760 	err = ipw2100_cmd(sc, IPW2100_CMD_SET_MODE,
    761 	    &data, sizeof (data));
    762 	if (err != DDI_SUCCESS)
    763 		return (err);
    764 
    765 	/*
    766 	 * operation channel if IBSS or MONITOR
    767 	 */
    768 	if (ic->ic_opmode == IEEE80211_M_IBSS) {
    769 
    770 		data = LE_32(ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
    771 
    772 		IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
    773 		    "ipw2100_config(): Setting channel to %u\n", LE_32(data)));
    774 
    775 		err = ipw2100_cmd(sc, IPW2100_CMD_SET_CHANNEL,
    776 		    &data, sizeof (data));
    777 		if (err != DDI_SUCCESS)
    778 			return (err);
    779 	}
    780 
    781 	/*
    782 	 * set MAC address
    783 	 */
    784 	IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
    785 	    "ipw2100_config(): Setting MAC address to "
    786 	    "%02x:%02x:%02x:%02x:%02x:%02x\n",
    787 	    ic->ic_macaddr[0], ic->ic_macaddr[1], ic->ic_macaddr[2],
    788 	    ic->ic_macaddr[3], ic->ic_macaddr[4], ic->ic_macaddr[5]));
    789 	err = ipw2100_cmd(sc, IPW2100_CMD_SET_MAC_ADDRESS, ic->ic_macaddr,
    790 	    IEEE80211_ADDR_LEN);
    791 	if (err != DDI_SUCCESS)
    792 		return (err);
    793 
    794 	/*
    795 	 * configuration capabilities
    796 	 */
    797 	cfg.flags = IPW2100_CFG_BSS_MASK | IPW2100_CFG_IBSS_MASK |
    798 	    IPW2100_CFG_PREAMBLE_AUTO | IPW2100_CFG_802_1x_ENABLE;
    799 	if (ic->ic_opmode == IEEE80211_M_IBSS)
    800 		cfg.flags |= IPW2100_CFG_IBSS_AUTO_START;
    801 	if (sc->if_flags & IFF_PROMISC)
    802 		cfg.flags |= IPW2100_CFG_PROMISCUOUS;
    803 	cfg.flags	= LE_32(cfg.flags);
    804 	cfg.bss_chan	= LE_32(sc->sc_chmask >> 1);
    805 	cfg.ibss_chan	= LE_32(sc->sc_chmask >> 1);
    806 
    807 	IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
    808 	    "ipw2100_config(): Setting configuration to 0x%x\n",
    809 	    LE_32(cfg.flags)));
    810 
    811 	err = ipw2100_cmd(sc, IPW2100_CMD_SET_CONFIGURATION,
    812 	    &cfg, sizeof (cfg));
    813 
    814 	if (err != DDI_SUCCESS)
    815 		return (err);
    816 
    817 	/*
    818 	 * set 802.11 Tx rates
    819 	 */
    820 	data = LE_32(0x3);  /* 1, 2 */
    821 	IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
    822 	    "ipw2100_config(): Setting 802.11 Tx rates to 0x%x\n",
    823 	    LE_32(data)));
    824 	err = ipw2100_cmd(sc, IPW2100_CMD_SET_BASIC_TX_RATES,
    825 	    &data, sizeof (data));
    826 	if (err != DDI_SUCCESS)
    827 		return (err);
    828 
    829 	/*
    830 	 * set 802.11b Tx rates
    831 	 */
    832 	data = LE_32(0xf);  /* 1, 2, 5.5, 11 */
    833 	IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
    834 	    "ipw2100_config(): Setting 802.11b Tx rates to 0x%x\n",
    835 	    LE_32(data)));
    836 	err = ipw2100_cmd(sc, IPW2100_CMD_SET_TX_RATES, &data, sizeof (data));
    837 	if (err != DDI_SUCCESS)
    838 		return (err);
    839 
    840 	/*
    841 	 * set power mode
    842 	 */
    843 	data = LE_32(IPW2100_POWER_MODE_CAM);
    844 	IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
    845 	    "ipw2100_config(): Setting power mode to %u\n", LE_32(data)));
    846 	err = ipw2100_cmd(sc, IPW2100_CMD_SET_POWER_MODE, &data, sizeof (data));
    847 	if (err != DDI_SUCCESS)
    848 		return (err);
    849 
    850 	/*
    851 	 * set power index
    852 	 */
    853 	if (ic->ic_opmode == IEEE80211_M_IBSS) {
    854 		data = LE_32(32);
    855 		IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
    856 		    "ipw2100_config(): Setting Tx power index to %u\n",
    857 		    LE_32(data)));
    858 		err = ipw2100_cmd(sc, IPW2100_CMD_SET_TX_POWER_INDEX,
    859 		    &data, sizeof (data));
    860 		if (err != DDI_SUCCESS)
    861 			return (err);
    862 	}
    863 
    864 	/*
    865 	 * set RTS threshold
    866 	 */
    867 	ic->ic_rtsthreshold = 2346;
    868 	data = LE_32(ic->ic_rtsthreshold);
    869 	IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
    870 	    "ipw2100_config(): Setting RTS threshold to %u\n", LE_32(data)));
    871 	err = ipw2100_cmd(sc, IPW2100_CMD_SET_RTS_THRESHOLD,
    872 	    &data, sizeof (data));
    873 	if (err != DDI_SUCCESS)
    874 		return (err);
    875 
    876 	/*
    877 	 * set frag threshold
    878 	 */
    879 	ic->ic_fragthreshold = 2346;
    880 	data = LE_32(ic->ic_fragthreshold);
    881 	IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
    882 	    "ipw2100_config(): Setting frag threshold to %u\n", LE_32(data)));
    883 	err = ipw2100_cmd(sc, IPW2100_CMD_SET_FRAG_THRESHOLD,
    884 	    &data, sizeof (data));
    885 	if (err != DDI_SUCCESS)
    886 		return (err);
    887 
    888 	/*
    889 	 * set ESSID
    890 	 */
    891 	IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
    892 	    "ipw2100_config(): Setting ESSID to %u, ESSID[0]%c\n",
    893 	    ic->ic_des_esslen, ic->ic_des_essid[0]));
    894 	err = ipw2100_cmd(sc, IPW2100_CMD_SET_ESSID,
    895 	    ic->ic_des_essid, ic->ic_des_esslen);
    896 	if (err != DDI_SUCCESS)
    897 		return (err);
    898 
    899 	/*
    900 	 * no mandatory BSSID
    901 	 */
    902 	err = ipw2100_cmd(sc, IPW2100_CMD_SET_MANDATORY_BSSID, NULL, 0);
    903 	if (err != DDI_SUCCESS)
    904 		return (err);
    905 
    906 	/*
    907 	 * set BSSID, if any
    908 	 */
    909 	if (ic->ic_flags & IEEE80211_F_DESBSSID) {
    910 		IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
    911 		    "ipw2100_config(): Setting BSSID to %u\n",
    912 		    IEEE80211_ADDR_LEN));
    913 		err = ipw2100_cmd(sc, IPW2100_CMD_SET_DESIRED_BSSID,
    914 		    ic->ic_des_bssid, IEEE80211_ADDR_LEN);
    915 		if (err != DDI_SUCCESS)
    916 			return (err);
    917 	}
    918 
    919 	/*
    920 	 * set security information
    921 	 */
    922 	(void) memset(&sec, 0, sizeof (sec));
    923 	/*
    924 	 * use the value set to ic_bss to retrieve current sharedmode
    925 	 */
    926 	sec.authmode = (ic->ic_bss->in_authmode == WL_SHAREDKEY) ?
    927 	    IPW2100_AUTH_SHARED : IPW2100_AUTH_OPEN;
    928 	sec.ciphers = LE_32(IPW2100_CIPHER_NONE);
    929 	IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
    930 	    "ipw2100_config(): Setting authmode to %u\n", sec.authmode));
    931 	err = ipw2100_cmd(sc, IPW2100_CMD_SET_SECURITY_INFORMATION,
    932 	    &sec, sizeof (sec));
    933 	if (err != DDI_SUCCESS)
    934 		return (err);
    935 
    936 	/*
    937 	 * set WEP if any
    938 	 */
    939 	if (ic->ic_flags & IEEE80211_F_PRIVACY) {
    940 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
    941 			if (ic->ic_nw_keys[i].wk_keylen == 0)
    942 				continue;
    943 			wkey.idx = (uint8_t)i;
    944 			wkey.len = ic->ic_nw_keys[i].wk_keylen;
    945 			(void) memset(wkey.key, 0, sizeof (wkey.key));
    946 			if (ic->ic_nw_keys[i].wk_keylen)
    947 				(void) memcpy(wkey.key,
    948 				    ic->ic_nw_keys[i].wk_key,
    949 				    ic->ic_nw_keys[i].wk_keylen);
    950 			err = ipw2100_cmd(sc, IPW2100_CMD_SET_WEP_KEY,
    951 			    &wkey, sizeof (wkey));
    952 			if (err != DDI_SUCCESS)
    953 				return (err);
    954 		}
    955 		data = LE_32(ic->ic_def_txkey);
    956 		err = ipw2100_cmd(sc, IPW2100_CMD_SET_WEP_KEY_INDEX,
    957 		    &data, sizeof (data));
    958 		if (err != DDI_SUCCESS)
    959 			return (err);
    960 	}
    961 
    962 	/*
    963 	 * turn on WEP
    964 	 */
    965 	data = LE_32((ic->ic_flags & IEEE80211_F_PRIVACY) ? 0x8 : 0);
    966 	IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
    967 	    "ipw2100_config(): Setting WEP flags to %u\n", LE_32(data)));
    968 	err = ipw2100_cmd(sc, IPW2100_CMD_SET_WEP_FLAGS, &data, sizeof (data));
    969 	if (err != DDI_SUCCESS)
    970 		return (err);
    971 
    972 	/*
    973 	 * set beacon interval if IBSS or HostAP
    974 	 */
    975 	if (ic->ic_opmode == IEEE80211_M_IBSS ||
    976 	    ic->ic_opmode == IEEE80211_M_HOSTAP) {
    977 
    978 		data = LE_32(ic->ic_lintval);
    979 		IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
    980 		    "ipw2100_config(): Setting beacon interval to %u\n",
    981 		    LE_32(data)));
    982 		err = ipw2100_cmd(sc, IPW2100_CMD_SET_BEACON_INTERVAL,
    983 		    &data, sizeof (data));
    984 		if (err != DDI_SUCCESS)
    985 			return (err);
    986 	}
    987 
    988 	/*
    989 	 * set scan options
    990 	 */
    991 	sopt.flags = LE_32(0);
    992 	sopt.channels = LE_32(sc->sc_chmask >> 1);
    993 	err = ipw2100_cmd(sc, IPW2100_CMD_SET_SCAN_OPTIONS,
    994 	    &sopt, sizeof (sopt));
    995 	if (err != DDI_SUCCESS)
    996 		return (err);
    997 
    998 en_adapter:
    999 
   1000 	IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
   1001 	    "ipw2100_config(): Enabling adapter\n"));
   1002 
   1003 	return (ipw2100_cmd(sc, IPW2100_CMD_ENABLE, NULL, 0));
   1004 }
   1005 
   1006 static int
   1007 ipw2100_cmd(struct ipw2100_softc *sc, uint32_t type, void *buf, size_t len)
   1008 {
   1009 	struct ipw2100_bd	*txbd;
   1010 	clock_t			clk;
   1011 	uint32_t		idx;
   1012 
   1013 	/*
   1014 	 * prepare command buffer
   1015 	 */
   1016 	sc->sc_cmd->type = LE_32(type);
   1017 	sc->sc_cmd->subtype = LE_32(0);
   1018 	sc->sc_cmd->seq = LE_32(0);
   1019 	/*
   1020 	 * copy data if any
   1021 	 */
   1022 	if (len && buf)
   1023 		(void) memcpy(sc->sc_cmd->data, buf, len);
   1024 	sc->sc_cmd->len = LE_32(len);
   1025 
   1026 	/*
   1027 	 * get host & device descriptor to submit command
   1028 	 */
   1029 	mutex_enter(&sc->sc_tx_lock);
   1030 
   1031 	IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT,
   1032 	    "ipw2100_cmd(): tx-free=%d\n", sc->sc_tx_free));
   1033 
   1034 	/*
   1035 	 * command need 1 descriptor
   1036 	 */
   1037 	while (sc->sc_tx_free < 1)  {
   1038 		sc->sc_flags |= IPW2100_FLAG_CMD_WAIT;
   1039 		cv_wait(&sc->sc_tx_cond, &sc->sc_tx_lock);
   1040 	}
   1041 	idx = sc->sc_tx_cur;
   1042 
   1043 	IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT,
   1044 	    "ipw2100_cmd(): tx-cur=%d\n", idx));
   1045 
   1046 	sc->sc_done = 0;
   1047 
   1048 	txbd		= &sc->sc_txbd[idx];
   1049 	txbd->phyaddr	= LE_32(sc->sc_dma_cmd.dr_pbase);
   1050 	txbd->len	= LE_32(sizeof (struct ipw2100_cmd));
   1051 	txbd->flags	= IPW2100_BD_FLAG_TX_FRAME_COMMAND
   1052 	    | IPW2100_BD_FLAG_TX_LAST_FRAGMENT;
   1053 	txbd->nfrag	= 1;
   1054 	/*
   1055 	 * sync for device
   1056 	 */
   1057 	(void) ddi_dma_sync(sc->sc_dma_cmd.dr_hnd, 0,
   1058 	    sizeof (struct ipw2100_cmd), DDI_DMA_SYNC_FORDEV);
   1059 	(void) ddi_dma_sync(sc->sc_dma_txbd.dr_hnd,
   1060 	    idx * sizeof (struct ipw2100_bd),
   1061 	    sizeof (struct ipw2100_bd), DDI_DMA_SYNC_FORDEV);
   1062 
   1063 	/*
   1064 	 * ring move forward
   1065 	 */
   1066 	sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2100_NUM_TXBD);
   1067 	sc->sc_tx_free--;
   1068 	ipw2100_csr_put32(sc, IPW2100_CSR_TX_WRITE_INDEX, sc->sc_tx_cur);
   1069 	mutex_exit(&sc->sc_tx_lock);
   1070 
   1071 	/*
   1072 	 * wait for command done
   1073 	 */
   1074 	clk = drv_usectohz(1000000);	/* 1 second */
   1075 	mutex_enter(&sc->sc_ilock);
   1076 	while (sc->sc_done == 0) {
   1077 		/*
   1078 		 * pending for the response
   1079 		 */
   1080 		if (cv_reltimedwait(&sc->sc_cmd_cond, &sc->sc_ilock,
   1081 		    clk, TR_CLOCK_TICK) < 0)
   1082 			break;
   1083 	}
   1084 	mutex_exit(&sc->sc_ilock);
   1085 
   1086 	IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT,
   1087 	    "ipw2100_cmd(): cmd-done=%s\n", sc->sc_done ? "yes" : "no"));
   1088 
   1089 	if (sc->sc_done == 0)
   1090 		return (DDI_FAILURE);
   1091 
   1092 	return (DDI_SUCCESS);
   1093 }
   1094 
   1095 int
   1096 ipw2100_init(struct ipw2100_softc *sc)
   1097 {
   1098 	int	err;
   1099 
   1100 	IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT,
   1101 	    "ipw2100_init(): enter\n"));
   1102 
   1103 	/*
   1104 	 * no firmware is available, return fail directly
   1105 	 */
   1106 	if (!(sc->sc_flags & IPW2100_FLAG_FW_CACHED)) {
   1107 		IPW2100_WARN((sc->sc_dip, CE_WARN,
   1108 		    "ipw2100_init(): no firmware is available\n"));
   1109 		return (DDI_FAILURE);
   1110 	}
   1111 
   1112 	ipw2100_stop(sc);
   1113 
   1114 	err = ipw2100_chip_reset(sc);
   1115 	if (err != DDI_SUCCESS) {
   1116 		IPW2100_WARN((sc->sc_dip, CE_WARN,
   1117 		    "ipw2100_init(): could not reset adapter\n"));
   1118 		goto fail;
   1119 	}
   1120 
   1121 	/*
   1122 	 * load microcode
   1123 	 */
   1124 	IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT,
   1125 	    "ipw2100_init(): loading microcode\n"));
   1126 	err = ipw2100_load_uc(sc);
   1127 	if (err != DDI_SUCCESS) {
   1128 		IPW2100_WARN((sc->sc_dip, CE_WARN,
   1129 		    "ipw2100_init(): could not load microcode, try again\n"));
   1130 		goto fail;
   1131 	}
   1132 
   1133 	ipw2100_master_stop(sc);
   1134 
   1135 	ipw2100_ring_hwsetup(sc);
   1136 
   1137 	/*
   1138 	 * load firmware
   1139 	 */
   1140 	IPW2100_DBG(IPW2100_DBG_INIT, (sc->sc_dip, CE_CONT,
   1141 	    "ipw2100_init(): loading firmware\n"));
   1142 	err = ipw2100_load_fw(sc);
   1143 	if (err != DDI_SUCCESS) {
   1144 		IPW2100_WARN((sc->sc_dip, CE_WARN,
   1145 		    "ipw2100_init(): could not load firmware, try again\n"));
   1146 		goto fail;
   1147 	}
   1148 
   1149 	/*
   1150 	 * initialize tables
   1151 	 */
   1152 	ipw2100_tables_init(sc);
   1153 	ipw2100_table1_put32(sc, IPW2100_INFO_LOCK, 0);
   1154 
   1155 	/*
   1156 	 * Hardware will be enabled after configuration
   1157 	 */
   1158 	err = ipw2100_config(sc);
   1159 	if (err != DDI_SUCCESS) {
   1160 		IPW2100_WARN((sc->sc_dip, CE_WARN,
   1161 		    "ipw2100_init(): device configuration failed\n"));
   1162 		goto fail;
   1163 	}
   1164 
   1165 	delay(drv_usectohz(delay_config_stable));
   1166 
   1167 	return (DDI_SUCCESS);
   1168 
   1169 fail:
   1170 	ipw2100_stop(sc);
   1171 
   1172 	return (err);
   1173 }
   1174 
   1175 /*
   1176  * get hardware configurations from EEPROM embedded within chip
   1177  */
   1178 static void
   1179 ipw2100_hwconf_get(struct ipw2100_softc *sc)
   1180 {
   1181 	int		i;
   1182 	uint16_t	val;
   1183 
   1184 	/*
   1185 	 * MAC address
   1186 	 */
   1187 	i = 0;
   1188 	val = ipw2100_rom_get16(sc, IPW2100_ROM_MAC + 0);
   1189 	sc->sc_macaddr[i++] = val >> 8;
   1190 	sc->sc_macaddr[i++] = val & 0xff;
   1191 	val = ipw2100_rom_get16(sc, IPW2100_ROM_MAC + 1);
   1192 	sc->sc_macaddr[i++] = val >> 8;
   1193 	sc->sc_macaddr[i++] = val & 0xff;
   1194 	val = ipw2100_rom_get16(sc, IPW2100_ROM_MAC + 2);
   1195 	sc->sc_macaddr[i++] = val >> 8;
   1196 	sc->sc_macaddr[i++] = val & 0xff;
   1197 
   1198 	/*
   1199 	 * formatted MAC address string
   1200 	 */
   1201 	(void) snprintf(sc->sc_macstr, sizeof (sc->sc_macstr),
   1202 	    "%02x:%02x:%02x:%02x:%02x:%02x",
   1203 	    sc->sc_macaddr[0], sc->sc_macaddr[1],
   1204 	    sc->sc_macaddr[2], sc->sc_macaddr[3],
   1205 	    sc->sc_macaddr[4], sc->sc_macaddr[5]);
   1206 
   1207 	/*
   1208 	 * channel mask
   1209 	 */
   1210 	val = ipw2100_rom_get16(sc, IPW2100_ROM_CHANNEL_LIST);
   1211 	if (val == 0)
   1212 		val = 0x7ff;
   1213 	sc->sc_chmask = val << 1;
   1214 	IPW2100_DBG(IPW2100_DBG_HWCAP, (sc->sc_dip, CE_CONT,
   1215 	    "ipw2100_hwconf_get(): channel-mask=0x%08x\n", sc->sc_chmask));
   1216 
   1217 	/*
   1218 	 * radio switch
   1219 	 */
   1220 	val = ipw2100_rom_get16(sc, IPW2100_ROM_RADIO);
   1221 	if (val & 0x08)
   1222 		sc->sc_flags |= IPW2100_FLAG_HAS_RADIO_SWITCH;
   1223 
   1224 	IPW2100_DBG(IPW2100_DBG_HWCAP, (sc->sc_dip, CE_CONT,
   1225 	    "ipw2100_hwconf_get(): has-radio-switch=%s(%u)\n",
   1226 	    (sc->sc_flags & IPW2100_FLAG_HAS_RADIO_SWITCH)?  "yes" : "no",
   1227 	    val));
   1228 }
   1229 
   1230 /*
   1231  * all ipw2100 interrupts will be masked by this routine
   1232  */
   1233 static void
   1234 ipw2100_master_stop(struct ipw2100_softc *sc)
   1235 {
   1236 	uint32_t	tmp;
   1237 	int		ntries;
   1238 
   1239 	/*
   1240 	 * disable interrupts
   1241 	 */
   1242 	ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, 0);
   1243 
   1244 	ipw2100_csr_put32(sc, IPW2100_CSR_RST, IPW2100_RST_STOP_MASTER);
   1245 	for (ntries = 0; ntries < 50; ntries++) {
   1246 		if (ipw2100_csr_get32(sc, IPW2100_CSR_RST)
   1247 		    & IPW2100_RST_MASTER_DISABLED)
   1248 			break;
   1249 		drv_usecwait(10);
   1250 	}
   1251 	if (ntries == 50 && !(sc->sc_flags & IPW2100_FLAG_QUIESCED))
   1252 		IPW2100_WARN((sc->sc_dip, CE_WARN,
   1253 		    "ipw2100_master_stop(): timeout when stop master\n"));
   1254 
   1255 	tmp = ipw2100_csr_get32(sc, IPW2100_CSR_RST);
   1256 	ipw2100_csr_put32(sc, IPW2100_CSR_RST,
   1257 	    tmp | IPW2100_RST_PRINCETON_RESET);
   1258 
   1259 	sc->sc_flags &= ~IPW2100_FLAG_FW_INITED;
   1260 }
   1261 
   1262 /*
   1263  * all ipw2100 interrupts will be masked by this routine
   1264  */
   1265 static int
   1266 ipw2100_chip_reset(struct ipw2100_softc *sc)
   1267 {
   1268 	int		ntries;
   1269 	uint32_t	tmp;
   1270 
   1271 	ipw2100_master_stop(sc);
   1272 
   1273 	/*
   1274 	 * move adatper to DO state
   1275 	 */
   1276 	tmp = ipw2100_csr_get32(sc, IPW2100_CSR_CTL);
   1277 	ipw2100_csr_put32(sc, IPW2100_CSR_CTL, tmp | IPW2100_CTL_INIT);
   1278 
   1279 	/*
   1280 	 * wait for clock stabilization
   1281 	 */
   1282 	for (ntries = 0; ntries < 1000; ntries++) {
   1283 		if (ipw2100_csr_get32(sc, IPW2100_CSR_CTL)
   1284 		    & IPW2100_CTL_CLOCK_READY)
   1285 			break;
   1286 		drv_usecwait(200);
   1287 	}
   1288 	if (ntries == 1000)
   1289 		return (DDI_FAILURE);
   1290 
   1291 	tmp = ipw2100_csr_get32(sc, IPW2100_CSR_RST);
   1292 	ipw2100_csr_put32(sc, IPW2100_CSR_RST, tmp | IPW2100_RST_SW_RESET);
   1293 
   1294 	drv_usecwait(10);
   1295 
   1296 	tmp = ipw2100_csr_get32(sc, IPW2100_CSR_CTL);
   1297 	ipw2100_csr_put32(sc, IPW2100_CSR_CTL, tmp | IPW2100_CTL_INIT);
   1298 
   1299 	return (DDI_SUCCESS);
   1300 }
   1301 
   1302 /*
   1303  * get the radio status from IPW_CSR_IO, invoked by wificonfig/dladm
   1304  */
   1305 int
   1306 ipw2100_get_radio(struct ipw2100_softc *sc)
   1307 {
   1308 	if (ipw2100_csr_get32(sc, IPW2100_CSR_IO) & IPW2100_IO_RADIO_DISABLED)
   1309 		return (0);
   1310 	else
   1311 		return (1);
   1312 
   1313 }
   1314 /*
   1315  * This function is used to get the statistic, invoked by wificonfig/dladm
   1316  */
   1317 void
   1318 ipw2100_get_statistics(struct ipw2100_softc *sc)
   1319 {
   1320 	struct ieee80211com	*ic = &sc->sc_ic;
   1321 	uint32_t		addr, size, i;
   1322 	uint32_t		atbl[256], *datatbl;
   1323 
   1324 	datatbl = atbl;
   1325 
   1326 	if (!(sc->sc_flags & IPW2100_FLAG_FW_INITED)) {
   1327 		IPW2100_DBG(IPW2100_DBG_STATISTIC, (sc->sc_dip, CE_CONT,
   1328 		    "ipw2100_get_statistic(): fw doesn't download yet."));
   1329 		return;
   1330 	}
   1331 
   1332 	ipw2100_csr_put32(sc, IPW2100_CSR_AUTOINC_ADDR, sc->sc_table1_base);
   1333 
   1334 	size = ipw2100_csr_get32(sc, IPW2100_CSR_AUTOINC_DATA);
   1335 	atbl[0] = size;
   1336 	for (i = 1, ++datatbl; i < size; i++, datatbl++) {
   1337 		addr = ipw2100_csr_get32(sc, IPW2100_CSR_AUTOINC_DATA);
   1338 		*datatbl = ipw2100_imem_get32(sc, addr);
   1339 	}
   1340 
   1341 	/*
   1342 	 * To retrieve the statistic information into proper places. There are
   1343 	 * lot of information.
   1344 	 */
   1345 	IPW2100_DBG(IPW2100_DBG_STATISTIC, (sc->sc_dip, CE_CONT,
   1346 	    "ipw2100_get_statistic(): \n"
   1347 	    "operating mode = %u\n"
   1348 	    "type of authentification= %u\n"
   1349 	    "average RSSI= %u\n"
   1350 	    "current channel = %d\n",
   1351 	    atbl[191], atbl[199], atbl[173], atbl[189]));
   1352 	/* WIFI_STAT_TX_FRAGS */
   1353 	ic->ic_stats.is_tx_frags = (uint32_t)atbl[2];
   1354 	/* WIFI_STAT_MCAST_TX = (all frame - unicast frame) */
   1355 	ic->ic_stats.is_tx_mcast = (uint32_t)atbl[2] - (uint32_t)atbl[3];
   1356 	/* WIFI_STAT_TX_RETRANS */
   1357 	ic->ic_stats.is_tx_retries = (uint32_t)atbl[42];
   1358 	/* WIFI_STAT_TX_FAILED */
   1359 	ic->ic_stats.is_tx_failed = (uint32_t)atbl[51];
   1360 	/* MAC_STAT_OBYTES */
   1361 	ic->ic_stats.is_tx_bytes = (uint32_t)atbl[41];
   1362 	/* WIFI_STAT_RX_FRAGS */
   1363 	ic->ic_stats.is_rx_frags = (uint32_t)atbl[61];
   1364 	/* WIFI_STAT_MCAST_RX */
   1365 	ic->ic_stats.is_rx_mcast = (uint32_t)atbl[71];
   1366 	/* MAC_STAT_IBYTES */
   1367 	ic->ic_stats.is_rx_bytes = (uint32_t)atbl[101];
   1368 	/* WIFI_STAT_ACK_FAILURE */
   1369 	ic->ic_stats.is_ack_failure = (uint32_t)atbl[59];
   1370 	/* WIFI_STAT_RTS_SUCCESS */
   1371 	ic->ic_stats.is_rts_success = (uint32_t)atbl[22];
   1372 }
   1373 
   1374 /*
   1375  * dma region alloc
   1376  */
   1377 static int
   1378 ipw2100_dma_region_alloc(struct ipw2100_softc *sc,
   1379     struct dma_region *dr, size_t size, uint_t dir, uint_t flags)
   1380 {
   1381 	dev_info_t	*dip = sc->sc_dip;
   1382 	int		err;
   1383 
   1384 	IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT,
   1385 	    "ipw2100_dma_region_alloc() name=%s size=%u\n",
   1386 	    dr->dr_name, size));
   1387 
   1388 	err = ddi_dma_alloc_handle(dip, &ipw2100_dma_attr, DDI_DMA_SLEEP, NULL,
   1389 	    &dr->dr_hnd);
   1390 	if (err != DDI_SUCCESS) {
   1391 		IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT,
   1392 		    "ipw2100_dma_region_alloc(): "
   1393 		    "ddi_dma_alloc_handle() failed\n"));
   1394 		goto fail0;
   1395 	}
   1396 
   1397 	err = ddi_dma_mem_alloc(dr->dr_hnd, size, &ipw2100_dma_accattr,
   1398 	    flags, DDI_DMA_SLEEP, NULL, &dr->dr_base,
   1399 	    &dr->dr_size, &dr->dr_acc);
   1400 	if (err != DDI_SUCCESS) {
   1401 		IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT,
   1402 		    "ipw2100_dma_region_alloc(): "
   1403 		    "ddi_dma_mem_alloc() failed\n"));
   1404 		goto fail1;
   1405 	}
   1406 
   1407 	err = ddi_dma_addr_bind_handle(dr->dr_hnd, NULL,
   1408 	    dr->dr_base, dr->dr_size, dir | flags, DDI_DMA_SLEEP, NULL,
   1409 	    &dr->dr_cookie, &dr->dr_ccnt);
   1410 	if (err != DDI_DMA_MAPPED) {
   1411 		IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT,
   1412 		    "ipw2100_dma_region_alloc(): "
   1413 		    "ddi_dma_addr_bind_handle() failed\n"));
   1414 		goto fail2;
   1415 	}
   1416 
   1417 	if (dr->dr_ccnt != 1) {
   1418 		err = DDI_FAILURE;
   1419 		goto fail3;
   1420 	}
   1421 	dr->dr_pbase = dr->dr_cookie.dmac_address;
   1422 
   1423 	IPW2100_DBG(IPW2100_DBG_DMA, (dip, CE_CONT,
   1424 	    "ipw2100_dma_region_alloc(): get physical-base=0x%08x\n",
   1425 	    dr->dr_pbase));
   1426 
   1427 	return (DDI_SUCCESS);
   1428 
   1429 fail3:
   1430 	(void) ddi_dma_unbind_handle(dr->dr_hnd);
   1431 fail2:
   1432 	ddi_dma_mem_free(&dr->dr_acc);
   1433 fail1:
   1434 	ddi_dma_free_handle(&dr->dr_hnd);
   1435 fail0:
   1436 	return (err);
   1437 }
   1438 
   1439 static void
   1440 ipw2100_dma_region_free(struct dma_region *dr)
   1441 {
   1442 	(void) ddi_dma_unbind_handle(dr->dr_hnd);
   1443 	ddi_dma_mem_free(&dr->dr_acc);
   1444 	ddi_dma_free_handle(&dr->dr_hnd);
   1445 }
   1446 
   1447 static int
   1448 ipw2100_ring_alloc(struct ipw2100_softc *sc)
   1449 {
   1450 	int	err, i;
   1451 
   1452 	/*
   1453 	 * tx ring
   1454 	 */
   1455 	sc->sc_dma_txbd.dr_name = "ipw2100-tx-ring-bd";
   1456 	err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_txbd,
   1457 	    IPW2100_TXBD_SIZE, DDI_DMA_WRITE, DDI_DMA_CONSISTENT);
   1458 	if (err != DDI_SUCCESS)
   1459 		goto fail0;
   1460 	/*
   1461 	 * tx bufs
   1462 	 */
   1463 	for (i = 0; i < IPW2100_NUM_TXBUF; i++) {
   1464 		sc->sc_dma_txbufs[i].dr_name = "ipw2100-tx-buf";
   1465 		err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_txbufs[i],
   1466 		    IPW2100_TXBUF_SIZE, DDI_DMA_WRITE, DDI_DMA_STREAMING);
   1467 		if (err != DDI_SUCCESS) {
   1468 			while (i > 0) {
   1469 				i--;
   1470 				ipw2100_dma_region_free(&sc->sc_dma_txbufs[i]);
   1471 			}
   1472 			goto fail1;
   1473 		}
   1474 	}
   1475 	/*
   1476 	 * rx ring
   1477 	 */
   1478 	sc->sc_dma_rxbd.dr_name = "ipw2100-rx-ring-bd";
   1479 	err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_rxbd,
   1480 	    IPW2100_RXBD_SIZE, DDI_DMA_WRITE, DDI_DMA_CONSISTENT);
   1481 	if (err != DDI_SUCCESS)
   1482 		goto fail2;
   1483 	/*
   1484 	 * rx bufs
   1485 	 */
   1486 	for (i = 0; i < IPW2100_NUM_RXBUF; i++) {
   1487 		sc->sc_dma_rxbufs[i].dr_name = "ipw2100-rx-buf";
   1488 		err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_rxbufs[i],
   1489 		    IPW2100_RXBUF_SIZE, DDI_DMA_READ, DDI_DMA_STREAMING);
   1490 		if (err != DDI_SUCCESS) {
   1491 			while (i > 0) {
   1492 				i--;
   1493 				ipw2100_dma_region_free(&sc->sc_dma_rxbufs[i]);
   1494 			}
   1495 			goto fail3;
   1496 		}
   1497 	}
   1498 	/*
   1499 	 * status
   1500 	 */
   1501 	sc->sc_dma_status.dr_name = "ipw2100-rx-status";
   1502 	err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_status,
   1503 	    IPW2100_STATUS_SIZE, DDI_DMA_READ, DDI_DMA_CONSISTENT);
   1504 	if (err != DDI_SUCCESS)
   1505 		goto fail4;
   1506 	/*
   1507 	 * command
   1508 	 */
   1509 	sc->sc_dma_cmd.dr_name = "ipw2100-cmd";
   1510 	err = ipw2100_dma_region_alloc(sc, &sc->sc_dma_cmd, IPW2100_CMD_SIZE,
   1511 	    DDI_DMA_WRITE, DDI_DMA_CONSISTENT);
   1512 	if (err != DDI_SUCCESS)
   1513 		goto fail5;
   1514 
   1515 	return (DDI_SUCCESS);
   1516 
   1517 fail5:
   1518 	ipw2100_dma_region_free(&sc->sc_dma_status);
   1519 fail4:
   1520 	for (i = 0; i < IPW2100_NUM_RXBUF; i++)
   1521 		ipw2100_dma_region_free(&sc->sc_dma_rxbufs[i]);
   1522 fail3:
   1523 	ipw2100_dma_region_free(&sc->sc_dma_rxbd);
   1524 fail2:
   1525 	for (i = 0; i < IPW2100_NUM_TXBUF; i++)
   1526 		ipw2100_dma_region_free(&sc->sc_dma_txbufs[i]);
   1527 fail1:
   1528 	ipw2100_dma_region_free(&sc->sc_dma_txbd);
   1529 fail0:
   1530 	return (err);
   1531 }
   1532 
   1533 static void
   1534 ipw2100_ring_free(struct ipw2100_softc *sc)
   1535 {
   1536 	int	i;
   1537 
   1538 	/*
   1539 	 * tx ring
   1540 	 */
   1541 	ipw2100_dma_region_free(&sc->sc_dma_txbd);
   1542 	/*
   1543 	 * tx buf
   1544 	 */
   1545 	for (i = 0; i < IPW2100_NUM_TXBUF; i++)
   1546 		ipw2100_dma_region_free(&sc->sc_dma_txbufs[i]);
   1547 	/*
   1548 	 * rx ring
   1549 	 */
   1550 	ipw2100_dma_region_free(&sc->sc_dma_rxbd);
   1551 	/*
   1552 	 * rx buf
   1553 	 */
   1554 	for (i = 0; i < IPW2100_NUM_RXBUF; i++)
   1555 		ipw2100_dma_region_free(&sc->sc_dma_rxbufs[i]);
   1556 	/*
   1557 	 * status
   1558 	 */
   1559 	ipw2100_dma_region_free(&sc->sc_dma_status);
   1560 	/*
   1561 	 * command
   1562 	 */
   1563 	ipw2100_dma_region_free(&sc->sc_dma_cmd);
   1564 }
   1565 
   1566 static void
   1567 ipw2100_ring_reset(struct ipw2100_softc *sc)
   1568 {
   1569 	int	i;
   1570 
   1571 	/*
   1572 	 * tx ring
   1573 	 */
   1574 	sc->sc_tx_cur   = 0;
   1575 	sc->sc_tx_free  = IPW2100_NUM_TXBD;
   1576 	sc->sc_txbd	= (struct ipw2100_bd *)sc->sc_dma_txbd.dr_base;
   1577 	for (i = 0; i < IPW2100_NUM_TXBUF; i++)
   1578 		sc->sc_txbufs[i] =
   1579 		    (struct ipw2100_txb *)sc->sc_dma_txbufs[i].dr_base;
   1580 	/*
   1581 	 * rx ring
   1582 	 */
   1583 	sc->sc_rx_cur   = 0;
   1584 	sc->sc_rx_free  = IPW2100_NUM_RXBD;
   1585 	sc->sc_status   = (struct ipw2100_status *)sc->sc_dma_status.dr_base;
   1586 	sc->sc_rxbd	= (struct ipw2100_bd *)sc->sc_dma_rxbd.dr_base;
   1587 	for (i = 0; i < IPW2100_NUM_RXBUF; i++) {
   1588 		sc->sc_rxbufs[i] =
   1589 		    (struct ipw2100_rxb *)sc->sc_dma_rxbufs[i].dr_base;
   1590 		/*
   1591 		 * initialize Rx buffer descriptors, both host and device
   1592 		 */
   1593 		sc->sc_rxbd[i].phyaddr  = LE_32(sc->sc_dma_rxbufs[i].dr_pbase);
   1594 		sc->sc_rxbd[i].len	= LE_32(sc->sc_dma_rxbufs[i].dr_size);
   1595 		sc->sc_rxbd[i].flags	= 0;
   1596 		sc->sc_rxbd[i].nfrag	= 1;
   1597 	}
   1598 	/*
   1599 	 * command
   1600 	 */
   1601 	sc->sc_cmd = (struct ipw2100_cmd *)sc->sc_dma_cmd.dr_base;
   1602 }
   1603 
   1604 /*
   1605  * tx, rx rings and command initialization
   1606  */
   1607 static int
   1608 ipw2100_ring_init(struct ipw2100_softc *sc)
   1609 {
   1610 	int	err;
   1611 
   1612 	err = ipw2100_ring_alloc(sc);
   1613 	if (err != DDI_SUCCESS)
   1614 		return (err);
   1615 
   1616 	ipw2100_ring_reset(sc);
   1617 
   1618 	return (DDI_SUCCESS);
   1619 }
   1620 
   1621 static void
   1622 ipw2100_ring_hwsetup(struct ipw2100_softc *sc)
   1623 {
   1624 	ipw2100_ring_reset(sc);
   1625 	/*
   1626 	 * tx ring
   1627 	 */
   1628 	ipw2100_csr_put32(sc, IPW2100_CSR_TX_BD_BASE, sc->sc_dma_txbd.dr_pbase);
   1629 	ipw2100_csr_put32(sc, IPW2100_CSR_TX_BD_SIZE, IPW2100_NUM_TXBD);
   1630 	/*
   1631 	 * no new packet to transmit, tx-rd-index == tx-wr-index
   1632 	 */
   1633 	ipw2100_csr_put32(sc, IPW2100_CSR_TX_READ_INDEX, sc->sc_tx_cur);
   1634 	ipw2100_csr_put32(sc, IPW2100_CSR_TX_WRITE_INDEX, sc->sc_tx_cur);
   1635 	/*
   1636 	 * rx ring
   1637 	 */
   1638 	ipw2100_csr_put32(sc, IPW2100_CSR_RX_BD_BASE, sc->sc_dma_rxbd.dr_pbase);
   1639 	ipw2100_csr_put32(sc, IPW2100_CSR_RX_BD_SIZE, IPW2100_NUM_RXBD);
   1640 	/*
   1641 	 * all rx buffer are empty, rx-rd-index == 0 && rx-wr-index == N-1
   1642 	 */
   1643 	IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT,
   1644 	    "ipw2100_ring_hwsetup(): rx-cur=%u, backward=%u\n",
   1645 	    sc->sc_rx_cur, RING_BACKWARD(sc->sc_rx_cur, 1, IPW2100_NUM_RXBD)));
   1646 	ipw2100_csr_put32(sc, IPW2100_CSR_RX_READ_INDEX, sc->sc_rx_cur);
   1647 	ipw2100_csr_put32(sc, IPW2100_CSR_RX_WRITE_INDEX,
   1648 	    RING_BACKWARD(sc->sc_rx_cur, 1, IPW2100_NUM_RXBD));
   1649 	/*
   1650 	 * status
   1651 	 */
   1652 	ipw2100_csr_put32(sc, IPW2100_CSR_RX_STATUS_BASE,
   1653 	    sc->sc_dma_status.dr_pbase);
   1654 }
   1655 
   1656 /*
   1657  * ieee80211_new_state() is not be used, since the hardware can handle the
   1658  * state transfer. Here, we just keep the status of the hardware notification
   1659  * result.
   1660  */
   1661 /* ARGSUSED */
   1662 static int
   1663 ipw2100_newstate(struct ieee80211com *ic, enum ieee80211_state state, int arg)
   1664 {
   1665 	struct ipw2100_softc	*sc = (struct ipw2100_softc *)ic;
   1666 	struct ieee80211_node	*in;
   1667 	uint8_t			macaddr[IEEE80211_ADDR_LEN];
   1668 	uint32_t		len;
   1669 	wifi_data_t		wd = { 0 };
   1670 
   1671 	IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
   1672 	    "ipw2100_newstate(): %s -> %s\n",
   1673 	    ieee80211_state_name[ic->ic_state], ieee80211_state_name[state]));
   1674 
   1675 	switch (state) {
   1676 	case IEEE80211_S_RUN:
   1677 		/*
   1678 		 * we only need to use BSSID as to find the node
   1679 		 */
   1680 		drv_usecwait(200); /* firmware needs a short delay here */
   1681 		len = IEEE80211_ADDR_LEN;
   1682 		(void) ipw2100_table2_getbuf(sc, IPW2100_INFO_CURRENT_BSSID,
   1683 		    macaddr, &len);
   1684 
   1685 		in = ieee80211_find_node(&ic->ic_scan, macaddr);
   1686 		if (in == NULL)
   1687 			break;
   1688 
   1689 		(void) ieee80211_sta_join(ic, in);
   1690 		ieee80211_node_authorize(in);
   1691 
   1692 		/*
   1693 		 * We can send data now; update the fastpath with our
   1694 		 * current associated BSSID.
   1695 		 */
   1696 		if (ic->ic_flags & IEEE80211_F_PRIVACY)
   1697 			wd.wd_secalloc = WIFI_SEC_WEP;
   1698 		else
   1699 			wd.wd_secalloc = WIFI_SEC_NONE;
   1700 		wd.wd_opmode = ic->ic_opmode;
   1701 		IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
   1702 		(void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd));
   1703 
   1704 		break;
   1705 
   1706 	case IEEE80211_S_INIT:
   1707 	case IEEE80211_S_SCAN:
   1708 	case IEEE80211_S_AUTH:
   1709 	case IEEE80211_S_ASSOC:
   1710 		break;
   1711 	}
   1712 
   1713 	/*
   1714 	 * notify to update the link
   1715 	 */
   1716 	if ((ic->ic_state != IEEE80211_S_RUN) && (state == IEEE80211_S_RUN)) {
   1717 		/*
   1718 		 * previously disconnected and now connected
   1719 		 */
   1720 		sc->sc_linkstate = LINK_STATE_UP;
   1721 		sc->sc_flags |= IPW2100_FLAG_LINK_CHANGE;
   1722 	} else if ((ic->ic_state == IEEE80211_S_RUN) &&
   1723 	    (state != IEEE80211_S_RUN)) {
   1724 		/*
   1725 		 * previously connected andd now disconnected
   1726 		 */
   1727 		sc->sc_linkstate = LINK_STATE_DOWN;
   1728 		sc->sc_flags |= IPW2100_FLAG_LINK_CHANGE;
   1729 	}
   1730 
   1731 	ic->ic_state = state;
   1732 	return (DDI_SUCCESS);
   1733 }
   1734 
   1735 /*
   1736  * GLD operations
   1737  */
   1738 /* ARGSUSED */
   1739 static int
   1740 ipw2100_m_stat(void *arg, uint_t stat, uint64_t *val)
   1741 {
   1742 	ieee80211com_t	*ic = (ieee80211com_t *)arg;
   1743 	IPW2100_DBG(IPW2100_DBG_GLD, (((struct ipw2100_softc *)arg)->sc_dip,
   1744 	    CE_CONT,
   1745 	    "ipw2100_m_stat(): enter\n"));
   1746 	/*
   1747 	 * some of below statistic data are from hardware, some from net80211
   1748 	 */
   1749 	switch (stat) {
   1750 	case MAC_STAT_RBYTES:
   1751 		*val = ic->ic_stats.is_rx_bytes;
   1752 		break;
   1753 	case MAC_STAT_IPACKETS:
   1754 		*val = ic->ic_stats.is_rx_frags;
   1755 		break;
   1756 	case MAC_STAT_OBYTES:
   1757 		*val = ic->ic_stats.is_tx_bytes;
   1758 		break;
   1759 	case MAC_STAT_OPACKETS:
   1760 		*val = ic->ic_stats.is_tx_frags;
   1761 		break;
   1762 	/*
   1763 	 * Get below from hardware statistic, retrieve net80211 value once 1s
   1764 	 */
   1765 	case WIFI_STAT_TX_FRAGS:
   1766 	case WIFI_STAT_MCAST_TX:
   1767 	case WIFI_STAT_TX_FAILED:
   1768 	case WIFI_STAT_TX_RETRANS:
   1769 	case WIFI_STAT_RTS_SUCCESS:
   1770 	case WIFI_STAT_ACK_FAILURE:
   1771 	case WIFI_STAT_RX_FRAGS:
   1772 	case WIFI_STAT_MCAST_RX:
   1773 	/*
   1774 	 * Get blow information from net80211
   1775 	 */
   1776 	case WIFI_STAT_RTS_FAILURE:
   1777 	case WIFI_STAT_RX_DUPS:
   1778 	case WIFI_STAT_FCS_ERRORS:
   1779 	case WIFI_STAT_WEP_ERRORS:
   1780 		return (ieee80211_stat(ic, stat, val));
   1781 	/*
   1782 	 * need be supported in the future
   1783 	 */
   1784 	case MAC_STAT_IFSPEED:
   1785 	case MAC_STAT_NOXMTBUF:
   1786 	case MAC_STAT_IERRORS:
   1787 	case MAC_STAT_OERRORS:
   1788 	default:
   1789 		return (ENOTSUP);
   1790 	}
   1791 	return (0);
   1792 }
   1793 
   1794 /* ARGSUSED */
   1795 static int
   1796 ipw2100_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
   1797 {
   1798 	/* not supported */
   1799 	IPW2100_DBG(IPW2100_DBG_GLD, (((struct ipw2100_softc *)arg)->sc_dip,
   1800 	    CE_CONT,
   1801 	    "ipw2100_m_multicst(): enter\n"));
   1802 
   1803 	return (0);
   1804 }
   1805 
   1806 /*
   1807  * This thread function is used to handle the fatal error.
   1808  */
   1809 static void
   1810 ipw2100_thread(struct ipw2100_softc *sc)
   1811 {
   1812 	struct ieee80211com	*ic = &sc->sc_ic;
   1813 	int32_t			nlstate;
   1814 	int			stat_cnt = 0;
   1815 
   1816 	IPW2100_DBG(IPW2100_DBG_SOFTINT, (sc->sc_dip, CE_CONT,
   1817 	    "ipw2100_thread(): into ipw2100 thread--> %d\n",
   1818 	    sc->sc_linkstate));
   1819 
   1820 	mutex_enter(&sc->sc_mflock);
   1821 
   1822 	while (sc->sc_mfthread_switch) {
   1823 		/*
   1824 		 * notify the link state
   1825 		 */
   1826 		if (ic->ic_mach && (sc->sc_flags & IPW2100_FLAG_LINK_CHANGE)) {
   1827 			IPW2100_DBG(IPW2100_DBG_SOFTINT, (sc->sc_dip, CE_CONT,
   1828 			    "ipw2100_thread(): link status --> %d\n",
   1829 			    sc->sc_linkstate));
   1830 
   1831 			sc->sc_flags &= ~IPW2100_FLAG_LINK_CHANGE;
   1832 			nlstate = sc->sc_linkstate;
   1833 
   1834 			mutex_exit(&sc->sc_mflock);
   1835 			mac_link_update(ic->ic_mach, nlstate);
   1836 			mutex_enter(&sc->sc_mflock);
   1837 		}
   1838 
   1839 		/*
   1840 		 * recovery interrupt fatal error
   1841 		 */
   1842 		if (ic->ic_mach &&
   1843 		    (sc->sc_flags & IPW2100_FLAG_HW_ERR_RECOVER)) {
   1844 
   1845 			IPW2100_DBG(IPW2100_DBG_FATAL, (sc->sc_dip, CE_CONT,
   1846 			    "try to recover fatal hw error\n"));
   1847 			sc->sc_flags &= ~IPW2100_FLAG_HW_ERR_RECOVER;
   1848 
   1849 			mutex_exit(&sc->sc_mflock);
   1850 			(void) ipw2100_init(sc); /* Force stat machine */
   1851 			delay(drv_usectohz(delay_fatal_recover));
   1852 			mutex_enter(&sc->sc_mflock);
   1853 		}
   1854 
   1855 		/*
   1856 		 * get statistic, the value will be retrieved by m_stat
   1857 		 */
   1858 		if (stat_cnt == 10) {
   1859 			stat_cnt = 0; /* re-start */
   1860 
   1861 			mutex_exit(&sc->sc_mflock);
   1862 			ipw2100_get_statistics(sc);
   1863 			mutex_enter(&sc->sc_mflock);
   1864 		} else
   1865 			stat_cnt++; /* until 1s */
   1866 
   1867 		mutex_exit(&sc->sc_mflock);
   1868 		delay(drv_usectohz(delay_aux_thread));
   1869 		mutex_enter(&sc->sc_mflock);
   1870 	}
   1871 	sc->sc_mf_thread = NULL;
   1872 	cv_broadcast(&sc->sc_mfthread_cv);
   1873 	mutex_exit(&sc->sc_mflock);
   1874 }
   1875 
   1876 static int
   1877 ipw2100_m_start(void *arg)
   1878 {
   1879 	struct ipw2100_softc	*sc = (struct ipw2100_softc *)arg;
   1880 
   1881 	IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
   1882 	    "ipw2100_m_start(): enter\n"));
   1883 
   1884 	/*
   1885 	 * initialize ipw2100 hardware
   1886 	 */
   1887 	(void) ipw2100_init(sc);
   1888 
   1889 	sc->sc_flags |= IPW2100_FLAG_RUNNING;
   1890 	/*
   1891 	 * fix KCF bug. - workaround, need to fix it in net80211
   1892 	 */
   1893 	(void) crypto_mech2id(SUN_CKM_RC4);
   1894 
   1895 	return (0);
   1896 }
   1897 
   1898 static void
   1899 ipw2100_m_stop(void *arg)
   1900 {
   1901 	struct ipw2100_softc	*sc = (struct ipw2100_softc *)arg;
   1902 
   1903 	IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
   1904 	    "ipw2100_m_stop(): enter\n"));
   1905 
   1906 	ipw2100_stop(sc);
   1907 
   1908 	sc->sc_flags &= ~IPW2100_FLAG_RUNNING;
   1909 }
   1910 
   1911 static int
   1912 ipw2100_m_unicst(void *arg, const uint8_t *macaddr)
   1913 {
   1914 	struct ipw2100_softc	*sc = (struct ipw2100_softc *)arg;
   1915 	struct ieee80211com	*ic = &sc->sc_ic;
   1916 	int			err;
   1917 
   1918 	IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
   1919 	    "ipw2100_m_unicst(): enter\n"));
   1920 
   1921 	IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
   1922 	    "ipw2100_m_unicst(): GLD setting MAC address to "
   1923 	    "%02x:%02x:%02x:%02x:%02x:%02x\n",
   1924 	    macaddr[0], macaddr[1], macaddr[2],
   1925 	    macaddr[3], macaddr[4], macaddr[5]));
   1926 
   1927 	if (!IEEE80211_ADDR_EQ(ic->ic_macaddr, macaddr)) {
   1928 		IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr);
   1929 
   1930 		if (sc->sc_flags & IPW2100_FLAG_RUNNING) {
   1931 			err = ipw2100_config(sc);
   1932 			if (err != DDI_SUCCESS) {
   1933 				IPW2100_WARN((sc->sc_dip, CE_WARN,
   1934 				    "ipw2100_m_unicst(): "
   1935 				    "device configuration failed\n"));
   1936 				goto fail;
   1937 			}
   1938 		}
   1939 	}
   1940 
   1941 	return (0);
   1942 fail:
   1943 	return (EIO);
   1944 }
   1945 
   1946 static int
   1947 ipw2100_m_promisc(void *arg, boolean_t on)
   1948 {
   1949 	struct ipw2100_softc	*sc = (struct ipw2100_softc *)arg;
   1950 	int recfg, err;
   1951 
   1952 	IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
   1953 	    "ipw2100_m_promisc(): enter. "
   1954 	    "GLD setting promiscuous mode - %d\n", on));
   1955 
   1956 	recfg = 0;
   1957 	if (on)
   1958 		if (!(sc->if_flags & IFF_PROMISC)) {
   1959 			sc->if_flags |= IFF_PROMISC;
   1960 			recfg = 1;
   1961 		}
   1962 	else
   1963 		if (sc->if_flags & IFF_PROMISC) {
   1964 			sc->if_flags &= ~IFF_PROMISC;
   1965 			recfg = 1;
   1966 		}
   1967 
   1968 	if (recfg && (sc->sc_flags & IPW2100_FLAG_RUNNING)) {
   1969 		err = ipw2100_config(sc);
   1970 		if (err != DDI_SUCCESS) {
   1971 			IPW2100_WARN((sc->sc_dip, CE_WARN,
   1972 			    "ipw2100_m_promisc(): "
   1973 			    "device configuration failed\n"));
   1974 			goto fail;
   1975 		}
   1976 	}
   1977 
   1978 	return (0);
   1979 fail:
   1980 	return (EIO);
   1981 }
   1982 
   1983 static mblk_t *
   1984 ipw2100_m_tx(void *arg, mblk_t *mp)
   1985 {
   1986 	struct ipw2100_softc	*sc = (struct ipw2100_softc *)arg;
   1987 	struct ieee80211com	*ic = &sc->sc_ic;
   1988 	mblk_t			*next;
   1989 
   1990 	/*
   1991 	 * No data frames go out unless we're associated; this
   1992 	 * should not happen as the 802.11 layer does not enable
   1993 	 * the xmit queue until we enter the RUN state.
   1994 	 */
   1995 	if (ic->ic_state != IEEE80211_S_RUN) {
   1996 		IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
   1997 		    "ipw2100_m_tx(): discard msg, ic_state = %u\n",
   1998 		    ic->ic_state));
   1999 		freemsgchain(mp);
   2000 		return (NULL);
   2001 	}
   2002 
   2003 	while (mp != NULL) {
   2004 		next = mp->b_next;
   2005 		mp->b_next = NULL;
   2006 		if (ipw2100_send(ic, mp, IEEE80211_FC0_TYPE_DATA) !=
   2007 		    DDI_SUCCESS) {
   2008 			mp->b_next = next;
   2009 			break;
   2010 		}
   2011 		mp = next;
   2012 	}
   2013 	return (mp);
   2014 }
   2015 
   2016 /* ARGSUSED */
   2017 static int
   2018 ipw2100_send(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
   2019 {
   2020 	struct ipw2100_softc	*sc = (struct ipw2100_softc *)ic;
   2021 	struct ieee80211_node	*in;
   2022 	struct ieee80211_frame	wh, *wh_tmp;
   2023 	struct ieee80211_key	*k;
   2024 	uint8_t			*hdat;
   2025 	mblk_t			*m0, *m;
   2026 	size_t			cnt, off;
   2027 	struct ipw2100_bd	*txbd[2];
   2028 	struct ipw2100_txb	*txbuf;
   2029 	struct dma_region	*dr;
   2030 	struct ipw2100_hdr	*h;
   2031 	uint32_t		idx, bidx;
   2032 	int			err;
   2033 
   2034 	ASSERT(mp->b_next == NULL);
   2035 
   2036 	m0 = NULL;
   2037 	m = NULL;
   2038 	err = DDI_SUCCESS;
   2039 
   2040 	IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
   2041 	    "ipw2100_send(): enter\n"));
   2042 
   2043 	if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA) {
   2044 		/*
   2045 		 * it is impossible to send non-data 802.11 frame in current
   2046 		 * ipw driver. Therefore, drop the package
   2047 		 */
   2048 		freemsg(mp);
   2049 		err = DDI_SUCCESS;
   2050 		goto fail0;
   2051 	}
   2052 
   2053 	mutex_enter(&sc->sc_tx_lock);
   2054 
   2055 	/*
   2056 	 * need 2 descriptors: 1 for SEND cmd parameter header,
   2057 	 * and the other for payload, i.e., 802.11 frame including 802.11
   2058 	 * frame header
   2059 	 */
   2060 	if (sc->sc_tx_free < 2) {
   2061 		mutex_enter(&sc->sc_resched_lock);
   2062 		IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_WARN,
   2063 		    "ipw2100_send(): no enough descriptors(%d)\n",
   2064 		    sc->sc_tx_free));
   2065 		ic->ic_stats.is_tx_nobuf++; /* no enough buffer */
   2066 		sc->sc_flags |= IPW2100_FLAG_TX_SCHED;
   2067 		err = DDI_FAILURE;
   2068 		mutex_exit(&sc->sc_resched_lock);
   2069 		goto fail1;
   2070 	}
   2071 	IPW2100_DBG(IPW2100_DBG_RING, (sc->sc_dip, CE_CONT,
   2072 	    "ipw2100_send(): tx-free=%d,tx-curr=%d\n",
   2073 	    sc->sc_tx_free, sc->sc_tx_cur));
   2074 
   2075 	wh_tmp = (struct ieee80211_frame *)mp->b_rptr;
   2076 	in = ieee80211_find_txnode(ic, wh_tmp->i_addr1);
   2077 	if (in == NULL) { /* can not find tx node, drop the package */
   2078 		freemsg(mp);
   2079 		err = DDI_SUCCESS;
   2080 		goto fail1;
   2081 	}
   2082 	in->in_inact = 0;
   2083 	(void) ieee80211_encap(ic, mp, in);
   2084 	ieee80211_free_node(in);
   2085 
   2086 	if (wh_tmp->i_fc[1] & IEEE80211_FC1_WEP) {
   2087 		/*
   2088 		 * it is very bad that ieee80211_crypto_encap can only accept a
   2089 		 * single continuous buffer.
   2090 		 */
   2091 		/*
   2092 		 * allocate 32 more bytes is to be compatible with further
   2093 		 * ieee802.11i standard.
   2094 		 */
   2095 		m = allocb(msgdsize(mp) + 32, BPRI_MED);
   2096 		if (m == NULL) { /* can not alloc buf, drop this package */
   2097 			IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
   2098 			    "ipw2100_send(): msg allocation failed\n"));
   2099 
   2100 			freemsg(mp);
   2101 
   2102 			err = DDI_SUCCESS;
   2103 			goto fail1;
   2104 		}
   2105 		off = 0;
   2106 		m0 = mp;
   2107 		while (m0) {
   2108 			cnt = MBLKL(m0);
   2109 			if (cnt) {
   2110 				(void) memcpy(m->b_rptr + off, m0->b_rptr, cnt);
   2111 				off += cnt;
   2112 			}
   2113 			m0 = m0->b_cont;
   2114 		}
   2115 		m->b_wptr += off;
   2116 		IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
   2117 		    "ipw2100_send(): "
   2118 		    "Encrypting 802.11 frame started, %d, %d\n",
   2119 		    msgdsize(mp), MBLKL(mp)));
   2120 		k = ieee80211_crypto_encap(ic, m);
   2121 		if (k == NULL) { /* can not get the key, drop packages */
   2122 			IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
   2123 			    "ipw2100_send(): "
   2124 			    "Encrypting 802.11 frame failed\n"));
   2125 
   2126 			freemsg(mp);
   2127 			err = DDI_SUCCESS;
   2128 			goto fail2;
   2129 		}
   2130 		IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
   2131 		    "ipw2100_send(): "
   2132 		    "Encrypting 802.11 frame finished, %d, %d, k=0x%08x\n",
   2133 		    msgdsize(mp), MBLKL(mp), k->wk_flags));
   2134 	}
   2135 
   2136 	/*
   2137 	 * header descriptor
   2138 	 */
   2139 	idx = sc->sc_tx_cur;
   2140 	txbd[0]  = &sc->sc_txbd[idx];
   2141 	if ((idx & 1) == 0)
   2142 		bidx = idx / 2;
   2143 	sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2100_NUM_TXBD);
   2144 	sc->sc_tx_free--;
   2145 
   2146 	/*
   2147 	 * payload descriptor
   2148 	 */
   2149 	idx = sc->sc_tx_cur;
   2150 	txbd[1]  = &sc->sc_txbd[idx];
   2151 	if ((idx & 1) == 0)
   2152 		bidx = idx / 2;
   2153 	sc->sc_tx_cur = RING_FORWARD(sc->sc_tx_cur, 1, IPW2100_NUM_TXBD);
   2154 	sc->sc_tx_free--;
   2155 
   2156 	/*
   2157 	 * one buffer, SEND cmd header and payload buffer
   2158 	 */
   2159 	txbuf = sc->sc_txbufs[bidx];
   2160 	dr = &sc->sc_dma_txbufs[bidx];
   2161 
   2162 	/*
   2163 	 * extract 802.11 header from message, fill wh from m0
   2164 	 */
   2165 	hdat = (uint8_t *)&wh;
   2166 	off = 0;
   2167 	if (m)
   2168 		m0 = m;
   2169 	else
   2170 		m0 = mp;
   2171 	while (off < sizeof (wh)) {
   2172 		cnt = MBLKL(m0);
   2173 		if (cnt > (sizeof (wh) - off))
   2174 			cnt = sizeof (wh) - off;
   2175 		if (cnt) {
   2176 			(void) memcpy(hdat + off, m0->b_rptr, cnt);
   2177 			off += cnt;
   2178 			m0->b_rptr += cnt;
   2179 		}
   2180 		else
   2181 			m0 = m0->b_cont;
   2182 	}
   2183 
   2184 	/*
   2185 	 * prepare SEND cmd header
   2186 	 */
   2187 	h		= &txbuf->txb_hdr;
   2188 	h->type		= LE_32(IPW2100_CMD_SEND);
   2189 	h->subtype	= LE_32(0);
   2190 	h->encrypted    = ic->ic_flags & IEEE80211_F_PRIVACY ? 1 : 0;
   2191 	h->encrypt	= 0;
   2192 	h->keyidx	= 0;
   2193 	h->keysz	= 0;
   2194 	h->fragsz	= LE_16(0);
   2195 	IEEE80211_ADDR_COPY(h->saddr, wh.i_addr2);
   2196 	if (ic->ic_opmode == IEEE80211_M_STA)
   2197 		IEEE80211_ADDR_COPY(h->daddr, wh.i_addr3);
   2198 	else
   2199 		IEEE80211_ADDR_COPY(h->daddr, wh.i_addr1);
   2200 
   2201 	/*
   2202 	 * extract payload from message into tx data buffer
   2203 	 */
   2204 	off = 0;
   2205 	while (m0) {
   2206 		cnt = MBLKL(m0);
   2207 		if (cnt) {
   2208 			(void) memcpy(&txbuf->txb_dat[off], m0->b_rptr, cnt);
   2209 			off += cnt;
   2210 		}
   2211 		m0 = m0->b_cont;
   2212 	}
   2213 
   2214 	/*
   2215 	 * fill SEND cmd header descriptor
   2216 	 */
   2217 	txbd[0]->phyaddr = LE_32(dr->dr_pbase +
   2218 	    OFFSETOF(struct ipw2100_txb, txb_hdr));
   2219 	txbd[0]->len	= LE_32(sizeof (struct ipw2100_hdr));
   2220 	txbd[0]->flags	= IPW2100_BD_FLAG_TX_FRAME_802_3 |
   2221 	    IPW2100_BD_FLAG_TX_NOT_LAST_FRAGMENT;
   2222 	txbd[0]->nfrag	= 2;
   2223 	/*
   2224 	 * fill payload descriptor
   2225 	 */
   2226 	txbd[1]->phyaddr = LE_32(dr->dr_pbase +
   2227 	    OFFSETOF(struct ipw2100_txb, txb_dat[0]));
   2228 	txbd[1]->len	= LE_32(off);
   2229 	txbd[1]->flags	= IPW2100_BD_FLAG_TX_FRAME_802_3 |
   2230 	    IPW2100_BD_FLAG_TX_LAST_FRAGMENT;
   2231 	txbd[1]->nfrag	= 0;
   2232 
   2233 	/*
   2234 	 * dma sync
   2235 	 */
   2236 	(void) ddi_dma_sync(dr->dr_hnd, 0, sizeof (struct ipw2100_txb),
   2237 	    DDI_DMA_SYNC_FORDEV);
   2238 	(void) ddi_dma_sync(sc->sc_dma_txbd.dr_hnd,
   2239 	    (txbd[0] - sc->sc_txbd) * sizeof (struct ipw2100_bd),
   2240 	    sizeof (struct ipw2100_bd), DDI_DMA_SYNC_FORDEV);
   2241 	/*
   2242 	 * since txbd[1] may not be successive to txbd[0] due to the ring
   2243 	 * organization, another dma_sync is needed to simplify the logic
   2244 	 */
   2245 	(void) ddi_dma_sync(sc->sc_dma_txbd.dr_hnd,
   2246 	    (txbd[1] - sc->sc_txbd) * sizeof (struct ipw2100_bd),
   2247 	    sizeof (struct ipw2100_bd), DDI_DMA_SYNC_FORDEV);
   2248 	/*
   2249 	 * update txcur
   2250 	 */
   2251 	ipw2100_csr_put32(sc, IPW2100_CSR_TX_WRITE_INDEX, sc->sc_tx_cur);
   2252 
   2253 	if (mp) /* success, free the original message */
   2254 		freemsg(mp);
   2255 fail2:
   2256 	if (m)
   2257 		freemsg(m);
   2258 fail1:
   2259 	mutex_exit(&sc->sc_tx_lock);
   2260 fail0:
   2261 	IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
   2262 	    "ipw2100_send(): exit - err=%d\n", err));
   2263 
   2264 	return (err);
   2265 }
   2266 
   2267 /*
   2268  * IOCTL Handler
   2269  */
   2270 #define	IEEE80211_IOCTL_REQUIRED	(1)
   2271 #define	IEEE80211_IOCTL_NOT_REQUIRED	(0)
   2272 static void
   2273 ipw2100_m_ioctl(void *arg, queue_t *q, mblk_t *m)
   2274 {
   2275 	struct ipw2100_softc	*sc  = (struct ipw2100_softc *)arg;
   2276 	struct ieee80211com	*ic = &sc->sc_ic;
   2277 	int			err;
   2278 
   2279 	IPW2100_DBG(IPW2100_DBG_GLD, (sc->sc_dip, CE_CONT,
   2280 	    "ipw2100_m_ioctl(): enter\n"));
   2281 
   2282 	/*
   2283 	 * check whether or not need to handle this in net80211
   2284 	 */
   2285 	if (ipw2100_ioctl(sc, q, m) == IEEE80211_IOCTL_NOT_REQUIRED)
   2286 		return; /* succes or fail */
   2287 
   2288 	err = ieee80211_ioctl(ic, q, m);
   2289 	if (err == ENETRESET) {
   2290 		if (sc->sc_flags & IPW2100_FLAG_RUNNING) {
   2291 			(void) ipw2100_m_start(sc);
   2292 			(void) ieee80211_new_state(ic,
   2293 			    IEEE80211_S_SCAN, -1);
   2294 		}
   2295 	}
   2296 	if (err == ERESTART) {
   2297 		if (sc->sc_flags & IPW2100_FLAG_RUNNING)
   2298 			(void) ipw2100_chip_reset(sc);
   2299 	}
   2300 }
   2301 
   2302 static int
   2303 ipw2100_ioctl(struct ipw2100_softc *sc, queue_t *q, mblk_t *m)
   2304 {
   2305 	struct iocblk	*iocp;
   2306 	uint32_t	len, ret, cmd;
   2307 	mblk_t		*m0;
   2308 	boolean_t	need_privilege;
   2309 	boolean_t	need_net80211;
   2310 
   2311 	if (MBLKL(m) < sizeof (struct iocblk)) {
   2312 		IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT,
   2313 		    "ipw2100_ioctl(): ioctl buffer too short, %u\n",
   2314 		    MBLKL(m)));
   2315 		miocnak(q, m, 0, EINVAL);
   2316 		return (IEEE80211_IOCTL_NOT_REQUIRED);
   2317 	}
   2318 
   2319 	/*
   2320 	 * Validate the command
   2321 	 */
   2322 	iocp = (struct iocblk *)(uintptr_t)m->b_rptr;
   2323 	iocp->ioc_error = 0;
   2324 	cmd = iocp->ioc_cmd;
   2325 	need_privilege = B_TRUE;
   2326 	switch (cmd) {
   2327 	case WLAN_SET_PARAM:
   2328 	case WLAN_COMMAND:
   2329 		break;
   2330 	case WLAN_GET_PARAM:
   2331 		need_privilege = B_FALSE;
   2332 		break;
   2333 	default:
   2334 		IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT,
   2335 		    "ieee80211_ioctl(): unknown cmd 0x%x", cmd));
   2336 		miocnak(q, m, 0, EINVAL);
   2337 		return (IEEE80211_IOCTL_NOT_REQUIRED);
   2338 	}
   2339 
   2340 	if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0) {
   2341 		miocnak(q, m, 0, ret);
   2342 		return (IEEE80211_IOCTL_NOT_REQUIRED);
   2343 	}
   2344 
   2345 	/*
   2346 	 * sanity check
   2347 	 */
   2348 	m0 = m->b_cont;
   2349 	if (iocp->ioc_count == 0 || iocp->ioc_count < sizeof (wldp_t) ||
   2350 	    m0 == NULL) {
   2351 		miocnak(q, m, 0, EINVAL);
   2352 		return (IEEE80211_IOCTL_NOT_REQUIRED);
   2353 	}
   2354 	/*
   2355 	 * assuming single data block
   2356 	 */
   2357 	if (m0->b_cont) {
   2358 		freemsg(m0->b_cont);
   2359 		m0->b_cont = NULL;
   2360 	}
   2361 
   2362 	need_net80211 = B_FALSE;
   2363 	ret = ipw2100_getset(sc, m0, cmd, &need_net80211);
   2364 	if (!need_net80211) {
   2365 		len = msgdsize(m0);
   2366 
   2367 		IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT,
   2368 		    "ipw2100_ioctl(): go to call miocack with "
   2369 		    "ret = %d, len = %d\n", ret, len));
   2370 		miocack(q, m, len, ret);
   2371 		return (IEEE80211_IOCTL_NOT_REQUIRED);
   2372 	}
   2373 
   2374 	/*
   2375 	 * IEEE80211_IOCTL_REQUIRED - need net80211 handle
   2376 	 */
   2377 	return (IEEE80211_IOCTL_REQUIRED);
   2378 }
   2379 
   2380 static int
   2381 ipw2100_getset(struct ipw2100_softc *sc, mblk_t *m, uint32_t cmd,
   2382 	boolean_t *need_net80211)
   2383 {
   2384 	wldp_t		*infp, *outfp;
   2385 	uint32_t	id;
   2386 	int		ret; /* IEEE80211_IOCTL - handled by net80211 */
   2387 
   2388 	infp  = (wldp_t *)(uintptr_t)m->b_rptr;
   2389 	outfp = (wldp_t *)(uintptr_t)m->b_rptr;
   2390 	outfp->wldp_result = WL_NOTSUPPORTED;
   2391 
   2392 	id = infp->wldp_id;
   2393 	IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT,
   2394 	    "ipw2100_getset(): id = 0x%x\n", id));
   2395 	switch (id) {
   2396 	/*
   2397 	 * which is not supported by net80211, so it
   2398 	 * has to be handled from driver side
   2399 	 */
   2400 	case WL_RADIO:
   2401 		ret = ipw_wificfg_radio(sc, cmd, outfp);
   2402 		break;
   2403 	/*
   2404 	 * so far, drier doesn't support fix-rates
   2405 	 */
   2406 	case WL_DESIRED_RATES:
   2407 		ret = ipw_wificfg_desrates(outfp);
   2408 		break;
   2409 	/*
   2410 	 * current net80211 implementation clears the bssid while
   2411 	 * this command received, which will result in the all zero
   2412 	 * mac address for scan'ed AP which is just disconnected.
   2413 	 * This is a workaround solution until net80211 find a
   2414 	 * better method.
   2415 	 */
   2416 	case WL_DISASSOCIATE:
   2417 		ret = ipw_wificfg_disassoc(sc, outfp);
   2418 		break;
   2419 	default:
   2420 		/*
   2421 		 * The wifi IOCTL net80211 supported:
   2422 		 *	case WL_ESSID:
   2423 		 *	case WL_BSSID:
   2424 		 *	case WL_WEP_KEY_TAB:
   2425 		 *	case WL_WEP_KEY_ID:
   2426 		 *	case WL_AUTH_MODE:
   2427 		 *	case WL_ENCRYPTION:
   2428 		 *	case WL_BSS_TYPE:
   2429 		 *	case WL_ESS_LIST:
   2430 		 *	case WL_LINKSTATUS:
   2431 		 *	case WL_RSSI:
   2432 		 *	case WL_SCAN:
   2433 		 *	case WL_LOAD_DEFAULTS:
   2434 		 */
   2435 
   2436 		/*
   2437 		 * When radio is off, need to ignore all ioctl.  What need to
   2438 		 * do is to check radio status firstly.  If radio is ON, pass
   2439 		 * it to net80211, otherwise, return to upper layer directly.
   2440 		 *
   2441 		 * Considering the WL_SUCCESS also means WL_CONNECTED for
   2442 		 * checking linkstatus, one exception for WL_LINKSTATUS is to
   2443 		 * let net80211 handle it.
   2444 		 */
   2445 		if ((ipw2100_get_radio(sc) == 0) &&
   2446 		    (id != WL_LINKSTATUS)) {
   2447 
   2448 			IPW2100_REPORT((sc->sc_dip, CE_WARN,
   2449 			    "ipw: RADIO is OFF\n"));
   2450 
   2451 			outfp->wldp_length = WIFI_BUF_OFFSET;
   2452 			outfp->wldp_result = WL_SUCCESS;
   2453 			ret = 0;
   2454 			break;
   2455 		}
   2456 
   2457 		*need_net80211 = B_TRUE; /* let net80211 do the rest */
   2458 		return (0);
   2459 	}
   2460 	/*
   2461 	 * we will overwrite everything
   2462 	 */
   2463 	m->b_wptr = m->b_rptr + outfp->wldp_length;
   2464 
   2465 	return (ret);
   2466 }
   2467 
   2468 /*
   2469  * Call back functions for get/set proporty
   2470  */
   2471 static int
   2472 ipw2100_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
   2473     uint_t pr_flags, uint_t wldp_length, void *wldp_buf, uint_t *perm)
   2474 {
   2475 	struct ipw2100_softc	*sc = (struct ipw2100_softc *)arg;
   2476 	struct ieee80211com	*ic = &sc->sc_ic;
   2477 	int 			err = 0;
   2478 
   2479 	switch (wldp_pr_num) {
   2480 	/* mac_prop_id */
   2481 	case MAC_PROP_WL_DESIRED_RATES:
   2482 		IPW2100_DBG(IPW2100_DBG_BRUSSELS, (sc->sc_dip, CE_CONT,
   2483 		    "ipw2100_m_getprop(): Not Support DESIRED_RATES\n"));
   2484 		break;
   2485 	case MAC_PROP_WL_RADIO:
   2486 		*(wl_linkstatus_t *)wldp_buf = ipw2100_get_radio(sc);
   2487 		break;
   2488 	default:
   2489 		/* go through net80211 */
   2490 		err = ieee80211_getprop(ic, pr_name, wldp_pr_num, pr_flags,
   2491 		    wldp_length, wldp_buf, perm);
   2492 		break;
   2493 	}
   2494 
   2495 	return (err);
   2496 }
   2497 
   2498 static int
   2499 ipw2100_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
   2500     uint_t wldp_length, const void *wldp_buf)
   2501 {
   2502 	struct ipw2100_softc	*sc = (struct ipw2100_softc *)arg;
   2503 	struct ieee80211com	*ic = &sc->sc_ic;
   2504 	int			err;
   2505 
   2506 	switch (wldp_pr_num) {
   2507 	/* mac_prop_id */
   2508 	case MAC_PROP_WL_DESIRED_RATES:
   2509 		IPW2100_DBG(IPW2100_DBG_BRUSSELS, (sc->sc_dip, CE_CONT,
   2510 		    "ipw2100_m_setprop(): Not Support DESIRED_RATES\n"));
   2511 		err = ENOTSUP;
   2512 		break;
   2513 	case MAC_PROP_WL_RADIO:
   2514 		IPW2100_DBG(IPW2100_DBG_BRUSSELS, (sc->sc_dip, CE_CONT,
   2515 		    "ipw2100_m_setprop(): Not Support RADIO\n"));
   2516 		err = ENOTSUP;
   2517 		break;
   2518 	default:
   2519 		/* go through net80211 */
   2520 		err = ieee80211_setprop(ic, pr_name, wldp_pr_num, wldp_length,
   2521 		    wldp_buf);
   2522 		break;
   2523 	}
   2524 
   2525 	if (err == ENETRESET) {
   2526 		if (sc->sc_flags & IPW2100_FLAG_RUNNING) {
   2527 			(void) ipw2100_m_start(sc);
   2528 			(void) ieee80211_new_state(ic,
   2529 			    IEEE80211_S_SCAN, -1);
   2530 		}
   2531 
   2532 		err = 0;
   2533 	}
   2534 
   2535 	return (err);
   2536 }
   2537 
   2538 static int
   2539 ipw_wificfg_radio(struct ipw2100_softc *sc, uint32_t cmd, wldp_t *outfp)
   2540 {
   2541 	uint32_t	ret = ENOTSUP;
   2542 
   2543 	switch (cmd) {
   2544 	case WLAN_GET_PARAM:
   2545 		*(wl_linkstatus_t *)(outfp->wldp_buf) = ipw2100_get_radio(sc);
   2546 		outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t);
   2547 		outfp->wldp_result = WL_SUCCESS;
   2548 		ret = 0; /* command sucess */
   2549 		break;
   2550 	case WLAN_SET_PARAM:
   2551 	default:
   2552 		break;
   2553 	}
   2554 	return (ret);
   2555 }
   2556 
   2557 static int
   2558 ipw_wificfg_desrates(wldp_t *outfp)
   2559 {
   2560 	/*
   2561 	 * return success, but with result NOTSUPPORTED
   2562 	 */
   2563 	outfp->wldp_length = WIFI_BUF_OFFSET;
   2564 	outfp->wldp_result = WL_NOTSUPPORTED;
   2565 	return (0);
   2566 }
   2567 
   2568 static int
   2569 ipw_wificfg_disassoc(struct ipw2100_softc *sc, wldp_t *outfp)
   2570 {
   2571 	struct ieee80211com	*ic = &sc->sc_ic;
   2572 
   2573 	/*
   2574 	 * init the state
   2575 	 */
   2576 	if (ic->ic_state != IEEE80211_S_INIT) {
   2577 		(void) ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
   2578 	}
   2579 
   2580 	/*
   2581 	 * return success always
   2582 	 */
   2583 	outfp->wldp_length = WIFI_BUF_OFFSET;
   2584 	outfp->wldp_result = WL_SUCCESS;
   2585 	return (0);
   2586 }
   2587 /* End of IOCTL Handler */
   2588 
   2589 static void
   2590 ipw2100_fix_channel(struct ieee80211com *ic, mblk_t *m)
   2591 {
   2592 	struct ieee80211_frame	*wh;
   2593 	uint8_t			subtype;
   2594 	uint8_t			*frm, *efrm;
   2595 
   2596 	wh = (struct ieee80211_frame *)m->b_rptr;
   2597 
   2598 	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT)
   2599 		return;
   2600 
   2601 	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
   2602 
   2603 	if (subtype != IEEE80211_FC0_SUBTYPE_BEACON &&
   2604 	    subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP)
   2605 		return;
   2606 
   2607 	/*
   2608 	 * assume the message contains only 1 block
   2609 	 */
   2610 	frm   = (uint8_t *)(wh + 1);
   2611 	efrm  = (uint8_t *)m->b_wptr;
   2612 	frm  += 12;  /* skip tstamp, bintval and capinfo fields */
   2613 	while (frm < efrm) {
   2614 		if (*frm == IEEE80211_ELEMID_DSPARMS) {
   2615 #if IEEE80211_CHAN_MAX < 255
   2616 			if (frm[2] <= IEEE80211_CHAN_MAX)
   2617 #endif
   2618 			{
   2619 				ic->ic_curchan = &ic->ic_sup_channels[frm[2]];
   2620 			}
   2621 		}
   2622 		frm += frm[1] + 2;
   2623 	}
   2624 }
   2625 
   2626 static void
   2627 ipw2100_rcvpkt(struct ipw2100_softc *sc, struct ipw2100_status *status,
   2628     uint8_t *rxbuf)
   2629 {
   2630 	struct ieee80211com	*ic = &sc->sc_ic;
   2631 	mblk_t			*m;
   2632 	struct ieee80211_frame	*wh = (struct ieee80211_frame *)rxbuf;
   2633 	struct ieee80211_node	*in;
   2634 	uint32_t		rlen;
   2635 
   2636 	in = ieee80211_find_rxnode(ic, wh);
   2637 	rlen = LE_32(status->len);
   2638 	m = allocb(rlen, BPRI_MED);
   2639 	if (m) {
   2640 		(void) memcpy(m->b_wptr, rxbuf, rlen);
   2641 		m->b_wptr += rlen;
   2642 		if (ic->ic_state == IEEE80211_S_SCAN)
   2643 			ipw2100_fix_channel(ic, m);
   2644 		(void) ieee80211_input(ic, m, in, status->rssi, 0);
   2645 	} else
   2646 		IPW2100_WARN((sc->sc_dip, CE_WARN,
   2647 		    "ipw2100_rcvpkg(): cannot allocate receive message(%u)\n",
   2648 		    LE_32(status->len)));
   2649 	ieee80211_free_node(in);
   2650 }
   2651 
   2652 static uint_t
   2653 ipw2100_intr(caddr_t arg)
   2654 {
   2655 	struct ipw2100_softc	*sc = (struct ipw2100_softc *)(uintptr_t)arg;
   2656 	uint32_t		ireg, ridx, len, i;
   2657 	struct ieee80211com	*ic = &sc->sc_ic;
   2658 	struct ipw2100_status	*status;
   2659 	uint8_t			*rxbuf;
   2660 	struct dma_region	*dr;
   2661 	uint32_t		state;
   2662 #if DEBUG
   2663 	struct ipw2100_bd *rxbd;
   2664 #endif
   2665 
   2666 	if (sc->sc_suspended)
   2667 		return (DDI_INTR_UNCLAIMED);
   2668 
   2669 	ireg = ipw2100_csr_get32(sc, IPW2100_CSR_INTR);
   2670 
   2671 	if (!(ireg & IPW2100_INTR_MASK_ALL))
   2672 		return (DDI_INTR_UNCLAIMED);
   2673 
   2674 	/*
   2675 	 * mask all interrupts
   2676 	 */
   2677 	ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, 0);
   2678 
   2679 	/*
   2680 	 * acknowledge all fired interrupts
   2681 	 */
   2682 	ipw2100_csr_put32(sc, IPW2100_CSR_INTR, ireg);
   2683 
   2684 	IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT,
   2685 	    "ipw2100_intr(): interrupt is fired. int=0x%08x\n", ireg));
   2686 
   2687 	if (ireg & IPW2100_INTR_MASK_ERR) {
   2688 
   2689 		IPW2100_DBG(IPW2100_DBG_FATAL, (sc->sc_dip, CE_CONT,
   2690 		    "ipw2100_intr(): interrupt is fired, MASK = 0x%08x\n",
   2691 		    ireg));
   2692 
   2693 		/*
   2694 		 * inform mfthread to recover hw error
   2695 		 */
   2696 		mutex_enter(&sc->sc_mflock);
   2697 		sc->sc_flags |= IPW2100_FLAG_HW_ERR_RECOVER;
   2698 		mutex_exit(&sc->sc_mflock);
   2699 
   2700 		goto enable_interrupt;
   2701 	}
   2702 
   2703 	/*
   2704 	 * FW intr
   2705 	 */
   2706 	if (ireg & IPW2100_INTR_FW_INIT_DONE) {
   2707 		mutex_enter(&sc->sc_ilock);
   2708 		sc->sc_flags |= IPW2100_FLAG_FW_INITED;
   2709 		cv_signal(&sc->sc_fw_cond);
   2710 		mutex_exit(&sc->sc_ilock);
   2711 	}
   2712 
   2713 	/*
   2714 	 * RX intr
   2715 	 */
   2716 	if (ireg & IPW2100_INTR_RX_TRANSFER) {
   2717 		ridx = ipw2100_csr_get32(sc,
   2718 		    IPW2100_CSR_RX_READ_INDEX);
   2719 
   2720 		for (; sc->sc_rx_cur != ridx;
   2721 		    sc->sc_rx_cur = RING_FORWARD(
   2722 		    sc->sc_rx_cur, 1, IPW2100_NUM_RXBD)) {
   2723 
   2724 			i	= sc->sc_rx_cur;
   2725 			status	= &sc->sc_status[i];
   2726 			rxbuf	= &sc->sc_rxbufs[i]->rxb_dat[0];
   2727 			dr	= &sc->sc_dma_rxbufs[i];
   2728 
   2729 			/*
   2730 			 * sync
   2731 			 */
   2732 			(void) ddi_dma_sync(sc->sc_dma_status.dr_hnd,
   2733 			    i * sizeof (struct ipw2100_status),
   2734 			    sizeof (struct ipw2100_status),
   2735 			    DDI_DMA_SYNC_FORKERNEL);
   2736 			(void) ddi_dma_sync(sc->sc_dma_rxbd.dr_hnd,
   2737 			    i * sizeof (struct ipw2100_bd),
   2738 			    sizeof (struct ipw2100_bd),
   2739 			    DDI_DMA_SYNC_FORKERNEL);
   2740 			(void) ddi_dma_sync(dr->dr_hnd, 0,
   2741 			    sizeof (struct ipw2100_rxb),
   2742 			    DDI_DMA_SYNC_FORKERNEL);
   2743 			IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT,
   2744 			    "ipw2100_intr(): status code=0x%04x, len=0x%08x, "
   2745 			    "flags=0x%02x, rssi=%02x\n",
   2746 			    LE_16(status->code), LE_32(status->len),
   2747 			    status->flags, status->rssi));
   2748 #if DEBUG
   2749 			rxbd	= &sc->sc_rxbd[i];
   2750 			IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT,
   2751 			    "ipw2100_intr(): rxbd,phyaddr=0x%08x, len=0x%08x, "
   2752 			    "flags=0x%02x,nfrag=%02x\n",
   2753 			    LE_32(rxbd->phyaddr), LE_32(rxbd->len),
   2754 			    rxbd->flags, rxbd->nfrag));
   2755 #endif
   2756 			switch (LE_16(status->code) & 0x0f) {
   2757 			/*
   2758 			 * command complete response
   2759 			 */
   2760 			case IPW2100_STATUS_CODE_COMMAND:
   2761 				mutex_enter(&sc->sc_ilock);
   2762 				sc->sc_done = 1;
   2763 				cv_signal(&sc->sc_cmd_cond);
   2764 				mutex_exit(&sc->sc_ilock);
   2765 				break;
   2766 			/*
   2767 			 * change state
   2768 			 */
   2769 			case IPW2100_STATUS_CODE_NEWSTATE:
   2770 				state = LE_32(* ((uint32_t *)(uintptr_t)rxbuf));
   2771 				IPW2100_DBG(IPW2100_DBG_INT,
   2772 				    (sc->sc_dip, CE_CONT,
   2773 				    "ipw2100_intr(): newstate,state=0x%x\n",
   2774 				    state));
   2775 
   2776 				switch (state) {
   2777 				case IPW2100_STATE_ASSOCIATED:
   2778 					ieee80211_new_state(ic,
   2779 					    IEEE80211_S_RUN, -1);
   2780 					break;
   2781 				case IPW2100_STATE_ASSOCIATION_LOST:
   2782 					case IPW2100_STATE_DISABLED:
   2783 					ieee80211_new_state(ic,
   2784 					    IEEE80211_S_INIT, -1);
   2785 					break;
   2786 				/*
   2787 				 * When radio is OFF, need a better
   2788 				 * scan approach to ensure scan
   2789 				 * result correct.
   2790 				 */
   2791 				case IPW2100_STATE_RADIO_DISABLED:
   2792 					IPW2100_REPORT((sc->sc_dip, CE_WARN,
   2793 					    "ipw2100_intr(): RADIO is OFF\n"));
   2794 					ipw2100_stop(sc);
   2795 					break;
   2796 				case IPW2100_STATE_SCAN_COMPLETE:
   2797 					ieee80211_cancel_scan(ic);
   2798 					break;
   2799 				case IPW2100_STATE_SCANNING:
   2800 					if (ic->ic_state != IEEE80211_S_RUN)
   2801 						ieee80211_new_state(ic,
   2802 						    IEEE80211_S_SCAN, -1);
   2803 					ic->ic_flags |= IEEE80211_F_SCAN;
   2804 
   2805 					break;
   2806 				default:
   2807 					break;
   2808 				}
   2809 				break;
   2810 			case IPW2100_STATUS_CODE_DATA_802_11:
   2811 			case IPW2100_STATUS_CODE_DATA_802_3:
   2812 				ipw2100_rcvpkt(sc, status, rxbuf);
   2813 				break;
   2814 			case IPW2100_STATUS_CODE_NOTIFICATION:
   2815 				break;
   2816 			default:
   2817 				IPW2100_WARN((sc->sc_dip, CE_WARN,
   2818 				    "ipw2100_intr(): "
   2819 				    "unknown status code 0x%04x\n",
   2820 				    LE_16(status->code)));
   2821 				break;
   2822 			}
   2823 		}
   2824 		/*
   2825 		 * write sc_rx_cur backward 1 step to RX_WRITE_INDEX
   2826 		 */
   2827 		ipw2100_csr_put32(sc, IPW2100_CSR_RX_WRITE_INDEX,
   2828 		    RING_BACKWARD(sc->sc_rx_cur, 1, IPW2100_NUM_RXBD));
   2829 	}
   2830 
   2831 	/*
   2832 	 * TX intr
   2833 	 */
   2834 	if (ireg & IPW2100_INTR_TX_TRANSFER) {
   2835 		mutex_enter(&sc->sc_tx_lock);
   2836 		ridx = ipw2100_csr_get32(sc, IPW2100_CSR_TX_READ_INDEX);
   2837 		len = RING_FLEN(RING_FORWARD(sc->sc_tx_cur,
   2838 		    sc->sc_tx_free, IPW2100_NUM_TXBD),
   2839 		    ridx, IPW2100_NUM_TXBD);
   2840 		sc->sc_tx_free += len;
   2841 		IPW2100_DBG(IPW2100_DBG_INT, (sc->sc_dip, CE_CONT,
   2842 		    "ipw2100_intr(): len=%d\n", len));
   2843 		mutex_exit(&sc->sc_tx_lock);
   2844 
   2845 		mutex_enter(&sc->sc_resched_lock);
   2846 		if (len > 1 && (sc->sc_flags & IPW2100_FLAG_TX_SCHED)) {
   2847 			sc->sc_flags &= ~IPW2100_FLAG_TX_SCHED;
   2848 			mac_tx_update(ic->ic_mach);
   2849 		}
   2850 		mutex_exit(&sc->sc_resched_lock);
   2851 	}
   2852 
   2853 enable_interrupt:
   2854 	/*
   2855 	 * enable all interrupts
   2856 	 */
   2857 	ipw2100_csr_put32(sc, IPW2100_CSR_INTR_MASK, IPW2100_INTR_MASK_ALL);
   2858 
   2859 	return (DDI_INTR_CLAIMED);
   2860 }
   2861 
   2862 
   2863 /*
   2864  * Module Loading Data & Entry Points
   2865  */
   2866 DDI_DEFINE_STREAM_OPS(ipw2100_devops, nulldev, nulldev, ipw2100_attach,
   2867     ipw2100_detach, nodev, NULL, D_MP, NULL, ipw2100_quiesce);
   2868 
   2869 static struct modldrv ipw2100_modldrv = {
   2870 	&mod_driverops,
   2871 	ipw2100_ident,
   2872 	&ipw2100_devops
   2873 };
   2874 
   2875 static struct modlinkage ipw2100_modlinkage = {
   2876 	MODREV_1,
   2877 	&ipw2100_modldrv,
   2878 	NULL
   2879 };
   2880 
   2881 int
   2882 _init(void)
   2883 {
   2884 	int	status;
   2885 
   2886 	status = ddi_soft_state_init(&ipw2100_ssp,
   2887 	    sizeof (struct ipw2100_softc), 1);
   2888 	if (status != DDI_SUCCESS)
   2889 		return (status);
   2890 
   2891 	mac_init_ops(&ipw2100_devops, IPW2100_DRV_NAME);
   2892 	status = mod_install(&ipw2100_modlinkage);
   2893 	if (status != DDI_SUCCESS) {
   2894 		mac_fini_ops(&ipw2100_devops);
   2895 		ddi_soft_state_fini(&ipw2100_ssp);
   2896 	}
   2897 
   2898 	return (status);
   2899 }
   2900 
   2901 int
   2902 _fini(void)
   2903 {
   2904 	int status;
   2905 
   2906 	status = mod_remove(&ipw2100_modlinkage);
   2907 	if (status == DDI_SUCCESS) {
   2908 		mac_fini_ops(&ipw2100_devops);
   2909 		ddi_soft_state_fini(&ipw2100_ssp);
   2910 	}
   2911 
   2912 	return (status);
   2913 }
   2914 
   2915 int
   2916 _info(struct modinfo *mip)
   2917 {
   2918 	return (mod_info(&ipw2100_modlinkage, mip));
   2919 }
   2920