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