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