xref: /titanic_44/usr/src/uts/common/io/ipw/ipw2100.c (revision de6732348404877079e00a1631babd13d8a5ad14)
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@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@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