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