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