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