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