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